Merge m-a to gum.
authorEddy Bruël <ejpbruel@gmail.com>
Thu, 06 Nov 2014 14:14:06 +0100
changeset 233733 639b0f85ca340bff90298476bd048c331a5b4d5e
parent 233732 91ef7bf03b244d1ecc84bf2bbe8d68dd3cfe4c63 (current diff)
parent 233670 7b1cbdeed5d898b6ab4fa73fb8931eaaeec42f47 (diff)
child 233734 c1515955999bc1052b6ad266b7a3b269346fdb1d
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone35.0a2
Merge m-a to gum.
browser/base/content/browser.js
browser/branding/aurora/branding.nsi
browser/devtools/main.js
browser/themes/osx/browser.css
configure.in
content/html/content/test/imports/file_cycle_5_A.html
content/html/content/test/imports/file_cycle_5_B.html
content/html/content/test/imports/file_cycle_5_C.html
content/html/content/test/imports/file_cycle_5_D.html
content/html/content/test/imports/test_cycle_5.html
dom/base/test/test_location_searchParams.html
gfx/thebes/nsSurfaceTexture.cpp
gfx/thebes/nsSurfaceTexture.h
--- a/browser/app/macbuild/Contents/MacOS-files.in
+++ b/browser/app/macbuild/Contents/MacOS-files.in
@@ -1,10 +1,9 @@
 /*.app/***
 /*.dylib
 /certutil
 /firefox-bin
 /gtest/***
 /pk12util
 /ssltunnel
-/webapprt-stub
 /xpcshell
 /XUL
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1150,17 +1150,19 @@ var gBrowserInit = {
     Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
     Services.obs.addObserver(gGatherTelemetryObserver, "gather-telemetry", false);
     window.messageManager.addMessageListener("Browser:URIFixup", gKeywordURIFixup);
     window.messageManager.addMessageListener("Browser:LoadURI", RedirectLoad);
 
     BrowserOffline.init();
     OfflineApps.init();
     IndexedDBPromptHelper.init();
+#ifdef E10S_TESTING_ONLY
     gRemoteTabsUI.init();
+#endif
 
     // Initialize the full zoom setting.
     // We do this before the session restore service gets initialized so we can
     // apply full zoom settings to tabs restored by the session restore service.
     FullZoom.init();
     PanelUI.init();
     LightweightThemeListener.init();
 
@@ -7147,24 +7149,19 @@ let gPrivateBrowsingUI = {
 let gRemoteTabsUI = {
   init: function() {
     if (window.location.href != getBrowserURL()) {
       return;
     }
 
     let newRemoteWindow = document.getElementById("menu_newRemoteWindow");
     let newNonRemoteWindow = document.getElementById("menu_newNonRemoteWindow");
-#ifdef E10S_TESTING_ONLY
     let autostart = Services.appinfo.browserTabsRemoteAutostart;
     newRemoteWindow.hidden = autostart;
     newNonRemoteWindow.hidden = !autostart;
-#else
-    newRemoteWindow.hidden = true;
-    newNonRemoteWindow.hidden = true;
-#endif
   }
 };
 
 /**
  * Switch to a tab that has a given URI, and focusses its browser window.
  * If a matching tab is in this window, it will be switched to. Otherwise, other
  * windows will be searched.
  *
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -2581,16 +2581,17 @@
         <parameter name="aTab"/>
         <body>
           <![CDATA[
             let url = aTab.linkedBrowser.currentURI.spec;
             return window.openDialog("chrome://browser/content/", "_blank", "chrome,all,dialog=no,non-remote", url);
           ]]>
         </body>
       </method>
+#endif
 
       <method name="moveTabTo">
         <parameter name="aTab"/>
         <parameter name="aIndex"/>
         <body>
         <![CDATA[
           var oldPosition = aTab._tPos;
           if (oldPosition == aIndex)
--- a/browser/base/moz.build
+++ b/browser/base/moz.build
@@ -17,17 +17,17 @@ BROWSER_CHROME_MANIFESTS += [
     'content/test/general/browser.ini',
     'content/test/newtab/browser.ini',
     'content/test/plugins/browser.ini',
     'content/test/popupNotifications/browser.ini',
     'content/test/social/browser.ini',
 ]
 
 DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
-DEFINES['E10S_TESTING_ONLY'] = CONFIG['E10S_TESTING_ONLY']
+
 DEFINES['APP_LICENSE_BLOCK'] = '%s/content/overrides/app-license.html' % SRCDIR
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3', 'cocoa'):
     DEFINES['HAVE_SHELL_SERVICE'] = 1
     DEFINES['CONTEXT_COPY_IMAGE_CONTENTS'] = 1
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'):
     DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
--- a/browser/components/customizableui/CustomizeMode.jsm
+++ b/browser/components/customizableui/CustomizeMode.jsm
@@ -1063,16 +1063,17 @@ CustomizeMode.prototype = {
       for (let target of this.areas) {
         for (let toolbarItem of target.children) {
           if (this.isWrappedToolbarItem(toolbarItem)) {
             yield this.deferredUnwrapToolbarItem(toolbarItem);
           }
         }
         this._removeDragHandlers(target);
       }
+      this.areas.clear();
     }.bind(this)).then(null, ERROR);
   },
 
   _removeExtraToolbarsIfEmpty: function() {
     let toolbox = this.window.gNavToolbox;
     for (let child of toolbox.children) {
       if (child.hasAttribute("customindex")) {
         let placements = CustomizableUI.getWidgetIdsInArea(child.id);
--- a/browser/components/customizableui/moz.build
+++ b/browser/components/customizableui/moz.build
@@ -10,18 +10,16 @@ DIRS += [
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 
 EXTRA_JS_MODULES += [
     'DragPositionManager.jsm',
     'ScrollbarSampler.jsm',
 ]
 
-DEFINES['E10S_TESTING_ONLY'] = CONFIG['E10S_TESTING_ONLY']
-
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'):
     DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3'):
     DEFINES['MENUBAR_CAN_AUTOHIDE'] = 1
 
 EXTRA_PP_JS_MODULES += [
     'CustomizableUI.jsm',
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -145,8 +145,9 @@ skip-if = os == "linux"
 [browser_996635_remove_non_widgets.js]
 [browser_1003588_no_specials_in_panel.js]
 [browser_1007336_lwthemes_in_customize_mode.js]
 [browser_1008559_anchor_undo_restore.js]
 [browser_1042100_default_placements_update.js]
 [browser_1058573_showToolbarsDropdown.js]
 [browser_bootstrapped_custom_toolbar.js]
 [browser_panel_toggle.js]
+[browser_1089591_still_customizable_after_reset.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/test/browser_1089591_still_customizable_after_reset.js
@@ -0,0 +1,25 @@
+"use strict";
+
+// Dragging the elements again after a reset should work
+add_task(function* () {
+  yield startCustomizing();
+  let historyButton = document.getElementById("wrapper-history-panelmenu");
+  let devButton = document.getElementById("wrapper-developer-button");
+
+  ok(historyButton && devButton, "Draggable elements should exist");
+  simulateItemDrag(historyButton, devButton);
+  gCustomizeMode.reset();
+  yield waitForCondition(() => !gCustomizeMode.resetting);
+  ok(CustomizableUI.inDefaultState, "Should be back in default state");
+
+  historyButton = document.getElementById("wrapper-history-panelmenu");
+  devButton = document.getElementById("wrapper-developer-button");
+  ok(historyButton && devButton, "Draggable elements should exist");
+  simulateItemDrag(historyButton, devButton);
+
+  yield endCustomizing();
+});
+
+add_task(function* asyncCleanup() {
+  yield resetCustomization();
+});
--- a/browser/components/loop/content/js/client.js
+++ b/browser/components/loop/content/js/client.js
@@ -146,49 +146,50 @@ loop.Client = (function($) {
           }
         }.bind(this));
     },
 
     /**
      * Block call URL based on the token identifier
      *
      * @param {string} token Conversation identifier used to block the URL
+     * @param {mozLoop.LOOP_SESSION_TYPE} sessionType The type of session which
+     *                                                the url belongs to.
      * @param {function} cb Callback function used for handling an error
      *                      response. XXX The incoming call panel does not
      *                      exist after the block button is clicked therefore
      *                      it does not make sense to display an error.
      **/
-    deleteCallUrl: function(token, cb) {
+    deleteCallUrl: function(token, sessionType, cb) {
       this._ensureRegistered(function(err) {
         if (err) {
           cb(err);
           return;
         }
 
-        this._deleteCallUrlInternal(token, cb);
+        this._deleteCallUrlInternal(token, sessionType, cb);
       }.bind(this));
     },
 
-    _deleteCallUrlInternal: function(token, cb) {
+    _deleteCallUrlInternal: function(token, sessionType, cb) {
       function deleteRequestCallback(error, responseText) {
         if (error) {
           this._failureHandler(cb, error);
           return;
         }
 
         try {
           cb(null);
         } catch (err) {
           console.log("Error deleting call info", err);
           cb(err);
         }
       }
 
-      // XXX hard-coding of GUEST to be removed by 1065155
-      this.mozLoop.hawkRequest(this.mozLoop.LOOP_SESSION_TYPE.GUEST,
+      this.mozLoop.hawkRequest(sessionType,
                                "/call-url/" + token, "DELETE", null,
                                deleteRequestCallback.bind(this));
     },
 
     /**
      * Requests a call URL from the Loop server. It will note the
      * expiry time for the url with the mozLoop api.  It will select the
      * appropriate hawk session to use based on whether or not the user
--- a/browser/components/loop/content/js/conversation.js
+++ b/browser/components/loop/content/js/conversation.js
@@ -491,22 +491,24 @@ loop.conversation = (function(mozL10n) {
      * Decline and block an incoming call
      * @note:
      * - loopToken is the callUrl identifier. It gets set in the panel
      *   after a callUrl is received
      */
     declineAndBlock: function() {
       navigator.mozLoop.stopAlerting();
       var token = this.props.conversation.get("callToken");
-      this.props.client.deleteCallUrl(token, function(error) {
-        // XXX The conversation window will be closed when this cb is triggered
-        // figure out if there is a better way to report the error to the user
-        // (bug 1048909).
-        console.log(error);
-      });
+      this.props.client.deleteCallUrl(token,
+        this.props.conversation.get("sessionType"),
+        function(error) {
+          // XXX The conversation window will be closed when this cb is triggered
+          // figure out if there is a better way to report the error to the user
+          // (bug 1048909).
+          console.log(error);
+        });
       this._declineCall();
     },
 
     /**
      * Handles a error starting the session
      */
     _handleSessionError: function() {
       // XXX Not the ideal response, but bug 1047410 will be replacing
--- a/browser/components/loop/content/js/conversation.jsx
+++ b/browser/components/loop/content/js/conversation.jsx
@@ -491,22 +491,24 @@ loop.conversation = (function(mozL10n) {
      * Decline and block an incoming call
      * @note:
      * - loopToken is the callUrl identifier. It gets set in the panel
      *   after a callUrl is received
      */
     declineAndBlock: function() {
       navigator.mozLoop.stopAlerting();
       var token = this.props.conversation.get("callToken");
-      this.props.client.deleteCallUrl(token, function(error) {
-        // XXX The conversation window will be closed when this cb is triggered
-        // figure out if there is a better way to report the error to the user
-        // (bug 1048909).
-        console.log(error);
-      });
+      this.props.client.deleteCallUrl(token,
+        this.props.conversation.get("sessionType"),
+        function(error) {
+          // XXX The conversation window will be closed when this cb is triggered
+          // figure out if there is a better way to report the error to the user
+          // (bug 1048909).
+          console.log(error);
+        });
       this._declineCall();
     },
 
     /**
      * Handles a error starting the session
      */
     _handleSessionError: function() {
       // XXX Not the ideal response, but bug 1047410 will be replacing
--- a/browser/components/loop/test/desktop-local/client_test.js
+++ b/browser/components/loop/test/desktop-local/client_test.js
@@ -51,57 +51,57 @@ describe("loop.Client", function() {
 
   afterEach(function() {
     sandbox.restore();
   });
 
   describe("loop.Client", function() {
     describe("#deleteCallUrl", function() {
       it("should ensure loop is registered", function() {
-        client.deleteCallUrl("fakeToken", callback);
+        client.deleteCallUrl("fakeToken", mozLoop.LOOP_SESSION_TYPE.FXA, callback);
 
         sinon.assert.calledOnce(mozLoop.ensureRegistered);
       });
 
       it("should send an error when registration fails", function() {
         mozLoop.ensureRegistered.callsArgWith(0, "offline");
 
-        client.deleteCallUrl("fakeToken", callback);
+        client.deleteCallUrl("fakeToken", mozLoop.LOOP_SESSION_TYPE.FXA, callback);
 
         sinon.assert.calledOnce(callback);
         sinon.assert.calledWithExactly(callback, "offline");
       });
 
       it("should make a delete call to /call-url/{fakeToken}", function() {
-        client.deleteCallUrl(fakeToken, callback);
+        client.deleteCallUrl(fakeToken, mozLoop.LOOP_SESSION_TYPE.GUEST, callback);
 
         sinon.assert.calledOnce(hawkRequestStub);
         sinon.assert.calledWith(hawkRequestStub,
                                 mozLoop.LOOP_SESSION_TYPE.GUEST,
                                 "/call-url/" + fakeToken, "DELETE");
       });
 
       it("should call the callback with null when the request succeeds",
          function() {
 
            // Sets up the hawkRequest stub to trigger the callback with no error
            // and the url.
            hawkRequestStub.callsArgWith(4, null);
 
-           client.deleteCallUrl(fakeToken, callback);
+           client.deleteCallUrl(fakeToken, mozLoop.LOOP_SESSION_TYPE.FXA, callback);
 
            sinon.assert.calledWithExactly(callback, null);
          });
 
       it("should send an error when the request fails", function() {
         // Sets up the hawkRequest stub to trigger the callback with
         // an error
         hawkRequestStub.callsArgWith(4, fakeErrorRes);
 
-        client.deleteCallUrl(fakeToken, callback);
+        client.deleteCallUrl(fakeToken, mozLoop.LOOP_SESSION_TYPE.FXA, callback);
 
         sinon.assert.calledOnce(callback);
         sinon.assert.calledWithMatch(callback, sinon.match(function(err) {
           return err.code == 400 && "invalid token" == err.message;
         }));
       });
     });
 
--- a/browser/components/loop/test/desktop-local/conversation_test.js
+++ b/browser/components/loop/test/desktop-local/conversation_test.js
@@ -508,60 +508,72 @@ describe("loop.conversation", function()
           icView.decline();
 
           sinon.assert.calledOnce(navigator.mozLoop.releaseCallData);
           sinon.assert.calledWithExactly(navigator.mozLoop.releaseCallData, 8699);
         });
       });
 
       describe("#blocked", function() {
+        var mozLoop;
+
         beforeEach(function() {
           icView = mountTestComponent();
 
           icView._websocket = {
             decline: sinon.spy(),
             close: sinon.stub()
           };
           sandbox.stub(window, "close");
+
+          mozLoop = {
+            LOOP_SESSION_TYPE: {
+              GUEST: 1,
+              FXA: 2
+            }
+          };
         });
 
         it("should call mozLoop.stopAlerting", function() {
           icView.declineAndBlock();
 
           sinon.assert.calledOnce(navigator.mozLoop.stopAlerting);
         });
 
         it("should call delete call", function() {
           sandbox.stub(conversation, "get").withArgs("callToken")
-                                           .returns("fakeToken");
+                                           .returns("fakeToken")
+                                           .withArgs("sessionType")
+                                           .returns(mozLoop.LOOP_SESSION_TYPE.FXA);
+
           var deleteCallUrl = sandbox.stub(loop.Client.prototype,
                                            "deleteCallUrl");
           icView.declineAndBlock();
 
           sinon.assert.calledOnce(deleteCallUrl);
-          sinon.assert.calledWithExactly(deleteCallUrl, "fakeToken",
-                                                        sinon.match.func);
+          sinon.assert.calledWithExactly(deleteCallUrl,
+            "fakeToken", mozLoop.LOOP_SESSION_TYPE.FXA, sinon.match.func);
         });
 
         it("should get callToken from conversation model", function() {
           sandbox.stub(conversation, "get");
           icView.declineAndBlock();
 
-          sinon.assert.calledTwice(conversation.get);
+          sinon.assert.called(conversation.get);
           sinon.assert.calledWithExactly(conversation.get, "callToken");
           sinon.assert.calledWithExactly(conversation.get, "callId");
         });
 
         it("should trigger error handling in case of error", function() {
           // XXX just logging to console for now
           var log = sandbox.stub(console, "log");
           var fakeError = {
             error: true
           };
-          sandbox.stub(loop.Client.prototype, "deleteCallUrl", function(_, cb) {
+          sandbox.stub(loop.Client.prototype, "deleteCallUrl", function(_, __, cb) {
             cb(fakeError);
           });
           icView.declineAndBlock();
 
           sinon.assert.calledOnce(log);
           sinon.assert.calledWithExactly(log, fakeError);
         });
 
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -38,16 +38,14 @@ EXTRA_PP_COMPONENTS += [
     'nsBrowserContentHandler.js',
     'nsBrowserGlue.js',
 ]
 
 EXTRA_JS_MODULES += [
     'distribution.js',
 ]
 
-DEFINES['E10S_TESTING_ONLY'] = CONFIG['E10S_TESTING_ONLY']
-
 BROWSER_CHROME_MANIFESTS += [
     'test/browser.ini'
 ]
 
 if CONFIG['MOZ_SAFE_BROWSING']:
     BROWSER_CHROME_MANIFESTS += ['safebrowsing/content/test/browser.ini']
--- a/browser/components/preferences/in-content/moz.build
+++ b/browser/components/preferences/in-content/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/.
 
-for var in ('MOZ_APP_NAME', 'MOZ_MACBUNDLE_NAME', 'E10S_TESTING_ONLY'):
+for var in ('MOZ_APP_NAME', 'MOZ_MACBUNDLE_NAME'):
     DEFINES[var] = CONFIG[var]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'cocoa'):
     DEFINES['HAVE_SHELL_SERVICE'] = 1
 
 JAR_MANIFESTS += ['jar.mn']
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -853,21 +853,17 @@ bin/libfreebl_32int64_3.so
 #endif
 #endif
 
 #ifdef MOZ_WEBAPP_RUNTIME
 [WebappRuntime]
 #ifdef XP_WIN
 @BINPATH@/webapp-uninstaller@BIN_SUFFIX@
 #endif
-#ifdef XP_MACOSX
-@APPNAME@/Contents/MacOS/webapprt-stub@BIN_SUFFIX@
-#else
 @BINPATH@/webapprt-stub@BIN_SUFFIX@
-#endif
 @BINPATH@/webapprt/webapprt.ini
 @BINPATH@/webapprt/chrome.manifest
 @BINPATH@/webapprt/chrome/webapprt@JAREXT@
 @BINPATH@/webapprt/chrome/webapprt.manifest
 @BINPATH@/webapprt/chrome/@AB_CD@@JAREXT@
 @BINPATH@/webapprt/chrome/@AB_CD@.manifest
 @BINPATH@/webapprt/components/CommandLineHandler.js
 @BINPATH@/webapprt/components/ContentPermission.js
--- a/browser/themes/linux/moz.build
+++ b/browser/themes/linux/moz.build
@@ -1,11 +1,9 @@
 # -*- 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/.
 
 DIRS += ['communicator']
 
-DEFINES['E10S_TESTING_ONLY'] = CONFIG['E10S_TESTING_ONLY']
-
 JAR_MANIFESTS += ['jar.mn']
--- a/browser/themes/osx/moz.build
+++ b/browser/themes/osx/moz.build
@@ -1,11 +1,9 @@
 # -*- 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/.
 
 DIRS += ['communicator']
 
-DEFINES['E10S_TESTING_ONLY'] = CONFIG['E10S_TESTING_ONLY']
-
 JAR_MANIFESTS += ['jar.mn']
--- a/browser/themes/windows/moz.build
+++ b/browser/themes/windows/moz.build
@@ -1,11 +1,9 @@
 # -*- 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/.
 
 DIRS += ['communicator']
 
-DEFINES['E10S_TESTING_ONLY'] = CONFIG['E10S_TESTING_ONLY']
-
 JAR_MANIFESTS += ['jar.mn']
--- a/configure.in
+++ b/configure.in
@@ -3518,18 +3518,19 @@ MOZ_ARG_DISABLE_BOOL(unified-compilation
     MOZ_DISABLE_UNIFIED_COMPILATION=1,
     MOZ_DISABLE_UNIFIED_COMPILATION=)
 AC_SUBST(MOZ_DISABLE_UNIFIED_COMPILATION)
 
 dnl ========================================================
 dnl Multiprocess Firefox Nightly Testing UI
 dnl To be removed in Bug 1003313
 dnl ========================================================
-if test -z "$NIGHTLY_BUILD"; then
+if test -n "$NIGHTLY_BUILD"; then
     E10S_TESTING_ONLY=1
+    AC_DEFINE(E10S_TESTING_ONLY)
 fi
 
 AC_SUBST(E10S_TESTING_ONLY)
 
 dnl ========================================================
 dnl system libevent Support
 dnl ========================================================
 MOZ_ARG_WITH_STRING(system-libevent,
@@ -5282,18 +5283,25 @@ MOZ_ARG_DISABLE_BOOL(ffmpeg,
 
 if test -n "$MOZ_FFMPEG"; then
     AC_DEFINE(MOZ_FFMPEG)
 fi;
 
 dnl ========================================================
 dnl = Built-in fragmented MP4 support.
 dnl ========================================================
+
+if test "$OS_TARGET" = Android; then
+    MOZ_FMP4=1
+fi
+
 if test -n "$MOZ_WMF" -o -n "$MOZ_FFMPEG" -o -n "$MOZ_APPLEMEDIA"; then
-    dnl Enable fragmented MP4 parser on platforms with decoder support.
+    dnl Enable fragmented MP4 parser on Windows by default.
+    dnl We will also need to enable it on other platforms as we implement
+    dnl platform decoder support there too.
     MOZ_FMP4=1
 fi
 
 MOZ_ARG_DISABLE_BOOL(fmp4,
 [  --disable-fmp4  Disable support for in built Fragmented MP4 parsing],
     MOZ_FMP4=,
     MOZ_FMP4=1)
 
@@ -8935,16 +8943,19 @@ AC_SUBST(LIBJPEG_TURBO_X64_ASM)
 AC_SUBST(LIBJPEG_TURBO_ARM_ASM)
 
 AC_SUBST(MOZ_PACKAGE_JSSHELL)
 AC_SUBST(MOZ_FOLD_LIBS)
 
 AC_SUBST(MOZ_ENABLE_SZIP)
 AC_SUBST(MOZ_SZIP_FLAGS)
 
+dnl Host JavaScript runtime, if any, to use during cross compiles.
+AC_SUBST(JS_BINARY)
+
 if test "$MOZ_DEBUG"; then
     MOZ_EM_DEBUG=1
 fi
 AC_SUBST(MOZ_EM_DEBUG)
 
 if test -n "$COMPILE_ENVIRONMENT"; then
 AC_CHECK_FUNCS(posix_fadvise posix_fallocate)
 
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -4010,17 +4010,17 @@ nsDocument::GetChildArray(uint32_t* aChi
 }
 
 
 nsresult
 nsDocument::InsertChildAt(nsIContent* aKid, uint32_t aIndex,
                           bool aNotify)
 {
   if (aKid->IsElement() && GetRootElement()) {
-    NS_ERROR("Inserting element child when we already have one");
+    NS_WARNING("Inserting root element when we already have one");
     return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
   }
 
   return doInsertChildAt(aKid, aIndex, aNotify, mChildren);
 }
 
 void
 nsDocument::RemoveChildAt(uint32_t aIndex, bool aNotify)
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -155,16 +155,17 @@ GK_ATOM(br, "br")
 GK_ATOM(braille, "braille")
 GK_ATOM(broadcast, "broadcast")
 GK_ATOM(broadcaster, "broadcaster")
 GK_ATOM(broadcasterset, "broadcasterset")
 GK_ATOM(browser, "browser")
 GK_ATOM(mozbrowser, "mozbrowser")
 GK_ATOM(bulletinboard, "bulletinboard")
 GK_ATOM(button, "button")
+GK_ATOM(brighttitlebarforeground, "brighttitlebarforeground")
 GK_ATOM(callTemplate, "call-template")
 GK_ATOM(cancel, "cancel")
 GK_ATOM(canvas, "canvas")
 GK_ATOM(caption, "caption")
 GK_ATOM(capture, "capture")
 GK_ATOM(caseOrder, "case-order")
 GK_ATOM(cdataSectionElements, "cdata-section-elements")
 GK_ATOM(ceiling, "ceiling")
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -674,18 +674,21 @@ HTMLInputElement::nsFilePickerShownCallb
     }
 
     nsCOMPtr<nsISupports> tmp;
     bool hasMore = true;
 
     while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
       iter->GetNext(getter_AddRefs(tmp));
       nsCOMPtr<nsIDOMFile> domFile = do_QueryInterface(tmp);
-      MOZ_ASSERT(domFile);
-      newFiles.AppendElement(static_cast<File*>(domFile.get()));
+      NS_WARN_IF_FALSE(domFile,
+                       "Null file object from FilePicker's file enumerator?");
+      if (domFile) {
+        newFiles.AppendElement(static_cast<File*>(domFile.get()));
+      }
     }
   } else {
     MOZ_ASSERT(mode == static_cast<int16_t>(nsIFilePicker::modeOpen));
     nsCOMPtr<nsIDOMFile> domFile;
     nsresult rv = mFilePicker->GetDomfile(getter_AddRefs(domFile));
     NS_ENSURE_SUCCESS(rv, rv);
     if (domFile) {
       newFiles.AppendElement(static_cast<File*>(domFile.get()));
deleted file mode 100644
--- a/content/html/content/test/imports/file_cycle_5_A.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<html lang="en-US">
-<head>
-  <link rel="import" href="file_cycle_5_B.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_D.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_C.html" onload="loaded()" onerror="failed()"></link>
-</head>
-<body>
-  <script>
-    order.push("A");
-  </script>
-</body>
-</html>
deleted file mode 100644
--- a/content/html/content/test/imports/file_cycle_5_B.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<html lang="en-US">
-<head>
-  <link rel="import" href="file_cycle_5_A.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_C.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_D.html" onload="loaded()" onerror="failed()"></link>
-</head>
-<body>
-  <script>
-    order.push("B");
-  </script>
-</body>
-</html>
deleted file mode 100644
--- a/content/html/content/test/imports/file_cycle_5_C.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<html lang="en-US">
-<head>
-  <link rel="import" href="file_cycle_5_A.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_B.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_D.html" onload="loaded()" onerror="failed()"></link>
-</head>
-<body>
-  <script>
-    order.push("C");
-  </script>
-</body>
-</html>
deleted file mode 100644
--- a/content/html/content/test/imports/file_cycle_5_D.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<html lang="en-US">
-<head>
-  <link rel="import" href="file_cycle_5_A.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_B.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_C.html" onload="loaded()" onerror="failed()"></link>
-</head>
-<body>
-  <script>
-    order.push("D");
-  </script>
-</body>
-</html>
--- a/content/html/content/test/imports/mochitest.ini
+++ b/content/html/content/test/imports/mochitest.ini
@@ -26,25 +26,19 @@ support-files =
   file_cycle_3_A.html
   file_cycle_3_B.html
   file_cycle_3_C.html
   file_cycle_4_A.html
   file_cycle_4_B.html
   file_cycle_4_C.html
   file_cycle_4_D.html
   file_cycle_4_E.html
-  file_cycle_5_A.html
-  file_cycle_5_B.html
-  file_cycle_5_C.html
-  file_cycle_5_D.html
   file_encoding.html
 
 [test_cycle_1.html]
 skip-if = toolkit == 'gonk' # nested imports fail on b2g emulator
 [test_cycle_2.html]
 skip-if = toolkit == 'gonk' # nested imports fail on b2g emulator
 [test_cycle_3.html]
 skip-if = toolkit == 'gonk' # nested imports fail on b2g emulator
 [test_cycle_4.html]
 skip-if = toolkit == 'gonk' # nested imports fail on b2g emulator
-[test_cycle_5.html]
-skip-if = toolkit == 'gonk' # nested imports fail on b2g emulator
 [test_encoding.html]
deleted file mode 100644
--- a/content/html/content/test/imports/test_cycle_5.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1061469
--->
-<head>
-  <title>Test for Bug 1061469</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-  <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
-</head>
-<body>
-  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1061469">Mozilla Bug 1061469</a>
-  <script type="text/javascript">
-    SimpleTest.waitForExplicitFinish();
-    var counter = 0;
-    var fcounter = 0;
-    var order = [];
-    function loaded() {
-      counter++;
-    }
-    function failed() {
-      fcounter++;
-    }
-  </script>
-  <link rel="import" href="file_cycle_5_A.html" onload="loaded()" onerror="failed()"></link>
-  <link rel="import" href="file_cycle_5_C.html" onload="loaded()" onerror="failed()"></link>
-  <script type="text/javascript">
-    is(counter, 14, "Imports are loaded");
-    is(fcounter, 0, "No error in imports");
-    var expected = ["D","C","B","A"];
-    for (i in expected)
-      is(order[i], expected[i], "import " + i + " should be " + expected[i]);
-    SimpleTest.finish();
-  </script>
-</body>
-</html>
--- a/content/media/fmp4/MP4Decoder.cpp
+++ b/content/media/fmp4/MP4Decoder.cpp
@@ -18,16 +18,19 @@
 #include "mozilla/WindowsVersion.h"
 #endif
 #ifdef MOZ_FFMPEG
 #include "FFmpegRuntimeLinker.h"
 #endif
 #ifdef MOZ_APPLEMEDIA
 #include "apple/AppleDecoderModule.h"
 #endif
+#ifdef MOZ_WIDGET_ANDROID
+#include "AndroidBridge.h"
+#endif
 
 namespace mozilla {
 
 MediaDecoderStateMachine* MP4Decoder::CreateStateMachine()
 {
   return new MediaDecoderStateMachine(this, new MP4Reader(this));
 }
 
@@ -163,16 +166,20 @@ IsGonkMP4DecoderAvailable()
 static bool
 HavePlatformMPEGDecoders()
 {
   return Preferences::GetBool("media.fragmented-mp4.use-blank-decoder") ||
 #ifdef XP_WIN
          // We have H.264/AAC platform decoders on Windows Vista and up.
          IsVistaOrLater() ||
 #endif
+#ifdef MOZ_WIDGET_ANDROID
+         // We need android.media.MediaCodec which exists in API level 16 and higher.
+         (AndroidBridge::Bridge()->GetAPIVersion() >= 16) ||
+#endif
          IsFFmpegAvailable() ||
          IsAppleAvailable() ||
          IsGonkMP4DecoderAvailable() ||
          // TODO: Other platforms...
          false;
 }
 
 /* static */
--- a/content/media/fmp4/PlatformDecoderModule.cpp
+++ b/content/media/fmp4/PlatformDecoderModule.cpp
@@ -12,52 +12,65 @@
 #include "FFmpegRuntimeLinker.h"
 #endif
 #ifdef MOZ_APPLEMEDIA
 #include "AppleDecoderModule.h"
 #endif
 #ifdef MOZ_GONK_MEDIACODEC
 #include "GonkDecoderModule.h"
 #endif
+#ifdef MOZ_WIDGET_ANDROID
+#include "AndroidDecoderModule.h"
+#endif
 
 #include "mozilla/Preferences.h"
 #ifdef MOZ_EME
 #include "EMEDecoderModule.h"
 #include "mozilla/CDMProxy.h"
 #endif
 #include "SharedThreadPool.h"
 #include "MediaTaskQueue.h"
 
 namespace mozilla {
 
 extern PlatformDecoderModule* CreateBlankDecoderModule();
 
 bool PlatformDecoderModule::sUseBlankDecoder = false;
 bool PlatformDecoderModule::sFFmpegDecoderEnabled = false;
 bool PlatformDecoderModule::sGonkDecoderEnabled = false;
+bool PlatformDecoderModule::sAndroidMCDecoderEnabled = false;
+bool PlatformDecoderModule::sAndroidMCDecoderPreferred = false;
 
 /* static */
 void
 PlatformDecoderModule::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
   static bool alreadyInitialized = false;
   if (alreadyInitialized) {
     return;
   }
   alreadyInitialized = true;
 
   Preferences::AddBoolVarCache(&sUseBlankDecoder,
                                "media.fragmented-mp4.use-blank-decoder");
   Preferences::AddBoolVarCache(&sFFmpegDecoderEnabled,
                                "media.fragmented-mp4.ffmpeg.enabled", false);
+
 #ifdef MOZ_GONK_MEDIACODEC
   Preferences::AddBoolVarCache(&sGonkDecoderEnabled,
                                "media.fragmented-mp4.gonk.enabled", false);
 #endif
+#ifdef MOZ_WIDGET_ANDROID
+  Preferences::AddBoolVarCache(&sAndroidMCDecoderEnabled,
+                               "media.fragmented-mp4.android-media-codec.enabled", false);
+  Preferences::AddBoolVarCache(&sAndroidMCDecoderPreferred,
+                               "media.fragmented-mp4.android-media-codec.preferred", false);
+#endif
+
 #ifdef XP_WIN
   WMFDecoderModule::Init();
 #endif
 #ifdef MOZ_APPLEMEDIA
   AppleDecoderModule::Init();
 #endif
 }
 
@@ -117,16 +130,21 @@ PlatformDecoderModule::CreateCDMWrapper(
 
 /* static */
 PlatformDecoderModule*
 PlatformDecoderModule::Create()
 {
   // Note: This runs on the decode thread.
   MOZ_ASSERT(!NS_IsMainThread());
 
+#ifdef MOZ_WIDGET_ANDROID
+  if(sAndroidMCDecoderPreferred && sAndroidMCDecoderEnabled){
+    return new AndroidDecoderModule();
+  }
+#endif
   if (sUseBlankDecoder) {
     return CreateBlankDecoderModule();
   }
 #ifdef XP_WIN
   nsAutoPtr<WMFDecoderModule> m(new WMFDecoderModule());
   if (NS_SUCCEEDED(m->Startup())) {
     return m.forget();
   }
@@ -145,16 +163,21 @@ PlatformDecoderModule::Create()
     return m.forget();
   }
 #endif
 #ifdef MOZ_GONK_MEDIACODEC
   if (sGonkDecoderEnabled) {
     return new GonkDecoderModule();
   }
 #endif
+#ifdef MOZ_WIDGET_ANDROID
+  if(sAndroidMCDecoderEnabled){
+    return new AndroidDecoderModule();
+  }
+#endif
   return nullptr;
 }
 
 bool
 PlatformDecoderModule::SupportsAudioMimeType(const char* aMimeType)
 {
   return !strcmp(aMimeType, "audio/mp4a-latm");
 }
--- a/content/media/fmp4/PlatformDecoderModule.h
+++ b/content/media/fmp4/PlatformDecoderModule.h
@@ -126,16 +126,18 @@ public:
   virtual ~PlatformDecoderModule() {}
 
 protected:
   PlatformDecoderModule() {}
   // Caches pref media.fragmented-mp4.use-blank-decoder
   static bool sUseBlankDecoder;
   static bool sFFmpegDecoderEnabled;
   static bool sGonkDecoderEnabled;
+  static bool sAndroidMCDecoderPreferred;
+  static bool sAndroidMCDecoderEnabled;
 };
 
 // A callback used by MediaDataDecoder to return output/errors to the
 // MP4Reader. Implementation is threadsafe, and can be called on any thread.
 class MediaDataDecoderCallback {
 public:
   virtual ~MediaDataDecoderCallback() {}
 
new file mode 100644
--- /dev/null
+++ b/content/media/fmp4/android/AndroidDecoderModule.cpp
@@ -0,0 +1,499 @@
+/* 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 "AndroidDecoderModule.h"
+#include "PlatformDecoderModule.h"
+#include "GeneratedJNIWrappers.h"
+#include "GeneratedSDKWrappers.h"
+#include "AndroidBridge.h"
+#include "MediaTaskQueue.h"
+#include "SharedThreadPool.h"
+#include "TexturePoolOGL.h"
+#include "GLImages.h"
+
+#include "MediaData.h"
+
+#include "mp4_demuxer/AnnexB.h"
+#include "mp4_demuxer/DecoderData.h"
+
+#include "nsThreadUtils.h"
+#include "nsAutoPtr.h"
+
+#include <jni.h>
+
+using namespace mozilla;
+using namespace mozilla::gl;
+using namespace mozilla::widget::android;
+
+namespace mozilla {
+
+static MediaCodec* CreateDecoder(JNIEnv* aEnv, const char* aMimeType)
+{
+  if (!aMimeType) {
+    return nullptr;
+  }
+
+  nsAutoString mimeType;
+  mimeType.AssignASCII(aMimeType);
+
+  jobject decoder = MediaCodec::CreateDecoderByType(mimeType);
+
+  return new MediaCodec(decoder, aEnv);
+}
+
+class VideoDataDecoder : public MediaCodecDataDecoder {
+public:
+  VideoDataDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
+                   MediaFormat* aFormat, MediaDataDecoderCallback* aCallback,
+                   layers::ImageContainer* aImageContainer)
+    : MediaCodecDataDecoder(MediaData::Type::VIDEO_FRAME, aConfig.mime_type, aFormat, aCallback)
+    , mImageContainer(aImageContainer)
+    , mConfig(aConfig)
+  {
+
+  }
+
+  nsresult Init() MOZ_OVERRIDE {
+    mSurfaceTexture = AndroidSurfaceTexture::Create();
+    if (!mSurfaceTexture) {
+      printf_stderr("Failed to create SurfaceTexture for video decode\n");
+      return NS_ERROR_FAILURE;
+    }
+
+    return InitDecoder(mSurfaceTexture->JavaSurface());
+  }
+
+  virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE {
+    mp4_demuxer::AnnexB::ConvertSample(aSample, mConfig.annex_b);
+    return MediaCodecDataDecoder::Input(aSample);
+  }
+
+  virtual nsresult PostOutput(BufferInfo* aInfo, MediaFormat* aFormat, Microseconds aDuration) MOZ_OVERRIDE {
+    VideoInfo videoInfo;
+    videoInfo.mDisplay = nsIntSize(mConfig.display_width, mConfig.display_height);
+
+    bool isSync = false;
+    if (MediaCodec::getBUFFER_FLAG_SYNC_FRAME() & aInfo->getFlags()) {
+      isSync = true;
+    }
+
+    nsRefPtr<layers::Image> img = mImageContainer->CreateImage(ImageFormat::SURFACE_TEXTURE);
+    layers::SurfaceTextureImage::Data data;
+    data.mSurfTex = mSurfaceTexture.get();
+    data.mSize = gfx::IntSize(mConfig.display_width, mConfig.display_height);
+    data.mInverted = true;
+
+    layers::SurfaceTextureImage* typedImg = static_cast<layers::SurfaceTextureImage*>(img.get());
+    typedImg->SetData(data);
+
+    mCallback->Output(VideoData::CreateFromImage(videoInfo, mImageContainer, aInfo->getOffset(),
+                                                 aInfo->getPresentationTimeUs(),
+                                                 aDuration,
+                                                 img, isSync,
+                                                 aInfo->getPresentationTimeUs(),
+                                                 gfx::IntRect(0, 0,
+                                                   mConfig.display_width,
+                                                   mConfig.display_height)));
+    return NS_OK;
+  }
+
+protected:
+  layers::ImageContainer* mImageContainer;
+  const mp4_demuxer::VideoDecoderConfig& mConfig;
+  nsRefPtr<AndroidSurfaceTexture> mSurfaceTexture;
+};
+
+class AudioDataDecoder : public MediaCodecDataDecoder {
+public:
+  AudioDataDecoder(const char* aMimeType, MediaFormat* aFormat, MediaDataDecoderCallback* aCallback)
+  : MediaCodecDataDecoder(MediaData::Type::AUDIO_SAMPLES, aMimeType, aFormat, aCallback)
+  {
+  }
+
+  nsresult Output(BufferInfo* aInfo, void* aBuffer, MediaFormat* aFormat, Microseconds aDuration) {
+    // The output on Android is always 16-bit signed
+
+    uint32_t numChannels = aFormat->GetInteger(NS_LITERAL_STRING("channel-count"));
+    uint32_t sampleRate = aFormat->GetInteger(NS_LITERAL_STRING("sample-rate"));
+    uint32_t numFrames = (aInfo->getSize() / numChannels) / 2;
+
+    AudioDataValue* audio = new AudioDataValue[aInfo->getSize()];
+    PodCopy(audio, static_cast<AudioDataValue*>(aBuffer), aInfo->getSize());
+
+    mCallback->Output(new AudioData(aInfo->getOffset(), aInfo->getPresentationTimeUs(),
+                                    aDuration,
+                                    numFrames,
+                                    audio,
+                                    numChannels,
+                                    sampleRate));
+    return NS_OK;
+  }
+};
+
+
+bool AndroidDecoderModule::SupportsAudioMimeType(const char* aMimeType) {
+  JNIEnv* env = GetJNIForThread();
+  MediaCodec* decoder = CreateDecoder(env, aMimeType);
+  bool supports = (decoder != nullptr);
+  delete decoder;
+  return supports;
+}
+
+already_AddRefed<MediaDataDecoder>
+AndroidDecoderModule::CreateH264Decoder(
+                                const mp4_demuxer::VideoDecoderConfig& aConfig,
+                                layers::LayersBackend aLayersBackend,
+                                layers::ImageContainer* aImageContainer,
+                                MediaTaskQueue* aVideoTaskQueue,
+                                MediaDataDecoderCallback* aCallback)
+{
+  nsAutoString mimeType;
+  mimeType.AssignASCII(aConfig.mime_type);
+
+  jobject jFormat = MediaFormat::CreateVideoFormat(mimeType,
+                                                   aConfig.display_width,
+                                                   aConfig.display_height);
+
+  if (!jFormat) {
+    return nullptr;
+  }
+
+  MediaFormat* format = MediaFormat::Wrap(jFormat);
+
+  if (!format) {
+    return nullptr;
+  }
+
+  nsRefPtr<MediaDataDecoder> decoder =
+    new VideoDataDecoder(aConfig, format, aCallback, aImageContainer);
+
+  return decoder.forget();
+}
+
+already_AddRefed<MediaDataDecoder>
+AndroidDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
+                                         MediaTaskQueue* aAudioTaskQueue,
+                                         MediaDataDecoderCallback* aCallback)
+{
+  MOZ_ASSERT(aConfig.bits_per_sample == 16, "We only handle 16-bit audio!");
+
+  nsAutoString mimeType;
+  mimeType.AssignASCII(aConfig.mime_type);
+
+  jobject jFormat = MediaFormat::CreateAudioFormat(mimeType,
+                                                   aConfig.samples_per_second,
+                                                   aConfig.channel_count);
+
+  if (jFormat == nullptr)
+    return nullptr;
+
+  MediaFormat* format = MediaFormat::Wrap(jFormat);
+
+  if(format == nullptr)
+    return nullptr;
+
+  JNIEnv* env = GetJNIForThread();
+
+  if (!format->GetByteBuffer(NS_LITERAL_STRING("csd-0"))) {
+    uint8_t* csd0 = new uint8_t[2];
+
+    csd0[0] = aConfig.audio_specific_config[0];
+    csd0[1] = aConfig.audio_specific_config[1];
+
+    jobject buffer = env->NewDirectByteBuffer(csd0, 2);
+    format->SetByteBuffer(NS_LITERAL_STRING("csd-0"), buffer);
+
+    env->DeleteLocalRef(buffer);
+  }
+
+  if (mimeType.EqualsLiteral("audio/mp4a-latm")) {
+    format->SetInteger(NS_LITERAL_STRING("is-adts"), 1);
+  }
+
+  nsRefPtr<MediaDataDecoder> decoder =
+    new AudioDataDecoder(aConfig.mime_type, format, aCallback);
+
+  return decoder.forget();
+
+}
+
+
+nsresult AndroidDecoderModule::Shutdown()
+{
+  return NS_OK;
+}
+
+MediaCodecDataDecoder::MediaCodecDataDecoder(MediaData::Type aType,
+                                             const char* aMimeType,
+                                             MediaFormat* aFormat,
+                                             MediaDataDecoderCallback* aCallback)
+  : mType(aType)
+  , mMimeType(strdup(aMimeType))
+  , mFormat(aFormat)
+  , mCallback(aCallback)
+  , mInputBuffers(nullptr)
+  , mOutputBuffers(nullptr)
+  , mMonitor("MediaCodecDataDecoder::mMonitor")
+  , mDraining(false)
+  , mStopping(false)
+{
+
+}
+
+MediaCodecDataDecoder::~MediaCodecDataDecoder()
+{
+  JNIEnv* env = GetJNIForThread();
+
+  Shutdown();
+
+  if (mInputBuffers) {
+    env->DeleteGlobalRef(mInputBuffers);
+    mInputBuffers = nullptr;
+  }
+
+  if (mOutputBuffers) {
+    env->DeleteGlobalRef(mOutputBuffers);
+    mOutputBuffers = nullptr;
+  }
+}
+
+nsresult MediaCodecDataDecoder::Init()
+{
+  return InitDecoder();
+}
+
+nsresult MediaCodecDataDecoder::InitDecoder(jobject aSurface)
+{
+  JNIEnv* env = GetJNIForThread();
+  mDecoder = CreateDecoder(env, mMimeType);
+  if (!mDecoder) {
+    mCallback->Error();
+    return NS_ERROR_FAILURE;
+  }
+
+  if (!mDecoder->Configure(mFormat->wrappedObject(), aSurface, nullptr, 0)) {
+    mCallback->Error();
+    return NS_ERROR_FAILURE;
+  }
+
+  mDecoder->Start();
+
+  ResetInputBuffers();
+  ResetOutputBuffers();
+
+  NS_NewNamedThread("MC Decoder", getter_AddRefs(mThread),
+                    NS_NewRunnableMethod(this, &MediaCodecDataDecoder::DecoderLoop));
+
+  return NS_OK;
+}
+
+// This is in usec, so that's 10ms
+#define DECODER_TIMEOUT 10000
+
+void MediaCodecDataDecoder::DecoderLoop()
+{
+  bool outputDone = false;
+
+  JNIEnv* env = GetJNIForThread();
+  mp4_demuxer::MP4Sample* sample = nullptr;
+
+  nsAutoPtr<MediaFormat> outputFormat;
+
+  for (;;) {
+    {
+      MonitorAutoLock lock(mMonitor);
+      while (!mStopping && !mDraining && mQueue.empty()) {
+        if (mQueue.empty()) {
+          // We could be waiting here forever if we don't signal that we need more input
+          mCallback->InputExhausted();
+        }
+        lock.Wait();
+      }
+
+      if (mStopping) {
+        // Get out of the loop. This is the only exit point.
+        break;
+      }
+
+      if (mDraining) {
+        mDecoder->Flush();
+        ClearQueue();
+        mDraining =  false;
+        lock.Notify();
+        continue;
+      }
+
+      // We're not stopping or draining, so try to get a sample
+      if (!mQueue.empty()) {
+        sample = mQueue.front();
+      }
+    }
+
+    if (sample) {
+      // We have a sample, try to feed it to the decoder
+      int inputIndex = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT);
+      if (inputIndex >= 0) {
+        jobject buffer = env->GetObjectArrayElement(mInputBuffers, inputIndex);
+        void* directBuffer = env->GetDirectBufferAddress(buffer);
+
+        // We're feeding this to the decoder, so remove it from the queue
+        mMonitor.Lock();
+        mQueue.pop();
+        mMonitor.Unlock();
+
+        MOZ_ASSERT(env->GetDirectBufferCapacity(buffer) >= sample->size,
+          "Decoder buffer is not large enough for sample");
+
+        PodCopy((uint8_t*)directBuffer, sample->data, sample->size);
+
+        mDecoder->QueueInputBuffer(inputIndex, 0, sample->size, sample->composition_timestamp, 0);
+        mDurations.push(sample->duration);
+
+        delete sample;
+        sample = nullptr;
+
+        outputDone = false;
+        env->DeleteLocalRef(buffer);
+      }
+    }
+
+    if (!outputDone) {
+      BufferInfo bufferInfo;
+
+      int outputStatus = mDecoder->DequeueOutputBuffer(bufferInfo.wrappedObject(), DECODER_TIMEOUT);
+      if (outputStatus == MediaCodec::getINFO_TRY_AGAIN_LATER()) {
+        // We might want to call mCallback->InputExhausted() here, but there seems to be
+        // some possible bad interactions here with the threading
+      } else if (outputStatus == MediaCodec::getINFO_OUTPUT_BUFFERS_CHANGED()) {
+        ResetOutputBuffers();
+      } else if (outputStatus == MediaCodec::getINFO_OUTPUT_FORMAT_CHANGED()) {
+        outputFormat = new MediaFormat(mDecoder->GetOutputFormat(), GetJNIForThread());
+      } else if (outputStatus < 0) {
+        printf_stderr("unknown error from decoder! %d\n", outputStatus);
+        mCallback->Error();
+      } else {
+        // We have a valid buffer index >= 0 here
+        if (bufferInfo.getFlags() & MediaCodec::getBUFFER_FLAG_END_OF_STREAM()) {
+          outputDone = true;
+        }
+
+        MOZ_ASSERT(!mDurations.empty(), "Should have had a duration queued");
+
+        Microseconds duration = 0;
+        if (!mDurations.empty()) {
+          duration = mDurations.front();
+          mDurations.pop();
+        }
+
+        jobject buffer = env->GetObjectArrayElement(mOutputBuffers, outputStatus);
+        if (buffer) {
+          // The buffer will be null on Android L if we are decoding to a Surface
+          void* directBuffer = env->GetDirectBufferAddress(buffer);
+          Output(&bufferInfo, directBuffer, outputFormat, duration);
+        }
+
+        // The Surface will be updated at this point (for video)
+        mDecoder->ReleaseOutputBuffer(outputStatus, true);
+
+        PostOutput(&bufferInfo, outputFormat, duration);
+
+        if (buffer) {
+          env->DeleteLocalRef(buffer);
+        }
+      }
+    }
+  }
+
+  // We're done
+  mMonitor.Lock();
+  mStopping = false;
+  mMonitor.Notify();
+  mMonitor.Unlock();
+}
+
+void MediaCodecDataDecoder::ClearQueue()
+{
+  mMonitor.AssertCurrentThreadOwns();
+  while (!mQueue.empty()) {
+    delete mQueue.front();
+    mQueue.pop();
+  }
+  while (!mDurations.empty()) {
+    mDurations.pop();
+  }
+}
+
+nsresult MediaCodecDataDecoder::Input(mp4_demuxer::MP4Sample* aSample) {
+  MonitorAutoLock lock(mMonitor);
+  mQueue.push(aSample);
+  lock.NotifyAll();
+
+  return NS_OK;
+}
+
+void MediaCodecDataDecoder::ResetInputBuffers()
+{
+  JNIEnv* env = GetJNIForThread();
+
+  if (mInputBuffers) {
+    env->DeleteGlobalRef(mInputBuffers);
+  }
+
+  mInputBuffers = (jobjectArray) env->NewGlobalRef(mDecoder->GetInputBuffers());
+}
+
+void MediaCodecDataDecoder::ResetOutputBuffers()
+{
+  JNIEnv* env = GetJNIForThread();
+
+  if (mOutputBuffers) {
+    env->DeleteGlobalRef(mOutputBuffers);
+  }
+
+  mOutputBuffers = (jobjectArray) env->NewGlobalRef(mDecoder->GetOutputBuffers());
+}
+
+nsresult MediaCodecDataDecoder::Flush() {
+  Drain();
+  return NS_OK;
+}
+
+nsresult MediaCodecDataDecoder::Drain() {
+  MonitorAutoLock lock(mMonitor);
+  mDraining = true;
+  lock.Notify();
+
+  while (mDraining) {
+    lock.Wait();
+  }
+
+  mCallback->DrainComplete();
+  return NS_OK;
+}
+
+
+nsresult MediaCodecDataDecoder::Shutdown() {
+  MonitorAutoLock lock(mMonitor);
+
+  if (!mThread || mStopping) {
+    // Already shutdown or in the process of doing so
+    return NS_OK;
+  }
+
+  mStopping = true;
+  lock.Notify();
+
+  while (mStopping) {
+    lock.Wait();
+  }
+
+  mThread->Shutdown();
+  mThread = nullptr;
+
+  mDecoder->Stop();
+  mDecoder->Release();
+  return NS_OK;
+}
+
+} // mozilla
new file mode 100644
--- /dev/null
+++ b/content/media/fmp4/android/AndroidDecoderModule.h
@@ -0,0 +1,109 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef AndroidDecoderModule_h_
+#define AndroidDecoderModule_h_
+
+#include "PlatformDecoderModule.h"
+#include "AndroidJavaWrappers.h"
+#include "AndroidSurfaceTexture.h"
+
+#include "GeneratedSDKWrappers.h"
+#include "mozilla/Monitor.h"
+
+#include <queue>
+
+namespace mozilla {
+
+typedef std::queue<mp4_demuxer::MP4Sample*> SampleQueue;
+
+namespace widget {
+namespace android {
+  class MediaCodec;
+  class MediaFormat;
+  class ByteBuffer;
+}
+}
+
+class MediaCodecDataDecoder;
+
+class AndroidDecoderModule : public PlatformDecoderModule {
+public:
+  virtual nsresult Shutdown() MOZ_OVERRIDE;
+
+  virtual already_AddRefed<MediaDataDecoder>
+  CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
+                    layers::LayersBackend aLayersBackend,
+                    layers::ImageContainer* aImageContainer,
+                    MediaTaskQueue* aVideoTaskQueue,
+                    MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
+
+  virtual already_AddRefed<MediaDataDecoder>
+  CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
+                     MediaTaskQueue* aAudioTaskQueue,
+                     MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE;
+
+
+  AndroidDecoderModule() {}
+  virtual ~AndroidDecoderModule() {}
+
+  virtual bool SupportsAudioMimeType(const char* aMimeType) MOZ_OVERRIDE;
+};
+
+class MediaCodecDataDecoder : public MediaDataDecoder {
+public:
+
+  MediaCodecDataDecoder(MediaData::Type aType,
+                        const char* aMimeType,
+                        mozilla::widget::android::MediaFormat* aFormat,
+                        MediaDataDecoderCallback* aCallback);
+
+  virtual ~MediaCodecDataDecoder();
+
+  virtual nsresult Init() MOZ_OVERRIDE;
+  virtual nsresult Flush() MOZ_OVERRIDE;
+  virtual nsresult Drain() MOZ_OVERRIDE;
+  virtual nsresult Shutdown() MOZ_OVERRIDE;
+  virtual nsresult Input(mp4_demuxer::MP4Sample* aSample);
+
+protected:
+  friend class AndroidDecoderModule;
+
+  MediaData::Type mType;
+
+  nsAutoPtr<char> mMimeType;
+  nsAutoPtr<mozilla::widget::android::MediaFormat> mFormat;
+
+  MediaDataDecoderCallback* mCallback;
+
+  nsAutoPtr<mozilla::widget::android::MediaCodec> mDecoder;
+
+  jobjectArray mInputBuffers;
+  jobjectArray mOutputBuffers;
+
+  nsCOMPtr<nsIThread> mThread;
+
+  // Only these members are protected by mMonitor.
+  Monitor mMonitor;
+  bool mDraining;
+  bool mStopping;
+
+  SampleQueue mQueue;
+  std::queue<Microseconds> mDurations;
+
+  virtual nsresult InitDecoder(jobject aSurface = nullptr);
+
+  virtual nsresult Output(mozilla::widget::android::BufferInfo* aInfo, void* aBuffer, mozilla::widget::android::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; }
+  virtual nsresult PostOutput(mozilla::widget::android::BufferInfo* aInfo, mozilla::widget::android::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; }
+
+  void ResetInputBuffers();
+  void ResetOutputBuffers();
+
+  void DecoderLoop();
+  virtual void ClearQueue();
+};
+
+} // namwspace mozilla
+
+#endif
--- a/content/media/fmp4/apple/AppleATDecoder.cpp
+++ b/content/media/fmp4/apple/AppleATDecoder.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <AudioToolbox/AudioToolbox.h>
 #include "AppleUtils.h"
 #include "MP4Reader.h"
 #include "MP4Decoder.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/ReentrantMonitor.h"
+#include "mp4_demuxer/Adts.h"
 #include "mp4_demuxer/DecoderData.h"
 #include "nsIThread.h"
 #include "AppleATDecoder.h"
 #include "prlog.h"
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* GetAppleMediaLog();
 #define LOG(...) PR_LOG(GetAppleMediaLog(), PR_LOG_DEBUG, (__VA_ARGS__))
@@ -350,16 +351,29 @@ AppleATDecoder::SetupDecoder()
     mConverter = nullptr;
     mCallback->Error();
   }
 }
 
 void
 AppleATDecoder::SubmitSample(nsAutoPtr<mp4_demuxer::MP4Sample> aSample)
 {
+  // Prepend ADTS header to AAC audio.
+  if (!strcmp(mConfig.mime_type, "audio/mp4a-latm")) {
+    bool rv = mp4_demuxer::Adts::ConvertSample(mConfig.channel_count,
+                                               mConfig.frequency_index,
+                                               mConfig.aac_profile,
+                                               aSample);
+    if (!rv) {
+      NS_ERROR("Failed to apply ADTS header");
+      mCallback->Error();
+      return;
+    }
+  }
+  // Push the sample to the AudioFileStream for parsing.
   mSamplePosition = aSample->byte_offset;
   mCurrentAudioTimestamp = aSample->composition_timestamp;
   uint32_t flags = mFlushed ? kAudioFileStreamParseFlag_Discontinuity : 0;
   OSStatus rv = AudioFileStreamParseBytes(mStream,
                                           aSample->size,
                                           aSample->data,
                                           flags);
   if (rv != noErr) {
--- a/content/media/fmp4/ffmpeg/FFmpegAudioDecoder.cpp
+++ b/content/media/fmp4/ffmpeg/FFmpegAudioDecoder.cpp
@@ -3,29 +3,31 @@
 /* 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 "MediaTaskQueue.h"
 #include "FFmpegRuntimeLinker.h"
 
 #include "FFmpegAudioDecoder.h"
+#include "mp4_demuxer/Adts.h"
 
 #define MAX_CHANNELS 16
 
 typedef mp4_demuxer::MP4Sample MP4Sample;
 
 namespace mozilla
 {
 
 FFmpegAudioDecoder<LIBAV_VER>::FFmpegAudioDecoder(
   MediaTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback,
   const mp4_demuxer::AudioDecoderConfig& aConfig)
   : FFmpegDataDecoder(aTaskQueue, GetCodecId(aConfig.mime_type))
   , mCallback(aCallback)
+  , mConfig(aConfig)
 {
   MOZ_COUNT_CTOR(FFmpegAudioDecoder);
 }
 
 nsresult
 FFmpegAudioDecoder<LIBAV_VER>::Init()
 {
   nsresult rv = FFmpegDataDecoder::Init();
@@ -78,16 +80,29 @@ CopyAndPackAudio(AVFrame* aFrame, uint32
   }
 
   return audio.forget();
 }
 
 void
 FFmpegAudioDecoder<LIBAV_VER>::DecodePacket(MP4Sample* aSample)
 {
+  // Prepend ADTS header to AAC audio.
+  if (!strcmp(mConfig.mime_type, "audio/mp4a-latm")) {
+    bool rv = mp4_demuxer::Adts::ConvertSample(mConfig.channel_count,
+                                               mConfig.frequency_index,
+                                               mConfig.aac_profile,
+                                               aSample);
+    if (!rv) {
+      NS_ERROR("Failed to apply ADTS header");
+      mCallback->Error();
+      return;
+    }
+  }
+
   AVPacket packet;
   av_init_packet(&packet);
 
   aSample->Pad(FF_INPUT_BUFFER_PADDING_SIZE);
   packet.data = aSample->data;
   packet.size = aSample->size;
   packet.pos = aSample->byte_offset;
 
--- a/content/media/fmp4/ffmpeg/FFmpegAudioDecoder.h
+++ b/content/media/fmp4/ffmpeg/FFmpegAudioDecoder.h
@@ -30,13 +30,14 @@ public:
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
   virtual nsresult Drain() MOZ_OVERRIDE;
   static AVCodecID GetCodecId(const char* aMimeType);
 
 private:
   void DecodePacket(mp4_demuxer::MP4Sample* aSample);
 
   MediaDataDecoderCallback* mCallback;
+  const mp4_demuxer::AudioDecoderConfig& mConfig;
 };
 
 } // namespace mozilla
 
 #endif // __FFmpegAACDecoder_h__
--- a/content/media/fmp4/gonk/GonkAudioDecoderManager.cpp
+++ b/content/media/fmp4/gonk/GonkAudioDecoderManager.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "MediaCodecProxy.h"
 #include <OMX_IVCommon.h>
 #include <gui/Surface.h>
 #include <ICrypto.h>
 #include "GonkAudioDecoderManager.h"
 #include "MediaDecoderReader.h"
+#include "mp4_demuxer/Adts.h"
 #include "VideoUtils.h"
 #include "nsTArray.h"
 #include "prlog.h"
 #include "stagefright/MediaBuffer.h"
 #include "stagefright/MetaData.h"
 #include "stagefright/MediaErrors.h"
 #include <stagefright/foundation/AMessage.h>
 #include <stagefright/foundation/ALooper.h>
@@ -37,21 +38,26 @@ typedef android::MediaCodecProxy MediaCo
 namespace mozilla {
 
 GonkAudioDecoderManager::GonkAudioDecoderManager(
   const mp4_demuxer::AudioDecoderConfig& aConfig)
   : mAudioChannels(aConfig.channel_count)
   , mAudioRate(aConfig.samples_per_second)
   , mAudioProfile(aConfig.aac_profile)
   , mAudioBuffer(nullptr)
+  , mUseAdts(true)
 {
   MOZ_COUNT_CTOR(GonkAudioDecoderManager);
   MOZ_ASSERT(mAudioChannels);
   mUserData.AppendElements(&aConfig.audio_specific_config[0],
                            aConfig.audio_specific_config.length());
+  // Pass through mp3 without applying an ADTS header.
+  if (strcmp(aConfig.mime_type, "audio/mp4a-latm") != 0) {
+      mUseAdts = false;
+  }
 }
 
 GonkAudioDecoderManager::~GonkAudioDecoderManager()
 {
   MOZ_COUNT_DTOR(GonkAudioDecoderManager);
 }
 
 android::sp<MediaCodecProxy>
@@ -210,16 +216,28 @@ void GonkAudioDecoderManager::ReleaseAud
 
 nsresult
 GonkAudioDecoderManager::Input(mp4_demuxer::MP4Sample* aSample)
 {
   if (mDecoder == nullptr) {
     ALOG("Decoder is not inited");
     return NS_ERROR_UNEXPECTED;
   }
+  if (aSample && mUseAdts) {
+    int8_t frequency_index =
+        mp4_demuxer::Adts::GetFrequencyIndex(mAudioRate);
+    bool rv = mp4_demuxer::Adts::ConvertSample(mAudioChannels,
+                                               frequency_index,
+                                               mAudioProfile,
+                                               aSample);
+    if (!rv) {
+      ALOG("Failed to apply ADTS header");
+      return NS_ERROR_FAILURE;
+    }
+  }
 
   status_t rv;
   if (aSample) {
     const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
     uint32_t length = aSample->size;
     rv = mDecoder->Input(data, length, aSample->composition_timestamp, 0);
   } else {
     // Inputted data is null, so it is going to notify decoder EOS
--- a/content/media/fmp4/gonk/GonkAudioDecoderManager.h
+++ b/content/media/fmp4/gonk/GonkAudioDecoderManager.h
@@ -40,16 +40,17 @@ private:
   void ReleaseAudioBuffer();
   // MediaCodedc's wrapper that performs the decoding.
   android::sp<MediaCodecProxy> mDecoder;
 
   const uint32_t mAudioChannels;
   const uint32_t mAudioRate;
   const uint32_t mAudioProfile;
   nsTArray<uint8_t> mUserData;
+  bool mUseAdts;
 
   MediaDataDecoderCallback*  mReaderCallback;
   android::MediaBuffer* mAudioBuffer;
   android::sp<ALooper> mLooper;
 };
 
 } // namespace mozilla
 
--- a/content/media/fmp4/moz.build
+++ b/content/media/fmp4/moz.build
@@ -20,17 +20,17 @@ SOURCES += [
     'MP4Reader.cpp',
 ]
 
 if CONFIG['MOZ_WMF']:
     DIRS += [ 'wmf' ];
 
 if CONFIG['MOZ_EME']:
     DIRS += ['eme']
-    
+
 if CONFIG['MOZ_FFMPEG']:
     EXPORTS += [
         'ffmpeg/FFmpegRuntimeLinker.h',
     ]
     UNIFIED_SOURCES += [
         'ffmpeg/FFmpegLog.cpp',
         'ffmpeg/FFmpegRuntimeLinker.cpp',
     ]
@@ -62,14 +62,22 @@ if CONFIG['MOZ_APPLEMEDIA']:
   ]
 
 if CONFIG['ANDROID_VERSION'] >= '18'and CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     DEFINES['MOZ_GONK_MEDIACODEC'] = True
     DIRS += ['gonk']
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
+    EXPORTS += [
+        'android/AndroidDecoderModule.h',
+    ]
+    UNIFIED_SOURCES += [
+        'android/AndroidDecoderModule.cpp',
+    ]
+
 FINAL_LIBRARY = 'xul'
 
 FAIL_ON_WARNINGS = True
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     DEFINES['NOMINMAX'] = True
--- a/content/media/fmp4/wmf/WMFAudioMFTManager.cpp
+++ b/content/media/fmp4/wmf/WMFAudioMFTManager.cpp
@@ -17,17 +17,18 @@ PRLogModuleInfo* GetDemuxerLog();
 #define LOG(...) PR_LOG(GetDemuxerLog(), PR_LOG_DEBUG, (__VA_ARGS__))
 #else
 #define LOG(...)
 #endif
 
 namespace mozilla {
 
 static void
-AACAudioSpecificConfigToUserData(const uint8_t* aAudioSpecConfig,
+AACAudioSpecificConfigToUserData(uint8_t aAACProfileLevelIndication,
+                                 const uint8_t* aAudioSpecConfig,
                                  uint32_t aConfigLength,
                                  nsTArray<BYTE>& aOutUserData)
 {
   MOZ_ASSERT(aOutUserData.IsEmpty());
 
   // The MF_MT_USER_DATA for AAC is defined here:
   // http://msdn.microsoft.com/en-us/library/windows/desktop/dd742784%28v=vs.85%29.aspx
   //
@@ -54,18 +55,18 @@ AACAudioSpecificConfigToUserData(const u
   //      DWORD        dwReserved2;
   //    }
   const UINT32 heeInfoLen = 4 * sizeof(WORD) + sizeof(DWORD);
 
   // The HEAACWAVEINFO must have payload and profile set,
   // the rest can be all 0x00.
   BYTE heeInfo[heeInfoLen] = {0};
   WORD* w = (WORD*)heeInfo;
-  w[0] = 0x1; // Payload type ADTS
-  w[1] = 0xFE; // Profile level indication, none specified.
+  w[0] = 0x0; // Payload type raw AAC packet
+  w[1] = aAACProfileLevelIndication;
 
   aOutUserData.AppendElements(heeInfo, heeInfoLen);
   aOutUserData.AppendElements(aAudioSpecConfig, aConfigLength);
 }
 
 WMFAudioMFTManager::WMFAudioMFTManager(
   const mp4_demuxer::AudioDecoderConfig& aConfig)
   : mAudioChannels(aConfig.channel_count)
@@ -76,17 +77,18 @@ WMFAudioMFTManager::WMFAudioMFTManager(
   , mMustRecaptureAudioPosition(true)
 {
   MOZ_COUNT_CTOR(WMFAudioMFTManager);
 
   if (!strcmp(aConfig.mime_type, "audio/mpeg")) {
     mStreamType = MP3;
   } else if (!strcmp(aConfig.mime_type, "audio/mp4a-latm")) {
     mStreamType = AAC;
-    AACAudioSpecificConfigToUserData(&aConfig.audio_specific_config[0],
+    AACAudioSpecificConfigToUserData(aConfig.aac_profile,
+                                     &aConfig.audio_specific_config[0],
                                      aConfig.audio_specific_config.length(),
                                      mUserData);
   } else {
     mStreamType = Unknown;
   }
 }
 
 WMFAudioMFTManager::~WMFAudioMFTManager()
@@ -140,17 +142,17 @@ WMFAudioMFTManager::Init()
 
   hr = type->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, mAudioRate);
   NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
 
   hr = type->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, mAudioChannels);
   NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
 
   if (mStreamType == AAC) {
-    hr = type->SetUINT32(MF_MT_AAC_PAYLOAD_TYPE, 0x1); // ADTS
+    hr = type->SetUINT32(MF_MT_AAC_PAYLOAD_TYPE, 0x0); // Raw AAC packet
     NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
 
     hr = type->SetBlob(MF_MT_USER_DATA,
                        mUserData.Elements(),
                        mUserData.Length());
     NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
   }
 
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -1153,18 +1153,22 @@ nsXULElement::AfterSetAttr(int32_t aName
                     }
                 }
                 else if (aName == nsGkAtoms::lwtheme ||
                          aName == nsGkAtoms::lwthemetextcolor) {
                     // if the lwtheme changed, make sure to reset the document lwtheme cache
                     nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(document);
                     if (xuldoc) {
                         xuldoc->ResetDocumentLWTheme();
+                        UpdateBrightTitlebarForeground(document);
                     }
                 }
+                else if (aName == nsGkAtoms::brighttitlebarforeground) {
+                    UpdateBrightTitlebarForeground(document);
+                }
             }
     
             if (aName == nsGkAtoms::src && document) {
                 LoadSrc();
             }
         } else  {
             if (mNodeInfo->Equals(nsGkAtoms::window)) {
                 if (aName == nsGkAtoms::hidechrome) {
@@ -1190,18 +1194,22 @@ nsXULElement::AfterSetAttr(int32_t aName
                     }
                 }
                 else if ((aName == nsGkAtoms::lwtheme ||
                           aName == nsGkAtoms::lwthemetextcolor)) {
                     // if the lwtheme changed, make sure to restyle appropriately
                     nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(doc);
                     if (xuldoc) {
                         xuldoc->ResetDocumentLWTheme();
+                        UpdateBrightTitlebarForeground(doc);
                     }
                 }
+                else if (aName == nsGkAtoms::brighttitlebarforeground) {
+                    UpdateBrightTitlebarForeground(doc);
+                }
                 else if (aName == nsGkAtoms::drawintitlebar) {
                     SetDrawsInTitlebar(false);
                 }
                 else if (aName == nsGkAtoms::drawtitle) {
                     SetDrawsTitle(false);
                 }
             }
         }
@@ -1979,16 +1987,32 @@ nsXULElement::SetDrawsTitle(bool aState)
     nsIWidget* mainWidget = GetWindowWidget();
     if (mainWidget) {
         // We can do this synchronously because SetDrawsTitle doesn't have any
         // synchronous effects apart from a harmless invalidation.
         mainWidget->SetDrawsTitle(aState);
     }
 }
 
+void
+nsXULElement::UpdateBrightTitlebarForeground(nsIDocument* aDoc)
+{
+    nsIWidget* mainWidget = GetWindowWidget();
+    if (mainWidget) {
+        // We can do this synchronously because SetBrightTitlebarForeground doesn't have any
+        // synchronous effects apart from a harmless invalidation.
+        mainWidget->SetUseBrightTitlebarForeground(
+          aDoc->GetDocumentLWTheme() == nsIDocument::Doc_Theme_Bright ||
+          aDoc->GetRootElement()->AttrValueIs(kNameSpaceID_None,
+                                              nsGkAtoms::brighttitlebarforeground,
+                                              NS_LITERAL_STRING("true"),
+                                              eCaseMatters));
+    }
+}
+
 class MarginSetter : public nsRunnable
 {
 public:
     explicit MarginSetter(nsIWidget* aWidget) :
         mWidget(aWidget), mMargin(-1, -1, -1, -1)
     {}
     MarginSetter(nsIWidget *aWidget, const nsIntMargin& aMargin) :
         mWidget(aWidget), mMargin(aMargin)
--- a/content/xul/content/src/nsXULElement.h
+++ b/content/xul/content/src/nsXULElement.h
@@ -688,16 +688,17 @@ protected:
     // attribute setters for widget
     nsresult HideWindowChrome(bool aShouldHide);
     void SetChromeMargins(const nsAttrValue* aValue);
     void ResetChromeMargins();
     void SetTitlebarColor(nscolor aColor, bool aActive);
 
     void SetDrawsInTitlebar(bool aState);
     void SetDrawsTitle(bool aState);
+    void UpdateBrightTitlebarForeground(nsIDocument* aDocument);
 
     void RemoveBroadcaster(const nsAString & broadcasterId);
 
 protected:
     // Internal accessor. This shadows the 'Slots', and returns
     // appropriate value.
     nsIControllers *Controllers() {
       nsDOMSlots* slots = GetExistingDOMSlots();
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -45,17 +45,16 @@ skip-if = buildapp == 'mulet' || buildap
 [test_gsp-standards.html]
 [test_getFeature_with_perm.html]
 [test_getFeature_without_perm.html]
 [test_hasFeature.html]
 [test_history_document_open.html]
 [test_history_state_null.html]
 [test_Image_constructor.html]
 [test_innersize_scrollport.html]
-[test_location_searchParams.html]
 [test_messageChannel.html]
 [test_messageChannel_cloning.html]
 [test_messageChannel_pingpong.html]
 [test_messageChannel_post.html]
 [test_messageChannel_pref.html]
 [test_messageChannel_start.html]
 [test_messagemanager_targetchain.html]
 [test_messageChannel_transferable.html]
deleted file mode 100644
--- a/dom/base/test/test_location_searchParams.html
+++ /dev/null
@@ -1,89 +0,0 @@
-
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1037715
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 1037715</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.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=1037715">Mozilla Bug 1037715</a>
-  <iframe id="a"></iframe>
-  <script type="application/javascript">
-
-var l;
-
-var iframe = document.getElementById('a');
-function onload0() {
-  iframe.removeEventListener('load', onload0);
-
-  l = iframe.contentWindow.location;
-  is(l.searchParams.get('a'), 'test0', 'l.searchParams value is ok');
-
-  info('changing location from JS...');
-  iframe.addEventListener('load', onload1);
-  iframe.contentWindow.location.href = 'file_empty.html?a=test1';
-}
-
-function onload1() {
-  iframe.removeEventListener('load', onload1);
-
-  var ll = iframe.contentWindow.location;
-  is(ll.searchParams.get('a'), 'test1', 'location.searchParams value is ok');
-  is(l.searchParams.get('a'), 'test1', 'l.searchParams value is ok');
-  isnot(ll.searchParams, l.searchParams, '2 different objects.');
-
-  info('changing location using l.searchParams...');
-  iframe.addEventListener('load', onload2);
-  l.searchParams.set('a', 'test2');
-}
-
-function onload2() {
-  iframe.removeEventListener('load', onload2);
-
-  var ll = iframe.contentWindow.location;
-  is(ll.searchParams.get('a'), 'test2', 'location.searchParams value is ok');
-  is(l.searchParams.get('a'), 'test2', 'l.searchParams value is ok');
-  isnot(ll.searchParams, l.searchParams, '2 different objects.');
-
-  info('changing iframe.src...');
-  iframe.addEventListener('load', onload3);
-  l.search = 'a=test3';
-}
-
-function onload3() {
-  iframe.removeEventListener('load', onload3);
-
-  var ll = iframe.contentWindow.location;
-  is(ll.searchParams.get('a'), 'test3', 'location.searchParams value is ok');
-  is(l.searchParams.get('a'), 'test3', 'l.searchParams value is ok');
-  isnot(ll.searchParams, l.searchParams, '2 different objects.');
-
-  info('changing iframe.src...');
-  iframe.addEventListener('load', onload4);
-  iframe.src = 'file_empty.html?a=test4';
-}
-
-function onload4() {
-  iframe.removeEventListener('load', onload4);
-
-  var ll = iframe.contentWindow.location;
-  is(ll.searchParams.get('a'), 'test4', 'location.searchParams value is ok');
-  is(l.searchParams.get('a'), 'test4', 'l.searchParams value is ok');
-  isnot(ll.searchParams, l.searchParams, '2 different objects.');
-
-  SimpleTest.finish();
-}
-
-iframe.addEventListener('load', onload0);
-iframe.src = "file_empty.html?a=test0";
-SimpleTest.waitForExplicitFinish();
-
-  </script>
-
-</body>
-</html>
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -947,26 +947,27 @@ nsNPAPIPluginInstance::TextureInfo nsNPA
 }
 
 void nsNPAPIPluginInstance::ReleaseContentTexture(nsNPAPIPluginInstance::TextureInfo& aTextureInfo)
 {
   EnsureSharedTexture();
   mContentTexture->Release(aTextureInfo);
 }
 
-nsSurfaceTexture* nsNPAPIPluginInstance::CreateSurfaceTexture()
+AndroidSurfaceTexture* nsNPAPIPluginInstance::CreateSurfaceTexture()
 {
   if (!EnsureGLContext())
     return nullptr;
 
   GLuint texture = TexturePoolOGL::AcquireTexture();
   if (!texture)
     return nullptr;
 
-  nsSurfaceTexture* surface = nsSurfaceTexture::Create(texture);
+  AndroidSurfaceTexture* surface = AndroidSurfaceTexture::Create(TexturePoolOGL::GetGLContext(),
+                                                                 texture);
   if (!surface)
     return nullptr;
 
   nsCOMPtr<nsIRunnable> frameCallback = NS_NewRunnableMethod(this, &nsNPAPIPluginInstance::OnSurfaceTextureFrameAvailable);
   surface->SetFrameAvailableCallback(frameCallback);
   return surface;
 }
 
@@ -980,46 +981,46 @@ void* nsNPAPIPluginInstance::AcquireCont
 {
   if (!mContentSurface) {
     mContentSurface = CreateSurfaceTexture();
 
     if (!mContentSurface)
       return nullptr;
   }
 
-  return mContentSurface->GetNativeWindow();
+  return mContentSurface->NativeWindow()->Handle();
 }
 
 EGLImage
 nsNPAPIPluginInstance::AsEGLImage()
 {
   if (!mContentTexture)
     return 0;
 
   return mContentTexture->CreateEGLImage();
 }
 
-nsSurfaceTexture*
+AndroidSurfaceTexture*
 nsNPAPIPluginInstance::AsSurfaceTexture()
 {
   if (!mContentSurface)
     return nullptr;
 
   return mContentSurface;
 }
 
 void* nsNPAPIPluginInstance::AcquireVideoWindow()
 {
-  nsSurfaceTexture* surface = CreateSurfaceTexture();
+  AndroidSurfaceTexture* surface = CreateSurfaceTexture();
   if (!surface)
     return nullptr;
 
   VideoInfo* info = new VideoInfo(surface);
 
-  void* window = info->mSurfaceTexture->GetNativeWindow();
+  void* window = info->mSurfaceTexture->NativeWindow()->Handle();
   mVideos.insert(std::pair<void*, VideoInfo*>(window, info));
 
   return window;
 }
 
 void nsNPAPIPluginInstance::ReleaseVideoWindow(void* window)
 {
   std::map<void*, VideoInfo*>::iterator it = mVideos.find(window);
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -16,17 +16,17 @@
 #include "nsInterfaceHashtable.h"
 #include "nsHashKeys.h"
 #include <prinrval.h>
 #include "js/TypeDecls.h"
 #ifdef MOZ_WIDGET_ANDROID
 #include "nsAutoPtr.h"
 #include "nsIRunnable.h"
 #include "GLContextTypes.h"
-#include "nsSurfaceTexture.h"
+#include "AndroidSurfaceTexture.h"
 #include "AndroidBridge.h"
 #include <map>
 class PluginEventRunnable;
 class SharedPluginTexture;
 #endif
 
 #include "mozilla/TimeStamp.h"
 #include "mozilla/PluginLibrary.h"
@@ -187,32 +187,32 @@ public:
 
   TextureInfo LockContentTexture();
   void ReleaseContentTexture(TextureInfo& aTextureInfo);
 
   // For ANPNativeWindow
   void* AcquireContentWindow();
 
   EGLImage AsEGLImage();
-  nsSurfaceTexture* AsSurfaceTexture();
+  mozilla::gl::AndroidSurfaceTexture* AsSurfaceTexture();
 
   // For ANPVideo
   class VideoInfo {
   public:
-    VideoInfo(nsSurfaceTexture* aSurfaceTexture) :
+    VideoInfo(mozilla::gl::AndroidSurfaceTexture* aSurfaceTexture) :
       mSurfaceTexture(aSurfaceTexture)
     {
     }
 
     ~VideoInfo()
     {
       mSurfaceTexture = nullptr;
     }
 
-    nsRefPtr<nsSurfaceTexture> mSurfaceTexture;
+    nsRefPtr<mozilla::gl::AndroidSurfaceTexture> mSurfaceTexture;
     gfxRect mDimensions;
   };
 
   void* AcquireVideoWindow();
   void ReleaseVideoWindow(void* aWindow);
   void SetVideoDimensions(void* aWindow, gfxRect aDimensions);
 
   void GetVideos(nsTArray<VideoInfo*>& aVideos);
@@ -329,17 +329,17 @@ protected:
   void OnSurfaceTextureFrameAvailable();
 
   uint32_t mFullScreenOrientation;
   bool mWakeLocked;
   bool mFullScreen;
   bool mInverted;
 
   nsRefPtr<SharedPluginTexture> mContentTexture;
-  nsRefPtr<nsSurfaceTexture> mContentSurface;
+  nsRefPtr<mozilla::gl::AndroidSurfaceTexture> mContentSurface;
 #endif
 
   enum {
     NOT_STARTED,
     RUNNING,
     DESTROYING,
     DESTROYED
   } mRunning;
@@ -378,17 +378,17 @@ private:
   void* mCurrentPluginEvent;
 
   // Timestamp for the last time this plugin was stopped.
   // This is only valid when the plugin is actually stopped!
   mozilla::TimeStamp mStopTime;
 
 #ifdef MOZ_WIDGET_ANDROID
   void EnsureSharedTexture();
-  nsSurfaceTexture* CreateSurfaceTexture();
+  mozilla::gl::AndroidSurfaceTexture* CreateSurfaceTexture();
 
   std::map<void*, VideoInfo*> mVideos;
   bool mOnScreen;
 
   nsIntSize mCurrentSize;
 #endif
 
   // is this instance Java and affected by bug 750480?
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -180,17 +180,17 @@ static void
 AttachToContainerAsSurfaceTexture(ImageContainer* container,
                                   nsNPAPIPluginInstance* instance,
                                   const LayoutDeviceRect& rect,
                                   nsRefPtr<Image>* out_image)
 {
   MOZ_ASSERT(out_image);
   MOZ_ASSERT(!*out_image);
 
-  nsSurfaceTexture* surfTex = instance->AsSurfaceTexture();
+  mozilla::gl::AndroidSurfaceTexture* surfTex = instance->AsSurfaceTexture();
   if (!surfTex) {
     return;
   }
 
   nsRefPtr<Image> img = container->CreateImage(ImageFormat::SURFACE_TEXTURE);
 
   SurfaceTextureImage::Data data;
   data.mSurfTex = surfTex;
--- a/dom/webidl/HTMLAnchorElement.webidl
+++ b/dom/webidl/HTMLAnchorElement.webidl
@@ -26,16 +26,17 @@ interface HTMLAnchorElement : HTMLElemen
            attribute DOMString hreflang;
            [SetterThrows]
            attribute DOMString type;
 
            [SetterThrows]
            attribute DOMString text;
 };
 HTMLAnchorElement implements URLUtils;
+HTMLAnchorElement implements URLUtilsSearchParams;
 
 // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
 partial interface HTMLAnchorElement {
            [SetterThrows]
            attribute DOMString coords;
            [SetterThrows]
            attribute DOMString charset;
            [SetterThrows]
--- a/dom/webidl/HTMLAreaElement.webidl
+++ b/dom/webidl/HTMLAreaElement.webidl
@@ -33,14 +33,15 @@ interface HTMLAreaElement : HTMLElement 
   // not implemented.
   //
   //       [SetterThrows]
   //       attribute DOMString hreflang;
   //       [SetterThrows]
   //       attribute DOMString type;
 };
 HTMLAreaElement implements URLUtils;
+HTMLAreaElement implements URLUtilsSearchParams;
 
 // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
 partial interface HTMLAreaElement {
            [SetterThrows]
            attribute boolean noHref;
 };
--- a/dom/webidl/Location.webidl
+++ b/dom/webidl/Location.webidl
@@ -16,10 +16,11 @@ interface Location {
   [Throws]
   void assign(DOMString url);
   [Throws, CrossOriginCallable]
   void replace(DOMString url);
   // XXXbz there is no forceget argument in the spec!  See bug 1037721.
   [Throws]
   void reload(optional boolean forceget = false);
 };
-// No support for .searchParams on Location yet.  See bug 1037715.
+// No support for .searchParams on Location yet.  See bug 1082734.
+
 Location implements URLUtils;
--- a/dom/webidl/URL.webidl
+++ b/dom/webidl/URL.webidl
@@ -14,16 +14,17 @@
 
 // [Constructor(DOMString url, optional (URL or DOMString) base = "about:blank")]
 [Constructor(DOMString url, URL base),
  Constructor(DOMString url, optional DOMString base = "about:blank"),
  Exposed=(Window,Worker)]
 interface URL {
 };
 URL implements URLUtils;
+URL implements URLUtilsSearchParams;
 
 partial interface URL {
   [Throws]
   static DOMString? createObjectURL(Blob blob, optional objectURLOptions options);
   [Throws]
   static DOMString? createObjectURL(MediaStream stream, optional objectURLOptions options);
   static void revokeObjectURL(DOMString url);
 };
--- a/dom/webidl/URLUtils.webidl
+++ b/dom/webidl/URLUtils.webidl
@@ -35,17 +35,21 @@ interface URLUtils {
            attribute DOMString hostname;
   [Throws]
            attribute DOMString port;
   [Throws]
            attribute DOMString pathname;
   [Throws]
            attribute DOMString search;
 
-           attribute URLSearchParams searchParams;
-
   [Throws]
            attribute DOMString hash;
 
   // Bug 824857 should remove this.
   [Throws]
   stringifier;
 };
+
+[NoInterfaceObject,
+ Exposed=(Window, Worker)]
+interface URLUtilsSearchParams {
+           attribute URLSearchParams searchParams;
+};
new file mode 100644
--- /dev/null
+++ b/gfx/gl/AndroidNativeWindow.cpp
@@ -0,0 +1,281 @@
+#ifdef MOZ_WIDGET_ANDROID
+
+#include "AndroidNativeWindow.h"
+#include "prlink.h"
+
+// #define ANDROID_NATIVE_WINDOW_DEBUG
+
+#if defined(ANDROID_NATIVE_WINDOW_DEBUG) || defined(DEBUG)
+#define ALOG(args...)  __android_log_print(ANDROID_LOG_INFO, "AndroidNativeWindow" , ## args)
+#else
+#define ALOG(args...) ((void)0)
+#endif
+
+using namespace mozilla::gfx;
+using namespace mozilla::gl;
+using namespace mozilla;
+
+class NativeWindowLibrary
+{
+public:
+
+  NativeWindowLibrary()
+    : fANativeWindow_fromSurface(nullptr)
+    , fANativeWindow_release(nullptr)
+    , fANativeWindow_setBuffersGeometry(nullptr)
+    , fANativeWindow_lock(nullptr)
+    , fANativeWindow_unlockAndPost(nullptr)
+    , fANativeWindow_getFormat(nullptr)
+    , fANativeWindow_getWidth(nullptr)
+    , fANativeWindow_getHeight(nullptr)
+  {
+    PRLibrary* lib = PR_LoadLibrary("libandroid.so");
+
+    fANativeWindow_fromSurface = (pfnANativeWindow_fromSurface)PR_FindSymbol(lib, "ANativeWindow_fromSurface");
+    fANativeWindow_release = (pfnANativeWindow_release)PR_FindSymbol(lib, "ANativeWindow_release");
+    fANativeWindow_setBuffersGeometry = (pfnANativeWindow_setBuffersGeometry)PR_FindSymbol(lib, "ANativeWindow_setBuffersGeometry");
+    fANativeWindow_lock = (pfnANativeWindow_lock)PR_FindSymbol(lib, "ANativeWindow_lock");
+    fANativeWindow_unlockAndPost = (pfnANativeWindow_unlockAndPost)PR_FindSymbol(lib, "ANativeWindow_unlockAndPost");
+    fANativeWindow_getFormat = (pfnANativeWindow_getFormat)PR_FindSymbol(lib, "ANativeWindow_getFormat");
+    fANativeWindow_getWidth = (pfnANativeWindow_getWidth)PR_FindSymbol(lib, "ANativeWindow_getWidth");
+    fANativeWindow_getHeight = (pfnANativeWindow_getHeight)PR_FindSymbol(lib, "ANativeWindow_getHeight");
+  }
+
+  void* ANativeWindow_fromSurface(JNIEnv* aEnv, jobject aSurface) {
+    ALOG("%s: env=%p, surface=%p\n", __PRETTY_FUNCTION__, aEnv, aSurface);
+    if (!Initialized()) {
+      return nullptr;
+    }
+
+    return fANativeWindow_fromSurface(aEnv, aSurface);
+  }
+
+  void ANativeWindow_release(void* aWindow) {
+    ALOG("%s: window=%p\n", __PRETTY_FUNCTION__, aWindow);
+    if (!Initialized()) {
+      return;
+    }
+
+    fANativeWindow_release(aWindow);
+  }
+
+  bool ANativeWindow_setBuffersGeometry(void* aWindow, int32_t aWidth, int32_t aHeight, int32_t aFormat) {
+    ALOG("%s: window=%p, width=%d, height=%d, format=%d\n", __PRETTY_FUNCTION__, aWindow, aWidth, aHeight, aFormat);
+    if (!Initialized()) {
+      return nullptr;
+    }
+
+    return fANativeWindow_setBuffersGeometry(aWindow, aWidth, aHeight, (int32_t)aFormat) == 0;
+  }
+
+  bool ANativeWindow_lock(void* aWindow, void* out_buffer, void*in_out_dirtyBounds) {
+    ALOG("%s: window=%p, out_buffer=%p, in_out_dirtyBounds=%p\n", __PRETTY_FUNCTION__,
+         aWindow, out_buffer, in_out_dirtyBounds);
+    if (!Initialized()) {
+      return false;
+    }
+
+    return fANativeWindow_lock(aWindow, out_buffer, in_out_dirtyBounds) == 0;
+  }
+
+  bool ANativeWindow_unlockAndPost(void* aWindow) {
+    ALOG("%s: window=%p\n", __PRETTY_FUNCTION__, aWindow);
+    if (!Initialized()) {
+      return false;
+    }
+
+    return fANativeWindow_unlockAndPost(aWindow) == 0;
+  }
+
+  AndroidWindowFormat ANativeWindow_getFormat(void* aWindow) {
+    ALOG("%s: window=%p\n", __PRETTY_FUNCTION__, aWindow);
+    if (!Initialized()) {
+      return AndroidWindowFormat::Unknown;
+    }
+
+    return (AndroidWindowFormat)fANativeWindow_getFormat(aWindow);
+  }
+
+  int32_t ANativeWindow_getWidth(void* aWindow) {
+    ALOG("%s: window=%p\n", __PRETTY_FUNCTION__, aWindow);
+    if (!Initialized()) {
+      return -1;
+    }
+
+    return fANativeWindow_getWidth(aWindow);
+  }
+
+  int32_t ANativeWindow_getHeight(void* aWindow) {
+    ALOG("%s: window=%p\n", __PRETTY_FUNCTION__, aWindow);
+    if (!Initialized()) {
+      return -1;
+    }
+
+    return fANativeWindow_getHeight(aWindow);
+  }
+
+  bool Initialized() {
+    return fANativeWindow_fromSurface && fANativeWindow_release && fANativeWindow_setBuffersGeometry
+      && fANativeWindow_lock && fANativeWindow_unlockAndPost && fANativeWindow_getFormat && fANativeWindow_getWidth
+      && fANativeWindow_getHeight;
+  }
+
+private:
+
+  typedef void* (*pfnANativeWindow_fromSurface)(JNIEnv* env, jobject surface);
+  pfnANativeWindow_fromSurface fANativeWindow_fromSurface;
+
+  typedef void (*pfnANativeWindow_release)(void* window);
+  pfnANativeWindow_release fANativeWindow_release;
+
+  typedef int32_t (*pfnANativeWindow_setBuffersGeometry)(void* window, int32_t width, int32_t height, int32_t format);
+  pfnANativeWindow_setBuffersGeometry fANativeWindow_setBuffersGeometry;
+
+  typedef int32_t (*pfnANativeWindow_lock)(void *window, void *out_buffer, void *in_out_dirtyBounds);
+  pfnANativeWindow_lock fANativeWindow_lock;
+
+  typedef int32_t (*pfnANativeWindow_unlockAndPost)(void *window);
+  pfnANativeWindow_unlockAndPost fANativeWindow_unlockAndPost;
+
+  typedef AndroidWindowFormat (*pfnANativeWindow_getFormat)(void* window);
+  pfnANativeWindow_getFormat fANativeWindow_getFormat;
+
+  typedef int32_t (*pfnANativeWindow_getWidth)(void* window);
+  pfnANativeWindow_getWidth fANativeWindow_getWidth;
+
+  typedef int32_t (*pfnANativeWindow_getHeight)(void* window);
+  pfnANativeWindow_getHeight fANativeWindow_getHeight;
+};
+
+static NativeWindowLibrary* sLibrary = nullptr;
+
+static bool
+EnsureInit()
+{
+  static bool initialized = false;
+  if (!initialized) {
+    if (!sLibrary) {
+      sLibrary = new NativeWindowLibrary();
+    }
+    initialized = sLibrary->Initialized();
+  }
+
+  return initialized;
+}
+
+
+namespace mozilla {
+
+/* static */ AndroidNativeWindow*
+AndroidNativeWindow::CreateFromSurface(JNIEnv* aEnv, jobject aSurface)
+{
+  if (!EnsureInit()) {
+    ALOG("Not initialized");
+    return nullptr;
+  }
+
+  void* window = sLibrary->ANativeWindow_fromSurface(aEnv, aSurface);
+  if (!window) {
+    ALOG("Failed to create window from surface");
+    return nullptr;
+  }
+
+  return new AndroidNativeWindow(window);
+}
+
+AndroidNativeWindow::~AndroidNativeWindow()
+{
+  if (EnsureInit() && mWindow) {
+    sLibrary->ANativeWindow_release(mWindow);
+    mWindow = nullptr;
+  }
+}
+
+IntSize
+AndroidNativeWindow::Size()
+{
+  MOZ_ASSERT(mWindow);
+  if (!EnsureInit()) {
+    return IntSize(0, 0);
+  }
+
+  return IntSize(sLibrary->ANativeWindow_getWidth(mWindow), sLibrary->ANativeWindow_getHeight(mWindow));
+}
+
+AndroidWindowFormat
+AndroidNativeWindow::Format()
+{
+  MOZ_ASSERT(mWindow);
+  if (!EnsureInit()) {
+    return AndroidWindowFormat::Unknown;
+  }
+
+  return sLibrary->ANativeWindow_getFormat(mWindow);
+}
+
+bool
+AndroidNativeWindow::SetBuffersGeometry(int32_t aWidth, int32_t aHeight, AndroidWindowFormat aFormat)
+{
+  MOZ_ASSERT(mWindow);
+  if (!EnsureInit())
+    return false;
+
+  return sLibrary->ANativeWindow_setBuffersGeometry(mWindow, aWidth, aHeight, (int32_t)aFormat);
+}
+
+bool
+AndroidNativeWindow::Lock(void** out_bits,int32_t* out_width, int32_t* out_height,
+                          int32_t* out_stride, AndroidWindowFormat* out_format)
+{
+  /* Copied from native_window.h in Android NDK (platform-9) */
+  typedef struct ANativeWindow_Buffer {
+      // The number of pixels that are show horizontally.
+      int32_t width;
+
+      // The number of pixels that are shown vertically.
+      int32_t height;
+
+      // The number of *pixels* that a line in the buffer takes in
+      // memory.  This may be >= width.
+      int32_t stride;
+
+      // The format of the buffer.  One of WINDOW_FORMAT_*
+      int32_t format;
+
+      // The actual bits.
+      void* bits;
+
+      // Do not touch.
+      uint32_t reserved[6];
+  } ANativeWindow_Buffer; 
+
+
+  ANativeWindow_Buffer buffer;
+
+  if (!sLibrary->ANativeWindow_lock(mWindow, &buffer, nullptr)) {
+    ALOG("Failed to lock");
+    return false;
+  }
+
+  *out_bits = buffer.bits;
+  *out_width = buffer.width;
+  *out_height = buffer.height;
+  *out_stride = buffer.stride;
+  *out_format = (AndroidWindowFormat)buffer.format;
+  return true;
+}
+
+bool
+AndroidNativeWindow::UnlockAndPost()
+{
+  if (!EnsureInit()) {
+    ALOG("Not initialized");
+    return false;
+  }
+
+  return sLibrary->ANativeWindow_unlockAndPost(mWindow);
+}
+
+}
+
+#endif // MOZ_WIDGET_ANDROID
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gfx/gl/AndroidNativeWindow.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+// vim:set ts=2 sts=2 sw=2 et cin:
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef AndroidNativeWindow_h__
+#define AndroidNativeWindow_h__
+#ifdef MOZ_WIDGET_ANDROID
+
+#include <jni.h>
+#include "GLDefs.h"
+
+#include "nsISupports.h"
+#include "mozilla/TypedEnum.h"
+#include "mozilla/gfx/2D.h"
+
+
+namespace mozilla {
+namespace gl {
+
+MOZ_BEGIN_ENUM_CLASS(AndroidWindowFormat)
+  Unknown = -1,
+  RGBA_8888 = 1,
+  RGBX_8888 = 1 << 1,
+  RGB_565 = 1 << 2
+MOZ_END_ENUM_CLASS(AndroidWindowFormat)
+
+/**
+ * This class is a wrapper around Android's SurfaceTexture class.
+ * Usage is pretty much exactly like the Java class, so see
+ * the Android documentation for details.
+ */
+class AndroidNativeWindow {
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AndroidNativeWindow)
+
+public:
+
+  static AndroidNativeWindow* CreateFromSurface(JNIEnv* aEnv, jobject aSurface);
+
+  gfx::IntSize Size();
+  AndroidWindowFormat Format();
+
+  bool SetBuffersGeometry(int32_t aWidth, int32_t aHeight, AndroidWindowFormat aFormat);
+
+  bool Lock(void** out_bits, int32_t* out_width, int32_t* out_height, int32_t* out_stride, AndroidWindowFormat* out_format);
+  bool UnlockAndPost();
+
+  void* Handle() { return mWindow; }
+
+protected:
+  AndroidNativeWindow(void* aWindow)
+    : mWindow(aWindow)
+  {
+
+  }
+
+  virtual ~AndroidNativeWindow();
+
+  void* mWindow;
+};
+
+}
+}
+
+
+#endif
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/gl/AndroidSurfaceTexture.cpp
@@ -0,0 +1,415 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+// vim:set ts=2 sts=2 sw=2 et cin:
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifdef MOZ_WIDGET_ANDROID
+
+#include <set>
+#include <map>
+#include <android/log.h>
+#include "AndroidSurfaceTexture.h"
+#include "gfxImageSurface.h"
+#include "AndroidBridge.h"
+#include "nsThreadUtils.h"
+#include "mozilla/gfx/Matrix.h"
+#include "GeneratedJNIWrappers.h"
+#include "GLContext.h"
+
+using namespace mozilla;
+using namespace mozilla::widget::android;
+
+namespace mozilla {
+namespace gl {
+
+// UGH
+static std::map<int, AndroidSurfaceTexture*> sInstances;
+static int sNextID = 0;
+
+static bool
+IsDetachSupported()
+{
+  return AndroidBridge::Bridge()->GetAPIVersion() >= 16; /* Jelly Bean */
+}
+
+static bool
+IsSTSupported()
+{
+  return AndroidBridge::Bridge()->GetAPIVersion() >= 14; /* ICS */
+}
+
+static class JNIFunctions {
+public:
+
+  JNIFunctions() : mInitialized(false)
+  {
+  }
+
+  bool EnsureInitialized()
+  {
+    if (mInitialized) {
+      return true;
+    }
+
+    if (!IsSTSupported()) {
+      return false;
+    }
+
+    JNIEnv* env = GetJNIForThread();
+
+    AutoLocalJNIFrame jniFrame(env);
+
+    jSurfaceTextureClass = (jclass)env->NewGlobalRef(env->FindClass("android/graphics/SurfaceTexture"));
+    jSurfaceTexture_Ctor = env->GetMethodID(jSurfaceTextureClass, "<init>", "(I)V");
+    jSurfaceTexture_updateTexImage = env->GetMethodID(jSurfaceTextureClass, "updateTexImage", "()V");
+    jSurfaceTexture_getTransformMatrix = env->GetMethodID(jSurfaceTextureClass, "getTransformMatrix", "([F)V");
+    jSurfaceTexture_setDefaultBufferSize = env->GetMethodID(jSurfaceTextureClass, "setDefaultBufferSize", "(II)V");
+
+    if (IsDetachSupported()) {
+      jSurfaceTexture_attachToGLContext = env->GetMethodID(jSurfaceTextureClass, "attachToGLContext", "(I)V");
+      jSurfaceTexture_detachFromGLContext = env->GetMethodID(jSurfaceTextureClass, "detachFromGLContext", "()V");
+    } else {
+      jSurfaceTexture_attachToGLContext = jSurfaceTexture_detachFromGLContext = 0;
+    }
+
+    jSurfaceClass = (jclass)env->NewGlobalRef(env->FindClass("android/view/Surface"));
+    jSurface_Ctor = env->GetMethodID(jSurfaceClass, "<init>", "(Landroid/graphics/SurfaceTexture;)V");
+
+    mInitialized = true;
+    return true;
+  }
+
+  jobject CreateSurfaceTexture(GLuint aTexture)
+  {
+    if (!EnsureInitialized())
+      return nullptr;
+
+    JNIEnv* env = GetJNIForThread();
+
+    AutoLocalJNIFrame jniFrame(env);
+
+    return env->NewGlobalRef(env->NewObject(jSurfaceTextureClass, jSurfaceTexture_Ctor, (int) aTexture));
+  }
+
+  jobject CreateSurface(jobject aSurfaceTexture)
+  {
+    if (!EnsureInitialized())
+      return nullptr;
+
+    JNIEnv* env = GetJNIForThread();
+    AutoLocalJNIFrame jniFrame(env);
+    return env->NewGlobalRef(env->NewObject(jSurfaceClass, jSurface_Ctor, aSurfaceTexture));
+  }
+
+  void ReleaseSurfaceTexture(jobject aSurfaceTexture)
+  {
+    JNIEnv* env = GetJNIForThread();
+
+    env->DeleteGlobalRef(aSurfaceTexture);
+  }
+
+  void UpdateTexImage(jobject aSurfaceTexture)
+  {
+    JNIEnv* env = GetJNIForThread();
+
+    AutoLocalJNIFrame jniFrame(env);
+    env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_updateTexImage);
+  }
+
+  bool GetTransformMatrix(jobject aSurfaceTexture, gfx::Matrix4x4& aMatrix)
+  {
+    JNIEnv* env = GetJNIForThread();
+
+    AutoLocalJNIFrame jniFrame(env);
+
+    jfloatArray jarray = env->NewFloatArray(16);
+    env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_getTransformMatrix, jarray);
+
+    jfloat* array = env->GetFloatArrayElements(jarray, nullptr);
+
+    aMatrix._11 = array[0];
+    aMatrix._12 = array[1];
+    aMatrix._13 = array[2];
+    aMatrix._14 = array[3];
+
+    aMatrix._21 = array[4];
+    aMatrix._22 = array[5];
+    aMatrix._23 = array[6];
+    aMatrix._24 = array[7];
+
+    aMatrix._31 = array[8];
+    aMatrix._32 = array[9];
+    aMatrix._33 = array[10];
+    aMatrix._34 = array[11];
+
+    aMatrix._41 = array[12];
+    aMatrix._42 = array[13];
+    aMatrix._43 = array[14];
+    aMatrix._44 = array[15];
+
+    env->ReleaseFloatArrayElements(jarray, array, 0);
+
+    return false;
+  }
+
+  void SetDefaultBufferSize(jobject aSurfaceTexture, int32_t width, int32_t height)
+  {
+    JNIEnv* env = GetJNIForThread();
+
+    AutoLocalJNIFrame jniFrame(env);
+    env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_setDefaultBufferSize, width, height);
+  }
+
+  void AttachToGLContext(jobject aSurfaceTexture, int32_t texName)
+  {
+    MOZ_ASSERT(jSurfaceTexture_attachToGLContext);
+
+    JNIEnv* env = GetJNIForThread();
+
+    env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_attachToGLContext, texName);
+    if (env->ExceptionCheck()) {
+      env->ExceptionDescribe();
+      env->ExceptionClear();
+    }
+  }
+
+  void DetachFromGLContext(jobject aSurfaceTexture)
+  {
+    MOZ_ASSERT(jSurfaceTexture_detachFromGLContext);
+
+    JNIEnv* env = GetJNIForThread();
+
+    env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_detachFromGLContext);
+    if (env->ExceptionCheck()) {
+      env->ExceptionDescribe();
+      env->ExceptionClear();
+    }
+  }
+
+private:
+  bool mInitialized;
+
+  jclass jSurfaceTextureClass;
+  jmethodID jSurfaceTexture_Ctor;
+  jmethodID jSurfaceTexture_updateTexImage;
+  jmethodID jSurfaceTexture_getTransformMatrix;
+  jmethodID jSurfaceTexture_setDefaultBufferSize;
+
+  jmethodID jSurfaceTexture_attachToGLContext;
+  jmethodID jSurfaceTexture_detachFromGLContext;
+
+  jclass jSurfaceClass;
+  jmethodID jSurface_Ctor;
+
+} sJNIFunctions;
+
+AndroidSurfaceTexture*
+AndroidSurfaceTexture::Create()
+{
+  return Create(nullptr, 0);
+}
+
+AndroidSurfaceTexture*
+AndroidSurfaceTexture::Create(GLContext* aContext, GLuint aTexture)
+{
+  if (!IsSTSupported()) {
+    return nullptr;
+  }
+
+  AndroidSurfaceTexture* st = new AndroidSurfaceTexture();
+  if (!st->Init(aContext, aTexture)) {
+    printf_stderr("Failed to initialize AndroidSurfaceTexture");
+    delete st;
+    st = nullptr;
+  }
+
+  return st;
+}
+
+AndroidSurfaceTexture*
+AndroidSurfaceTexture::Find(int id)
+{
+  std::map<int, AndroidSurfaceTexture*>::iterator it;
+
+  it = sInstances.find(id);
+  if (it == sInstances.end())
+    return nullptr;
+
+  return it->second;
+}
+
+bool
+AndroidSurfaceTexture::Check()
+{
+  return sJNIFunctions.EnsureInitialized();
+}
+
+bool
+AndroidSurfaceTexture::Attach(GLContext* aContext, PRIntervalTime aTimeout)
+{
+  MonitorAutoLock lock(mMonitor);
+
+  if (mAttachedContext == aContext) {
+    NS_WARNING("Tried to attach same GLContext to AndroidSurfaceTexture");
+    return true;
+  }
+
+  if (!IsDetachSupported()) {
+    return false;
+  }
+
+  while (mAttachedContext) {
+    // Wait until it's detached (or we time out)
+    if (NS_FAILED(lock.Wait(aTimeout))) {
+      return false;
+    }
+  }
+
+  MOZ_ASSERT(aContext->IsOwningThreadCurrent(), "Trying to attach GLContext from different thread");
+
+  mAttachedContext = aContext;
+  mAttachedContext->MakeCurrent();
+  aContext->fGenTextures(1, &mTexture);
+
+  sJNIFunctions.AttachToGLContext(mSurfaceTexture, mTexture);
+  return true;
+}
+
+bool
+AndroidSurfaceTexture::Detach()
+{
+  MonitorAutoLock lock(mMonitor);
+
+  if (!IsDetachSupported() ||
+      !mAttachedContext || !mAttachedContext->IsOwningThreadCurrent()) {
+    return false;
+  }
+
+  mAttachedContext->MakeCurrent();
+
+  // This call takes care of deleting the texture
+  sJNIFunctions.DetachFromGLContext(mSurfaceTexture);
+
+  mTexture = 0;
+  mAttachedContext = nullptr;
+  lock.NotifyAll();
+  return true;
+}
+
+bool
+AndroidSurfaceTexture::Init(GLContext* aContext, GLuint aTexture)
+{
+  if (!aTexture && !IsDetachSupported()) {
+    // We have no texture and cannot initialize detached, bail out
+    return false;
+  }
+
+  if (!sJNIFunctions.EnsureInitialized())
+    return false;
+
+  JNIEnv* env = GetJNIForThread();
+
+  mSurfaceTexture = sJNIFunctions.CreateSurfaceTexture(aTexture);
+  if (!mSurfaceTexture) {
+    return false;
+  }
+
+  if (!aTexture) {
+    sJNIFunctions.DetachFromGLContext(mSurfaceTexture);
+  }
+
+  mAttachedContext = aContext;
+
+  mSurface = sJNIFunctions.CreateSurface(mSurfaceTexture);
+  if (!mSurface) {
+    return false;
+  }
+
+  mNativeWindow = AndroidNativeWindow::CreateFromSurface(env, mSurface);
+
+  mID = ++sNextID;
+  sInstances.insert(std::pair<int, AndroidSurfaceTexture*>(mID, this));
+
+  return true;
+}
+
+AndroidSurfaceTexture::AndroidSurfaceTexture()
+  : mTexture(0)
+  , mSurfaceTexture(nullptr)
+  , mSurface(nullptr)
+  , mMonitor("AndroidSurfaceTexture::mContextMonitor")
+  , mAttachedContext(nullptr)
+{
+}
+
+AndroidSurfaceTexture::~AndroidSurfaceTexture()
+{
+  sInstances.erase(mID);
+
+  mFrameAvailableCallback = nullptr;
+
+  JNIEnv* env = GetJNIForThread();
+
+  if (mSurfaceTexture) {
+    GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
+
+    env->DeleteGlobalRef(mSurfaceTexture);
+    mSurfaceTexture = nullptr;
+  }
+
+  if (mSurface) {
+    env->DeleteGlobalRef(mSurface);
+    mSurface = nullptr;
+  }
+}
+
+void
+AndroidSurfaceTexture::UpdateTexImage()
+{
+  sJNIFunctions.UpdateTexImage(mSurfaceTexture);
+}
+
+bool
+AndroidSurfaceTexture::GetTransformMatrix(gfx::Matrix4x4& aMatrix)
+{
+  return sJNIFunctions.GetTransformMatrix(mSurfaceTexture, aMatrix);
+}
+
+void
+AndroidSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable)
+{
+  if (aRunnable) {
+    GeckoAppShell::RegisterSurfaceTextureFrameListener(mSurfaceTexture, mID);
+  } else {
+     GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
+  }
+
+  mFrameAvailableCallback = aRunnable;
+}
+
+void
+AndroidSurfaceTexture::SetDefaultSize(mozilla::gfx::IntSize size)
+{
+  sJNIFunctions.SetDefaultBufferSize(mSurfaceTexture, size.width, size.height);
+}
+
+void
+AndroidSurfaceTexture::NotifyFrameAvailable()
+{
+  if (mFrameAvailableCallback) {
+    // Proxy to main thread if we aren't on it
+    if (!NS_IsMainThread()) {
+      // Proxy to main thread
+      nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &AndroidSurfaceTexture::NotifyFrameAvailable);
+      NS_DispatchToCurrentThread(event);
+    } else {
+      mFrameAvailableCallback->Run();
+    }
+  }
+}
+
+} // gl
+} // mozilla
+
+#endif // MOZ_WIDGET_ANDROID
new file mode 100644
--- /dev/null
+++ b/gfx/gl/AndroidSurfaceTexture.h
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+// vim:set ts=2 sts=2 sw=2 et cin:
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef AndroidSurfaceTexture_h__
+#define AndroidSurfaceTexture_h__
+#ifdef MOZ_WIDGET_ANDROID
+
+#include <jni.h>
+#include "nsIRunnable.h"
+#include "gfxPlatform.h"
+#include "GLDefs.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/Monitor.h"
+
+#include "AndroidNativeWindow.h"
+
+class gfxASurface;
+
+namespace mozilla {
+namespace gfx {
+class Matrix4x4;
+}
+}
+
+namespace mozilla {
+namespace gl {
+
+class GLContext;
+
+/**
+ * This class is a wrapper around Android's SurfaceTexture class.
+ * Usage is pretty much exactly like the Java class, so see
+ * the Android documentation for details.
+ */
+class AndroidSurfaceTexture {
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AndroidSurfaceTexture)
+
+public:
+
+  // The SurfaceTexture is created in an attached state. This method requires
+  // Android Ice Cream Sandwich.
+  static AndroidSurfaceTexture* Create(GLContext* aGLContext, GLuint aTexture);
+
+  // Here the SurfaceTexture will be created in a detached state. You must call
+  // Attach() with the GLContext you wish to composite with. It must be done
+  // on the thread where that GLContext is current. This method requires
+  // Android Jelly Bean.
+  static AndroidSurfaceTexture* Create();
+
+  static AndroidSurfaceTexture* Find(int id);
+
+  // Returns with reasonable certainty whether or not we'll
+  // be able to create and use a SurfaceTexture
+  static bool Check();
+
+  // If we are on Jelly Bean, the SurfaceTexture can be detached and reattached
+  // to allow consumption from different GLContexts. It is recommended to only
+  // attach while you are consuming in order to allow this.
+  //
+  // Only one GLContext may be attached at any given time. If another is already
+  // attached, we try to wait for it to become detached.
+  bool Attach(GLContext* aContext, PRIntervalTime aTiemout = PR_INTERVAL_NO_TIMEOUT);
+
+  // This is a noop on ICS, and will always fail
+  bool Detach();
+
+  GLContext* GetAttachedContext() { return mAttachedContext; }
+
+  AndroidNativeWindow* NativeWindow() {
+    return mNativeWindow;
+  }
+
+  // This attaches the updated data to the TEXTURE_EXTERNAL target
+  void UpdateTexImage();
+
+  bool GetTransformMatrix(mozilla::gfx::Matrix4x4& aMatrix);
+  int ID() { return mID; }
+
+  void SetDefaultSize(mozilla::gfx::IntSize size);
+
+  // The callback is guaranteed to be called on the main thread even
+  // if the upstream callback is received on a different thread
+  void SetFrameAvailableCallback(nsIRunnable* aRunnable);
+
+  // Only should be called by AndroidJNI when we get a
+  // callback from the underlying SurfaceTexture instance
+  void NotifyFrameAvailable();
+
+  GLuint Texture() { return mTexture; }
+  jobject JavaSurface() { return mSurface; }
+private:
+  AndroidSurfaceTexture();
+  ~AndroidSurfaceTexture();
+
+  bool Init(GLContext* aContext, GLuint aTexture);
+
+  GLuint mTexture;
+  jobject mSurfaceTexture;
+  jobject mSurface;
+
+  Monitor mMonitor;
+  GLContext* mAttachedContext;
+
+  RefPtr<AndroidNativeWindow> mNativeWindow;
+  int mID;
+  nsRefPtr<nsIRunnable> mFrameAvailableCallback;
+};
+
+}
+}
+
+
+#endif
+#endif
--- a/gfx/gl/GLBlitHelper.cpp
+++ b/gfx/gl/GLBlitHelper.cpp
@@ -5,22 +5,28 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GLBlitHelper.h"
 #include "GLContext.h"
 #include "ScopedGLHelpers.h"
 #include "mozilla/Preferences.h"
 #include "ImageContainer.h"
 #include "HeapCopyOfStackArray.h"
+#include "mozilla/gfx/Matrix.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "GrallocImages.h"
 #include "GLLibraryEGL.h"
 #endif
 
+#ifdef MOZ_WIDGET_ANDROID
+#include "AndroidSurfaceTexture.h"
+#include "GLImages.h"
+#endif
+
 using mozilla::layers::PlanarYCbCrImage;
 using mozilla::layers::PlanarYCbCrData;
 
 namespace mozilla {
 namespace gl {
 
 static void
 RenderbufferStorageBySamples(GLContext* aGL, GLsizei aSamples,
@@ -139,16 +145,17 @@ GLBlitHelper::GLBlitHelper(GLContext* gl
     : mGL(gl)
     , mTexBlit_Buffer(0)
     , mTexBlit_VertShader(0)
     , mTex2DBlit_FragShader(0)
     , mTex2DRectBlit_FragShader(0)
     , mTex2DBlit_Program(0)
     , mTex2DRectBlit_Program(0)
     , mYFlipLoc(-1)
+    , mTextureTransformLoc(-1)
     , mTexExternalBlit_FragShader(0)
     , mTexYUVPlanarBlit_FragShader(0)
     , mTexExternalBlit_Program(0)
     , mTexYUVPlanarBlit_Program(0)
     , mFBO(0)
     , mSrcTexY(0)
     , mSrcTexCb(0)
     , mSrcTexCr(0)
@@ -233,31 +240,33 @@ GLBlitHelper::InitTexQuadProgram(BlitTyp
         varying vec2 vTexCoord;                                       \n\
                                                                       \n\
         void main(void)                                               \n\
         {                                                             \n\
             gl_FragColor = texture2DRect(uTexUnit,                    \n\
                                          vTexCoord * uTexCoordMult);  \n\
         }                                                             \n\
     ";
-#ifdef MOZ_WIDGET_GONK
+#ifdef ANDROID /* MOZ_WIDGET_ANDROID || MOZ_WIDGET_GONK */
     const char kTexExternalBlit_FragShaderSource[] = "\
-        #extension GL_OES_EGL_image_external : require      \n\
-        #ifdef GL_FRAGMENT_PRECISION_HIGH                   \n\
-            precision highp float;                          \n\
-        #else                                               \n\
-            precision mediump float;                        \n\
-        #endif                                              \n\
-        varying vec2 vTexCoord;                             \n\
-        uniform samplerExternalOES uTexUnit;                \n\
-                                                            \n\
-        void main()                                         \n\
-        {                                                   \n\
-            gl_FragColor = texture2D(uTexUnit, vTexCoord);  \n\
-        }                                                   \n\
+        #extension GL_OES_EGL_image_external : require                  \n\
+        #ifdef GL_FRAGMENT_PRECISION_HIGH                               \n\
+            precision highp float;                                      \n\
+        #else                                                           \n\
+            precision mediump float;                                    \n\
+        #endif                                                          \n\
+        varying vec2 vTexCoord;                                         \n\
+        uniform mat4 uTextureTransform;                                 \n\
+        uniform samplerExternalOES uTexUnit;                            \n\
+                                                                        \n\
+        void main()                                                     \n\
+        {                                                               \n\
+            gl_FragColor = texture2D(uTexUnit,                          \n\
+                (uTextureTransform * vec4(vTexCoord, 0.0, 1.0)).xy);    \n\
+        }                                                               \n\
     ";
 #endif
     /* From Rec601:
     [R] [1.1643835616438356, 0.0, 1.5960267857142858] [ Y - 16]
     [G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708] x [Cb - 128]
     [B] [1.1643835616438356, 2.017232142857143, 8.862867620416422e-17] [Cr - 128]
 
     For [0,1] instead of [0,255], and to 5 places:
@@ -301,17 +310,18 @@ GLBlitHelper::InitTexQuadProgram(BlitTyp
         fragShaderPtr = &mTex2DBlit_FragShader;
         fragShaderSource = kTex2DBlit_FragShaderSource;
         break;
     case BlitTexRect:
         programPtr = &mTex2DRectBlit_Program;
         fragShaderPtr = &mTex2DRectBlit_FragShader;
         fragShaderSource = kTex2DRectBlit_FragShaderSource;
         break;
-#ifdef MOZ_WIDGET_GONK
+#ifdef ANDROID
+    case ConvertSurfaceTexture:
     case ConvertGralloc:
         programPtr = &mTexExternalBlit_Program;
         fragShaderPtr = &mTexExternalBlit_FragShader;
         fragShaderSource = kTexExternalBlit_FragShaderSource;
         break;
 #endif
     case ConvertPlanarYCbCr:
         programPtr = &mTexYUVPlanarBlit_Program;
@@ -436,18 +446,19 @@ GLBlitHelper::InitTexQuadProgram(BlitTyp
             break;
         }
 
         // Cache and set attribute and uniform
         mGL->fUseProgram(program);
         switch (target) {
             case BlitTex2D:
             case BlitTexRect:
+            case ConvertSurfaceTexture:
             case ConvertGralloc: {
-#ifdef MOZ_WIDGET_GONK
+#ifdef ANDROID
                 GLint texUnitLoc = mGL->fGetUniformLocation(program, "uTexUnit");
                 MOZ_ASSERT(texUnitLoc != -1, "uniform uTexUnit not found");
                 mGL->fUniform1i(texUnitLoc, 0);
                 break;
 #endif
             }
             case ConvertPlanarYCbCr: {
                 GLint texY = mGL->fGetUniformLocation(program, "uYTexture");
@@ -467,16 +478,22 @@ GLBlitHelper::InitTexQuadProgram(BlitTyp
                 mGL->fUniform1i(texCb, Channel_Cb);
                 mGL->fUniform1i(texCr, Channel_Cr);
                 break;
             }
         }
         MOZ_ASSERT(mGL->fGetAttribLocation(program, "aPosition") == 0);
         mYFlipLoc = mGL->fGetUniformLocation(program, "uYflip");
         MOZ_ASSERT(mYFlipLoc != -1, "uniform: uYflip not found");
+        mTextureTransformLoc = mGL->fGetUniformLocation(program, "uTextureTransform");
+        if (mTextureTransformLoc >= 0) {
+            // Set identity matrix as default
+            gfx::Matrix4x4 identity;
+            mGL->fUniformMatrix4fv(mTextureTransformLoc, 1, false, &identity._11);
+        }
         success = true;
     } while (false);
 
     if (!success) {
         // Clean up:
         DeleteTexBlitProgram();
         return false;
     }
@@ -695,16 +712,52 @@ GLBlitHelper::BlitGrallocImage(layers::G
     mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
 
     sEGLLibrary.fDestroyImage(sEGLLibrary.Display(), image);
     mGL->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL_OES, oldBinding);
     return true;
 }
 #endif
 
+#ifdef MOZ_WIDGET_ANDROID
+
+bool
+GLBlitHelper::BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage)
+{
+    AndroidSurfaceTexture* surfaceTexture = stImage->GetData()->mSurfTex;
+    bool yFlip = stImage->GetData()->mInverted;
+
+    ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
+    mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
+
+    if (!surfaceTexture->Attach(mGL)) {
+        return false;
+    }
+
+    // UpdateTexImage() changes the EXTERNAL binding, so save it here
+    // so we can restore it after.
+    int oldBinding = 0;
+    mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL, &oldBinding);
+
+    surfaceTexture->UpdateTexImage();
+
+    gfx::Matrix4x4 transform;
+    surfaceTexture->GetTransformMatrix(transform);
+
+    mGL->fUniformMatrix4fv(mTextureTransformLoc, 1, false, &transform._11);
+    mGL->fUniform1f(mYFlipLoc, yFlip ? 1.0f : 0.0f);
+    mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+
+    surfaceTexture->Detach();
+
+    mGL->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, oldBinding);
+    return true;
+}
+#endif
+
 bool
 GLBlitHelper::BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage, bool yFlip)
 {
     ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
     const PlanarYCbCrData* yuvData = yuvImage->GetData();
 
     bool needsAllocation = false;
     if (mTexWidth != yuvData->mYStride || mTexHeight != yuvData->mYSize.height) {
@@ -733,53 +786,52 @@ GLBlitHelper::BlitPlanarYCbCrImage(layer
     for (int i = 0; i < 3; i++) {
         mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
         mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, oldTex[i]);
     }
     return true;
 }
 
 bool
-GLBlitHelper::BlitImageToTexture(layers::Image* srcImage,
-                                 const gfx::IntSize& destSize,
-                                 GLuint destTex,
-                                 GLenum destTarget,
-                                 bool yFlip,
-                                 GLuint xoffset,
-                                 GLuint yoffset,
-                                 GLuint cropWidth,
-                                 GLuint cropHeight)
+GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
+                                     const gfx::IntSize& destSize,
+                                     GLuint destFB,
+                                     bool yFlip,
+                                     GLuint xoffset,
+                                     GLuint yoffset,
+                                     GLuint cropWidth,
+                                     GLuint cropHeight)
 {
     ScopedGLDrawState autoStates(mGL);
 
     BlitType type;
     switch (srcImage->GetFormat()) {
     case ImageFormat::PLANAR_YCBCR:
         type = ConvertPlanarYCbCr;
         break;
     case ImageFormat::GRALLOC_PLANAR_YCBCR:
 #ifdef MOZ_WIDGET_GONK
         type = ConvertGralloc;
         break;
 #endif
+#ifdef MOZ_WIDGET_ANDROID
+    case ImageFormat::SURFACE_TEXTURE:
+        type = ConvertSurfaceTexture;
+        break;
+#endif
     default:
         return false;
     }
 
     bool init = InitTexQuadProgram(type);
     if (!init) {
         return false;
     }
 
-    if (!mFBO) {
-        mGL->fGenFramebuffers(1, &mFBO);
-    }
-
-    ScopedBindFramebuffer boundFB(mGL, mFBO);
-    mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, destTarget, destTex, 0);
+    ScopedBindFramebuffer boundFB(mGL, destFB);
     mGL->fColorMask(LOCAL_GL_TRUE, LOCAL_GL_TRUE, LOCAL_GL_TRUE, LOCAL_GL_TRUE);
     mGL->fViewport(0, 0, destSize.width, destSize.height);
     if (xoffset != 0 && yoffset != 0 && cropWidth != 0 && cropHeight != 0) {
         mGL->fEnable(LOCAL_GL_SCISSOR_TEST);
         mGL->fScissor(xoffset, yoffset, (GLsizei)cropWidth, (GLsizei)cropHeight);
     }
 
 #ifdef MOZ_WIDGET_GONK
@@ -788,20 +840,49 @@ GLBlitHelper::BlitImageToTexture(layers:
         return BlitGrallocImage(grallocImage, yFlip);
     }
 #endif
     if (type == ConvertPlanarYCbCr) {
         mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1);
         PlanarYCbCrImage* yuvImage = static_cast<PlanarYCbCrImage*>(srcImage);
         return BlitPlanarYCbCrImage(yuvImage, yFlip);
     }
+#ifdef MOZ_WIDGET_ANDROID
+    if (type == ConvertSurfaceTexture) {
+        layers::SurfaceTextureImage* stImage = static_cast<layers::SurfaceTextureImage*>(srcImage);
+        return BlitSurfaceTextureImage(stImage);
+    }
+#endif
 
     return false;
 }
 
+bool
+GLBlitHelper::BlitImageToTexture(layers::Image* srcImage,
+                                 const gfx::IntSize& destSize,
+                                 GLuint destTex,
+                                 GLenum destTarget,
+                                 bool yFlip,
+                                 GLuint xoffset,
+                                 GLuint yoffset,
+                                 GLuint cropWidth,
+                                 GLuint cropHeight)
+{
+    ScopedGLDrawState autoStates(mGL);
+
+    if (!mFBO) {
+        mGL->fGenFramebuffers(1, &mFBO);
+    }
+
+    ScopedBindFramebuffer boundFB(mGL, mFBO);
+    mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, destTarget, destTex, 0);
+    return BlitImageToFramebuffer(srcImage, destSize, mFBO, yFlip, xoffset, yoffset,
+                                  cropWidth, cropHeight);
+}
+
 void
 GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
                                        const gfx::IntSize& srcSize,
                                        const gfx::IntSize& destSize,
                                        GLenum srcTarget,
                                        bool internalFBs)
 {
     MOZ_ASSERT(mGL->fIsTexture(srcTex));
--- a/gfx/gl/GLBlitHelper.h
+++ b/gfx/gl/GLBlitHelper.h
@@ -14,16 +14,17 @@
 #include "mozilla/gfx/Point.h"
 
 namespace mozilla {
 
 namespace layers {
 class Image;
 class PlanarYCbCrImage;
 class GrallocImage;
+class SurfaceTextureImage;
 }
 
 namespace gl {
 
 class GLContext;
 
 /**
  * Helper function that creates a 2D texture aSize.width x aSize.height with
@@ -92,29 +93,32 @@ class GLBlitHelper MOZ_FINAL
      * Convert type is created for canvas.
      */
     enum BlitType
     {
         BlitTex2D,
         BlitTexRect,
         ConvertGralloc,
         ConvertPlanarYCbCr,
+        ConvertSurfaceTexture
     };
     // The GLContext is the sole owner of the GLBlitHelper.
     GLContext* mGL;
 
     GLuint mTexBlit_Buffer;
     GLuint mTexBlit_VertShader;
     GLuint mTex2DBlit_FragShader;
     GLuint mTex2DRectBlit_FragShader;
     GLuint mTex2DBlit_Program;
     GLuint mTex2DRectBlit_Program;
 
     GLint mYFlipLoc;
 
+    GLint mTextureTransformLoc;
+
     // Data for image blit path
     GLuint mTexExternalBlit_FragShader;
     GLuint mTexYUVPlanarBlit_FragShader;
     GLuint mTexExternalBlit_Program;
     GLuint mTexYUVPlanarBlit_Program;
     GLuint mFBO;
     GLuint mSrcTexY;
     GLuint mSrcTexCb;
@@ -137,16 +141,19 @@ class GLBlitHelper MOZ_FINAL
     void DeleteTexBlitProgram();
     void BindAndUploadYUVTexture(Channel which, uint32_t width, uint32_t height, void* data, bool allocation);
 
 #ifdef MOZ_WIDGET_GONK
     void BindAndUploadExternalTexture(EGLImage image);
     bool BlitGrallocImage(layers::GrallocImage* grallocImage, bool yFlip = false);
 #endif
     bool BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage, bool yFlip = false);
+#ifdef MOZ_WIDGET_ANDROID
+    bool BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage);
+#endif
 
 public:
 
     explicit GLBlitHelper(GLContext* gl);
     ~GLBlitHelper();
 
     // If you don't have |srcFormats| for the 2nd definition,
     // then you'll need the framebuffer_blit extensions to use
@@ -170,16 +177,19 @@ public:
                                   const gfx::IntSize& destSize,
                                   GLenum destTarget = LOCAL_GL_TEXTURE_2D,
                                   bool internalFBs = false);
     void BlitTextureToTexture(GLuint srcTex, GLuint destTex,
                               const gfx::IntSize& srcSize,
                               const gfx::IntSize& destSize,
                               GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
                               GLenum destTarget = LOCAL_GL_TEXTURE_2D);
+    bool BlitImageToFramebuffer(layers::Image* srcImage, const gfx::IntSize& destSize,
+                                GLuint destFB, bool yFlip = false, GLuint xoffset = 0,
+                                GLuint yoffset = 0, GLuint width = 0, GLuint height = 0);
     bool BlitImageToTexture(layers::Image* srcImage, const gfx::IntSize& destSize,
                             GLuint destTex, GLenum destTarget, bool yFlip = false, GLuint xoffset = 0,
                             GLuint yoffset = 0, GLuint width = 0, GLuint height = 0);
 };
 
 }
 }
 
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -20,17 +20,16 @@
 #include "HwcComposer2D.h"
 #include "libdisplay/GonkDisplay.h"
 #endif
 
 #if defined(ANDROID)
 /* from widget */
 #if defined(MOZ_WIDGET_ANDROID)
 #include "AndroidBridge.h"
-#include "nsSurfaceTexture.h"
 #endif
 
 #include <android/log.h>
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
 
 # if defined(MOZ_WIDGET_GONK)
 #  include "cutils/properties.h"
 #  include <ui/GraphicBuffer.h>
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -21,16 +21,18 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'an
     gl_provider = 'EGL'
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     gl_provider = 'EGL'
 
 if CONFIG['MOZ_GL_PROVIDER']:
     gl_provider = CONFIG['MOZ_GL_PROVIDER']
 
 EXPORTS += [
+    'AndroidNativeWindow.h',
+    'AndroidSurfaceTexture.h',
     'DecomposeIntoNoRepeatTriangles.h',
     'EGLUtils.h',
     'ForceDiscreteGPUHelperCGL.h',
     'GfxTexturesReporter.h',
     'GLBlitHelper.h',
     'GLBlitTextureImageHelper.h',
     'GLConsts.h',
     'GLContext.h',
@@ -110,16 +112,18 @@ elif gl_provider == 'GLX':
         'GLContextProviderGLX.cpp',
     ]
 else:
     UNIFIED_SOURCES += [
         'GLContextProvider%s.cpp' % gl_provider,
     ]
 
 UNIFIED_SOURCES += [
+    'AndroidNativeWindow.cpp',
+    'AndroidSurfaceTexture.cpp',
     'DecomposeIntoNoRepeatTriangles.cpp',
     'EGLUtils.cpp',
     'GfxTexturesReporter.cpp',
     'GLBlitHelper.cpp',
     'GLBlitTextureImageHelper.cpp',
     'GLContext.cpp',
     'GLContextFeatures.cpp',
     'GLContextTypes.cpp',
new file mode 100644
--- /dev/null
+++ b/gfx/layers/GLImages.cpp
@@ -0,0 +1,63 @@
+#ifdef MOZ_WIDGET_ANDROID
+
+#include "GLImages.h"
+#include "GLContext.h"
+#include "GLContextProvider.h"
+#include "ScopedGLHelpers.h"
+#include "GLImages.h"
+#include "GLBlitHelper.h"
+#include "GLReadTexImageHelper.h"
+#include "AndroidSurfaceTexture.h"
+
+using namespace mozilla;
+using namespace mozilla::gl;
+
+namespace mozilla {
+namespace layers {
+
+static nsRefPtr<GLContext> sSnapshotContext;
+
+TemporaryRef<gfx::SourceSurface>
+SurfaceTextureImage::GetAsSourceSurface()
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Should be on the main thread");
+
+  if (!sSnapshotContext) {
+    SurfaceCaps caps = SurfaceCaps::ForRGBA();
+    sSnapshotContext = GLContextProvider::CreateOffscreen(gfxIntSize(16, 16), caps);
+
+    if (!sSnapshotContext) {
+      return nullptr;
+    }
+  }
+
+  sSnapshotContext->MakeCurrent();
+  ScopedTexture scopedTex(sSnapshotContext);
+  ScopedBindTexture boundTex(sSnapshotContext, scopedTex.Texture());
+  sSnapshotContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA,
+                                mData.mSize.width, mData.mSize.height, 0,
+                                LOCAL_GL_RGBA,
+                                LOCAL_GL_UNSIGNED_BYTE,
+                                nullptr);
+
+  ScopedFramebufferForTexture fb(sSnapshotContext, scopedTex.Texture());
+
+  GLBlitHelper helper(sSnapshotContext);
+
+  helper.BlitImageToFramebuffer(this, mData.mSize, fb.FB(), false);
+  ScopedBindFramebuffer bind(sSnapshotContext, fb.FB());
+
+  RefPtr<gfx::DataSourceSurface> source =
+        gfx::Factory::CreateDataSourceSurface(mData.mSize, gfx::SurfaceFormat::B8G8R8A8);
+  if (NS_WARN_IF(!source)) {
+    return nullptr;
+  }
+
+  ReadPixelsIntoDataSurface(sSnapshotContext, source);
+  return source.forget();
+}
+
+} // layers
+} // mozilla
+
+#endif
--- a/gfx/layers/GLImages.h
+++ b/gfx/layers/GLImages.h
@@ -7,19 +7,20 @@
 #define GFX_GLIMAGES_H
 
 #include "GLTypes.h"
 #include "ImageContainer.h"             // for Image
 #include "ImageTypes.h"                 // for ImageFormat::SHARED_GLTEXTURE
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "mozilla/gfx/Point.h"          // for IntSize
 
-class nsSurfaceTexture;
-
 namespace mozilla {
+namespace gl {
+class AndroidSurfaceTexture;
+}
 namespace layers {
 
 class EGLImageImage : public Image {
 public:
   struct Data {
     EGLImage mImage;
     gfx::IntSize mSize;
     bool mInverted;
@@ -41,30 +42,27 @@ private:
   Data mData;
 };
 
 #ifdef MOZ_WIDGET_ANDROID
 
 class SurfaceTextureImage : public Image {
 public:
   struct Data {
-    nsSurfaceTexture* mSurfTex;
+    mozilla::gl::AndroidSurfaceTexture* mSurfTex;
     gfx::IntSize mSize;
     bool mInverted;
   };
 
   void SetData(const Data& aData) { mData = aData; }
   const Data* GetData() { return &mData; }
 
   gfx::IntSize GetSize() { return mData.mSize; }
 
-  virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() MOZ_OVERRIDE
-  {
-    return nullptr;
-  }
+  virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() MOZ_OVERRIDE;
 
   SurfaceTextureImage() : Image(nullptr, ImageFormat::SURFACE_TEXTURE) {}
 
 private:
   Data mData;
 };
 
 #endif // MOZ_WIDGET_ANDROID
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -285,16 +285,17 @@ UNIFIED_SOURCES += [
     'composite/LayerManagerComposite.cpp',
     'composite/PaintedLayerComposite.cpp',
     'composite/TextRenderer.cpp',
     'composite/TextureHost.cpp',
     'composite/TiledContentHost.cpp',
     'Compositor.cpp',
     'CopyableCanvasLayer.cpp',
     'Effects.cpp',
+    'GLImages.cpp',
     'ImageDataSerializer.cpp',
     'ImageLayers.cpp',
     'ipc/AsyncTransactionTracker.cpp',
     'ipc/CompositableTransactionParent.cpp',
     'ipc/CompositorBench.cpp',
     'ipc/CompositorChild.cpp',
     'ipc/CompositorParent.cpp',
     'ipc/ImageBridgeChild.cpp',
--- a/gfx/layers/opengl/TextureClientOGL.cpp
+++ b/gfx/layers/opengl/TextureClientOGL.cpp
@@ -74,17 +74,17 @@ EGLImageTextureClient::Unlock()
 }
   
 ////////////////////////////////////////////////////////////////////////
 // SurfaceTextureClient
 
 #ifdef MOZ_WIDGET_ANDROID
 
 SurfaceTextureClient::SurfaceTextureClient(TextureFlags aFlags,
-                                           nsSurfaceTexture* aSurfTex,
+                                           AndroidSurfaceTexture* aSurfTex,
                                            gfx::IntSize aSize,
                                            bool aInverted)
   : TextureClient(aFlags)
   , mSurfTex(aSurfTex)
   , mSize(aSize)
   , mIsLocked(false)
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default,
--- a/gfx/layers/opengl/TextureClientOGL.h
+++ b/gfx/layers/opengl/TextureClientOGL.h
@@ -8,23 +8,17 @@
 
 #include "GLContextTypes.h"             // for SharedTextureHandle, etc
 #include "gfxTypes.h"
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/TextureClient.h"  // for TextureClient, etc
-#include "nsSurfaceTexture.h"
-
-namespace mozilla {
-namespace gl {
-class SurfaceStream;
-}
-}
+#include "AndroidSurfaceTexture.h"
 
 namespace mozilla {
 namespace layers {
 
 class CompositableForwarder;
 
 class EGLImageTextureClient : public TextureClient
 {
@@ -75,17 +69,17 @@ protected:
 };
 
 #ifdef MOZ_WIDGET_ANDROID
 
 class SurfaceTextureClient : public TextureClient
 {
 public:
   SurfaceTextureClient(TextureFlags aFlags,
-                       nsSurfaceTexture* aSurfTex,
+                       gl::AndroidSurfaceTexture* aSurfTex,
                        gfx::IntSize aSize,
                        bool aInverted);
 
   ~SurfaceTextureClient();
 
   virtual bool IsAllocated() const MOZ_OVERRIDE { return true; }
 
   virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
@@ -114,17 +108,17 @@ public:
   }
 
   virtual bool AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags) MOZ_OVERRIDE
   {
     return false;
   }
 
 protected:
-  const nsRefPtr<nsSurfaceTexture> mSurfTex;
+  const RefPtr<gl::AndroidSurfaceTexture> mSurfTex;
   const gfx::IntSize mSize;
   bool mIsLocked;
 };
 
 #endif // MOZ_WIDGET_ANDROID
 
 } // namespace
 } // namespace
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -18,17 +18,17 @@
 # include "GrallocImages.h"  // for GrallocImage
 # include "EGLImageHelpers.h"
 #endif
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "mozilla/layers/GrallocTextureHost.h"
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsSurfaceTexture.h"
+#include "AndroidSurfaceTexture.h"
 #include "GfxTexturesReporter.h"        // for GfxTexturesReporter
 #include "GLBlitTextureImageHelper.h"
 #ifdef XP_MACOSX
 #include "SharedSurfaceIO.h"
 #include "mozilla/layers/MacIOSurfaceTextureHostOGL.h"
 #endif
 #include "GeckoProfiler.h"
 
@@ -63,17 +63,17 @@ CreateTextureHostOGL(const SurfaceDescri
                                                    aDeallocator, aFlags);
       break;
     }
 
 #ifdef MOZ_WIDGET_ANDROID
     case SurfaceDescriptor::TSurfaceTextureDescriptor: {
       const SurfaceTextureDescriptor& desc = aDesc.get_SurfaceTextureDescriptor();
       result = new SurfaceTextureHost(aFlags,
-                                      (nsSurfaceTexture*)desc.surfTex(),
+                                      (AndroidSurfaceTexture*)desc.surfTex(),
                                       desc.size());
       break;
     }
 #endif
 
     case SurfaceDescriptor::TEGLImageDescriptor: {
       const EGLImageDescriptor& desc = aDesc.get_EGLImageDescriptor();
       result = new EGLImageTextureHost(aFlags,
@@ -573,17 +573,17 @@ GLTextureSource::gl() const
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 // SurfaceTextureHost
 
 #ifdef MOZ_WIDGET_ANDROID
 
 SurfaceTextureSource::SurfaceTextureSource(CompositorOGL* aCompositor,
-                                           nsSurfaceTexture* aSurfTex,
+                                           AndroidSurfaceTexture* aSurfTex,
                                            gfx::SurfaceFormat aFormat,
                                            GLenum aTarget,
                                            GLenum aWrapMode,
                                            gfx::IntSize aSize)
   : mCompositor(aCompositor)
   , mSurfTex(aSurfTex)
   , mFormat(aFormat)
   , mTextureTarget(aTarget)
@@ -594,20 +594,18 @@ SurfaceTextureSource::SurfaceTextureSour
 
 void
 SurfaceTextureSource::BindTexture(GLenum aTextureUnit, gfx::Filter aFilter)
 {
   if (!gl()) {
     NS_WARNING("Trying to bind a texture without a GLContext");
     return;
   }
-  GLuint tex = mCompositor->GetTemporaryTexture(GetTextureTarget(), aTextureUnit);
 
   gl()->fActiveTexture(aTextureUnit);
-  gl()->fBindTexture(mTextureTarget, tex);
 #ifndef DEBUG
   // SurfaceTexture spams us if there are any existing GL errors, so
   // we'll clear them here in order to avoid that.
   gl()->GetAndClearError();
 #endif
   mSurfTex->UpdateTexImage();
 
   ApplyFilterToBoundTexture(gl(), aFilter, mTextureTarget);
@@ -638,17 +636,17 @@ SurfaceTextureSource::GetTextureTransfor
   mSurfTex->GetTransformMatrix(ret);
 
   return ret;
 }
 
 ////////////////////////////////////////////////////////////////////////
 
 SurfaceTextureHost::SurfaceTextureHost(TextureFlags aFlags,
-                                       nsSurfaceTexture* aSurfTex,
+                                       AndroidSurfaceTexture* aSurfTex,
                                        gfx::IntSize aSize)
   : TextureHost(aFlags)
   , mSurfTex(aSurfTex)
   , mSize(aSize)
   , mCompositor(nullptr)
 {
 }
 
@@ -676,22 +674,25 @@ SurfaceTextureHost::Lock()
     mTextureSource = new SurfaceTextureSource(mCompositor,
                                               mSurfTex,
                                               format,
                                               target,
                                               wrapMode,
                                               mSize);
   }
 
+  mSurfTex->Attach(gl());
+
   return true;
 }
 
 void
 SurfaceTextureHost::Unlock()
 {
+  mSurfTex->Detach();
 }
 
 void
 SurfaceTextureHost::SetCompositor(Compositor* aCompositor)
 {
   CompositorOGL* glCompositor = static_cast<CompositorOGL*>(aCompositor);
   mCompositor = glCompositor;
   if (mTextureSource) {
--- a/gfx/layers/opengl/TextureHostOGL.h
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -34,28 +34,27 @@
 #include <ui/GraphicBuffer.h>
 #if ANDROID_VERSION >= 17
 #include <ui/Fence.h>
 #endif
 #endif
 
 class gfxReusableSurfaceWrapper;
 class nsIntRegion;
-class nsSurfaceTexture;
 struct nsIntPoint;
 struct nsIntRect;
 struct nsIntSize;
 
 namespace mozilla {
 namespace gfx {
 class DataSourceSurface;
 }
 
 namespace gl {
-class SurfaceStream;
+class AndroidSurfaceTexture;
 }
 
 namespace layers {
 
 class Compositor;
 class CompositorOGL;
 class TextureImageTextureSourceOGL;
 class TextureSharedDataGonkOGL;
@@ -412,17 +411,17 @@ protected:
 
 #ifdef MOZ_WIDGET_ANDROID
 
 class SurfaceTextureSource : public TextureSource
                            , public TextureSourceOGL
 {
 public:
   SurfaceTextureSource(CompositorOGL* aCompositor,
-                       nsSurfaceTexture* aSurfTex,
+                       mozilla::gl::AndroidSurfaceTexture* aSurfTex,
                        gfx::SurfaceFormat aFormat,
                        GLenum aTarget,
                        GLenum aWrapMode,
                        gfx::IntSize aSize);
 
   virtual TextureSourceOGL* AsSourceOGL() { return this; }
 
   virtual void BindTexture(GLenum activetex, gfx::Filter aFilter) MOZ_OVERRIDE;
@@ -443,28 +442,28 @@ public:
   virtual void DeallocateDeviceData() MOZ_OVERRIDE {}
 
   virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
 
   gl::GLContext* gl() const;
 
 protected:
   RefPtr<CompositorOGL> mCompositor;
-  nsSurfaceTexture* const mSurfTex;
+  mozilla::gl::AndroidSurfaceTexture* const mSurfTex;
   const gfx::SurfaceFormat mFormat;
   const GLenum mTextureTarget;
   const GLenum mWrapMode;
   const gfx::IntSize mSize;
 };
 
 class SurfaceTextureHost : public TextureHost
 {
 public:
   SurfaceTextureHost(TextureFlags aFlags,
-                     nsSurfaceTexture* aSurfTex,
+                     mozilla::gl::AndroidSurfaceTexture* aSurfTex,
                      gfx::IntSize aSize);
 
   virtual ~SurfaceTextureHost();
 
   // We don't own anything.
   virtual void DeallocateDeviceData() MOZ_OVERRIDE {}
 
   virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
@@ -487,17 +486,17 @@ public:
 
   gl::GLContext* gl() const;
 
   virtual gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
 
   virtual const char* Name() { return "SurfaceTextureHost"; }
 
 protected:
-  nsSurfaceTexture* const mSurfTex;
+  mozilla::gl::AndroidSurfaceTexture* const mSurfTex;
   const gfx::IntSize mSize;
   RefPtr<CompositorOGL> mCompositor;
   RefPtr<SurfaceTextureSource> mTextureSource;
 };
 
 #endif // MOZ_WIDGET_ANDROID
 
 ////////////////////////////////////////////////////////////////////////
--- a/gfx/layers/opengl/TexturePoolOGL.cpp
+++ b/gfx/layers/opengl/TexturePoolOGL.cpp
@@ -97,16 +97,21 @@ void TexturePoolOGL::Fill(GLContext* aCo
     texture = (GLuint*)malloc(sizeof(GLuint));
     sActiveContext->fGenTextures(1, texture);
     sTextures->Push((void*) texture);
   }
 
   sMonitor->NotifyAll();
 }
 
+GLContext* TexturePoolOGL::GetGLContext()
+{
+  return sActiveContext;
+}
+
 void TexturePoolOGL::Init()
 {
   sMonitor = new Monitor("TexturePoolOGL.sMonitor");
   sTextures = new nsDeque();
 }
 
 void TexturePoolOGL::Shutdown()
 {
--- a/gfx/layers/opengl/TexturePoolOGL.h
+++ b/gfx/layers/opengl/TexturePoolOGL.h
@@ -7,29 +7,31 @@
 
 #include "GLContextTypes.h"             // for GLContext, GLuint
 
 namespace mozilla {
 namespace gl {
 
 // A texture pool for for the on-screen GLContext. The main purpose of this class
 // is to provide the ability to easily allocate an on-screen texture from the
-// content thread. The unfortunate nature of the SurfaceTexture API (see nsSurfaceTexture)
+// content thread. The unfortunate nature of the SurfaceTexture API (see AndroidSurfaceTexture)
 // necessitates this.
 class TexturePoolOGL
 {
 public:
   // Get a new texture from the pool. Will block
   // and wait for one to be created if necessary
   static GLuint AcquireTexture();
 
   // Called by the active LayerManagerOGL to fill
   // the pool
   static void Fill(GLContext* aContext);
 
+  static GLContext* GetGLContext();
+
   // Initializes the pool, but does not fill it. Called by gfxPlatform init.
   static void Init();
 
   // Clears all internal data structures in preparation for shutdown
   static void Shutdown();
 };
 
 } // gl
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -19,16 +19,17 @@
 #include "nsTArray.h"
 
 #include "nsIWindowsRegKey.h"
 #include "nsIFile.h"
 #include "plbase64.h"
 #include "nsIXULRuntime.h"
 
 #include "nsIGfxInfo.h"
+#include "GfxDriverInfo.h"
 
 #include "gfxCrashReporterUtils.h"
 
 #include "gfxGDIFontList.h"
 #include "gfxGDIFont.h"
 
 #include "mozilla/layers/CompositorParent.h"   // for CompositorParent::IsInCompositorThread
 #include "DeviceManagerD3D9.h"
@@ -64,16 +65,20 @@
 
 #include "nsIMemoryReporter.h"
 #include <winternl.h>
 #include "d3dkmtQueryStatistics.h"
 
 #include "SurfaceCache.h"
 #include "gfxPrefs.h"
 
+#if defined(MOZ_CRASHREPORTER)
+#include "nsExceptionHandler.h"
+#endif
+
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using namespace mozilla::widget;
 using namespace mozilla::image;
 
 #ifdef CAIRO_HAS_D2D_SURFACE
 
@@ -390,17 +395,17 @@ gfxWindowsPlatform::UpdateRenderMode()
     if (d2dDisabled || mUsingGDIFonts) {
         tryD2D = false;
     }
 
     ID3D11Device *device = GetD3D11Device();
     if (isVistaOrHigher && !safeMode && tryD2D &&
         device &&
         device->GetFeatureLevel() >= D3D_FEATURE_LEVEL_10_0 &&
-        DoesD3D11DeviceSupportResourceSharing(device)) {
+        DoesD3D11DeviceWork(device)) {
 
         VerifyD2DDevice(d2dForceEnabled);
         if (mD2DDevice) {
             mRenderMode = RENDER_DIRECT2D;
             mUseDirectWrite = true;
         }
     } else {
         mD2DDevice = nullptr;
@@ -1502,24 +1507,58 @@ gfxWindowsPlatform::GetDXGIAdapter()
   // We leak this module everywhere, we might as well do so here as well.
   dxgiModule.disown();
 
   return mAdapter;
 }
 
 // See bug 1083071. On some drivers, Direct3D 11 CreateShaderResourceView fails
 // with E_OUTOFMEMORY.
-bool DoesD3D11DeviceSupportResourceSharing(ID3D11Device *device)
+bool DoesD3D11DeviceWork(ID3D11Device *device)
 {
   static bool checked;
   static bool result;
 
   if (checked)
       return result;
   checked = true;
+
+  if (GetModuleHandleW(L"dlumd32.dll") && GetModuleHandleW(L"igd10umd32.dll")) {
+    nsString displayLinkModuleVersionString;
+    gfxWindowsPlatform::GetDLLVersion(L"dlumd32.dll", displayLinkModuleVersionString);
+    uint64_t displayLinkModuleVersion;
+    if (!ParseDriverVersion(displayLinkModuleVersionString, &displayLinkModuleVersion)) {
+#if defined(MOZ_CRASHREPORTER)
+      CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("DisplayLink: could not parse version\n"));
+#endif
+      return false;
+    }
+    if (displayLinkModuleVersion <= GFX_DRIVER_VERSION(8,6,1,36484)) {
+#if defined(MOZ_CRASHREPORTER)
+      CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("DisplayLink: too old version\n"));
+#endif
+      return false;
+    }
+  }
+
+  if (GetModuleHandleW(L"atidxx32.dll")) {
+    nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
+    if (gfxInfo) {
+      nsString vendorID, vendorID2;
+      gfxInfo->GetAdapterVendorID(vendorID);
+      gfxInfo->GetAdapterVendorID2(vendorID2);
+      if (vendorID.EqualsLiteral("0x8086") && vendorID2.IsEmpty()) {
+#if defined(MOZ_CRASHREPORTER)
+        CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("Unexpected Intel/AMD dual-GPU setup\n"));
+#endif
+        return false;
+      }
+    }
+  }
+
   RefPtr<ID3D11Texture2D> texture;
   D3D11_TEXTURE2D_DESC desc;
   desc.Width = 32;
   desc.Height = 32;
   desc.MipLevels = 1;
   desc.ArraySize = 1;
   desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
   desc.SampleDesc.Count = 1;
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -300,11 +300,11 @@ private:
     mozilla::RefPtr<mozilla::layers::ReadbackManagerD3D11> mD3D11ReadbackManager;
 
     virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
 
     // TODO: unify this with mPrefFonts (NB: holds families, not fonts) in gfxPlatformFontList
     nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts;
 };
 
-bool DoesD3D11DeviceSupportResourceSharing(ID3D11Device *device);
+bool DoesD3D11DeviceWork(ID3D11Device *device);
 
 #endif /* GFX_WINDOWS_PLATFORM_H */
--- a/gfx/thebes/moz.build
+++ b/gfx/thebes/moz.build
@@ -44,17 +44,16 @@ EXPORTS += [
     'gfxSkipChars.h',
     'gfxSVGGlyphs.h',
     'gfxTeeSurface.h',
     'gfxTextRun.h',
     'gfxTypes.h',
     'gfxUserFontSet.h',
     'gfxUtils.h',
     'GraphicsFilter.h',
-    'nsSurfaceTexture.h',
     'RoundedRect.h',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     EXPORTS += [
         'gfxAndroidPlatform.h',
         'gfxFT2FontBase.h',
         'gfxFT2Fonts.h',
@@ -237,17 +236,16 @@ UNIFIED_SOURCES += [
     'gfxReusableSharedImageSurfaceWrapper.cpp',
     'gfxScriptItemizer.cpp',
     'gfxSkipChars.cpp',
     'gfxSVGGlyphs.cpp',
     'gfxTeeSurface.cpp',
     'gfxTextRun.cpp',
     'gfxUserFontSet.cpp',
     'gfxUtils.cpp',
-    'nsSurfaceTexture.cpp',
     'nsUnicodeRange.cpp',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     UNIFIED_SOURCES += [
         'gfxMacPlatformFontList.mm',
     ]
 
deleted file mode 100644
--- a/gfx/thebes/nsSurfaceTexture.cpp
+++ /dev/null
@@ -1,247 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-// vim:set ts=2 sts=2 sw=2 et cin:
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifdef MOZ_WIDGET_ANDROID
-
-#include <set>
-#include <map>
-#include <android/log.h>
-#include "nsSurfaceTexture.h"
-#include "AndroidBridge.h"
-#include "nsThreadUtils.h"
-#include "mozilla/gfx/Matrix.h"
-
-using namespace mozilla;
-
-// UGH
-static std::map<int, nsSurfaceTexture*> sInstances;
-static int sNextID = 0;
-
-static class JNIFunctions {
-public:
-
-  JNIFunctions() : mInitialized(false)
-  {
-  }
-
-  bool EnsureInitialized()
-  {
-    if (mInitialized)
-      return true;
-
-    JNIEnv* env = GetJNIForThread();
-
-    AutoLocalJNIFrame jniFrame(env);
-
-    jSurfaceTextureClass = (jclass)env->NewGlobalRef(env->FindClass("android/graphics/SurfaceTexture"));
-    jSurfaceTexture_Ctor = env->GetMethodID(jSurfaceTextureClass, "<init>", "(I)V");
-    jSurfaceTexture_updateTexImage = env->GetMethodID(jSurfaceTextureClass, "updateTexImage", "()V");
-    jSurfaceTexture_getTransformMatrix = env->GetMethodID(jSurfaceTextureClass, "getTransformMatrix", "([F)V");
-
-    mInitialized = true;
-    return true;
-  }
-
-  jobject CreateSurfaceTexture(GLuint aTexture)
-  {
-    if (!EnsureInitialized())
-      return nullptr;
-
-    JNIEnv* env = GetJNIForThread();
-
-    AutoLocalJNIFrame jniFrame(env);
-
-    return env->NewGlobalRef(env->NewObject(jSurfaceTextureClass, jSurfaceTexture_Ctor, (int) aTexture));
-  }
-
-  void ReleaseSurfaceTexture(jobject aSurfaceTexture)
-  {
-    JNIEnv* env = GetJNIForThread();
-
-    env->DeleteGlobalRef(aSurfaceTexture);
-  }
-
-  void UpdateTexImage(jobject aSurfaceTexture)
-  {
-    JNIEnv* env = GetJNIForThread();
-
-    AutoLocalJNIFrame jniFrame(env);
-    env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_updateTexImage);
-  }
-
-  bool GetTransformMatrix(jobject aSurfaceTexture, gfx::Matrix4x4& aMatrix)
-  {
-    JNIEnv* env = GetJNIForThread();
-
-    AutoLocalJNIFrame jniFrame(env);
-
-    jfloatArray jarray = env->NewFloatArray(16);
-    env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_getTransformMatrix, jarray);
-
-    jfloat* array = env->GetFloatArrayElements(jarray, nullptr);
-
-    aMatrix._11 = array[0];
-    aMatrix._12 = array[1];
-    aMatrix._13 = array[2];
-    aMatrix._14 = array[3];
-
-    aMatrix._21 = array[4];
-    aMatrix._22 = array[5];
-    aMatrix._23 = array[6];
-    aMatrix._24 = array[7];
-
-    aMatrix._31 = array[8];
-    aMatrix._32 = array[9];
-    aMatrix._33 = array[10];
-    aMatrix._34 = array[11];
-
-    aMatrix._41 = array[12];
-    aMatrix._42 = array[13];
-    aMatrix._43 = array[14];
-    aMatrix._44 = array[15];
-
-    env->ReleaseFloatArrayElements(jarray, array, 0);
-
-    return false;
-  }
-
-private:
-  bool mInitialized;
-
-  jclass jSurfaceTextureClass;
-  jmethodID jSurfaceTexture_Ctor;
-  jmethodID jSurfaceTexture_updateTexImage;
-  jmethodID jSurfaceTexture_getTransformMatrix;
-
-} sJNIFunctions;
-
-nsSurfaceTexture*
-nsSurfaceTexture::Create(GLuint aTexture)
-{
-  // Right now we only support creating this on the main thread because
-  // of the JNIEnv assumptions in JNIHelper and elsewhere
-  if (!NS_IsMainThread())
-    return nullptr;
-
-  nsSurfaceTexture* st = new nsSurfaceTexture();
-  if (!st->Init(aTexture)) {
-    printf_stderr("Failed to initialize nsSurfaceTexture");
-    delete st;
-    st = nullptr;
-  }
-
-  return st;
-}
-
-nsSurfaceTexture*
-nsSurfaceTexture::Find(int id)
-{
-  std::map<int, nsSurfaceTexture*>::iterator it;
-
-  it = sInstances.find(id);
-  if (it == sInstances.end())
-    return nullptr;
-
-  return it->second;
-}
-
-bool
-nsSurfaceTexture::Check()
-{
-  return sJNIFunctions.EnsureInitialized();
-}
-
-bool
-nsSurfaceTexture::Init(GLuint aTexture)
-{
-  if (!sJNIFunctions.EnsureInitialized())
-    return false;
-
-  JNIEnv* env = GetJNIForThread();
-
-  mSurfaceTexture = sJNIFunctions.CreateSurfaceTexture(aTexture);
-  if (!mSurfaceTexture)
-    return false;
-
-  mNativeWindow = AndroidBridge::Bridge()->AcquireNativeWindowFromSurfaceTexture(env, mSurfaceTexture);
-
-  mID = ++sNextID;
-  sInstances.insert(std::pair<int, nsSurfaceTexture*>(mID, this));
-
-  return true;
-}
-
-nsSurfaceTexture::nsSurfaceTexture()
-  : mSurfaceTexture(nullptr), mNativeWindow(nullptr)
-{
-}
-
-nsSurfaceTexture::~nsSurfaceTexture()
-{
-  sInstances.erase(mID);
-
-  mFrameAvailableCallback = nullptr;
-
-  if (mNativeWindow) {
-    AndroidBridge::Bridge()->ReleaseNativeWindowForSurfaceTexture(mSurfaceTexture);
-    mNativeWindow = nullptr;
-  }
-
-  JNIEnv* env = GetJNIForThread();
-
-  if (mSurfaceTexture) {
-    mozilla::widget::android::GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
-
-    env->DeleteGlobalRef(mSurfaceTexture);
-    mSurfaceTexture = nullptr;
-  }
-}
-
-void*
-nsSurfaceTexture::GetNativeWindow()
-{
-  return mNativeWindow;
-}
-
-void
-nsSurfaceTexture::UpdateTexImage()
-{
-  sJNIFunctions.UpdateTexImage(mSurfaceTexture);
-}
-
-bool
-nsSurfaceTexture::GetTransformMatrix(gfx::Matrix4x4& aMatrix)
-{
-  return sJNIFunctions.GetTransformMatrix(mSurfaceTexture, aMatrix);
-}
-
-void
-nsSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable)
-{
-  if (aRunnable)
-    mozilla::widget::android::GeckoAppShell::RegisterSurfaceTextureFrameListener(mSurfaceTexture, mID);
-  else
-    mozilla::widget::android::GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
-
-  mFrameAvailableCallback = aRunnable;
-}
-
-void
-nsSurfaceTexture::NotifyFrameAvailable()
-{
-  if (mFrameAvailableCallback) {
-    // Proxy to main thread if we aren't on it
-    if (!NS_IsMainThread()) {
-      // Proxy to main thread 
-      nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &nsSurfaceTexture::NotifyFrameAvailable);
-      NS_DispatchToCurrentThread(event);
-    } else {
-      mFrameAvailableCallback->Run();
-    }
-  }
-}
-
-#endif // MOZ_WIDGET_ANDROID
deleted file mode 100644
--- a/gfx/thebes/nsSurfaceTexture.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-// vim:set ts=2 sts=2 sw=2 et cin:
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef nsSurfaceTexture_h__
-#define nsSurfaceTexture_h__
-#ifdef MOZ_WIDGET_ANDROID
-
-#include <jni.h>
-#include "nsIRunnable.h"
-#include "gfxPlatform.h"
-#include "GLDefs.h"
-
-namespace mozilla {
-namespace gfx {
-class Matrix4x4;
-}
-}
-
-/**
- * This class is a wrapper around Android's SurfaceTexture class.
- * Usage is pretty much exactly like the Java class, so see
- * the Android documentation for details.
- */
-class nsSurfaceTexture MOZ_FINAL {
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsSurfaceTexture)
-
-public:
-  static nsSurfaceTexture* Create(GLuint aTexture);
-  static nsSurfaceTexture* Find(int id);
-
-  // Returns with reasonable certainty whether or not we'll
-  // be able to create and use a SurfaceTexture
-  static bool Check();
-
-  // This is an ANativeWindow. Use AndroidBridge::LockWindow and
-  // friends for manipulating it.
-  void* GetNativeWindow();
-
-  // This attaches the updated data to the TEXTURE_EXTERNAL target
-  void UpdateTexImage();
-
-  bool GetTransformMatrix(mozilla::gfx::Matrix4x4& aMatrix);
-  int ID() { return mID; }
-
-  // The callback is guaranteed to be called on the main thread even
-  // if the upstream callback is received on a different thread
-  void SetFrameAvailableCallback(nsIRunnable* aRunnable);
-
-  // Only should be called by AndroidJNI when we get a
-  // callback from the underlying SurfaceTexture instance
-  void NotifyFrameAvailable();
-private:
-  nsSurfaceTexture();
-
-  // Private destructor, to discourage deletion outside of Release():
-  ~nsSurfaceTexture();
-
-  bool Init(GLuint aTexture);
-
-  jobject mSurfaceTexture;
-  void* mNativeWindow;
-  int mID;
-  nsRefPtr<nsIRunnable> mFrameAvailableCallback;
-};
-
-#endif
-#endif
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1089761.js
@@ -0,0 +1,14 @@
+var hits = 0;
+for (var j = 0; j < 9; ++j) {
+    try {
+        (function() {
+            (function() {
+                eval("x")
+                let x
+            })()
+        })()
+    } catch (e) {
+      hits++;
+    }
+}
+assertEq(hits, 9);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1090037.js
@@ -0,0 +1,7 @@
+function f(x) {
+    Math.sin([] | 0 && x)
+}
+for (var j = 0; j < 1; j++) {
+    f(1 && 0)
+}
+
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1092833.js
@@ -0,0 +1,49 @@
+// Test that lexicals work with functions with many bindings.
+
+(function() {
+    var a01
+    var b02
+    var c03
+    var d04
+    var e05
+    var f06
+    var g07
+    var h08
+    let i09
+    var j10
+    var k11
+    var l12
+    var m13
+    var n14
+    var o15
+    (function n14() {
+      assertEq(i09, undefined);
+    })()
+})();
+
+try {
+  (function() {
+      var a01
+      var b02
+      var c03
+      var d04
+      var e05
+      var f06
+      var g07
+      var h08
+      let i09
+      var j10
+      var k11
+      var l12
+      var m13
+      var n14
+      var o15
+      (function n14() {
+        i12++
+      })()
+      let i12
+  })()
+} catch (e) {
+  assertEq(e instanceof ReferenceError, true);
+  assertEq(e.message.indexOf("i12") > 0, true);
+}
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4448,58 +4448,64 @@ CodeGenerator::visitNewDeclEnvObject(LNe
     bool initFixedSlots = ShouldInitFixedSlots(lir, templateObj);
     masm.createGCObject(objReg, tempReg, templateObj, gc::DefaultHeap, ool->entry(),
                         initFixedSlots);
 
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleShape, HandleTypeObject);
+typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleShape, HandleTypeObject, uint32_t);
 static const VMFunction NewCallObjectInfo =
     FunctionInfo<NewCallObjectFn>(NewCallObject);
 
 bool
 CodeGenerator::visitNewCallObject(LNewCallObject *lir)
 {
     Register objReg = ToRegister(lir->output());
     Register tempReg = ToRegister(lir->temp());
 
     NativeObject *templateObj = lir->mir()->templateObject();
 
+    JSScript *script = lir->mir()->block()->info().script();
+    uint32_t lexicalBegin = script->bindings.aliasedBodyLevelLexicalBegin();
     OutOfLineCode *ool = oolCallVM(NewCallObjectInfo, lir,
                                    (ArgList(), ImmGCPtr(templateObj->lastProperty()),
-                                               ImmGCPtr(templateObj->type())),
+                                               ImmGCPtr(templateObj->type()),
+                                               Imm32(lexicalBegin)),
                                    StoreRegisterTo(objReg));
     if (!ool)
         return false;
 
     // Inline call object creation, using the OOL path only for tricky cases.
     bool initFixedSlots = ShouldInitFixedSlots(lir, templateObj);
     masm.createGCObject(objReg, tempReg, templateObj, gc::DefaultHeap, ool->entry(),
                         initFixedSlots);
 
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef JSObject *(*NewSingletonCallObjectFn)(JSContext *, HandleShape);
+typedef JSObject *(*NewSingletonCallObjectFn)(JSContext *, HandleShape, uint32_t);
 static const VMFunction NewSingletonCallObjectInfo =
     FunctionInfo<NewSingletonCallObjectFn>(NewSingletonCallObject);
 
 bool
 CodeGenerator::visitNewSingletonCallObject(LNewSingletonCallObject *lir)
 {
     Register objReg = ToRegister(lir->output());
 
     JSObject *templateObj = lir->mir()->templateObject();
 
+    JSScript *script = lir->mir()->block()->info().script();
+    uint32_t lexicalBegin = script->bindings.aliasedBodyLevelLexicalBegin();
     OutOfLineCode *ool;
     ool = oolCallVM(NewSingletonCallObjectInfo, lir,
-                    (ArgList(), ImmGCPtr(templateObj->lastProperty())),
+                    (ArgList(), ImmGCPtr(templateObj->lastProperty()),
+                                Imm32(lexicalBegin)),
                     StoreRegisterTo(objReg));
     if (!ool)
         return false;
 
     // Objects can only be given singleton types in VM calls.  We make the call
     // out of line to not bloat inline code, even if (naively) this seems like
     // extra work.
     masm.jump(ool->entry());
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -21,16 +21,17 @@
 #include "vm/ForkJoin.h"
 #include "vm/TraceLogging.h"
 
 #ifdef JSGC_GENERATIONAL
 # include "jsgcinlines.h"
 #endif
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
+#include "vm/Interpreter-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using JS::GenericNaN;
 
 namespace {
 
@@ -741,49 +742,76 @@ MacroAssembler::copySlotsFromTemplate(Re
                                       uint32_t start, uint32_t end)
 {
     uint32_t nfixed = Min(templateObj->numFixedSlots(), end);
     for (unsigned i = start; i < nfixed; i++)
         storeValue(templateObj->getFixedSlot(i), Address(obj, NativeObject::getFixedSlotOffset(i)));
 }
 
 void
-MacroAssembler::fillSlotsWithUndefined(Address base, Register temp, uint32_t start, uint32_t end)
+MacroAssembler::fillSlotsWithConstantValue(Address base, Register temp,
+                                           uint32_t start, uint32_t end, const Value &v)
 {
+    MOZ_ASSERT(v.isUndefined() || IsUninitializedLexical(v));
+
+    if (start >= end)
+        return;
+
 #ifdef JS_NUNBOX32
     // We only have a single spare register, so do the initialization as two
     // strided writes of the tag and body.
-    jsval_layout jv = JSVAL_TO_IMPL(UndefinedValue());
+    jsval_layout jv = JSVAL_TO_IMPL(v);
 
     Address addr = base;
     move32(Imm32(jv.s.payload.i32), temp);
     for (unsigned i = start; i < end; ++i, addr.offset += sizeof(HeapValue))
         store32(temp, ToPayload(addr));
 
     addr = base;
     move32(Imm32(jv.s.tag), temp);
     for (unsigned i = start; i < end; ++i, addr.offset += sizeof(HeapValue))
         store32(temp, ToType(addr));
 #else
-    moveValue(UndefinedValue(), temp);
+    moveValue(v, temp);
     for (uint32_t i = start; i < end; ++i, base.offset += sizeof(HeapValue))
         storePtr(temp, base);
 #endif
 }
 
-static uint32_t
-FindStartOfUndefinedSlots(NativeObject *templateObj, uint32_t nslots)
+void
+MacroAssembler::fillSlotsWithUndefined(Address base, Register temp, uint32_t start, uint32_t end)
+{
+    fillSlotsWithConstantValue(base, temp, start, end, UndefinedValue());
+}
+
+void
+MacroAssembler::fillSlotsWithUninitialized(Address base, Register temp, uint32_t start, uint32_t end)
+{
+    fillSlotsWithConstantValue(base, temp, start, end, MagicValue(JS_UNINITIALIZED_LEXICAL));
+}
+
+static void
+FindStartOfUndefinedAndUninitializedSlots(NativeObject *templateObj, uint32_t nslots,
+                                          uint32_t *startOfUndefined, uint32_t *startOfUninitialized)
 {
     MOZ_ASSERT(nslots == templateObj->lastProperty()->slotSpan(templateObj->getClass()));
     MOZ_ASSERT(nslots > 0);
-    for (uint32_t first = nslots; first != 0; --first) {
-        if (templateObj->getSlot(first - 1) != UndefinedValue())
-            return first;
+    uint32_t first = nslots;
+    for (; first != 0; --first) {
+        if (!IsUninitializedLexical(templateObj->getSlot(first - 1)))
+            break;
     }
-    return 0;
+    *startOfUninitialized = first;
+    for (; first != 0; --first) {
+        if (templateObj->getSlot(first - 1) != UndefinedValue()) {
+            *startOfUndefined = first;
+            return;
+        }
+    }
+    *startOfUndefined = 0;
 }
 
 void
 MacroAssembler::initGCSlots(Register obj, Register slots, NativeObject *templateObj,
                             bool initFixedSlots)
 {
     // Slots of non-array objects are required to be initialized.
     // Use the values currently in the template object.
@@ -796,34 +824,53 @@ MacroAssembler::initGCSlots(Register obj
 
     // Attempt to group slot writes such that we minimize the amount of
     // duplicated data we need to embed in code and load into registers. In
     // general, most template object slots will be undefined except for any
     // reserved slots. Since reserved slots come first, we split the object
     // logically into independent non-UndefinedValue writes to the head and
     // duplicated writes of UndefinedValue to the tail. For the majority of
     // objects, the "tail" will be the entire slot range.
-    uint32_t startOfUndefined = FindStartOfUndefinedSlots(templateObj, nslots);
+    //
+    // The template object may be a CallObject, in which case we need to
+    // account for uninitialized lexical slots as well as undefined
+    // slots. Unitialized lexical slots always appear at the very end of
+    // slots, after undefined.
+    uint32_t startOfUndefined = nslots;
+    uint32_t startOfUninitialized = nslots;
+    FindStartOfUndefinedAndUninitializedSlots(templateObj, nslots,
+                                              &startOfUndefined, &startOfUninitialized);
     MOZ_ASSERT(startOfUndefined <= nfixed); // Reserved slots must be fixed.
+    MOZ_ASSERT_IF(startOfUndefined != nfixed, startOfUndefined <= startOfUninitialized);
+    MOZ_ASSERT_IF(!templateObj->is<CallObject>(), startOfUninitialized == nslots);
 
     // Copy over any preserved reserved slots.
     copySlotsFromTemplate(obj, templateObj, 0, startOfUndefined);
 
-    // Fill the rest of the fixed slots with undefined.
+    // Fill the rest of the fixed slots with undefined and uninitialized.
     if (initFixedSlots) {
         fillSlotsWithUndefined(Address(obj, NativeObject::getFixedSlotOffset(startOfUndefined)), slots,
-                               startOfUndefined, nfixed);
+                               startOfUndefined, Min(startOfUninitialized, nfixed));
+        size_t offset = NativeObject::getFixedSlotOffset(startOfUninitialized);
+        fillSlotsWithUninitialized(Address(obj, offset), slots, startOfUninitialized, nfixed);
     }
 
     if (ndynamic) {
         // We are short one register to do this elegantly. Borrow the obj
         // register briefly for our slots base address.
         push(obj);
         loadPtr(Address(obj, NativeObject::offsetOfSlots()), obj);
+
+        // Initially fill all dynamic slots with undefined.
         fillSlotsWithUndefined(Address(obj, 0), slots, 0, ndynamic);
+
+        // Fill uninitialized slots if necessary.
+        fillSlotsWithUninitialized(Address(obj, 0), slots, startOfUninitialized - nfixed,
+                                   nslots - startOfUninitialized);
+
         pop(obj);
     }
 }
 
 void
 MacroAssembler::initGCThing(Register obj, Register slots, NativeObject *templateObj,
                             bool initFixedSlots)
 {
--- a/js/src/jit/IonMacroAssembler.h
+++ b/js/src/jit/IonMacroAssembler.h
@@ -796,17 +796,20 @@ class MacroAssembler : public MacroAssem
     void nurseryAllocate(Register result, Register slots, gc::AllocKind allocKind,
                          size_t nDynamicSlots, gc::InitialHeap initialHeap, Label *fail);
     void freeListAllocate(Register result, Register temp, gc::AllocKind allocKind, Label *fail);
     void allocateObject(Register result, Register slots, gc::AllocKind allocKind,
                         uint32_t nDynamicSlots, gc::InitialHeap initialHeap, Label *fail);
     void allocateNonObject(Register result, Register temp, gc::AllocKind allocKind, Label *fail);
     void copySlotsFromTemplate(Register obj, const NativeObject *templateObj,
                                uint32_t start, uint32_t end);
+    void fillSlotsWithConstantValue(Address addr, Register temp, uint32_t start, uint32_t end,
+                                    const Value &v);
     void fillSlotsWithUndefined(Address addr, Register temp, uint32_t start, uint32_t end);
+    void fillSlotsWithUninitialized(Address addr, Register temp, uint32_t start, uint32_t end);
     void initGCSlots(Register obj, Register temp, NativeObject *templateObj, bool initFixedSlots);
 
   public:
     void callMallocStub(size_t nbytes, Register result, Label *fail);
     void callFreeStub(Register slots);
     void createGCObject(Register result, Register temp, NativeObject *templateObj,
                         gc::InitialHeap initialHeap, Label *fail, bool initFixedSlots = true);
 
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -1272,16 +1272,33 @@ MPhi::foldsTernary()
     if (!trueDef->isConstant() && !falseDef->isConstant())
         return nullptr;
 
     MConstant *c = trueDef->isConstant() ? trueDef->toConstant() : falseDef->toConstant();
     MDefinition *testArg = (trueDef == c) ? falseDef : trueDef;
     if (testArg != test->input())
         return nullptr;
 
+    // This check should be a tautology, except that the constant might be the
+    // result of the removal of a branch.  In such case the domination scope of
+    // the block which is holding the constant might be incomplete. This
+    // condition is used to prevent doing this optimization based on incomplete
+    // information.
+    //
+    // As GVN removed a branch, it will update the dominations rules before
+    // trying to fold this MPhi again. Thus, this condition does not inhibit
+    // this optimization.
+    MBasicBlock *truePred = block()->getPredecessor(firstIsTrueBranch ? 0 : 1);
+    MBasicBlock *falsePred = block()->getPredecessor(firstIsTrueBranch ? 1 : 0);
+    if (!trueDef->block()->dominates(truePred) ||
+        !falseDef->block()->dominates(falsePred))
+    {
+        return nullptr;
+    }
+
     // If testArg is an int32 type we can:
     // - fold testArg ? testArg : 0 to testArg
     // - fold testArg ? 0 : testArg to 0
     if (testArg->type() == MIRType_Int32 && c->vp()->toNumber() == 0) {
         // When folding to the constant we need to hoist it.
         if (trueDef == c && !c->block()->dominates(block()))
             c->block()->moveBefore(pred->lastIns(), c);
         return trueDef;
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -550,37 +550,37 @@ InterruptCheck(JSContext *cx)
 
 void *
 MallocWrapper(JSRuntime *rt, size_t nbytes)
 {
     return rt->pod_malloc<uint8_t>(nbytes);
 }
 
 JSObject *
-NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type)
+NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type, uint32_t lexicalBegin)
 {
-    JSObject *obj = CallObject::create(cx, shape, type);
+    JSObject *obj = CallObject::create(cx, shape, type, lexicalBegin);
     if (!obj)
         return nullptr;
 
 #ifdef JSGC_GENERATIONAL
     // The JIT creates call objects in the nursery, so elides barriers for
     // the initializing writes. The interpreter, however, may have allocated
     // the call object tenured, so barrier as needed before re-entering.
     if (!IsInsideNursery(obj))
         cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(obj);
 #endif
 
     return obj;
 }
 
 JSObject *
-NewSingletonCallObject(JSContext *cx, HandleShape shape)
+NewSingletonCallObject(JSContext *cx, HandleShape shape, uint32_t lexicalBegin)
 {
-    JSObject *obj = CallObject::createSingleton(cx, shape);
+    JSObject *obj = CallObject::createSingleton(cx, shape, lexicalBegin);
     if (!obj)
         return nullptr;
 
 #ifdef JSGC_GENERATIONAL
     // The JIT creates call objects in the nursery, so elides barriers for
     // the initializing writes. The interpreter, however, may have allocated
     // the call object tenured, so barrier as needed before re-entering.
     MOZ_ASSERT(!IsInsideNursery(obj),
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -662,18 +662,19 @@ bool CharCodeAt(JSContext *cx, HandleStr
 JSFlatString *StringFromCharCode(JSContext *cx, int32_t code);
 
 bool SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
                  bool strict, jsbytecode *pc);
 
 bool InterruptCheck(JSContext *cx);
 
 void *MallocWrapper(JSRuntime *rt, size_t nbytes);
-JSObject *NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type);
-JSObject *NewSingletonCallObject(JSContext *cx, HandleShape shape);
+JSObject *NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type,
+                        uint32_t lexicalBegin);
+JSObject *NewSingletonCallObject(JSContext *cx, HandleShape shape, uint32_t lexicalBegin);
 JSObject *NewStringObject(JSContext *cx, HandleString str);
 
 bool SPSEnter(JSContext *cx, HandleScript script);
 bool SPSExit(JSContext *cx, HandleScript script);
 
 bool OperatorIn(JSContext *cx, HandleValue key, HandleObject obj, bool *out);
 bool OperatorInI(JSContext *cx, uint32_t index, HandleObject obj, bool *out);
 
--- a/js/src/jit/ValueNumbering.cpp
+++ b/js/src/jit/ValueNumbering.cpp
@@ -653,16 +653,20 @@ ValueNumberer::leader(MDefinition *def)
             // The congruent value doesn't dominate. It never will again in this
             // dominator tree, so overwrite it.
             values_.overwrite(p, def);
         } else {
             // No match. Add a new entry.
             if (!values_.add(p, def))
                 return nullptr;
         }
+
+#ifdef DEBUG
+        JitSpew(JitSpew_GVN, "      Recording %s%u", def->opName(), def->id());
+#endif
     }
 
     return def;
 }
 
 // Test whether |phi| is dominated by a congruent phi.
 bool
 ValueNumberer::hasLeader(const MPhi *phi, const MBasicBlock *phiBlock) const
--- a/js/src/vm/ScopeObject-inl.h
+++ b/js/src/vm/ScopeObject-inl.h
@@ -49,22 +49,27 @@ inline void
 CallObject::setAliasedVarFromArguments(JSContext *cx, const Value &argsValue, jsid id, const Value &v)
 {
     setSlot(argsValue.magicUint32(), v);
     if (hasSingletonType())
         types::AddTypePropertyId(cx, this, id, v);
 }
 
 inline void
-CallObject::setAliasedLexicalsToThrowOnTouch(JSScript *script)
+CallObject::initRemainingSlotsToUninitializedLexicals(uint32_t begin)
 {
-    uint32_t aliasedLexicalBegin = script->bindings.aliasedBodyLevelLexicalBegin();
-    uint32_t aliasedLexicalEnd = numFixedSlots();
-    for (uint32_t slot = aliasedLexicalBegin; slot < aliasedLexicalEnd; slot++)
-        initFixedSlot(slot, MagicValue(JS_UNINITIALIZED_LEXICAL));
+    uint32_t end = slotSpan();
+    for (uint32_t slot = begin; slot < end; slot++)
+        initSlot(slot, MagicValue(JS_UNINITIALIZED_LEXICAL));
+}
+
+inline void
+CallObject::initAliasedLexicalsToThrowOnTouch(JSScript *script)
+{
+    initRemainingSlotsToUninitializedLexicals(script->bindings.aliasedBodyLevelLexicalBegin());
 }
 
 template <AllowGC allowGC>
 inline bool
 StaticScopeIter<allowGC>::done() const
 {
     return !obj;
 }
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -134,49 +134,51 @@ void
 ScopeObject::setEnclosingScope(HandleObject obj)
 {
     MOZ_ASSERT_IF(obj->is<CallObject>() || obj->is<DeclEnvObject>() || obj->is<BlockObject>(),
                   obj->isDelegate());
     setFixedSlot(SCOPE_CHAIN_SLOT, ObjectValue(*obj));
 }
 
 CallObject *
-CallObject::create(JSContext *cx, HandleShape shape, HandleTypeObject type)
+CallObject::create(JSContext *cx, HandleShape shape, HandleTypeObject type, uint32_t lexicalBegin)
 {
     MOZ_ASSERT(!type->singleton(),
                "passed a singleton type to create() (use createSingleton() "
                "instead)");
     gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
     MOZ_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_));
     kind = gc::GetBackgroundAllocKind(kind);
 
     JSObject *obj = JSObject::create(cx, kind, gc::DefaultHeap, shape, type);
     if (!obj)
         return nullptr;
 
+    obj->as<CallObject>().initRemainingSlotsToUninitializedLexicals(lexicalBegin);
     return &obj->as<CallObject>();
 }
 
 CallObject *
-CallObject::createSingleton(JSContext *cx, HandleShape shape)
+CallObject::createSingleton(JSContext *cx, HandleShape shape, uint32_t lexicalBegin)
 {
     gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
     MOZ_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_));
     kind = gc::GetBackgroundAllocKind(kind);
 
     RootedTypeObject type(cx, cx->getSingletonType(&class_, TaggedProto(nullptr)));
     if (!type)
         return nullptr;
     RootedObject obj(cx, JSObject::create(cx, kind, gc::TenuredHeap, shape, type));
     if (!obj)
         return nullptr;
 
     MOZ_ASSERT(obj->hasSingletonType(),
                "type created inline above must be a singleton");
 
+    obj->as<CallObject>().initRemainingSlotsToUninitializedLexicals(lexicalBegin);
     return &obj->as<CallObject>();
 }
 
 /*
  * Create a CallObject for a JSScript that is not initialized to any particular
  * callsite. This object can either be initialized (with an enclosing scope and
  * callee) or used as a template for jit compilation.
  */
@@ -193,16 +195,20 @@ CallObject::createTemplateObject(JSConte
     gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
     MOZ_ASSERT(CanBeFinalizedInBackground(kind, &class_));
     kind = gc::GetBackgroundAllocKind(kind);
 
     JSObject *obj = JSObject::create(cx, kind, heap, shape, type);
     if (!obj)
         return nullptr;
 
+    // Set uninitialized lexicals even on template objects, as Ion will use
+    // copy over the template object's slot values in the fast path.
+    obj->as<CallObject>().initAliasedLexicalsToThrowOnTouch(script);
+
     return &obj->as<CallObject>();
 }
 
 /*
  * Construct a call object for the given bindings.  If this is a call object
  * for a function invocation, callee should be the function being called.
  * Otherwise it must be a call object for eval of strict mode code, and callee
  * must be null.
@@ -212,17 +218,16 @@ CallObject::create(JSContext *cx, Handle
 {
     gc::InitialHeap heap = script->treatAsRunOnce() ? gc::TenuredHeap : gc::DefaultHeap;
     CallObject *callobj = CallObject::createTemplateObject(cx, script, heap);
     if (!callobj)
         return nullptr;
 
     callobj->as<ScopeObject>().setEnclosingScope(enclosing);
     callobj->initFixedSlot(CALLEE_SLOT, ObjectOrNullValue(callee));
-    callobj->setAliasedLexicalsToThrowOnTouch(script);
 
     if (script->treatAsRunOnce()) {
         Rooted<CallObject*> ncallobj(cx, callobj);
         if (!JSObject::setSingletonType(cx, ncallobj))
             return nullptr;
         return ncallobj;
     }
 
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -232,36 +232,37 @@ class ScopeObject : public NativeObject
 
 class CallObject : public ScopeObject
 {
     static const uint32_t CALLEE_SLOT = 1;
 
     static CallObject *
     create(JSContext *cx, HandleScript script, HandleObject enclosing, HandleFunction callee);
 
-    inline void setAliasedLexicalsToThrowOnTouch(JSScript *script);
+    inline void initRemainingSlotsToUninitializedLexicals(uint32_t begin);
+    inline void initAliasedLexicalsToThrowOnTouch(JSScript *script);
 
   public:
     static const Class class_;
 
     /* These functions are internal and are exposed only for JITs. */
 
     /*
      * Construct a bare-bones call object given a shape and a non-singleton
      * type.  The call object must be further initialized to be usable.
      */
     static CallObject *
-    create(JSContext *cx, HandleShape shape, HandleTypeObject type);
+    create(JSContext *cx, HandleShape shape, HandleTypeObject type, uint32_t lexicalBegin);
 
     /*
      * Construct a bare-bones call object given a shape and make it have
      * singleton type.  The call object must be initialized to be usable.
      */
     static CallObject *
-    createSingleton(JSContext *cx, HandleShape shape);
+    createSingleton(JSContext *cx, HandleShape shape, uint32_t lexicalBegin);
 
     static CallObject *
     createTemplateObject(JSContext *cx, HandleScript script, gc::InitialHeap heap);
 
     static const uint32_t RESERVED_SLOTS = 2;
 
     static CallObject *createForFunction(JSContext *cx, HandleObject enclosing, HandleFunction callee);
 
--- a/layout/base/PositionedEventTargeting.cpp
+++ b/layout/base/PositionedEventTargeting.cpp
@@ -238,25 +238,32 @@ ClipToFrame(nsIFrame* aRootFrame, nsIFra
   nsRect bound = nsLayoutUtils::TransformFrameRectToAncestor(
     aFrame, nsRect(nsPoint(0, 0), aFrame->GetSize()), aRootFrame);
   nsRect result = bound.Intersect(aRect);
   return result;
 }
 
 static nsRect
 GetTargetRect(nsIFrame* aRootFrame, const nsPoint& aPointRelativeToRootFrame,
-              nsIFrame* aRestrictToDescendants, const EventRadiusPrefs* aPrefs)
+              nsIFrame* aRestrictToDescendants, const EventRadiusPrefs* aPrefs,
+              uint32_t aFlags)
 {
   nsMargin m(AppUnitsFromMM(aRootFrame, aPrefs->mSideRadii[0], true),
              AppUnitsFromMM(aRootFrame, aPrefs->mSideRadii[1], false),
              AppUnitsFromMM(aRootFrame, aPrefs->mSideRadii[2], true),
              AppUnitsFromMM(aRootFrame, aPrefs->mSideRadii[3], false));
   nsRect r(aPointRelativeToRootFrame, nsSize(0,0));
   r.Inflate(m);
-  return ClipToFrame(aRootFrame, aRestrictToDescendants, r);
+  if (!(aFlags & INPUT_IGNORE_ROOT_SCROLL_FRAME)) {
+    // Don't clip this rect to the root scroll frame if the flag to ignore the
+    // root scroll frame is set. Note that the GetClosest code will still enforce
+    // that the target found is a descendant of aRestrictToDescendants.
+    r = ClipToFrame(aRootFrame, aRestrictToDescendants, r);
+  }
+  return r;
 }
 
 static float
 ComputeDistanceFromRect(const nsPoint& aPoint, const nsRect& aRect)
 {
   nscoord dx = std::max(0, std::max(aRect.x - aPoint.x, aPoint.x - aRect.XMost()));
   nscoord dy = std::max(0, std::max(aRect.y - aPoint.y, aPoint.y - aRect.YMost()));
   return float(NS_hypot(dx, dy));
@@ -381,17 +388,17 @@ FindFrameTargetedByInputEvent(const Widg
   // document as the exact target. Otherwise, if an ancestor document has
   // a mouse event handler for example, targets that are !IsElementClickable can
   // never be targeted --- something nsSubDocumentFrame in an ancestor document
   // would be targeted instead.
   nsIFrame* restrictToDescendants = target ?
     target->PresContext()->PresShell()->GetRootFrame() : aRootFrame;
 
   nsRect targetRect = GetTargetRect(aRootFrame, aPointRelativeToRootFrame,
-                                    restrictToDescendants, prefs);
+                                    restrictToDescendants, prefs, aFlags);
   nsAutoTArray<nsIFrame*,8> candidates;
   nsresult rv = nsLayoutUtils::GetFramesForArea(aRootFrame, targetRect, candidates, flags);
   if (NS_FAILED(rv)) {
     return target;
   }
 
   nsIFrame* closestClickable =
     GetClosest(aRootFrame, aPointRelativeToRootFrame, targetRect, prefs,
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -1522,16 +1522,22 @@ RestyleManager::DoRebuildAllStyleData(Re
 
 void
 RestyleManager::ProcessPendingRestyles()
 {
   NS_PRECONDITION(mPresContext->Document(), "No document?  Pshaw!");
   NS_PRECONDITION(!nsContentUtils::IsSafeToRunScript(),
                   "Missing a script blocker!");
 
+  if (mRebuildAllStyleData) {
+    RebuildAllStyleData(nsChangeHint(0), nsRestyleHint(0));
+    MOZ_ASSERT(mPendingRestyles.Count() == 0);
+    return;
+  }
+
   // First do any queued-up frame creation.  (We should really
   // merge this into the rest of the process, though; see bug 827239.)
   mPresContext->FrameConstructor()->CreateNeededFrames();
 
   // Process non-animation restyles...
   NS_ABORT_IF_FALSE(!mIsProcessingRestyles,
                     "Nesting calls to ProcessPendingRestyles?");
 #ifdef DEBUG
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -5312,41 +5312,49 @@ nsLayoutUtils::DrawSingleImage(nsRenderi
                                imgIContainer*         aImage,
                                GraphicsFilter         aGraphicsFilter,
                                const nsRect&          aDest,
                                const nsRect&          aDirty,
                                const SVGImageContext* aSVGContext,
                                uint32_t               aImageFlags,
                                const nsRect*          aSourceArea)
 {
-  nsIntSize imageSize(ComputeSizeForDrawingWithFallback(aImage, aDest.Size()));
-  NS_ENSURE_TRUE(imageSize.width > 0 && imageSize.height > 0, NS_ERROR_FAILURE);
+  nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel();
+  nsIntSize pixelImageSize(ComputeSizeForDrawingWithFallback(aImage, aDest.Size()));
+  NS_ENSURE_TRUE(pixelImageSize.width > 0 && pixelImageSize.height > 0, NS_ERROR_FAILURE);
+  nsSize imageSize(pixelImageSize.width * appUnitsPerCSSPixel,
+                   pixelImageSize.height * appUnitsPerCSSPixel);
 
   nsRect source;
   nsCOMPtr<imgIContainer> image;
   if (aSourceArea) {
     source = *aSourceArea;
     nsIntRect subRect(source.x, source.y, source.width, source.height);
-    subRect.ScaleInverseRoundOut(nsDeviceContext::AppUnitsPerCSSPixel());
+    subRect.ScaleInverseRoundOut(appUnitsPerCSSPixel);
     image = ImageOps::Clip(aImage, subRect);
+
+    nsRect imageRect;
+    imageRect.SizeTo(imageSize);
+    nsRect clippedSource = imageRect.Intersect(source);
+
+    source -= clippedSource.TopLeft();
+    imageSize = clippedSource.Size();
   } else {
-    nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel();
-    source.SizeTo(imageSize.width*appUnitsPerCSSPixel,
-                  imageSize.height*appUnitsPerCSSPixel);
+    source.SizeTo(imageSize);
     image = aImage;
   }
 
-  nsRect dest = nsLayoutUtils::GetWholeImageDestination(imageSize, source,
-                                                        aDest);
+  nsRect dest = GetWholeImageDestination(imageSize, source, aDest);
+
   // Ensure that only a single image tile is drawn. If aSourceArea extends
   // outside the image bounds, we want to honor the aSourceArea-to-aDest
   // transform but we don't want to actually tile the image.
   nsRect fill;
   fill.IntersectRect(aDest, dest);
-  return DrawImageInternal(aRenderingContext, aPresContext, aImage,
+  return DrawImageInternal(aRenderingContext, aPresContext, image,
                            aGraphicsFilter, dest, fill, fill.TopLeft(),
                            aDirty, aSVGContext, aImageFlags);
 }
 
 /* static */ void
 nsLayoutUtils::ComputeSizeForDrawing(imgIContainer *aImage,
                                      nsIntSize&     aImageSize, /*outparam*/
                                      nsSize&        aIntrinsicRatio, /*outparam*/
@@ -5447,31 +5455,42 @@ nsLayoutUtils::DrawImage(nsRenderingCont
                          uint32_t            aImageFlags)
 {
   return DrawImageInternal(aRenderingContext, aPresContext, aImage,
                            aGraphicsFilter, aDest, aFill, aAnchor,
                            aDirty, nullptr, aImageFlags);
 }
 
 /* static */ nsRect
-nsLayoutUtils::GetWholeImageDestination(const nsIntSize& aWholeImageSize,
+nsLayoutUtils::GetWholeImageDestination(const nsSize& aWholeImageSize,
                                         const nsRect& aImageSourceArea,
                                         const nsRect& aDestArea)
 {
   double scaleX = double(aDestArea.width)/aImageSourceArea.width;
   double scaleY = double(aDestArea.height)/aImageSourceArea.height;
   nscoord destOffsetX = NSToCoordRound(aImageSourceArea.x*scaleX);
   nscoord destOffsetY = NSToCoordRound(aImageSourceArea.y*scaleY);
-  nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel();
-  nscoord wholeSizeX = NSToCoordRound(aWholeImageSize.width*appUnitsPerCSSPixel*scaleX);
-  nscoord wholeSizeY = NSToCoordRound(aWholeImageSize.height*appUnitsPerCSSPixel*scaleY);
+  nscoord wholeSizeX = NSToCoordRound(aWholeImageSize.width*scaleX);
+  nscoord wholeSizeY = NSToCoordRound(aWholeImageSize.height*scaleY);
   return nsRect(aDestArea.TopLeft() - nsPoint(destOffsetX, destOffsetY),
                 nsSize(wholeSizeX, wholeSizeY));
 }
 
+/* static */ nsRect
+nsLayoutUtils::GetWholeImageDestination(const nsIntSize& aWholeImageSize,
+                                        const nsRect& aImageSourceArea,
+                                        const nsRect& aDestArea)
+{
+  nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel();
+  return GetWholeImageDestination(nsSize(aWholeImageSize.width * appUnitsPerCSSPixel,
+                                         aWholeImageSize.height * appUnitsPerCSSPixel),
+                                  aImageSourceArea,
+                                  aDestArea);
+}
+
 /* static */ already_AddRefed<imgIContainer>
 nsLayoutUtils::OrientImage(imgIContainer* aContainer,
                            const nsStyleImageOrientation& aOrientation)
 {
   MOZ_ASSERT(aContainer, "Should have an image container");
   nsCOMPtr<imgIContainer> img(aContainer);
 
   if (aOrientation.IsFromImage()) {
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1588,16 +1588,20 @@ public:
    * would be covered by the whole image. This is useful for passing to
    * the aDest parameter of DrawImage, when we want to draw a subimage
    * of an overall image.
    */
   static nsRect GetWholeImageDestination(const nsIntSize& aWholeImageSize,
                                          const nsRect& aImageSourceArea,
                                          const nsRect& aDestArea);
 
+  static nsRect GetWholeImageDestination(const nsSize& aWholeImageSize,
+                                         const nsRect& aImageSourceArea,
+                                         const nsRect& aDestArea);
+
   /**
    * Given an image container and an orientation, returns an image container
    * that contains the same image, reoriented appropriately. May return the
    * original image container if no changes are needed.
    *
    * @param aContainer   The image container to apply the orientation to.
    * @param aOrientation The desired orientation.
    */
--- a/layout/reftests/font-face/reftest.list
+++ b/layout/reftests/font-face/reftest.list
@@ -2,19 +2,19 @@
 # ../fonts/.  We can't use file:/// URLs because of cross-directory access
 # restrictions on file: URLs.
 
 HTTP(..) != download-1.html download-1-notref.html
 HTTP(..) == download-2.html download-2-ref.html
 HTTP(..) != download-2.html about:blank
 random-if(winWidget) HTTP(..) == download-2-big.html download-2-big-otf.html # bug 470713
 HTTP(..) != download-2-big-otf.html about:blank
-asserts-if(Android,2) skip-if(Android&&AndroidVersion==17) HTTP(..) != download-3-notref.html download-3.html # bug 1019192, bug 936226
-HTTP(..) == download-3-ref.html download-3.html
-HTTP(..) == fallback-to-system-1.html fallback-to-system-1-ref.html
+asserts-if(Android,4-8) skip-if(Android&&AndroidVersion==17) HTTP(..) != download-3-notref.html download-3.html # bug 1019192, bug 936226
+asserts-if(Android,0-8) HTTP(..) == download-3-ref.html download-3.html # same bugs as above
+asserts-if(Android,0-8) HTTP(..) == fallback-to-system-1.html fallback-to-system-1-ref.html # just delayed assertions from above tests
 HTTP(..) == name-override-simple-1.html name-override-simple-1-ref.html
 HTTP(..) != name-override-simple-1.html download-1-notref.html
 fails HTTP(..) == name-override-1.html name-override-1-ref.html
 HTTP(..) == multiple-descriptor-1.html multiple-descriptor-1-ref.html
 HTTP(..) != multiple-descriptor-1.html multiple-descriptor-1-notref.html
 HTTP(..) == src-list-1.html src-list-1-ref.html
 HTTP(..) == src-list-2.html src-list-2-ref.html
 random-if(winWidget) HTTP(..) == src-list-2-big-otf.html src-list-2-big-ref.html # bug 470713
--- a/media/libstagefright/binding/Adts.cpp
+++ b/media/libstagefright/binding/Adts.cpp
@@ -28,18 +28,18 @@ Adts::GetFrequencyIndex(uint16_t aSample
   if (!freq_lookup[i]) {
     return -1;
   }
 
   return i;
 }
 
 bool
-Adts::ConvertEsdsToAdts(uint16_t aChannelCount, int8_t aFrequencyIndex,
-                        int8_t aProfile, MP4Sample* aSample)
+Adts::ConvertSample(uint16_t aChannelCount, int8_t aFrequencyIndex,
+                    int8_t aProfile, MP4Sample* aSample)
 {
   static const int kADTSHeaderSize = 7;
 
   size_t newSize = aSample->size + kADTSHeaderSize;
 
   // ADTS header uses 13 bits for packet size.
   if (newSize >= (1 << 13) || aChannelCount > 15 ||
       aFrequencyIndex < 0 || aProfile < 1 || aProfile > 4)
--- a/media/libstagefright/binding/include/mp4_demuxer/Adts.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/Adts.h
@@ -11,14 +11,14 @@ namespace mp4_demuxer
 {
 
 class MP4Sample;
 
 class Adts
 {
 public:
   static int8_t GetFrequencyIndex(uint16_t aSamplesPerSecond);
-  static bool ConvertEsdsToAdts(uint16_t aChannelCount, int8_t aFrequencyIndex,
-                                int8_t aProfile, MP4Sample* aSample);
+  static bool ConvertSample(uint16_t aChannelCount, int8_t aFrequencyIndex,
+                            int8_t aProfile, MP4Sample* aSample);
 };
 }
 
 #endif
--- a/media/libstagefright/binding/mp4_demuxer.cpp
+++ b/media/libstagefright/binding/mp4_demuxer.cpp
@@ -2,17 +2,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "include/MPEG4Extractor.h"
 #include "media/stagefright/DataSource.h"
 #include "media/stagefright/MediaDefs.h"
 #include "media/stagefright/MediaSource.h"
 #include "media/stagefright/MetaData.h"
-#include "mp4_demuxer/Adts.h"
 #include "mp4_demuxer/mp4_demuxer.h"
 #include "mp4_demuxer/Index.h"
 #include "MediaResource.h"
 
 #include <stdint.h>
 #include <algorithm>
 #include <limits>
 
@@ -170,23 +169,16 @@ MP4Demuxer::DemuxAudioSample()
     mPrivate->mAudio->read(&sample->mMediaBuffer, &mPrivate->mAudioOptions);
   mPrivate->mAudioOptions.clearSeekTo();
 
   if (status < 0) {
     return nullptr;
   }
 
   sample->Update();
-  if (!strcmp(mAudioConfig.mime_type, MEDIA_MIMETYPE_AUDIO_AAC)) {
-    if (!Adts::ConvertEsdsToAdts(mAudioConfig.channel_count,
-                                 mAudioConfig.frequency_index,
-                                 mAudioConfig.aac_profile, sample)) {
-      return nullptr;
-    }
-  }
 
   return sample.forget();
 }
 
 MP4Sample*
 MP4Demuxer::DemuxVideoSample()
 {
   nsAutoPtr<MP4Sample> sample(new MP4Sample());
--- a/media/libstagefright/moz.build
+++ b/media/libstagefright/moz.build
@@ -43,16 +43,17 @@ if CONFIG['OS_TARGET'] != 'Android':
     ]
     UNIFIED_SOURCES += [
         'system/core/libcutils/strdup16to8.c',
         'system/core/liblog/logd_write.c',
         'system/core/liblog/logprint.c',
     ]
 
 EXPORTS.mp4_demuxer += [
+    'binding/include/mp4_demuxer/Adts.h',
     'binding/include/mp4_demuxer/AnnexB.h',
     'binding/include/mp4_demuxer/BufferStream.h',
     'binding/include/mp4_demuxer/ByteReader.h',
     'binding/include/mp4_demuxer/DecoderData.h',
     'binding/include/mp4_demuxer/Interval.h',
     'binding/include/mp4_demuxer/MoofParser.h',
     'binding/include/mp4_demuxer/mp4_demuxer.h',
 ]
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -605,16 +605,22 @@ pref("media.preload.auto", 2);    // pre
 // Number of video frames we buffer while decoding video.
 // On Android this is decided by a similar value which varies for
 // each OMX decoder |OMX_PARAM_PORTDEFINITIONTYPE::nBufferCountMin|. This
 // number must be less than the OMX equivalent or gecko will think it is
 // chronically starved of video frames. All decoders seen so far have a value
 // of at least 4.
 pref("media.video-queue.default-size", 3);
 
+// Enable the MediaCodec PlatformDecoderModule by default.
+pref("media.fragmented-mp4.exposed", true);
+pref("media.fragmented-mp4.enabled", true);
+pref("media.fragmented-mp4.android-media-codec.enabled", true);
+pref("media.fragmented-mp4.android-media-codec.preferred", true);
+
 // optimize images memory usage
 pref("image.mem.decodeondraw", true);
 pref("image.mem.min_discard_timeout_ms", 10000);
 
 #ifdef NIGHTLY_BUILD
 // Shumway component (SWF player) is disabled by default. Also see bug 904346.
 pref("shumway.disabled", true);
 #endif
--- a/mobile/android/base/ChromeCast.java
+++ b/mobile/android/base/ChromeCast.java
@@ -43,16 +43,35 @@ class ChromeCast implements GeckoMediaPl
     private final RouteInfo route;
     private GoogleApiClient apiClient;
     private RemoteMediaPlayer remoteMediaPlayer;
     private final boolean canMirror;
     private String mSessionId;
     private MirrorChannel mMirrorChannel;
     private boolean mApplicationStarted = false;
 
+    // EventCallback which is actually a GeckoEventCallback is sometimes being invoked more
+    // than once. That causes the IllegalStateException to be thrown. To prevent a crash,
+    // catch the exception and report it as an error to the log.
+    private static void sendSuccess(final EventCallback callback, final String msg) {
+        try {
+            callback.sendSuccess(msg);
+        } catch (final IllegalStateException e) {
+            Log.e(LOGTAG, "Attempting to invoke callback.sendSuccess more than once.", e);
+        }
+    }
+
+    private static void sendError(final EventCallback callback, final String msg) {
+        try {
+            callback.sendError(msg);
+        } catch (final IllegalStateException e) {
+            Log.e(LOGTAG, "Attempting to invoke callback.sendError more than once.", e);
+        }
+    }
+
     // Callback to start playback of a url on a remote device
     private class VideoPlayCallback implements ResultCallback<ApplicationConnectionResult>,
                                                RemoteMediaPlayer.OnStatusUpdatedListener,
                                                RemoteMediaPlayer.OnMetadataUpdatedListener {
         private final String url;
         private final String type;
         private final String title;
         private final EventCallback callback;
@@ -96,51 +115,51 @@ class ChromeCast implements GeckoMediaPl
                 try {
                     Cast.CastApi.setMessageReceivedCallbacks(apiClient, remoteMediaPlayer.getNamespace(), remoteMediaPlayer);
                 } catch (IOException e) {
                     debug("Exception while creating media channel", e);
                 }
 
                 startPlayback();
             } else {
-                callback.sendError(status.toString());
+                sendError(callback, status.toString());
             }
         }
 
         private void startPlayback() {
             MediaMetadata mediaMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
             mediaMetadata.putString(MediaMetadata.KEY_TITLE, title);
             MediaInfo mediaInfo = new MediaInfo.Builder(url)
                                                .setContentType(type)
                                                .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
                                                .setMetadata(mediaMetadata)
                                                .build();
             try {
                 remoteMediaPlayer.load(apiClient, mediaInfo, true).setResultCallback(new ResultCallback<RemoteMediaPlayer.MediaChannelResult>() {
                     @Override
                     public void onResult(MediaChannelResult result) {
                         if (result.getStatus().isSuccess()) {
-                            callback.sendSuccess(null);
+                            sendSuccess(callback, null);
                             debug("Media loaded successfully");
                             return;
                         }
 
                         debug("Media load failed " + result.getStatus());
-                        callback.sendError(result.getStatus().toString());
+                        sendError(callback, result.getStatus().toString());
                     }
                 });
 
                 return;
             } catch (IllegalStateException e) {
                 debug("Problem occurred with media during loading", e);
             } catch (Exception e) {
                 debug("Problem opening media during loading", e);
             }
 
-            callback.sendError("");
+            sendError(callback, "");
         }
     }
 
     public ChromeCast(Context context, RouteInfo route) {
         int status =  GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
         if (status != ConnectionResult.SUCCESS) {
             throw new IllegalStateException("Play services are required for Chromecast support (go status code " + status + ")");
         }
@@ -193,17 +212,17 @@ class ChromeCast implements GeckoMediaPl
         apiClient = new GoogleApiClient.Builder(context)
             .addApi(Cast.API, apiOptionsBuilder.build())
             .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
                 @Override
                 public void onConnected(Bundle connectionHint) {
                     // Sometimes apiClient is null here. See bug 1061032
                     if (apiClient != null && !apiClient.isConnected()) {
                         debug("Connection failed");
-                        callback.sendError("Not connected");
+                        sendError(callback, "Not connected");
                         return;
                     }
 
                     // Launch the media player app and launch this url once its loaded
                     try {
                         Cast.CastApi.launchApplication(apiClient, CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID, true)
                                     .setResultCallback(new VideoPlayCallback(url, type, title, callback));
                     } catch (Exception e) {
@@ -218,39 +237,39 @@ class ChromeCast implements GeckoMediaPl
         }).build();
 
         apiClient.connect();
     }
 
     @Override
     public void start(final EventCallback callback) {
         // Nothing to be done here
-        callback.sendSuccess(null);
+        sendSuccess(callback, null);
     }
 
     @Override
     public void stop(final EventCallback callback) {
         // Nothing to be done here
-        callback.sendSuccess(null);
+        sendSuccess(callback, null);
     }
 
     public boolean verifySession(final EventCallback callback) {
         String msg = null;
         if (apiClient == null || !apiClient.isConnected()) {
             msg = "Not connected";
         }
 
         if (mSessionId == null) {
             msg = "No session";
         }
 
         if (msg != null) {
             debug(msg);
             if (callback != null) {
-                callback.sendError(msg);
+                sendError(callback, msg);
             }
             return false;
         }
 
         return true;
     }
 
     @Override
@@ -261,50 +280,50 @@ class ChromeCast implements GeckoMediaPl
 
         try {
             remoteMediaPlayer.play(apiClient).setResultCallback(new ResultCallback<MediaChannelResult>() {
                 @Override
                 public void onResult(MediaChannelResult result) {
                     Status status = result.getStatus();
                     if (!status.isSuccess()) {
                         debug("Unable to play: " + status.getStatusCode());
-                        callback.sendError(status.toString());
+                        sendError(callback, status.toString());
                     } else {
-                        callback.sendSuccess(null);
+                        sendSuccess(callback, null);
                     }
                 }
             });
         } catch(IllegalStateException ex) {
             // The media player may throw if the session has been killed. For now, we're just catching this here.
-            callback.sendError("Error playing");
+            sendError(callback, "Error playing");
         }
     }
 
     @Override
     public void pause(final EventCallback callback) {
         if (!verifySession(callback)) {
             return;
         }
 
         try {
             remoteMediaPlayer.pause(apiClient).setResultCallback(new ResultCallback<MediaChannelResult>() {
                 @Override
                 public void onResult(MediaChannelResult result) {
                     Status status = result.getStatus();
                     if (!status.isSuccess()) {
                         debug("Unable to pause: " + status.getStatusCode());
-                        callback.sendError(status.toString());
+                        sendError(callback, status.toString());
                     } else {
-                        callback.sendSuccess(null);
+                        sendSuccess(callback, null);
                     }
                 }
             });
         } catch(IllegalStateException ex) {
             // The media player may throw if the session has been killed. For now, we're just catching this here.
-            callback.sendError("Error pausing");
+            sendError(callback, "Error pausing");
         }
     }
 
     @Override
     public void end(final EventCallback callback) {
         if (!verifySession(callback)) {
             return;
         }
@@ -317,33 +336,33 @@ class ChromeCast implements GeckoMediaPl
                         try {
                             Cast.CastApi.removeMessageReceivedCallbacks(apiClient, remoteMediaPlayer.getNamespace());
                             remoteMediaPlayer = null;
                             mSessionId = null;
                             apiClient.disconnect();
                             apiClient = null;
 
                             if (callback != null) {
-                                callback.sendSuccess(null);
+                                sendSuccess(callback, null);
                             }
 
                             return;
                         } catch(Exception ex) {
                             debug("Error ending", ex);
                         }
                     }
 
                     if (callback != null) {
-                        callback.sendError(result.getStatus().toString());
+                        sendError(callback, result.getStatus().toString());
                     }
                 }
             });
         } catch(IllegalStateException ex) {
             // The media player may throw if the session has been killed. For now, we're just catching this here.
-            callback.sendError("Error stopping");
+            sendError(callback, "Error stopping");
         }
     }
 
     class MirrorChannel implements MessageReceivedCallback {
         /**
          * @return custom namespace
          */
         public String getNamespace() {
@@ -371,17 +390,16 @@ class ChromeCast implements GeckoMediaPl
                                            });
                 } catch (Exception e) {
                     Log.e(LOGTAG, "Exception while sending message", e);
                 }
             }
         }
     }
     private class MirrorCallback implements ResultCallback<ApplicationConnectionResult> {
-
         final EventCallback callback;
         MirrorCallback(final EventCallback callback) {
             this.callback = callback;
         }
 
 
         @Override
         public void onResult(ApplicationConnectionResult result) {
@@ -396,24 +414,24 @@ class ChromeCast implements GeckoMediaPl
                 // Create the custom message
                 // channel
                 mMirrorChannel = new MirrorChannel();
                 try {
                     Cast.CastApi.setMessageReceivedCallbacks(apiClient,
                                                              mMirrorChannel
                                                              .getNamespace(),
                                                              mMirrorChannel);
-                    callback.sendSuccess(null);
+                    sendSuccess(callback, null);
                 } catch (IOException e) {
                     Log.e(LOGTAG, "Exception while creating channel", e);
                 }
 
                 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Casting:Mirror", route.getId()));
             } else {
-                callback.sendError(status.toString());
+                sendError(callback, status.toString());
             }
         }
     }
 
     @Override
     public void message(String msg, final EventCallback callback) {
         if (mMirrorChannel != null) {
             mMirrorChannel.sendMessage(msg);
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -2465,17 +2465,17 @@ public class GeckoAppShell
     }
 
     @WrapElementForJNI
     public static void notifyWakeLockChanged(String topic, String state) {
         if (getGeckoInterface() != null)
             getGeckoInterface().notifyWakeLockChanged(topic, state);
     }
 
-    @WrapElementForJNI
+    @WrapElementForJNI(allowMultithread = true)
     public static void registerSurfaceTextureFrameListener(Object surfaceTexture, final int id) {
         ((SurfaceTexture)surfaceTexture).setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
             @Override
             public void onFrameAvailable(SurfaceTexture surfaceTexture) {
                 GeckoAppShell.onSurfaceTextureFrameAvailable(surfaceTexture, id);
             }
         });
     }
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -468,17 +468,47 @@ var BrowserApp = {
 
     if (!ParentalControls.isAllowed(ParentalControls.INSTALL_EXTENSIONS)) {
       // Disable extension installs
       Services.prefs.setIntPref("extensions.enabledScopes", 1);
       Services.prefs.setIntPref("extensions.autoDisableScopes", 1);
       Services.prefs.setBoolPref("xpinstall.enabled", false);
     }
 
-    // notify java that gecko has loaded
+    // Fix fallout from Bug 1091803.
+    if (Services.prefs.prefHasUserValue("intl.locale.os")) {
+      try {
+        let currentAcceptLang = Services.prefs.getCharPref("intl.accept_languages");
+
+        // The trailing comma is very important. This means we've set it to a
+        // real char pref, and it's something like "chrome://...,en-US,en".
+        if (currentAcceptLang.startsWith("chrome://global/locale/intl.properties,")) {
+          // If general.useragent.locale was set to a plain string, we ought to fix it, too.
+          try {
+            let currentUALocale = Services.prefs.getCharPref("general.useragent.locale");
+            if (currentUALocale.startsWith("chrome://")) {
+              // We're fine. This is what happens when you read a localized string as a char pref.
+            } else {
+              // Turn it into a localized string.
+              this.setLocalizedPref("general.useragent.locale", currentUALocale);
+            }
+          } catch (ee) {
+          }
+
+          // Now compute and save a valid Accept-Languages header from the clean strings.
+          let osLocale = this.getOSLocalePref();
+          let uaLocale = this.getUALocalePref();
+          this.computeAcceptLanguages(osLocale, uaLocale);
+        }
+      } catch (e) {
+        // Phew.
+      }
+    }
+
+    // Notify Java that Gecko has loaded.
     Messaging.sendRequest({ type: "Gecko:Ready" });
   },
 
   get _startupStatus() {
     delete this._startupStatus;
 
     let savedMilestone = null;
     try {
@@ -1516,16 +1546,43 @@ var BrowserApp = {
       if (formHelperMode == kFormHelperModeDynamic && this.isTablet)
         shouldZoom = false;
       // ZoomHelper.zoomToElement will handle not sending any message if this input is already mostly filling the screen
       ZoomHelper.zoomToElement(focused, -1, false,
           aAllowZoom && shouldZoom && !ViewportHandler.getViewportMetadata(aBrowser.contentWindow).isSpecified);
     }
   },
 
+  getUALocalePref: function () {
+    try {
+      return Services.prefs.getComplexValue("general.useragent.locale", Ci.nsIPrefLocalizedString).data;
+    } catch (e) {
+      try {
+        return Services.prefs.getCharPref("general.useragent.locale");
+      } catch (ee) {
+        return undefined;
+      }
+    }
+  },
+
+  getOSLocalePref: function () {
+    try {
+      return Services.prefs.getCharPref("intl.locale.os");
+    } catch (e) {
+      return undefined;
+    }
+  },
+
+  setLocalizedPref: function (pref, value) {
+    let pls = Cc["@mozilla.org/pref-localizedstring;1"]
+                .createInstance(Ci.nsIPrefLocalizedString);
+    pls.data = value;
+    Services.prefs.setComplexValue(pref, Ci.nsIPrefLocalizedString, pls);
+  },
+
   observe: function(aSubject, aTopic, aData) {
     let browser = this.selectedBrowser;
 
     switch (aTopic) {
 
       case "Session:Back":
         browser.goBack();
         break;
@@ -1757,47 +1814,42 @@ var BrowserApp = {
 
       case "Webapps:AutoUninstall":
         WebappManager.autoUninstall(JSON.parse(aData));
         break;
 
       case "Locale:OS":
         // We know the system locale. We use this for generating Accept-Language headers.
         console.log("Locale:OS: " + aData);
-        let currentOSLocale;
-        try {
-          currentOSLocale = Services.prefs.getCharPref("intl.locale.os");
-        } catch (e) {
-        }
+        let currentOSLocale = this.getOSLocalePref();
         if (currentOSLocale == aData) {
           break;
         }
 
         console.log("New OS locale.");
 
         // Ensure that this choice is immediately persisted, because
         // Gecko won't be told again if it forgets.
         Services.prefs.setCharPref("intl.locale.os", aData);
         Services.prefs.savePrefFile(null);
 
-        let appLocale;
-        try {
-          appLocale = Services.prefs.getCharPref("general.useragent.locale");
-        } catch (e) {
-        }
+        let appLocale = this.getUALocalePref();
 
         this.computeAcceptLanguages(aData, appLocale);
         break;
 
       case "Locale:Changed":
         if (aData) {
           // The value provided to Locale:Changed should be a BCP47 language tag
           // understood by Gecko -- for example, "es-ES" or "de".
           console.log("Locale:Changed: " + aData);
-          Services.prefs.setCharPref("general.useragent.locale", aData);
+
+          // We always write a localized pref, even though sometimes the value is a char pref.
+          // (E.g., on desktop single-locale builds.)
+          this.setLocalizedPref("general.useragent.locale", aData);
         } else {
           // Resetting.
           console.log("Switching to system locale.");
           Services.prefs.clearUserPref("general.useragent.locale");
         }
 
         Services.prefs.setBoolPref("intl.locale.matchOS", !aData);
 
@@ -1876,17 +1928,17 @@ var BrowserApp = {
     }
 
     if (appLocale && appLocale != osLocale) {
       chosen.unshift(appLocale);
     }
 
     let result = chosen.join(",");
     console.log("Setting intl.accept_languages to " + result);
-    Services.prefs.setCharPref("intl.accept_languages", result);
+    this.setLocalizedPref("intl.accept_languages", result);
   },
 
   get defaultBrowserWidth() {
     delete this.defaultBrowserWidth;
     let width = Services.prefs.getIntPref("browser.viewport.desktopWidth");
     return this.defaultBrowserWidth = width;
   },
 
--- a/mobile/android/components/FilePicker.js
+++ b/mobile/android/components/FilePicker.js
@@ -152,17 +152,18 @@ FilePicker.prototype = {
 
     return new File(f);
   },
 
   get domfiles() {
     let win = this._domWin;
     return this.getEnumerator([this.file], function(file) {
       if (win) {
-        return new win.File(file);
+        let utils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+        return utils.wrapDOMFile(file);
       }
 
       return new File(file);
     });
   },
 
   get addToRecentDocs() {
     return this._addToRecentDocs;
new file mode 100755
--- /dev/null
+++ b/mobile/android/config/js_wrapper.sh
@@ -0,0 +1,20 @@
+#! /bin/sh
+# 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/.
+
+# Wrapper for running SpiderMonkey js shell in automation with correct
+# LD_LIBRARY_PATH.
+
+# We don't have a reference to topsrcdir at this point, but we are invoked as
+# "$topsrcdir/mobile/android/config/js_wrapper.sh" so we can extract topsrcdir
+# from $0.
+topsrcdir=`cd \`dirname $0\`/../../..; pwd`
+
+JS_BINARY="$topsrcdir/jsshell/js"
+
+LD_LIBRARY_PATH="$topsrcdir/jsshell${LD_LIBRARY_PATH+:$LD_LIBRARY_PATH}"
+export LD_LIBRARY_PATH
+
+# Pass through all arguments and exit with status from js shell.
+exec "$JS_BINARY" "$@"
--- a/mobile/android/config/mozconfigs/common
+++ b/mobile/android/config/mozconfigs/common
@@ -48,8 +48,10 @@ HOST_CC="/tools/gcc-4.7.2-0moz1/bin/gcc"
 HOST_CXX="/tools/gcc-4.7.2-0moz1/bin/g++"
 
 # Avoid dependency on libstdc++ 4.7
 ac_add_options --enable-stdcxx-compat
 
 mk_add_options "export ANT_HOME=$topsrcdir/apache-ant"
 
 mk_add_options "export PATH=$topsrcdir/apache-ant/bin:$PATH"
+
+JS_BINARY="$topsrcdir/mobile/android/config/js_wrapper.sh"
--- a/mobile/android/config/tooltool-manifests/android-armv6/releng.manifest
+++ b/mobile/android/config/tooltool-manifests/android-armv6/releng.manifest
@@ -23,10 +23,17 @@
 "algorithm": "sha512",
 "filename": "sccache.tar.bz2"
 },
 {
 "size": 7920445,
 "digest": "e28b7a12fbbef02ad742958df8dd356ea2adb8ef79e95cd8eb8dbc953eb4cc11888969dac7d636187fd3ace9c63d9a6bc3d7795021c1d811a843e413fe5e52c9",
 "algorithm": "sha512",
 "filename": "apache-ant-bin.tar.bz2"
+},
+{
+"size": 4906080,
+"digest": "d735544e039da89382c53b2302b7408d4610247b4f8b5cdc5a4d5a8ec5470947b19e8ea7f7a37e78222e661347e394e0030d81f41534138b527b14e9c4e55634",
+"algorithm": "sha512",
+"filename": "jsshell.tar.xz",
+"unpack": "True"
 }
 ]
--- a/mobile/android/config/tooltool-manifests/android-x86/releng.manifest
+++ b/mobile/android/config/tooltool-manifests/android-x86/releng.manifest
@@ -23,10 +23,17 @@
 "algorithm": "sha512",
 "filename": "sccache.tar.bz2"
 },
 {
 "size": 7920445,
 "digest": "e28b7a12fbbef02ad742958df8dd356ea2adb8ef79e95cd8eb8dbc953eb4cc11888969dac7d636187fd3ace9c63d9a6bc3d7795021c1d811a843e413fe5e52c9",
 "algorithm": "sha512",
 "filename": "apache-ant-bin.tar.bz2"
+},
+{
+"size": 4906080,
+"digest": "d735544e039da89382c53b2302b7408d4610247b4f8b5cdc5a4d5a8ec5470947b19e8ea7f7a37e78222e661347e394e0030d81f41534138b527b14e9c4e55634",
+"algorithm": "sha512",
+"filename": "jsshell.tar.xz",
+"unpack": "True"
 }
 ]
--- a/mobile/android/config/tooltool-manifests/android/releng.manifest
+++ b/mobile/android/config/tooltool-manifests/android/releng.manifest
@@ -23,10 +23,17 @@
 "algorithm": "sha512",
 "filename": "sccache.tar.bz2"
 },
 {
 "size": 7920445,
 "digest": "e28b7a12fbbef02ad742958df8dd356ea2adb8ef79e95cd8eb8dbc953eb4cc11888969dac7d636187fd3ace9c63d9a6bc3d7795021c1d811a843e413fe5e52c9",
 "algorithm": "sha512",
 "filename": "apache-ant-bin.tar.bz2"
+},
+{
+"size": 4906080,
+"digest": "d735544e039da89382c53b2302b7408d4610247b4f8b5cdc5a4d5a8ec5470947b19e8ea7f7a37e78222e661347e394e0030d81f41534138b527b14e9c4e55634",
+"algorithm": "sha512",
+"filename": "jsshell.tar.xz",
+"unpack": "True"
 }
 ]
--- a/mobile/android/installer/Makefile.in
+++ b/mobile/android/installer/Makefile.in
@@ -30,16 +30,23 @@ endif
 ifdef MOZ_PKG_MANIFEST_P
 MOZ_PKG_MANIFEST = package-manifest
 endif
 
 MOZ_PACKAGER_MINIFY=1
 
 include $(topsrcdir)/toolkit/mozapps/installer/packager.mk
 
+# Note that JS_BINARY can be defined in packager.mk, so this test must come
+# after including that file. MOZ_PACKAGER_MINIFY_JS is used in packager.mk, but
+# since recipe evaluation is deferred, we can set it here after the inclusion.
+ifneq (,$(JS_BINARY))
+MOZ_PACKAGER_MINIFY_JS=1
+endif
+
 ifeq (bundle, $(MOZ_FS_LAYOUT))
 BINPATH = $(_BINPATH)
 DEFINES += -DAPPNAME=$(_APPNAME)
 else
 # Every other platform just winds up in dist/bin
 BINPATH = bin
 endif
 DEFINES += -DBINPATH=$(BINPATH)
--- a/mobile/locales/en-US/searchplugins/wikipedia.xml
+++ b/mobile/locales/en-US/searchplugins/wikipedia.xml
@@ -9,14 +9,15 @@
 <Url type="application/x-suggestions+json" method="GET" template="https://en.wikipedia.org/w/api.php">
   <Param name="action" value="opensearch"/>
   <Param name="search" value="{searchTerms}"/>
 </Url>
 <Url type="text/html" method="GET" template="https://en.wikipedia.org/wiki/Special:Search">
   <Param name="search" value="{searchTerms}"/>
   <Param name="sourceid" value="Mozilla-search"/>
 </Url>
+<!-- Search activity -->
 <Url type="text/html" method="GET" rel="mobile" template="https://en.m.wikipedia.org/wiki/Special:Search">
   <Param name="search" value="{searchTerms}"/>
   <Param name="sourceid" value="Mozilla-search"/>
 </Url>
 <SearchForm>https://en.wikipedia.org/wiki/Special:Search</SearchForm>
 </SearchPlugin>
--- a/mobile/locales/en-US/searchplugins/yahoo.xml
+++ b/mobile/locales/en-US/searchplugins/yahoo.xml
@@ -13,10 +13,16 @@
   <Param name="command" value="{searchTerms}" />
   <MozParam name="nresults" condition="pref" pref="maxSuggestions" />
 </Url>
 <Url type="text/html" method="GET" template="https://search.yahoo.com/search">
   <Param name="p" value="{searchTerms}" />
   <Param name="ei" value="UTF-8" />
   <Param name="fr" value="mozmob1" />
 </Url>
+<!-- Search activity -->
+<Url type="text/html" method="GET" rel="mobile" template="https://search.yahoo.com/search">
+  <Param name="p" value="{searchTerms}" />
+  <Param name="ei" value="UTF-8" />
+  <Param name="fr" value="mozmob2" />
+</Url>
 <SearchForm>https://search.yahoo.com/</SearchForm>
 </SearchPlugin>
--- a/parser/html/nsHtml5Parser.cpp
+++ b/parser/html/nsHtml5Parser.cpp
@@ -233,17 +233,18 @@ nsHtml5Parser::Parse(const nsAString& aS
       mTreeBuilder->StartPlainText();
       mTokenizer->StartPlainText();
     }
     /*
      * If you move the following line, be very careful not to cause 
      * WillBuildModel to be called before the document has had its 
      * script global object set.
      */
-    mExecutor->WillBuildModel(eDTDMode_unknown);
+    rv = mExecutor->WillBuildModel(eDTDMode_unknown);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Return early if the parser has processed EOF
   if (mExecutor->IsComplete()) {
     return NS_OK;
   }
 
   if (aLastCall && aSourceBuffer.IsEmpty() && !aKey) {
@@ -251,17 +252,17 @@ nsHtml5Parser::Parse(const nsAString& aS
     NS_ASSERTION(!GetStreamParser(),
                  "Had stream parser but got document.close().");
     if (mDocumentClosed) {
       // already closed
       return NS_OK;
     }
     mDocumentClosed = true;
     if (!mBlocked && !mInDocumentWrite) {
-      ParseUntilBlocked();
+      return ParseUntilBlocked();
     }
     return NS_OK;
   }
 
   // If we got this far, we are dealing with a document.write or
   // document.writeln call--not document.close().
 
   NS_ASSERTION(IsInsertionPointDefined(),
@@ -374,17 +375,18 @@ nsHtml5Parser::Parse(const nsAString& aS
       if (inRootContext) {
         mRootContextLineNumber = mTokenizer->getLineNumber();
       } else {
         mTokenizer->setLineNumber(lineNumberSave);
       }
 
       if (mTreeBuilder->HasScript()) {
         mTreeBuilder->Flush(); // Move ops to the executor
-        mExecutor->FlushDocumentWrite(); // run the ops
+        rv = mExecutor->FlushDocumentWrite(); // run the ops
+        NS_ENSURE_SUCCESS(rv, rv);
         // Flushing tree ops can cause all sorts of things.
         // Return early if the parser got terminated.
         if (mExecutor->IsComplete()) {
           return NS_OK;
         }
       }
       // Ignore suspension requests
     }
@@ -433,17 +435,18 @@ nsHtml5Parser::Parse(const nsAString& aS
     }
   }
 
   if (!mBlocked) { // buffer was tokenized to completion
     NS_ASSERTION(!stackBuffer.hasMore(),
       "Buffer wasn't tokenized to completion?");
     // Scripting semantics require a forced tree builder flush here
     mTreeBuilder->Flush(); // Move ops to the executor
-    mExecutor->FlushDocumentWrite(); // run the ops
+    rv = mExecutor->FlushDocumentWrite(); // run the ops
+    NS_ENSURE_SUCCESS(rv, rv);
   } else if (stackBuffer.hasMore()) {
     // The buffer wasn't tokenized to completion. Tokenize the untokenized
     // content in order to preload stuff. This content will be retokenized
     // later for normal parsing.
     if (!mDocWriteSpeculatorActive) {
       mDocWriteSpeculatorActive = true;
       if (!mDocWriteSpeculativeTreeBuilder) {
         // Lazily initialize if uninitialized
@@ -591,44 +594,48 @@ bool
 nsHtml5Parser::IsScriptCreated()
 {
   return !GetStreamParser();
 }
 
 /* End nsIParser  */
 
 // not from interface
-void
+nsresult
 nsHtml5Parser::ParseUntilBlocked()
 {
-  if (mBlocked || mExecutor->IsComplete() || NS_FAILED(mExecutor->IsBroken())) {
-    return;
+  nsresult rv = mExecutor->IsBroken();
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (mBlocked || mExecutor->IsComplete()) {
+    return NS_OK;
   }
   NS_ASSERTION(mExecutor->HasStarted(), "Bad life cycle.");
   NS_ASSERTION(!mInDocumentWrite,
     "ParseUntilBlocked entered while in doc.write!");
 
   mDocWriteSpeculatorActive = false;
 
   for (;;) {
     if (!mFirstBuffer->hasMore()) {
       if (mFirstBuffer == mLastBuffer) {
         if (mExecutor->IsComplete()) {
           // something like cache manisfests stopped the parse in mid-flight
-          return;
+          return NS_OK;
         }
         if (mDocumentClosed) {
           NS_ASSERTION(!GetStreamParser(),
                        "This should only happen with script-created parser.");
           mTokenizer->eof();
           mTreeBuilder->StreamEnded();
           mTreeBuilder->Flush();
           mExecutor->FlushDocumentWrite();
+          // The below call does memory cleanup, so call it even if the
+          // parser has been marked as broken.
           mTokenizer->end();
-          return;            
+          return NS_OK;
         }
         // never release the last buffer.
         NS_ASSERTION(!mLastBuffer->getStart() && !mLastBuffer->getEnd(),
                      "Sentinel buffer had its indeces changed.");
         if (GetStreamParser()) {
           if (mReturnToStreamParserPermitted &&
               !mExecutor->IsScriptExecuting()) {
             mTreeBuilder->Flush();
@@ -640,44 +647,45 @@ nsHtml5Parser::ParseUntilBlocked()
         } else {
           // Script-created parser
           mTreeBuilder->Flush();
           // No need to flush the executor, because the executor is already
           // in a flush
           NS_ASSERTION(mExecutor->IsInFlushLoop(),
               "How did we come here without being in the flush loop?");
         }
-        return; // no more data for now but expecting more
+        return NS_OK; // no more data for now but expecting more
       }
       mFirstBuffer = mFirstBuffer->next;
       continue;
     }
 
     if (mBlocked || mExecutor->IsComplete()) {
-      return;
+      return NS_OK;
     }
 
     // now we have a non-empty buffer
     mFirstBuffer->adjust(mLastWasCR);
     mLastWasCR = false;
     if (mFirstBuffer->hasMore()) {
       bool inRootContext = (!GetStreamParser() && !mFirstBuffer->key);
       if (inRootContext) {
         mTokenizer->setLineNumber(mRootContextLineNumber);
       }
       mLastWasCR = mTokenizer->tokenizeBuffer(mFirstBuffer);
       if (inRootContext) {
         mRootContextLineNumber = mTokenizer->getLineNumber();
       }
       if (mTreeBuilder->HasScript()) {
         mTreeBuilder->Flush();
-        mExecutor->FlushDocumentWrite();
+        nsresult rv = mExecutor->FlushDocumentWrite();
+        NS_ENSURE_SUCCESS(rv, rv);
       }
       if (mBlocked) {
-        return;
+        return NS_OK;
       }
     }
     continue;
   }
 }
 
 nsresult
 nsHtml5Parser::Initialize(nsIDocument* aDoc,
--- a/parser/html/nsHtml5Parser.h
+++ b/parser/html/nsHtml5Parser.h
@@ -256,17 +256,17 @@ class nsHtml5Parser MOZ_FINAL : public n
         return nullptr;
       }
       return mStreamListener->GetDelegate();
     }
 
     /**
      * Parse until pending data is exhausted or a script blocks the parser
      */
-    void ParseUntilBlocked();
+    nsresult ParseUntilBlocked();
 
   private:
 
     virtual ~nsHtml5Parser();
 
     // State variables
 
     /**
--- a/parser/html/nsHtml5StreamParser.cpp
+++ b/parser/html/nsHtml5StreamParser.cpp
@@ -788,17 +788,17 @@ nsHtml5StreamParser::WriteStreamBytes(co
                                       uint32_t aCount,
                                       uint32_t* aWriteCount)
 {
   NS_ASSERTION(IsParserThread(), "Wrong thread!");
   // mLastBuffer should always point to a buffer of the size
   // NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE.
   if (!mLastBuffer) {
     NS_WARNING("mLastBuffer should not be null!");
-    MarkAsBroken();
+    MarkAsBroken(NS_ERROR_NULL_POINTER);
     return NS_ERROR_NULL_POINTER;
   }
   if (mLastBuffer->getEnd() == NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE) {
     nsRefPtr<nsHtml5OwningUTF16Buffer> newBuf =
       nsHtml5OwningUTF16Buffer::FalliblyCreate(
         NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE);
     if (!newBuf) {
       return NS_ERROR_OUT_OF_MEMORY;
@@ -894,17 +894,18 @@ nsHtml5StreamParser::OnStartRequest(nsIR
     mTokenizer->StartPlainText();
   }
 
   /*
    * If you move the following line, be very careful not to cause 
    * WillBuildModel to be called before the document has had its 
    * script global object set.
    */
-  mExecutor->WillBuildModel(eDTDMode_unknown);
+  rv = mExecutor->WillBuildModel(eDTDMode_unknown);
+  NS_ENSURE_SUCCESS(rv, rv);
   
   nsRefPtr<nsHtml5OwningUTF16Buffer> newBuf =
     nsHtml5OwningUTF16Buffer::FalliblyCreate(
       NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE);
   if (!newBuf) {
     // marks this stream parser as terminated,
     // which prevents entry to code paths that
     // would use mFirstBuffer or mLastBuffer.
@@ -999,18 +1000,19 @@ nsHtml5StreamParser::DoStopRequest()
   if (IsTerminated()) {
     return;
   }
 
   mStreamState = STREAM_ENDED;
 
   if (!mUnicodeDecoder) {
     uint32_t writeCount;
-    if (NS_FAILED(FinalizeSniffing(nullptr, 0, &writeCount, 0))) {
-      MarkAsBroken();
+    nsresult rv;
+    if (NS_FAILED(rv = FinalizeSniffing(nullptr, 0, &writeCount, 0))) {
+      MarkAsBroken(rv);
       return;
     }
   } else if (mFeedChardet) {
     mChardet->Done();
   }
 
   if (IsTerminatedOrInterrupted()) {
     return;
@@ -1072,17 +1074,17 @@ nsHtml5StreamParser::DoDataAvailable(con
       mChardet->DoIt((const char*)aBuffer, aLength, &dontFeed);
       mFeedChardet = !dontFeed;
     }
     rv = WriteStreamBytes(aBuffer, aLength, &writeCount);
   } else {
     rv = SniffStreamBytes(aBuffer, aLength, &writeCount);
   }
   if (NS_FAILED(rv)) {
-    MarkAsBroken();
+    MarkAsBroken(rv);
     return;
   }
   NS_ASSERTION(writeCount == aLength, "Wrong number of stream bytes written/sniffed.");
 
   if (IsTerminatedOrInterrupted()) {
     return;
   }
 
@@ -1658,21 +1660,21 @@ nsHtml5StreamParser::TimerFlush()
       if (NS_FAILED(NS_DispatchToMainThread(mExecutorFlusher))) {
         NS_WARNING("failed to dispatch executor flush event");
       }
     }
   }
 }
 
 void
-nsHtml5StreamParser::MarkAsBroken()
+nsHtml5StreamParser::MarkAsBroken(nsresult aRv)
 {
   NS_ASSERTION(IsParserThread(), "Wrong thread!");
   mTokenizerMutex.AssertCurrentThreadOwns();
 
   Terminate();
-  mTreeBuilder->MarkAsBroken();
+  mTreeBuilder->MarkAsBroken(aRv);
   mozilla::DebugOnly<bool> hadOps = mTreeBuilder->Flush(false);
   NS_ASSERTION(hadOps, "Should have had the markAsBroken op!");
   if (NS_FAILED(NS_DispatchToMainThread(mExecutorFlusher))) {
     NS_WARNING("failed to dispatch executor flush event");
   }
 }
--- a/parser/html/nsHtml5StreamParser.h
+++ b/parser/html/nsHtml5StreamParser.h
@@ -212,17 +212,17 @@ class nsHtml5StreamParser : public nsICh
 #ifdef DEBUG
     bool IsParserThread() {
       bool ret;
       mThread->IsOnCurrentThread(&ret);
       return ret;
     }
 #endif
 
-    void MarkAsBroken();
+    void MarkAsBroken(nsresult aRv);
 
     /**
      * Marks the stream parser as interrupted. If you ever add calls to this
      * method, be sure to review Uninterrupt usage very, very carefully to
      * avoid having a previous in-flight runnable cancel your Interrupt()
      * call on the other thread too soon.
      */
     void Interrupt()
--- a/parser/html/nsHtml5TreeBuilderCppSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h
@@ -924,24 +924,24 @@ void
 nsHtml5TreeBuilder::DropHandles()
 {
   MOZ_ASSERT(!mBuilder, "Must not drop handles with builder.");
   mOldHandles.Clear();
   mHandlesUsed = 0;
 }
 
 void
-nsHtml5TreeBuilder::MarkAsBroken()
+nsHtml5TreeBuilder::MarkAsBroken(nsresult aRv)
 {
   if (MOZ_UNLIKELY(mBuilder)) {
     MOZ_ASSERT_UNREACHABLE("Must not call this with builder.");
     return;
   }
   mOpQueue.Clear(); // Previous ops don't matter anymore
-  mOpQueue.AppendElement()->Init(eTreeOpMarkAsBroken);
+  mOpQueue.AppendElement()->Init(aRv);
 }
 
 void
 nsHtml5TreeBuilder::StartPlainTextViewSource(const nsAutoString& aTitle)
 {
   MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
   startTag(nsHtml5ElementName::ELT_TITLE,
            nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES,
--- a/parser/html/nsHtml5TreeBuilderHSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderHSupplement.h
@@ -218,9 +218,9 @@
     void errNoCheckUnclosedElementsOnStack();
 
     void errEndTagDidNotMatchCurrentOpenElement(nsIAtom* aName, nsIAtom* aOther);
 
     void errEndTagViolatesNestingRules(nsIAtom* aName);
 
     void errEndWithUnclosedElements(nsIAtom* aName);
 
-    void MarkAsBroken();
+    void MarkAsBroken(nsresult aRv);
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
@@ -407,17 +407,21 @@ nsHtml5TreeOpExecutor::RunFlushLoop()
         return;
       }
       // Not sure if this grip is still needed, but previously, the code
       // gripped before calling ParseUntilBlocked();
       nsRefPtr<nsHtml5StreamParser> streamKungFuDeathGrip = 
         GetParser()->GetStreamParser();
       // Now parse content left in the document.write() buffer queue if any.
       // This may generate tree ops on its own or dequeue a speculation.
-      GetParser()->ParseUntilBlocked();
+      nsresult rv = GetParser()->ParseUntilBlocked();
+      if (NS_FAILED(rv)) {
+        MarkAsBroken(rv);
+        return;
+      }
     }
 
     if (mOpQueue.IsEmpty()) {
       // Avoid bothering the rest of the engine with a doc update if there's 
       // nothing to do.
       return;
     }
 
@@ -490,31 +494,34 @@ nsHtml5TreeOpExecutor::RunFlushLoop()
         #endif
         nsHtml5TreeOpExecutor::ContinueInterruptedParsingAsync();
         return;      
       }
     }
   }
 }
 
-void
+nsresult
 nsHtml5TreeOpExecutor::FlushDocumentWrite()
 {
+  nsresult rv = IsBroken();
+  NS_ENSURE_SUCCESS(rv, rv);
+
   FlushSpeculativeLoads(); // Make sure speculative loads never start after the
                 // corresponding normal loads for the same URLs.
 
   if (MOZ_UNLIKELY(!mParser)) {
     // The parse has ended.
     mOpQueue.Clear(); // clear in order to be able to assert in destructor
-    return;
+    return rv;
   }
   
   if (mFlushState != eNotFlushing) {
     // XXX Can this happen? In case it can, let's avoid crashing.
-    return;
+    return rv;
   }
 
   mFlushState = eInFlush;
 
   // avoid crashing near EOF
   nsRefPtr<nsHtml5TreeOpExecutor> kungFuDeathGrip(this);
   nsRefPtr<nsParserBase> parserKungFuDeathGrip(mParser);
 
@@ -537,38 +544,39 @@ nsHtml5TreeOpExecutor::FlushDocumentWrit
        iter < end;
        ++iter) {
     if (MOZ_UNLIKELY(!mParser)) {
       // The previous tree op caused a call to nsIParser::Terminate().
       break;
     }
     NS_ASSERTION(mFlushState == eInDocUpdate, 
       "Tried to perform tree op outside update batch.");
-    nsresult rv = iter->Perform(this, &scriptElement);
+    rv = iter->Perform(this, &scriptElement);
     if (NS_FAILED(rv)) {
       MarkAsBroken(rv);
       break;
     }
   }
 
   mOpQueue.Clear();
   
   EndDocUpdate();
 
   mFlushState = eNotFlushing;
 
   if (MOZ_UNLIKELY(!mParser)) {
     // Ending the doc update caused a call to nsIParser::Terminate().
-    return;
+    return rv;
   }
 
   if (scriptElement) {
     // must be tail call when mFlushState is eNotFlushing
     RunScript(scriptElement);
   }
+  return rv;
 }
 
 // copied from HTML content sink
 bool
 nsHtml5TreeOpExecutor::IsScriptEnabled()
 {
   if (!mDocument || !mDocShell)
     return true;
--- a/parser/html/nsHtml5TreeOpExecutor.h
+++ b/parser/html/nsHtml5TreeOpExecutor.h
@@ -173,17 +173,17 @@ class nsHtml5TreeOpExecutor MOZ_FINAL : 
     virtual nsresult MarkAsBroken(nsresult aReason);
 
     void StartLayout();
     
     void FlushSpeculativeLoads();
                   
     void RunFlushLoop();
 
-    void FlushDocumentWrite();
+    nsresult FlushDocumentWrite();
 
     void MaybeSuspend();
 
     void Start();
 
     void NeedsCharsetSwitchTo(const char* aEncoding,
                               int32_t aSource,
                               uint32_t aLineNumber);
--- a/parser/html/nsHtml5TreeOperation.cpp
+++ b/parser/html/nsHtml5TreeOperation.cpp
@@ -192,16 +192,20 @@ nsHtml5TreeOperation::AppendToDocument(n
   MOZ_ASSERT(aBuilder);
   MOZ_ASSERT(aBuilder->GetDocument() == aNode->OwnerDoc());
   MOZ_ASSERT(aBuilder->IsInDocUpdate());
   nsresult rv = NS_OK;
 
   nsIDocument* doc = aBuilder->GetDocument();
   uint32_t childCount = doc->GetChildCount();
   rv = doc->AppendChildTo(aNode, false);
+  if (rv == NS_ERROR_DOM_HIERARCHY_REQUEST_ERR) {
+    aNode->SetParserHasNotified();
+    return NS_OK;
+  }
   NS_ENSURE_SUCCESS(rv, rv);
   aNode->SetParserHasNotified();
   nsNodeUtils::ContentInserted(doc, aNode, childCount);
 
   NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
                "Someone forgot to block scripts");
   if (aNode->IsElement()) {
     nsContentUtils::AddScriptRunner(
@@ -721,18 +725,17 @@ nsHtml5TreeOperation::Perform(nsHtml5Tre
       return AppendDoctypeToDocument(name, publicId, systemId, aBuilder);
     }
     case eTreeOpGetDocumentFragmentForTemplate: {
       nsIContent* node = *(mOne.node);
       *mTwo.node = GetDocumentFragmentForTemplate(node);
       return NS_OK;
     }
     case eTreeOpMarkAsBroken: {
-      aBuilder->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
-      return NS_OK;
+      return mOne.result;
     }
     case eTreeOpRunScript: {
       nsIContent* node = *(mOne.node);
       nsAHtml5TreeBuilderState* snapshot = mTwo.state;
       if (snapshot) {
         aBuilder->InitializeDocWriteParserState(snapshot, mFour.integer);
       }
       *aScriptElement = node;
--- a/parser/html/nsHtml5TreeOperation.h
+++ b/parser/html/nsHtml5TreeOperation.h
@@ -427,16 +427,25 @@ class nsHtml5TreeOperation {
       NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
         "Op code must be uninitialized when initializing.");
       NS_PRECONDITION(aNode, "Initialized tree op with null node.");
       mOpCode = aOpCode;
       mOne.node = static_cast<nsIContent**>(aNode);
       mFour.integer = aInt;
     }
 
+    inline void Init(nsresult aRv)
+    {
+      NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
+        "Op code must be uninitialized when initializing.");
+      NS_PRECONDITION(NS_FAILED(aRv), "Initialized tree op with non-failure.");
+      mOpCode = eTreeOpMarkAsBroken;
+      mOne.result = aRv;
+    }
+
     inline void InitAddClass(nsIContentHandle* aNode, const char16_t* aClass)
     {
       NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
         "Op code must be uninitialized when initializing.");
       NS_PRECONDITION(aNode, "Initialized tree op with null node.");
       NS_PRECONDITION(aClass, "Initialized tree op with null string.");
       // aClass must be a literal string that does not need freeing
       mOpCode = eTreeOpAddClass;
@@ -479,17 +488,18 @@ class nsHtml5TreeOperation {
     // Make the queue take items the size of pointer and make the op code
     // decide how many operands it dequeues after it.
     eHtml5TreeOperation mOpCode;
     union {
       nsIContent**                    node;
       nsIAtom*                        atom;
       nsHtml5HtmlAttributes*          attributes;
       nsHtml5DocumentMode             mode;
-      char16_t*                      unicharPtr;
+      char16_t*                       unicharPtr;
       char*                           charPtr;
       nsHtml5TreeOperationStringPair* stringPair;
       nsAHtml5TreeBuilderState*       state;
       int32_t                         integer;
+      nsresult                        result;
     }                   mOne, mTwo, mThree, mFour;
 };
 
 #endif // nsHtml5TreeOperation_h
--- a/testing/mochitest/mach_commands.py
+++ b/testing/mochitest/mach_commands.py
@@ -87,17 +87,17 @@ class MochitestRunner(MozbuildObject):
     to hook up result parsing, etc.
     """
 
     def get_webapp_runtime_path(self):
         import mozinfo
         appname = 'webapprt-stub' + mozinfo.info.get('bin_suffix', '')
         if sys.platform.startswith('darwin'):
             appname = os.path.join(self.distdir, self.substs['MOZ_MACBUNDLE_NAME'],
-            'Contents', 'MacOS', appname)
+            'Contents', 'Resources', appname)
         else:
             appname = os.path.join(self.distdir, 'bin', appname)
         return appname
 
     def __init__(self, *args, **kwargs):
         MozbuildObject.__init__(self, *args, **kwargs)
 
         # TODO Bug 794506 remove once mach integrates with virtualenv.
--- a/testing/testsuite-targets.mk
+++ b/testing/testsuite-targets.mk
@@ -164,17 +164,17 @@ ifeq (powerpc,$(TARGET_CPU))
 	$(RUN_MOCHITEST) --setpref=dom.ipc.plugins.enabled.ppc.test.plugin=false $(IPCPLUGINS_PATH_ARG)
 endif
 else
 	$(RUN_MOCHITEST) --setpref=dom.ipc.plugins.enabled=false --test-path=dom/plugins/test
 endif
 	$(CHECK_TEST_ERROR)
 
 ifeq ($(OS_ARCH),Darwin)
-webapprt_stub_path = $(TARGET_DIST)/$(MOZ_MACBUNDLE_NAME)/Contents/MacOS/webapprt-stub$(BIN_SUFFIX)
+webapprt_stub_path = $(TARGET_DIST)/$(MOZ_MACBUNDLE_NAME)/Contents/Resources/webapprt-stub$(BIN_SUFFIX)
 endif
 ifeq ($(OS_ARCH),WINNT)
 webapprt_stub_path = $(TARGET_DIST)/bin/webapprt-stub$(BIN_SUFFIX)
 endif
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 webapprt_stub_path = $(TARGET_DIST)/bin/webapprt-stub$(BIN_SUFFIX)
 endif
 
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -671,21 +671,20 @@ KeyedHistogram::Clear()
   mHistogramMap.Clear();
 }
 
 /* static */
 PLDHashOperator
 KeyedHistogram::ReflectKeys(KeyedHistogramEntry* entry, void* arg)
 {
   ReflectKeysArgs* args = static_cast<ReflectKeysArgs*>(arg);
-  const nsACString& key = entry->GetKey();
 
   JS::RootedValue jsKey(args->jsContext);
-  const nsCString& flat = nsPromiseFlatCString(key);
-  jsKey.setString(JS_NewStringCopyN(args->jsContext, flat.get(), flat.Length()));
+  const NS_ConvertUTF8toUTF16 key(entry->GetKey());
+  jsKey.setString(JS_NewUCStringCopyN(args->jsContext, key.Data(), key.Length()));
   args->vector->append(jsKey);
 
   return PL_DHASH_NEXT;
 }
 
 nsresult
 KeyedHistogram::GetJSKeys(JSContext* cx, JS::CallArgs& args)
 {
@@ -718,20 +717,19 @@ KeyedHistogram::ReflectKeyedHistogram(Ke
   if (!histogramSnapshot) {
     return false;
   }
 
   if (ReflectHistogramSnapshot(cx, histogramSnapshot, entry->mData) != REFLECT_OK) {
     return false;
   }
 
-  const nsACString& key = entry->GetKey();
-  const nsCString& flat = nsPromiseFlatCString(key);
-
-  if (!JS_DefineProperty(cx, obj, flat.get(), histogramSnapshot, JSPROP_ENUMERATE)) {
+  const NS_ConvertUTF8toUTF16 key(entry->GetKey());
+  if (!JS_DefineUCProperty(cx, obj, key.Data(), key.Length(),
+                           histogramSnapshot, JSPROP_ENUMERATE)) {
     return false;
   }
 
   return true;
 }
 
 nsresult
 KeyedHistogram::GetJSSnapshot(JSContext* cx, JS::Handle<JSObject*> obj)
--- a/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js
+++ b/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js
@@ -385,17 +385,18 @@ function numberRange(lower, upper)
     a.push(i);
   }
   return a;
 }
 
 function test_keyed_boolean_histogram()
 {
   const KEYED_ID = "test::keyed::boolean";
-  const KEYS = ["key"+(i+1) for (i of numberRange(0, 3))];
+  KEYS = ["key"+(i+1) for (i of numberRange(0, 2))];
+  KEYS.push("漢語");
   let histogramBase = {
     "min": 1,
     "max": 2,
     "histogram_type": 2,
     "sum": 1,
     "sum_squares_lo": 1,
     "sum_squares_hi": 0,
     "ranges": [0, 1, 2],
--- a/toolkit/webapps/MacNativeApp.js
+++ b/toolkit/webapps/MacNativeApp.js
@@ -217,17 +217,18 @@ NativeApp.prototype = {
                           { unixMode: PERMS_DIRECTORY, ignoreExisting: true });
 
     yield OS.File.makeDir(OS.Path.join(aDir, this.resourcesDir),
                           { unixMode: PERMS_DIRECTORY, ignoreExisting: true });
   }),
 
   _copyPrebuiltFiles: function(aDir) {
     let destDir = getFile(aDir, this.macOSDir);
-    let stub = getFile(this.runtimeFolder, "webapprt-stub");
+    let stub = getFile(OS.Path.join(OS.Path.dirname(this.runtimeFolder),
+                                    "Resources"), "webapprt-stub");
     stub.copyTo(destDir, "webapprt");
   },
 
   _createConfigFiles: function(aDir) {
     // ${ProfileDir}/webapp.json
     yield writeToFile(OS.Path.join(aDir, this.configJson),
                       JSON.stringify(this.webappJson));
 
--- a/toolkit/webapps/tests/test_webapp_runtime_executable_update.xul
+++ b/toolkit/webapps/tests/test_webapp_runtime_executable_update.xul
@@ -89,17 +89,17 @@ let runTest = Task.async(function*() {
   yield nativeApp.install(app, manifest);
   while (!WebappOSUtils.isLaunchable(app)) {
     yield wait(1000);
   }
   ok(true, "App launchable");
 
   let fakeInstallDir;
   if (MAC) {
-    fakeInstallDir = getFile(testAppInfo.installPath, "Contents", "MacOS");
+    fakeInstallDir = getFile(testAppInfo.installPath, "Contents", "Resources");
   } else {
     fakeInstallDir = getFile(OS.Constants.Path.profileDir, "fakeInstallDir");
     fakeInstallDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
   }
 
   let fakeAppIniFile = fakeInstallDir.clone();
   fakeAppIniFile.append("application.ini");
 
--- a/webapprt/mac/webapprt.mm
+++ b/webapprt/mac/webapprt.mm
@@ -161,17 +161,17 @@ main(int argc, char **argv)
       NSLog(@"### This Application has an old webrt. Updating it.");
       NSLog(@"### My webapprt path: %@", myWebRTPath);
 
       NSFileManager* fileClerk = [[NSFileManager alloc] init];
       NSError *errorDesc = nil;
 
       //we know the firefox path, so copy the new webapprt here
       NSString *newWebRTPath =
-        [NSString stringWithFormat: @"%@%s%s", firefoxPath, APP_MACOS_PATH,
+        [NSString stringWithFormat: @"%@%s%s", firefoxPath, APP_RESOURCES_PATH,
                                                WEBAPPRT_EXECUTABLE];
       NSLog(@"### Firefox webapprt path: %@", newWebRTPath);
       if (![fileClerk fileExistsAtPath:newWebRTPath]) {
         NSString* msg = [NSString stringWithFormat: @"This version of Firefox (%@) cannot run web applications, because it is not recent enough or damaged", firefoxVersion];
         @throw MakeException(@"Missing Web Runtime Files", msg);
       }
 
       [fileClerk removeItemAtPath: myWebRTPath error: &errorDesc];
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -36,16 +36,17 @@
 #include "nsIDOMClientRect.h"
 #include "StrongPointer.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "nsPrintfCString.h"
 #include "NativeJSContainer.h"
 #include "nsContentUtils.h"
 #include "nsIScriptError.h"
 #include "nsIHttpChannel.h"
+#include "GeneratedSDKWrappers.h"
 
 using namespace mozilla;
 using namespace mozilla::widget::android;
 using namespace mozilla::gfx;
 
 AndroidBridge* AndroidBridge::sBridge;
 pthread_t AndroidBridge::sJavaUiThread = -1;
 static unsigned sJavaEnvThreadIndex = 0;
@@ -215,16 +216,21 @@ AndroidBridge::Init(JNIEnv *jEnv)
     jByteBufferRead = jEnv->GetMethodID(jReadableByteChannel, "read", "(Ljava/nio/ByteBuffer;)I");
 
     jInputStream = getClassGlobalRef("java/io/InputStream");
     jClose = jEnv->GetMethodID(jInputStream, "close", "()V");
     jAvailable = jEnv->GetMethodID(jInputStream, "available", "()I");
 
     InitAndroidJavaWrappers(jEnv);
 
+    if (mAPIVersion >= 16 /* Jelly Bean */) {
+        // We only use this for MediaCodec right now
+        InitSDKStubs(jEnv);
+    }
+
     // jEnv should NOT be cached here by anything -- the jEnv here
     // is not valid for the real gecko main thread, which is set
     // at SetMainThread time.
 
     return true;
 }
 
 bool
--- a/widget/android/AndroidJNI.cpp
+++ b/widget/android/AndroidJNI.cpp
@@ -36,17 +36,17 @@
 #include "mozilla/dom/SmsMessage.h"
 #include "mozilla/dom/mobilemessage/Constants.h"
 #include "mozilla/dom/mobilemessage/Types.h"
 #include "mozilla/dom/mobilemessage/PSms.h"
 #include "mozilla/dom/mobilemessage/SmsParent.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "nsIMobileMessageDatabaseService.h"
 #include "nsPluginInstanceOwner.h"
-#include "nsSurfaceTexture.h"
+#include "AndroidSurfaceTexture.h"
 #include "GeckoProfiler.h"
 #include "nsMemoryPressure.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::dom::mobilemessage;
 using namespace mozilla::layers;
 using namespace mozilla::widget::android;
@@ -858,19 +858,19 @@ Java_org_mozilla_gecko_GeckoAppShell_get
         }
     }
     return jenv->CallObjectMethod(queue, jNextMethod);
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_onSurfaceTextureFrameAvailable(JNIEnv* jenv, jclass, jobject surfaceTexture, jint id)
 {
-  nsSurfaceTexture* st = nsSurfaceTexture::Find(id);
+  mozilla::gl::AndroidSurfaceTexture* st = mozilla::gl::AndroidSurfaceTexture::Find(id);
   if (!st) {
-    __android_log_print(ANDROID_LOG_ERROR, "GeckoJNI", "Failed to find nsSurfaceTexture with id %d", id);
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoJNI", "Failed to find AndroidSurfaceTexture with id %d", id);
     return;
   }
 
   st->NotifyFrameAvailable();
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_dispatchMemoryPressure(JNIEnv* jenv, jclass)
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -6,16 +6,17 @@
 #include "AndroidJavaWrappers.h"
 #include "AndroidBridge.h"
 #include "AndroidBridgeUtilities.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsIWidget.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/TouchEvents.h"
+#include "GeneratedSDKWrappers.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::widget::android;
 
 jclass AndroidGeckoEvent::jGeckoEventClass = 0;
 jfieldID AndroidGeckoEvent::jActionField = 0;
 jfieldID AndroidGeckoEvent::jTypeField = 0;
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -1111,17 +1111,17 @@ bool GeckoAppShell::PumpMessageLoop() {
 
     bool temp = env->CallStaticBooleanMethod(mGeckoAppShellClass, jPumpMessageLoop);
     AndroidBridge::HandleUncaughtException(env);
     env->PopLocalFrame(nullptr);
     return temp;
 }
 
 void GeckoAppShell::RegisterSurfaceTextureFrameListener(jobject a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    JNIEnv *env = GetJNIForThread();
     if (env->PushLocalFrame(1) != 0) {
         AndroidBridge::HandleUncaughtException(env);
         MOZ_CRASH("Exception should have caused crash.");
     }
 
     env->CallStaticVoidMethod(mGeckoAppShellClass, jRegisterSurfaceTextureFrameListener, a0, a1);
     AndroidBridge::HandleUncaughtException(env);
     env->PopLocalFrame(nullptr);
new file mode 100644
--- /dev/null
+++ b/widget/android/GeneratedSDKWrappers.cpp
@@ -0,0 +1,1877 @@
+// GENERATED CODE
+// Generated by the Java program at /build/jarClassProcessors at compile time from
+// a given set of jars and a set of requested methods. To update, change the annotations
+// on the corresponding Java methods and rerun the build. Manually updating this file
+// will cause your build to fail.
+
+#include "GeneratedSDKWrappers.h"
+#include "AndroidBridgeUtilities.h"
+#include "nsXPCOMStrings.h"
+#include "AndroidBridge.h"
+#include "nsDebug.h"
+
+namespace mozilla {
+namespace widget {
+namespace android {
+jclass MediaCodec::mMediaCodecClass = 0;
+jmethodID MediaCodec::jConfigure = 0;
+jmethodID MediaCodec::jCreateByCodecName = 0;
+jmethodID MediaCodec::jCreateDecoderByType = 0;
+jmethodID MediaCodec::jCreateEncoderByType = 0;
+jmethodID MediaCodec::jDequeueInputBuffer = 0;
+jmethodID MediaCodec::jDequeueOutputBuffer = 0;
+jmethodID MediaCodec::jFinalize = 0;
+jmethodID MediaCodec::jFlush = 0;
+jmethodID MediaCodec::jGetInputBuffers = 0;
+jmethodID MediaCodec::jGetOutputBuffers = 0;
+jmethodID MediaCodec::jGetOutputFormat = 0;
+jmethodID MediaCodec::jQueueInputBuffer = 0;
+jmethodID MediaCodec::jQueueSecureInputBuffer = 0;
+jmethodID MediaCodec::jRelease = 0;
+jmethodID MediaCodec::jReleaseOutputBuffer = 0;
+jmethodID MediaCodec::jSetVideoScalingMode = 0;
+jmethodID MediaCodec::jStart = 0;
+jmethodID MediaCodec::jStop = 0;
+jfieldID MediaCodec::jBUFFER_FLAG_CODEC_CONFIG = 0;
+jfieldID MediaCodec::jBUFFER_FLAG_END_OF_STREAM = 0;
+jfieldID MediaCodec::jBUFFER_FLAG_SYNC_FRAME = 0;
+jfieldID MediaCodec::jCONFIGURE_FLAG_ENCODE = 0;
+jfieldID MediaCodec::jCRYPTO_MODE_AES_CTR = 0;
+jfieldID MediaCodec::jCRYPTO_MODE_UNENCRYPTED = 0;
+jfieldID MediaCodec::jINFO_OUTPUT_BUFFERS_CHANGED = 0;
+jfieldID MediaCodec::jINFO_OUTPUT_FORMAT_CHANGED = 0;
+jfieldID MediaCodec::jINFO_TRY_AGAIN_LATER = 0;
+jfieldID MediaCodec::jVIDEO_SCALING_MODE_SCALE_TO_FIT = 0;
+jfieldID MediaCodec::jVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 0;
+void MediaCodec::InitStubs(JNIEnv *jEnv) {
+    initInit();
+
+    mMediaCodecClass = getClassGlobalRef("android/media/MediaCodec");
+    jConfigure = getMethod("configure", "(Landroid/media/MediaFormat;Landroid/view/Surface;Landroid/media/MediaCrypto;I)V");
+    jCreateByCodecName = getStaticMethod("createByCodecName", "(Ljava/lang/String;)Landroid/media/MediaCodec;");
+    jCreateDecoderByType = getStaticMethod("createDecoderByType", "(Ljava/lang/String;)Landroid/media/MediaCodec;");
+    jCreateEncoderByType = getStaticMethod("createEncoderByType", "(Ljava/lang/String;)Landroid/media/MediaCodec;");
+    jDequeueInputBuffer = getMethod("dequeueInputBuffer", "(J)I");
+    jDequeueOutputBuffer = getMethod("dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I");
+    jFinalize = getMethod("finalize", "()V");
+    jFlush = getMethod("flush", "()V");
+    jGetInputBuffers = getMethod("getInputBuffers", "()[Ljava/nio/ByteBuffer;");
+    jGetOutputBuffers = getMethod("getOutputBuffers", "()[Ljava/nio/ByteBuffer;");
+    jGetOutputFormat = getMethod("getOutputFormat", "()Landroid/media/MediaFormat;");
+    jQueueInputBuffer = getMethod("queueInputBuffer", "(IIIJI)V");
+    jQueueSecureInputBuffer = getMethod("queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V");
+    jRelease = getMethod("release", "()V");
+    jReleaseOutputBuffer = getMethod("releaseOutputBuffer", "(IZ)V");
+    jSetVideoScalingMode = getMethod("setVideoScalingMode", "(I)V");
+    jStart = getMethod("start", "()V");
+    jStop = getMethod("stop", "()V");
+    jBUFFER_FLAG_CODEC_CONFIG = getStaticField("BUFFER_FLAG_CODEC_CONFIG", "I");
+    jBUFFER_FLAG_END_OF_STREAM = getStaticField("BUFFER_FLAG_END_OF_STREAM", "I");
+    jBUFFER_FLAG_SYNC_FRAME = getStaticField("BUFFER_FLAG_SYNC_FRAME", "I");
+    jCONFIGURE_FLAG_ENCODE = getStaticField("CONFIGURE_FLAG_ENCODE", "I");
+    jCRYPTO_MODE_AES_CTR = getStaticField("CRYPTO_MODE_AES_CTR", "I");
+    jCRYPTO_MODE_UNENCRYPTED = getStaticField("CRYPTO_MODE_UNENCRYPTED", "I");
+    jINFO_OUTPUT_BUFFERS_CHANGED = getStaticField("INFO_OUTPUT_BUFFERS_CHANGED", "I");
+    jINFO_OUTPUT_FORMAT_CHANGED = getStaticField("INFO_OUTPUT_FORMAT_CHANGED", "I");
+    jINFO_TRY_AGAIN_LATER = getStaticField("INFO_TRY_AGAIN_LATER", "I");
+    jVIDEO_SCALING_MODE_SCALE_TO_FIT = getStaticField("VIDEO_SCALING_MODE_SCALE_TO_FIT", "I");
+    jVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = getStaticField("VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING", "I");
+}
+
+MediaCodec* MediaCodec::Wrap(jobject obj) {
+    JNIEnv *env = GetJNIForThread();
+    MediaCodec* ret = new MediaCodec(obj, env);
+    env->DeleteLocalRef(obj);
+    return ret;
+}
+
+bool MediaCodec::Configure(jobject a0, jobject a1, jobject a2, int32_t a3) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(3) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jvalue args[4];
+    args[0].l = a0;
+    args[1].l = a1;
+    args[2].l = a2;
+    args[3].i = a3;
+
+    env->CallVoidMethodA(wrapped_obj, jConfigure, args);
+    if (env->ExceptionCheck()) {
+        env->ExceptionClear();
+        env->PopLocalFrame(nullptr);
+        return false;
+    }
+    env->PopLocalFrame(nullptr);
+    return true;
+}
+
+jobject MediaCodec::CreateByCodecName(const nsAString& a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(2) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+
+    jobject temp = env->CallStaticObjectMethod(mMediaCodecClass, jCreateByCodecName, j0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject MediaCodec::CreateDecoderByType(const nsAString& a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(2) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+
+    jobject temp = env->CallStaticObjectMethod(mMediaCodecClass, jCreateDecoderByType, j0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject MediaCodec::CreateEncoderByType(const nsAString& a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(2) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+
+    jobject temp = env->CallStaticObjectMethod(mMediaCodecClass, jCreateEncoderByType, j0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+int32_t MediaCodec::DequeueInputBuffer(int64_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    int32_t temp = env->CallIntMethod(wrapped_obj, jDequeueInputBuffer, a0);
+    if (env->ExceptionCheck()) {
+        env->ExceptionClear();
+        env->PopLocalFrame(nullptr);
+        return MEDIACODEC_EXCEPTION_INDEX;
+    }
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+int32_t MediaCodec::DequeueOutputBuffer(jobject a0, int64_t a1) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    int32_t temp = env->CallIntMethod(wrapped_obj, jDequeueOutputBuffer, a0, a1);
+    if (env->ExceptionCheck()) {
+        env->ExceptionClear();
+        env->PopLocalFrame(nullptr);
+        return MEDIACODEC_EXCEPTION_INDEX;
+    }
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+void MediaCodec::Finalize() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    env->CallVoidMethod(wrapped_obj, jFinalize);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+}
+
+void MediaCodec::Flush() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    env->CallVoidMethod(wrapped_obj, jFlush);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+}
+
+jobjectArray MediaCodec::GetInputBuffers() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jGetInputBuffers);
+    AndroidBridge::HandleUncaughtException(env);
+    jobjectArray ret = static_cast<jobjectArray>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobjectArray MediaCodec::GetOutputBuffers() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jGetOutputBuffers);
+    AndroidBridge::HandleUncaughtException(env);
+    jobjectArray ret = static_cast<jobjectArray>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject MediaCodec::GetOutputFormat() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jGetOutputFormat);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+void MediaCodec::QueueInputBuffer(int32_t a0, int32_t a1, int32_t a2, int64_t a3, int32_t a4) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(5) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jvalue args[5];
+    args[0].i = a0;
+    args[1].i = a1;
+    args[2].i = a2;
+    args[3].j = a3;
+    args[4].i = a4;
+
+    env->CallVoidMethodA(wrapped_obj, jQueueInputBuffer, args);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+}
+
+void MediaCodec::QueueSecureInputBuffer(int32_t a0, int32_t a1, jobject a2, int64_t a3, int32_t a4) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jvalue args[5];
+    args[0].i = a0;
+    args[1].i = a1;
+    args[2].l = a2;
+    args[3].j = a3;
+    args[4].i = a4;
+
+    env->CallVoidMethodA(wrapped_obj, jQueueSecureInputBuffer, args);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+}
+
+void MediaCodec::Release() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    env->CallVoidMethod(wrapped_obj, jRelease);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+}
+
+void MediaCodec::ReleaseOutputBuffer(int32_t a0, bool a1) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    env->CallVoidMethod(wrapped_obj, jReleaseOutputBuffer, a0, a1);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+}
+
+void MediaCodec::SetVideoScalingMode(int32_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    env->CallVoidMethod(wrapped_obj, jSetVideoScalingMode, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+}
+
+bool MediaCodec::Start() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    env->CallVoidMethod(wrapped_obj, jStart);
+    if (env->ExceptionCheck()) {
+        env->ExceptionClear();
+        env->PopLocalFrame(nullptr);
+        return false;
+    }
+    env->PopLocalFrame(nullptr);
+    return true;
+}
+
+void MediaCodec::Stop() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    env->CallVoidMethod(wrapped_obj, jStop);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+}
+
+int32_t MediaCodec::getBUFFER_FLAG_CODEC_CONFIG() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetStaticIntField(mMediaCodecClass, jBUFFER_FLAG_CODEC_CONFIG);
+}
+
+int32_t MediaCodec::getBUFFER_FLAG_END_OF_STREAM() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetStaticIntField(mMediaCodecClass, jBUFFER_FLAG_END_OF_STREAM);
+}
+
+int32_t MediaCodec::getBUFFER_FLAG_SYNC_FRAME() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetStaticIntField(mMediaCodecClass, jBUFFER_FLAG_SYNC_FRAME);
+}
+
+int32_t MediaCodec::getCONFIGURE_FLAG_ENCODE() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetStaticIntField(mMediaCodecClass, jCONFIGURE_FLAG_ENCODE);
+}
+
+int32_t MediaCodec::getCRYPTO_MODE_AES_CTR() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetStaticIntField(mMediaCodecClass, jCRYPTO_MODE_AES_CTR);
+}
+
+int32_t MediaCodec::getCRYPTO_MODE_UNENCRYPTED() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetStaticIntField(mMediaCodecClass, jCRYPTO_MODE_UNENCRYPTED);
+}
+
+int32_t MediaCodec::getINFO_OUTPUT_BUFFERS_CHANGED() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetStaticIntField(mMediaCodecClass, jINFO_OUTPUT_BUFFERS_CHANGED);
+}
+
+int32_t MediaCodec::getINFO_OUTPUT_FORMAT_CHANGED() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetStaticIntField(mMediaCodecClass, jINFO_OUTPUT_FORMAT_CHANGED);
+}
+
+int32_t MediaCodec::getINFO_TRY_AGAIN_LATER() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetStaticIntField(mMediaCodecClass, jINFO_TRY_AGAIN_LATER);
+}
+
+int32_t MediaCodec::getVIDEO_SCALING_MODE_SCALE_TO_FIT() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetStaticIntField(mMediaCodecClass, jVIDEO_SCALING_MODE_SCALE_TO_FIT);
+}
+
+int32_t MediaCodec::getVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetStaticIntField(mMediaCodecClass, jVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
+}
+jclass MediaFormat::mMediaFormatClass = 0;
+jmethodID MediaFormat::jMediaFormat = 0;
+jmethodID MediaFormat::jContainsKey = 0;
+jmethodID MediaFormat::jCreateAudioFormat = 0;
+jmethodID MediaFormat::jCreateVideoFormat = 0;
+jmethodID MediaFormat::jGetByteBuffer = 0;
+jmethodID MediaFormat::jGetFloat = 0;
+jmethodID MediaFormat::jGetInteger = 0;
+jmethodID MediaFormat::jGetLong = 0;
+jmethodID MediaFormat::jGetString = 0;
+jmethodID MediaFormat::jSetByteBuffer = 0;
+jmethodID MediaFormat::jSetFloat = 0;
+jmethodID MediaFormat::jSetInteger = 0;
+jmethodID MediaFormat::jSetLong = 0;
+jmethodID MediaFormat::jSetString = 0;
+jmethodID MediaFormat::jToString = 0;
+jfieldID MediaFormat::jKEY_AAC_PROFILE = 0;
+jfieldID MediaFormat::jKEY_BIT_RATE = 0;
+jfieldID MediaFormat::jKEY_CHANNEL_COUNT = 0;
+jfieldID MediaFormat::jKEY_CHANNEL_MASK = 0;
+jfieldID MediaFormat::jKEY_COLOR_FORMAT = 0;
+jfieldID MediaFormat::jKEY_DURATION = 0;
+jfieldID MediaFormat::jKEY_FLAC_COMPRESSION_LEVEL = 0;
+jfieldID MediaFormat::jKEY_FRAME_RATE = 0;
+jfieldID MediaFormat::jKEY_HEIGHT = 0;
+jfieldID MediaFormat::jKEY_IS_ADTS = 0;
+jfieldID MediaFormat::jKEY_I_FRAME_INTERVAL = 0;
+jfieldID MediaFormat::jKEY_MAX_INPUT_SIZE = 0;
+jfieldID MediaFormat::jKEY_MIME = 0;
+jfieldID MediaFormat::jKEY_SAMPLE_RATE = 0;
+jfieldID MediaFormat::jKEY_WIDTH = 0;
+void MediaFormat::InitStubs(JNIEnv *jEnv) {
+    initInit();
+
+    mMediaFormatClass = getClassGlobalRef("android/media/MediaFormat");
+    jMediaFormat = getMethod("<init>", "()V");
+    jContainsKey = getMethod("containsKey", "(Ljava/lang/String;)Z");
+    jCreateAudioFormat = getStaticMethod("createAudioFormat", "(Ljava/lang/String;II)Landroid/media/MediaFormat;");
+    jCreateVideoFormat = getStaticMethod("createVideoFormat", "(Ljava/lang/String;II)Landroid/media/MediaFormat;");
+    jGetByteBuffer = getMethod("getByteBuffer", "(Ljava/lang/String;)Ljava/nio/ByteBuffer;");
+    jGetFloat = getMethod("getFloat", "(Ljava/lang/String;)F");
+    jGetInteger = getMethod("getInteger", "(Ljava/lang/String;)I");
+    jGetLong = getMethod("getLong", "(Ljava/lang/String;)J");
+    jGetString = getMethod("getString", "(Ljava/lang/String;)Ljava/lang/String;");
+    jSetByteBuffer = getMethod("setByteBuffer", "(Ljava/lang/String;Ljava/nio/ByteBuffer;)V");
+    jSetFloat = getMethod("setFloat", "(Ljava/lang/String;F)V");
+    jSetInteger = getMethod("setInteger", "(Ljava/lang/String;I)V");
+    jSetLong = getMethod("setLong", "(Ljava/lang/String;J)V");
+    jSetString = getMethod("setString", "(Ljava/lang/String;Ljava/lang/String;)V");
+    jToString = getMethod("toString", "()Ljava/lang/String;");
+    jKEY_AAC_PROFILE = getStaticField("KEY_AAC_PROFILE", "Ljava/lang/String;");
+    jKEY_BIT_RATE = getStaticField("KEY_BIT_RATE", "Ljava/lang/String;");
+    jKEY_CHANNEL_COUNT = getStaticField("KEY_CHANNEL_COUNT", "Ljava/lang/String;");
+    jKEY_CHANNEL_MASK = getStaticField("KEY_CHANNEL_MASK", "Ljava/lang/String;");
+    jKEY_COLOR_FORMAT = getStaticField("KEY_COLOR_FORMAT", "Ljava/lang/String;");
+    jKEY_DURATION = getStaticField("KEY_DURATION", "Ljava/lang/String;");
+    jKEY_FLAC_COMPRESSION_LEVEL = getStaticField("KEY_FLAC_COMPRESSION_LEVEL", "Ljava/lang/String;");
+    jKEY_FRAME_RATE = getStaticField("KEY_FRAME_RATE", "Ljava/lang/String;");
+    jKEY_HEIGHT = getStaticField("KEY_HEIGHT", "Ljava/lang/String;");
+    jKEY_IS_ADTS = getStaticField("KEY_IS_ADTS", "Ljava/lang/String;");
+    jKEY_I_FRAME_INTERVAL = getStaticField("KEY_I_FRAME_INTERVAL", "Ljava/lang/String;");
+    jKEY_MAX_INPUT_SIZE = getStaticField("KEY_MAX_INPUT_SIZE", "Ljava/lang/String;");
+    jKEY_MIME = getStaticField("KEY_MIME", "Ljava/lang/String;");
+    jKEY_SAMPLE_RATE = getStaticField("KEY_SAMPLE_RATE", "Ljava/lang/String;");
+    jKEY_WIDTH = getStaticField("KEY_WIDTH", "Ljava/lang/String;");
+}
+
+MediaFormat* MediaFormat::Wrap(jobject obj) {
+    JNIEnv *env = GetJNIForThread();
+    MediaFormat* ret = new MediaFormat(obj, env);
+    env->DeleteLocalRef(obj);
+    return ret;
+}
+
+MediaFormat::MediaFormat() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    Init(env->NewObject(mMediaFormatClass, jMediaFormat), env);
+    env->PopLocalFrame(nullptr);
+}
+
+bool MediaFormat::ContainsKey(const nsAString& a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+
+    bool temp = env->CallBooleanMethod(wrapped_obj, jContainsKey, j0);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+jobject MediaFormat::CreateAudioFormat(const nsAString& a0, int32_t a1, int32_t a2) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(2) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jvalue args[3];
+    args[0].l = AndroidBridge::NewJavaString(env, a0);
+    args[1].i = a1;
+    args[2].i = a2;
+
+    jobject temp = env->CallStaticObjectMethodA(mMediaFormatClass, jCreateAudioFormat, args);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject MediaFormat::CreateVideoFormat(const nsAString& a0, int32_t a1, int32_t a2) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(2) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jvalue args[3];
+    args[0].l = AndroidBridge::NewJavaString(env, a0);
+    args[1].i = a1;
+    args[2].i = a2;
+
+    jobject temp = env->CallStaticObjectMethodA(mMediaFormatClass, jCreateVideoFormat, args);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject MediaFormat::GetByteBuffer(const nsAString& a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(2) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jGetByteBuffer, j0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jfloat MediaFormat::GetFloat(const nsAString& a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+
+    jfloat temp = env->CallFloatMethod(wrapped_obj, jGetFloat, j0);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+int32_t MediaFormat::GetInteger(const nsAString& a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+
+    int32_t temp = env->CallIntMethod(wrapped_obj, jGetInteger, j0);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+int64_t MediaFormat::GetLong(const nsAString& a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+
+    int64_t temp = env->CallLongMethod(wrapped_obj, jGetLong, j0);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+jstring MediaFormat::GetString(const nsAString& a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(2) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jGetString, j0);
+    AndroidBridge::HandleUncaughtException(env);
+    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+void MediaFormat::SetByteBuffer(const nsAString& a0, jobject a1) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(2) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+
+    env->CallVoidMethod(wrapped_obj, jSetByteBuffer, j0, a1);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+}
+
+void MediaFormat::SetFloat(const nsAString& a0, jfloat a1) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+
+    env->CallVoidMethod(wrapped_obj, jSetFloat, j0, a1);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+}
+
+void MediaFormat::SetInteger(const nsAString& a0, int32_t a1) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+
+    env->CallVoidMethod(wrapped_obj, jSetInteger, j0, a1);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+}
+
+void MediaFormat::SetLong(const nsAString& a0, int64_t a1) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+
+    env->CallVoidMethod(wrapped_obj, jSetLong, j0, a1);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+}
+
+void MediaFormat::SetString(const nsAString& a0, const nsAString& a1) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(2) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+    jstring j1 = AndroidBridge::NewJavaString(env, a1);
+
+    env->CallVoidMethod(wrapped_obj, jSetString, j0, j1);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+}
+
+jstring MediaFormat::ToString() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jToString);
+    AndroidBridge::HandleUncaughtException(env);
+    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jstring MediaFormat::getKEY_AAC_PROFILE() {
+    JNIEnv *env = GetJNIForThread();
+    return static_cast<jstring>(env->GetStaticObjectField(mMediaFormatClass, jKEY_AAC_PROFILE));
+}
+
+jstring MediaFormat::getKEY_BIT_RATE() {
+    JNIEnv *env = GetJNIForThread();
+    return static_cast<jstring>(env->GetStaticObjectField(mMediaFormatClass, jKEY_BIT_RATE));
+}
+
+jstring MediaFormat::getKEY_CHANNEL_COUNT() {
+    JNIEnv *env = GetJNIForThread();
+    return static_cast<jstring>(env->GetStaticObjectField(mMediaFormatClass, jKEY_CHANNEL_COUNT));
+}
+
+jstring MediaFormat::getKEY_CHANNEL_MASK() {
+    JNIEnv *env = GetJNIForThread();
+    return static_cast<jstring>(env->GetStaticObjectField(mMediaFormatClass, jKEY_CHANNEL_MASK));
+}
+
+jstring MediaFormat::getKEY_COLOR_FORMAT() {
+    JNIEnv *env = GetJNIForThread();
+    return static_cast<jstring>(env->GetStaticObjectField(mMediaFormatClass, jKEY_COLOR_FORMAT));
+}
+
+jstring MediaFormat::getKEY_DURATION() {
+    JNIEnv *env = GetJNIForThread();
+    return static_cast<jstring>(env->GetStaticObjectField(mMediaFormatClass, jKEY_DURATION));
+}
+
+jstring MediaFormat::getKEY_FLAC_COMPRESSION_LEVEL() {
+    JNIEnv *env = GetJNIForThread();
+    return static_cast<jstring>(env->GetStaticObjectField(mMediaFormatClass, jKEY_FLAC_COMPRESSION_LEVEL));
+}
+
+jstring MediaFormat::getKEY_FRAME_RATE() {
+    JNIEnv *env = GetJNIForThread();
+    return static_cast<jstring>(env->GetStaticObjectField(mMediaFormatClass, jKEY_FRAME_RATE));
+}
+
+jstring MediaFormat::getKEY_HEIGHT() {
+    JNIEnv *env = GetJNIForThread();
+    return static_cast<jstring>(env->GetStaticObjectField(mMediaFormatClass, jKEY_HEIGHT));
+}
+
+jstring MediaFormat::getKEY_IS_ADTS() {
+    JNIEnv *env = GetJNIForThread();
+    return static_cast<jstring>(env->GetStaticObjectField(mMediaFormatClass, jKEY_IS_ADTS));
+}
+
+jstring MediaFormat::getKEY_I_FRAME_INTERVAL() {
+    JNIEnv *env = GetJNIForThread();
+    return static_cast<jstring>(env->GetStaticObjectField(mMediaFormatClass, jKEY_I_FRAME_INTERVAL));
+}
+
+jstring MediaFormat::getKEY_MAX_INPUT_SIZE() {
+    JNIEnv *env = GetJNIForThread();
+    return static_cast<jstring>(env->GetStaticObjectField(mMediaFormatClass, jKEY_MAX_INPUT_SIZE));
+}
+
+jstring MediaFormat::getKEY_MIME() {
+    JNIEnv *env = GetJNIForThread();
+    return static_cast<jstring>(env->GetStaticObjectField(mMediaFormatClass, jKEY_MIME));
+}
+
+jstring MediaFormat::getKEY_SAMPLE_RATE() {
+    JNIEnv *env = GetJNIForThread();
+    return static_cast<jstring>(env->GetStaticObjectField(mMediaFormatClass, jKEY_SAMPLE_RATE));
+}
+
+jstring MediaFormat::getKEY_WIDTH() {
+    JNIEnv *env = GetJNIForThread();
+    return static_cast<jstring>(env->GetStaticObjectField(mMediaFormatClass, jKEY_WIDTH));
+}
+jclass ByteBuffer::mByteBufferClass = 0;
+jmethodID ByteBuffer::j_get = 0;
+jmethodID ByteBuffer::j_put = 0;
+jmethodID ByteBuffer::jAllocate = 0;
+jmethodID ByteBuffer::jAllocateDirect = 0;
+jmethodID ByteBuffer::jArray = 0;
+jmethodID ByteBuffer::jArray1 = 0;
+jmethodID ByteBuffer::jArrayOffset = 0;
+jmethodID ByteBuffer::jAsCharBuffer = 0;
+jmethodID ByteBuffer::jAsDoubleBuffer = 0;
+jmethodID ByteBuffer::jAsFloatBuffer = 0;
+jmethodID ByteBuffer::jAsIntBuffer = 0;
+jmethodID ByteBuffer::jAsLongBuffer = 0;
+jmethodID ByteBuffer::jAsReadOnlyBuffer = 0;
+jmethodID ByteBuffer::jAsShortBuffer = 0;
+jmethodID ByteBuffer::jCompact = 0;
+jmethodID ByteBuffer::jCompareTo = 0;
+jmethodID ByteBuffer::jCompareTo1 = 0;
+jmethodID ByteBuffer::jDuplicate = 0;
+jmethodID ByteBuffer::jEquals = 0;
+jmethodID ByteBuffer::jGet = 0;
+jmethodID ByteBuffer::jGet1 = 0;
+jmethodID ByteBuffer::jGet10 = 0;
+jmethodID ByteBuffer::jGet11 = 0;
+jmethodID ByteBuffer::jGetChar = 0;
+jmethodID ByteBuffer::jGetChar1 = 0;
+jmethodID ByteBuffer::jGetDouble = 0;
+jmethodID ByteBuffer::jGetDouble1 = 0;
+jmethodID ByteBuffer::jGetFloat = 0;
+jmethodID ByteBuffer::jGetFloat1 = 0;
+jmethodID ByteBuffer::jGetInt = 0;
+jmethodID ByteBuffer::jGetInt1 = 0;
+jmethodID ByteBuffer::jGetLong = 0;
+jmethodID ByteBuffer::jGetLong1 = 0;
+jmethodID ByteBuffer::jGetShort = 0;
+jmethodID ByteBuffer::jGetShort1 = 0;
+jmethodID ByteBuffer::jHasArray = 0;
+jmethodID ByteBuffer::jHashCode = 0;
+jmethodID ByteBuffer::jIsDirect = 0;
+jmethodID ByteBuffer::jOrder = 0;
+jmethodID ByteBuffer::jOrder1 = 0;
+jmethodID ByteBuffer::jPut = 0;
+jmethodID ByteBuffer::jPut1 = 0;
+jmethodID ByteBuffer::jPut12 = 0;
+jmethodID ByteBuffer::jPut13 = 0;
+jmethodID ByteBuffer::jPut14 = 0;
+jmethodID ByteBuffer::jPutChar = 0;
+jmethodID ByteBuffer::jPutChar1 = 0;
+jmethodID ByteBuffer::jPutDouble = 0;
+jmethodID ByteBuffer::jPutDouble1 = 0;
+jmethodID ByteBuffer::jPutFloat = 0;
+jmethodID ByteBuffer::jPutFloat1 = 0;
+jmethodID ByteBuffer::jPutInt = 0;
+jmethodID ByteBuffer::jPutInt1 = 0;
+jmethodID ByteBuffer::jPutLong = 0;
+jmethodID ByteBuffer::jPutLong1 = 0;
+jmethodID ByteBuffer::jPutShort = 0;
+jmethodID ByteBuffer::jPutShort1 = 0;
+jmethodID ByteBuffer::jSlice = 0;
+jmethodID ByteBuffer::jToString = 0;
+jmethodID ByteBuffer::jWrap = 0;
+jmethodID ByteBuffer::jWrap1 = 0;
+jfieldID ByteBuffer::jBigEndian = 0;
+jfieldID ByteBuffer::jHb = 0;
+jfieldID ByteBuffer::jIsReadOnly = 0;
+jfieldID ByteBuffer::jNativeByteOrder = 0;
+jfieldID ByteBuffer::jOffset = 0;
+void ByteBuffer::InitStubs(JNIEnv *jEnv) {
+    initInit();
+
+    mByteBufferClass = getClassGlobalRef("java/nio/ByteBuffer");
+    //j_get = getMethod("_get", "(I)B");
+    //j_put = getMethod("_put", "(IB)V");
+    jAllocate = getStaticMethod("allocate", "(I)Ljava/nio/ByteBuffer;");
+    jAllocateDirect = getStaticMethod("allocateDirect", "(I)Ljava/nio/ByteBuffer;");
+    jArray = getMethod("array", "()Ljava/lang/Object;");
+    jArray1 = getMethod("array", "()[B");
+    jArrayOffset = getMethod("arrayOffset", "()I");
+    jAsCharBuffer = getMethod("asCharBuffer", "()Ljava/nio/CharBuffer;");
+    jAsDoubleBuffer = getMethod("asDoubleBuffer", "()Ljava/nio/DoubleBuffer;");
+    jAsFloatBuffer = getMethod("asFloatBuffer", "()Ljava/nio/FloatBuffer;");
+    jAsIntBuffer = getMethod("asIntBuffer", "()Ljava/nio/IntBuffer;");
+    jAsLongBuffer = getMethod("asLongBuffer", "()Ljava/nio/LongBuffer;");
+    jAsReadOnlyBuffer = getMethod("asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;");
+    jAsShortBuffer = getMethod("asShortBuffer", "()Ljava/nio/ShortBuffer;");
+    jCompact = getMethod("compact", "()Ljava/nio/ByteBuffer;");
+    jCompareTo = getMethod("compareTo", "(Ljava/lang/Object;)I");
+    jCompareTo1 = getMethod("compareTo", "(Ljava/nio/ByteBuffer;)I");
+    jDuplicate = getMethod("duplicate", "()Ljava/nio/ByteBuffer;");
+    jEquals = getMethod("equals", "(Ljava/lang/Object;)Z");
+    jGet = getMethod("get", "()B");
+    jGet1 = getMethod("get", "(I)B");
+    jGet10 = getMethod("get", "([B)Ljava/nio/ByteBuffer;");
+    jGet11 = getMethod("get", "([BII)Ljava/nio/ByteBuffer;");
+    jGetChar = getMethod("getChar", "()C");
+    jGetChar1 = getMethod("getChar", "(I)C");
+    jGetDouble = getMethod("getDouble", "()D");
+    jGetDouble1 = getMethod("getDouble", "(I)D");
+    jGetFloat = getMethod("getFloat", "()F");
+    jGetFloat1 = getMethod("getFloat", "(I)F");
+    jGetInt = getMethod("getInt", "()I");
+    jGetInt1 = getMethod("getInt", "(I)I");
+    jGetLong = getMethod("getLong", "()J");
+    jGetLong1 = getMethod("getLong", "(I)J");
+    jGetShort = getMethod("getShort", "()S");
+    jGetShort1 = getMethod("getShort", "(I)S");
+    jHasArray = getMethod("hasArray", "()Z");
+    jHashCode = getMethod("hashCode", "()I");
+    jIsDirect = getMethod("isDirect", "()Z");
+    jOrder = getMethod("order", "()Ljava/nio/ByteOrder;");
+    jOrder1 = getMethod("order", "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
+    jPut = getMethod("put", "(B)Ljava/nio/ByteBuffer;");
+    jPut1 = getMethod("put", "(IB)Ljava/nio/ByteBuffer;");
+    jPut12 = getMethod("put", "(Ljava/nio/ByteBuffer;)Ljava/nio/ByteBuffer;");
+    jPut13 = getMethod("put", "([B)Ljava/nio/ByteBuffer;");
+    jPut14 = getMethod("put", "([BII)Ljava/nio/ByteBuffer;");
+    jPutChar = getMethod("putChar", "(C)Ljava/nio/ByteBuffer;");
+    jPutChar1 = getMethod("putChar", "(IC)Ljava/nio/ByteBuffer;");
+    jPutDouble = getMethod("putDouble", "(D)Ljava/nio/ByteBuffer;");
+    jPutDouble1 = getMethod("putDouble", "(ID)Ljava/nio/ByteBuffer;");
+    jPutFloat = getMethod("putFloat", "(F)Ljava/nio/ByteBuffer;");
+    jPutFloat1 = getMethod("putFloat", "(IF)Ljava/nio/ByteBuffer;");
+    jPutInt = getMethod("putInt", "(I)Ljava/nio/ByteBuffer;");
+    jPutInt1 = getMethod("putInt", "(II)Ljava/nio/ByteBuffer;");
+    jPutLong = getMethod("putLong", "(IJ)Ljava/nio/ByteBuffer;");
+    jPutLong1 = getMethod("putLong", "(J)Ljava/nio/ByteBuffer;");
+    jPutShort = getMethod("putShort", "(IS)Ljava/nio/ByteBuffer;");
+    jPutShort1 = getMethod("putShort", "(S)Ljava/nio/ByteBuffer;");
+    jSlice = getMethod("slice", "()Ljava/nio/ByteBuffer;");
+    jToString = getMethod("toString", "()Ljava/lang/String;");
+    jWrap = getStaticMethod("wrap", "([B)Ljava/nio/ByteBuffer;");
+    jWrap1 = getStaticMethod("wrap", "([BII)Ljava/nio/ByteBuffer;");
+    /*
+    jBigEndian = getField("bigEndian", "Z");
+    jHb = getField("hb", "[B");
+    jIsReadOnly = getField("isReadOnly", "Z");
+    jNativeByteOrder = getField("nativeByteOrder", "Z");
+    jOffset = getField("offset", "I");
+  */
+}
+
+ByteBuffer* ByteBuffer::Wrap(jobject obj) {
+    JNIEnv *env = GetJNIForThread();
+    ByteBuffer* ret = new ByteBuffer(obj, env);
+    env->DeleteLocalRef(obj);
+    return ret;
+}
+
+int8_t ByteBuffer::_get(int32_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    int8_t temp = env->CallByteMethod(wrapped_obj, j_get, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+void ByteBuffer::_put(int32_t a0, int8_t a1) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    env->CallVoidMethod(wrapped_obj, j_put, a0, a1);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+}
+
+jobject ByteBuffer::Allocate(int32_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallStaticObjectMethod(mByteBufferClass, jAllocate, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::AllocateDirect(int32_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallStaticObjectMethod(mByteBufferClass, jAllocateDirect, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::Array() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jArray);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jbyteArray ByteBuffer::Array1() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jArray1);
+    AndroidBridge::HandleUncaughtException(env);
+    jbyteArray ret = static_cast<jbyteArray>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+int32_t ByteBuffer::ArrayOffset() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    int32_t temp = env->CallIntMethod(wrapped_obj, jArrayOffset);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+jstring ByteBuffer::AsCharBuffer() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jAsCharBuffer);
+    AndroidBridge::HandleUncaughtException(env);
+    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::AsDoubleBuffer() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jAsDoubleBuffer);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::AsFloatBuffer() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jAsFloatBuffer);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::AsIntBuffer() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jAsIntBuffer);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::AsLongBuffer() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jAsLongBuffer);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::AsReadOnlyBuffer() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jAsReadOnlyBuffer);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::AsShortBuffer() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jAsShortBuffer);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::Compact() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jCompact);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+int32_t ByteBuffer::CompareTo(jobject a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    int32_t temp = env->CallIntMethod(wrapped_obj, jCompareTo, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+int32_t ByteBuffer::CompareTo1(jobject a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    int32_t temp = env->CallIntMethod(wrapped_obj, jCompareTo1, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+jobject ByteBuffer::Duplicate() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jDuplicate);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+bool ByteBuffer::Equals(jobject a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    bool temp = env->CallBooleanMethod(wrapped_obj, jEquals, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+int8_t ByteBuffer::Get() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    int8_t temp = env->CallByteMethod(wrapped_obj, jGet);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+int8_t ByteBuffer::Get1(int32_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    int8_t temp = env->CallByteMethod(wrapped_obj, jGet1, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+jobject ByteBuffer::Get1(jbyteArray a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(2) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jGet10, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::Get1(jbyteArray a0, int32_t a1, int32_t a2) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(2) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jvalue args[3];
+    args[0].l = a0;
+    args[1].i = a1;
+    args[2].i = a2;
+
+    jobject temp = env->CallObjectMethodA(wrapped_obj, jGet11, args);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+uint16_t ByteBuffer::GetChar() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    uint16_t temp = env->CallCharMethod(wrapped_obj, jGetChar);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+uint16_t ByteBuffer::GetChar1(int32_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    uint16_t temp = env->CallCharMethod(wrapped_obj, jGetChar1, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+jdouble ByteBuffer::GetDouble() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jdouble temp = env->CallDoubleMethod(wrapped_obj, jGetDouble);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+jdouble ByteBuffer::GetDouble1(int32_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jdouble temp = env->CallDoubleMethod(wrapped_obj, jGetDouble1, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+jfloat ByteBuffer::GetFloat() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jfloat temp = env->CallFloatMethod(wrapped_obj, jGetFloat);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+jfloat ByteBuffer::GetFloat1(int32_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jfloat temp = env->CallFloatMethod(wrapped_obj, jGetFloat1, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+int32_t ByteBuffer::GetInt() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    int32_t temp = env->CallIntMethod(wrapped_obj, jGetInt);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+int32_t ByteBuffer::GetInt1(int32_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    int32_t temp = env->CallIntMethod(wrapped_obj, jGetInt1, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+int64_t ByteBuffer::GetLong() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    int64_t temp = env->CallLongMethod(wrapped_obj, jGetLong);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+int64_t ByteBuffer::GetLong1(int32_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    int64_t temp = env->CallLongMethod(wrapped_obj, jGetLong1, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+int16_t ByteBuffer::GetShort() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    int16_t temp = env->CallShortMethod(wrapped_obj, jGetShort);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+int16_t ByteBuffer::GetShort1(int32_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    int16_t temp = env->CallShortMethod(wrapped_obj, jGetShort1, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+bool ByteBuffer::HasArray() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    bool temp = env->CallBooleanMethod(wrapped_obj, jHasArray);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+int32_t ByteBuffer::HashCode() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    int32_t temp = env->CallIntMethod(wrapped_obj, jHashCode);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+bool ByteBuffer::IsDirect() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    bool temp = env->CallBooleanMethod(wrapped_obj, jIsDirect);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+    return temp;
+}
+
+jobject ByteBuffer::Order() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jOrder);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::Order1(jobject a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(2) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jOrder1, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::Put(int8_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jPut, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::Put1(int32_t a0, int8_t a1) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jPut1, a0, a1);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::Put1(jobject a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(2) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jPut12, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::Put1(jbyteArray a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(2) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jPut13, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::Put1(jbyteArray a0, int32_t a1, int32_t a2) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(2) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jvalue args[3];
+    args[0].l = a0;
+    args[1].i = a1;
+    args[2].i = a2;
+
+    jobject temp = env->CallObjectMethodA(wrapped_obj, jPut14, args);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::PutChar(uint16_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jPutChar, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::PutChar1(int32_t a0, uint16_t a1) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jPutChar1, a0, a1);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::PutDouble(jdouble a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jPutDouble, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::PutDouble1(int32_t a0, jdouble a1) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jPutDouble1, a0, a1);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::PutFloat(jfloat a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jPutFloat, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::PutFloat1(int32_t a0, jfloat a1) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jPutFloat1, a0, a1);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::PutInt(int32_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jPutInt, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::PutInt1(int32_t a0, int32_t a1) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jPutInt1, a0, a1);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::PutLong(int32_t a0, int64_t a1) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jPutLong, a0, a1);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::PutLong1(int64_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jPutLong1, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::PutShort(int32_t a0, int16_t a1) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jPutShort, a0, a1);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::PutShort1(int16_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jPutShort1, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::Slice() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jSlice);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jstring ByteBuffer::ToString() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(1) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallObjectMethod(wrapped_obj, jToString);
+    AndroidBridge::HandleUncaughtException(env);
+    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::Wrap1(jbyteArray a0) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(2) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jobject temp = env->CallStaticObjectMethod(mByteBufferClass, jWrap, a0);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+jobject ByteBuffer::Wrap2(jbyteArray a0, int32_t a1, int32_t a2) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(2) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jvalue args[3];
+    args[0].l = a0;
+    args[1].i = a1;
+    args[2].i = a2;
+
+    jobject temp = env->CallStaticObjectMethodA(mByteBufferClass, jWrap1, args);
+    AndroidBridge::HandleUncaughtException(env);
+    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
+    return ret;
+}
+
+bool ByteBuffer::getBigEndian() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetBooleanField(wrapped_obj, jBigEndian);
+}
+
+void ByteBuffer::setBigEndian(bool a0) {
+    JNIEnv *env = GetJNIForThread();
+    env->SetBooleanField(wrapped_obj, jBigEndian, a0);
+}
+
+jbyteArray ByteBuffer::getHb() {
+    JNIEnv *env = GetJNIForThread();
+    return static_cast<jbyteArray>(env->GetObjectField(wrapped_obj, jHb));
+}
+
+bool ByteBuffer::getIsReadOnly() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetBooleanField(wrapped_obj, jIsReadOnly);
+}
+
+void ByteBuffer::setIsReadOnly(bool a0) {
+    JNIEnv *env = GetJNIForThread();
+    env->SetBooleanField(wrapped_obj, jIsReadOnly, a0);
+}
+
+bool ByteBuffer::getNativeByteOrder() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetBooleanField(wrapped_obj, jNativeByteOrder);
+}
+
+void ByteBuffer::setNativeByteOrder(bool a0) {
+    JNIEnv *env = GetJNIForThread();
+    env->SetBooleanField(wrapped_obj, jNativeByteOrder, a0);
+}
+
+int32_t ByteBuffer::getOffset() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetIntField(wrapped_obj, jOffset);
+}
+
+jclass BufferInfo::mBufferInfoClass = 0;
+jmethodID BufferInfo::jBufferInfo = 0;
+jmethodID BufferInfo::jSet = 0;
+jfieldID BufferInfo::jFlags = 0;
+jfieldID BufferInfo::jOffset = 0;
+jfieldID BufferInfo::jPresentationTimeUs = 0;
+jfieldID BufferInfo::jSize = 0;
+void BufferInfo::InitStubs(JNIEnv *jEnv) {
+    initInit();
+
+    mBufferInfoClass = getClassGlobalRef("android/media/MediaCodec$BufferInfo");
+    jBufferInfo = getMethod("<init>", "()V");
+    jSet = getMethod("set", "(IIJI)V");
+    jFlags = getField("flags", "I");
+    jOffset = getField("offset", "I");
+    jPresentationTimeUs = getField("presentationTimeUs", "J");
+    jSize = getField("size", "I");
+}
+
+BufferInfo* BufferInfo::Wrap(jobject obj) {
+    JNIEnv *env = GetJNIForThread();
+    BufferInfo* ret = new BufferInfo(obj, env);
+    env->DeleteLocalRef(obj);
+    return ret;
+}
+
+BufferInfo::BufferInfo() {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    Init(env->NewObject(mBufferInfoClass, jBufferInfo), env);
+    env->PopLocalFrame(nullptr);
+}
+
+void BufferInfo::Set(int32_t a0, int32_t a1, int64_t a2, int32_t a3) {
+    JNIEnv *env = GetJNIForThread();
+    if (env->PushLocalFrame(0) != 0) {
+        AndroidBridge::HandleUncaughtException(env);
+        MOZ_CRASH("Exception should have caused crash.");
+    }
+
+    jvalue args[4];
+    args[0].i = a0;
+    args[1].i = a1;
+    args[2].j = a2;
+    args[3].i = a3;
+
+    env->CallVoidMethodA(wrapped_obj, jSet, args);
+    AndroidBridge::HandleUncaughtException(env);
+    env->PopLocalFrame(nullptr);
+}
+
+int32_t BufferInfo::getFlags() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetIntField(wrapped_obj, jFlags);
+}
+
+void BufferInfo::setFlags(int32_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    env->SetIntField(wrapped_obj, jFlags, a0);
+}
+
+int32_t BufferInfo::getOffset() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetIntField(wrapped_obj, jOffset);
+}
+
+void BufferInfo::setOffset(int32_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    env->SetIntField(wrapped_obj, jOffset, a0);
+}
+
+int64_t BufferInfo::getPresentationTimeUs() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetLongField(wrapped_obj, jPresentationTimeUs);
+}
+
+void BufferInfo::setPresentationTimeUs(int64_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    env->SetLongField(wrapped_obj, jPresentationTimeUs, a0);
+}
+
+int32_t BufferInfo::getSize() {
+    JNIEnv *env = GetJNIForThread();
+    return env->GetIntField(wrapped_obj, jSize);
+}
+
+void BufferInfo::setSize(int32_t a0) {
+    JNIEnv *env = GetJNIForThread();
+    env->SetIntField(wrapped_obj, jSize, a0);
+}
+
+void InitSDKStubs(JNIEnv *jEnv) {
+    MediaCodec::InitStubs(jEnv);
+    MediaFormat::InitStubs(jEnv);
+    ByteBuffer::InitStubs(jEnv);
+    BufferInfo::InitStubs(jEnv);
+}
+} /* android */
+} /* widget */
+} /* mozilla */
new file mode 100644
--- /dev/null
+++ b/widget/android/GeneratedSDKWrappers.h
@@ -0,0 +1,335 @@
+// GENERATED CODE
+
+// NOTE: This code has been doctored. The JarClassProcessor is still a work in progress,
+// and so additions and deletions have been made to make this file valid.
+
+// Generated by the Java program at /build/jarClassProcessors at compile time from
+// a given set of jars and a set of requested methods. To update, change the annotations
+// on the corresponding Java methods and rerun the build. Manually updating this file
+// will cause your build to fail.
+
+#ifndef GeneratedSDKWrappers_h__
+#define GeneratedSDKWrappers_h__
+
+#include "nsXPCOMStrings.h"
+#include "AndroidJavaWrappers.h"
+
+namespace mozilla {
+namespace widget {
+namespace android {
+
+#define MEDIACODEC_EXCEPTION_INDEX -255
+
+void InitSDKStubs(JNIEnv *jEnv);
+
+class MediaCodec : public AutoGlobalWrappedJavaObject {
+public:
+    static void InitStubs(JNIEnv *jEnv);
+    static MediaCodec* Wrap(jobject obj);
+    MediaCodec(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {};
+    bool Configure(jobject a0, jobject a1, jobject a2, int32_t a3);
+    static jobject CreateByCodecName(const nsAString& a0);
+    static jobject CreateDecoderByType(const nsAString& a0);
+    static jobject CreateEncoderByType(const nsAString& a0);
+    int32_t DequeueInputBuffer(int64_t a0);
+    int32_t DequeueOutputBuffer(jobject a0, int64_t a1);
+    void Finalize();
+    void Flush();
+    jobjectArray GetInputBuffers();
+    jobjectArray GetOutputBuffers();
+    jobject GetOutputFormat();
+    void QueueInputBuffer(int32_t a0, int32_t a1, int32_t a2, int64_t a3, int32_t a4);
+    void QueueSecureInputBuffer(int32_t a0, int32_t a1, jobject a2, int64_t a3, int32_t a4);
+    void Release();
+    void ReleaseOutputBuffer(int32_t a0, bool a1);
+    void SetVideoScalingMode(int32_t a0);
+    bool Start();
+    void Stop();
+    static int32_t getBUFFER_FLAG_CODEC_CONFIG();
+    static int32_t getBUFFER_FLAG_END_OF_STREAM();
+    static int32_t getBUFFER_FLAG_SYNC_FRAME();
+    static int32_t getCONFIGURE_FLAG_ENCODE();
+    static int32_t getCRYPTO_MODE_AES_CTR();
+    static int32_t getCRYPTO_MODE_UNENCRYPTED();
+    static int32_t getINFO_OUTPUT_BUFFERS_CHANGED();
+    static int32_t getINFO_OUTPUT_FORMAT_CHANGED();
+    static int32_t getINFO_TRY_AGAIN_LATER();
+    static int32_t getVIDEO_SCALING_MODE_SCALE_TO_FIT();
+    static int32_t getVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING();
+    MediaCodec() : AutoGlobalWrappedJavaObject() {};
+protected:
+    static jclass mMediaCodecClass;
+    static jmethodID jConfigure;
+    static jmethodID jCreateByCodecName;
+    static jmethodID jCreateDecoderByType;
+    static jmethodID jCreateEncoderByType;
+    static jmethodID jDequeueInputBuffer;
+    static jmethodID jDequeueOutputBuffer;
+    static jmethodID jFinalize;
+    static jmethodID jFlush;
+    static jmethodID jGetInputBuffers;
+    static jmethodID jGetOutputBuffers;
+    static jmethodID jGetOutputFormat;
+    static jmethodID jQueueInputBuffer;
+    static jmethodID jQueueSecureInputBuffer;
+    static jmethodID jRelease;
+    static jmethodID jReleaseOutputBuffer;
+    static jmethodID jSetVideoScalingMode;
+    static jmethodID jStart;
+    static jmethodID jStop;
+    static jfieldID jBUFFER_FLAG_CODEC_CONFIG;
+    static jfieldID jBUFFER_FLAG_END_OF_STREAM;
+    static jfieldID jBUFFER_FLAG_SYNC_FRAME;
+    static jfieldID jCONFIGURE_FLAG_ENCODE;
+    static jfieldID jCRYPTO_MODE_AES_CTR;
+    static jfieldID jCRYPTO_MODE_UNENCRYPTED;
+    static jfieldID jINFO_OUTPUT_BUFFERS_CHANGED;
+    static jfieldID jINFO_OUTPUT_FORMAT_CHANGED;
+    static jfieldID jINFO_TRY_AGAIN_LATER;
+    static jfieldID jVIDEO_SCALING_MODE_SCALE_TO_FIT;
+    static jfieldID jVIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING;
+};
+
+class MediaFormat : public AutoGlobalWrappedJavaObject {
+public:
+    static void InitStubs(JNIEnv *jEnv);
+    static MediaFormat* Wrap(jobject obj);
+    MediaFormat(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {};
+    MediaFormat();
+    bool ContainsKey(const nsAString& a0);
+    static jobject CreateAudioFormat(const nsAString& a0, int32_t a1, int32_t a2);
+    static jobject CreateVideoFormat(const nsAString& a0, int32_t a1, int32_t a2);
+    jobject GetByteBuffer(const nsAString& a0);
+    jfloat GetFloat(const nsAString& a0);
+    int32_t GetInteger(const nsAString& a0);
+    int64_t GetLong(const nsAString& a0);
+    jstring GetString(const nsAString& a0);
+    void SetByteBuffer(const nsAString& a0, jobject a1);
+    void SetFloat(const nsAString& a0, jfloat a1);
+    void SetInteger(const nsAString& a0, int32_t a1);
+    void SetLong(const nsAString& a0, int64_t a1);
+    void SetString(const nsAString& a0, const nsAString& a1);
+    jstring ToString();
+    static jstring getKEY_AAC_PROFILE();
+    static jstring getKEY_BIT_RATE();
+    static jstring getKEY_CHANNEL_COUNT();
+    static jstring getKEY_CHANNEL_MASK();
+    static jstring getKEY_COLOR_FORMAT();
+    static jstring getKEY_DURATION();
+    static jstring getKEY_FLAC_COMPRESSION_LEVEL();
+    static jstring getKEY_FRAME_RATE();
+    static jstring getKEY_HEIGHT();
+    static jstring getKEY_IS_ADTS();
+    static jstring getKEY_I_FRAME_INTERVAL();
+    static jstring getKEY_MAX_INPUT_SIZE();
+    static jstring getKEY_MIME();
+    static jstring getKEY_SAMPLE_RATE();
+    static jstring getKEY_WIDTH();
+protected:
+    static jclass mMediaFormatClass;
+    static jmethodID jMediaFormat;
+    static jmethodID jContainsKey;
+    static jmethodID jCreateAudioFormat;
+    static jmethodID jCreateVideoFormat;
+    static jmethodID jGetByteBuffer;
+    static jmethodID jGetFloat;
+    static jmethodID jGetInteger;
+    static jmethodID jGetLong;
+    static jmethodID jGetString;
+    static jmethodID jSetByteBuffer;
+    static jmethodID jSetFloat;
+    static jmethodID jSetInteger;
+    static jmethodID jSetLong;
+    static jmethodID jSetString;
+    static jmethodID jToString;
+    static jfieldID jKEY_AAC_PROFILE;
+    static jfieldID jKEY_BIT_RATE;
+    static jfieldID jKEY_CHANNEL_COUNT;
+    static jfieldID jKEY_CHANNEL_MASK;
+    static jfieldID jKEY_COLOR_FORMAT;
+    static jfieldID jKEY_DURATION;
+    static jfieldID jKEY_FLAC_COMPRESSION_LEVEL;
+    static jfieldID jKEY_FRAME_RATE;
+    static jfieldID jKEY_HEIGHT;
+    static jfieldID jKEY_IS_ADTS;
+    static jfieldID jKEY_I_FRAME_INTERVAL;
+    static jfieldID jKEY_MAX_INPUT_SIZE;
+    static jfieldID jKEY_MIME;
+    static jfieldID jKEY_SAMPLE_RATE;
+    static jfieldID jKEY_WIDTH;
+};
+
+class ByteBuffer : public AutoGlobalWrappedJavaObject {
+public:
+    static void InitStubs(JNIEnv *jEnv);
+    static ByteBuffer* Wrap(jobject obj);
+    ByteBuffer(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {};
+    int8_t _get(int32_t a0);
+    void _put(int32_t a0, int8_t a1);
+    static jobject Allocate(int32_t a0);
+    static jobject AllocateDirect(int32_t a0);
+    jobject Array();
+    jbyteArray Array1();
+    int32_t ArrayOffset();
+    jstring AsCharBuffer();
+    jobject AsDoubleBuffer();
+    jobject AsFloatBuffer();
+    jobject AsIntBuffer();
+    jobject AsLongBuffer();
+    jobject AsReadOnlyBuffer();
+    jobject AsShortBuffer();
+    jobject Compact();
+    int32_t CompareTo(jobject a0);
+    int32_t CompareTo1(jobject a0);
+    jobject Duplicate();
+    bool Equals(jobject a0);
+    int8_t Get();
+    int8_t Get1(int32_t a0);
+    jobject Get1(jbyteArray a0);
+    jobject Get1(jbyteArray a0, int32_t a1, int32_t a2);
+    uint16_t GetChar();
+    uint16_t GetChar1(int32_t a0);
+    jdouble GetDouble();
+    jdouble GetDouble1(int32_t a0);
+    jfloat GetFloat();
+    jfloat GetFloat1(int32_t a0);
+    int32_t GetInt();
+    int32_t GetInt1(int32_t a0);
+    int64_t GetLong();
+    int64_t GetLong1(int32_t a0);
+    int16_t GetShort();
+    int16_t GetShort1(int32_t a0);
+    bool HasArray();
+    int32_t HashCode();
+    bool IsDirect();
+    jobject Order();
+    jobject Order1(jobject a0);
+    jobject Put(int8_t a0);
+    jobject Put1(int32_t a0, int8_t a1);
+    jobject Put1(jobject a0);
+    jobject Put1(jbyteArray a0);
+    jobject Put1(jbyteArray a0, int32_t a1, int32_t a2);
+    jobject PutChar(uint16_t a0);
+    jobject PutChar1(int32_t a0, uint16_t a1);
+    jobject PutDouble(jdouble a0);
+    jobject PutDouble1(int32_t a0, jdouble a1);
+    jobject PutFloat(jfloat a0);
+    jobject PutFloat1(int32_t a0, jfloat a1);
+    jobject PutInt(int32_t a0);
+    jobject PutInt1(int32_t a0, int32_t a1);
+    jobject PutLong(int32_t a0, int64_t a1);
+    jobject PutLong1(int64_t a0);
+    jobject PutShort(int32_t a0, int16_t a1);
+    jobject PutShort1(int16_t a0);
+    jobject Slice();
+    jstring ToString();
+    static jobject Wrap1(jbyteArray a0);
+    static jobject Wrap2(jbyteArray a0, int32_t a1, int32_t a2);
+    bool getBigEndian();
+    void setBigEndian(bool a0);
+    jbyteArray getHb();
+    bool getIsReadOnly();
+    void setIsReadOnly(bool a0);
+    bool getNativeByteOrder();
+    void setNativeByteOrder(bool a0);
+    int32_t getOffset();
+    ByteBuffer() : AutoGlobalWrappedJavaObject() {};
+protected:
+    static jclass mByteBufferClass;
+    static jmethodID j_get;
+    static jmethodID j_put;
+    static jmethodID jAllocate;
+    static jmethodID jAllocateDirect;
+    static jmethodID jArray;
+    static jmethodID jArray1;
+    static jmethodID jArrayOffset;
+    static jmethodID jAsCharBuffer;
+    static jmethodID jAsDoubleBuffer;
+    static jmethodID jAsFloatBuffer;
+    static jmethodID jAsIntBuffer;
+    static jmethodID jAsLongBuffer;
+    static jmethodID jAsReadOnlyBuffer;
+    static jmethodID jAsShortBuffer;
+    static jmethodID jCompact;
+    static jmethodID jCompareTo;
+    static jmethodID jCompareTo1;
+    static jmethodID jDuplicate;
+    static jmethodID jEquals;
+    static jmethodID jGet;
+    static jmethodID jGet1;
+    static jmethodID jGet10;
+    static jmethodID jGet11;
+    static jmethodID jGetChar;
+    static jmethodID jGetChar1;
+    static jmethodID jGetDouble;
+    static jmethodID jGetDouble1;
+    static jmethodID jGetFloat;
+    static jmethodID jGetFloat1;
+    static jmethodID jGetInt;
+    static jmethodID jGetInt1;
+    static jmethodID jGetLong;
+    static jmethodID jGetLong1;
+    static jmethodID jGetShort;
+    static jmethodID jGetShort1;
+    static jmethodID jHasArray;
+    static jmethodID jHashCode;
+    static jmethodID jIsDirect;
+    static jmethodID jOrder;
+    static jmethodID jOrder1;
+    static jmethodID jPut;
+    static jmethodID jPut1;
+    static jmethodID jPut12;
+    static jmethodID jPut13;
+    static jmethodID jPut14;
+    static jmethodID jPutChar;
+    static jmethodID jPutChar1;
+    static jmethodID jPutDouble;
+    static jmethodID jPutDouble1;
+    static jmethodID jPutFloat;
+    static jmethodID jPutFloat1;
+    static jmethodID jPutInt;
+    static jmethodID jPutInt1;
+    static jmethodID jPutLong;
+    static jmethodID jPutLong1;
+    static jmethodID jPutShort;
+    static jmethodID jPutShort1;
+    static jmethodID jSlice;
+    static jmethodID jToString;
+    static jmethodID jWrap;
+    static jmethodID jWrap1;
+    static jfieldID jBigEndian;
+    static jfieldID jHb;
+    static jfieldID jIsReadOnly;
+    static jfieldID jNativeByteOrder;
+    static jfieldID jOffset;
+};
+
+class BufferInfo : public AutoGlobalWrappedJavaObject {
+public:
+    static void InitStubs(JNIEnv *jEnv);
+    static BufferInfo* Wrap(jobject obj);
+    BufferInfo(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {};
+    BufferInfo();
+    void Set(int32_t a0, int32_t a1, int64_t a2, int32_t a3);
+    int32_t getFlags();
+    void setFlags(int32_t a0);
+    int32_t getOffset();
+    void setOffset(int32_t a0);
+    int64_t getPresentationTimeUs();
+    void setPresentationTimeUs(int64_t a0);
+    int32_t getSize();
+    void setSize(int32_t a0);
+protected:
+    static jclass mBufferInfoClass;
+    static jmethodID jBufferInfo;
+    static jmethodID jSet;
+    static jfieldID jFlags;
+    static jfieldID jOffset;
+    static jfieldID jPresentationTimeUs;
+    static jfieldID jSize;
+};
+
+} /* android */
+} /* widget */
+} /* mozilla */
+#endif
--- a/widget/android/moz.build
+++ b/widget/android/moz.build
@@ -10,27 +10,29 @@ XPIDL_SOURCES += [
 
 XPIDL_MODULE = 'widget_android'
 
 EXPORTS += [
     'AndroidBridge.h',
     'AndroidJavaWrappers.h',
     'AndroidJNIWrapper.h',
     'GeneratedJNIWrappers.h',
+    'GeneratedSDKWrappers.h',
 ]
 
 SOURCES += [
     'AndroidBridge.cpp',
     'AndroidDirectTexture.cpp',
     'AndroidGraphicBuffer.cpp',
     'AndroidJavaWrappers.cpp',
     'AndroidJNI.cpp',
     'AndroidJNIWrapper.cpp',
     'APZCCallbackHandler.cpp',
     'GeneratedJNIWrappers.cpp',
+    'GeneratedSDKWrappers.cpp',
     'GfxInfo.cpp',
     'NativeJSContainer.cpp',
     'nsAndroidProtocolHandler.cpp',
     'nsAppShell.cpp',
     'nsClipboard.cpp',
     'nsDeviceContextAndroid.cpp',
     'nsIdleServiceAndroid.cpp',
     'nsIMEPicker.cpp',
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -2425,17 +2425,37 @@ nsChildView::UpdateTitlebarCGContext()
 
     if ([context isFlipped] != [view isFlipped]) {
       CGContextTranslateCTM(ctx, 0, viewFrame.size.height);
       CGContextScaleCTM(ctx, 1, -1);
     }
 
     [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:[view isFlipped]]];
 
-    [cell drawWithFrame:[button bounds] inView:button];
+    if ([window useBrightTitlebarForeground] && !nsCocoaFeatures::OnYosemiteOrLater() &&
+        view == [window standardWindowButton:NSWindowFullScreenButton]) {
+      // Make the fullscreen button visible on dark titlebar backgrounds by
+      // drawing it into a new transparency layer and turning it white.
+      CGRect r = NSRectToCGRect([view bounds]);
+      CGContextBeginTransparencyLayerWithRect(ctx, r, nullptr);
+
+      // Draw twice for double opacity.
+      [cell drawWithFrame:[button bounds] inView:button];
+      [cell drawWithFrame:[button bounds] inView:button];
+
+      // Make it white.
+      CGContextSetBlendMode(ctx, kCGBlendModeSourceIn);
+      CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
+      CGContextFillRect(ctx, r);
+      CGContextSetBlendMode(ctx, kCGBlendModeNormal);
+
+      CGContextEndTransparencyLayer(ctx);
+    } else {
+      [cell drawWithFrame:[button bounds] inView:button];
+    }
 
     [NSGraphicsContext setCurrentContext:context];
     CGContextRestoreGState(ctx);
   }
 
   CGContextRestoreGState(ctx);
 
   DrawTitlebarHighlight([frameView bounds].size, [(ChildView*)mView cornerRadius],
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -74,16 +74,17 @@ typedef struct _nsCocoaWindowList {
   // is ridiculously slow, so we cache it in the toplevel window for all
   // descendants to use.
   float mDPI;
 
   NSTrackingArea* mTrackingArea;
 
   BOOL mBeingShown;
   BOOL mDrawTitle;
+  BOOL mBrightTitlebarForeground;
 }
 
 - (void)importState:(NSDictionary*)aState;
 - (NSMutableDictionary*)exportState;
 - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState;
 - (BOOL)drawsContentsIntoWindowFrame;
 - (void)setTitlebarColor:(NSColor*)aColor forActiveWindow:(BOOL)aActive;
 - (NSColor*)titlebarColorForActiveWindow:(BOOL)aActive;
@@ -104,16 +105,19 @@ typedef struct _nsCocoaWindowList {
 
 - (ChildView*)mainChildView;
 
 - (NSArray*)titlebarControls;
 
 - (void)setWantsTitleDrawn:(BOOL)aDrawTitle;
 - (BOOL)wantsTitleDrawn;
 
+- (void)setUseBrightTitlebarForeground:(BOOL)aBrightForeground;
+- (BOOL)useBrightTitlebarForeground;
+
 - (void)disableSetNeedsDisplay;
 - (void)enableSetNeedsDisplay;
 
 @end
 
 @interface NSWindow (Undocumented)
 
 // If a window has been explicitly removed from the "window cache" (to
@@ -297,16 +301,17 @@ public:
     virtual bool HasPendingInputEvent();
     virtual nsTransparencyMode GetTransparencyMode();
     virtual void SetTransparencyMode(nsTransparencyMode aMode);
     NS_IMETHOD SetWindowShadowStyle(int32_t aStyle);
     virtual void SetShowsToolbarButton(bool aShow);
     virtual void SetShowsFullScreenButton(bool aShow);
     virtual void SetWindowAnimationType(WindowAnimationType aType);
     virtual void SetDrawsTitle(bool aDrawTitle);
+    virtual void SetUseBrightTitlebarForeground(bool aBrightForeground) MOZ_OVERRIDE;
     NS_IMETHOD SetNonClientMargins(nsIntMargin &margins);
     NS_IMETHOD SetWindowTitlebarColor(nscolor aColor, bool aActive);
     virtual void SetDrawsInTitlebar(bool aState);
     virtual nsresult SynthesizeNativeMouseEvent(nsIntPoint aPoint,
                                                 uint32_t aNativeMessage,
                                                 uint32_t aModifierFlags);
 
     void DispatchSizeModeEvent();
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -1995,16 +1995,26 @@ nsCocoaWindow::SetDrawsTitle(bool aDrawT
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   [mWindow setWantsTitleDrawn:aDrawTitle];
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
+void
+nsCocoaWindow::SetUseBrightTitlebarForeground(bool aBrightForeground)
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+  [mWindow setUseBrightTitlebarForeground:aBrightForeground];
+
+  NS_OBJC_END_TRY_ABORT_BLOCK;
+}
+
 NS_IMETHODIMP nsCocoaWindow::SetNonClientMargins(nsIntMargin &margins)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
   SetDrawsInTitlebar(margins.top == 0);
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
@@ -2627,16 +2637,17 @@ static NSMutableSet *gSwizzledFrameViewC
   mActiveTitlebarColor = nil;
   mInactiveTitlebarColor = nil;
   mScheduledShadowInvalidation = NO;
   mDisabledNeedsDisplay = NO;
   mDPI = GetDPI(self);
   mTrackingArea = nil;
   mBeingShown = NO;
   mDrawTitle = NO;
+  mBrightTitlebarForeground = NO;
   [self updateTrackingArea];
 
   return self;
 }
 
 - (void)setBeingShown:(BOOL)aValue
 {
   mBeingShown = aValue;
@@ -2725,16 +2736,27 @@ static const NSString* kStateShowsToolba
   mDrawTitle = aDrawTitle;
 }
 
 - (BOOL)wantsTitleDrawn
 {
   return mDrawTitle;
 }
 
+- (void)setUseBrightTitlebarForeground:(BOOL)aBrightForeground
+{
+  mBrightTitlebarForeground = aBrightForeground;
+  [[self standardWindowButton:NSWindowFullScreenButton] setNeedsDisplay:YES];
+}
+
+- (BOOL)useBrightTitlebarForeground
+{
+  return mBrightTitlebarForeground;
+}
+
 // Pass nil here to get the default appearance.
 - (void)setTitlebarColor:(NSColor*)aColor forActiveWindow:(BOOL)aActive
 {
   [aColor retain];
   if (aActive) {
     [mActiveTitlebarColor release];
     mActiveTitlebarColor = aColor;
   } else {
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -94,18 +94,18 @@ typedef void* nsNativeWidget;
 #ifdef XP_WIN
 #define NS_NATIVE_TSF_THREAD_MGR       100
 #define NS_NATIVE_TSF_CATEGORY_MGR     101
 #define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
 #define NS_NATIVE_ICOREWINDOW          103 // winrt specific
 #endif
 
 #define NS_IWIDGET_IID \
-{ 0x5b27abd6, 0x9e53, 0x4a0a, \
-  { 0x86, 0xf, 0x77, 0x5c, 0xc5, 0x69, 0x35, 0xf } };
+{ 0xcfe7543b, 0x8c0e, 0x40c3, \
+  { 0x9a, 0x6d, 0x77, 0x6e, 0x84, 0x8a, 0x7c, 0xfc } };
 
 /*
  * Window shadow styles
  * Also used for the -moz-window-shadow CSS property
  */
 
 #define NS_STYLE_WINDOW_SHADOW_NONE             0
 #define NS_STYLE_WINDOW_SHADOW_DEFAULT          1
@@ -1362,16 +1362,22 @@ class nsIWidget : public nsISupports {
 
     /**
      * Specifies whether the window title should be drawn even if the window
      * contents extend into the titlebar. Ignored on windows that don't draw
      * in the titlebar. Only implemented on OS X.
      */
     virtual void SetDrawsTitle(bool aDrawTitle) {}
 
+    /**
+     * Indicates whether the widget should attempt to make titlebar controls
+     * easier to see on dark titlebar backgrounds.
+     */
+    virtual void SetUseBrightTitlebarForeground(bool aBrightForeground) {}
+
     /** 
      * Hide window chrome (borders, buttons) for this widget.
      *
      */
     NS_IMETHOD HideWindowChrome(bool aShouldHide) = 0;
 
     /**
      * Put the toplevel window into or out of fullscreen mode.
--- a/widget/windows/GfxInfo.cpp
+++ b/widget/windows/GfxInfo.cpp
@@ -1104,24 +1104,18 @@ GfxInfo::GetFeatureStatusImpl(int32_t aF
     }
 
     // Windows Server 2003 should be just like Windows XP for present purpose, but still has a different version number.
     // OTOH Windows Server 2008 R1 and R2 already have the same version numbers as Vista and Seven respectively
     if (os == DRIVER_OS_WINDOWS_SERVER_2003)
       os = DRIVER_OS_WINDOWS_XP;
 
     if (mHasDriverVersionMismatch) {
-      if (aFeature == nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS ||
-          aFeature == nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS ||
-          aFeature == nsIGfxInfo::FEATURE_DIRECT2D ||
-          aFeature == nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS)
-      {
-        *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
-        return NS_OK;
-      }
+      *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
+      return NS_OK;
     }
   }
 
   return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, &os);
 }
 
 #ifdef DEBUG
 
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -6734,23 +6734,22 @@ nsWindow::GetPreferredCompositorBackends
         mTransparencyMode == eTransparencyTransparent)) {
     if (prefs.mPreferOpenGL) {
       aHints.AppendElement(LayersBackend::LAYERS_OPENGL);
     }
 
     ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11Device();
     if (device &&
         device->GetFeatureLevel() >= D3D_FEATURE_LEVEL_10_0 &&
-        !DoesD3D11DeviceSupportResourceSharing(device)) {
+        !DoesD3D11DeviceWork(device)) {
       // bug 1083071 - bad things - fall back to basic layers
       // This should not happen aside from driver bugs, and in particular
       // should not happen on our test machines, so let's NS_ERROR to ensure
       // that we would catch it as a test failure.
-      NS_ERROR("Can't use Direct3D 11 because of a driver bug "
-        "causing resource sharing to fail");
+      NS_ERROR("Can't use Direct3D 11 because of a driver bug");
     } else {
       if (!prefs.mPreferD3D9) {
         aHints.AppendElement(LayersBackend::LAYERS_D3D11);
       }
       aHints.AppendElement(LayersBackend::LAYERS_D3D9);
     }
   }
   aHints.AppendElement(LayersBackend::LAYERS_BASIC);