Merge m-c to b2g-inbound.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 22 Apr 2014 13:08:18 -0700
changeset 180081 8db8b22698e22c2e07f7e775b84214c5193ed500
parent 180080 48ac7adee648072596540c21996092c59dc36839 (current diff)
parent 180040 1ab07aa4d004229b7537e7366c8d5ce1eea0d8be (diff)
child 180082 269f549a066e75ec6074262097e371928cbf8afa
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
milestone31.0a1
Merge m-c to b2g-inbound.
browser/devtools/inspector/test/browser_inspector_changes.js
dom/imptests/failures/html/dom/nodes/test_Document-createEvent.html.json
layout/mathml/mathfontAsanaMath.properties
layout/mathml/mathfontSTIXSize1.properties
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -658,32 +658,144 @@ pref("plugins.hide_infobar_for_outdated_
 
 pref("plugins.update.url", "https://www.mozilla.org/%LOCALE%/plugincheck/");
 pref("plugins.update.notifyUser", false);
 
 pref("plugins.click_to_play", true);
 
 pref("plugins.hideMissingPluginsNotification", false);
 
-#ifdef RELEASE_BUILD
-// For now, plugins other than Java and Flash are enabled in beta/release
-// and click-to-activate in earlier channels.
-pref("plugin.default.state", 2);
-#else
 pref("plugin.default.state", 1);
-#endif
 
 // Plugins bundled in XPIs are enabled by default.
 pref("plugin.defaultXpi.state", 2);
 
 // Flash is enabled by default, and Java is click-to-activate by default on
 // all channels.
 pref("plugin.state.flash", 2);
 pref("plugin.state.java", 1);
 
+// Whitelist Requests
+
+// Unity player, bug 979849
+#ifdef XP_WIN
+pref("plugin.state.npunity3d", 2);
+#endif
+#ifdef XP_MACOSX
+pref("plugin.state.unity web player", 2);
+#endif
+
+// Cisco Jabber SDK, bug 980133
+#ifdef XP_WIN
+pref("plugin.state.npciscowebcommunicator", 2);
+#endif
+#ifdef XP_MACOSX
+pref("plugin.state.ciscowebcommunicator", 2);
+#endif
+
+// McAfee Security Scanner detection plugin, bug 980772
+#ifdef XP_WIN
+pref("plugin.state.npmcafeemss", 2);
+#endif
+
+// Cisco VGConnect for directv.com, bug 981403
+#ifdef XP_WIN
+pref("plugin.state.npplayerplugin", 2);
+#endif
+#ifdef XP_MACOSX
+pref("plugin.state.playerplugin", 2);
+#endif
+
+// Cisco Jabber Client, bug 981905
+#ifdef XP_WIN
+pref("plugin.state.npchip", 2);
+#endif
+#ifdef XP_MACOSX
+pref("plugin.state.cisco jabber guest plug-in", 2);
+#endif
+
+// Estonian ID-card plugin, bug 982045
+#ifdef XP_WIN
+pref("plugin.state.npesteid-firefox-plugin", 2);
+#endif
+#ifdef XP_MACOSX
+pref("plugin.state.esteidfirefoxplugin", 2);
+#endif
+#ifdef UNIX_BUT_NOT_MAC
+pref("plugin.state.npesteid-firefox-plugin", 2);
+#endif
+
+// coupons.com, bug 984441
+#ifdef XP_WIN
+pref("plugin.state.npmozcouponprinter", 2);
+#endif
+#ifdef XP_MACOSX
+pref("plugin.state.couponprinter-firefox_v", 2);
+#endif
+
+// Nexus Personal BankID, bug 987056
+pref("plugin.state.npbispbrowser", 2);
+
+// Gradecam, bug 988119
+#ifdef XP_WIN
+pref("plugin.state.npgcplugin", 2);
+#endif
+#ifdef XP_MACOSX
+pref("plugin.state.gcplugin", 2);
+#endif
+
+// Smart Card Plugin, bug 988781
+#ifdef XP_WIN
+pref("plugin.state.npwebcard", 2);
+#endif
+
+// Cisco WebEx, bug 989096
+#ifdef XP_WIN
+pref("plugin.state.npatgpc", 2);
+#endif
+#ifdef XP_MACOSX
+pref("plugin.state.webex", 2);
+#endif
+#ifdef UNIX_BUT_NOT_MAC
+pref("plugin.state.npatgpc", 2);
+#endif
+
+// Skype, bug 990067
+#ifdef XP_WIN
+pref("plugin.state.npskypewebplugin", 2);
+#endif
+#ifdef XP_MACOSX
+pref("plugin.state.skypewebplugin", 2);
+#endif
+
+// Facebook video calling, bug 990068
+#ifdef XP_WIN
+pref("plugin.state.npfacebookvideocalling", 2);
+#endif
+#ifdef XP_MACOSX
+pref("plugin.state.facebookvideocalling", 2);
+#endif
+
+// MS Office Lync plugin, bug 990069
+#ifdef XP_WIN
+pref("plugin.state.npmeetingjoinpluginoc", 2);
+#endif
+#ifdef XP_MACOSX
+pref("plugin.state.lwaplugin", 2);
+#endif
+
+// VidyoWeb, bug 990286
+#ifdef XP_WIN
+pref("plugin.state.npvidyoweb", 2);
+#endif
+#ifdef XP_MACOSX
+pref("plugin.state.npvidyoweb", 2);
+pref("plugin.state.vidyoweb", 2);
+#endif
+
 // display door hanger if flash not installed
 pref("plugins.notifyMissingFlash", true);
 
 #ifdef XP_WIN
 pref("browser.preferences.instantApply", false);
 #else
 pref("browser.preferences.instantApply", true);
 #endif
@@ -1281,17 +1393,17 @@ pref("devtools.hud.loglimit.console", 20
 pref("devtools.eyedropper.zoom", 6);
 
 // The developer tools editor configuration:
 // - tabsize: how many spaces to use when a Tab character is displayed.
 // - expandtab: expand Tab characters to spaces.
 // - keymap: which keymap to use (can be 'default', 'emacs' or 'vim')
 // - autoclosebrackets: whether to permit automatic bracket/quote closing.
 // - detectindentation: whether to detect the indentation from the file
-pref("devtools.editor.tabsize", 4);
+pref("devtools.editor.tabsize", 2);
 pref("devtools.editor.expandtab", true);
 pref("devtools.editor.keymap", "default");
 pref("devtools.editor.autoclosebrackets", true);
 pref("devtools.editor.detectindentation", true);
 
 // Enable the Font Inspector
 pref("devtools.fontinspector.enabled", true);
 
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -117,46 +117,35 @@ tabbrowser {
 }
 
 .tabbrowser-tab:not([pinned]):not([fadein]) {
   max-width: 0.1px;
   min-width: 0.1px;
   visibility: hidden;
 }
 
-.tab-background,
 .tab-close-button,
-.tab-label {
+.tab-background {
   /* Explicitly set the visibility to override the value (collapsed)
    * we inherit from #TabsToolbar[collapsed] upon opening a browser window. */
   visibility: visible;
 }
 
+.tab-close-button[fadein],
 .tab-background[fadein] {
   /* This transition is only wanted for opening tabs. */
   transition: visibility 0ms 25ms;
 }
 
+.tab-close-button:not([fadein]),
 .tab-background:not([fadein]) {
   visibility: hidden;
 }
 
-.tab-close-button[fadein],
-.tab-label[fadein] {
-  /* This transition is only wanted for opening tabs. */
-  transition: opacity 70ms 230ms,
-              visibility 0ms 230ms;
-}
-
-.tab-close-button:not([fadein]),
-.tab-label:not([fadein]) {
-  visibility: collapse;
-  opacity: .6;
-}
-
+.tab-label:not([fadein]),
 .tab-throbber:not([fadein]),
 .tab-icon-image:not([fadein]) {
   display: none;
 }
 
 .tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab[pinned] {
   position: fixed !important;
   display: block; /* position:fixed already does this (bug 579776), but let's be explicit */
--- a/browser/components/customizableui/test/browser_968447_bookmarks_toolbar_items_in_panel.js
+++ b/browser/components/customizableui/test/browser_968447_bookmarks_toolbar_items_in_panel.js
@@ -22,11 +22,11 @@ add_task(function() {
   let newWin = yield openAndLoadWindow();
   yield newWin.PanelUI.show();
   let newWinBookmarksToolbarPlaceholder = newWin.document.getElementById(buttonId);
   ok(newWinBookmarksToolbarPlaceholder.classList.contains("toolbarbutton-1"),
      "Button in new window should have toolbarbutton-1 class");
   is(newWinBookmarksToolbarPlaceholder.getAttribute("wrap"), "true",
      "Button in new window should have 'wrap' attribute");
   yield newWin.PanelUI.hide();
-  newWin.close();
+  yield promiseWindowClosed(newWin);
   CustomizableUI.reset();
 });
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -128,17 +128,16 @@ PlacesController.prototype = {
     if (PlacesUIUtils.useAsyncTransactions) {
       switch (aCommand) {
       case "cmd_cut":
       case "placesCmd_cut":
       case "cmd_copy":
       case "cmd_paste":
       case "cmd_delete":
       case "placesCmd_delete":
-      case "placesCmd_moveBookmarks":
       case "cmd_paste":
       case "placesCmd_paste":
       case "placesCmd_new:folder":
       case "placesCmd_new:bookmark":
       case "placesCmd_createBookmark":
         return false;
       }
     }
--- a/browser/components/places/content/moveBookmarks.js
+++ b/browser/components/places/content/moveBookmarks.js
@@ -18,37 +18,48 @@ var gMoveBookmarksDialog = {
     this._nodes = window.arguments[0];
 
     this.foldersTree.place =
       "place:excludeItems=1&excludeQueries=1&excludeReadOnlyFolders=1&folder=" +
       PlacesUIUtils.allBookmarksFolderId;
   },
 
   onOK: function MBD_onOK(aEvent) {
-    var selectedNode = this.foldersTree.selectedNode;
-    NS_ASSERT(selectedNode,
-              "selectedNode must be set in a single-selection tree with initial selection set");
-    var selectedFolderID = PlacesUtils.getConcreteItemId(selectedNode);
+    let selectedNode = this.foldersTree.selectedNode;
+    let selectedFolderId = PlacesUtils.getConcreteItemId(selectedNode);
+
+    if (!PlacesUIUtils.useAsyncTransactions) {
+      let transactions = [];
+      for (var i=0; i < this._nodes.length; i++) {
+        // Nothing to do if the node is already under the selected folder
+        if (this._nodes[i].parent.itemId == selectedFolderId)
+          continue;
 
-    var transactions = [];
-    for (var i=0; i < this._nodes.length; i++) {
-      // Nothing to do if the node is already under the selected folder
-      if (this._nodes[i].parent.itemId == selectedFolderID)
-        continue;
-
-      let txn = new PlacesMoveItemTransaction(this._nodes[i].itemId,
-                                              selectedFolderID,
-                                              PlacesUtils.bookmarks.DEFAULT_INDEX);
-      transactions.push(txn);
+        let txn = new PlacesMoveItemTransaction(this._nodes[i].itemId,
+                                                selectedFolderId,
+                                                PlacesUtils.bookmarks.DEFAULT_INDEX);
+        transactions.push(txn);
+      }
+      if (transactions.length != 0) {
+        let txn = new PlacesAggregatedTransaction("Move Items", transactions);
+        PlacesUtils.transactionManager.doTransaction(txn);
+      }
+      return;
     }
 
-    if (transactions.length != 0) {
-      let txn = new PlacesAggregatedTransaction("Move Items", transactions);
-      PlacesUtils.transactionManager.doTransaction(txn);
-    }
+    PlacesTransactions.transact(function* () {
+      let newParentGUID = yield PlacesUtils.promiseItemGUID(selectedFolderId);
+      for (let node of this._nodes) {
+        // Nothing to do if the node is already under the selected folder.
+        if (node.parent.itemId == selectedFolderId)
+          continue;
+        yield PlacesTransactions.MoveItem({ GUID: node.bookmarkGuid
+                                          , newParentGUID: newParentGUID });
+      }
+    }.bind(this)).then(null, Components.utils.reportError);
   },
 
   newFolder: function MBD_newFolder() {
     // The command is disabled when the tree is not focused
     this.foldersTree.focus();
     goDoCommand("placesCmd_new:folder");
   }
 };
--- a/browser/devtools/debugger/test/browser_dbg_auto-pretty-print-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_auto-pretty-print-01.js
@@ -47,17 +47,17 @@ function test(){
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + DevToolsUtils.safeErrorString(aError));
       })
   });
 }
 
 function testSourceIsUgly() {
-  ok(!gEditor.getText().contains("\n    "),
+  ok(!gEditor.getText().contains("\n  "),
     "The source shouldn't be pretty printed yet.");
 }
 
 function testSecondSourceLabel(){
   ok(gSources.containsValue(EXAMPLE_URL + gSecondSourceLabel),
     "Second source url is correct.");
 }
 
@@ -88,17 +88,17 @@ function enableAutoPrettyPrint(){
 function testAutoPrettyPrintOff(){
   is(gPrefs.autoPrettyPrint, false,
     "The auto-pretty-print pref should be off.");
   isnot(gOptions._autoPrettyPrint.getAttribute("checked"), "true",
        "The Auto pretty print menu item should not be checked.");
 }
 
 function testSourceIsPretty() {
-  ok(gEditor.getText().contains("\n    "),
+  ok(gEditor.getText().contains("\n  "),
     "The source should be pretty printed.")
 }
 
 registerCleanupFunction(function() {
   gTab = null;
   gDebuggee = null;
   gPanel = null;
   gDebugger = null;
--- a/browser/devtools/debugger/test/browser_dbg_auto-pretty-print-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_auto-pretty-print-02.js
@@ -58,17 +58,17 @@ function test(){
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + DevToolsUtils.safeErrorString(aError));
       })
   });
 }
 
 function testSourceIsUgly() {
-  ok(!gEditor.getText().contains("\n    "),
+  ok(!gEditor.getText().contains("\n  "),
     "The source shouldn't be pretty printed yet.");
 }
 
 function testFirstSourceLabel(){
   ok(gSources.containsValue(EXAMPLE_URL + gFirstSourceLabel),
     "First source url is correct.");
 }
 
@@ -91,17 +91,17 @@ function testPrettyPrintButtonOn(){
 
 function disableAutoPrettyPrint(){
   gOptions._autoPrettyPrint.setAttribute("checked", "false");
   gOptions._toggleAutoPrettyPrint();
   gOptions._onPopupHidden();
 }
 
 function testSourceIsPretty() {
-  ok(gEditor.getText().contains("\n    "),
+  ok(gEditor.getText().contains("\n  "),
     "The source should be pretty printed.")
 }
 
 registerCleanupFunction(function() {
   gTab = null;
   gDebuggee = null;
   gPanel = null;
   gDebugger = null;
--- a/browser/devtools/debugger/test/browser_dbg_pretty-print-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-01.js
@@ -33,45 +33,45 @@ function test() {
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + DevToolsUtils.safeErrorString(aError));
       });
   });
 }
 
 function testSourceIsUgly() {
-  ok(!gEditor.getText().contains("\n    "),
+  ok(!gEditor.getText().contains("\n  "),
      "The source shouldn't be pretty printed yet.");
 }
 
 function clickPrettyPrintButton() {
   gDebugger.document.getElementById("pretty-print").click();
 }
 
 function testProgressBarShown() {
   const deck = gDebugger.document.getElementById("editor-deck");
   is(deck.selectedIndex, 2, "The progress bar should be shown");
 }
 
 function testSourceIsPretty() {
-  ok(gEditor.getText().contains("\n    "),
+  ok(gEditor.getText().contains("\n  "),
      "The source should be pretty printed.")
 }
 
 function testEditorShown() {
   const deck = gDebugger.document.getElementById("editor-deck");
   is(deck.selectedIndex, 0, "The editor should be shown");
 }
 
 function testSourceIsStillPretty() {
   const deferred = promise.defer();
 
   const { source } = gSources.selectedItem.attachment;
   gDebugger.DebuggerController.SourceScripts.getText(source).then(([, text]) => {
-    ok(text.contains("\n    "),
+    ok(text.contains("\n  "),
        "Subsequent calls to getText return the pretty printed source.");
     deferred.resolve();
   });
 
   return deferred.promise;
 }
 
 registerCleanupFunction(function() {
--- a/browser/devtools/debugger/test/browser_dbg_pretty-print-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-02.js
@@ -38,17 +38,17 @@ function selectContextMenuItem() {
   once(gContextMenu, "popupshown").then(() => {
     const menuItem = gDebugger.document.getElementById("se-dbg-cMenu-prettyPrint");
     menuItem.click();
   });
   gContextMenu.openPopup(gEditor.container, "overlap", 0, 0, true, false);
 }
 
 function testSourceIsPretty() {
-  ok(gEditor.getText().contains("\n    "),
+  ok(gEditor.getText().contains("\n  "),
      "The source should be pretty printed.")
 }
 
 registerCleanupFunction(function() {
   gTab = null;
   gDebuggee = null;
   gPanel = null;
   gDebugger = null;
--- a/browser/devtools/debugger/test/browser_dbg_pretty-print-11.js
+++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-11.js
@@ -32,26 +32,26 @@ function test() {
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + DevToolsUtils.safeErrorString(aError));
       });
   });
 }
 
 function testSourceIsUgly() {
-  ok(!gEditor.getText().contains("\n    "),
+  ok(!gEditor.getText().contains("\n  "),
      "The source shouldn't be pretty printed yet.");
 }
 
 function clickPrettyPrintButton() {
   gDebugger.document.getElementById("pretty-print").click();
 }
 
 function testSourceIsPretty() {
-  ok(gEditor.getText().contains("\n    "),
+  ok(gEditor.getText().contains("\n  "),
      "The source should be pretty printed.")
 }
 
 registerCleanupFunction(function() {
   gTab = null;
   gDebuggee = null;
   gPanel = null;
   gDebugger = null;
--- a/browser/devtools/debugger/test/browser_dbg_pretty-print-13.js
+++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-13.js
@@ -36,45 +36,45 @@ function test() {
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + DevToolsUtils.safeErrorString(aError));
       });
   });
 }
 
 function testSourceIsUgly() {
-  ok(!gEditor.getText().contains("\n    "),
+  ok(!gEditor.getText().contains("\n  "),
      "The source shouldn't be pretty printed yet.");
 }
 
 function clickPrettyPrintButton() {
   gDebugger.document.getElementById("pretty-print").click();
 }
 
 function testProgressBarShown() {
   const deck = gDebugger.document.getElementById("editor-deck");
   is(deck.selectedIndex, 2, "The progress bar should be shown");
 }
 
 function testSourceIsPretty() {
-  ok(gEditor.getText().contains("\n    "),
+  ok(gEditor.getText().contains("\n  "),
      "The source should be pretty printed.")
 }
 
 function testEditorShown() {
   const deck = gDebugger.document.getElementById("editor-deck");
   is(deck.selectedIndex, 0, "The editor should be shown");
 }
 
 function testSourceIsStillPretty() {
   const deferred = promise.defer();
 
   const { source } = gSources.selectedItem.attachment;
   gDebugger.DebuggerController.SourceScripts.getText(source).then(([, text]) => {
-    ok(text.contains("\n    "),
+    ok(text.contains("\n  "),
        "Subsequent calls to getText return the pretty printed source.");
     deferred.resolve();
   });
 
   return deferred.promise;
 }
 
 registerCleanupFunction(function() {
--- a/browser/devtools/inspector/test/browser.ini
+++ b/browser/devtools/inspector/test/browser.ini
@@ -23,17 +23,16 @@ support-files =
 [browser_inspector_bug_674871.js]
 [browser_inspector_bug_699308_iframe_navigation.js]
 [browser_inspector_bug_817558_delete_node.js]
 [browser_inspector_bug_831693_combinator_suggestions.js]
 [browser_inspector_bug_831693_input_suggestion.js]
 # [browser_inspector_bug_831693_searchbox_panel_navigation.js]
 # Disabled for too many intermittent failures (bug 851349)
 [browser_inspector_bug_840156_destroy_after_navigation.js]
-[browser_inspector_changes.js]
 [browser_inspector_cmd_inspect.js]
 [browser_inspector_dead_node_exception.js]
 [browser_inspector_destroyselection.js]
 [browser_inspector_highlighter.js]
 [browser_inspector_iframeTest.js]
 [browser_inspector_infobar.js]
 [browser_inspector_initialization.js]
 [browser_inspector_invalidate.js]
deleted file mode 100644
--- a/browser/devtools/inspector/test/browser_inspector_changes.js
+++ /dev/null
@@ -1,156 +0,0 @@
-/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-let doc;
-let testDiv;
-
-function test() {
-  let inspector;
-
-  function createDocument()
-  {
-    doc.body.innerHTML = '<div id="testdiv">Test div!</div>';
-    doc.title = "Inspector Change Test";
-    openInspector(runInspectorTests);
-  }
-
-  function getInspectorRuleProp(aName)
-  {
-    let ruleview = inspector.sidebar.getWindowForTab("ruleview").ruleview.view;
-    let inlineStyles = ruleview._elementStyle.rules[0];
-
-    for (let key in inlineStyles.textProps) {
-      let prop = inlineStyles.textProps[key];
-      if (prop.name == aName) {
-        return prop;
-      }
-    }
-    return null;
-  }
-
-  function runInspectorTests(aInspector)
-  {
-    inspector = aInspector;
-
-    waitForView("computedview", () => {
-      info("Computed View ready");
-      inspector.sidebar.select("computedview");
-
-      testDiv = doc.getElementById("testdiv");
-
-      testDiv.style.fontSize = "10px";
-
-      // Start up the style inspector panel...
-      inspector.once("computed-view-refreshed", () => {
-        executeSoon(computedStylePanelTests);
-      });
-      inspector.selection.setNode(testDiv);
-    });
-  }
-
-  function computedStylePanelTests()
-  {
-    let computedview = inspector.sidebar.getWindowForTab("computedview").computedview;
-    ok(computedview, "Style Panel has a cssHtmlTree");
-
-    let fontSize = getComputedPropertyValue("font-size");
-    is(fontSize, "10px", "Style inspector should be showing the correct font size.");
-
-    testDiv.style.cssText = "font-size: 15px; color: red;";
-
-    // Wait until layout-change fires from mutation to skip earlier refresh event
-    inspector.once("layout-change", () => {
-      inspector.once("computed-view-refreshed", () => {
-        executeSoon(computedStylePanelAfterChange);
-      });
-    });
-  }
-
-  function computedStylePanelAfterChange()
-  {
-    let fontSize = getComputedPropertyValue("font-size");
-    is(fontSize, "15px", "Style inspector should be showing the new font size.");
-
-    let color = getComputedPropertyValue("color");
-    is(color, "#F00", "Style inspector should be showing the new color.");
-
-    computedStylePanelNotActive();
-  }
-
-  function computedStylePanelNotActive()
-  {
-    // Tests changes made while the style panel is not active.
-    inspector.sidebar.select("ruleview");
-
-    testDiv.style.cssText = "font-size: 20px; color: blue; text-align: center";
-
-    inspector.once("computed-view-refreshed", () => {
-      executeSoon(computedStylePanelAfterSwitch);
-    });
-  }
-
-  function computedStylePanelAfterSwitch()
-  {
-    let fontSize = getComputedPropertyValue("font-size");
-    is(fontSize, "20px", "Style inspector should be showing the new font size.");
-
-    let color = getComputedPropertyValue("color");
-    is(color, "#00F", "Style inspector should be showing the new color.");
-
-    let textAlign = getComputedPropertyValue("text-align");
-    is(textAlign, "center", "Style inspector should be showing the new text align.");
-
-    rulePanelTests();
-  }
-
-  function rulePanelTests()
-  {
-    inspector.sidebar.select("ruleview");
-    let ruleview = inspector.sidebar.getWindowForTab("ruleview").ruleview;
-    ok(ruleview, "Style Panel has a ruleview");
-
-    let propView = getInspectorRuleProp("text-align");
-    is(propView.value, "center", "Style inspector should be showing the new text align.");
-
-    testDiv.style.cssText = "font-size: 3em; color: lightgoldenrodyellow; text-align: right; text-transform: uppercase";
-
-    inspector.once("rule-view-refreshed", () => {
-      executeSoon(rulePanelAfterChange);
-    });
-  }
-
-  function rulePanelAfterChange()
-  {
-    let propView = getInspectorRuleProp("text-align");
-    is(propView.value, "right", "Style inspector should be showing the new text align.");
-
-    let propView = getInspectorRuleProp("color");
-    is(propView.value, "lightgoldenrodyellow", "Style inspector should be showing the new color.")
-
-    let propView = getInspectorRuleProp("font-size");
-    is(propView.value, "3em", "Style inspector should be showing the new font size.");
-
-    let propView = getInspectorRuleProp("text-transform");
-    is(propView.value, "uppercase", "Style inspector should be showing the new text transform.");
-
-    finishTest();
-  }
-
-  function finishTest()
-  {
-    gBrowser.removeCurrentTab();
-    finish();
-  }
-
-  waitForExplicitFinish();
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    doc = content.document;
-    waitForFocus(createDocument, content);
-  }, true);
-
-  content.location = "data:text/html;charset=utf-8,browser_inspector_changes.js";
-}
--- a/browser/devtools/sourceeditor/autocomplete.js
+++ b/browser/devtools/sourceeditor/autocomplete.js
@@ -164,17 +164,35 @@ function onEditorKeypress({ ed, Editor }
 
   // Do not try to autocomplete with multiple selections.
   if (ed.hasMultipleSelections()) {
     private.doNotAutocomplete = true;
     private.popup.hidePopup();
     return;
   }
 
+  if ((event.ctrlKey || event.metaKey) && event.keyCode == event.DOM_VK_SPACE) {
+    // When Ctrl/Cmd + Space is pressed, two simultaneous keypresses are emitted
+    // first one for just the Ctrl/Cmd and second one for combo. The first one
+    // leave the private.doNotAutocomplete as true, so we have to make it false
+    private.doNotAutocomplete = false;
+    return;
+  }
+
+  if (event.ctrlKey || event.metaKey || event.altKey) {
+    private.doNotAutocomplete = true;
+    private.popup.hidePopup();
+    return;
+  }
+
   switch (event.keyCode) {
+    case event.DOM_VK_RETURN:
+      private.doNotAutocomplete = true;
+      break;
+
     case event.DOM_VK_ESCAPE:
       if (private.popup.isOpen)
         event.preventDefault();
     case event.DOM_VK_LEFT:
     case event.DOM_VK_RIGHT:
     case event.DOM_VK_HOME:
     case event.DOM_VK_END:
       private.doNotAutocomplete = true;
--- a/browser/devtools/sourceeditor/test/browser_detectindent.js
+++ b/browser/devtools/sourceeditor/test/browser_detectindent.js
@@ -57,34 +57,34 @@ const TABS_CODE = [
 "}"
 ].join("\n");
 
 
 function test() {
   waitForExplicitFinish();
 
   setup((ed, win) => {
-    is(ed.getOption("indentUnit"), 4,
-       "4 spaces before code added");
+    is(ed.getOption("indentUnit"), 2,
+       "2 spaces before code added");
     is(ed.getOption("indentWithTabs"), false,
        "spaces is default");
 
+    ed.setText(FOUR_SPACES_CODE);
+    is(ed.getOption("indentUnit"), 4,
+       "4 spaces detected in 4 space code");
+    is(ed.getOption("indentWithTabs"), false,
+       "spaces detected in 4 space code");
+
     ed.setText(TWO_SPACES_CODE);
     is(ed.getOption("indentUnit"), 2,
        "2 spaces detected in 2 space code");
     is(ed.getOption("indentWithTabs"), false,
        "spaces detected in 2 space code");
 
-    ed.setText(FOUR_SPACES_CODE);
-    is(ed.getOption("indentUnit"), 4,
-       "4 spaces detected in 4 space code");
-    is(ed.getOption("indentWithTabs"), false,
-       "spaces detected in 4 space code");
-
     ed.setText(TABS_CODE);
-    is(ed.getOption("indentUnit"), 4,
-       "4 space indentation unit");
+    is(ed.getOption("indentUnit"), 2,
+       "2 space indentation unit");
     is(ed.getOption("indentWithTabs"), true,
        "tabs detected in majority tabs code");
 
     teardown(ed, win);
   });
 }
--- a/browser/devtools/styleinspector/test/browser.ini
+++ b/browser/devtools/styleinspector/test/browser.ini
@@ -26,16 +26,18 @@ support-files =
 [browser_computedview_keybindings_01.js]
 [browser_computedview_keybindings_02.js]
 [browser_computedview_matched-selectors-toggle.js]
 [browser_computedview_matched-selectors_01.js]
 [browser_computedview_matched-selectors_02.js]
 [browser_computedview_media-queries.js]
 [browser_computedview_no-results-placeholder.js]
 [browser_computedview_original-source-link.js]
+[browser_computedview_refresh-on-style-change_01.js]
+[browser_computedview_refresh-on-style-change_02.js]
 [browser_computedview_search-filter.js]
 [browser_computedview_select-and-copy-styles.js]
 [browser_computedview_style-editor-link.js]
 [browser_ruleview_add-property-and-reselect.js]
 [browser_ruleview_add-property-cancel_01.js]
 [browser_ruleview_add-property-cancel_02.js]
 [browser_ruleview_add-property-cancel_03.js]
 [browser_ruleview_add-property_01.js]
@@ -72,16 +74,17 @@ skip-if = os == "win" && debug # bug 963
 [browser_ruleview_multiple-properties-unfinished_02.js]
 [browser_ruleview_multiple_properties_01.js]
 [browser_ruleview_multiple_properties_02.js]
 [browser_ruleview_original-source-link.js]
 [browser_ruleview_override.js]
 [browser_ruleview_pseudo-element.js]
 [browser_ruleview_refresh-on-attribute-change_01.js]
 [browser_ruleview_refresh-on-attribute-change_02.js]
+[browser_ruleview_refresh-on-style-change.js]
 [browser_ruleview_select-and-copy-styles.js]
 [browser_ruleview_style-editor-link.js]
 [browser_ruleview_urls-clickable.js]
 [browser_ruleview_user-property-reset.js]
 [browser_styleinspector_csslogic-content-stylesheets.js]
 [browser_styleinspector_csslogic-inherited-properties.js]
 [browser_styleinspector_csslogic-specificity.js]
 [browser_styleinspector_inplace-editor.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_computedview_refresh-on-style-change_01.js
@@ -0,0 +1,35 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the computed view refreshes when the current node has its style
+// changed
+
+const TESTCASE_URI = 'data:text/html;charset=utf-8,' +
+                     '<div id="testdiv" style="font-size:10px;">Test div!</div>';
+
+let test = asyncTest(function*() {
+  yield addTab(TESTCASE_URI);
+
+  info("Getting the test node");
+  let div = getNode("#testdiv");
+
+  info("Opening the computed view and selecting the test node");
+  let {toolbox, inspector, view} = yield openComputedView();
+  yield selectNode(div, inspector);
+
+  let fontSize = getComputedViewPropertyValue(view, "font-size");
+  is(fontSize, "10px", "The computed view shows the right font-size");
+
+  info("Changing the node's style and waiting for the update");
+  let onUpdated = inspector.once("computed-view-refreshed");
+  div.style.cssText = "font-size: 15px; color: red;";
+  yield onUpdated;
+
+  fontSize = getComputedViewPropertyValue(view, "font-size");
+  is(fontSize, "15px", "The computed view shows the updated font-size");
+  let color = getComputedViewPropertyValue(view, "color");
+  is(color, "#F00", "The computed view also shows the color now");
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_computedview_refresh-on-style-change_02.js
@@ -0,0 +1,40 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the computed view refreshes when the current node has its style
+// changed, even if the view is not the active one
+
+const TESTCASE_URI = 'data:text/html;charset=utf-8,' +
+                     '<div id="testdiv" style="font-size:10px;">Test div!</div>';
+
+let test = asyncTest(function*() {
+  yield addTab(TESTCASE_URI);
+
+  info("Getting the test node");
+  let div = getNode("#testdiv");
+
+  info("Opening the computed view and selecting the test node");
+  let {toolbox, inspector, view} = yield openComputedView();
+  yield selectNode(div, inspector);
+
+  let fontSize = getComputedViewPropertyValue(view, "font-size");
+  is(fontSize, "10px", "The computed view shows the right font-size");
+
+  info("Now switching to the rule view");
+  yield openRuleView();
+
+  info("Changing the node's style and waiting for the update");
+  let onUpdated = inspector.once("computed-view-refreshed");
+  div.style.cssText = "font-size: 20px; color: blue; text-align: center";
+  yield onUpdated;
+
+  fontSize = getComputedViewPropertyValue(view, "font-size");
+  is(fontSize, "20px", "The computed view shows the updated font-size");
+  let color = getComputedViewPropertyValue(view, "color");
+  is(color, "#00F", "The computed view also shows the color now");
+  let textAlign = getComputedViewPropertyValue(view, "text-align");
+  is(textAlign, "center", "The computed view also shows the text-align now");
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_ruleview_refresh-on-style-change.js
@@ -0,0 +1,41 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the rule view refreshes when the current node has its style
+// changed
+
+const TESTCASE_URI = 'data:text/html;charset=utf-8,' +
+                     '<div id="testdiv" style="font-size:10px;">Test div!</div>';
+
+let test = asyncTest(function*() {
+  yield addTab(TESTCASE_URI);
+
+  Services.prefs.setCharPref("devtools.defaultColorUnit", "name");
+
+  info("Getting the test node");
+  let div = getNode("#testdiv");
+
+  info("Opening the rule view and selecting the test node");
+  let {toolbox, inspector, view} = yield openRuleView();
+  yield selectNode(div, inspector);
+
+  let fontSize = getRuleViewPropertyValue(view, "element", "font-size");
+  is(fontSize, "10px", "The rule view shows the right font-size");
+
+  info("Changing the node's style and waiting for the update");
+  let onUpdated = inspector.once("rule-view-refreshed");
+  div.style.cssText = "font-size: 3em; color: lightgoldenrodyellow; text-align: right; text-transform: uppercase";
+  yield onUpdated;
+
+  let textAlign = getRuleViewPropertyValue(view, "element", "text-align");
+  is(textAlign, "right", "The rule view shows the new text align.");
+  let color = getRuleViewPropertyValue(view, "element", "color");
+  is(color, "lightgoldenrodyellow", "The rule view shows the new color.")
+  let fontSize = getRuleViewPropertyValue(view, "element", "font-size");
+  is(fontSize, "3em", "The rule view shows the new font size.");
+  let textTransform = getRuleViewPropertyValue(view, "element", "text-transform");
+  is(textTransform, "uppercase", "The rule view shows the new text transform.");
+});
--- a/browser/devtools/styleinspector/test/head.js
+++ b/browser/devtools/styleinspector/test/head.js
@@ -29,19 +29,24 @@ registerCleanupFunction(() => {
   } catch (ex) {
     dump(ex);
   }
   while (gBrowser.tabs.length > 1) {
     gBrowser.removeCurrentTab();
   }
 });
 
+// Uncomment to log events
 // Services.prefs.setBoolPref("devtools.dump.emit", true);
+
+// Clean-up all prefs that might have been changed during a test run
+// (safer here because if the test fails, then the pref is never reverted)
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("devtools.dump.emit");
+  Services.prefs.clearUserPref("devtools.defaultColorUnit");
 });
 
 /**
  * The functions found below are here to ease test development and maintenance.
  * Most of these functions are stateless and will require some form of context
  * (the instance of the current toolbox, or inspector panel for instance).
  *
  * Most of these functions are async too and return promises.
@@ -472,17 +477,17 @@ function hasSideBarTab(inspector, id) {
  * @param {CssRuleView} view The instance of the rule-view panel
  * @param {String} selectorText The selector in the rule-view for which the rule
  * object is wanted
  * @return {DOMNode}
  */
 function getRuleViewRule(view, selectorText) {
   let rule;
   for (let r of view.doc.querySelectorAll(".ruleview-rule")) {
-    let selector = r.querySelector(".ruleview-selector-matched");
+    let selector = r.querySelector(".ruleview-selector, .ruleview-selector-matched");
     if (selector && selector.textContent === selectorText) {
       rule = r;
       break;
     }
   }
 
   return rule;
 }
@@ -511,16 +516,30 @@ function getRuleViewProperty(view, selec
         break;
       }
     }
   }
   return prop;
 }
 
 /**
+ * Get the text value of the property corresponding to a given selector and name
+ * in the rule-view
+ * @param {CssRuleView} view The instance of the rule-view panel
+ * @param {String} selectorText The selector in the rule-view to look for the
+ * property in
+ * @param {String} propertyName The name of the property
+ * @return {String} The property value
+ */
+function getRuleViewPropertyValue(view, selectorText, propertyName) {
+  return getRuleViewProperty(view, selectorText, propertyName)
+    .valueSpan.textContent;
+}
+
+/**
  * Simulate a color change in a given color picker tooltip, and optionally wait
  * for a given element in the page to have its style changed as a result
  * @param {SwatchColorPickerTooltip} colorPicker
  * @param {Array} newRgba The new color to be set [r, g, b, a]
  * @param {Object} expectedChange Optional object that needs the following props:
  *                 - {DOMNode} element The element in the page that will have its
  *                   style changed.
  *                 - {String} name The style name that will be changed
@@ -651,16 +670,28 @@ function getComputedViewProperty(view, n
       prop = {nameSpan: nameSpan, valueSpan: valueSpan};
       break;
     }
   }
   return prop;
 }
 
 /**
+ * Get the text value of the property corresponding to a given name in the
+ * computed-view
+ * @param {CssHtmlTree} view The instance of the computed view panel
+ * @param {String} name The name of the property to retrieve
+ * @return {String} The property value
+ */
+function getComputedViewPropertyValue(view, selectorText, propertyName) {
+  return getComputedViewProperty(view, selectorText, propertyName)
+    .valueSpan.textContent;
+}
+
+/**
  * Expand a given property, given its index in the current property list of
  * the computed view
  * @param {CssHtmlTree} view The instance of the computed view panel
  * @param {InspectorPanel} inspector The instance of the inspector panel
  * @param {Number} index The index of the property to be expanded
  * @return a promise that resolves when the property has been expanded, or
  * rejects if the property was not found
  */
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -46,25 +46,28 @@
   background-color: -moz-Dialog;
 }
 
 #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar) {
   padding-top: 1px;
   padding-bottom: 1px;
 }
 
+#TabsToolbar:not([collapsed="true"]) + #nav-bar {
+  margin-top: -@tabToolbarNavbarOverlap@; /* Move up into the TabsToolbar */
+  /* Position the toolbar above the bottom of background tabs */
+  position: relative;
+  z-index: 1;
+}
+
 #nav-bar {
   background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
   box-shadow: 0 1px 0 @toolbarHighlight@ inset;
-  margin-top: -@tabToolbarNavbarOverlap@; /* Move up into the TabsToolbar */
   padding-top: 2px;
   padding-bottom: 2px;
-  /* Position the toolbar above the bottom of background tabs */
-  position: relative;
-  z-index: 1;
 }
 
 #nav-bar-overflow-button {
   -moz-image-region: rect(-5px, 12px, 11px, -4px);
 }
 
 /* This only has an effect when this element is placed on the bookmarks toolbar.
  * It's 30px to make sure buttons with 18px icons fit along with the default 16px
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -104,35 +104,38 @@ toolbarseparator {
   min-height: 22px;
 }
 
 #navigator-toolbox > toolbar:not(#TabsToolbar):not(#nav-bar):not(:-moz-lwtheme) {
   -moz-appearance: none;
   background: url(chrome://browser/skin/Toolbar-background-noise.png) hsl(0,0%,83%);
 }
 
+#TabsToolbar:not([collapsed="true"]) + #nav-bar {
+  margin-top: -@tabToolbarNavbarOverlap@; /* Move up into the TabsToolbar */
+  /* Position the toolbar above the bottom of background tabs */
+  position: relative;
+  z-index: 1;
+}
+
 #nav-bar {
   -moz-appearance: none;
   background: url(chrome://browser/skin/Toolbar-background-noise.png),
               linear-gradient(hsl(0,0%,93%), hsl(0,0%,83%));
   background-clip: border-box;
   background-origin: border-box !important;
 
   /* Move the noise texture out of the top 1px strip because that overlaps
      with the tabbar and we don't want to repaint it when animating tabs.
      The noise image is at least 100px high, so repeating it only horizontally
      is enough. */
   background-repeat: repeat-x, no-repeat;
   background-position: 0 1px, 0 0;
 
   box-shadow: inset 0 1px 0 hsla(0,0%,100%,.4);
-  margin-top: -@tabToolbarNavbarOverlap@;
-  /* Position the toolbar above the bottom of background tabs */
-  position: relative;
-  z-index: 1;
 }
 
 @media (min-resolution: 2dppx) {
   #nav-bar {
     background-size: 100px 100px, auto;
   }
 }
 
--- a/browser/themes/osx/customizableui/panelUIOverlay.css
+++ b/browser/themes/osx/customizableui/panelUIOverlay.css
@@ -94,16 +94,20 @@
 .subviewbutton {
   -moz-padding-start: 18px;
 }
 
 .subviewbutton[checked="true"] {
   background-position: top 5px left 4px;
 }
 
+.subviewbutton[checked="true"]:-moz-locale-dir(rtl) {
+  background-position: top 5px right 4px;
+}
+
 .subviewbutton:not(:-moz-any([image],[targetURI],.cui-withicon, .bookmark-item)) > .menu-iconic-left {
   display: none;
 }
 
 menu.subviewbutton,
 menuitem.subviewbutton:not(.panel-subview-footer) {
   padding-top: 2px;
   padding-bottom: 2px;
--- a/browser/themes/shared/customizableui/panelUIOverlay.inc.css
+++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css
@@ -1063,16 +1063,20 @@ toolbaritem[overflowedItem=true],
   background-size: 1px 18px;
   box-shadow: 0 0 0 1px hsla(0,0%,100%,.2);
 }
 
 .subviewbutton[checked="true"] {
   background: url("chrome://global/skin/menu/shared-menu-check.png") center left 7px / 11px 11px no-repeat transparent;
 }
 
+.subviewbutton[checked="true"]:-moz-locale-dir(rtl) {
+  background-position: center right 7px;
+}
+
 .subviewbutton > .menu-iconic-left {
   -moz-appearance: none;
   -moz-margin-end: 3px;
 }
 
 menuitem[checked="true"].subviewbutton > .menu-iconic-left {
   visibility: hidden;
 }
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -278,25 +278,28 @@
     background-image: linear-gradient(to bottom,
         rgb(207, 214, 188) 0, rgb(207, 214, 188) 1px,
         rgb(224, 226, 200) 1px, rgb(224, 226, 200) 2px,
         rgb(214, 216, 190) 2px, rgb(214, 216, 190) 3px,
         transparent 3px);
   }
 }
 
-#nav-bar {
-  background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
-  box-shadow: 0 1px 0 @toolbarHighlight@ inset;
+#TabsToolbar:not([collapsed="true"]) + #nav-bar {
   margin-top: -@tabToolbarNavbarOverlap@; /* Move up into the TabsToolbar */
   /* Position the toolbar above the bottom of background tabs */
   position: relative;
   z-index: 1;
 }
 
+#nav-bar {
+  background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
+  box-shadow: 0 1px 0 @toolbarHighlight@ inset;
+}
+
 #personal-bookmarks {
   min-height: 24px;
 }
 
 #print-preview-toolbar:not(:-moz-lwtheme) {
   -moz-appearance: toolbox;
 }
 
--- a/build/gyp.mozbuild
+++ b/build/gyp.mozbuild
@@ -30,16 +30,17 @@ gyp_vars = {
     # saves 4MB when webrtc_trace is off
     'enable_lazy_trace_alloc': 1,
 
      # turn off mandatory use of NEON and instead use NEON detection
     'arm_neon': 0,
     'arm_neon_optional': 1,
 
     'moz_widget_toolkit_gonk': 0,
+    'moz_omx_encoder': 0,
 
     # (for vp8) chromium sets to 0 also
     'use_temporal_layers': 0,
     # Creates AEC internal sample dump files in current directory
     # 'aec_debug_dump': 1,
 
     # codec enable/disables:
     'include_g711': 1,
@@ -56,16 +57,18 @@ if os == 'WINNT':
     gyp_vars.update(
         MSVS_VERSION=CONFIG['_MSVS_VERSION'],
         MSVS_OS_BITS=64 if CONFIG['HAVE_64BIT_OS'] else 32,
     )
 elif os == 'Android':
     if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
         gyp_vars['build_with_gonk'] = 1
         gyp_vars['moz_widget_toolkit_gonk'] = 1
+        if CONFIG['MOZ_OMX_ENCODER']:
+          gyp_vars['moz_omx_encoder'] = 1
     else:
         gyp_vars.update(
             gtest_target_type='executable',
             android_toolchain=CONFIG['ANDROID_TOOLCHAIN'],
         )
 
 flavors = {
     'WINNT': 'win',
--- a/config/system-headers
+++ b/config/system-headers
@@ -1098,23 +1098,25 @@ pixman.h
 shareuiinterface.h
 #endif
 #if MOZ_NATIVE_LIBVPX==1
 vpx/vpx_codec.h
 vpx/vpx_decoder.h
 vpx/vpx_encoder.h
 vpx/vp8cx.h
 vpx/vp8dx.h
+vpx_mem/vpx_mem.h
 #endif
 #ifdef GKMEDIAS_SHARED_LIBRARY
 vpx/vpx_codec.h
 vpx/vpx_decoder.h
 vpx/vpx_encoder.h
 vpx/vp8cx.h
 vpx/vp8dx.h
+vpx_mem/vpx_mem.h
 vorbis/codec.h
 theora/theoradec.h
 tremor/ivorbiscodec.h
 ogg/ogg.h
 ogg/os_types.h
 nestegg/nestegg.h
 cubeb/cubeb.h
 #endif
--- a/configure.in
+++ b/configure.in
@@ -5392,31 +5392,43 @@ MOZ_LIBVPX_CFLAGS=
 MOZ_LIBVPX_LIBS=
 
 if test -n "$MOZ_VPX"; then
     AC_DEFINE(MOZ_VPX)
     if test -n "$MOZ_VPX_ERROR_CONCEALMENT" ; then
         AC_DEFINE(MOZ_VPX_ERROR_CONCEALMENT)
     fi
 
+    _SAVE_CFLAGS=$CFLAGS
+    _SAVE_LIBS=$LIBS
     if test -n "$MOZ_NATIVE_LIBVPX"; then
         dnl ============================
         dnl === libvpx Version check ===
         dnl ============================
         dnl Check to see if we have a system libvpx package.
         PKG_CHECK_MODULES(MOZ_LIBVPX, vpx >= 1.3.0)
 
+        CFLAGS="$CFLAGS $MOZ_LIBVPX_CFLAGS"
+        LIBS="$LIBS $MOZ_LIBVPX_LIBS"
+
         MOZ_CHECK_HEADER([vpx/vpx_decoder.h], [],
          [AC_MSG_ERROR([Couldn't find vpx/vpx_decoder.h which is required for build with system libvpx. Use --without-system-libvpx to build with in-tree libvpx.])])
 
-        _SAVE_LIBS=$LIBS
         AC_CHECK_LIB(vpx, vpx_codec_dec_init_ver, [],
          [AC_MSG_ERROR([--with-system-libvpx requested but symbol vpx_codec_dec_init_ver not found])])
-        LIBS=$_SAVE_LIBS
-    fi
+
+        MOZ_CHECK_HEADER([vpx_mem/vpx_mem.h],
+         [AC_CHECK_FUNC(vpx_mem_set_functions)])
+        if test "$ac_cv_header_vpx_mem_vpx_mem_h" = no -o \
+                "$ac_cv_func_vpx_mem_set_functions" = no; then
+            AC_DEFINE(MOZ_VPX_NO_MEM_REPORTING)
+        fi
+    fi
+    CFLAGS=$_SAVE_CFLAGS
+    LIBS=$_SAVE_LIBS
 fi
 
 AC_SUBST(MOZ_NATIVE_LIBVPX)
 AC_SUBST(MOZ_LIBVPX_CFLAGS)
 AC_SUBST(MOZ_LIBVPX_LIBS)
 
 if test "$MOZ_WEBM"; then
     if test "$MOZ_SAMPLE_TYPE_FLOAT32"; then
--- a/content/base/public/nsIAttribute.h
+++ b/content/base/public/nsIAttribute.h
@@ -7,18 +7,18 @@
 #define nsIAttribute_h___
 
 #include "nsINode.h"
 
 class nsDOMAttributeMap;
 class nsIContent;
 
 #define NS_IATTRIBUTE_IID  \
-{ 0x8d9d7dbf, 0xc42d, 0x4715, \
-  { 0x95, 0xcf, 0x7a, 0x5e, 0xd5, 0xa4, 0x47, 0x70 } }
+{ 0x233a9c4d, 0xb27f, 0x4662, \
+    { 0xbd, 0x90, 0xba, 0xd6, 0x2e, 0x76, 0xc8, 0xe1 } }
 
 class nsIAttribute : public nsINode
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IATTRIBUTE_IID)
 
   virtual void SetMap(nsDOMAttributeMap *aMap) = 0;
   
@@ -27,18 +27,16 @@ public:
     return mAttrMap;
   }
 
   nsINodeInfo *NodeInfo() const
   {
     return mNodeInfo;
   }
 
-  virtual nsIContent* GetContent() const = 0;
-
   /**
    * Called when our ownerElement is moved into a new document.
    * Updates the nodeinfo of this node.
    */
   virtual nsresult SetOwnerDocument(nsIDocument* aDocument) = 0;
 
 protected:
 #ifdef MOZILLA_INTERNAL_API
--- a/content/base/src/Attr.cpp
+++ b/content/base/src/Attr.cpp
@@ -73,17 +73,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Attr)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Attr)
   nsINode::Unlink(tmp);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAttrMap)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(Attr)
-  Element* ownerElement = tmp->GetContentInternal();
+  Element* ownerElement = tmp->GetElement();
   if (tmp->IsBlack()) {
     if (ownerElement) {
       // The attribute owns the element via attribute map so we can
       // mark it when the attribute is certainly alive.
       mozilla::dom::FragmentOrElement::MarkNodeChildren(ownerElement);
     }
     return true;
   }
@@ -124,20 +124,24 @@ Attr::SetMap(nsDOMAttributeMap *aMap)
     // We're breaking a relationship with content and not getting a new one,
     // need to locally cache value. GetValue() does that.
     GetValue(mValue);
   }
 
   mAttrMap = aMap;
 }
 
-nsIContent*
-Attr::GetContent() const
+Element*
+Attr::GetElement() const
 {
-  return GetContentInternal();
+  if (!mAttrMap) {
+    return nullptr;
+  }
+  nsIContent* content = mAttrMap->GetContent();
+  return content ? content->AsElement() : nullptr;
 }
 
 nsresult
 Attr::SetOwnerDocument(nsIDocument* aDocument)
 {
   NS_ASSERTION(aDocument, "Missing document");
 
   nsIDocument *doc = OwnerDoc();
@@ -177,39 +181,39 @@ Attr::GetNameAtom(nsIContent* aContent)
   }
   nsCOMPtr<nsIAtom> nameAtom = mNodeInfo->NameAtom();
   return nameAtom.forget();
 }
 
 NS_IMETHODIMP
 Attr::GetValue(nsAString& aValue)
 {
-  nsIContent* content = GetContentInternal();
-  if (content) {
-    nsCOMPtr<nsIAtom> nameAtom = GetNameAtom(content);
-    content->GetAttr(mNodeInfo->NamespaceID(), nameAtom, aValue);
+  Element* element = GetElement();
+  if (element) {
+    nsCOMPtr<nsIAtom> nameAtom = GetNameAtom(element);
+    element->GetAttr(mNodeInfo->NamespaceID(), nameAtom, aValue);
   }
   else {
     aValue = mValue;
   }
 
   return NS_OK;
 }
 
 void
 Attr::SetValue(const nsAString& aValue, ErrorResult& aRv)
 {
-  nsIContent* content = GetContentInternal();
-  if (!content) {
+  Element* element = GetElement();
+  if (!element) {
     mValue = aValue;
     return;
   }
 
-  nsCOMPtr<nsIAtom> nameAtom = GetNameAtom(content);
-  aRv = content->SetAttr(mNodeInfo->NamespaceID(),
+  nsCOMPtr<nsIAtom> nameAtom = GetNameAtom(element);
+  aRv = element->SetAttr(mNodeInfo->NamespaceID(),
                          nameAtom,
                          mNodeInfo->GetPrefixAtom(),
                          aValue,
                          true);
 }
 
 NS_IMETHODIMP
 Attr::SetValue(const nsAString& aValue)
@@ -233,28 +237,28 @@ Attr::GetSpecified(bool* aSpecified)
   *aSpecified = Specified();
   return NS_OK;
 }
 
 Element*
 Attr::GetOwnerElement(ErrorResult& aRv)
 {
   OwnerDoc()->WarnOnceAbout(nsIDocument::eOwnerElement);
-  return GetContentInternal();
+  return GetElement();
 }
 
 NS_IMETHODIMP
 Attr::GetOwnerElement(nsIDOMElement** aOwnerElement)
 {
   NS_ENSURE_ARG_POINTER(aOwnerElement);
   OwnerDoc()->WarnOnceAbout(nsIDocument::eOwnerElement);
 
-  nsIContent* content = GetContentInternal();
-  if (content) {
-    return CallQueryInterface(content, aOwnerElement);
+  Element* element = GetElement();
+  if (element) {
+    return CallQueryInterface(element, aOwnerElement);
   }
 
   *aOwnerElement = nullptr;
 
   return NS_OK;
 }
 
 void
@@ -288,17 +292,17 @@ Attr::Clone(nsINodeInfo *aNodeInfo, nsIN
   NS_ADDREF(*aResult);
 
   return NS_OK;
 }
 
 already_AddRefed<nsIURI>
 Attr::GetBaseURI(bool aTryUseXHRDocBaseURI) const
 {
-  nsINode *parent = GetContentInternal();
+  Element* parent = GetElement();
 
   return parent ? parent->GetBaseURI(aTryUseXHRDocBaseURI) : nullptr;
 }
 
 void
 Attr::GetTextContentInternal(nsAString& aTextContent)
 {
   OwnerDoc()->WarnOnceAbout(nsIDocument::eTextContent);
@@ -313,26 +317,24 @@ Attr::SetTextContentInternal(const nsASt
   OwnerDoc()->WarnOnceAbout(nsIDocument::eTextContent);
 
   SetNodeValueInternal(aTextContent, aError);
 }
 
 NS_IMETHODIMP
 Attr::GetIsId(bool* aReturn)
 {
-  nsIContent* content = GetContentInternal();
-  if (!content)
-  {
+  Element* element = GetElement();
+  if (!element) {
     *aReturn = false;
     return NS_OK;
   }
 
-  nsIAtom* idAtom = content->GetIDAttributeName();
-  if (!idAtom)
-  {
+  nsIAtom* idAtom = element->GetIDAttributeName();
+  if (!idAtom) {
     *aReturn = false;
     return NS_OK;
   }
 
   *aReturn = mNodeInfo->Equals(idAtom, kNameSpaceID_None);
   return NS_OK;
 }
 
@@ -399,16 +401,10 @@ Attr::Shutdown()
 }
 
 JSObject*
 Attr::WrapObject(JSContext* aCx)
 {
   return AttrBinding::Wrap(aCx, this);
 }
 
-Element*
-Attr::GetContentInternal() const
-{
-  return mAttrMap ? mAttrMap->GetContent() : nullptr;
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/content/base/src/Attr.h
+++ b/content/base/src/Attr.h
@@ -51,17 +51,17 @@ public:
 
   // nsIDOMAttr interface
   NS_DECL_NSIDOMATTR
 
   virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
 
   // nsIAttribute interface
   void SetMap(nsDOMAttributeMap *aMap) MOZ_OVERRIDE;
-  nsIContent *GetContent() const MOZ_OVERRIDE;
+  Element* GetElement() const;
   nsresult SetOwnerDocument(nsIDocument* aDocument) MOZ_OVERRIDE;
 
   // nsINode interface
   virtual bool IsNodeOfType(uint32_t aFlags) const MOZ_OVERRIDE;
   virtual uint32_t GetChildCount() const MOZ_OVERRIDE;
   virtual nsIContent *GetChildAt(uint32_t aIndex) const MOZ_OVERRIDE;
   virtual nsIContent * const * GetChildArray(uint32_t* aChildCount) const MOZ_OVERRIDE;
   virtual int32_t IndexOf(const nsINode* aPossibleChild) const MOZ_OVERRIDE;
@@ -93,24 +93,23 @@ public:
   // XPCOM GetPrefix() is OK
   // XPCOM GetLocalName() is OK
 
   Element* GetOwnerElement(ErrorResult& aRv);
 
 protected:
   virtual Element* GetNameSpaceElement()
   {
-    return GetContentInternal();
+    return GetElement();
   }
 
   static bool sInitialized;
 
 private:
   already_AddRefed<nsIAtom> GetNameAtom(nsIContent* aContent);
-  Element* GetContentInternal() const;
 
   nsString mValue;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_Attr_h */
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -122,16 +122,17 @@
 #include "mozilla/Telemetry.h"
 
 #include "mozilla/CORSMode.h"
 #include "mozilla/dom/ShadowRoot.h"
 
 #include "nsStyledElement.h"
 #include "nsXBLService.h"
 #include "nsITextControlElement.h"
+#include "nsITextControlFrame.h"
 #include "nsISupportsImpl.h"
 #include "mozilla/dom/DocumentFragment.h"
 #include "mozilla/IntegerPrintfMacros.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMETHODIMP
@@ -196,17 +197,38 @@ Element::UpdateState(bool aNotify)
 
 void
 nsIContent::UpdateEditableState(bool aNotify)
 {
   // Guaranteed to be non-element content
   NS_ASSERTION(!IsElement(), "What happened here?");
   nsIContent *parent = GetParent();
 
-  SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
+  // Skip over unknown native anonymous content to avoid setting a flag we
+  // can't clear later
+  bool isUnknownNativeAnon = false;
+  if (IsInNativeAnonymousSubtree()) {
+    isUnknownNativeAnon = true;
+    nsCOMPtr<nsIContent> root = this;
+    while (root && !root->IsRootOfNativeAnonymousSubtree()) {
+      root = root->GetParent();
+    }
+    // root should always be true here, but isn't -- bug 999416
+    if (root) {
+      nsIFrame* rootFrame = root->GetPrimaryFrame();
+      if (rootFrame) {
+        nsIFrame* parentFrame = rootFrame->GetParent();
+        nsITextControlFrame* textCtrl = do_QueryFrame(parentFrame);
+        isUnknownNativeAnon = !textCtrl;
+      }
+    }
+  }
+
+  SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE) &&
+                  !isUnknownNativeAnon);
 }
 
 void
 Element::UpdateEditableState(bool aNotify)
 {
   nsIContent *parent = GetParent();
 
   SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -7745,17 +7745,23 @@ nsIDocument::CreateEvent(const nsAString
     presContext = shell->GetPresContext();
   }
 
   // Create event even without presContext.
   nsCOMPtr<nsIDOMEvent> ev;
   rv = EventDispatcher::CreateEvent(const_cast<nsIDocument*>(this),
                                     presContext, nullptr, aEventType,
                                     getter_AddRefs(ev));
-  return ev ? dont_AddRef(ev.forget().take()->InternalDOMEvent()) : nullptr;
+  if (!ev) {
+    return nullptr;
+  }
+  WidgetEvent* e = ev->GetInternalNSEvent();
+  e->mFlags.mBubbles = false;
+  e->mFlags.mCancelable = false;
+  return dont_AddRef(ev.forget().take()->InternalDOMEvent());
 }
 
 void
 nsDocument::FlushPendingNotifications(mozFlushType aType)
 {
   nsDocumentOnStack dos(this);
 
   // We need to flush the sink for non-HTML documents (because the XML
--- a/content/base/src/nsINode.cpp
+++ b/content/base/src/nsINode.cpp
@@ -804,30 +804,30 @@ nsINode::CompareDocumentPosition(nsINode
     return static_cast<uint16_t>(nsIDOMNode::DOCUMENT_POSITION_FOLLOWING);
   }
 
   nsAutoTArray<const nsINode*, 32> parents1, parents2;
 
   const nsINode *node1 = &aOtherNode, *node2 = this;
 
   // Check if either node is an attribute
-  const nsIAttribute* attr1 = nullptr;
+  const Attr* attr1 = nullptr;
   if (node1->IsNodeOfType(nsINode::eATTRIBUTE)) {
-    attr1 = static_cast<const nsIAttribute*>(node1);
-    const nsIContent* elem = attr1->GetContent();
+    attr1 = static_cast<const Attr*>(node1);
+    const Element* elem = attr1->GetElement();
     // If there is an owner element add the attribute
     // to the chain and walk up to the element
     if (elem) {
       node1 = elem;
       parents1.AppendElement(attr1);
     }
   }
   if (node2->IsNodeOfType(nsINode::eATTRIBUTE)) {
-    const nsIAttribute* attr2 = static_cast<const nsIAttribute*>(node2);
-    const nsIContent* elem = attr2->GetContent();
+    const Attr* attr2 = static_cast<const Attr*>(node2);
+    const Element* elem = attr2->GetElement();
     if (elem == node1 && attr1) {
       // Both nodes are attributes on the same element.
       // Compare position between the attributes.
 
       uint32_t i;
       const nsAttrName* attrName;
       for (i = 0; (attrName = elem->GetAttrNameAt(i)); ++i) {
         if (attrName->Equals(attr1->NodeInfo())) {
--- a/content/media/omx/OMXCodecDescriptorUtil.cpp
+++ b/content/media/omx/OMXCodecDescriptorUtil.cpp
@@ -2,36 +2,44 @@
 /* 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 "OMXCodecDescriptorUtil.h"
 
 namespace android {
 
-// NAL unit start code.
-static const uint8_t kNALUnitStartCode[] = { 0x00, 0x00, 0x00, 0x01 };
-
-// This class is used to generate AVC/H.264 decoder config descriptor blob from
-// the sequence parameter set(SPS) + picture parameter set(PPS) data.
+// The utility functions in this file concatenate two AVC/H.264 parameter sets,
+// sequence parameter set(SPS) and picture parameter set(PPS), into byte stream
+// format or construct AVC decoder config descriptor blob from them.
+//
+// * NAL unit defined in ISO/IEC 14496-10 7.3.1
+// * SPS defined ISO/IEC 14496-10 7.3.2.1.1
+// * PPS defined in ISO/IEC 14496-10 7.3.2.2
 //
-// SPS + PPS format:
-// --- SPS NAL unit ---
-//   Start code <0x00 0x00 0x00 0x01>  (4 bytes)
-//   NAL unit type <0x07>              (5 bits)
-//   SPS                               (1+ bytes)
+// Byte stream format:
+// Start code <0x00 0x00 0x00 0x01>  (4 bytes)
+// --- (SPS) NAL unit ---
+//   ...                             (3 bits)
+//   NAL unit type <0x07>            (5 bits)
+//   SPS                             (3+ bytes)
+//     Profile                         (1 byte)
+//     Compatible profiles             (1 byte)
+//     Level                           (1 byte)
 //   ...
-// --- PPS NAL unit ---
-//   Start code <0x00 0x00 0x00 0x01>  (4 bytes)
-//   NAL unit type <0x08>              (5 bits)
-//   PPS                               (1+ bytes)
+// --- End ---
+// Start code <0x00 0x00 0x00 0x01>  (4 bytes)
+// --- (PPS) NAL unit ---
+//   ...                             (3 bits)
+//   NAL unit type <0x08>            (5 bits)
+//   PPS                             (1+ bytes)
 //   ...
 // --- End ---
 //
-// Descriptor format:
+// Descriptor format: (defined in ISO/IEC 14496-15 5.2.4.1.1)
 // --- Header (5 bytes) ---
 //   Version <0x01>       (1 byte)
 //   Profile              (1 byte)
 //   Compatible profiles  (1 byte)
 //   Level                (1 byte)
 //   Reserved <111111>    (6 bits)
 //   NAL length type      (2 bits)
 // --- Parameter sets ---
@@ -42,232 +50,156 @@ static const uint8_t kNALUnitStartCode[]
 //     SPS NAL unit         (1+ bytes)
 //   ...
 //   Number of PPS        (1 byte)
 //   PPS                  (3+ bytes)
 //     Length               (2 bytes)
 //     PPS NAL unit         (1+ bytes)
 //   ...
 // --- End ---
-class AVCDecodeConfigDescMaker {
-public:
-  // Convert SPS + PPS data to decoder config descriptor blob. aParamSets
-  // contains the source data, and the generated blob will be appended to
-  // aOutputBuf.
-  status_t ConvertParamSetsToDescriptorBlob(ABuffer* aParamSets,
-                                            nsTArray<uint8_t>* aOutputBuf)
-  {
-    uint8_t header[] = {
-      0x01, // Version.
-      0x00, // Will be filled with 'profile' when parsing SPS later.
-      0x00, // Will be filled with 'compatible profiles' when parsing SPS later.
-      0x00, // Will be filled with 'level' when parsing SPS later.
-      0xFF, // 6 bits reserved value <111111> + 2 bits NAL length type <11>
-    };
+
+// NAL unit start code.
+static const uint8_t kNALUnitStartCode[] = { 0x00, 0x00, 0x00, 0x01 };
 
-    size_t paramSetsSize = ParseParamSets(aParamSets, header);
-    NS_ENSURE_TRUE(paramSetsSize > 0, ERROR_MALFORMED);
+// NAL unit types.
+enum {
+  kNALUnitTypeSPS = 0x07,   // Value for sequence parameter set.
+  kNALUnitTypePPS = 0x08,   // Value for picture parameter set.
+  kNALUnitTypeBad = -1,     // Malformed data.
+};
 
-    // Extra 1 byte for number of SPS & the other for number of PPS.
-    aOutputBuf->SetCapacity(sizeof(header) + paramSetsSize + 2);
-    // 5 bytes Header.
-    aOutputBuf->AppendElements(header, sizeof(header));
-    // 3 bits <111> + 5 bits number of SPS.
-    uint8_t n = mSPS.Length();
-    aOutputBuf->AppendElement(0xE0 | n);
-    // SPS NAL units.
-    for (int i = 0; i < n; i++) {
-      mSPS.ElementAt(i).AppendTo(aOutputBuf);
-    }
-    // 1 byte number of PPS.
-    n = mPPS.Length();
-    aOutputBuf->AppendElement(n);
-    // PPS NAL units.
-    for (int i = 0; i < n; i++) {
-      mPPS.ElementAt(i).AppendTo(aOutputBuf);
-    }
+// Sequence parameter set or picture parameter set.
+struct AVCParamSet {
+  AVCParamSet(const uint8_t* aPtr, const size_t aSize)
+    : mPtr(aPtr)
+    , mSize(aSize)
+  {
+    MOZ_ASSERT(mPtr && mSize > 0);
+  }
 
-    return OK;
+  size_t Size() {
+    return mSize + 2; // 2 more bytes for length value.
   }
 
-private:
-  // Sequence parameter set or picture parameter set.
-  struct AVCParamSet {
-    AVCParamSet(const uint8_t* aPtr, const size_t aSize)
-      : mPtr(aPtr)
-      , mSize(aSize)
-    {}
+  // Append 2 bytes length value and NAL unit bitstream to aOutputBuf.
+  void AppendTo(nsTArray<uint8_t>* aOutputBuf)
+  {
+    // 2 bytes length value.
+    uint8_t size[] = {
+      (mSize & 0xFF00) >> 8, // MSB.
+      mSize & 0x00FF,        // LSB.
+    };
+    aOutputBuf->AppendElements(size, sizeof(size));
 
-    // Append 2 bytes length value and NAL unit bitstream to aOutputBuf.
-    void AppendTo(nsTArray<uint8_t>* aOutputBuf)
-    {
-      MOZ_ASSERT(mPtr && mSize > 0);
+    aOutputBuf->AppendElements(mPtr, mSize);
+  }
+
+  const uint8_t* mPtr; // Pointer to NAL unit.
+  const size_t mSize;  // NAL unit length in bytes.
+};
 
-      // 2 bytes length value.
-      uint8_t size[] = {
-        (mSize & 0xFF00) >> 8, // MSB.
-        mSize & 0x00FF,        // LSB.
-      };
-      aOutputBuf->AppendElements(size, sizeof(size));
+// Convert SPS and PPS data into decoder config descriptor blob. The generated
+// blob will be appended to aOutputBuf.
+static status_t
+ConvertParamSetsToDescriptorBlob(sp<ABuffer>& aSPS, sp<ABuffer>& aPPS,
+                                 nsTArray<uint8_t>* aOutputBuf)
+{
+  // Strip start code in the input.
+  AVCParamSet sps(aSPS->data() + sizeof(kNALUnitStartCode),
+                  aSPS->size() - sizeof(kNALUnitStartCode));
+  AVCParamSet pps(aPPS->data() + sizeof(kNALUnitStartCode),
+                  aPPS->size() - sizeof(kNALUnitStartCode));
+  size_t paramSetsSize = sps.Size() + pps.Size();
 
-      aOutputBuf->AppendElements(mPtr, mSize);
-    }
+  // Profile/level info in SPS.
+  uint8_t* info = aSPS->data() + 5;
 
-    const uint8_t* mPtr; // Pointer to NAL unit.
-    const size_t mSize;  // NAL unit length in bytes.
-  };
-
-  // NAL unit types.
-  enum {
-    kNALUnitTypeSPS = 0x07, // Value for sequence parameter set.
-    kNALUnitTypePPS = 0x08, // Value for picture parameter set.
+  uint8_t header[] = {
+    0x01,     // Version.
+    info[0],  // Profile.
+    info[1],  // Compatible profiles.
+    info[2],  // Level.
+    0xFF,     // 6 bits reserved value <111111> + 2 bits NAL length type <11>
   };
 
-  // Search for next start code to determine the location of parameter set data
-  // and save the result to corresponding parameter set arrays. The search range
-  // is from aPtr to (aPtr + aSize - 4), and aType indicates which array to save
-  // the result.
-  // The size (in bytes) of found parameter set will be stored in
-  // aParameterSize.
-  // This function also returns the pointer to found start code that caller can
-  // use for the next iteration of search. If the returned pointer is beyond
-  // the end of search range, it means no start code is found.
-  uint8_t* ParseParamSet(uint8_t* aPtr, size_t aSize, uint8_t aType,
-                         size_t* aParamSetSize)
-  {
-    MOZ_ASSERT(aPtr && aSize > 0);
-    MOZ_ASSERT(aType == kNALUnitTypeSPS || aType == kNALUnitTypePPS);
-    MOZ_ASSERT(aParamSetSize);
-
-    // Find next start code.
-    size_t index = 0;
-    size_t end = aSize - sizeof(kNALUnitStartCode);
-    uint8_t* nextStartCode = aPtr;
-    while (index <= end &&
-            memcmp(kNALUnitStartCode, aPtr + index, sizeof(kNALUnitStartCode))) {
-      ++index;
-    }
-    if (index <= end) {
-      // Found.
-      nextStartCode = aPtr + index;
-    } else {
-      nextStartCode = aPtr + aSize;
-    }
-
-    *aParamSetSize = nextStartCode - aPtr;
-    NS_ENSURE_TRUE(*aParamSetSize > 0, nullptr);
-
-    AVCParamSet paramSet(aPtr, *aParamSetSize);
-    if (aType == kNALUnitTypeSPS) {
-      // SPS should have at least 4 bytes.
-      NS_ENSURE_TRUE(*aParamSetSize >= 4, nullptr);
-      mSPS.AppendElement(paramSet);
-    } else {
-      mPPS.AppendElement(paramSet);
-    }
-    return nextStartCode;
-  }
-
-  // Walk through SPS + PPS data and save the pointer & size of each parameter
-  // set to corresponding arrays. It also fills several values in aHeader.
-  // Will return total size of all parameter sets, or 0 if fail to parse.
-  size_t ParseParamSets(ABuffer* aParamSets, uint8_t* aHeader)
-  {
-    // Data starts with a start code.
-    // SPS and PPS are separated with start codes.
-    // Also, SPS must come before PPS
-    uint8_t type = kNALUnitTypeSPS;
-    bool hasSPS = false;
-    bool hasPPS = false;
-    uint8_t* ptr = aParamSets->data();
-    uint8_t* nextStartCode = ptr;
-    size_t remain = aParamSets->size();
-    size_t paramSetSize = 0;
-    size_t totalSize = 0;
-    // Examine
-    while (remain > sizeof(kNALUnitStartCode) &&
-            !memcmp(kNALUnitStartCode, ptr, sizeof(kNALUnitStartCode))) {
-      ptr += sizeof(kNALUnitStartCode);
-      remain -= sizeof(kNALUnitStartCode);
-      // NAL unit format is defined in ISO/IEC 14496-10 7.3.1:
-      // --- NAL unit ---
-      // Reserved <111>         (3 bits)
-      // Type                   (5 bits)
-      // Parameter set          (4+ bytes for SPS, 1+ bytes for PPS)
-      // --- End ---
-      type = (ptr[0] & 0x1F);
-      if (type == kNALUnitTypeSPS) {
-        // SPS must come before PPS.
-        NS_ENSURE_FALSE(hasPPS, 0);
-        if (!hasSPS) {
-          // SPS contains some header values.
-          aHeader[1] = ptr[1]; // Profile.
-          aHeader[2] = ptr[2]; // Compatible Profiles.
-          aHeader[3] = ptr[3]; // Level.
-
-          hasSPS = true;
-        }
-        nextStartCode = ParseParamSet(ptr, remain, type, &paramSetSize);
-      } else if (type == kNALUnitTypePPS) {
-        // SPS must come before PPS.
-        NS_ENSURE_TRUE(hasSPS, 0);
-        if (!hasPPS) {
-          hasPPS = true;
-        }
-        nextStartCode = ParseParamSet(ptr, remain, type, &paramSetSize);
-      } else {
-        // Should never contain NAL unit other than SPS or PPS.
-        NS_ENSURE_TRUE(false, 0);
-      }
-      NS_ENSURE_TRUE(nextStartCode, 0);
-
-      // Move to next start code.
-      remain -= (nextStartCode - ptr);
-      ptr = nextStartCode;
-      totalSize += (2 + paramSetSize); // 2 bytes length + NAL unit.
-    }
-
-    // Sanity check on the number of parameter sets.
-    size_t n = mSPS.Length();
-    NS_ENSURE_TRUE(n > 0 && n <= 0x1F, 0); // 5 bits length only.
-    n = mPPS.Length();
-    NS_ENSURE_TRUE(n > 0 && n <= 0xFF, 0); // 1 byte length only.
-
-    return totalSize;
-  }
-
-  nsTArray<AVCParamSet> mSPS;
-  nsTArray<AVCParamSet> mPPS;
-};
-
-// Blob from OMX encoder could be in descriptor format already, or sequence
-// parameter set(SPS) + picture parameter set(PPS). If later, it needs to be
-// parsed and converted into descriptor format.
-// See MPEG4Writer::Track::makeAVCCodecSpecificData() and
-// MPEG4Writer::Track::writeAvccBox() implementation in libstagefright.
-status_t
-GenerateAVCDescriptorBlob(ABuffer* aData, nsTArray<uint8_t>* aOutputBuf)
-{
-  const size_t csdSize = aData->size();
-  const uint8_t* csd = aData->data();
-
-  MOZ_ASSERT(csdSize > sizeof(kNALUnitStartCode),
-             "Size of codec specific data is too short. "
-             "There could be a serious problem in MediaCodec.");
-
-  NS_ENSURE_TRUE(csdSize > sizeof(kNALUnitStartCode), ERROR_MALFORMED);
-
-  if (memcmp(csd, kNALUnitStartCode, sizeof(kNALUnitStartCode))) {
-    // Already in descriptor format. It should has at least 13 bytes.
-    NS_ENSURE_TRUE(csdSize >= 13, ERROR_MALFORMED);
-
-    aOutputBuf->AppendElements(aData->data(), csdSize);
-  } else {
-    // In SPS + PPS format. Generate descriptor blob from parameters sets.
-    AVCDecodeConfigDescMaker maker;
-    status_t result = maker.ConvertParamSetsToDescriptorBlob(aData, aOutputBuf);
-    NS_ENSURE_TRUE(result == OK, result);
-  }
+  // Reserve 1 byte for number of SPS & another 1 for number of PPS.
+  aOutputBuf->SetCapacity(sizeof(header) + paramSetsSize + 2);
+  // Build the blob.
+  aOutputBuf->AppendElements(header, sizeof(header)); // 5 bytes Header.
+  aOutputBuf->AppendElement(0xE0 | 1); // 3 bits <111> + 5 bits number of SPS.
+  sps.AppendTo(aOutputBuf); // SPS NALU data.
+  aOutputBuf->AppendElement(1); // 1 byte number of PPS.
+  pps.AppendTo(aOutputBuf); // PPS NALU data.
 
   return OK;
 }
 
-} // namespace android
\ No newline at end of file
+static int
+NALType(sp<ABuffer>& aBuffer)
+{
+  if (aBuffer == nullptr) {
+    return kNALUnitTypeBad;
+  }
+  // Start code?
+  uint8_t* data = aBuffer->data();
+  if (aBuffer->size() <= 4 ||
+      memcmp(data, kNALUnitStartCode, sizeof(kNALUnitStartCode))) {
+    return kNALUnitTypeBad;
+  }
+
+  return data[4] & 0x1F;
+}
+
+// Generate AVC/H.264 decoder config blob.
+// See MPEG4Writer::Track::makeAVCCodecSpecificData() and
+// MPEG4Writer::Track::writeAvccBox() implementation in libstagefright.
+status_t
+GenerateAVCDescriptorBlob(sp<AMessage>& aConfigData,
+                          nsTArray<uint8_t>* aOutputBuf,
+                          OMXVideoEncoder::BlobFormat aFormat)
+{
+  // Search for parameter sets using key "csd-0" and "csd-1".
+  char key[6] = "csd-";
+  sp<ABuffer> sps;
+  sp<ABuffer> pps;
+  for (int i = 0; i < 2; i++) {
+    snprintf(key + 4, 2, "%d", i);
+    sp<ABuffer> paramSet;
+    bool found = aConfigData->findBuffer(key, &paramSet);
+    int type = NALType(paramSet);
+    bool valid = ((type == kNALUnitTypeSPS) || (type == kNALUnitTypePPS));
+
+    MOZ_ASSERT(found && valid);
+    if (!found || !valid) {
+      return ERROR_MALFORMED;
+    }
+
+    switch (type) {
+      case kNALUnitTypeSPS:
+        sps = paramSet;
+        break;
+      case kNALUnitTypePPS:
+        pps = paramSet;
+        break;
+      default:
+        NS_NOTREACHED("Should not get here!");
+    }
+  }
+
+  MOZ_ASSERT(sps != nullptr && pps != nullptr);
+  if (sps == nullptr || pps == nullptr) {
+    return ERROR_MALFORMED;
+  }
+
+  status_t result = OK;
+  if (aFormat == OMXVideoEncoder::BlobFormat::AVC_NAL) {
+    // SPS + PPS.
+    aOutputBuf->AppendElements(sps->data(), sps->size());
+    aOutputBuf->AppendElements(pps->data(), pps->size());
+    return OK;
+  } else {
+    status_t result = ConvertParamSetsToDescriptorBlob(sps, pps, aOutputBuf);
+    MOZ_ASSERT(result == OK);
+    return result;
+  }
+}
+
+} // namespace android
--- a/content/media/omx/OMXCodecDescriptorUtil.h
+++ b/content/media/omx/OMXCodecDescriptorUtil.h
@@ -1,23 +1,27 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef OMXCodecDescriptorUtil_h_
 #define OMXCodecDescriptorUtil_h_
 
-#include <stagefright/foundation/ABuffer.h>
+#include <stagefright/foundation/AMessage.h>
 #include <stagefright/MediaErrors.h>
 
 #include <nsTArray.h>
 
-namespace android {
+#include "OMXCodecWrapper.h"
 
-// Generate decoder config descriptor (defined in ISO/IEC 14496-15 5.2.4.1.1)
-// for AVC/H.264 using codec config blob from encoder.
-status_t GenerateAVCDescriptorBlob(ABuffer* aData,
-                                   nsTArray<uint8_t>* aOutputBuf);
+namespace android {
+// Generate decoder config blob using aConfigData provided by encoder.
+// The output will be stored in aOutputBuf.
+// aFormat specifies the output format: AVC_MP4 is for MP4 file, and AVC_NAL is
+// for RTP packet used by WebRTC.
+status_t GenerateAVCDescriptorBlob(sp<AMessage>& aConfigData,
+                                   nsTArray<uint8_t>* aOutputBuf,
+                                   OMXVideoEncoder::BlobFormat aFormat);
 
 }
 
-#endif // OMXCodecDescriptorUtil_h_
\ No newline at end of file
+#endif // OMXCodecDescriptorUtil_h_
--- a/content/media/omx/OMXCodecWrapper.cpp
+++ b/content/media/omx/OMXCodecWrapper.cpp
@@ -124,26 +124,27 @@ OMXCodecWrapper::Stop()
 
   status_t result = mCodec->stop();
   mStarted = !(result == OK);
 
   return result;
 }
 
 // Check system property to see if we're running on emulator.
-static
-bool IsRunningOnEmulator()
+static bool
+IsRunningOnEmulator()
 {
   char qemu[PROPERTY_VALUE_MAX];
   property_get("ro.kernel.qemu", qemu, "");
   return strncmp(qemu, "1", 1) == 0;
 }
 
 nsresult
-OMXVideoEncoder::Configure(int aWidth, int aHeight, int aFrameRate)
+OMXVideoEncoder::Configure(int aWidth, int aHeight, int aFrameRate,
+                           BlobFormat aBlobFormat)
 {
   MOZ_ASSERT(!mStarted, "Configure() was called already.");
 
   NS_ENSURE_TRUE(aWidth > 0 && aHeight > 0 && aFrameRate > 0,
                  NS_ERROR_INVALID_ARG);
 
   OMX_VIDEO_AVCLEVELTYPE level = OMX_VIDEO_AVCLevel3;
   OMX_VIDEO_CONTROLRATETYPE bitrateMode = OMX_Video_ControlRateConstant;
@@ -180,33 +181,33 @@ OMXVideoEncoder::Configure(int aWidth, i
   format->setInt32("frame-rate", aFrameRate);
 
   status_t result = mCodec->configure(format, nullptr, nullptr,
                                       MediaCodec::CONFIGURE_FLAG_ENCODE);
   NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
 
   mWidth = aWidth;
   mHeight = aHeight;
+  mBlobFormat = aBlobFormat;
 
   result = Start();
 
   return result == OK ? NS_OK : NS_ERROR_FAILURE;
 }
 
 // Copy pixels from planar YUV (4:4:4/4:2:2/4:2:0) or NV21 (semi-planar 4:2:0)
 // format to NV12 (semi-planar 4:2:0) format for QCOM HW encoder.
 // Planar YUV:  YYY...UUU...VVV...
 // NV21:        YYY...VUVU...
 // NV12:        YYY...UVUV...
 // For 4:4:4/4:2:2 -> 4:2:0, subsample using odd row/column without
 // interpolation.
 // aSource contains info about source image data, and the result will be stored
 // in aDestination, whose size needs to be >= Y plane size * 3 / 2.
-static
-void
+static void
 ConvertPlanarYCbCrToNV12(const PlanarYCbCrData* aSource, uint8_t* aDestination)
 {
   // Fill Y plane.
   uint8_t* y = aSource->mYChannel;
   IntSize ySize = aSource->mYSize;
 
   // Y plane.
   for (int i = 0; i < ySize.height; i++) {
@@ -247,18 +248,17 @@ ConvertPlanarYCbCrToNV12(const PlanarYCb
   }
 }
 
 // Convert pixels in graphic buffer to NV12 format. aSource is the layer image
 // containing source graphic buffer, and aDestination is the destination of
 // conversion. Currently only 2 source format are supported:
 // - NV21/HAL_PIXEL_FORMAT_YCrCb_420_SP (from camera preview window).
 // - YV12/HAL_PIXEL_FORMAT_YV12 (from video decoder).
-static
-void
+static void
 ConvertGrallocImageToNV12(GrallocImage* aSource, uint8_t* aDestination)
 {
   // Get graphic buffer.
   sp<GraphicBuffer> graphicBuffer = aSource->GetGraphicBuffer();
 
   int pixelFormat = graphicBuffer->getPixelFormat();
   // Only support NV21 (from camera) or YV12 (from HW decoder output) for now.
   NS_ENSURE_TRUE_VOID(pixelFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP ||
@@ -368,38 +368,72 @@ OMXVideoEncoder::Encode(const Image* aIm
 
   return result == OK ? NS_OK : NS_ERROR_FAILURE;
 }
 
 status_t
 OMXVideoEncoder::AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
                                      ABuffer* aData)
 {
-  // AVC/H.264 decoder config descriptor is needed to construct MP4 'avcC' box
-  // (defined in ISO/IEC 14496-15 5.2.4.1.1).
-  return GenerateAVCDescriptorBlob(aData, aOutputBuf);
+  // Codec already parsed aData. Using its result makes generating config blob
+  // much easier.
+  sp<AMessage> format;
+  mCodec->getOutputFormat(&format);
+
+  // NAL unit format is needed by WebRTC for RTP packets; AVC/H.264 decoder
+  // config descriptor is needed to construct MP4 'avcC' box.
+  status_t result = GenerateAVCDescriptorBlob(format, aOutputBuf, mBlobFormat);
+  mHasConfigBlob = (result == OK);
+
+  return result;
 }
 
 // Override to replace NAL unit start code with 4-bytes unit length.
 // See ISO/IEC 14496-15 5.2.3.
-void OMXVideoEncoder::AppendFrame(nsTArray<uint8_t>* aOutputBuf,
-                                  const uint8_t* aData, size_t aSize)
+void
+OMXVideoEncoder::AppendFrame(nsTArray<uint8_t>* aOutputBuf,
+                             const uint8_t* aData, size_t aSize)
 {
+  aOutputBuf->SetCapacity(aSize);
+
+  if (mBlobFormat == BlobFormat::AVC_NAL) {
+    // Append NAL format data without modification.
+    aOutputBuf->AppendElements(aData, aSize);
+    return;
+  }
+  // Replace start code with data length.
   uint8_t length[] = {
     (aSize >> 24) & 0xFF,
     (aSize >> 16) & 0xFF,
     (aSize >> 8) & 0xFF,
     aSize & 0xFF,
   };
-  aOutputBuf->SetCapacity(aSize);
   aOutputBuf->AppendElements(length, sizeof(length));
   aOutputBuf->AppendElements(aData + sizeof(length), aSize);
 }
 
 nsresult
+OMXVideoEncoder::GetCodecConfig(nsTArray<uint8_t>* aOutputBuf)
+{
+  MOZ_ASSERT(mHasConfigBlob, "Haven't received codec config yet.");
+
+  return AppendDecoderConfig(aOutputBuf, nullptr) == OK ? NS_OK : NS_ERROR_FAILURE;
+}
+
+nsresult
+OMXVideoEncoder::SetBitrate(int32_t aKbps)
+{
+  sp<AMessage> msg = new AMessage();
+  msg->setInt32("videoBitrate", aKbps * 1000 /* kbps -> bps */);
+  status_t result = mCodec->setParameters(msg);
+  MOZ_ASSERT(result == OK);
+  return result == OK ? NS_OK : NS_ERROR_FAILURE;
+}
+
+nsresult
 OMXAudioEncoder::Configure(int aChannels, int aInputSampleRate,
                            int aEncodedSampleRate)
 {
   MOZ_ASSERT(!mStarted);
 
   NS_ENSURE_TRUE(aChannels > 0 && aInputSampleRate > 0 && aEncodedSampleRate >= 0,
                  NS_ERROR_INVALID_ARG);
 
--- a/content/media/omx/OMXCodecWrapper.h
+++ b/content/media/omx/OMXCodecWrapper.h
@@ -112,17 +112,18 @@ protected:
    * See whether the object has been initialized successfully and is ready to
    * use.
    */
   virtual bool IsValid() { return mCodec != nullptr; }
 
   /**
    * Construct codec specific configuration blob with given data aData generated
    * by media codec and append it into aOutputBuf. Needed by MP4 container
-   * writer for generating decoder config box. Returns OK if succeed.
+   * writer for generating decoder config box, or WebRTC for generating RTP
+   * packets. Returns OK if succeed.
    */
   virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
                                        ABuffer* aData) = 0;
 
   /**
    * Append encoded frame data generated by media codec (stored in aData and
    * is aSize bytes long) into aOutputBuf. Subclasses can override this function
    * to process the data for specific container writer.
@@ -235,55 +236,82 @@ private:
   int64_t mSampleDuration;
 };
 
 /**
  * Video encoder.
  */
 class OMXVideoEncoder MOZ_FINAL : public OMXCodecWrapper
 {
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OMXVideoEncoder)
 public:
+  // Types of output blob format.
+  enum BlobFormat {
+    AVC_MP4, // MP4 file config descripter (defined in ISO/IEC 14496-15 5.2.4.1.1)
+    AVC_NAL  // NAL (Network Abstract Layer) (defined in ITU-T H.264 7.4.1)
+  };
+
   /**
    * Configure video codec parameters and start media codec. It must be called
    * before calling Encode() and GetNextEncodedFrame().
+   * aBlobFormat specifies output blob format provided by encoder. It can be
+   * AVC_MP4 or AVC_NAL.
    */
-  nsresult Configure(int aWidth, int aHeight, int aFrameRate);
+  nsresult Configure(int aWidth, int aHeight, int aFrameRate,
+                     BlobFormat aBlobFormat = BlobFormat::AVC_MP4);
 
   /**
    * Encode a aWidth pixels wide and aHeight pixels tall video frame of
    * semi-planar YUV420 format stored in the buffer of aImage. aTimestamp gives
    * the frame timestamp/presentation time (in microseconds). To notify end of
    * stream, set aInputFlags to BUFFER_EOS.
    */
   nsresult Encode(const mozilla::layers::Image* aImage, int aWidth, int aHeight,
                   int64_t aTimestamp, int aInputFlags = 0);
 
+  /** Set encoding bitrate (in kbps). */
+  nsresult SetBitrate(int32_t aKbps);
+
+  /**
+   * Get current AVC codec config blob. The output format depends on the
+   * aBlobFormat argument given when Configure() was called.
+   */
+  nsresult GetCodecConfig(nsTArray<uint8_t>* aOutputBuf);
+
 protected:
   virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
                                        ABuffer* aData) MOZ_OVERRIDE;
 
-  // AVC/H.264 encoder replaces NAL unit start code with the unit length as
-  // specified in ISO/IEC 14496-15 5.2.3.
+  // If configured to output MP4 format blob, AVC/H.264 encoder has to replace
+  // NAL unit start code with the unit length as specified in
+  // ISO/IEC 14496-15 5.2.3.
   virtual void AppendFrame(nsTArray<uint8_t>* aOutputBuf,
                            const uint8_t* aData, size_t aSize) MOZ_OVERRIDE;
 
 private:
   // Hide these. User should always use creator functions to get a media codec.
   OMXVideoEncoder() MOZ_DELETE;
   OMXVideoEncoder(const OMXVideoEncoder&) MOZ_DELETE;
   OMXVideoEncoder& operator=(const OMXVideoEncoder&) MOZ_DELETE;
 
   /**
    * Create a video codec. It will be a AVC/H.264 encoder if aCodecType is
    * CODEC_AVC_ENC.
    */
   OMXVideoEncoder(CodecType aCodecType)
-    : OMXCodecWrapper(aCodecType), mWidth(0), mHeight(0) {}
+    : OMXCodecWrapper(aCodecType)
+    , mWidth(0)
+    , mHeight(0)
+    , mBlobFormat(BlobFormat::AVC_MP4)
+    , mHasConfigBlob(false)
+  {}
 
   // For creator function to access hidden constructor.
   friend class OMXCodecWrapper;
 
   int mWidth;
   int mHeight;
+  BlobFormat mBlobFormat;
+  bool mHasConfigBlob;
 };
 
 } // namespace android
 #endif // OMXCodecWrapper_h_
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -533,35 +533,52 @@ nsDOMWindowUtils::SetCriticalDisplayPort
 NS_IMETHODIMP
 nsDOMWindowUtils::SetResolution(float aXResolution, float aYResolution)
 {
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   nsIPresShell* presShell = GetPresShell();
-  return presShell ? presShell->SetResolution(aXResolution, aYResolution)
-                   : NS_ERROR_FAILURE;
+  if (!presShell) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
+  if (sf) {
+    sf->SetResolution(gfxSize(aXResolution, aYResolution));
+    presShell->SetResolution(aXResolution, aYResolution);
+  }
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetResolution(float* aXResolution, float* aYResolution)
 {
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   nsIPresShell* presShell = GetPresShell();
-
-  if (presShell) {
+  if (!presShell) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
+  if (sf) {
+    const gfxSize& res = sf->GetResolution();
+    *aXResolution = res.width;
+    *aYResolution = res.height;
+  } else {
     *aXResolution = presShell->GetXResolution();
     *aYResolution = presShell->GetYResolution();
-    return NS_OK;
-  }
-  return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SetIsFirstPaint(bool aIsFirstPaint)
 {
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
--- a/dom/imptests/failures/html/dom/nodes/mochitest.ini
+++ b/dom/imptests/failures/html/dom/nodes/mochitest.ini
@@ -1,15 +1,14 @@
 # THIS FILE IS AUTOGENERATED BY parseFailures.py - DO NOT EDIT
 [DEFAULT]
 support-files =
 
 
 [test_Document-createElement-namespace.html.json]
 [test_Document-createElementNS.html.json]
-[test_Document-createEvent.html.json]
 [test_Document-getElementsByTagName.html.json]
 [test_Node-isEqualNode.xhtml.json]
 [test_Node-properties.html.json]
 [test_attributes.html.json]
 [test_case.html.json]
 [test_getElementsByClassName-10.xml.json]
 [test_getElementsByClassName-11.xml.json]
deleted file mode 100644
--- a/dom/imptests/failures/html/dom/nodes/test_Document-createEvent.html.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-  "createEvent('CustomEvent') should be initialized correctly.": true,
-  "createEvent('customevent') should be initialized correctly.": true,
-  "createEvent('CUSTOMEVENT') should be initialized correctly.": true,
-  "createEvent('Event') should be initialized correctly.": true,
-  "createEvent('event') should be initialized correctly.": true,
-  "createEvent('EVENT') should be initialized correctly.": true,
-  "createEvent('Events') should be initialized correctly.": true,
-  "createEvent('events') should be initialized correctly.": true,
-  "createEvent('EVENTS') should be initialized correctly.": true,
-  "createEvent('HTMLEvents') should be initialized correctly.": true,
-  "createEvent('htmlevents') should be initialized correctly.": true,
-  "createEvent('HTMLEVENTS') should be initialized correctly.": true,
-  "createEvent('MouseEvent') should be initialized correctly.": true,
-  "createEvent('mouseevent') should be initialized correctly.": true,
-  "createEvent('MOUSEEVENT') should be initialized correctly.": true,
-  "createEvent('MouseEvents') should be initialized correctly.": true,
-  "createEvent('mouseevents') should be initialized correctly.": true,
-  "createEvent('MOUSEEVENTS') should be initialized correctly.": true,
-  "createEvent('UIEvent') should be initialized correctly.": true,
-  "createEvent('uievent') should be initialized correctly.": true,
-  "createEvent('UIEVENT') should be initialized correctly.": true,
-  "createEvent('UIEvents') should be initialized correctly.": true,
-  "createEvent('uievents') should be initialized correctly.": true,
-  "createEvent('UIEVENTS') should be initialized correctly.": true
-}
--- a/dom/xslt/xpath/nsXPathResult.cpp
+++ b/dom/xslt/xpath/nsXPathResult.cpp
@@ -2,18 +2,18 @@
 /* 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 "nsXPathResult.h"
 #include "txExprResult.h"
 #include "txNodeSet.h"
 #include "nsError.h"
+#include "mozilla/dom/Attr.h"
 #include "mozilla/dom/Element.h"
-#include "nsIAttribute.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMDocument.h"
 #include "nsDOMString.h"
 #include "txXPathTreeWalker.h"
 #include "nsCycleCollectionParticipant.h"
 
 using namespace mozilla::dom;
@@ -356,18 +356,18 @@ nsXPathResult::Invalidate(const nsIConte
         // the changes are happening in a different anonymous trees, no
         // invalidation should happen.
         nsIContent* ctxBindingParent = nullptr;
         if (contextNode->IsNodeOfType(nsINode::eCONTENT)) {
             ctxBindingParent =
                 static_cast<nsIContent*>(contextNode.get())
                     ->GetBindingParent();
         } else if (contextNode->IsNodeOfType(nsINode::eATTRIBUTE)) {
-            nsIContent* parent =
-              static_cast<nsIAttribute*>(contextNode.get())->GetContent();
+            Element* parent =
+              static_cast<Attr*>(contextNode.get())->GetElement();
             if (parent) {
                 ctxBindingParent = parent->GetBindingParent();
             }
         }
         if (ctxBindingParent != aChangeRoot->GetBindingParent()) {
           return;
         }
     }
--- a/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp
+++ b/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp
@@ -16,20 +16,23 @@
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsTextFragment.h"
 #include "txXMLUtils.h"
 #include "txLog.h"
 #include "nsUnicharUtils.h"
 #include "nsAttrName.h"
 #include "nsTArray.h"
+#include "mozilla/dom/Attr.h"
 #include "mozilla/dom/Element.h"
 #include <stdint.h>
 #include <algorithm>
 
+using mozilla::dom::Attr;
+
 const uint32_t kUnknownIndex = uint32_t(-1);
 
 txXPathTreeWalker::txXPathTreeWalker(const txXPathTreeWalker& aOther)
     : mPosition(aOther.mPosition),
       mCurrentIndex(aOther.mCurrentIndex)
 {
 }
 
@@ -686,17 +689,18 @@ txXPathNativeNode::createXPathNode(nsIDO
     uint16_t nodeType;
     aNode->GetNodeType(&nodeType);
 
     if (nodeType == nsIDOMNode::ATTRIBUTE_NODE) {
         nsCOMPtr<nsIAttribute> attr = do_QueryInterface(aNode);
         NS_ASSERTION(attr, "doesn't implement nsIAttribute");
 
         nsINodeInfo *nodeInfo = attr->NodeInfo();
-        nsIContent *parent = attr->GetContent();
+        mozilla::dom::Element* parent =
+          static_cast<Attr*>(attr.get())->GetElement();
         if (!parent) {
             return nullptr;
         }
 
         nsINode* root = aKeepRootAlive ? txXPathNode::RootOf(parent) : nullptr;
 
         uint32_t i, total = parent->GetAttrCount();
         for (i = 0; i < total; ++i) {
new file mode 100644
--- /dev/null
+++ b/gfx/doc/MozSurface.md
@@ -0,0 +1,230 @@
+MozSurface {#mozsurface}
+==========
+
+**This document is work in progress.  Some information may be missing or incomplete.**
+
+## Goals
+
+We need to be able to safely and efficiently render web content into surfaces that may be shared accross processes.
+MozSurface is a cross-process and backend-independent Surface API and not a stream API.
+
+## Owner
+
+Nicolas Silva
+
+## Definitions
+
+* Client and Host: In Gecko's compositing architecture, the client process is the producer, while the host process is the consumer side, where compositing takes place.
+
+## Use cases
+
+Drawing web content into a surface and share it with the compositor process to display it on the screen without copies.
+
+## Requirement
+
+* It must be possible to efficiently share a MozSurface with a separate thread or process through IPDL
+* It must be possible to obtain read access a MozSurface on both the client and the host side at the same time.
+* The creation, update and destrution of surfaces must be safe and race-free. In particular, the ownership of the shared data must be clearly defined.
+* MozSurface must be a cross-backend/cross-platform abstraction that we will use on all of the supported platforms.
+* It must be possible to efficiently draw into a MozSurface using Moz2D.
+* While it should be possible to share MozSurfaces accross processes, it should not be limited to that. MozSurface should also be the preferred abstraction for use with surfaces that are not shared with the compositor process.
+
+## TextureClient and TextureHost
+
+TextureClient and TextureHost are the closest abstractions we currently have to MozSurface.
+Inline documentation about TextureClient and TextureHost can be found in:
+
+* [gfx/layers/client/TextureClient.h](http://dxr.mozilla.org/mozilla-central/source/gfx/layers/client/TextureClient.h)
+* [gfx/layers/composite/TextureHost.h](http://dxr.mozilla.org/mozilla-central/source/gfx/layers/composite/TextureHost.h)
+
+TextureClient is the client-side handle on a MozSurface, while TextureHost is the equivalent host-side representation. There can only be one TextureClient for a given TextureHost, and one TextureHost for a given TextureClient. Likewise, there can only be one shared object for a given TextureClient/TextureHost pair.
+
+A MozSurface containing data that is shared between a client process and a host process exists in the foolowing form:
+
+```
+                                 .
+            Client process       .      Host process
+                                 .
+     ________________      ______________      ______________
+    |                |    |              |    |              |
+    | TextureClient  +----+ <SharedData> +----+ TextureHost  |
+    |________________|    |______________|    |______________|
+                                 .
+                                 .
+                                 .
+    Figure 1) A Surface as seen by the client and the host processes
+```
+
+The above figure is a logical representation, not a class diagram.
+`<SharedData>` is a placeholder for whichever platform specific surface type we are sharing, for example a Gralloc buffer on Gonk or a D3D11 texture on Windows.
+
+## Locking semantics
+
+In order to access the shared surface data users of MozSurface must acquire and release a lock on the surface, specifying the open mode (read/write/read+write).
+
+    bool Lock(OpenMode aMode);
+    void Unlock();
+
+This locking API has two purposes:
+
+* Ensure that access to the shared data is race-free.
+* Let the implemetation do whatever is necessary for the user to have access to the data. For example it can be mapping and unmapping the surface data in memory if the underlying backend requires it.
+
+The lock is expected to behave as a cross-process blocking read/write lock that is not reentrant.
+
+## Immutable surfaces
+
+In some cases we know in advance that a surface will not be modified after it has been shared. This is for example true for video frames. In this case the surface can be marked as immutable and the underlying implementation doesn't need to hold an actual blocking lock on the shared data.
+Trying to acquire a write lock on a MozSurface that is marked as immutable and already shared must fail (return false).
+Note that it is still required to use the Lock/Unlock API to read the data, in order for the implementation to be able to properly map and unmap the memory. This is just an optimization and a safety check.
+
+## Drawing into a surface
+
+In most cases we want to be able to paint directly into a surface through the Moz2D API.
+
+A surface lets you *borrow* a DrawTarget that is only valid between Lock and Unlock.
+
+    DrawTarget* GetAsDrawTarget();
+
+It is invalid to hold a reference to the DrawTarget after Unlock, and a different DrawTarget may be obtained during the next Lock/Unlock interval.
+
+In some cases we want to use MozSurface without Drawing into it. For instance to share video frames accross processes. Some surface types may also not be accessible through a DrawTarget (for example YCbCr surfaces).
+
+    bool CanExposeDrawTarget();
+
+helps with making sure that a Surface supports exposing a Moz2D DrawTarget.
+
+## Using a MozSurface as a source for Compositing
+
+To interface with the Compositor API, MozSurface gives access to TextureSource objects. TextureSource is the cross-backend representation of a texture that Compositor understands.
+While MozSurface handles memory management of (potentially shared) texture data, TextureSource is only an abstraction for Compositing.
+
+## Fence synchronization
+
+TODO: We need to figure this out. Right now we have a Gonk specific implementation, but no cross-platform abstraction/design.
+
+## Ownership of the shared data
+
+MozSurface (TextureClient/TextureHost in its current form) defines ownership rules that depend on the configuration of the surface, in order to satisy efficiency and safety requirements.
+
+These rules rely on the fact that the underlying shared data is strictly owned by the MozSurface. This means that keeping direct references to the shared data is illegal and unsafe.
+
+## Deallocation protocol
+
+The shared data is accessible by both the client-side and the host-side of the MozSurface. A deallocation protocol must be defined to handle which side deallocates the data, and to ensure that it doesn't cause any race condition.
+The client side, which contains the web content's logic, always "decides" when a surface is needed or not. So the life time of a MozSurface is driven by the reference count of it's client-side handle (TextureClient).
+When a TextureClient's reference count reaches zero, a "Remove" message is sent in order to let the host side that the shared data is not accessible on the client side and that it si safe for it to be deleted. The host side responds with a "Delete" message.
+
+
+```
+           client side                .         host side
+                                      .
+    (A) Client: Send Remove     -.    .
+                                  \   .
+                                   \  .   ... can receive and send ...
+                                    \
+        Can receive                  `--> (B) Host: Receive Remove
+        Can't send                         |
+                                      .-- (C) Host: Send Delete
+                                     /
+                                    / .   ... can't receive nor send ...
+                                   /  .
+    (D) Client: Receive Delete <--'   .
+                                      .
+    Figure 2) MozSurface deallocation handshake
+```
+
+This handshake protocol is twofold:
+
+* It defines where and when it is possible to deallocate the shared data without races
+* It makes it impossible for asynchronous messages to race with the destruction of the MozSurface.
+
+### Deallocating on the host side
+
+In the common case, the shared data is deallocated asynchronously on the host side. In this case the deallocation takes place at the point (C) of figure 2.
+
+### Deallocating on the client side
+
+In some rare cases, for instance if the underlying implementation requires it, the shared data must be deallocated on the client side. In such cases, deallocation happens at the point (D) of figure 2.
+
+In some exceptional cases, this needs to happen synchronously, meaning that the client-side thread will block until the Delete message is received. This is supported but it is terrible for performance, so it should be avoided as much as possible.
+Currently this is needed when shutting down a hardware-decoded video stream with libstagefright on Gonk, because the libstagefright unfortunately assumes it has full ownership over the shared data (gralloc buffers) and crashes if there are still users of the buffers.
+
+### Sharing state
+
+The above deallocation protocol of a MozSurface applies to the common case that is when the surface is shared between two processes. A Surface can also be deallocated while it is not shared.
+
+The sharing state of a MozSurface can be one of the following:
+
+* (1) Uninitialized (it doesn't have any shared data)
+* (2) Local (it isn't shared with the another thread/process)
+* (3) Shared (the state you would expect it to be most of the time)
+* (4) Invalid (when for some rare cases we needed to force the deallocation of the shared data before the destruction of the TextureClient object).
+
+Surfaces can move from state N to state N+1 and be deallocated in any of these states. It could be possible to move from Shared to Local, but we currently don't have a use case for it.
+
+The deallocation protocol above, applies to the Shared state (3).
+In the other cases:
+
+* (1) Unitilialized: There is nothing to do.
+* (2) Local: The shared data is deallocated by the client side without need for a handshake, since it is not shared with other threads.
+* (4) Invalid: There is nothing to do (deallocation has already happenned).
+
+## Internal buffers / direct texturing
+
+Some MozSurface implementations use CPU-side shared memory to share the texture data accross processes, and require a GPU texture upload when interfacing with a TextureSource. In this case we say that the surface has an internal buffer (because it is implicitly equivalent to double buffering where the shared data is the back buffer and the GPU side texture is the front buffer). We also say that it doesn't do "direct texturing" meaning that we don't draw directly into the GPU-side texture.
+
+Examples:
+
+ * Shmem MozSurface + OpenGL TextureSource: Has an internal buffer (no direct texturing)
+ * Gralloc MozSurface + Gralloc TextureSource: No internal buffer (direct texturing)
+
+While direct texturing is usually the most efficient way, it is not always available depending on the platform and the required allocation size or format. Textures with internal buffers have less restrictions around locking since the host side will only need to read from the MozSurface once per update, meaning that we can often get away with single buffering where we would need double buffering with direct texturing.
+
+## Alternative solutions
+
+### Sending ownership back and forth between the client and host sides through message passing, intead of sharing.
+
+The current design of MozSurface makes the surface accessible from both sides at the same time, forcing us to do Locking and have a hand shake around deallocating the shared data, while using pure message passing and making the surface accessible only from one side at a time would avoid these complications.
+
+Using pure message passing was actually the first approach we tried when we created the first version of TextureClient and TextureHost. This strategy failed in several places, partly because of some legacy in Gecko's architecture, and partly because of some of optimizations we do to avoid copying surfaces.
+
+We need a given surface to be accessible on both the client and host for the following reasons:
+
+* Gecko can at any time require read access on the client side to a surface that is shared with the host process, for example to build a temporary layer manager and generate a screenshot. This is mostly a legacy problem.
+* We do some copy-on-write optimizations on surfaces that are shared with the compositor in order to keep invalid regions as small as possible. Out tiling implementation is an example of that.
+* Our buffer rotation code on scrollable non-tiled layers also requires a synchronization on the client side between the front and back buffers, while the front buffer is used on the host side.
+
+## Backends
+
+We have MozSurface implementaions (classes inheriting from TextureClient/TextureHost) for OpenGL, Software, D3D9, and D3D11 backends.
+Some implemtations can be used with any backend (ex. ShmemTextureClient/Host).
+
+## Users of MozSurface
+
+MozSurface is the mechanism used by layers to share surfaces with the compositor, but it is not limited to layers. It should be used by anything that draws into a surface that may be shared with the compositor thread.
+
+## Testing
+
+TODO - How can we make MozSurface more testable and what should we test?
+
+## Future work
+
+### Rename TextureClient/TextureHost
+
+The current terminology is very confusing.
+
+### Unify TextureClient and TextureHost
+
+TextureClient and TextureHost should live under a common interface to better hide the IPC details. The base classe should only expose the non-ipc related methods such as Locking, access through a DrawTarget, access to a TextureSource.
+
+### Using a MozSurface as a source for Drawing
+
+MozSurface should be able to expose a borrowed Moz2D SourceSurface that is valid between Lock and Unlock similarly to how it exposes a DrawTarget.
+
+## Comparison with other APIs
+
+MozSurface is somewhat equivalent to Gralloc on Android/Gonk: it is a reference counted cross-process surface with locking semantics. While Gralloc can interface itself with OpenGL textures for compositing, MozSurface can interface itself to TextureSource objects.
+
+MozSurface should not be confused with higher level APIs such as EGLStream. A swap-chain API like EGLStream can be implemented on top of MozSurface, but MozSurface's purpose is to define and manage the memory and resources of shared texture data.
+
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug995673.js
@@ -0,0 +1,16 @@
+var total = 0
+
+x = [ [] ]
+x[0].valueOf = function () {
+  total++;
+}
+function f(y) {
+    y != Math.abs()
+}
+(function() {
+    f()
+    f(x[0])
+    f(x[0])
+})()
+
+assertEq(total, 2)
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -2818,16 +2818,20 @@ class MToDouble
   private:
     ConversionKind conversion_;
 
     MToDouble(MDefinition *def, ConversionKind conversion = NonStringPrimitives)
       : MUnaryInstruction(def), conversion_(conversion)
     {
         setResultType(MIRType_Double);
         setMovable();
+
+        // An object might have "valueOf", which means it is effectful.
+        if (def->mightBeType(MIRType_Object))
+            setGuard();
     }
 
   public:
     INSTRUCTION_HEADER(ToDouble)
     static MToDouble *New(TempAllocator &alloc, MDefinition *def,
                           ConversionKind conversion = NonStringPrimitives)
     {
         return new(alloc) MToDouble(def, conversion);
@@ -2880,16 +2884,20 @@ class MToFloat32
   protected:
     ConversionKind conversion_;
 
     MToFloat32(MDefinition *def, ConversionKind conversion)
       : MUnaryInstruction(def), conversion_(conversion)
     {
         setResultType(MIRType_Float32);
         setMovable();
+
+        // An object might have "valueOf", which means it is effectful.
+        if (def->mightBeType(MIRType_Object))
+            setGuard();
     }
 
   public:
     INSTRUCTION_HEADER(ToFloat32)
     static MToFloat32 *New(TempAllocator &alloc, MDefinition *def,
                            ConversionKind conversion = NonStringPrimitives)
     {
         return new(alloc) MToFloat32(def, conversion);
@@ -2988,16 +2996,20 @@ class MToInt32
 
     MToInt32(MDefinition *def, MacroAssembler::IntConversionInputKind conversion)
       : MUnaryInstruction(def),
         canBeNegativeZero_(true),
         conversion_(conversion)
     {
         setResultType(MIRType_Int32);
         setMovable();
+
+        // An object might have "valueOf", which means it is effectful.
+        if (def->mightBeType(MIRType_Object))
+            setGuard();
     }
 
   public:
     INSTRUCTION_HEADER(ToInt32)
     static MToInt32 *New(TempAllocator &alloc, MDefinition *def,
                          MacroAssembler::IntConversionInputKind conversion =
                              MacroAssembler::IntConversion_Any)
     {
@@ -3042,16 +3054,20 @@ class MToInt32
 // operations. This is an infallible ValueToECMAInt32.
 class MTruncateToInt32 : public MUnaryInstruction
 {
     MTruncateToInt32(MDefinition *def)
       : MUnaryInstruction(def)
     {
         setResultType(MIRType_Int32);
         setMovable();
+
+        // An object might have "valueOf", which means it is effectful.
+        if (def->mightBeType(MIRType_Object))
+            setGuard();
     }
 
   public:
     INSTRUCTION_HEADER(TruncateToInt32)
     static MTruncateToInt32 *New(TempAllocator &alloc, MDefinition *def) {
         return new(alloc) MTruncateToInt32(def);
     }
     static MTruncateToInt32 *NewAsmJS(TempAllocator &alloc, MDefinition *def) {
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -1838,34 +1838,56 @@ AddTransformedBoundsToRegion(const nsInt
   if (!gfxUtils::GfxRectToIntRect(transformed, &intRect)) {
     // This should only fail if coordinates are too big to fit in an int32
     *aDest = nsIntRect(-INT32_MAX/2, -INT32_MAX/2, INT32_MAX, INT32_MAX);
     return;
   }
   aDest->Or(*aDest, intRect);
 }
 
+static bool
+CanOptimizeAwayThebesLayer(ThebesLayerData* aData,
+                           FrameLayerBuilder* aLayerBuilder)
+{
+  bool isRetained = aData->mLayer->Manager()->IsWidgetLayerManager();
+  if (!isRetained) {
+    return false;
+  }
+
+  // If there's no thebes layer with valid content in it that we can reuse,
+  // always create a color or image layer (and potentially throw away an
+  // existing completely invalid thebes layer).
+  if (aData->mLayer->GetValidRegion().IsEmpty()) {
+    return true;
+  }
+
+  // There is an existing thebes layer we can reuse. Throwing it away can make
+  // compositing cheaper (see bug 946952), but it might cause us to re-allocate
+  // the thebes layer frequently due to an animation. So we only discard it if
+  // we're in tree compression mode, which is triggered at a low frequency.
+  return aLayerBuilder->CheckInLayerTreeCompressionMode();
+}
+
 void
 ContainerState::PopThebesLayerData()
 {
   NS_ASSERTION(!mThebesLayerDataStack.IsEmpty(), "Can't pop");
 
   int32_t lastIndex = mThebesLayerDataStack.Length() - 1;
   ThebesLayerData* data = mThebesLayerDataStack[lastIndex];
 
   AdjustLayerDataForFixedPositioning(data->mFixedPosFrameForLayerData,
                                      data->mDrawRegion,
                                      &data->mVisibleRegion,
                                      &data->mIsSolidColorInVisibleRegion);
   nsRefPtr<Layer> layer;
   nsRefPtr<ImageContainer> imageContainer = data->CanOptimizeImageLayer(mBuilder);
 
-  bool isRetained = data->mLayer->Manager()->IsWidgetLayerManager();
-  if (isRetained && (data->mIsSolidColorInVisibleRegion || imageContainer) &&
-      (data->mLayer->GetValidRegion().IsEmpty() || mLayerBuilder->CheckInLayerTreeCompressionMode())) {
+  if ((data->mIsSolidColorInVisibleRegion || imageContainer) &&
+      CanOptimizeAwayThebesLayer(data, mLayerBuilder)) {
     NS_ASSERTION(!(data->mIsSolidColorInVisibleRegion && imageContainer),
                  "Can't be a solid color as well as an image!");
     if (imageContainer) {
       nsRefPtr<ImageLayer> imageLayer = CreateOrRecycleImageLayer(data->mLayer);
       imageLayer->SetContainer(imageContainer);
       data->mImage->ConfigureLayer(imageLayer, mParameters.mOffset);
       imageLayer->SetPostScale(mParameters.mXScale,
                                mParameters.mYScale);
--- a/layout/base/nsPresState.h
+++ b/layout/base/nsPresState.h
@@ -7,71 +7,84 @@
  * a piece of state that is stored in session history when the document
  * is not
  */
 
 #ifndef nsPresState_h_
 #define nsPresState_h_
 
 #include "nsPoint.h"
+#include "gfxPoint.h"
 #include "nsAutoPtr.h"
 
 class nsPresState
 {
 public:
   nsPresState()
     : mContentData(nullptr)
     , mScrollState(0, 0)
+    , mResolution(1.0, 1.0)
     , mDisabledSet(false)
     , mDisabled(false)
   {}
 
   void SetScrollState(const nsPoint& aState)
   {
     mScrollState = aState;
   }
 
-  nsPoint GetScrollState()
+  nsPoint GetScrollState() const
   {
     return mScrollState;
   }
 
+  void SetResolution(const gfxSize& aSize)
+  {
+    mResolution = aSize;
+  }
+
+  gfxSize GetResolution() const
+  {
+    return mResolution;
+  }
+
   void ClearNonScrollState()
   {
     mContentData = nullptr;
     mDisabledSet = false;
   }
 
-  bool GetDisabled()
+  bool GetDisabled() const
   {
     return mDisabled;
   }
 
   void SetDisabled(bool aDisabled)
   {
     mDisabled = aDisabled;
     mDisabledSet = true;
   }
 
-  bool IsDisabledSet()
+  bool IsDisabledSet() const
   {
     return mDisabledSet;
   }
 
-  nsISupports* GetStateProperty()
+  nsISupports* GetStateProperty() const
   {
     return mContentData;
   }
 
   void SetStateProperty(nsISupports *aProperty)
   {
     mContentData = aProperty;
   }
 
 // MEMBER VARIABLES
 protected:
   nsCOMPtr<nsISupports> mContentData;
   nsPoint mScrollState;
+  gfxSize mResolution;
   bool mDisabledSet;
   bool mDisabled;
 };
 
 #endif /* nsPresState_h_ */
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1595,16 +1595,17 @@ ScrollFrameHelper::ScrollFrameHelper(nsC
   , mOuter(aOuter)
   , mAsyncScroll(nullptr)
   , mOriginOfLastScroll(nsGkAtoms::other)
   , mScrollGeneration(++sScrollGenerationCounter)
   , mDestination(0, 0)
   , mScrollPosAtLastPaint(0, 0)
   , mRestorePos(-1, -1)
   , mLastPos(-1, -1)
+  , mResolution(1.0, 1.0)
   , mScrollPosForLayerPixelAlignment(-1, -1)
   , mLastUpdateImagesPos(-1, -1)
   , mNeverHasVerticalScrollbar(false)
   , mNeverHasHorizontalScrollbar(false)
   , mHasVerticalScrollbar(false)
   , mHasHorizontalScrollbar(false)
   , mFrameIsUpdatingScrollbar(false)
   , mDidHistoryRestore(false)
@@ -2781,16 +2782,28 @@ ScrollFrameHelper::GetScrollPositionClam
 {
   nsIPresShell* presShell = mOuter->PresContext()->PresShell();
   if (mIsRoot && presShell->IsScrollPositionClampingScrollPortSizeSet()) {
     return presShell->GetScrollPositionClampingScrollPortSize();
   }
   return mScrollPort.Size();
 }
 
+gfxSize
+ScrollFrameHelper::GetResolution() const
+{
+  return mResolution;
+}
+
+void
+ScrollFrameHelper::SetResolution(const gfxSize& aResolution)
+{
+  mResolution = aResolution;
+}
+
 static void
 AdjustForWholeDelta(int32_t aDelta, nscoord* aCoord)
 {
   if (aDelta < 0) {
     *aCoord = nscoord_MIN;
   } else if (aDelta > 0) {
     *aCoord = nscoord_MAX;
   }
@@ -4481,17 +4494,17 @@ ScrollFrameHelper::GetCoordAttribute(nsI
 
   // Only this exact default value is allowed.
   *aRangeStart = aDefaultValue;
   *aRangeLength = 0;
   return aDefaultValue;
 }
 
 nsPresState*
-ScrollFrameHelper::SaveState()
+ScrollFrameHelper::SaveState() const
 {
   nsIScrollbarMediator* mediator = do_QueryFrame(GetScrolledFrame());
   if (mediator) {
     // child handles its own scroll state, so don't bother saving state here
     return nullptr;
   }
 
   // Don't store a scroll state if we never have been scrolled or restored
@@ -4506,25 +4519,31 @@ ScrollFrameHelper::SaveState()
   // that ScrollToRestoredPosition uses). This ensures if a reframe occurs
   // while we're in the process of loading content to scroll to a restored
   // position, we'll keep trying after the reframe.
   nsPoint pt = GetLogicalScrollPosition();
   if (mRestorePos.y != -1 && pt == mLastPos) {
     pt = mRestorePos;
   }
   state->SetScrollState(pt);
+  state->SetResolution(mResolution);
   return state;
 }
 
 void
 ScrollFrameHelper::RestoreState(nsPresState* aState)
 {
   mRestorePos = aState->GetScrollState();
   mDidHistoryRestore = true;
   mLastPos = mScrolledFrame ? GetLogicalScrollPosition() : nsPoint(0,0);
+  mResolution = aState->GetResolution();
+
+  if (mIsRoot) {
+    mOuter->PresContext()->PresShell()->SetResolution(mResolution.width, mResolution.height);
+  }
 }
 
 void
 ScrollFrameHelper::PostScrolledAreaEvent()
 {
   if (mScrolledAreaEvent.IsPending()) {
     return;
   }
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -158,16 +158,19 @@ public:
       mScrollPort.XMost() - mScrolledFrame->GetRect().XMost();
     pt.y = mScrollPort.y - mScrolledFrame->GetPosition().y;
     return pt;
   }
   nsRect GetScrollRange() const;
   // Get the scroll range assuming the scrollport has size (aWidth, aHeight).
   nsRect GetScrollRange(nscoord aWidth, nscoord aHeight) const;
   nsSize GetScrollPositionClampingScrollPortSize() const;
+  gfxSize GetResolution() const;
+  void SetResolution(const gfxSize& aResolution);
+
 protected:
   nsRect GetScrollRangeForClamping() const;
 
 public:
   static void AsyncScrollCallback(void* anInstance, mozilla::TimeStamp aTime);
   /**
    * @note This method might destroy the frame, pres shell and other objects.
    * aRange is the range of allowable scroll positions around the desired
@@ -202,17 +205,17 @@ public:
   /**
    * @note This method might destroy the frame, pres shell and other objects.
    */
   void ScrollToRestoredPosition();
 
   nsSize GetLineScrollAmount() const;
   nsSize GetPageScrollAmount() const;
 
-  nsPresState* SaveState();
+  nsPresState* SaveState() const;
   void RestoreState(nsPresState* aState);
 
   nsIFrame* GetScrolledFrame() const { return mScrolledFrame; }
   nsIFrame* GetScrollbarBox(bool aVertical) const {
     return aVertical ? mVScrollbarBox : mHScrollbarBox;
   }
 
   void AddScrollPositionListener(nsIScrollPositionListener* aListener) {
@@ -343,16 +346,19 @@ public:
   // after every reflow --- because after each time content is loaded/added to the
   // scrollable element, there will be a reflow.
   nsPoint mRestorePos;
   // The last logical position we scrolled to while trying to restore mRestorePos, or
   // 0,0 when this is a new frame. Set to -1,-1 once we've scrolled for any reason
   // other than trying to restore mRestorePos.
   nsPoint mLastPos;
 
+  // The current resolution derived from the zoom level and device pixel ratio.
+  gfxSize mResolution;
+
   nsExpirationState mActivityExpirationState;
 
   nsCOMPtr<nsITimer> mScrollActivityTimer;
   nsPoint mScrollPosForLayerPixelAlignment;
 
   // The scroll position where we last updated image visibility.
   nsPoint mLastUpdateImagesPos;
 
@@ -572,16 +578,22 @@ public:
     return mHelper.GetLogicalScrollPosition();
   }
   virtual nsRect GetScrollRange() const MOZ_OVERRIDE {
     return mHelper.GetScrollRange();
   }
   virtual nsSize GetScrollPositionClampingScrollPortSize() const MOZ_OVERRIDE {
     return mHelper.GetScrollPositionClampingScrollPortSize();
   }
+  virtual gfxSize GetResolution() const MOZ_OVERRIDE {
+    return mHelper.GetResolution();
+  }
+  virtual void SetResolution(const gfxSize& aResolution) MOZ_OVERRIDE {
+    return mHelper.SetResolution(aResolution);
+  }
   virtual nsSize GetLineScrollAmount() const MOZ_OVERRIDE {
     return mHelper.GetLineScrollAmount();
   }
   virtual nsSize GetPageScrollAmount() const MOZ_OVERRIDE {
     return mHelper.GetPageScrollAmount();
   }
   /**
    * @note This method might destroy the frame, pres shell and other objects.
@@ -882,16 +894,22 @@ public:
     return mHelper.GetLogicalScrollPosition();
   }
   virtual nsRect GetScrollRange() const MOZ_OVERRIDE {
     return mHelper.GetScrollRange();
   }
   virtual nsSize GetScrollPositionClampingScrollPortSize() const MOZ_OVERRIDE {
     return mHelper.GetScrollPositionClampingScrollPortSize();
   }
+  virtual gfxSize GetResolution() const MOZ_OVERRIDE {
+    return mHelper.GetResolution();
+  }
+  virtual void SetResolution(const gfxSize& aResolution) MOZ_OVERRIDE {
+    return mHelper.SetResolution(aResolution);
+  }
   virtual nsSize GetLineScrollAmount() const MOZ_OVERRIDE {
     return mHelper.GetLineScrollAmount();
   }
   virtual nsSize GetPageScrollAmount() const MOZ_OVERRIDE {
     return mHelper.GetPageScrollAmount();
   }
   /**
    * @note This method might destroy the frame, pres shell and other objects.
--- a/layout/generic/nsIScrollableFrame.h
+++ b/layout/generic/nsIScrollableFrame.h
@@ -129,17 +129,24 @@ public:
    * device pixels.
    */
   virtual nsRect GetScrollRange() const = 0;
   /**
    * Get the size of the scroll port to use when clamping the scroll
    * position.
    */
   virtual nsSize GetScrollPositionClampingScrollPortSize() const = 0;
-
+  /**
+   * Get the element resolution.
+   */
+  virtual gfxSize GetResolution() const = 0;
+  /**
+   * Set the element resolution.
+   */
+  virtual void SetResolution(const gfxSize& aResolution) = 0;
   /**
    * Return how much we would try to scroll by in each direction if
    * asked to scroll by one "line" vertically and horizontally.
    */
   virtual nsSize GetLineScrollAmount() const = 0;
   /**
    * Return how much we would try to scroll by in each direction if
    * asked to scroll by one "page" vertically and horizontally.
--- a/layout/tools/reftest/reftest-preferences.js
+++ b/layout/tools/reftest/reftest-preferences.js
@@ -43,8 +43,10 @@
     // Disable interruptible reflow since (1) it's normally not going to
     // happen, but (2) it might happen if we somehow end up with both
     // pending user events and clock skew.  So to avoid having to change
     // MakeProgress to deal with waiting for interruptible reflows to
     // complete for a rare edge case, we just disable interruptible
     // reflow so that that rare edge case doesn't lead to reftest
     // failures.
     branch.setBoolPref("layout.interruptible-reflow.enabled", false);
+    // Don't try to connect to the telemetry server.
+    branch.setBoolPref("toolkit.telemetry.enabled", false);
--- a/media/libcubeb/src/cubeb_pulse.c
+++ b/media/libcubeb/src/cubeb_pulse.c
@@ -89,17 +89,17 @@ enum cork_state {
   CORK = 1 << 0,
   NOTIFY = 1 << 1
 };
 
 static void
 sink_info_callback(pa_context * context, const pa_sink_info * info, int eol, void * u)
 {
   cubeb * ctx = u;
-   if (!eol) {
+  if (!eol) {
     ctx->default_sink_info = malloc(sizeof(pa_sink_info));
     memcpy(ctx->default_sink_info, info, sizeof(pa_sink_info));
   }
   WRAP(pa_threaded_mainloop_signal)(ctx->mainloop, 0);
 }
 
 static void
 server_info_callback(pa_context * context, const pa_server_info * info, void * u)
@@ -399,28 +399,32 @@ pulse_get_backend_id(cubeb * ctx)
   return "pulse";
 }
 
 static int
 pulse_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
 {
   assert(ctx && max_channels);
 
+  WRAP(pa_threaded_mainloop_lock)(ctx->mainloop);
   while (!ctx->default_sink_info) {
     WRAP(pa_threaded_mainloop_wait)(ctx->mainloop);
   }
+  WRAP(pa_threaded_mainloop_unlock)(ctx->mainloop);
 
   *max_channels = ctx->default_sink_info->channel_map.channels;
 
   return CUBEB_OK;
 }
 
 static int
 pulse_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
 {
+  assert(ctx && rate);
+
   WRAP(pa_threaded_mainloop_lock)(ctx->mainloop);
   while (!ctx->default_sink_info) {
     WRAP(pa_threaded_mainloop_wait)(ctx->mainloop);
   }
   WRAP(pa_threaded_mainloop_unlock)(ctx->mainloop);
 
   *rate = ctx->default_sink_info->sample_spec.rate;
 
--- a/media/libcubeb/tests/test_latency.cpp
+++ b/media/libcubeb/tests/test_latency.cpp
@@ -1,39 +1,48 @@
 #ifdef NDEBUG
 #undef NDEBUG
 #endif
 #include <stdlib.h>
 #include <cubeb/cubeb.h>
 #include <assert.h>
+#include <stdio.h>
+
+#define LOG(msg) fprintf(stderr, "%s\n", msg);
 
 int main(int argc, char * argv[])
 {
   cubeb * ctx = NULL;
   int rv;
   uint32_t max_channels;
   uint32_t preferred_rate;
   uint32_t latency_ms;
 
+  LOG("latency_test start");
   rv = cubeb_init(&ctx, "Cubeb audio test");
   assert(rv == CUBEB_OK && "Cubeb init failed.");
+  LOG("cubeb_init ok");
 
   rv = cubeb_get_max_channel_count(ctx, &max_channels);
   assert(rv == CUBEB_OK && "Could not query the max channe count.");
   assert(max_channels > 0 && "Invalid max channel count.");
+  LOG("cubeb_get_max_channel_count ok");
 
   rv = cubeb_get_preferred_sample_rate(ctx, &preferred_rate);
   assert(rv == CUBEB_OK && "Could not query the preferred sample rate.");
   assert(preferred_rate && "Invalid preferred sample rate.");
+  LOG("cubeb_get_preferred_sample_rate ok");
 
   cubeb_stream_params params = {
     CUBEB_SAMPLE_FLOAT32NE,
     preferred_rate,
     max_channels
   };
   rv = cubeb_get_min_latency(ctx, params, &latency_ms);
   assert(rv == CUBEB_OK && "Could not query the minimal latency.");
   assert(latency_ms && "Invalid minimal latency.");
+  LOG("cubeb_get_min_latency ok");
 
   cubeb_destroy(ctx);
+  LOG("cubeb_destroy ok");
 
   return EXIT_SUCCESS;
 }
--- a/media/webrtc/signaling/signaling.gyp
+++ b/media/webrtc/signaling/signaling.gyp
@@ -52,16 +52,17 @@
         './src/sipcc/cpr/include',
         '../../../ipc/chromium/src',
         '../../../ipc/chromium/src/base/third_party/nspr',
         '../../../xpcom/base',
         '../../../dom/base',
         '../../../content/media',
         '../../../media/mtransport',
         '../trunk',
+        '../trunk/webrtc',
         '../trunk/webrtc/video_engine/include',
         '../trunk/webrtc/voice_engine/include',
         '../trunk/webrtc/modules/interface',
         '../trunk/webrtc/peerconnection',
         '../../libyuv/include',
         '../../../netwerk/srtp/src/include',
         '../../../netwerk/srtp/src/crypto/include',
         '../../../ipc/chromium/src',
@@ -186,16 +187,36 @@
         '$(NSS_CFLAGS)',
         '$(MOZ_PIXMAN_CFLAGS)',
       ],
 
       #
       # Conditionals
       #
       'conditions': [
+        ['moz_omx_encoder==1', {
+          'sources': [
+            './src/media-conduit/WebrtcOMXH264VideoCodec.cpp',
+            './src/media-conduit/OMXVideoCodec.cpp',
+          ],
+          'include_dirs': [
+            '../../../content/media/omx',
+            '../../../gfx/layers/client',
+          ],
+          'cflags_mozilla': [
+            '-I$(ANDROID_SOURCE)/frameworks/av/include/media/stagefright',
+            '-I$(ANDROID_SOURCE)/frameworks/av/include',
+            '-I$(ANDROID_SOURCE)/frameworks/native/include/media/openmax',
+            '-I$(ANDROID_SOURCE)/frameworks/native/include',
+            '-I$(ANDROID_SOURCE)/frameworks/native/opengl/include',
+          ],
+          'defines' : [
+            'MOZ_OMX_ENCODER'
+          ],
+        }],
         ['build_for_test==0', {
           'defines' : [
             'MOZILLA_INTERNAL_API'
           ],
           'sources': [
             './src/peerconnection/WebrtcGlobalInformation.cpp',
             './src/peerconnection/WebrtcGlobalInformation.h',
           ],
--- a/media/webrtc/signaling/src/media-conduit/CodecConfig.h
+++ b/media/webrtc/signaling/src/media-conduit/CodecConfig.h
@@ -73,31 +73,43 @@ struct VideoCodecConfig
                    LoadManager* load_manager = nullptr) :
                                      mType(type),
                                      mName(name),
                                      mRtcpFbTypes(rtcpFbTypes),
                                      mMaxFrameSize(0),
                                      mMaxFrameRate(0),
                                      mLoadManager(load_manager)
   {
+    // Replace codec name here because  WebRTC.org code has a whitelist of
+    // supported video codec in |webrtc::ViECodecImpl::CodecValid()| and will
+    // reject registration of those not in it.
+    // TODO: bug 995884 to support H.264 in WebRTC.org code.
+    if (mName == "H264_P0")
+      mName = "I420";
   }
 
   VideoCodecConfig(int type,
                    std::string name,
                    int rtcpFbTypes,
                    unsigned int max_fs,
                    unsigned int max_fr,
                    LoadManager* load_manager = nullptr) :
                                          mType(type),
                                          mName(name),
                                          mRtcpFbTypes(rtcpFbTypes),
                                          mMaxFrameSize(max_fs),
                                          mMaxFrameRate(max_fr),
                                          mLoadManager(load_manager)
   {
+    // Replace codec name here because  WebRTC.org code has a whitelist of
+    // supported video codec in |webrtc::ViECodecImpl::CodecValid()| and will
+    // reject registration of those not in it.
+    // TODO: bug 995884 to support H.264 in WebRTC.org code.
+    if (mName == "H264_P0")
+      mName = "I420";
   }
 
 
   bool RtcpFbIsSet(sdp_rtcp_fb_nack_type_e type) const
   {
     return mRtcpFbTypes & sdp_rtcp_fb_nack_to_bitmap(type);
   }
 
--- a/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h
+++ b/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h
@@ -8,16 +8,18 @@
 #include "nsISupportsImpl.h"
 #include "nsXPCOM.h"
 #include "nsDOMNavigationTiming.h"
 #include "mozilla/RefPtr.h"
 #include "CodecConfig.h"
 #include "VideoTypes.h"
 #include "MediaConduitErrors.h"
 
+#include "ImageContainer.h"
+
 #include <vector>
 
 namespace mozilla {
 /**
  * Abstract Interface for transporting RTP packets - audio/vidoeo
  * The consumers of this interface are responsible for passing in
  * the RTPfied media packets
  */
@@ -39,16 +41,30 @@ public:
    * @param data : RTCP Packet to be transported
    * @param len  : Length of the RTCP packet
    * @result     : NS_OK on success, NS_ERROR_FAILURE otherwise
    */
   virtual nsresult SendRtcpPacket(const void* data, int len) = 0;
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TransportInterface)
 };
 
+/**
+ * This class wraps image object for VideoRenderer::RenderVideoFrame()
+ * callback implementation to use for rendering.
+ */
+class ImageHandle
+{
+public:
+  ImageHandle(layers::Image* image) : mImage(image) {}
+
+  const RefPtr<layers::Image>& GetImage() const { return mImage; }
+
+private:
+  RefPtr<layers::Image> mImage;
+};
 
 /**
  * 1. Abstract renderer for video data
  * 2. This class acts as abstract interface between the video-engine and
  *    video-engine agnostic renderer implementation.
  * 3. Concrete implementation of this interface is responsible for
  *    processing and/or rendering the obtained raw video frame to appropriate
  *    output , say, <video>
@@ -70,26 +86,31 @@ class VideoRenderer
 
   /**
    * Callback Function reporting decoded I420 frame for processing.
    * @param buffer: pointer to decoded video frame
    * @param buffer_size: size of the decoded frame
    * @param time_stamp: Decoder timestamp, typically 90KHz as per RTP
    * @render_time: Wall-clock time at the decoder for synchronization
    *                purposes in milliseconds
-   * NOTE: It is the responsibility of the concrete implementations of this
-   * class to own copy of the frame if needed for time longer than scope of
-   * this callback.
+   * @handle: opaque handle for image object of decoded video frame.
+   * NOTE: If decoded video frame is passed through buffer , it is the
+   * responsibility of the concrete implementations of this class to own copy
+   * of the frame if needed for time longer than scope of this callback.
    * Such implementations should be quick in processing the frames and return
    * immediately.
+   * On the other hand, if decoded video frame is passed through handle, the
+   * implementations should keep a reference to the (ref-counted) image object
+   * inside until it's no longer needed.
    */
   virtual void RenderVideoFrame(const unsigned char* buffer,
                                 unsigned int buffer_size,
                                 uint32_t time_stamp,
-                                int64_t render_time) = 0;
+                                int64_t render_time,
+                                const ImageHandle& handle) = 0;
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoRenderer)
 };
 
 
 /**
  * Generic Interface for representing Audio/Video Session
  * MediaSession conduit is identified by 2 main components
@@ -157,16 +178,28 @@ public:
   virtual bool GetRTCPSenderReport(DOMHighResTimeStamp* timestamp,
                                    unsigned int* packetsSent,
                                    uint64_t* bytesSent) = 0;
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaSessionConduit)
 
 };
 
+// Abstract base classes for external encoder/decoder.
+class VideoEncoder
+{
+public:
+  virtual ~VideoEncoder() {};
+};
+
+class VideoDecoder
+{
+public:
+  virtual ~VideoDecoder() {};
+};
 
 /**
  * MediaSessionConduit for video
  * Refer to the comments on MediaSessionConduit above for overall
  * information
  */
 class VideoSessionConduit : public MediaSessionConduit
 {
@@ -236,16 +269,31 @@ public:
    * @param sendSessionConfig: CodecConfiguration
    * NOTE: This API can be invoked multiple time. Invoking this API may involve restarting
    *        reception sub-system on the engine
    *
    */
   virtual MediaConduitErrorCode ConfigureRecvMediaCodecs(
                                 const std::vector<VideoCodecConfig* >& recvCodecConfigList) = 0;
 
+  /**
+   * Set an external encoder
+   * @param encoder
+   * @result: on success, we will use the specified encoder
+   */
+  virtual MediaConduitErrorCode SetExternalSendCodec(int pltype,
+                                                     VideoEncoder* encoder) = 0;
+
+  /**
+   * Set an external decoder
+   * @param decoder
+   * @result: on success, we will use the specified decoder
+   */
+  virtual MediaConduitErrorCode SetExternalRecvCodec(int pltype,
+                                                     VideoDecoder* decoder) = 0;
 
   /**
    * These methods allow unit tests to double-check that the
    * max-fs and max-fr related settings are as expected.
    */
   virtual unsigned short SendingWidth() = 0;
 
   virtual unsigned short SendingHeight() = 0;
@@ -356,12 +404,8 @@ public:
     * @param id: id to be used for this rtp header extension
     * NOTE: See AudioConduit for more information
     */
   virtual MediaConduitErrorCode EnableAudioLevelExtension(bool enabled, uint8_t id) = 0;
 
 };
 }
 #endif
-
-
-
-
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/media-conduit/OMXVideoCodec.cpp
@@ -0,0 +1,30 @@
+/* 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 "OMXVideoCodec.h"
+
+#ifdef WEBRTC_GONK
+#include "WebrtcOMXH264VideoCodec.h"
+#endif
+
+namespace mozilla {
+
+VideoEncoder*
+OMXVideoCodec::CreateEncoder(CodecType aCodecType)
+{
+  if (aCodecType == CODEC_H264) {
+    return new WebrtcOMXH264VideoEncoder();
+  }
+  return nullptr;
+}
+
+VideoDecoder*
+OMXVideoCodec::CreateDecoder(CodecType aCodecType) {
+  if (aCodecType == CODEC_H264) {
+    return new WebrtcOMXH264VideoDecoder();
+  }
+  return nullptr;
+}
+
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/media-conduit/OMXVideoCodec.h
@@ -0,0 +1,32 @@
+/* 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 OMX_VIDEO_CODEC_H_
+#define OMX_VIDEO_CODEC_H_
+
+#include "MediaConduitInterface.h"
+
+namespace mozilla {
+class OMXVideoCodec {
+ public:
+  enum CodecType {
+    CODEC_H264,
+  };
+
+  /**
+   * Create encoder object for codec type |aCodecType|. Return |nullptr| when
+   * failed.
+   */
+  static VideoEncoder* CreateEncoder(CodecType aCodecType);
+
+  /**
+   * Create decoder object for codec type |aCodecType|. Return |nullptr| when
+   * failed.
+   */
+  static VideoDecoder* CreateDecoder(CodecType aCodecType);
+};
+
+}
+
+#endif // OMX_VIDEO_CODEC_H_
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -9,16 +9,17 @@
 #include "ccsdp.h"
 
 #include "VideoConduit.h"
 #include "AudioConduit.h"
 #include "nsThreadUtils.h"
 
 #include "LoadManager.h"
 
+#include "webrtc/common_video/interface/native_handle.h"
 #include "webrtc/video_engine/include/vie_errors.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidJNIWrapper.h"
 #endif
 
 #include <algorithm>
 #include <math.h>
@@ -120,16 +121,17 @@ WebrtcVideoConduit::~WebrtcVideoConduit(
     // We can't delete the VideoEngine until all these are released!
     // And we can't use a Scoped ptr, since the order is arbitrary
     mPtrViEBase = nullptr;
     mPtrViECapture = nullptr;
     mPtrViECodec = nullptr;
     mPtrViENetwork = nullptr;
     mPtrViERender = nullptr;
     mPtrRTP = nullptr;
+    mPtrExtCodec = nullptr;
 
     // only one opener can call Delete.  Have it be the last to close.
     if(mVideoEngine)
     {
       webrtc::VideoEngine::Delete(mVideoEngine);
     }
   }
 }
@@ -279,16 +281,23 @@ MediaConduitErrorCode WebrtcVideoConduit
   }
 
   if( !(mPtrRTP = webrtc::ViERTP_RTCP::GetInterface(mVideoEngine)))
   {
     CSFLogError(logTag, "%s Unable to get video RTCP interface ", __FUNCTION__);
     return kMediaConduitSessionNotInited;
   }
 
+  if ( !(mPtrExtCodec = webrtc::ViEExternalCodec::GetInterface(mVideoEngine)))
+  {
+    CSFLogError(logTag, "%s Unable to get external codec interface %d ",
+                __FUNCTION__, mPtrViEBase->LastError());
+    return kMediaConduitSessionNotInited;
+  }
+
   if (other) {
     mChannel = other->mChannel;
     mPtrExtCapture = other->mPtrExtCapture;
     mCapId = other->mCapId;
   } else {
     CSFLogDebug(logTag, "%s Engine Created: Init'ng the interfaces ",__FUNCTION__);
 
     if(mPtrViEBase->Init() == -1)
@@ -840,16 +849,35 @@ WebrtcVideoConduit::SelectSendResolution
       CSFLogDebug(logTag, "%s: Encoder resolution changed to %ux%u",
                   __FUNCTION__, width, height);
     } // else no change; mSendingWidth likely was 0
   }
   return true;
 }
 
 MediaConduitErrorCode
+WebrtcVideoConduit::SetExternalSendCodec(int pltype,
+                                         VideoEncoder* encoder) {
+  int ret = mPtrExtCodec->RegisterExternalSendCodec(mChannel,
+                                                    pltype,
+                                                    static_cast<WebrtcVideoEncoder*>(encoder),
+                                                    false);
+  return ret ? kMediaConduitInvalidSendCodec : kMediaConduitNoError;
+}
+
+MediaConduitErrorCode
+WebrtcVideoConduit::SetExternalRecvCodec(int pltype,
+                                         VideoDecoder* decoder) {
+  int ret = mPtrExtCodec->RegisterExternalReceiveCodec(mChannel,
+                                                       pltype,
+                                                       static_cast<WebrtcVideoDecoder*>(decoder));
+  return ret ? kMediaConduitInvalidReceiveCodec : kMediaConduitNoError;
+}
+
+MediaConduitErrorCode
 WebrtcVideoConduit::SendVideoFrame(unsigned char* video_frame,
                                    unsigned int video_frame_length,
                                    unsigned short width,
                                    unsigned short height,
                                    VideoType video_type,
                                    uint64_t capture_time)
 {
   CSFLogDebug(logTag,  "%s ", __FUNCTION__);
@@ -1038,17 +1066,27 @@ WebrtcVideoConduit::DeliverFrame(unsigne
                                  uint32_t time_stamp,
                                  int64_t render_time,
                                  void *handle)
 {
   CSFLogDebug(logTag,  "%s Buffer Size %d", __FUNCTION__, buffer_size);
 
   if(mRenderer)
   {
-    mRenderer->RenderVideoFrame(buffer, buffer_size, time_stamp, render_time);
+    layers::Image* img = nullptr;
+    // |handle| should be a webrtc::NativeHandle if available.
+    if (handle) {
+      webrtc::NativeHandle* native_h = static_cast<webrtc::NativeHandle*>(handle);
+      // In the handle, there should be a layers::Image.
+      img = static_cast<layers::Image*>(native_h->GetHandle());
+    }
+
+    const ImageHandle img_h(img);
+    mRenderer->RenderVideoFrame(buffer, buffer_size, time_stamp, render_time,
+                                img_h);
     return 0;
   }
 
   CSFLogError(logTag,  "%s Renderer is NULL  ", __FUNCTION__);
   return -1;
 }
 
 /**
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.h
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.h
@@ -7,39 +7,54 @@
 
 #include "mozilla/Attributes.h"
 
 #include "MediaConduitInterface.h"
 #include "MediaEngineWrapper.h"
 
 // Video Engine Includes
 #include "webrtc/common_types.h"
+#ifdef FF
+#undef FF // Avoid name collision between scoped_ptr.h and nsCRTGlue.h.
+#endif
+#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
 #include "webrtc/video_engine/include/vie_base.h"
 #include "webrtc/video_engine/include/vie_capture.h"
 #include "webrtc/video_engine/include/vie_codec.h"
+#include "webrtc/video_engine/include/vie_external_codec.h"
 #include "webrtc/video_engine/include/vie_render.h"
 #include "webrtc/video_engine/include/vie_network.h"
 #include "webrtc/video_engine/include/vie_rtp_rtcp.h"
 
 /** This file hosts several structures identifying different aspects
  * of a RTP Session.
  */
 
  using  webrtc::ViEBase;
  using  webrtc::ViENetwork;
  using  webrtc::ViECodec;
  using  webrtc::ViECapture;
  using  webrtc::ViERender;
  using  webrtc::ViEExternalCapture;
-
+ using  webrtc::ViEExternalCodec;
 
 namespace mozilla {
 
 class WebrtcAudioConduit;
 
+// Interface of external video encoder for WebRTC.
+class WebrtcVideoEncoder:public VideoEncoder
+                         ,public webrtc::VideoEncoder
+{};
+
+// Interface of external video decoder for WebRTC.
+class WebrtcVideoDecoder:public VideoDecoder
+                         ,public webrtc::VideoDecoder
+{};
+
 /**
  * Concrete class for Video session. Hooks up
  *  - media-source and target to external transport
  */
 class WebrtcVideoConduit:public VideoSessionConduit
                          ,public webrtc::Transport
                          ,public webrtc::ExternalRenderer
 {
@@ -122,16 +137,29 @@ public:
    */
   virtual MediaConduitErrorCode SendVideoFrame(unsigned char* video_frame,
                                                 unsigned int video_frame_length,
                                                 unsigned short width,
                                                 unsigned short height,
                                                 VideoType video_type,
                                                 uint64_t capture_time);
 
+  /**
+   * Set an external encoder object |encoder| to the payload type |pltype|
+   * for sender side codec.
+   */
+  virtual MediaConduitErrorCode SetExternalSendCodec(int pltype,
+                                                     VideoEncoder* encoder);
+
+  /**
+   * Set an external decoder object |decoder| to the payload type |pltype|
+   * for receiver side codec.
+   */
+  virtual MediaConduitErrorCode SetExternalRecvCodec(int pltype,
+                                                     VideoDecoder* decoder);
 
 
   /**
    * Webrtc transport implementation to send and receive RTP packet.
    * VideoConduit registers itself as ExternalTransport to the VideoEngine
    */
   virtual int SendPacket(int channel, const void *data, int len) ;
 
@@ -149,19 +177,26 @@ public:
   virtual int FrameSizeChange(unsigned int, unsigned int, unsigned int);
 
   virtual int DeliverFrame(unsigned char*,int, uint32_t , int64_t,
                            void *handle);
 
   /**
    * Does DeliverFrame() support a null buffer and non-null handle
    * (video texture)?
-   * XXX Investigate!  Especially for Android/B2G
+   * B2G support it (when using HW video decoder with graphic buffer output).
+   * XXX Investigate!  Especially for Android
    */
-  virtual bool IsTextureSupported() { return false; }
+  virtual bool IsTextureSupported() {
+#ifdef WEBRTC_GONK
+    return true;
+#else
+    return false;
+#endif
+  }
 
   unsigned short SendingWidth() {
     return mSendingWidth;
   }
 
   unsigned short SendingHeight() {
     return mSendingHeight;
   }
@@ -260,16 +295,17 @@ private:
   mozilla::RefPtr<VideoRenderer> mRenderer;
 
   ScopedCustomReleasePtr<webrtc::ViEBase> mPtrViEBase;
   ScopedCustomReleasePtr<webrtc::ViECapture> mPtrViECapture;
   ScopedCustomReleasePtr<webrtc::ViECodec> mPtrViECodec;
   ScopedCustomReleasePtr<webrtc::ViENetwork> mPtrViENetwork;
   ScopedCustomReleasePtr<webrtc::ViERender> mPtrViERender;
   ScopedCustomReleasePtr<webrtc::ViERTP_RTCP> mPtrRTP;
+  ScopedCustomReleasePtr<webrtc::ViEExternalCodec> mPtrExtCodec;
 
   webrtc::ViEExternalCapture* mPtrExtCapture; // shared
 
   // Engine state we are concerned with.
   bool mEngineTransmitting; //If true ==> Transmit Sub-system is up and running
   bool mEngineReceiving;    // if true ==> Receive Sus-sysmtem up and running
 
   int mChannel; // Video Channel for this conduit
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp
@@ -0,0 +1,875 @@
+/* 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 "CSFLog.h"
+
+#include "WebrtcOMXH264VideoCodec.h"
+
+// Android/Stagefright
+#include <avc_utils.h>
+#include <binder/ProcessState.h>
+#include <foundation/ABuffer.h>
+#include <foundation/AMessage.h>
+#include <gui/Surface.h>
+#include <media/ICrypto.h>
+#include <MediaCodec.h>
+#include <MediaDefs.h>
+#include <MediaErrors.h>
+#include <MetaData.h>
+#include <OMX_Component.h>
+using namespace android;
+
+// WebRTC
+#include "common_video/interface/texture_video_frame.h"
+#include "video_engine/include/vie_external_codec.h"
+
+// Gecko
+#include "GonkNativeWindow.h"
+#include "GonkNativeWindowClient.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/Mutex.h"
+#include "nsThreadUtils.h"
+#include "OMXCodecWrapper.h"
+#include "TextureClient.h"
+
+#define DEQUEUE_BUFFER_TIMEOUT_US (100 * 1000ll) // 100ms.
+#define START_DEQUEUE_BUFFER_TIMEOUT_US (10 * DEQUEUE_BUFFER_TIMEOUT_US) // 1s.
+#define DRAIN_THREAD_TIMEOUT_US  (1000 * 1000ll) // 1s.
+
+#define LOG_TAG "WebrtcOMXH264VideoCodec"
+#define CODEC_LOGV(...) CSFLogInfo(LOG_TAG, __VA_ARGS__)
+#define CODEC_LOGD(...) CSFLogDebug(LOG_TAG, __VA_ARGS__)
+#define CODEC_LOGI(...) CSFLogInfo(LOG_TAG, __VA_ARGS__)
+#define CODEC_LOGW(...) CSFLogWarn(LOG_TAG, __VA_ARGS__)
+#define CODEC_LOGE(...) CSFLogError(LOG_TAG, __VA_ARGS__)
+
+namespace mozilla {
+
+// NS_INLINE_DECL_THREADSAFE_REFCOUNTING() cannot be used directly in
+// ImageNativeHandle below because the return type of webrtc::NativeHandle
+// AddRef()/Release() conflicts with those defined in macro. To avoid another
+// copy/paste of ref-counting implementation here, this dummy base class
+// is created to proivde another level of indirection.
+class DummyRefCountBase {
+public:
+  // Use the name of real class for logging.
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageNativeHandle)
+  // To make sure subclass will be deleted/destructed properly.
+  virtual ~DummyRefCountBase() {}
+};
+
+// This function implements 2 interafces:
+// 1. webrtc::NativeHandle: to wrap layers::Image object so decoded frames can
+//    be passed through WebRTC rendering pipeline using TextureVideoFrame.
+// 2. ImageHandle: for renderer to get the image object inside without knowledge
+//    about webrtc::NativeHandle.
+class ImageNativeHandle MOZ_FINAL
+  : public webrtc::NativeHandle
+  , public DummyRefCountBase
+{
+public:
+  ImageNativeHandle(layers::Image* aImage)
+    : mImage(aImage)
+  {}
+
+  // Implement webrtc::NativeHandle.
+  virtual void* GetHandle() MOZ_OVERRIDE { return mImage.get(); }
+
+  virtual int AddRef() MOZ_OVERRIDE
+  {
+    return DummyRefCountBase::AddRef();
+  }
+
+  virtual int Release() MOZ_OVERRIDE
+  {
+    return DummyRefCountBase::Release();
+  }
+
+private:
+  RefPtr<layers::Image> mImage;
+};
+
+// Graphic buffer lifecycle management.
+// Return buffer to OMX codec when renderer is done with it.
+class RecycleCallback
+{
+public:
+  RecycleCallback(const sp<MediaCodec>& aOmx, uint32_t aBufferIndex)
+    : mOmx(aOmx)
+    , mBufferIndex(aBufferIndex)
+  {}
+  typedef void* CallbackPtr;
+  static void ReturnOMXBuffer(layers::TextureClient* aClient, CallbackPtr aClosure)
+  {
+    aClient->ClearRecycleCallback();
+    RecycleCallback* self = static_cast<RecycleCallback*>(aClosure);
+    self->mOmx->releaseOutputBuffer(self->mBufferIndex);
+    delete self;
+  }
+
+private:
+  sp<MediaCodec> mOmx;
+  uint32_t mBufferIndex;
+};
+
+struct EncodedFrame
+{
+  uint32_t mWidth;
+  uint32_t mHeight;
+  uint32_t mTimestamp;
+  int64_t mRenderTimeMs;
+};
+
+// Base runnable class to repeatly pull OMX output buffers in seperate thread.
+// How to use:
+// - implementing DrainOutput() to get output. Remember to return false to tell
+//   drain not to pop input queue.
+// - call QueueInput() to schedule a run to drain output. The input, aFrame,
+//   should contains corresponding info such as image size and timestamps for
+//   DrainOutput() implementation to construct data needed by encoded/decoded
+//   callbacks.
+// TODO: Bug 997110 - Revisit queue/drain logic. Current design assumes that
+//       encoder only generate one output buffer per input frame and won't work
+//       if encoder drops frames or generates multiple output per input.
+class OMXOutputDrain : public nsRunnable
+{
+public:
+  void Start() {
+    MonitorAutoLock lock(mMonitor);
+    if (mThread == nullptr) {
+      NS_NewNamedThread("OMXOutputDrain", getter_AddRefs(mThread));
+    }
+    CODEC_LOGD("OMXOutputDrain started");
+    mEnding = false;
+    mThread->Dispatch(this, NS_DISPATCH_NORMAL);
+  }
+
+  void Stop() {
+    MonitorAutoLock lock(mMonitor);
+    mEnding = true;
+    lock.NotifyAll(); // In case Run() is waiting.
+
+    if (mThread != nullptr) {
+      mThread->Shutdown();
+      mThread = nullptr;
+    }
+    CODEC_LOGD("OMXOutputDrain stopped");
+  }
+
+  void QueueInput(const EncodedFrame& aFrame)
+  {
+    MonitorAutoLock lock(mMonitor);
+
+    MOZ_ASSERT(mThread);
+
+    mInputFrames.push(aFrame);
+    // Notify Run() about queued input and it can start working.
+    lock.NotifyAll();
+  }
+
+  NS_IMETHODIMP Run() MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(mThread);
+
+    MonitorAutoLock lock(mMonitor);
+    while (true) {
+      if (mInputFrames.empty()) {
+        ALOGE("Waiting OMXOutputDrain");
+        // Wait for new input.
+        lock.Wait();
+      }
+
+      if (mEnding) {
+        ALOGE("Ending OMXOutputDrain");
+        // Stop draining.
+        break;
+      }
+
+      MOZ_ASSERT(!mInputFrames.empty());
+      EncodedFrame frame = mInputFrames.front();
+      bool shouldPop = false;
+      {
+        // Release monitor while draining because it's blocking.
+        MonitorAutoUnlock unlock(mMonitor);
+        // |frame| provides size and time of corresponding input.
+        shouldPop = DrainOutput(frame);
+      }
+      if (shouldPop) {
+        mInputFrames.pop();
+      }
+    }
+
+    CODEC_LOGD("OMXOutputDrain Ended");
+    return NS_OK;
+  }
+
+protected:
+  OMXOutputDrain()
+    : mMonitor("OMXOutputDrain monitor")
+    , mEnding(false)
+  {}
+
+  // Drain output buffer for input frame aFrame.
+  // aFrame contains info such as size and time of the input frame and can be
+  // used to construct data for encoded/decoded callbacks if needed.
+  // Return true to indicate we should pop input queue, and return false to
+  // indicate aFrame should not be removed from input queue (either output is
+  // not ready yet and should try again later, or the drained output is SPS/PPS
+  // NALUs that has no corresponding input in queue).
+  virtual bool DrainOutput(const EncodedFrame& aFrame) = 0;
+
+private:
+  // This monitor protects all things below it, and is also used to
+  // wait/notify queued input.
+  Monitor mMonitor;
+  nsCOMPtr<nsIThread> mThread;
+  std::queue<EncodedFrame> mInputFrames;
+  bool mEnding;
+};
+
+// H.264 decoder using stagefright.
+class WebrtcOMXDecoder MOZ_FINAL
+{
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebrtcOMXDecoder)
+public:
+  WebrtcOMXDecoder(const char* aMimeType)
+    : mWidth(0)
+    , mHeight(0)
+    , mStarted(false)
+  {
+    // Create binder thread pool required by stagefright.
+    android::ProcessState::self()->startThreadPool();
+
+    mLooper = new ALooper;
+    mLooper->start();
+    mCodec = MediaCodec::CreateByType(mLooper, aMimeType, false /* encoder */);
+  }
+
+  virtual ~WebrtcOMXDecoder()
+  {
+    if (mStarted) {
+      Stop();
+    }
+    if (mCodec != nullptr) {
+      mCodec->release();
+      mCodec.clear();
+    }
+    mLooper.clear();
+  }
+
+  // Parse SPS/PPS NALUs.
+  static sp<MetaData> ParseParamSets(sp<ABuffer>& aParamSets)
+  {
+    return MakeAVCCodecSpecificData(aParamSets);
+  }
+
+  // Configure decoder using data returned by ParseParamSets().
+  status_t ConfigureWithParamSets(const sp<MetaData>& aParamSets)
+  {
+    MOZ_ASSERT(mCodec != nullptr);
+    if (mCodec == nullptr) {
+      return INVALID_OPERATION;
+    }
+
+    int32_t width = 0;
+    bool ok = aParamSets->findInt32(kKeyWidth, &width);
+    MOZ_ASSERT(ok && width > 0);
+    int32_t height = 0;
+    ok = aParamSets->findInt32(kKeyHeight, &height);
+    MOZ_ASSERT(ok && height > 0);
+    CODEC_LOGD("OMX:%p decoder config width:%d height:%d", this, width, height);
+
+    sp<AMessage> config = new AMessage();
+    config->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
+    config->setInt32("width", width);
+    config->setInt32("height", height);
+    mWidth = width;
+    mHeight = height;
+
+    sp<Surface> surface = nullptr;
+    mNativeWindow = new GonkNativeWindow();
+    if (mNativeWindow.get()) {
+      mNativeWindowClient = new GonkNativeWindowClient(mNativeWindow->getBufferQueue());
+      if (mNativeWindowClient.get()) {
+        surface = new Surface(mNativeWindowClient->getIGraphicBufferProducer());
+      }
+    }
+    status_t result = mCodec->configure(config, surface, nullptr, 0);
+    if (result == OK) {
+      result = Start();
+    }
+    return result;
+  }
+
+  status_t
+  FillInput(const webrtc::EncodedImage& aEncoded, bool aIsFirstFrame,
+            int64_t& aRenderTimeMs, webrtc::DecodedImageCallback* aCallback)
+  {
+    MOZ_ASSERT(mCodec != nullptr);
+    if (mCodec == nullptr) {
+      return INVALID_OPERATION;
+    }
+
+    size_t index;
+    status_t err = mCodec->dequeueInputBuffer(&index,
+      aIsFirstFrame ? START_DEQUEUE_BUFFER_TIMEOUT_US : DEQUEUE_BUFFER_TIMEOUT_US);
+    if (err != OK) {
+      CODEC_LOGE("decode dequeue input buffer error:%d", err);
+      return err;
+    }
+
+    uint32_t flags = 0;
+    if (aEncoded._frameType == webrtc::kKeyFrame) {
+      flags = aIsFirstFrame ? MediaCodec::BUFFER_FLAG_CODECCONFIG : MediaCodec::BUFFER_FLAG_SYNCFRAME;
+    }
+    size_t size = aEncoded._length;
+    MOZ_ASSERT(size);
+    const sp<ABuffer>& omxIn = mInputBuffers.itemAt(index);
+    MOZ_ASSERT(omxIn->capacity() >= size);
+    omxIn->setRange(0, size);
+    // Copying is needed because MediaCodec API doesn't support externallay
+    // allocated buffer as input.
+    memcpy(omxIn->data(), aEncoded._buffer, size);
+    int64_t inputTimeUs = aEncoded._timeStamp * 1000 / 90; // 90kHz -> us.
+    err = mCodec->queueInputBuffer(index, 0, size, inputTimeUs, flags);
+    if (err == OK && !(flags & MediaCodec::BUFFER_FLAG_CODECCONFIG)) {
+      if (mOutputDrain == nullptr) {
+        mOutputDrain = new OutputDrain(this, aCallback);
+        mOutputDrain->Start();
+      }
+      EncodedFrame frame;
+      frame.mWidth = mWidth;
+      frame.mHeight = mHeight;
+      frame.mTimestamp = aEncoded._timeStamp;
+      frame.mRenderTimeMs = aRenderTimeMs;
+      mOutputDrain->QueueInput(frame);
+    }
+
+    return err;
+  }
+
+  status_t
+  DrainOutput(const EncodedFrame& aFrame, webrtc::DecodedImageCallback* aCallback)
+  {
+    MOZ_ASSERT(mCodec != nullptr);
+    if (mCodec == nullptr) {
+      return INVALID_OPERATION;
+    }
+
+    size_t index = 0;
+    size_t outOffset = 0;
+    size_t outSize = 0;
+    int64_t outTime = -1ll;
+    uint32_t outFlags = 0;
+    status_t err = mCodec->dequeueOutputBuffer(&index, &outOffset, &outSize,
+                                               &outTime, &outFlags,
+                                               DRAIN_THREAD_TIMEOUT_US);
+    switch (err) {
+      case OK:
+        break;
+      case -EAGAIN:
+        // Not an error: output not available yet. Try later.
+        CODEC_LOGI("decode dequeue OMX output buffer timed out. Try later.");
+        return err;
+      case INFO_FORMAT_CHANGED:
+        // Not an error: will get this value when OMX output buffer is enabled,
+        // or when input size changed.
+        CODEC_LOGD("decode dequeue OMX output buffer format change");
+        return err;
+      case INFO_OUTPUT_BUFFERS_CHANGED:
+        // Not an error: will get this value when OMX output buffer changed
+        // (probably because of input size change).
+        CODEC_LOGD("decode dequeue OMX output buffer change");
+        err = mCodec->getOutputBuffers(&mOutputBuffers);
+        MOZ_ASSERT(err == OK);
+        return INFO_OUTPUT_BUFFERS_CHANGED;
+      default:
+        CODEC_LOGE("decode dequeue OMX output buffer error:%d", err);
+        // Return OK to instruct OutputDrain to drop input from queue.
+        return OK;
+    }
+
+    sp<ABuffer> omxOut = mOutputBuffers.itemAt(index);
+    nsAutoPtr<webrtc::I420VideoFrame> videoFrame(GenerateVideoFrame(aFrame,
+                                                                    index,
+                                                                    omxOut));
+    if (videoFrame == nullptr) {
+      mCodec->releaseOutputBuffer(index);
+    } else if (aCallback) {
+      aCallback->Decoded(*videoFrame);
+      // OMX buffer will be released by RecycleCallback after rendered.
+    }
+
+    return err;
+  }
+
+private:
+  class OutputDrain : public OMXOutputDrain
+  {
+  public:
+    OutputDrain(WebrtcOMXDecoder* aOMX, webrtc::DecodedImageCallback* aCallback)
+      : OMXOutputDrain()
+      , mOMX(aOMX)
+      , mCallback(aCallback)
+    {}
+
+  protected:
+    virtual bool DrainOutput(const EncodedFrame& aFrame) MOZ_OVERRIDE
+    {
+      return (mOMX->DrainOutput(aFrame, mCallback) == OK);
+    }
+
+  private:
+    WebrtcOMXDecoder* mOMX;
+    webrtc::DecodedImageCallback* mCallback;
+  };
+
+  status_t Start()
+  {
+    MOZ_ASSERT(!mStarted);
+    if (mStarted) {
+      return OK;
+    }
+
+    status_t err = mCodec->start();
+    if (err == OK) {
+      mStarted = true;
+      mCodec->getInputBuffers(&mInputBuffers);
+      mCodec->getOutputBuffers(&mOutputBuffers);
+    }
+
+    return err;
+  }
+
+  status_t Stop()
+  {
+    MOZ_ASSERT(mStarted);
+    if (!mStarted) {
+      return OK;
+    }
+    if (mOutputDrain != nullptr) {
+      mOutputDrain->Stop();
+      mOutputDrain = nullptr;
+    }
+
+    status_t err = mCodec->stop();
+    if (err == OK) {
+      mInputBuffers.clear();
+      mOutputBuffers.clear();
+      mStarted = false;
+    } else {
+      MOZ_ASSERT(false);
+    }
+
+    return err;
+  }
+
+  webrtc::I420VideoFrame*
+  GenerateVideoFrame(const EncodedFrame& aEncoded, uint32_t aBufferIndex,
+                     const sp<ABuffer>& aOMXBuffer)
+  {
+    // TODO: Get decoded frame buffer through native window to obsolete
+    //       changes to stagefright code.
+    sp<RefBase> obj;
+    bool hasGraphicBuffer = aOMXBuffer->meta()->findObject("graphic-buffer", &obj);
+    if (!hasGraphicBuffer) {
+      MOZ_ASSERT(false, "Decoder doesn't produce graphic buffer");
+      // Nothing to render.
+      return nullptr;
+    }
+
+    sp<GraphicBuffer> gb = static_cast<GraphicBuffer*>(obj.get());
+    if (!gb.get()) {
+      MOZ_ASSERT(false, "Null graphic buffer");
+      return nullptr;
+    }
+
+    RefPtr<mozilla::layers::TextureClient> textureClient =
+      mNativeWindow->getTextureClientFromBuffer(gb.get());
+    textureClient->SetRecycleCallback(RecycleCallback::ReturnOMXBuffer,
+                                      new RecycleCallback(mCodec, aBufferIndex));
+
+    int width = gb->getWidth();
+    int height = gb->getHeight();
+    layers::GrallocImage::GrallocData grallocData;
+    grallocData.mPicSize = gfx::IntSize(width, height);
+    grallocData.mGraphicBuffer = textureClient;
+
+    layers::GrallocImage* grallocImage = new layers::GrallocImage();
+    grallocImage->SetData(grallocData);
+
+    nsAutoPtr<webrtc::I420VideoFrame> videoFrame(
+      new webrtc::TextureVideoFrame(new ImageNativeHandle(grallocImage),
+                                    width, height,
+                                    aEncoded.mTimestamp,
+                                    aEncoded.mRenderTimeMs));
+
+    return videoFrame.forget();
+  }
+
+  sp<ALooper> mLooper;
+  sp<MediaCodec> mCodec; // OMXCodec
+  int mWidth;
+  int mHeight;
+  android::Vector<sp<ABuffer> > mInputBuffers;
+  android::Vector<sp<ABuffer> > mOutputBuffers;
+  bool mStarted;
+
+  sp<GonkNativeWindow> mNativeWindow;
+  sp<GonkNativeWindowClient> mNativeWindowClient;
+
+  RefPtr<OutputDrain> mOutputDrain;
+};
+
+class EncOutputDrain : public OMXOutputDrain
+{
+public:
+  EncOutputDrain(OMXVideoEncoder* aOMX, webrtc::EncodedImageCallback* aCallback)
+    : OMXOutputDrain()
+    , mOMX(aOMX)
+    , mCallback(aCallback)
+    , mIsPrevOutputParamSets(false)
+  {}
+
+protected:
+  virtual bool DrainOutput(const EncodedFrame& aInputFrame) MOZ_OVERRIDE
+  {
+    nsTArray<uint8_t> output;
+    int64_t timeUs = -1ll;
+    int flags = 0;
+    nsresult rv = mOMX->GetNextEncodedFrame(&output, &timeUs, &flags,
+                                            DRAIN_THREAD_TIMEOUT_US);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      // Fail to get encoded frame. The corresponding input frame should be
+      // removed.
+      return true;
+    }
+
+    if (output.Length() == 0) {
+      // No encoded data yet. Try later.
+      CODEC_LOGD("OMX:%p (encode no output available this time)", mOMX);
+      return false;
+    }
+
+    bool isParamSets = (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG);
+    bool isIFrame = (flags & MediaCodec::BUFFER_FLAG_SYNCFRAME);
+    // Should not be parameter sets and I-frame at the same time.
+    MOZ_ASSERT(!(isParamSets && isIFrame));
+
+    if (mCallback) {
+      // Implementation here assumes encoder output to be a buffer containing
+      // parameter sets(SPS + PPS) followed by a series of buffers, each for
+      // one input frame.
+      // TODO: handle output violating this assumpton in bug 997110.
+      webrtc::EncodedImage encoded(output.Elements(), output.Length(),
+                                   output.Capacity());
+      encoded._frameType = (isParamSets || isIFrame) ?
+                           webrtc::kKeyFrame : webrtc::kDeltaFrame;
+      encoded._encodedWidth = aInputFrame.mWidth;
+      encoded._encodedHeight = aInputFrame.mHeight;
+      encoded._timeStamp = aInputFrame.mTimestamp;
+      encoded.capture_time_ms_ = aInputFrame.mRenderTimeMs;
+      encoded._completeFrame = true;
+
+      ALOGE("OMX:%p encode frame type:%d size:%u", mOMX, encoded._frameType, encoded._length);
+
+      // Prepend SPS/PPS to I-frames unless they were sent last time.
+      SendEncodedDataToCallback(encoded, isIFrame && !mIsPrevOutputParamSets);
+      mIsPrevOutputParamSets = isParamSets;
+    }
+
+    // Tell base class not to pop input for parameter sets blob because they
+    // don't have corresponding input.
+    return !isParamSets;
+  }
+
+private:
+  // Send encoded data to callback.The data will be broken into individual NALUs
+  // if necessary and sent to callback one by one. This function can also insert
+  // SPS/PPS NALUs in front of input data if requested.
+  void SendEncodedDataToCallback(webrtc::EncodedImage& aEncodedImage,
+                                 bool aPrependParamSets)
+  {
+    // Individual NALU inherits metadata from input encoded data.
+    webrtc::EncodedImage nalu(aEncodedImage);
+
+    if (aPrependParamSets) {
+      // Insert current parameter sets in front of the input encoded data.
+      nsTArray<uint8_t> paramSets;
+      mOMX->GetCodecConfig(&paramSets);
+      MOZ_ASSERT(paramSets.Length() > 4); // Start code + ...
+      // Set buffer range.
+      nalu._buffer = paramSets.Elements();
+      nalu._length = paramSets.Length();
+      // Break into NALUs and send.
+      SendEncodedDataToCallback(nalu, false);
+    }
+
+    // Break input encoded data into NALUs and send each one to callback.
+    const uint8_t* data = aEncodedImage._buffer;
+    size_t size = aEncodedImage._length;
+    const uint8_t* nalStart = nullptr;
+    size_t nalSize = 0;
+    while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
+      nalu._buffer = const_cast<uint8_t*>(nalStart);
+      nalu._length = nalSize;
+      mCallback->Encoded(nalu, nullptr, nullptr);
+    }
+  }
+
+  OMXVideoEncoder* mOMX;
+  webrtc::EncodedImageCallback* mCallback;
+  bool mIsPrevOutputParamSets;
+};
+
+// Encoder.
+WebrtcOMXH264VideoEncoder::WebrtcOMXH264VideoEncoder()
+  : mOMX(nullptr)
+  , mCallback(nullptr)
+  , mWidth(0)
+  , mHeight(0)
+  , mFrameRate(0)
+  , mOMXConfigured(false)
+{
+  CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p constructed", this);
+}
+
+int32_t
+WebrtcOMXH264VideoEncoder::InitEncode(const webrtc::VideoCodec* aCodecSettings,
+                                      int32_t aNumOfCores,
+                                      uint32_t aMaxPayloadSize)
+{
+  CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p init", this);
+
+  if (mOMX == nullptr) {
+    nsAutoPtr<OMXVideoEncoder> omx(OMXCodecWrapper::CreateAVCEncoder());
+    if (NS_WARN_IF(omx == nullptr)) {
+      return WEBRTC_VIDEO_CODEC_ERROR;
+    }
+    mOMX = omx.forget();
+  }
+
+  // Defer configuration until 1st frame is received because this function will
+  // be called more than once, and unfortunately with incorrect setting values
+  // at first.
+  mWidth = aCodecSettings->width;
+  mHeight = aCodecSettings->height;
+  mFrameRate = aCodecSettings->maxFramerate;
+
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t
+WebrtcOMXH264VideoEncoder::Encode(const webrtc::I420VideoFrame& aInputImage,
+                                  const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
+                                  const std::vector<webrtc::VideoFrameType>* aFrameTypes)
+{
+  MOZ_ASSERT(mOMX != nullptr);
+  if (mOMX == nullptr) {
+    return WEBRTC_VIDEO_CODEC_ERROR;
+  }
+
+  if (!mOMXConfigured) {
+    mOMX->Configure(mWidth, mHeight, mFrameRate,
+                    OMXVideoEncoder::BlobFormat::AVC_NAL);
+    mOMXConfigured = true;
+    CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p start OMX with image size:%ux%u",
+               this, mWidth, mHeight);
+  }
+
+  // Wrap I420VideoFrame input with PlanarYCbCrImage for OMXVideoEncoder.
+  layers::PlanarYCbCrData yuvData;
+  yuvData.mYChannel = const_cast<uint8_t*>(aInputImage.buffer(webrtc::kYPlane));
+  yuvData.mYSize = gfx::IntSize(aInputImage.width(), aInputImage.height());
+  yuvData.mYStride = aInputImage.stride(webrtc::kYPlane);
+  MOZ_ASSERT(aInputImage.stride(webrtc::kUPlane) == aInputImage.stride(webrtc::kVPlane));
+  yuvData.mCbCrStride = aInputImage.stride(webrtc::kUPlane);
+  yuvData.mCbChannel = const_cast<uint8_t*>(aInputImage.buffer(webrtc::kUPlane));
+  yuvData.mCrChannel = const_cast<uint8_t*>(aInputImage.buffer(webrtc::kVPlane));
+  yuvData.mCbCrSize = gfx::IntSize((yuvData.mYSize.width + 1) / 2,
+                                   (yuvData.mYSize.height + 1) / 2);
+  yuvData.mPicSize = yuvData.mYSize;
+  yuvData.mStereoMode = StereoMode::MONO;
+  layers::PlanarYCbCrImage img(nullptr);
+  img.SetDataNoCopy(yuvData);
+
+  nsresult rv = mOMX->Encode(&img,
+                             yuvData.mYSize.width,
+                             yuvData.mYSize.height,
+                             aInputImage.timestamp() * 1000 / 90, // 90kHz -> us.
+                             0);
+  if (rv == NS_OK) {
+    if (mOutputDrain == nullptr) {
+      mOutputDrain = new EncOutputDrain(mOMX, mCallback);
+      mOutputDrain->Start();
+    }
+    EncodedFrame frame;
+    frame.mWidth = mWidth;
+    frame.mHeight = mHeight;
+    frame.mTimestamp = aInputImage.timestamp();
+    frame.mRenderTimeMs = aInputImage.render_time_ms();
+    mOutputDrain->QueueInput(frame);
+  }
+
+  return (rv == NS_OK) ? WEBRTC_VIDEO_CODEC_OK : WEBRTC_VIDEO_CODEC_ERROR;
+}
+
+int32_t
+WebrtcOMXH264VideoEncoder::RegisterEncodeCompleteCallback(
+    webrtc::EncodedImageCallback* aCallback)
+{
+  CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p set callback:%p", this, aCallback);
+  MOZ_ASSERT(aCallback);
+  mCallback = aCallback;
+
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t
+WebrtcOMXH264VideoEncoder::Release()
+{
+  CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p will be released", this);
+
+  if (mOutputDrain != nullptr) {
+    mOutputDrain->Stop();
+    mOutputDrain = nullptr;
+  }
+
+  mOMX = nullptr;
+
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+WebrtcOMXH264VideoEncoder::~WebrtcOMXH264VideoEncoder()
+{
+  CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p will be destructed", this);
+
+  Release();
+}
+
+// Inform the encoder of the new packet loss rate and the round-trip time of
+// the network. aPacketLossRate is fraction lost and can be 0~255
+// (255 means 100% lost).
+// Note: stagefright doesn't handle these parameters.
+int32_t
+WebrtcOMXH264VideoEncoder::SetChannelParameters(uint32_t aPacketLossRate,
+                                                int aRoundTripTimeMs)
+{
+  CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p set channel packet loss:%u, rtt:%d",
+             this, aPacketLossRate, aRoundTripTimeMs);
+
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+// TODO: Bug 997567. Find the way to support frame rate change.
+int32_t
+WebrtcOMXH264VideoEncoder::SetRates(uint32_t aBitRate, uint32_t aFrameRate)
+{
+  CODEC_LOGD("WebrtcOMXH264VideoEncoder:%p set bitrate:%u, frame rate:%u)",
+             this, aBitRate, aFrameRate);
+  MOZ_ASSERT(mOMX != nullptr);
+  if (mOMX == nullptr) {
+    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
+  }
+
+  mOMX->SetBitrate(aBitRate);
+
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+// Decoder.
+WebrtcOMXH264VideoDecoder::WebrtcOMXH264VideoDecoder()
+  : mCallback(nullptr)
+  , mOMX(nullptr)
+{
+  CODEC_LOGD("WebrtcOMXH264VideoDecoder:%p will be constructed", this);
+}
+
+int32_t
+WebrtcOMXH264VideoDecoder::InitDecode(const webrtc::VideoCodec* aCodecSettings,
+                                      int32_t aNumOfCores)
+{
+  CODEC_LOGD("WebrtcOMXH264VideoDecoder:%p init OMX:%p", this, mOMX.get());
+
+  // Defer configuration until SPS/PPS NALUs (where actual decoder config
+  // values can be extracted) are received.
+
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t
+WebrtcOMXH264VideoDecoder::Decode(const webrtc::EncodedImage& aInputImage,
+                                  bool aMissingFrames,
+                                  const webrtc::RTPFragmentationHeader* aFragmentation,
+                                  const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
+                                  int64_t aRenderTimeMs)
+{
+  if (aInputImage._length== 0 || !aInputImage._buffer) {
+    return WEBRTC_VIDEO_CODEC_ERROR;
+  }
+
+  ALOGE("WebrtcOMXH264VideoDecoder:%p will decode", this);
+
+  bool configured = !!mOMX;
+  if (!configured) {
+    // Search for SPS/PPS NALUs in input to get decoder config.
+    sp<ABuffer> input = new ABuffer(aInputImage._buffer, aInputImage._length);
+    sp<MetaData> paramSets = WebrtcOMXDecoder::ParseParamSets(input);
+    if (NS_WARN_IF(paramSets == nullptr)) {
+      // Cannot config decoder because SPS/PPS NALUs haven't been seen.
+      return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
+    }
+    RefPtr<WebrtcOMXDecoder> omx = new WebrtcOMXDecoder(MEDIA_MIMETYPE_VIDEO_AVC);
+    status_t result = omx->ConfigureWithParamSets(paramSets);
+    if (NS_WARN_IF(result != OK)) {
+      return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
+    }
+    CODEC_LOGD("WebrtcOMXH264VideoDecoder:%p start OMX", this);
+    mOMX = omx;
+  }
+
+  bool feedFrame = true;
+  while (feedFrame) {
+    int64_t timeUs;
+    status_t err = mOMX->FillInput(aInputImage, !configured, aRenderTimeMs, mCallback);
+    feedFrame = (err == -EAGAIN); // No input buffer available. Try again.
+  }
+
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t
+WebrtcOMXH264VideoDecoder::RegisterDecodeCompleteCallback(webrtc::DecodedImageCallback* aCallback)
+{
+  CODEC_LOGD("WebrtcOMXH264VideoDecoder:%p set callback:%p", this, aCallback);
+  MOZ_ASSERT(aCallback);
+  mCallback = aCallback;
+
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t
+WebrtcOMXH264VideoDecoder::Release()
+{
+  CODEC_LOGD("WebrtcOMXH264VideoDecoder:%p will be released", this);
+
+  mOMX = nullptr;
+
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+WebrtcOMXH264VideoDecoder::~WebrtcOMXH264VideoDecoder()
+{
+  CODEC_LOGD("WebrtcOMXH264VideoDecoder:%p will be destructed", this);
+  Release();
+}
+
+int32_t
+WebrtcOMXH264VideoDecoder::Reset()
+{
+  CODEC_LOGW("WebrtcOMXH264VideoDecoder::Reset() will NOT reset decoder");
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+}
new file mode 100644
--- /dev/null
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.h
@@ -0,0 +1,88 @@
+/* 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 WEBRTC_GONK
+#pragma error WebrtcOMXH264VideoCodec works only on B2G.
+#endif
+
+#ifndef WEBRTC_OMX_H264_CODEC_H_
+#define WEBRTC_OMX_H264_CODEC_H_
+
+#include "AudioConduit.h"
+#include "VideoConduit.h"
+
+namespace android {
+  class OMXVideoEncoder;
+}
+
+namespace mozilla {
+
+class WebrtcOMXDecoder;
+class OMXOutputDrain;
+
+class WebrtcOMXH264VideoEncoder : public WebrtcVideoEncoder
+{
+public:
+  WebrtcOMXH264VideoEncoder();
+
+  virtual ~WebrtcOMXH264VideoEncoder();
+
+  // Implement VideoEncoder interface.
+  virtual int32_t InitEncode(const webrtc::VideoCodec* aCodecSettings,
+                             int32_t aNumOfCores,
+                             uint32_t aMaxPayloadSize) MOZ_OVERRIDE;
+
+  virtual int32_t Encode(const webrtc::I420VideoFrame& aInputImage,
+                         const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
+                         const std::vector<webrtc::VideoFrameType>* aFrameTypes) MOZ_OVERRIDE;
+
+  virtual int32_t RegisterEncodeCompleteCallback(webrtc::EncodedImageCallback* aCallback) MOZ_OVERRIDE;
+
+  virtual int32_t Release() MOZ_OVERRIDE;
+
+  virtual int32_t SetChannelParameters(uint32_t aPacketLossRate,
+                                       int aRoundTripTimeMs) MOZ_OVERRIDE;
+
+  virtual int32_t SetRates(uint32_t aBitRate, uint32_t aFrameRate) MOZ_OVERRIDE;
+
+private:
+  RefPtr<android::OMXVideoEncoder> mOMX;
+  webrtc::EncodedImageCallback* mCallback;
+  RefPtr<OMXOutputDrain> mOutputDrain;
+  uint32_t mWidth;
+  uint32_t mHeight;
+  uint32_t mFrameRate;
+  bool mOMXConfigured;
+  webrtc::EncodedImage mEncodedImage;
+};
+
+class WebrtcOMXH264VideoDecoder : public WebrtcVideoDecoder
+{
+public:
+  WebrtcOMXH264VideoDecoder();
+
+  virtual ~WebrtcOMXH264VideoDecoder();
+
+  // Implement VideoDecoder interface.
+  virtual int32_t InitDecode(const webrtc::VideoCodec* aCodecSettings,
+                             int32_t aNumOfCores) MOZ_OVERRIDE;
+  virtual int32_t Decode(const webrtc::EncodedImage& aInputImage,
+                         bool aMissingFrames,
+                         const webrtc::RTPFragmentationHeader* aFragmentation,
+                         const webrtc::CodecSpecificInfo* aCodecSpecificInfo = nullptr,
+                         int64_t aRenderTimeMs = -1) MOZ_OVERRIDE;
+  virtual int32_t RegisterDecodeCompleteCallback(webrtc::DecodedImageCallback* callback) MOZ_OVERRIDE;
+
+  virtual int32_t Release() MOZ_OVERRIDE;
+
+  virtual int32_t Reset() MOZ_OVERRIDE;
+
+private:
+  webrtc::DecodedImageCallback* mCallback;
+  RefPtr<WebrtcOMXDecoder> mOMX;
+};
+
+}
+
+#endif // WEBRTC_OMX_H264_CODEC_H_
--- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
+++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
@@ -32,16 +32,20 @@
 #include "nsIPrefBranch.h"
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <ssl.h>
 #include <sslproto.h>
 #include <algorithm>
 
+#ifdef MOZ_OMX_ENCODER
+#include "OMXVideoCodec.h"
+#endif
+
 extern "C" {
 #include "ccsdp.h"
 #include "vcm.h"
 #include "cc_call_feature.h"
 #include "cip_mmgr_mediadefinitions.h"
 #include "cip_Sipcc_CodecMask.h"
 
 extern void lsm_start_multipart_tone_timer (vcm_tones_t tone,
@@ -49,16 +53,21 @@ extern void lsm_start_multipart_tone_tim
                                             cc_call_handle_t callId);
 extern void lsm_start_continuous_tone_timer (vcm_tones_t tone,
                                              uint32_t delay,
                                              cc_call_handle_t callId);
 extern void lsm_update_active_tone(vcm_tones_t tone, cc_call_handle_t call_handle);
 extern void lsm_stop_multipart_tone_timer(void);
 extern void lsm_stop_continuous_tone_timer(void);
 
+static int vcmEnsureExternalCodec(
+    const mozilla::RefPtr<mozilla::VideoSessionConduit>& conduit,
+    mozilla::VideoCodecConfig* config,
+    bool send);
+
 }//end extern "C"
 
 static const char* logTag = "VcmSipccBinding";
 
 // Cloned from ccapi.h
 typedef enum {
     CC_AUDIO_1,
     CC_VIDEO_1,
@@ -1688,16 +1697,19 @@ static int vcmRxStartICE_m(cc_mcapid_t m
 
     for(int i=0; i <num_payloads; i++)
     {
       config_raw = new mozilla::VideoCodecConfig(
         payloads[i].remote_rtp_pt,
         ccsdpCodecName(payloads[i].codec_type),
         payloads[i].video.rtcp_fb_types,
         pc.impl()->load_manager());
+      if (vcmEnsureExternalCodec(conduit, config_raw, false)) {
+        continue;
+      }
       configs.push_back(config_raw);
     }
 
     if (conduit->ConfigureRecvMediaCodecs(configs))
       return VCM_ERROR;
 
     // Now we have all the pieces, create the pipeline
     mozilla::RefPtr<mozilla::MediaPipeline> pipeline =
@@ -2095,16 +2107,55 @@ short vcmTxOpen(cc_mcapid_t mcap_id,
 
     if (call_handle == CC_NO_CALL_ID) {
         /* no operation when no call ID */
         return VCM_ERROR;
     }
     return 0;
 }
 
+/*
+ * Add external H.264 video codec.
+ */
+static int vcmEnsureExternalCodec(
+    const mozilla::RefPtr<mozilla::VideoSessionConduit>& conduit,
+    mozilla::VideoCodecConfig* config,
+    bool send)
+{
+#ifdef MOZ_OMX_ENCODER
+  // Here we use "I420" to register H.264 because WebRTC.org code has a
+  // whitelist of supported video codec in |webrtc::ViECodecImpl::CodecValid()|
+  // and will reject registration of those not in it.
+  // TODO: bug 995884 to support H.264 in WebRTC.org code.
+  if (config->mName != "I420") {
+    // Do nothing for non-I420 config.
+    return send ? kMediaConduitInvalidSendCodec : kMediaConduitInvalidReceiveCodec;
+  }
+  // Register H.264 codec.
+  if (send) {
+    VideoEncoder* encoder = OMXVideoCodec::CreateEncoder(OMXVideoCodec::CodecType::CODEC_H264);
+    if (encoder) {
+      return conduit->SetExternalSendCodec(config->mType, encoder);
+    } else {
+      return kMediaConduitInvalidSendCodec;
+    }
+  } else {
+    VideoDecoder* decoder = OMXVideoCodec::CreateDecoder(OMXVideoCodec::CodecType::CODEC_H264);
+    if (decoder) {
+      return conduit->SetExternalRecvCodec(config->mType, decoder);
+    } else {
+      return kMediaConduitInvalidReceiveCodec;
+    }
+  }
+  NS_NOTREACHED("Shouldn't get here!");
+#endif
+
+  return 0;
+}
+
 /**
  *  start tx stream
  *  Note: For video calls, for a given call_handle there will be
  *        two media lines and the corresponding group_id/stream_id pair.
  *        One RTP session is requested from media server for each
  *        media line(group/stream) i.e. a video call would result in
  *        two rtp_sessions in our session info list created by two
  *        calls to vcm_rx/tx with mcap_id of AUDIO and VIDEO respectively.
@@ -2358,17 +2409,23 @@ static int vcmTxStartICE_m(cc_mcapid_t m
     MOZ_ASSERT_IF(rx_conduit, rx_conduit->type() == MediaSessionConduit::VIDEO);
 
     // The two sides of a send/receive pair of conduits each keep a raw pointer to the other,
     // and are responsible for cleanly shutting down.
     mozilla::RefPtr<mozilla::VideoSessionConduit> conduit =
       mozilla::VideoSessionConduit::Create(static_cast<VideoSessionConduit *>(rx_conduit.get()));
 
     // Find the appropriate media conduit config
-    if (!conduit || conduit->ConfigureSendMediaCodec(config))
+    if (!conduit)
+      return VCM_ERROR;
+
+    if (vcmEnsureExternalCodec(conduit, config_raw, true))
+      return VCM_ERROR;
+
+    if (conduit->ConfigureSendMediaCodec(config))
       return VCM_ERROR;
 
     pc.impl()->media()->AddConduit(level, false, conduit);
 
     // Now we have all the pieces, create the pipeline
     mozilla::RefPtr<mozilla::MediaPipeline> pipeline =
         new mozilla::MediaPipelineTransmit(
             pc.impl()->GetHandle(),
@@ -3213,9 +3270,8 @@ short vcmGetVideoMaxFr(uint16_t codec,
 
   mozilla::SyncRunnable::DispatchToThread(VcmSIPCCBinding::getMainThread(),
       WrapRunnableNMRet(&vcmGetVideoMaxFr_m,
                         codec,
                         max_fr,
                         &ret));
   return ret;
 }
-
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
@@ -18,17 +18,17 @@
 #include "srtp.h"
 
 #ifdef MOZILLA_INTERNAL_API
 #include "VideoSegment.h"
 #include "Layers.h"
 #include "ImageTypes.h"
 #include "ImageContainer.h"
 #include "VideoUtils.h"
-#ifdef MOZ_WIDGET_GONK
+#ifdef WEBRTC_GONK
 #include "GrallocImages.h"
 #include "mozilla/layers/GrallocTextureClient.h"
 #endif
 #endif
 
 #include "nsError.h"
 #include "AudioSegment.h"
 #include "MediaSegment.h"
@@ -1105,17 +1105,17 @@ void MediaPipelineTransmit::PipelineList
   // We get passed duplicate frames every ~10ms even if there's no frame change!
   int32_t serial = img->GetSerial();
   if (serial == last_img_) {
     return;
   }
   last_img_ = serial;
 
   ImageFormat format = img->GetFormat();
-#ifdef MOZ_WIDGET_GONK
+#ifdef WEBRTC_GONK
   if (format == ImageFormat::GRALLOC_PLANAR_YCBCR) {
     layers::GrallocImage *nativeImage = static_cast<layers::GrallocImage*>(img);
     android::sp<android::GraphicBuffer> graphicBuffer = nativeImage->GetGraphicBuffer();
     void *basePtr;
     graphicBuffer->lock(android::GraphicBuffer::USAGE_SW_READ_MASK, &basePtr);
     conduit->SendVideoFrame(static_cast<unsigned char*>(basePtr),
                             (graphicBuffer->getWidth() * graphicBuffer->getHeight() * 3) / 2,
                             graphicBuffer->getWidth(),
@@ -1399,50 +1399,59 @@ MediaPipelineReceiveVideo::PipelineListe
   image_container_ = layers::LayerManager::CreateImageContainer();
 #endif
 }
 
 void MediaPipelineReceiveVideo::PipelineListener::RenderVideoFrame(
     const unsigned char* buffer,
     unsigned int buffer_size,
     uint32_t time_stamp,
-    int64_t render_time) {
+    int64_t render_time,
+    const RefPtr<layers::Image>& video_image) {
 #ifdef MOZILLA_INTERNAL_API
   ReentrantMonitorAutoEnter enter(monitor_);
 
-  // Create a video frame and append it to the track.
+  if (buffer) {
+    // Create a video frame using |buffer|.
 #ifdef MOZ_WIDGET_GONK
-  ImageFormat format = ImageFormat::GRALLOC_PLANAR_YCBCR;
+    ImageFormat format = ImageFormat::GRALLOC_PLANAR_YCBCR;
 #else
-  ImageFormat format = ImageFormat::PLANAR_YCBCR;
+    ImageFormat format = ImageFormat::PLANAR_YCBCR;
 #endif
-  nsRefPtr<layers::Image> image = image_container_->CreateImage(format);
-
-  layers::PlanarYCbCrImage* videoImage = static_cast<layers::PlanarYCbCrImage*>(image.get());
-  uint8_t* frame = const_cast<uint8_t*>(static_cast<const uint8_t*> (buffer));
-  const uint8_t lumaBpp = 8;
-  const uint8_t chromaBpp = 4;
+    nsRefPtr<layers::Image> image = image_container_->CreateImage(format);
+    layers::PlanarYCbCrImage* yuvImage = static_cast<layers::PlanarYCbCrImage*>(image.get());
+    uint8_t* frame = const_cast<uint8_t*>(static_cast<const uint8_t*> (buffer));
+    const uint8_t lumaBpp = 8;
+    const uint8_t chromaBpp = 4;
 
-  layers::PlanarYCbCrData data;
-  data.mYChannel = frame;
-  data.mYSize = IntSize(width_, height_);
-  data.mYStride = width_ * lumaBpp/ 8;
-  data.mCbCrStride = width_ * chromaBpp / 8;
-  data.mCbChannel = frame + height_ * data.mYStride;
-  data.mCrChannel = data.mCbChannel + height_ * data.mCbCrStride / 2;
-  data.mCbCrSize = IntSize(width_/ 2, height_/ 2);
-  data.mPicX = 0;
-  data.mPicY = 0;
-  data.mPicSize = IntSize(width_, height_);
-  data.mStereoMode = StereoMode::MONO;
+    layers::PlanarYCbCrData yuvData;
+    yuvData.mYChannel = frame;
+    yuvData.mYSize = IntSize(width_, height_);
+    yuvData.mYStride = width_ * lumaBpp/ 8;
+    yuvData.mCbCrStride = width_ * chromaBpp / 8;
+    yuvData.mCbChannel = frame + height_ * yuvData.mYStride;
+    yuvData.mCrChannel = yuvData.mCbChannel + height_ * yuvData.mCbCrStride / 2;
+    yuvData.mCbCrSize = IntSize(width_/ 2, height_/ 2);
+    yuvData.mPicX = 0;
+    yuvData.mPicY = 0;
+    yuvData.mPicSize = IntSize(width_, height_);
+    yuvData.mStereoMode = StereoMode::MONO;
 
-  videoImage->SetData(data);
+    yuvImage->SetData(yuvData);
 
-  image_ = image.forget();
-#endif
+    image_ = image.forget();
+  }
+#ifdef WEBRTC_GONK
+  else {
+    // Decoder produced video frame that can be appended to the track directly.
+    MOZ_ASSERT(video_image);
+    image_ = video_image;
+  }
+#endif // WEBRTC_GONK
+#endif // MOZILLA_INTERNAL_API
 }
 
 void MediaPipelineReceiveVideo::PipelineListener::
 NotifyPull(MediaStreamGraph* graph, StreamTime desired_time) {
   ReentrantMonitorAutoEnter enter(monitor_);
 
 #ifdef MOZILLA_INTERNAL_API
   nsRefPtr<layers::Image> image = image_;
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
@@ -638,19 +638,21 @@ class MediaPipelineReceiveVideo : public
                                  unsigned int height,
                                  unsigned int number_of_streams) {
       pipeline_->listener_->FrameSizeChange(width, height, number_of_streams);
     }
 
     virtual void RenderVideoFrame(const unsigned char* buffer,
                                   unsigned int buffer_size,
                                   uint32_t time_stamp,
-                                  int64_t render_time) {
+                                  int64_t render_time,
+                                  const ImageHandle& handle) {
       pipeline_->listener_->RenderVideoFrame(buffer, buffer_size, time_stamp,
-                                            render_time);
+                                             render_time,
+                                             handle.GetImage());
     }
 
    private:
     MediaPipelineReceiveVideo *pipeline_;  // Raw pointer to avoid cycles
   };
 
   // Separate class to allow ref counting
   class PipelineListener : public GenericReceiveListener {
@@ -673,18 +675,18 @@ class MediaPipelineReceiveVideo : public
 
       width_ = width;
       height_ = height;
     }
 
     void RenderVideoFrame(const unsigned char* buffer,
                           unsigned int buffer_size,
                           uint32_t time_stamp,
-                          int64_t render_time);
-
+                          int64_t render_time,
+                          const RefPtr<layers::Image>& video_image);
 
    private:
     int width_;
     int height_;
 #ifdef MOZILLA_INTERNAL_API
     nsRefPtr<layers::ImageContainer> image_container_;
     nsRefPtr<layers::Image> image_;
 #endif
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp
@@ -268,17 +268,22 @@ nsresult PeerConnectionCtx::Initialize()
 
   //Add the local video codecs
   // FIX - Get this list from MediaEngine instead
   // Turning them all on for now
   codecMask = 0;
   // Only adding codecs supported
   //codecMask |= VCM_CODEC_RESOURCE_H263;
 
-  //codecMask |= VCM_CODEC_RESOURCE_H264;
+#ifdef MOZILLA_INTERNAL_API
+  if (Preferences::GetBool("media.peerconnection.video.h264_enabled")) {
+    codecMask |= VCM_CODEC_RESOURCE_H264;
+  }
+#endif
+
   codecMask |= VCM_CODEC_RESOURCE_VP8;
   //codecMask |= VCM_CODEC_RESOURCE_I420;
   mCCM->setVideoCodecs(codecMask);
 
   ccAppReadyToStartLock = PR_NewLock();
   if (!ccAppReadyToStartLock) {
     return NS_ERROR_FAILURE;
   }
--- a/media/webrtc/signaling/src/sipcc/core/common/prot_configmgr.c
+++ b/media/webrtc/signaling/src/sipcc/core/common/prot_configmgr.c
@@ -609,20 +609,16 @@ sip_config_video_supported_codecs_get (r
     if ( isOffer ) {
         codec_mask = vcmGetVideoCodecList(VCM_DSP_FULLDUPLEX);
     } else {
         /* we are trying to match the answer then we
            already have the rx stream open */
         //codec_mask = vcmGetVideoCodecList(DSP_ENCODEONLY);
         codec_mask = vcmGetVideoCodecList(VCM_DSP_IGNORE);
     }
-    if ( codec_mask & VCM_CODEC_RESOURCE_VP8) {
-      aSupportedCodecs[count] = RTP_VP8;
-      count++;
-    }
     if ( codec_mask & VCM_CODEC_RESOURCE_H264) {
       /*
        * include payload type for packetization mode 1 only if ucm sis version
        * is equal to or greater than 5.1.0 (AngelFire).
        */
       platGetSISProtocolVer(&major_ver, &minor_ver, NULL, NULL);
       if ((major_ver > SIS_PROTOCOL_MAJOR_VERSION_ANGELFIRE) ||
           (major_ver == SIS_PROTOCOL_MAJOR_VERSION_ANGELFIRE &&
@@ -630,16 +626,20 @@ sip_config_video_supported_codecs_get (r
           if (vcmGetVideoMaxSupportedPacketizationMode() == 1) {
             aSupportedCodecs[count] = RTP_H264_P1;
             count++;
           }
       }
       aSupportedCodecs[count] = RTP_H264_P0;
       count++;
     }
+    if ( codec_mask & VCM_CODEC_RESOURCE_VP8) {
+      aSupportedCodecs[count] = RTP_VP8;
+      count++;
+    }
     if ( codec_mask & VCM_CODEC_RESOURCE_H263) {
       aSupportedCodecs[count] = RTP_H263;
       count++;
     }
 
     return count;
 }
 
--- a/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
@@ -4661,16 +4661,17 @@ gsmsdp_negotiate_rtcp_fb (cc_sdp_t *cc_s
             i++;
         } while (ccm_type != SDP_RTCP_FB_CCM_NOT_FOUND);
 
         /*
          * Mask out the types that we do not support
          */
         switch (codec) {
             case RTP_VP8:
+            case RTP_I420:
                 fb_types &=
                   sdp_rtcp_fb_nack_to_bitmap(SDP_RTCP_FB_NACK_BASIC) |
                   sdp_rtcp_fb_nack_to_bitmap(SDP_RTCP_FB_NACK_PLI) |
                   sdp_rtcp_fb_ccm_to_bitmap(SDP_RTCP_FB_CCM_FIR);
                 break;
             default:
                 fb_types = 0;
         }
--- a/media/webrtc/signaling/test/mediaconduit_unittests.cpp
+++ b/media/webrtc/signaling/test/mediaconduit_unittests.cpp
@@ -351,17 +351,18 @@ public:
   virtual ~DummyVideoTarget()
   {
   }
 
 
   void RenderVideoFrame(const unsigned char* buffer,
                         unsigned int buffer_size,
                         uint32_t time_stamp,
-                        int64_t render_time)
+                        int64_t render_time,
+                        const mozilla::ImageHandle& handle)
  {
   //write the frame to the file
   if(VerifyFrame(buffer, buffer_size) == 0)
   {
       vidStatsGlobal.numFramesRenderedSuccessfully++;
   } else
   {
       vidStatsGlobal.numFramesRenderedWrongly++;
--- a/mobile/android/base/db/HomeProvider.java
+++ b/mobile/android/base/db/HomeProvider.java
@@ -78,17 +78,17 @@ public class HomeProvider extends SQLite
     }
 
     /**
      * Returns a cursor populated with static fake data.
      */
     private Cursor queryFakeItems(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
         JSONArray items = null;
         try {
-            final String jsonString = RawResource.get(getContext(), R.raw.fake_home_items);
+            final String jsonString = RawResource.getAsString(getContext(), R.raw.fake_home_items);
             items = new JSONArray(jsonString);
         } catch (IOException e) {
             Log.e(LOGTAG, "Error getting fake home items", e);
             return null;
         } catch (JSONException e) {
             Log.e(LOGTAG, "Error parsing fake_home_items.json", e);
             return null;
         }
--- a/mobile/android/base/tests/components/ToolbarComponent.java
+++ b/mobile/android/base/tests/components/ToolbarComponent.java
@@ -81,16 +81,23 @@ public class ToolbarComponent extends Ba
         return (ImageButton) getToolbarView().findViewById(R.id.back);
     }
 
     private ImageButton getForwardButton() {
         DeviceHelper.assertIsTablet();
         return (ImageButton) getToolbarView().findViewById(R.id.forward);
     }
 
+    /**
+     * Returns the View for the edit cancel button in the browser toolbar.
+     */
+    private ImageButton getEditCancelButton() {
+        return (ImageButton) getToolbarView().findViewById(R.id.edit_cancel);
+    }
+
     private CharSequence getTitle() {
         return getTitleHelper(true);
     }
 
     /**
      * Returns the title of the page. Note that this makes no assertions to Toolbar state and
      * may return a value that may never be visible to the user. Callers likely want to use
      * {@link assertTitle} instead.
@@ -140,25 +147,30 @@ public class ToolbarComponent extends Ba
         waitForNotEditing();
 
         return this;
     }
 
     public ToolbarComponent dismissEditingMode() {
         assertIsEditing();
 
-        if (getUrlEditText().isInputMethodTarget()) {
-            // Drop the soft keyboard.
-            // TODO: Solo.hideSoftKeyboard() does not clear focus, causing unexpected
-            // behavior, but we may want to use it over goBack().
+        // Cancel Button not implemeneted in tablet.
+        if (DeviceHelper.isTablet()) {
+            if (getUrlEditText().isInputMethodTarget()) {
+                // Drop the soft keyboard.
+                // TODO: Solo.hideSoftKeyboard() does not clear focus, causing unexpected
+                // behavior, but we may want to use it over goBack().
+                mSolo.goBack();
+            }
+
             mSolo.goBack();
+        } else {
+            mSolo.clickOnView(getEditCancelButton());
         }
 
-        mSolo.goBack();
-
         waitForNotEditing();
 
         return this;
     }
 
     public ToolbarComponent enterUrl(final String url) {
         fAssertNotNull("url is not null", url);
 
--- a/mobile/android/base/util/RawResource.java
+++ b/mobile/android/base/util/RawResource.java
@@ -7,18 +7,27 @@ package org.mozilla.gecko.util;
 import android.content.Context;
 import android.content.res.Resources;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.StringWriter;
 
+/**
+ * {@code RawResource} provides API to load raw resources in different
+ * forms. For now, we only load them as strings. We're using raw resources
+ * as localizable 'assets' as opposed to a string that can be directly
+ * translatable e.g. JSON file vs string.
+ *
+ * This is just a utility class to avoid code duplication for the different
+ * cases where need to read such assets.
+ */
 public final class RawResource {
-    public static String get(Context context, int id) throws IOException {
+    public static String getAsString(Context context, int id) throws IOException {
         InputStreamReader reader = null;
 
         try {
             final Resources res = context.getResources();
             final InputStream is = res.openRawResource(id);
             if (is == null) {
                 return null;
             }
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -2877,16 +2877,17 @@ let gReflowPending = null;
 let gViewportMargins = { top: 0, right: 0, bottom: 0, left: 0};
 
 function Tab(aURL, aParams) {
   this.browser = null;
   this.id = 0;
   this.lastTouchedAt = Date.now();
   this._zoom = 1.0;
   this._drawZoom = 1.0;
+  this._restoreZoom = false;
   this._fixedMarginLeft = 0;
   this._fixedMarginTop = 0;
   this._fixedMarginRight = 0;
   this._fixedMarginBottom = 0;
   this._readerEnabled = false;
   this._readerActive = false;
   this.userScrollPos = { x: 0, y: 0 };
   this.viewportExcludesHorizontalMargins = true;
@@ -3481,16 +3482,17 @@ Tab.prototype = {
       docViewer.pausePainting();
 
       BrowserApp.selectedTab.performReflowOnZoom(aViewport);
       BrowserApp.selectedTab.probablyNeedRefloz = false;
     }
 
     let win = this.browser.contentWindow;
     win.scrollTo(x, y);
+    this.saveSessionZoom(aViewport.zoom);
 
     this.userScrollPos.x = win.scrollX;
     this.userScrollPos.y = win.scrollY;
     this.setResolution(aViewport.zoom, false);
 
     if (aViewport.displayPort)
       this.setDisplayPort(aViewport.displayPort);
 
@@ -3530,36 +3532,37 @@ Tab.prototype = {
     let html = aDocument.documentElement || { scrollWidth: aDefaultWidth, scrollHeight: aDefaultHeight };
     return [Math.max(body.scrollWidth, html.scrollWidth),
       Math.max(body.scrollHeight, html.scrollHeight)];
   },
 
   getViewport: function() {
     let screenW = gScreenWidth - gViewportMargins.left - gViewportMargins.right;
     let screenH = gScreenHeight - gViewportMargins.top - gViewportMargins.bottom;
+    let zoom = this.restoredSessionZoom() || this._zoom;
 
     let viewport = {
       width: screenW,
       height: screenH,
-      cssWidth: screenW / this._zoom,
-      cssHeight: screenH / this._zoom,
+      cssWidth: screenW / zoom,
+      cssHeight: screenH / zoom,
       pageLeft: 0,
       pageTop: 0,
       pageRight: screenW,
       pageBottom: screenH,
       // We make up matching css page dimensions
       cssPageLeft: 0,
       cssPageTop: 0,
-      cssPageRight: screenW / this._zoom,
-      cssPageBottom: screenH / this._zoom,
+      cssPageRight: screenW / zoom,
+      cssPageBottom: screenH / zoom,
       fixedMarginLeft: this._fixedMarginLeft,
       fixedMarginTop: this._fixedMarginTop,
       fixedMarginRight: this._fixedMarginRight,
       fixedMarginBottom: this._fixedMarginBottom,
-      zoom: this._zoom,
+      zoom: zoom,
     };
 
     // Set the viewport offset to current scroll offset
     viewport.cssX = this.browser.contentWindow.scrollX || 0;
     viewport.cssY = this.browser.contentWindow.scrollY || 0;
 
     // Transform coordinates based on zoom
     viewport.x = Math.round(viewport.cssX * viewport.zoom);
@@ -4181,28 +4184,47 @@ Tab.prototype = {
   },
 
   _sendHistoryEvent: function(aMessage, aParams) {
     let message = {
       type: "SessionHistory:" + aMessage,
       tabID: this.id,
     };
 
+    // Restore zoom only when moving in session history, not for new page loads.
+    this._restoreZoom = aMessage != "New";
+
     if (aParams) {
       if ("url" in aParams)
         message.url = aParams.url;
       if ("index" in aParams)
         message.index = aParams.index;
       if ("numEntries" in aParams)
         message.numEntries = aParams.numEntries;
     }
 
     sendMessageToJava(message);
   },
 
+  saveSessionZoom: function(aZoom) {
+    let cwu = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+    cwu.setResolution(aZoom / window.devicePixelRatio, aZoom / window.devicePixelRatio);
+  },
+
+  restoredSessionZoom: function() {
+    if (!this._restoreZoom) {
+      return null;
+    }
+
+    let cwu = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+    let res = {x: {}, y: {}};
+    cwu.getResolution(res.x, res.y);
+    return res.x.value * window.devicePixelRatio;
+  },
+
   OnHistoryNewEntry: function(aUri) {
     this._sendHistoryEvent("New", { url: aUri.spec });
   },
 
   OnHistoryGoBack: function(aUri) {
     this._sendHistoryEvent("Back");
     return true;
   },
@@ -4317,18 +4339,21 @@ Tab.prototype = {
     //    viewport)
     // 3. screen size remains constant, but CSS viewport changes (meta viewport
     //    tag is added or removed)
     // 4. neither screen size nor CSS viewport changes
     //
     // In all of these cases, we maintain how much actual content is visible
     // within the screen width. Note that "actual content" may be different
     // with respect to CSS pixels because of the CSS viewport size changing.
-    let zoomScale = (screenW * oldBrowserWidth) / (aOldScreenWidth * viewportW);
-    let zoom = (aInitialLoad && metadata.defaultZoom) ? metadata.defaultZoom : this.clampZoom(this._zoom * zoomScale);
+    let zoom = this.restoredSessionZoom() || metadata.defaultZoom;
+    if (!zoom || !aInitialLoad) {
+      let zoomScale = (screenW * oldBrowserWidth) / (aOldScreenWidth * viewportW);
+      zoom = this.clampZoom(this._zoom * zoomScale);
+    }
     this.setResolution(zoom, false);
     this.setScrollClampingSize(zoom);
 
     // if this page has not been painted yet, then this must be getting run
     // because a meta-viewport element was added (via the DOMMetaAdded handler).
     // in this case, we should not do anything that forces a reflow (see bug 759678)
     // such as requesting the page size or sending a viewport update. this code
     // will get run again in the before-first-paint handler and that point we
@@ -4454,17 +4479,18 @@ Tab.prototype = {
           this.contentDocumentIsDisplayed = true;
 
           // reset CSS viewport and zoom to default on new page, and then calculate
           // them properly using the actual metadata from the page. note that the
           // updateMetadata call takes into account the existing CSS viewport size
           // and zoom when calculating the new ones, so we need to reset these
           // things here before calling updateMetadata.
           this.setBrowserSize(kDefaultCSSViewportWidth, kDefaultCSSViewportHeight);
-          this.setResolution(gScreenWidth / this.browserWidth, false);
+          let zoom = this.restoredSessionZoom() || gScreenWidth / this.browserWidth;
+          this.setResolution(zoom, true);
           ViewportHandler.updateMetadata(this, true);
 
           // Note that if we draw without a display-port, things can go wrong. By the
           // time we execute this, it's almost certain a display-port has been set via
           // the MozScrolledAreaChanged event. If that didn't happen, the updateMetadata
           // call above does so at the end of the updateViewportSize function. As long
           // as that is happening, we don't need to do it again here.
 
--- a/mobile/android/tests/browser/junit3/moz.build
+++ b/mobile/android/tests/browser/junit3/moz.build
@@ -8,16 +8,17 @@ DEFINES['ANDROID_PACKAGE_NAME'] = CONFIG
 
 jar = add_java_jar('browser-junit3')
 jar.sources += [
     'src/harness/BrowserInstrumentationTestRunner.java',
     'src/harness/BrowserTestListener.java',
     'src/tests/BrowserTestCase.java',
     'src/tests/TestGeckoSharedPrefs.java',
     'src/tests/TestJarReader.java',
+    'src/tests/TestRawResource.java',
     'src/tests/TestTopSitesCursorWrapper.java',
 ]
 jar.generated_sources = [] # None yet -- try to keep it this way.
 jar.javac_flags += ['-Xlint:all,-unchecked']
 
 # Android Eclipse project.
 main = add_android_eclipse_project('BrowserInstrumentationTests', OBJDIR + '/AndroidManifest.xml')
 # The package name doesn't really matter, but it looks nicest if the
new file mode 100644
--- /dev/null
+++ b/mobile/android/tests/browser/junit3/src/tests/TestRawResource.java
@@ -0,0 +1,67 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+package org.mozilla.gecko.browser.tests;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.test.mock.MockContext;
+import android.test.mock.MockResources;
+import android.util.TypedValue;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.mozilla.gecko.util.RawResource;
+
+/**
+ * Tests whether RawResource.getAsString() produces the right String
+ * result after reading the returned raw resource's InputStream.
+ */
+public class TestRawResource extends BrowserTestCase {
+    private static final int RAW_RESOURCE_ID = 1;
+    private static final String RAW_CONTENTS = "RAW";
+
+    private static class TestContext extends MockContext {
+        private final Resources resources;
+
+        public TestContext() {
+            resources = new TestResources();
+        }
+
+        @Override
+        public Resources getResources() {
+            return resources;
+        }
+    }
+
+    /**
+     * Browser instrumentation tests can't have access to test-only
+     * resources (bug 994135) yet so we mock the access to resources
+     * for now.
+     */
+    private static class TestResources extends MockResources {
+        @Override
+        public InputStream openRawResource(int id) {
+            if (id == RAW_RESOURCE_ID) {
+                return new ByteArrayInputStream(RAW_CONTENTS.getBytes());
+            }
+
+            return null;
+        }
+    }
+
+    public void testGet() {
+        Context context = new TestContext();
+        String result;
+
+        try {
+            result = RawResource.getAsString(context, RAW_RESOURCE_ID);
+        } catch (IOException e) {
+            result = null;
+        }
+
+        assertEquals(RAW_CONTENTS, result);
+    }
+}
\ No newline at end of file
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -240,16 +240,17 @@ pref("media.navigator.video.default_fps"
 pref("media.navigator.video.default_minfps",10);
 #ifdef MOZ_WIDGET_GONK
 pref("media.navigator.video.default_width",320);
 pref("media.navigator.video.default_height",240);
 pref("media.peerconnection.enabled", true);
 pref("media.peerconnection.video.enabled", true);
 pref("media.navigator.video.max_fs", 1200); // 640x480 == 1200mb
 pref("media.navigator.video.max_fr", 30);
+pref("media.peerconnection.video.h264_enabled", false);
 #else
 pref("media.navigator.video.default_width",640);
 pref("media.navigator.video.default_height",480);
 pref("media.peerconnection.enabled", true);
 pref("media.peerconnection.video.enabled", true);
 pref("media.navigator.video.max_fs", 0); // unrestricted
 pref("media.navigator.video.max_fr", 0); // unrestricted
 #endif
--- a/netwerk/cache/nsCacheService.cpp
+++ b/netwerk/cache/nsCacheService.cpp
@@ -17,16 +17,17 @@
 #include "nsCacheEntry.h"
 #include "nsCacheEntryDescriptor.h"
 #include "nsCacheDevice.h"
 #include "nsMemoryCacheDevice.h"
 #include "nsICacheVisitor.h"
 #include "nsDiskCacheDevice.h"
 #include "nsDiskCacheDeviceSQL.h"
 #include "nsCacheUtils.h"
+#include "../cache2/CacheObserver.h"
 
 #include "nsIObserverService.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsIFile.h"
 #include "nsIOService.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsAppDirectoryServiceDefs.h"
@@ -3103,16 +3104,20 @@ nsCacheService::SetDiskSmartSize()
     return gService->SetDiskSmartSize_Locked();
 }
 
 nsresult
 nsCacheService::SetDiskSmartSize_Locked()
 {
     nsresult rv;
 
+    if (mozilla::net::CacheObserver::UseNewCache()) {
+        return NS_ERROR_NOT_AVAILABLE;
+    }
+
     if (!mObserver->DiskCacheParentDirectory())
         return NS_ERROR_NOT_AVAILABLE;
 
     if (!mDiskDevice)
         return NS_ERROR_NOT_AVAILABLE;
 
     if (!mObserver->SmartSizeEnabled())
         return NS_ERROR_NOT_AVAILABLE;
--- a/netwerk/cache2/CacheFile.cpp
+++ b/netwerk/cache2/CacheFile.cpp
@@ -314,17 +314,20 @@ CacheFile::OnChunkRead(nsresult aResult,
 
   nsresult rv;
 
   uint32_t index = aChunk->Index();
 
   LOG(("CacheFile::OnChunkRead() [this=%p, rv=0x%08x, chunk=%p, idx=%d]",
        this, aResult, aChunk, index));
 
-  // TODO handle ERROR state
+  if (NS_FAILED(aResult)) {
+    SetError(aResult);
+    CacheFileIOManager::DoomFile(mHandle, nullptr);
+  }
 
   if (HaveChunkListeners(index)) {
     rv = NotifyChunkListeners(index, aResult, aChunk);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
@@ -336,65 +339,65 @@ CacheFile::OnChunkWritten(nsresult aResu
 
   nsresult rv;
 
   LOG(("CacheFile::OnChunkWritten() [this=%p, rv=0x%08x, chunk=%p, idx=%d]",
        this, aResult, aChunk, aChunk->Index()));
 
   MOZ_ASSERT(!mMemoryOnly);
   MOZ_ASSERT(!mOpeningFile);
-
-  // TODO handle ERROR state
+  MOZ_ASSERT(mHandle);
 
   if (NS_FAILED(aResult)) {
-    // TODO ??? doom entry
-    // TODO mark this chunk as memory only, since it wasn't written to disk and
-    // therefore cannot be released from memory
-    // LOG
+    SetError(aResult);
+    CacheFileIOManager::DoomFile(mHandle, nullptr);
   }
 
   if (NS_SUCCEEDED(aResult) && !aChunk->IsDirty()) {
     // update hash value in metadata
     mMetadata->SetHash(aChunk->Index(), aChunk->Hash());
   }
 
   // notify listeners if there is any
   if (HaveChunkListeners(aChunk->Index())) {
     // don't release the chunk since there are some listeners queued
-    rv = NotifyChunkListeners(aChunk->Index(), NS_OK, aChunk);
+    rv = NotifyChunkListeners(aChunk->Index(), aResult, aChunk);
     if (NS_SUCCEEDED(rv)) {
       MOZ_ASSERT(aChunk->mRefCnt != 2);
       return NS_OK;
     }
   }
 
   if (aChunk->mRefCnt != 2) {
     LOG(("CacheFile::OnChunkWritten() - Chunk is still used [this=%p, chunk=%p,"
          " refcnt=%d]", this, aChunk, aChunk->mRefCnt.get()));
 
     return NS_OK;
   }
 
 #ifdef CACHE_CHUNKS
-  LOG(("CacheFile::OnChunkWritten() - Caching unused chunk [this=%p, chunk=%p]",
-       this, aChunk));
+  if (NS_SUCCEEDED(aResult)) {
+    LOG(("CacheFile::OnChunkWritten() - Caching unused chunk [this=%p, "
+         "chunk=%p]", this, aChunk));
+  } else {
+    LOG(("CacheFile::OnChunkWritten() - Removing failed chunk [this=%p, "
+         "chunk=%p]", this, aChunk));
+  }
 #else
-  LOG(("CacheFile::OnChunkWritten() - Releasing unused chunk [this=%p, "
-       "chunk=%p]", this, aChunk));
+  LOG(("CacheFile::OnChunkWritten() - Releasing %s chunk [this=%p, chunk=%p]",
+       NS_SUCCEEDED(aResult) ? "unused" : "failed", this, aChunk));
 #endif
 
-  aChunk->mRemovingChunk = true;
-  ReleaseOutsideLock(static_cast<CacheFileChunkListener *>(
-                       aChunk->mFile.forget().take()));
-
+  RemoveChunkInternal(aChunk,
 #ifdef CACHE_CHUNKS
-  mCachedChunks.Put(aChunk->Index(), aChunk);
+                      NS_SUCCEEDED(aResult));
+#else
+                      false);
 #endif
 
-  mChunks.Remove(aChunk->Index());
   WriteMetadataIfNeededLocked();
 
   return NS_OK;
 }
 
 nsresult
 CacheFile::OnChunkAvailable(nsresult aResult, uint32_t aChunkIdx,
                             CacheFileChunk *aChunk)
@@ -995,16 +998,26 @@ CacheFile::GetChunkLocked(uint32_t aInde
 
   nsresult rv;
 
   nsRefPtr<CacheFileChunk> chunk;
   if (mChunks.Get(aIndex, getter_AddRefs(chunk))) {
     LOG(("CacheFile::GetChunkLocked() - Found chunk %p in mChunks [this=%p]",
          chunk.get(), this));
 
+    // We might get failed chunk between releasing the lock in
+    // CacheFileChunk::OnDataWritten/Read and CacheFile::OnChunkWritten/Read
+    rv = chunk->GetStatus();
+    if (NS_FAILED(rv)) {
+      SetError(rv);
+      LOG(("CacheFile::GetChunkLocked() - Found failed chunk in mChunks "
+           "[this=%p]", this));
+      return rv;
+    }
+
     if (chunk->IsReady() || aWriter) {
       chunk.swap(*_retval);
     }
     else {
       rv = QueueChunkListener(aIndex, aCallback);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
@@ -1051,22 +1064,19 @@ CacheFile::GetChunkLocked(uint32_t aInde
 
     LOG(("CacheFile::GetChunkLocked() - Reading newly created chunk %p from "
          "the disk [this=%p]", chunk.get(), this));
 
     // Read the chunk from the disk
     rv = chunk->Read(mHandle, std::min(static_cast<uint32_t>(mDataSize - off),
                      static_cast<uint32_t>(kChunkSize)),
                      mMetadata->GetHash(aIndex), this);
-    if (NS_FAILED(rv)) {
-      chunk->mRemovingChunk = true;
-      ReleaseOutsideLock(static_cast<CacheFileChunkListener *>(
-                           chunk->mFile.forget().take()));
-      mChunks.Remove(aIndex);
-      NS_ENSURE_SUCCESS(rv, rv);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      RemoveChunkInternal(chunk, false);
+      return rv;
     }
 
     if (aWriter) {
       chunk.swap(*_retval);
     }
     else {
       rv = QueueChunkListener(aIndex, aCallback);
       NS_ENSURE_SUCCESS(rv, rv);
@@ -1199,28 +1209,42 @@ CacheFile::RemoveChunk(CacheFileChunk *a
 
       // We also shouldn't have any queued listener for this chunk
       ChunkListeners *listeners;
       mChunkListeners.Get(chunk->Index(), &listeners);
       MOZ_ASSERT(!listeners);
     }
 #endif
 
+    if (NS_FAILED(mStatus)) {
+      // Don't write any chunk to disk since this entry will be doomed
+      LOG(("CacheFile::RemoveChunk() - Removing chunk because of status "
+           "[this=%p, chunk=%p, mStatus=0x%08x]", this, chunk.get(), mStatus));
+
+      RemoveChunkInternal(chunk, false);
+      return mStatus;
+    }
+
     if (chunk->IsDirty() && !mMemoryOnly && !mOpeningFile) {
       LOG(("CacheFile::RemoveChunk() - Writing dirty chunk to the disk "
            "[this=%p]", this));
 
       mDataIsDirty = true;
 
       rv = chunk->Write(mHandle, this);
       if (NS_FAILED(rv)) {
-        // TODO ??? doom entry
-        // TODO mark this chunk as memory only, since it wasn't written to disk
-        // and therefore cannot be released from memory
-        // LOG
+        LOG(("CacheFile::RemoveChunk() - CacheFileChunk::Write() failed "
+             "synchronously. Removing it. [this=%p, chunk=%p, rv=0x%08x]",
+             this, chunk.get(), rv));
+
+        RemoveChunkInternal(chunk, false);
+
+        SetError(rv);
+        CacheFileIOManager::DoomFile(mHandle, nullptr);
+        return rv;
       }
       else {
         // Chunk will be removed in OnChunkWritten if it is still unused
 
         // chunk needs to be released under the lock to be able to rely on
         // CacheFileChunk::mRefCnt in CacheFile::OnChunkWritten()
         chunk = nullptr;
         return NS_OK;
@@ -1236,35 +1260,45 @@ CacheFile::RemoveChunk(CacheFileChunk *a
            " reason=%s]", this, chunk.get(),
            mMemoryOnly ? "memory-only" : "opening-file"));
     } else {
       LOG(("CacheFile::RemoveChunk() - Releasing unused chunk [this=%p, "
            "chunk=%p]", this, chunk.get()));
     }
 #endif
 
-    chunk->mRemovingChunk = true;
-    ReleaseOutsideLock(static_cast<CacheFileChunkListener *>(
-                         chunk->mFile.forget().take()));
-#ifndef CACHE_CHUNKS
-    // Cache the chunk only when we have a reason to do so
-    if (mMemoryOnly || mOpeningFile)
+    RemoveChunkInternal(chunk,
+#ifdef CACHE_CHUNKS
+                        true);
+#else
+                        // Cache the chunk only when we have a reason to do so
+                        mMemoryOnly || mOpeningFile);
 #endif
-    {
-      mCachedChunks.Put(chunk->Index(), chunk);
-    }
 
-    mChunks.Remove(chunk->Index());
     if (!mMemoryOnly)
       WriteMetadataIfNeededLocked();
   }
 
   return NS_OK;
 }
 
+void
+CacheFile::RemoveChunkInternal(CacheFileChunk *aChunk, bool aCacheChunk)
+{
+  aChunk->mRemovingChunk = true;
+  ReleaseOutsideLock(static_cast<CacheFileChunkListener *>(
+                       aChunk->mFile.forget().take()));
+
+  if (aCacheChunk) {
+    mCachedChunks.Put(aChunk->Index(), aChunk);
+  }
+
+  mChunks.Remove(aChunk->Index());
+}
+
 nsresult
 CacheFile::RemoveInput(CacheFileInputStream *aInput)
 {
   CacheFileAutoLock lock(this);
 
   LOG(("CacheFile::RemoveInput() [this=%p, input=%p]", this, aInput));
 
   DebugOnly<bool> found;
@@ -1496,21 +1530,20 @@ CacheFile::WriteMetadataIfNeededLocked(b
   LOG(("CacheFile::WriteMetadataIfNeededLocked() - Writing metadata [this=%p]",
        this));
 
   rv = mMetadata->WriteMetadata(mDataSize, aFireAndForget ? nullptr : this);
   if (NS_SUCCEEDED(rv)) {
     mWritingMetadata = true;
     mDataIsDirty = false;
   } else {
-    LOG(("CacheFile::WriteMetadataIfNeededLocked() - Writing synchronously failed "
-         "[this=%p]", this));
+    LOG(("CacheFile::WriteMetadataIfNeededLocked() - Writing synchronously "
+         "failed [this=%p]", this));
     // TODO: close streams with error
-    if (NS_SUCCEEDED(mStatus))
-      mStatus = rv;
+    SetError(rv);
   }
 }
 
 void
 CacheFile::PostWriteTimer()
 {
   LOG(("CacheFile::PostWriteTimer() [this=%p]", this));
 
@@ -1610,16 +1643,24 @@ CacheFile::PadChunkWithZeroes(uint32_t a
   chunk->UpdateDataSize(chunk->DataSize(), kChunkSize - chunk->DataSize(),
                         false);
 
   ReleaseOutsideLock(chunk.forget().take());
 
   return NS_OK;
 }
 
+void
+CacheFile::SetError(nsresult aStatus)
+{
+  if (NS_SUCCEEDED(mStatus)) {
+    mStatus = aStatus;
+  }
+}
+
 nsresult
 CacheFile::InitIndexEntry()
 {
   MOZ_ASSERT(mHandle);
 
   if (mHandle->IsDoomed())
     return NS_OK;
 
--- a/netwerk/cache2/CacheFile.h
+++ b/netwerk/cache2/CacheFile.h
@@ -121,16 +121,17 @@ private:
 
   nsresult GetChunk(uint32_t aIndex, bool aWriter,
                     CacheFileChunkListener *aCallback,
                     CacheFileChunk **_retval);
   nsresult GetChunkLocked(uint32_t aIndex, bool aWriter,
                           CacheFileChunkListener *aCallback,
                           CacheFileChunk **_retval);
   nsresult RemoveChunk(CacheFileChunk *aChunk);
+  void     RemoveChunkInternal(CacheFileChunk *aChunk, bool aCacheChunk);
 
   nsresult RemoveInput(CacheFileInputStream *aInput);
   nsresult RemoveOutput(CacheFileOutputStream *aOutput);
   nsresult NotifyChunkListener(CacheFileChunkListener *aCallback,
                                nsIEventTarget *aTarget,
                                nsresult aResult,
                                uint32_t aChunkIdx,
                                CacheFileChunk *aChunk);
@@ -156,16 +157,18 @@ private:
                            void* aClosure);
 
   static PLDHashOperator FailUpdateListeners(const uint32_t& aIdx,
                                              nsRefPtr<CacheFileChunk>& aChunk,
                                              void* aClosure);
 
   nsresult PadChunkWithZeroes(uint32_t aChunkIdx);
 
+  void SetError(nsresult aStatus);
+
   nsresult InitIndexEntry();
 
   mozilla::Mutex mLock;
   bool           mOpeningFile;
   bool           mReady;
   bool           mMemoryOnly;
   bool           mOpenAsMemoryOnly;
   bool           mDataAccessed;
--- a/netwerk/cache2/CacheFileChunk.cpp
+++ b/netwerk/cache2/CacheFileChunk.cpp
@@ -122,16 +122,17 @@ NS_INTERFACE_MAP_BEGIN(CacheFileChunk)
   NS_INTERFACE_MAP_ENTRY(mozilla::net::CacheFileIOListener)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END_THREADSAFE
 
 CacheFileChunk::CacheFileChunk(CacheFile *aFile, uint32_t aIndex)
   : CacheMemoryConsumer(aFile->mOpenAsMemoryOnly ? MEMORY_ONLY : DONT_REPORT)
   , mIndex(aIndex)
   , mState(INITIAL)
+  , mStatus(NS_OK)
   , mIsDirty(false)
   , mRemovingChunk(false)
   , mDataSize(0)
   , mBuf(nullptr)
   , mBufSize(0)
   , mRWBuf(nullptr)
   , mRWBufSize(0)
   , mReadHash(0)
@@ -198,27 +199,27 @@ CacheFileChunk::Read(CacheFileHandle *aH
 
   mRWBuf = static_cast<char *>(moz_xmalloc(aLen));
   mRWBufSize = aLen;
 
   DoMemoryReport(MemorySize());
 
   rv = CacheFileIOManager::Read(aHandle, mIndex * kChunkSize, mRWBuf, aLen,
                                 this);
-  if (NS_FAILED(rv)) {
-    mState = READING;   // TODO: properly handle error states
-//    mState = ERROR;
-    NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    rv = mIndex ? NS_ERROR_FILE_CORRUPTED : NS_ERROR_FILE_NOT_FOUND;
+    SetError(rv);
+  } else {
+    mState = READING;
+    mListener = aCallback;
+    mDataSize = aLen;
+    mReadHash = aHash;
   }
 
-  mState = READING;
-  mListener = aCallback;
-  mDataSize = aLen;
-  mReadHash = aHash;
-  return NS_OK;
+  return rv;
 }
 
 nsresult
 CacheFileChunk::Write(CacheFileHandle *aHandle,
                       CacheFileChunkListener *aCallback)
 {
   mFile->AssertOwnsLock();
 
@@ -234,26 +235,25 @@ CacheFileChunk::Write(CacheFileHandle *a
 
   mRWBuf = mBuf;
   mRWBufSize = mBufSize;
   mBuf = nullptr;
   mBufSize = 0;
 
   rv = CacheFileIOManager::Write(aHandle, mIndex * kChunkSize, mRWBuf,
                                  mDataSize, false, this);
-  if (NS_FAILED(rv)) {
-    mState = WRITING;   // TODO: properly handle error states
-//    mState = ERROR;
-    NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    SetError(rv);
+  } else {
+    mState = WRITING;
+    mListener = aCallback;
+    mIsDirty = false;
   }
 
-  mState = WRITING;
-  mListener = aCallback;
-  mIsDirty = false;
-  return NS_OK;
+  return rv;
 }
 
 void
 CacheFileChunk::WaitForUpdate(CacheFileChunkListener *aCallback)
 {
   mFile->AssertOwnsLock();
 
   LOG(("CacheFileChunk::WaitForUpdate() [this=%p, listener=%p]",
@@ -363,16 +363,20 @@ CacheFileChunk::DataSize()
 void
 CacheFileChunk::UpdateDataSize(uint32_t aOffset, uint32_t aLen, bool aEOF)
 {
   mFile->AssertOwnsLock();
 
   MOZ_ASSERT(!aEOF, "Implement me! What to do with opened streams?");
   MOZ_ASSERT(aOffset <= mDataSize);
 
+  // UpdateDataSize() is called only when we've written some data to the chunk
+  // and we never write data anymore once some error occurs.
+  MOZ_ASSERT(mState != ERROR);
+
   LOG(("CacheFileChunk::UpdateDataSize() [this=%p, offset=%d, len=%d, EOF=%d]",
        this, aOffset, aLen, aEOF));
 
   mIsDirty = true;
 
   int64_t fileSize = kChunkSize * mIndex + aOffset + aLen;
   bool notify = false;
 
@@ -463,39 +467,33 @@ CacheFileChunk::OnDataWritten(CacheFileH
   nsCOMPtr<CacheFileChunkListener> listener;
 
   {
     CacheFileAutoLock lock(mFile);
 
     MOZ_ASSERT(mState == WRITING);
     MOZ_ASSERT(mListener);
 
-#if 0
-    // TODO: properly handle error states
-    if (NS_FAILED(aResult)) {
-      mState = ERROR;
-    }
-    else {
-#endif
+    if (NS_WARN_IF(NS_FAILED(aResult))) {
+      SetError(aResult);
+    } else {
       mState = READY;
-      if (!mBuf) {
-        mBuf = mRWBuf;
-        mBufSize = mRWBufSize;
-      }
-      else {
-        free(mRWBuf);
-      }
+    }
 
-      mRWBuf = nullptr;
-      mRWBufSize = 0;
+    if (!mBuf) {
+      mBuf = mRWBuf;
+      mBufSize = mRWBufSize;
+    } else {
+      free(mRWBuf);
+    }
 
-      DoMemoryReport(MemorySize());
-#if 0
-    }
-#endif
+    mRWBuf = nullptr;
+    mRWBufSize = 0;
+
+    DoMemoryReport(MemorySize());
 
     mListener.swap(listener);
   }
 
   listener->OnChunkWritten(aResult, this);
 
   return NS_OK;
 }
@@ -550,24 +548,20 @@ CacheFileChunk::OnDataRead(CacheFileHand
           mRWBufSize = 0;
 
           DoMemoryReport(MemorySize());
         }
       }
     }
 
     if (NS_FAILED(aResult)) {
-#if 0
-      // TODO: properly handle error states
-      mState = ERROR;
-#endif
-      mState = READY;
+      aResult = mIndex ? NS_ERROR_FILE_CORRUPTED : NS_ERROR_FILE_NOT_FOUND;
+      SetError(aResult);
       mDataSize = 0;
-    }
-    else {
+    } else {
       mState = READY;
     }
 
     mListener.swap(listener);
   }
 
   listener->OnChunkRead(aResult, this);
 
@@ -595,27 +589,47 @@ CacheFileChunk::OnFileRenamed(CacheFileH
   return NS_ERROR_UNEXPECTED;
 }
 
 bool
 CacheFileChunk::IsReady() const
 {
   mFile->AssertOwnsLock();
 
-  return (mState == READY || mState == WRITING);
+  return (NS_SUCCEEDED(mStatus) && (mState == READY || mState == WRITING));
 }
 
 bool
 CacheFileChunk::IsDirty() const
 {
   mFile->AssertOwnsLock();
 
   return mIsDirty;
 }
 
+nsresult
+CacheFileChunk::GetStatus()
+{
+  mFile->AssertOwnsLock();
+
+  return mStatus;
+}
+
+void
+CacheFileChunk::SetError(nsresult aStatus)
+{
+  if (NS_SUCCEEDED(mStatus)) {
+    MOZ_ASSERT(mState != ERROR);
+    mStatus = aStatus;
+    mState = ERROR;
+  } else {
+    MOZ_ASSERT(mState == ERROR);
+  }
+}
+
 char *
 CacheFileChunk::BufForWriting() const
 {
   mFile->AssertOwnsLock();
 
   MOZ_ASSERT(mBuf); // Writer should always first call EnsureBufSize()
 
   MOZ_ASSERT((mState == READY && !mRWBuf) ||
@@ -636,16 +650,20 @@ CacheFileChunk::BufForReading() const
   return mBuf ? mBuf : mRWBuf;
 }
 
 void
 CacheFileChunk::EnsureBufSize(uint32_t aBufSize)
 {
   mFile->AssertOwnsLock();
 
+  // EnsureBufSize() is called only when we want to write some data to the chunk
+  // and we never write data anymore once some error occurs.
+  MOZ_ASSERT(mState != ERROR);
+
   if (mBufSize >= aBufSize)
     return;
 
   bool copy = false;
   if (!mBuf && mState == WRITING) {
     // We need to duplicate the data that is being written on the background
     // thread, so make sure that all the data fits into the new buffer.
     copy = true;
--- a/netwerk/cache2/CacheFileChunk.h
+++ b/netwerk/cache2/CacheFileChunk.h
@@ -92,16 +92,19 @@ public:
   NS_IMETHOD OnDataRead(CacheFileHandle *aHandle, char *aBuf, nsresult aResult);
   NS_IMETHOD OnFileDoomed(CacheFileHandle *aHandle, nsresult aResult);
   NS_IMETHOD OnEOFSet(CacheFileHandle *aHandle, nsresult aResult);
   NS_IMETHOD OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult);
 
   bool   IsReady() const;
   bool   IsDirty() const;
 
+  nsresult GetStatus();
+  void     SetError(nsresult aStatus);
+
   char *       BufForWriting() const;
   const char * BufForReading() const;
   void         EnsureBufSize(uint32_t aBufSize);
   uint32_t     MemorySize() const { return sizeof(CacheFileChunk) + mRWBufSize + mBufSize; }
 
   // Memory reporting
   size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
@@ -118,16 +121,17 @@ private:
     READING = 1,
     WRITING = 2,
     READY   = 3,
     ERROR   = 4
   };
 
   uint32_t mIndex;
   EState   mState;
+  nsresult mStatus;
   bool     mIsDirty;
   bool     mRemovingChunk;
   uint32_t mDataSize;
 
   char    *mBuf;
   uint32_t mBufSize;
 
   char               *mRWBuf;
--- a/netwerk/cache2/CacheFileIOManager.cpp
+++ b/netwerk/cache2/CacheFileIOManager.cpp
@@ -22,35 +22,43 @@
 #include "nsISizeOf.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Services.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "private/pprio.h"
 #include "mozilla/VisualEventTracer.h"
+#include "mozilla/Preferences.h"
 
 // include files for ftruncate (or equivalent)
 #if defined(XP_UNIX)
 #include <unistd.h>
 #elif defined(XP_WIN)
 #include <windows.h>
 #undef CreateFile
 #undef CREATE_NEW
 #else
 // XXX add necessary include file for ftruncate (or equivalent)
 #endif
 
 
 namespace mozilla {
 namespace net {
 
-#define kOpenHandlesLimit      64
-#define kMetadataWriteDelay    5000
-#define kRemoveTrashStartDelay 60000   // in milliseconds
+#define kOpenHandlesLimit        64
+#define kMetadataWriteDelay      5000
+#define kRemoveTrashStartDelay   60000 // in milliseconds
+#define kSmartSizeUpdateInterval 60000 // in milliseconds
+
+#ifdef ANDROID
+const uint32_t kMaxCacheSizeKB = 200*1024; // 200 MB
+#else
+const uint32_t kMaxCacheSizeKB = 350*1024; // 350 MB
+#endif
 
 bool
 CacheFileHandle::DispatchRelease()
 {
   if (CacheFileIOManager::IsOnIOThreadOrCeased()) {
     return false;
   }
 
@@ -2373,16 +2381,18 @@ CacheFileIOManager::EvictIfOverLimitInte
   }
 
   if (mOverLimitEvicting) {
     LOG(("CacheFileIOManager::EvictIfOverLimitInternal() - Eviction already "
          "running."));
     return NS_OK;
   }
 
+  UpdateSmartCacheSize();
+
   uint32_t cacheUsage;
   rv = CacheIndex::GetCacheSize(&cacheUsage);
   NS_ENSURE_SUCCESS(rv, rv);
 
   uint32_t cacheLimit = CacheObserver::DiskCacheCapacity() >> 10;
   if (cacheUsage <= cacheLimit) {
     LOG(("CacheFileIOManager::EvictIfOverLimitInternal() - Cache size under "
          "limit. [cacheSize=%u, limit=%u]", cacheUsage, cacheLimit));
@@ -2419,16 +2429,18 @@ CacheFileIOManager::OverLimitEvictionInt
   // early anywhere in this method and the variable will contain a correct
   // value. Otherwise we would need to set it to false on every failing place.
   mOverLimitEvicting = false;
 
   if (mShuttingDown) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
+  UpdateSmartCacheSize();
+
   while (true) {
     uint32_t cacheUsage;
     rv = CacheIndex::GetCacheSize(&cacheUsage);
     NS_ENSURE_SUCCESS(rv, rv);
 
     uint32_t cacheLimit = CacheObserver::DiskCacheCapacity() >> 10;
     if (cacheUsage <= cacheLimit) {
       LOG(("CacheFileIOManager::OverLimitEvictionInternal() - Cache size under "
@@ -3527,16 +3539,126 @@ CacheFileIOManager::SyncRemoveAllCacheFi
     if (NS_FAILED(rv)) {
       nsAutoCString leafName;
       mTrashDir->GetNativeLeafName(leafName);
       mFailedTrashDirs.AppendElement(leafName);
     }
   }
 }
 
+// Returns default ("smart") size (in KB) of cache, given available disk space
+// (also in KB)
+static uint32_t
+SmartCacheSize(const uint32_t availKB)
+{
+  uint32_t maxSize = kMaxCacheSizeKB;
+
+  if (availKB > 100 * 1024 * 1024) {
+    return maxSize;  // skip computing if we're over 100 GB
+  }
+
+  // Grow/shrink in 10 MB units, deliberately, so that in the common case we
+  // don't shrink cache and evict items every time we startup (it's important
+  // that we don't slow down startup benchmarks).
+  uint32_t sz10MBs = 0;
+  uint32_t avail10MBs = availKB / (1024*10);
+
+  // .5% of space above 25 GB
+  if (avail10MBs > 2500) {
+    sz10MBs += static_cast<uint32_t>((avail10MBs - 2500)*.005);
+    avail10MBs = 2500;
+  }
+  // 1% of space between 7GB -> 25 GB
+  if (avail10MBs > 700) {
+    sz10MBs += static_cast<uint32_t>((avail10MBs - 700)*.01);
+    avail10MBs = 700;
+  }
+  // 5% of space between 500 MB -> 7 GB
+  if (avail10MBs > 50) {
+    sz10MBs += static_cast<uint32_t>((avail10MBs - 50)*.05);
+    avail10MBs = 50;
+  }
+
+#ifdef ANDROID
+  // On Android, smaller/older devices may have very little storage and
+  // device owners may be sensitive to storage footprint: Use a smaller
+  // percentage of available space and a smaller minimum.
+
+  // 20% of space up to 500 MB (10 MB min)
+  sz10MBs += std::max<uint32_t>(1, static_cast<uint32_t>(avail10MBs * .2));
+#else
+  // 40% of space up to 500 MB (50 MB min)
+  sz10MBs += std::max<uint32_t>(5, static_cast<uint32_t>(avail10MBs * .4));
+#endif
+
+  return std::min<uint32_t>(maxSize, sz10MBs * 10 * 1024);
+}
+
+nsresult
+CacheFileIOManager::UpdateSmartCacheSize()
+{
+  MOZ_ASSERT(mIOThread->IsCurrentThread());
+
+  nsresult rv;
+
+  if (!CacheObserver::UseNewCache()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  if (!CacheObserver::SmartCacheSizeEnabled()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  // Wait at least kSmartSizeUpdateInterval before recomputing smart size.
+  static const TimeDuration kUpdateLimit =
+    TimeDuration::FromMilliseconds(kSmartSizeUpdateInterval);
+  if (!mLastSmartSizeTime.IsNull() &&
+      (TimeStamp::NowLoRes() - mLastSmartSizeTime) < kUpdateLimit) {
+    return NS_OK;
+  }
+
+  // Do not compute smart size when cache size is not reliable.
+  bool isUpToDate = false;
+  CacheIndex::IsUpToDate(&isUpToDate);
+  if (!isUpToDate) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  uint32_t cacheUsage;
+  rv = CacheIndex::GetCacheSize(&cacheUsage);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    LOG(("CacheFileIOManager::UpdateSmartCacheSize() - Cannot get cacheUsage! "
+         "[rv=0x%08x]", rv));
+    return rv;
+  }
+
+  int64_t avail;
+  rv = mCacheDirectory->GetDiskSpaceAvailable(&avail);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    // Do not change smart size.
+    LOG(("CacheFileIOManager::UpdateSmartCacheSize() - GetDiskSpaceAvailable() "
+         "failed! [rv=0x%08x]", rv));
+    return rv;
+  }
+
+  mLastSmartSizeTime = TimeStamp::NowLoRes();
+
+  uint32_t smartSize = SmartCacheSize(static_cast<uint32_t>(avail / 1024) +
+                                      cacheUsage);
+
+  if (smartSize == (CacheObserver::DiskCacheCapacity() >> 10)) {
+    // Smart size has not changed.
+    return NS_OK;
+  }
+
+  CacheObserver::SetDiskCacheCapacity(smartSize << 10);
+
+  return NS_OK;
+}
+
 // Memory reporting
 
 namespace { // anon
 
 // A helper class that dispatches and waits for an event that gets result of
 // CacheFileIOManager->mHandles.SizeOfExcludingThis() on the I/O thread
 // to safely get handles memory report.
 // We must do this, since the handle list is only accessed and managed w/o
--- a/netwerk/cache2/CacheFileIOManager.h
+++ b/netwerk/cache2/CacheFileIOManager.h
@@ -354,16 +354,22 @@ private:
 
   nsresult ScheduleMetadataWriteInternal(CacheFile * aFile);
   nsresult UnscheduleMetadataWriteInternal(CacheFile * aFile);
   nsresult ShutdownMetadataWriteSchedulingInternal();
 
   static nsresult CacheIndexStateChanged();
   nsresult CacheIndexStateChangedInternal();
 
+  // Smart size calculation. UpdateSmartCacheSize() must be called on IO thread.
+  // It is called in EvictIfOverLimitInternal() just before we decide whether to
+  // start overlimit eviction or not and also in OverLimitEvictionInternal()
+  // before we start an eviction loop.
+  nsresult UpdateSmartCacheSize();
+
   // Memory reporting (private part)
   size_t SizeOfExcludingThisInternal(mozilla::MallocSizeOf mallocSizeOf) const;
 
   static CacheFileIOManager           *gInstance;
   TimeStamp                            mStartTime;
   bool                                 mShuttingDown;
   nsRefPtr<CacheIOThread>              mIOThread;
   nsCOMPtr<nsIFile>                    mCacheDirectory;
@@ -375,14 +381,15 @@ private:
   nsCOMPtr<nsITimer>                   mMetadataWritesTimer;
   bool                                 mOverLimitEvicting;
   bool                                 mRemovingTrashDirs;
   nsCOMPtr<nsITimer>                   mTrashTimer;
   nsCOMPtr<nsIFile>                    mTrashDir;
   nsCOMPtr<nsIDirectoryEnumerator>     mTrashDirEnumerator;
   nsTArray<nsCString>                  mFailedTrashDirs;
   nsRefPtr<CacheFileContextEvictor>    mContextEvictor;
+  TimeStamp                            mLastSmartSizeTime;
 };
 
 } // net
 } // mozilla
 
 #endif
--- a/netwerk/cache2/CacheFileInputStream.cpp
+++ b/netwerk/cache2/CacheFileInputStream.cpp
@@ -78,16 +78,19 @@ CacheFileInputStream::Available(uint64_t
 
   if (mClosed) {
     LOG(("CacheFileInputStream::Available() - Stream is closed. [this=%p, "
          "status=0x%08x]", this, mStatus));
     return NS_FAILED(mStatus) ? mStatus : NS_BASE_STREAM_CLOSED;
   }
 
   EnsureCorrectChunk(false);
+  if (NS_FAILED(mStatus))
+    return mStatus;
+
   *_retval = 0;
 
   if (mChunk) {
     int64_t canRead;
     const char *buf;
     CanRead(&canRead, &buf);
 
     if (canRead > 0)
@@ -119,16 +122,19 @@ CacheFileInputStream::Read(char *aBuf, u
     if NS_FAILED(mStatus)
       return mStatus;
 
     *_retval = 0;
     return NS_OK;
   }
 
   EnsureCorrectChunk(false);
+  if (NS_FAILED(mStatus))
+    return mStatus;
+
   if (!mChunk) {
     if (mListeningForChunk == -1) {
       LOG(("  no chunk, returning 0 read and NS_OK"));
       *_retval = 0;
       return NS_OK;
     }
     else {
       LOG(("  waiting for chuck, returning WOULD_BLOCK"));
@@ -189,16 +195,19 @@ CacheFileInputStream::ReadSegments(nsWri
     if NS_FAILED(mStatus)
       return mStatus;
 
     *_retval = 0;
     return NS_OK;
   }
 
   EnsureCorrectChunk(false);
+  if (NS_FAILED(mStatus))
+    return mStatus;
+
   if (!mChunk) {
     if (mListeningForChunk == -1) {
       *_retval = 0;
       return NS_OK;
     }
     else {
       return NS_BASE_STREAM_WOULD_BLOCK;
     }
@@ -430,17 +439,27 @@ CacheFileInputStream::OnChunkAvailable(n
     MOZ_ASSERT(!mCallback);
 
     LOG(("CacheFileInputStream::OnChunkAvailable() - Stream is closed, "
          "ignoring notification. [this=%p]", this));
 
     return NS_OK;
   }
 
-  mChunk = aChunk;
+  if (NS_SUCCEEDED(aResult)) {
+    mChunk = aChunk;
+  } else if (aResult != NS_ERROR_NOT_AVAILABLE) {
+    // We store the error in mStatus, so we can propagate it later to consumer
+    // in Read(), Available() etc. We need to handle NS_ERROR_NOT_AVAILABLE
+    // differently since it is returned when the requested chunk is not
+    // available and there is no writer that could create it, i.e. it means that
+    // we've reached the end of the file.
+    mStatus = aResult;
+  }
+
   MaybeNotifyListener();
 
   return NS_OK;
 }
 
 nsresult
 CacheFileInputStream::OnChunkUpdated(CacheFileChunk *aChunk)
 {
@@ -523,17 +542,24 @@ CacheFileInputStream::EnsureCorrectChunk
 
     return;
   }
 
   rv = mFile->GetChunkLocked(chunkIdx, false, this, getter_AddRefs(mChunk));
   if (NS_FAILED(rv)) {
     LOG(("CacheFileInputStream::EnsureCorrectChunk() - GetChunkLocked failed. "
          "[this=%p, idx=%d, rv=0x%08x]", this, chunkIdx, rv));
-
+    if (rv != NS_ERROR_NOT_AVAILABLE) {
+      // We store the error in mStatus, so we can propagate it later to consumer
+      // in Read(), Available() etc. We need to handle NS_ERROR_NOT_AVAILABLE
+      // differently since it is returned when the requested chunk is not
+      // available and there is no writer that could create it, i.e. it means
+      // that we've reached the end of the file.
+      mStatus = rv;
+    }
   }
   else if (!mChunk) {
     mListeningForChunk = static_cast<int64_t>(chunkIdx);
   }
 
   MaybeNotifyListener();
 }
 
@@ -582,17 +608,17 @@ CacheFileInputStream::MaybeNotifyListene
   LOG(("CacheFileInputStream::MaybeNotifyListener() [this=%p, mCallback=%p, "
        "mClosed=%d, mStatus=0x%08x, mChunk=%p, mListeningForChunk=%lld, "
        "mWaitingForUpdate=%d]", this, mCallback.get(), mClosed, mStatus,
        mChunk.get(), mListeningForChunk, mWaitingForUpdate));
 
   if (!mCallback)
     return;
 
-  if (mClosed) {
+  if (mClosed || NS_FAILED(mStatus)) {
     NotifyListener();
     return;
   }
 
   if (!mChunk) {
     if (mListeningForChunk == -1) {
       // EOF, should we notify even if mCallbackFlags == WAIT_CLOSURE_ONLY ??
       NotifyListener();
--- a/netwerk/cache2/CacheFileOutputStream.cpp
+++ b/netwerk/cache2/CacheFileOutputStream.cpp
@@ -93,16 +93,18 @@ CacheFileOutputStream::Write(const char 
 
     return NS_FAILED(mStatus) ? mStatus : NS_BASE_STREAM_CLOSED;
   }
 
   *_retval = aCount;
 
   while (aCount) {
     EnsureCorrectChunk(false);
+    if (NS_FAILED(mStatus))
+      return mStatus;
 
     FillHole();
 
     uint32_t chunkOffset = mPos - (mPos / kChunkSize) * kChunkSize;
     uint32_t canWrite = kChunkSize - chunkOffset;
     uint32_t thisWrite = std::min(static_cast<uint32_t>(canWrite), aCount);
     mChunk->EnsureBufSize(chunkOffset + thisWrite);
     memcpy(mChunk->BufForWriting() + chunkOffset, aBuf, thisWrite);
@@ -337,20 +339,23 @@ CacheFileOutputStream::EnsureCorrectChun
     else {
       ReleaseChunk();
     }
   }
 
   if (aReleaseOnly)
     return;
 
-  DebugOnly<nsresult> rv;
+  nsresult rv;
   rv = mFile->GetChunkLocked(chunkIdx, true, nullptr, getter_AddRefs(mChunk));
-  MOZ_ASSERT(NS_SUCCEEDED(rv),
-             "CacheFile::GetChunkLocked() should always succeed for writer");
+  if (NS_FAILED(rv)) {
+    LOG(("CacheFileOutputStream::EnsureCorrectChunk() - GetChunkLocked failed. "
+         "[this=%p, idx=%d, rv=0x%08x]", this, chunkIdx, rv));
+    mStatus = rv;
+  }
 }
 
 void
 CacheFileOutputStream::FillHole()
 {
   mFile->AssertOwnsLock();
 
   MOZ_ASSERT(mChunk);
--- a/netwerk/cache2/CacheObserver.cpp
+++ b/netwerk/cache2/CacheObserver.cpp
@@ -48,16 +48,19 @@ uint32_t CacheObserver::sMetadataMemoryL
 static int32_t const kDefaultMemoryCacheCapacity = -1; // autodetect
 int32_t CacheObserver::sMemoryCacheCapacity = kDefaultMemoryCacheCapacity;
 // Cache of the calculated memory capacity based on the system memory size
 int32_t CacheObserver::sAutoMemoryCacheCapacity = -1;
 
 static uint32_t const kDefaultDiskCacheCapacity = 250 * 1024; // 250 MB
 uint32_t CacheObserver::sDiskCacheCapacity = kDefaultDiskCacheCapacity;
 
+static bool const kDefaultSmartCacheSizeEnabled = false;
+bool CacheObserver::sSmartCacheSizeEnabled = kDefaultSmartCacheSizeEnabled;
+
 static uint32_t const kDefaultMaxMemoryEntrySize = 4 * 1024; // 4 MB
 uint32_t CacheObserver::sMaxMemoryEntrySize = kDefaultMaxMemoryEntrySize;
 
 static uint32_t const kDefaultMaxDiskEntrySize = 50 * 1024; // 50 MB
 uint32_t CacheObserver::sMaxDiskEntrySize = kDefaultMaxDiskEntrySize;
 
 static uint32_t const kDefaultCompressionLevel = 1;
 uint32_t CacheObserver::sCompressionLevel = kDefaultCompressionLevel;
@@ -128,16 +131,18 @@ CacheObserver::AttachToPreferences()
   mozilla::Preferences::AddBoolVarCache(
     &sUseMemoryCache, "browser.cache.memory.enable", kDefaultUseMemoryCache);
 
   mozilla::Preferences::AddUintVarCache(
     &sMetadataMemoryLimit, "browser.cache.disk.metadata_memory_limit", kDefaultMetadataMemoryLimit);
 
   mozilla::Preferences::AddUintVarCache(
     &sDiskCacheCapacity, "browser.cache.disk.capacity", kDefaultDiskCacheCapacity);
+  mozilla::Preferences::AddBoolVarCache(
+    &sSmartCacheSizeEnabled, "browser.cache.disk.smart_size.enabled", kDefaultSmartCacheSizeEnabled);
   mozilla::Preferences::AddIntVarCache(
     &sMemoryCacheCapacity, "browser.cache.memory.capacity", kDefaultMemoryCacheCapacity);
 
   mozilla::Preferences::AddUintVarCache(
     &sMaxDiskEntrySize, "browser.cache.disk.max_entry_size", kDefaultMaxDiskEntrySize);
   mozilla::Preferences::AddUintVarCache(
     &sMaxMemoryEntrySize, "browser.cache.memory.max_entry_size", kDefaultMaxMemoryEntrySize);
 
@@ -269,16 +274,42 @@ bool const CacheObserver::UseNewCache()
     case 1: // use the new cache backend
       return true;
   }
 
   return true;
 }
 
 // static
+void
+CacheObserver::SetDiskCacheCapacity(uint32_t aCapacity)
+{
+  sDiskCacheCapacity = aCapacity >> 10;
+
+  if (!sSelf) {
+    return;
+  }
+
+  if (NS_IsMainThread()) {
+    sSelf->StoreDiskCacheCapacity();
+  } else {
+    nsCOMPtr<nsIRunnable> event =
+      NS_NewRunnableMethod(sSelf, &CacheObserver::StoreDiskCacheCapacity);
+    NS_DispatchToMainThread(event);
+  }
+}
+
+void
+CacheObserver::StoreDiskCacheCapacity()
+{
+  mozilla::Preferences::SetInt("browser.cache.disk.capacity",
+                               sDiskCacheCapacity);
+}
+
+// static
 void CacheObserver::ParentDirOverride(nsIFile** aDir)
 {
   if (NS_WARN_IF(!aDir))
     return;
 
   *aDir = nullptr;
 
   if (!sSelf)
--- a/netwerk/cache2/CacheObserver.h
+++ b/netwerk/cache2/CacheObserver.h
@@ -12,17 +12,17 @@
 #include <algorithm>
 
 namespace mozilla {
 namespace net {
 
 class CacheObserver : public nsIObserver
                     , public nsSupportsWeakReference
 {
-  NS_DECL_ISUPPORTS
+  NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   virtual ~CacheObserver() {}
 
   static nsresult Init();
   static nsresult Shutdown();
   static CacheObserver* Self() { return sSelf; }
 
@@ -32,16 +32,19 @@ class CacheObserver : public nsIObserver
     { return sUseDiskCache; }
   static bool const UseMemoryCache()
     { return sUseMemoryCache; }
   static uint32_t const MetadataMemoryLimit() // result in bytes.
     { return sMetadataMemoryLimit << 10; }
   static uint32_t const MemoryCacheCapacity(); // result in bytes.
   static uint32_t const DiskCacheCapacity() // result in bytes.
     { return sDiskCacheCapacity << 10; }
+  static void SetDiskCacheCapacity(uint32_t); // parameter in bytes.
+  static bool const SmartCacheSizeEnabled()
+    { return sSmartCacheSizeEnabled; }
   static uint32_t const MaxMemoryEntrySize() // result in bytes.
     { return sMaxMemoryEntrySize << 10; }
   static uint32_t const MaxDiskEntrySize() // result in bytes.
     { return sMaxDiskEntrySize << 10; }
   static uint32_t const CompressionLevel()
     { return sCompressionLevel; }
   static uint32_t const HalfLifeSeconds()
     { return sHalfLifeHours * 60 * 60; }
@@ -51,26 +54,28 @@ class CacheObserver : public nsIObserver
     { return sSanitizeOnShutdown && sClearCacheOnShutdown; }
   static void ParentDirOverride(nsIFile ** aDir);
 
   static bool const EntryIsTooBig(int64_t aSize, bool aUsingDisk);
 
 private:
   static CacheObserver* sSelf;
 
+  void StoreDiskCacheCapacity();
   void AttachToPreferences();
   void SchduleAutoDelete();
 
   static uint32_t sUseNewCache;
   static bool sUseMemoryCache;
   static bool sUseDiskCache;
   static uint32_t sMetadataMemoryLimit;
   static int32_t sMemoryCacheCapacity;
   static int32_t sAutoMemoryCacheCapacity;
   static uint32_t sDiskCacheCapacity;
+  static bool sSmartCacheSizeEnabled;
   static uint32_t sMaxMemoryEntrySize;
   static uint32_t sMaxDiskEntrySize;
   static uint32_t sCompressionLevel;
   static uint32_t sHalfLifeHours;
   static int32_t sHalfLifeExperiment;
   static bool sSanitizeOnShutdown;
   static bool sClearCacheOnShutdown;
 
--- a/testing/mozbase/mozlog/mozlog/structured/commandline.py
+++ b/testing/mozbase/mozlog/mozlog/structured/commandline.py
@@ -58,16 +58,18 @@ def setup_logging(suite, args, defaults)
                      when there is no logging supplied on the command line.
 
     :rtype: StructuredLogger
     """
     logger = StructuredLogger(suite)
     prefix = "log_"
     found = False
     found_stdout_logger = False
+    if not hasattr(args, 'iteritems'):
+        args = vars(args)
     for name, values in args.iteritems():
         if name.startswith(prefix) and values is not None:
             for value in values:
                 found = True
                 if value == sys.stdout:
                     found_stdout_logger = True
                 formatter_cls = log_formatters[name[len(prefix):]][0]
                 logger.add_handler(handlers.StreamHandler(stream=value,
--- a/testing/mozbase/mozlog/tests/test_structured.py
+++ b/testing/mozbase/mozlog/tests/test_structured.py
@@ -1,15 +1,20 @@
+import argparse
 import os
 import time
 import unittest
 import StringIO
 import json
 
-from mozlog.structured import structuredlog, reader
+from mozlog.structured import (
+    commandline,
+    reader,
+    structuredlog,
+)
 
 
 class TestHandler(object):
     def __init__(self):
         self.last_item = None
 
     def __call__(self, data):
         self.last_item = data
@@ -177,16 +182,24 @@ class TestStructuredLog(BaseStructuredTe
                                 "message": "line 3"})
 
         file_like.write("line 4\r\n")
 
         self.assert_log_equals({"action": "log",
                                 "level": "INFO",
                                 "message": "line 4"})
 
+class TestCommandline(unittest.TestCase):
+    def test_setup_logging(self):
+        parser = argparse.ArgumentParser()
+        commandline.add_logging_group(parser)
+        args = parser.parse_args(["--log-raw=/tmp/foo"])
+        logger = commandline.setup_logging("test", args, {})
+        self.assertEqual(len(logger.handlers), 1)
+
 class TestReader(unittest.TestCase):
     def to_file_like(self, obj):
         data_str = "\n".join(json.dumps(item) for item in obj)
         return StringIO.StringIO(data_str)
 
     def test_read(self):
         data = [{"action": "action_0", "data": "data_0"},
                 {"action": "action_1", "data": "data_1"}]
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -183,8 +183,11 @@ user_pref("browser.cache.use_new_backend
 // Don't connect to Yahoo! for RSS feed tests.
 // en-US only uses .types.0.uri, but set all of them just to be sure.
 user_pref('browser.contentHandlers.types.0.uri', 'http://test1.example.org/rss?url=%%s')
 user_pref('browser.contentHandlers.types.1.uri', 'http://test1.example.org/rss?url=%%s')
 user_pref('browser.contentHandlers.types.2.uri', 'http://test1.example.org/rss?url=%%s')
 user_pref('browser.contentHandlers.types.3.uri', 'http://test1.example.org/rss?url=%%s')
 user_pref('browser.contentHandlers.types.4.uri', 'http://test1.example.org/rss?url=%%s')
 user_pref('browser.contentHandlers.types.5.uri', 'http://test1.example.org/rss?url=%%s')
+
+// We want to collect telemetry, but we don't want to send in the results.
+user_pref('toolkit.telemetry.server', 'https://%(server)s/telemetry-dummy/');
--- a/toolkit/components/places/PlacesTransactions.jsm
+++ b/toolkit/components/places/PlacesTransactions.jsm
@@ -346,26 +346,30 @@ let PlacesTransactions = {
    * @note All PlacesTransactions operations are serialized. This means that the
    * transactions history state may change by the time the transaction/generator
    * is processed.  It's guaranteed, however, that a generator function "blocks"
    * the queue: that is, it is assured that no other operations are performed
    * by or on PlacesTransactions until the generator returns.  Keep in mind you
    * are not protected from consumers who use the raw places APIs directly.
    */
   transact: function (aToTransact) {
-    let generatorMode = typeof(aToTransact) == "function";
-    if (generatorMode) {
-      if (!aToTransact.isGenerator())
+    let isGeneratorObj =
+      o => Object.prototype.toString.call(o) ==  "[object Generator]";
+
+    let generator = null;
+    if (typeof(aToTransact) == "function") {
+      generator = aToTransact();
+      if (!isGeneratorObj(generator))
         throw new Error("aToTransact is not a generator function");
     }
-    else {
-      if (!TransactionsHistory.isProxifiedTransactionObject(aToTransact))
-        throw new Error("aToTransact is not a valid transaction object");
-      if (executedTransactions.has(aToTransact))
-        throw new Error("Transactions objects may not be recycled.");
+    else if (!TransactionsHistory.isProxifiedTransactionObject(aToTransact)) {
+      throw new Error("aToTransact is not a valid transaction object");
+    }
+    else if (executedTransactions.has(aToTransact)) {
+      throw new Error("Transactions objects may not be recycled.");
     }
 
     return Serialize(function* () {
       // The entry in the transactions history is created once the first
       // transaction is committed. This means that if |transact| is called
       // in its "generator mode" and no transactions are committed by the
       // generator, the transactions history is left unchanged.
       // Bug 982115: Depending on how this API is actually used we may revise
@@ -382,17 +386,17 @@ let PlacesTransactions = {
 
       function* transactBatch(aGenerator) {
         let error = false;
         let sendValue = undefined;
         while (true) {
           let next = error ?
                      aGenerator.throw(sendValue) : aGenerator.next(sendValue);
           sendValue = next.value;
-          if (Object.prototype.toString.call(sendValue) == "[object Generator]") {
+          if (isGeneratorObj(sendValue)) {
             sendValue = yield transactBatch(sendValue);
           }
           else if (typeof(sendValue) == "object" && sendValue) {
             if (TransactionsHistory.isProxifiedTransactionObject(sendValue)) {
               if (executedTransactions.has(sendValue)) {
                 sendValue = new Error("Transactions may not be recycled.");
                 error = true;
               }
@@ -405,18 +409,18 @@ let PlacesTransactions = {
             }
           }
           if (next.done)
             break;
         }
         return sendValue;
       }
 
-      if (generatorMode)
-        return yield transactBatch(aToTransact());
+      if (generator)
+        return yield transactBatch(generator);
       else
         return yield transactOneTransaction(aToTransact);
     }.bind(this));
   },
 
   /**
    * Asynchronously undo the transaction immediately after the current undo
    * position in the transactions history in the reverse order, if any, and
@@ -882,19 +886,20 @@ PT.NewLivemark.prototype = Object.seal({
     };
     return guid;
   }
 });
 
 /**
  * Transaction for moving an item.
  *
- * Required Input Properties: GUID, newParentGUID, newIndex.
+ * Required Input Properties: GUID, newParentGUID.
+ * Optional Input Properties  newIndex.
  */
-PT.MoveItem = DefineTransaction(["GUID", "newParentGUID", "newIndex"]);
+PT.MoveItem = DefineTransaction(["GUID", "newParentGUID"], ["newIndex"]);
 PT.MoveItem.prototype = Object.seal({
   execute: function* (aGUID, aNewParentGUID, aNewIndex) {
     let itemId = yield PlacesUtils.promiseItemId(aGUID),
         oldParentId = PlacesUtils.bookmarks.getFolderIdForItem(itemId),
         oldIndex = PlacesUtils.bookmarks.getItemIndex(itemId),
         newParentId = yield PlacesUtils.promiseItemId(aNewParentGUID);
 
     PlacesUtils.bookmarks.moveItem(itemId, newParentId, aNewIndex);
--- a/toolkit/components/places/tests/unit/test_async_transactions.js
+++ b/toolkit/components/places/tests/unit/test_async_transactions.js
@@ -449,18 +449,17 @@ add_task(function* test_move_items_to_fo
     let bkm_b_txn = PT.NewBookmark(bkm_b_info);
     bkm_b_info.GUID = yield bkm_b_txn;
     return [folder_a_txn, bkm_a_txn, bkm_b_txn];
   });
 
   ensureUndoState([[bkm_b_txn, bkm_a_txn, folder_a_txn]], 0);
 
   let moveTxn = PT.MoveItem({ GUID:          bkm_a_info.GUID
-                            , newParentGUID: folder_a_info.GUID
-                            , newIndex:      bmsvc.DEFAULT_INDEX });
+                            , newParentGUID: folder_a_info.GUID });
   yield PT.transact(moveTxn);
 
   let ensureDo = () => {
     ensureUndoState([[moveTxn], [bkm_b_txn, bkm_a_txn, folder_a_txn]], 0);
     ensureItemsMoved({ GUID:          bkm_a_info.GUID
                      , oldParentGUID: folder_a_info.GUID
                      , newParentGUID: folder_a_info.GUID
                      , oldIndex:      0
--- a/toolkit/components/url-classifier/SafeBrowsing.jsm
+++ b/toolkit/components/url-classifier/SafeBrowsing.jsm
@@ -8,17 +8,22 @@ const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 
 // Skip all the ones containining "test", because we never need to ask for
 // updates for them.
 function getLists(prefName) {
-  return Services.prefs.getCharPref(prefName).split(",")
+  let pref = Services.prefs.getCharPref(prefName);
+  // Splitting an empty string returns [''], we really want an empty array.
+  if (!pref) {
+    return [];
+  }
+  return pref.split(",")
     .filter(function(value) { return value.indexOf("test-") == -1; })
     .map(function(value) { return value.trim(); });
 }
 
 // These may be a comma-separated lists of tables.
 const phishingLists = getLists("urlclassifier.phish_table");
 const malwareLists = getLists("urlclassifier.malware_table");
 const downloadBlockLists = getLists("urlclassifier.downloadBlockTable");
--- a/toolkit/components/url-classifier/content/listmanager.js
+++ b/toolkit/components/url-classifier/content/listmanager.js
@@ -183,23 +183,37 @@ PROT_ListManager.prototype.maybeStartMan
   if (this.isTesting_)
     return;
 
   // We might have been told about tables already, so see if we should be
   // actually updating.
   this.maybeToggleUpdateChecking();
 }
 
-PROT_ListManager.prototype.kickoffUpdate_ = function (tableData)
+/**
+ * Acts as a nsIUrlClassifierCallback for getTables.
+ */
+PROT_ListManager.prototype.kickoffUpdate_ = function (onDiskTableData)
 {
   this.startingUpdate_ = false;
+  var initialUpdateDelay = 3000;
+
+  // Check if any table registered for updates has ever been downloaded.
+  var diskTablesAreUpdating = false;
+  for (var tableName in this.tablesData) {
+    if (this.tablesData[tableName].needsUpdate) {
+      if (onDiskTableData.indexOf(tableName) != -1) {
+        diskTablesAreUpdating = true;
+      }
+    }
+  }
+
   // If the user has never downloaded tables, do the check now.
   // If the user has tables, add a fuzz of a few minutes.
-  var initialUpdateDelay = 3000;
-  if (tableData != "") {
+  if (diskTablesAreUpdating) {
     // Add a fuzz of 0-5 minutes.
     initialUpdateDelay += Math.floor(Math.random() * (5 * 60 * 1000));
   }
 
   this.currentUpdateChecker_ =
     new G_Alarm(BindToObject(this.checkForUpdates, this),
                 initialUpdateDelay);
 }
--- a/toolkit/themes/windows/mozapps/jar.mn
+++ b/toolkit/themes/windows/mozapps/jar.mn
@@ -8,17 +8,17 @@ toolkit.jar:
 # NOTE: If you add a new file here, you'll need to add it to the aero
 # section at the bottom of this file
         skin/classic/mozapps/downloads/downloadButtons.png         (downloads/downloadButtons.png)
         skin/classic/mozapps/downloads/downloadIcon.png            (downloads/downloadIcon.png)
         skin/classic/mozapps/downloads/downloads.css               (downloads/downloads.css)
         skin/classic/mozapps/downloads/unknownContentType.css      (downloads/unknownContentType.css)
         skin/classic/mozapps/extensions/about.css                  (extensions/about.css)
         skin/classic/mozapps/extensions/blocklist.css              (extensions/blocklist.css)
-        skin/classic/mozapps/extensions/extensions.css             (extensions/extensions.css)
+*       skin/classic/mozapps/extensions/extensions.css             (extensions/extensions.css)
 *       skin/classic/mozapps/extensions/selectAddons.css           (extensions/selectAddons.css)
         skin/classic/mozapps/extensions/update.css                 (extensions/update.css)
         skin/classic/mozapps/extensions/extensions.svg             (extensions/extensions.svg)
         skin/classic/mozapps/extensions/category-search.png        (extensions/category-search.png)
         skin/classic/mozapps/extensions/category-discover.png      (extensions/category-discover.png)
         skin/classic/mozapps/extensions/category-languages.png     (extensions/localeGeneric.png)
         skin/classic/mozapps/extensions/category-searchengines.png (extensions/category-searchengines.png)
         skin/classic/mozapps/extensions/category-extensions.png    (extensions/extensionGeneric.png)
--- a/widget/gonk/nativewindow/moz.build
+++ b/widget/gonk/nativewindow/moz.build
@@ -36,17 +36,17 @@ elif CONFIG['ANDROID_VERSION'] in ('17',
         'GonkNativeWindowJB.h',
     ]
 elif CONFIG['ANDROID_VERSION'] == '15':
     EXPORTS += [
         'GonkNativeWindowClientICS.h',
         'GonkNativeWindowICS.h',
     ]
 
-if CONFIG['MOZ_B2G_CAMERA'] or CONFIG['MOZ_OMX_DECODER']:
+if CONFIG['MOZ_B2G_CAMERA'] or CONFIG['MOZ_OMX_DECODER'] or CONFIG['MOZ_WEBRTC']:
     if CONFIG['ANDROID_VERSION'] == '19':
         SOURCES += [
             'GonkBufferQueueKK.cpp',
             'GonkConsumerBaseKK.cpp',
             'GonkNativeWindowClientKK.cpp',
             'GonkNativeWindowKK.cpp',
             'IGonkGraphicBufferConsumer.cpp',
         ]
--- a/widget/xpwidgets/nsIdleService.cpp
+++ b/widget/xpwidgets/nsIdleService.cpp
@@ -428,21 +428,21 @@ nsIdleService::AddIdleObserver(nsIObserv
 
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     dom::ContentChild* cpc = dom::ContentChild::GetSingleton();
     cpc->AddIdleObserver(aObserver, aIdleTimeInS);
     return NS_OK;
   }
 
   PR_LOG(sLog, PR_LOG_DEBUG,
-       ("idleService: Register idle observer %x for %d seconds",
+       ("idleService: Register idle observer %p for %d seconds",
         aObserver, aIdleTimeInS));
 #ifdef MOZ_WIDGET_ANDROID
   __android_log_print(ANDROID_LOG_INFO, "IdleService",
-                      "Register idle observer %x for %d seconds",
+                      "Register idle observer %p for %d seconds",
                       aObserver, aIdleTimeInS);
 #endif
 
   // Put the time + observer in a struct we can keep:
   IdleListener listener(aObserver, aIdleTimeInS);
 
   if (!mArrayListeners.AppendElement(listener)) {
     return NS_ERROR_OUT_OF_MEMORY;
@@ -498,33 +498,33 @@ nsIdleService::RemoveIdleObserver(nsIObs
   // little while.
   IdleListenerComparator c;
   nsTArray<IdleListener>::index_type listenerIndex = mArrayListeners.IndexOf(listener, 0, c);
   if (listenerIndex != mArrayListeners.NoIndex) {
     if (mArrayListeners.ElementAt(listenerIndex).isIdle)
       mIdleObserverCount--;
     mArrayListeners.RemoveElementAt(listenerIndex);
     PR_LOG(sLog, PR_LOG_DEBUG,
-           ("idleService: Remove observer %x (%d seconds), %d remain idle",
+           ("idleService: Remove observer %p (%d seconds), %d remain idle",
             aObserver, aTimeInS, mIdleObserverCount));
 #ifdef MOZ_WIDGET_ANDROID
     __android_log_print(ANDROID_LOG_INFO, "IdleService",
-                        "Remove observer %x (%d seconds), %d remain idle",
+                        "Remove observer %p (%d seconds), %d remain idle",
                         aObserver, aTimeInS, mIdleObserverCount);
 #endif
     return NS_OK;
   }
 
   // If we get here, we haven't removed anything:
   PR_LOG(sLog, PR_LOG_WARNING, 
-         ("idleService: Failed to remove idle observer %x (%d seconds)",
+         ("idleService: Failed to remove idle observer %p (%d seconds)",
           aObserver, aTimeInS));
 #ifdef MOZ_WIDGET_ANDROID
   __android_log_print(ANDROID_LOG_INFO, "IdleService",
-                      "Failed to remove idle observer %x (%d seconds)",
+                      "Failed to remove idle observer %p (%d seconds)",
                       aObserver, aTimeInS);
 #endif
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsIdleService::ResetIdleTimeOut(uint32_t idleDeltaInMS)
 {
@@ -584,21 +584,21 @@ nsIdleService::ResetIdleTimeOut(uint32_t
   // We need a text string to send with any state change events.
   nsAutoString timeStr;
 
   timeStr.AppendInt((int32_t)(idleDeltaInMS / PR_MSEC_PER_SEC));
 
   // Send the "non-idle" events.
   while (numberOfPendingNotifications--) {
     PR_LOG(sLog, PR_LOG_DEBUG,
-           ("idleService: Reset idle timeout: tell observer %x user is back",
+           ("idleService: Reset idle timeout: tell observer %p user is back",
             notifyList[numberOfPendingNotifications]));
 #ifdef MOZ_WIDGET_ANDROID
     __android_log_print(ANDROID_LOG_INFO, "IdleService",
-                        "Reset idle timeout: tell observer %x user is back",
+                        "Reset idle timeout: tell observer %p user is back",
                         notifyList[numberOfPendingNotifications]);
 #endif
     notifyList[numberOfPendingNotifications]->Observe(this,
                                                       OBSERVER_TOPIC_ACTIVE,
                                                       timeStr.get());
   }
   return NS_OK;
 }
@@ -768,21 +768,21 @@ nsIdleService::IdleTimerCallback(void)
 
   // We need a text string to send with any state change events.
   nsAutoString timeStr;
   timeStr.AppendInt(currentIdleTimeInS);
 
   // Notify all listeners that just timed out.
   while (numberOfPendingNotifications--) {
     PR_LOG(sLog, PR_LOG_DEBUG,
-           ("idleService: **** Idle timer callback: tell observer %x user is idle",
+           ("idleService: **** Idle timer callback: tell observer %p user is idle",
             notifyList[numberOfPendingNotifications]));
 #ifdef MOZ_WIDGET_ANDROID
   __android_log_print(ANDROID_LOG_INFO, "IdleService",
-                      "Idle timer callback: tell observer %x user is idle",
+                      "Idle timer callback: tell observer %p user is idle",
                       notifyList[numberOfPendingNotifications]);
 #endif
     notifyList[numberOfPendingNotifications]->Observe(this,
                                                       OBSERVER_TOPIC_IDLE,
                                                       timeStr.get());
   }
 }
 
@@ -887,21 +887,21 @@ nsIdleService::ReconfigureTimer(void)
 
   // Check if we should correct the timeout time because we should poll before.
   if ((mIdleObserverCount > 0) && UsePollMode()) {
     TimeStamp pollTimeout =
         curTime + TimeDuration::FromMilliseconds(MIN_IDLE_POLL_INTERVAL_MSEC);
 
     if (nextTimeoutAt > pollTimeout) {
       PR_LOG(sLog, PR_LOG_DEBUG,
-           ("idleService: idle observers, reducing timeout to %u msec from now",
+           ("idleService: idle observers, reducing timeout to %lu msec from now",
             MIN_IDLE_POLL_INTERVAL_MSEC));
 #ifdef MOZ_WIDGET_ANDROID
       __android_log_print(ANDROID_LOG_INFO, "IdleService",
-                          "idle observers, reducing timeout to %u msec from now",
+                          "idle observers, reducing timeout to %lu msec from now",
                           MIN_IDLE_POLL_INTERVAL_MSEC);
 #endif
       nextTimeoutAt = pollTimeout;
     }
   }
 
   SetTimerExpiryIfBefore(nextTimeoutAt);
 }
--- a/xpcom/build/nsXPComInit.cpp
+++ b/xpcom/build/nsXPComInit.cpp
@@ -129,17 +129,17 @@ extern nsresult nsStringInputStreamConst
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/SystemMemoryReporter.h"
 
 #ifdef MOZ_VISUAL_EVENT_TRACER
 #include "mozilla/VisualEventTracer.h"
 #endif
 
 #include "ogg/ogg.h"
-#ifdef MOZ_VPX
+#if defined(MOZ_VPX) && !defined(MOZ_VPX_NO_MEM_REPORTING)
 #include "vpx_mem/vpx_mem.h"
 #endif
 #ifdef MOZ_WEBM
 #include "nestegg/nestegg.h"
 #endif
 
 #include "GeckoProfiler.h"
 
@@ -597,17 +597,17 @@ NS_InitXPCOM2(nsIServiceManager* *result
     mozilla::SetICUMemoryFunctions();
 
     // Do the same for libogg.
     ogg_set_mem_functions(OggReporter::CountingMalloc,
                           OggReporter::CountingCalloc,
                           OggReporter::CountingRealloc,
                           OggReporter::CountingFree);
 
-#ifdef MOZ_VPX
+#if defined(MOZ_VPX) && !defined(MOZ_VPX_NO_MEM_REPORTING)
     // And for VPX.
     vpx_mem_set_functions(VPXReporter::CountingMalloc,
                           VPXReporter::CountingCalloc,
                           VPXReporter::CountingRealloc,
                           VPXReporter::CountingFree,
                           memcpy,
                           memset,
                           memmove);