Merge backout on a CLOSED TREE.
authorMs2ger <ms2ger@gmail.com>
Thu, 08 Nov 2012 09:20:52 +0100
changeset 112671 e0d7b394462b18bea7f70c5f6aa297800371d666
parent 112670 82c59210f11fbad3621810e0787de8db6c026c83 (current diff)
parent 112669 bdd3bfd15630dca7e468e1b77081db88beb79a2a (diff)
child 112672 84b0991ccd9781f8231179dbc623e9a1bffe48e0
child 112717 1437578c371fea3073f73d7b7ee2b6a65b26507b
push id17714
push userMs2ger@gmail.com
push dateThu, 08 Nov 2012 08:21:14 +0000
treeherdermozilla-inbound@e0d7b394462b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge backout on a CLOSED TREE.
browser/devtools/debugger/VariablesView.jsm
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
layout/reftests/flexbox/flexbox-inlinecontent-horiz-6-ref.xhtml
layout/reftests/flexbox/flexbox-inlinecontent-horiz-6.xhtml
layout/reftests/flexbox/flexbox-whitespace-handling-3-ref.xhtml
layout/reftests/flexbox/flexbox-whitespace-handling-3.xhtml
mobile/android/base/gfx/ViewportMetrics.java
netwerk/test/unit_ipc/test_httpcancel_wrap.js
netwerk/test/unit_ipc/test_traceable_channel_wrap.js
xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_bsdos.s
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -1729,16 +1729,23 @@ Accessible::ARIATransformRole(role aRole
       while ((targetAcc = rel.Next()))
         if (targetAcc->Role() == roles::COMBOBOX)
           return roles::COMBOBOX_LIST;
     }
 
   } else if (aRole == roles::OPTION) {
     if (mParent && mParent->Role() == roles::COMBOBOX_LIST)
       return roles::COMBOBOX_OPTION;
+
+  } else if (aRole == roles::MENUITEM) {
+    // Menuitem has a submenu.
+    if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_haspopup,
+                              nsGkAtoms::_true, eCaseMatters)) {
+      return roles::PARENT_MENUITEM;
+    }
   }
 
   return aRole;
 }
 
 role
 Accessible::NativeRole()
 {
--- a/accessible/tests/mochitest/tree/Makefile.in
+++ b/accessible/tests/mochitest/tree/Makefile.in
@@ -11,16 +11,17 @@ relativesrcdir  = accessible/tree
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_A11Y_FILES =\
 		dockids.html \
 	$(warning test_applicationacc.xul temporarily disabled, see bug 561508) \
 		test_aria_globals.html \
 		test_aria_imgmap.html \
+		test_aria_menu.html \
 		test_aria_presentation.html \
 		test_brokencontext.html \
 		test_button.xul \
 		test_canvas.html \
 		test_combobox.xul \
 		test_cssoverflow.html \
 		test_dochierarchy.html \
 		test_dockids.html \
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/tree/test_aria_menu.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Test accessible tree when ARIA role menuitem is used</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../role.js"></script>
+
+  <script type="application/javascript">
+  function doTest()
+  {
+    // Menuitem with no popup.
+    tree =
+      { SECTION: [ // container
+        { MENUPOPUP: [ // menu
+          { MENUITEM: [
+            { STATICTEXT: [] }, // bullet
+            { TEXT_LEAF: [] }
+          ] }
+        ] }
+      ] }
+    testAccessibleTree("menu", tree);
+
+    // Menuitem with explicit no popup.
+    tree =
+      { SECTION: [ // container
+        { MENUPOPUP: [ // menu
+          { MENUITEM: [
+            { STATICTEXT: [] }, // bullet
+            { TEXT_LEAF: [] }
+          ] }
+        ] }
+      ] }
+    testAccessibleTree("menu_nopopup", tree);
+
+    // Menuitem with popup.
+    tree =
+      { SECTION: [ // container
+        { MENUPOPUP: [ // menu
+          { PARENT_MENUITEM: [ // menuitem with aria-haspopup="true"
+            { STATICTEXT: [] }, // bullet
+            { TEXT_LEAF: [] }
+          ] }
+        ] }
+      ] }
+    testAccessibleTree("menu_popup", tree);
+
+    SimpleTest.finish();
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=786566"
+     title="ARIA menuitem acting as submenu should have PARENT_MENUITEM role">
+    Mozilla Bug 786566
+  </a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <div id="menu">
+    <ul role="menu">
+      <li role="menuitem">Normal Menu</li>
+    </ul>
+  </div>
+
+  <div id="menu_nopopup">
+    <ul role="menu">
+      <li role="menuitem" aria-haspopup="false">Menu with explicit no popup</li>
+    </ul>
+  </div>
+
+  <div id="menu_popup">
+    <ul role="menu">
+      <li role="menuitem" aria-haspopup="true">Menu with popup</li>
+    </ul>
+  </div>
+
+</body>
+</html>
--- a/b2g/chrome/content/dbg-browser-actors.js
+++ b/b2g/chrome/content/dbg-browser-actors.js
@@ -132,18 +132,17 @@ DeviceTabActor.prototype.grip = function
  * up the content window for debugging.
  */
 DeviceTabActor.prototype._pushContext = function DTA_pushContext() {
   dbg_assert(!this._contextPool, "Can't push multiple contexts");
 
   this._contextPool = new ActorPool(this.conn);
   this.conn.addActorPool(this._contextPool);
 
-  this.threadActor = new ThreadActor(this);
-  this._addDebuggees(this.browser.wrappedJSObject);
+  this.threadActor = new ThreadActor(this, this.browser.wrappedJSObject);
   this._contextPool.addActor(this.threadActor);
 };
 
 // Protocol Request Handlers
 
 /**
  * Prepare to enter a nested event loop by disabling debuggee events.
  */
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -126,16 +126,21 @@ SettingsListener.observe('language.curre
 
   ['ril.data.mmsport'].forEach(function(key) {
     SettingsListener.observe(key, null, function(value) {
       if (value != null) {
         Services.prefs.setIntPref(key, value);
       }
     });
   });
+
+  SettingsListener.observe('ril.sms.strict7BitEncoding.enabled', false,
+    function(value) {
+      Services.prefs.setBoolPref('dom.sms.strict7BitEncoding', value);
+  });
 })();
 
 //=================== DeviceInfo ====================
 Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
 Components.utils.import('resource://gre/modules/ctypes.jsm');
 (function DeviceInfoToSettings() {
   XPCOMUtils.defineLazyServiceGetter(this, 'gSettingsService',
                                      '@mozilla.org/settingsService;1',
@@ -219,8 +224,12 @@ SettingsListener.observe('app.reportCras
     Services.prefs.setBoolPref('app.reportCrashes', true);
   } else if (value == 'never') {
     Services.prefs.setBoolPref('app.reportCrashes', false);
   } else {
     Services.prefs.clearUserPref('app.reportCrashes');
   }
 });
 
+// ================ Updates ================
+SettingsListener.observe('app.update.interval', 86400, function(value) {
+  Services.prefs.setIntPref('app.update.interval', value);
+});
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -514,17 +514,17 @@ Services.obs.addObserver(function onWeba
 }, 'webapps-registry-start', false);
 
 Services.obs.addObserver(function onWebappsReady(subject, topic, data) {
   shell.sendChromeEvent({ type: 'webapps-registry-ready' });
 }, 'webapps-registry-ready', false);
 
 Services.obs.addObserver(function onBluetoothVolumeChange(subject, topic, data) {
   shell.sendChromeEvent({
-    type: "volumeset",
+    type: "bluetooth-volumeset",
     value: data
   });
 }, 'bluetooth-volume-change', false);
 
 (function Repl() {
   if (!Services.prefs.getBoolPref('b2g.remote-js.enabled')) {
     return;
   }
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -41,8 +41,9 @@ fi
 MOZ_APP_ID={3c2e2abc-06d4-11e1-ac3b-374f68613e61}
 MOZ_EXTENSION_MANAGER=1
 
 MOZ_SYS_MSG=1
 MOZ_TIME_MANAGER=1
 
 MOZ_PAY=1
 MOZ_TOOLKIT_SEARCH=
+MOZ_B2G=1
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1047,17 +1047,18 @@ pref("devtools.debugger.remote-timeout",
 
 // The default Debugger UI settings
 pref("devtools.debugger.ui.height", 250);
 pref("devtools.debugger.ui.remote-win.width", 900);
 pref("devtools.debugger.ui.remote-win.height", 400);
 pref("devtools.debugger.ui.stackframes-width", 200);
 pref("devtools.debugger.ui.variables-width", 300);
 pref("devtools.debugger.ui.panes-visible-on-startup", false);
-pref("devtools.debugger.ui.non-enum-visible", true);
+pref("devtools.debugger.ui.variables-non-enum-visible", true);
+pref("devtools.debugger.ui.variables-searchbox-visible", false);
 
 // Enable the style inspector
 pref("devtools.styleinspector.enabled", true);
 
 // Enable the Tilt inspector
 pref("devtools.tilt.enabled", true);
 pref("devtools.tilt.intro_transition", true);
 pref("devtools.tilt.outro_transition", true);
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1466,17 +1466,18 @@ var gBrowserInit = {
                   gPrefService.getBoolPref("devtools.debugger.remote-enabled");
     if (enabled) {
       let cmd = document.getElementById("Tools:ChromeDebugger");
       cmd.removeAttribute("disabled");
       cmd.removeAttribute("hidden");
     }
 
     // Enable Error Console?
-    let consoleEnabled = gPrefService.getBoolPref("devtools.errorconsole.enabled");
+    let consoleEnabled = gPrefService.getBoolPref("devtools.errorconsole.enabled") ||
+                         gPrefService.getBoolPref("devtools.chrome.enabled");
     if (consoleEnabled) {
       let cmd = document.getElementById("Tools:ErrorConsole");
       cmd.removeAttribute("hidden");
     }
 
     // Enable Scratchpad in the UI, if the preference allows this.
     let scratchpadEnabled = gPrefService.getBoolPref(Scratchpad.prefEnabledName);
     if (scratchpadEnabled) {
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -192,17 +192,16 @@ endif
                  browser_clearplugindata.html \
                  browser_clearplugindata_noage.html \
                  browser_popupUI.js \
                  browser_sanitizeDialog.js \
                  browser_save_video.js \
                  bug564387.html \
                  bug564387_video1.ogv \
                  bug564387_video1.ogv^headers^ \
-                 browser_save_link.js \
                  browser_save_private_link.js \
                  bug792517.html \
                  bug792517-2.html \
                  bug792517.sjs \
                  browser_scope.js \
                  browser_selectTabAtIndex.js \
                  browser_tab_dragdrop.js \
                  browser_tab_dragdrop2.js \
@@ -299,16 +298,21 @@ else
 
 # TODO: Activate after carbon test plugin lands, bug 628651
 # 		browser_maconly_carbon_mismatch_plugin.js \
 
 endif
 
 ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
 _BROWSER_FILES += \
-		browser_private_browsing_window.js \
-		$(NULL)
+                browser_private_browsing_window.js \
+                $(warning browser_save_link-perwindowpb.js disabled until bug 722850) \
+                $(NULL)
+else
+_BROWSER_FILES += \
+                browser_save_link.js \
+                $(NULL)
 endif
 
 include $(topsrcdir)/config/rules.mk
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
copy from browser/base/content/test/browser_save_link.js
copy to browser/base/content/test/browser_save_link-perwindowpb.js
--- a/browser/base/content/test/browser_save_link.js
+++ b/browser/base/content/test/browser_save_link-perwindowpb.js
@@ -7,63 +7,62 @@ MockFilePicker.init();
 let tempScope = {};
 Cu.import("resource://gre/modules/NetUtil.jsm", tempScope);
 let NetUtil = tempScope.NetUtil;
 
 // Trigger a save of a link in public mode, then trigger an identical save
 // in private mode and ensure that the second request is differentiated from
 // the first by checking the cookies that are sent.
 
-function triggerSave(aCallback) {
+function triggerSave(aWindow, aCallback) {
   var fileName;
-  gBrowser.selectedTab = gBrowser.addTab();
-  let testBrowser = gBrowser.selectedBrowser;
+  let testBrowser = aWindow.gBrowser.selectedBrowser;
   testBrowser.loadURI("http://mochi.test:8888/browser/browser/base/content/test/bug792517-2.html");
   testBrowser.addEventListener("pageshow", function pageShown(event) {
     if (event.target.location == "about:blank")
       return;
     testBrowser.removeEventListener("pageshow", pageShown, false);
 
     executeSoon(function () {
-      document.addEventListener("popupshown", contextMenuOpened, false);
+      aWindow.document.addEventListener("popupshown", function(e) contextMenuOpened(aWindow, e), false);
 
       var link = testBrowser.contentDocument.getElementById("fff");
       EventUtils.synthesizeMouseAtCenter(link,
                                          { type: "contextmenu", button: 2 },
                                          testBrowser.contentWindow);
     });
   }, false);
 
-  function contextMenuOpened(event) {
+  function contextMenuOpened(aWindow, event) {
     event.currentTarget.removeEventListener("popupshown", contextMenuOpened, false);
 
     // Create the folder the link will be saved into.
     var destDir = createTemporarySaveDirectory();
     var destFile = destDir.clone();
 
     MockFilePicker.displayDirectory = destDir;
     MockFilePicker.showCallback = function(fp) {
       fileName = fp.defaultString;
       destFile.append (fileName);
       MockFilePicker.returnFiles = [destFile];
       MockFilePicker.filterIndex = 1; // kSaveAsType_URL
     };
 
-    mockTransferCallback = function(a) onTransferComplete(a, destFile, destDir);
+    mockTransferCallback = function(a) onTransferComplete(aWindow, a, destFile, destDir);
 
     // Select "Save Link As" option from context menu
-    var saveLinkCommand = document.getElementById("context-savelink");
+    var saveLinkCommand = aWindow.document.getElementById("context-savelink");
     saveLinkCommand.doCommand();
 
     event.target.hidePopup();
   }
 
-  function onTransferComplete(downloadSuccess, destFile, destDir) {
+  function onTransferComplete(aWindow, downloadSuccess, destFile, destDir) {
     ok(downloadSuccess, "Link should have been downloaded successfully");
-    gBrowser.removeCurrentTab();
+    aWindow.gBrowser.removeCurrentTab();
 
     // Give the request a chance to finish
     executeSoon(function() aCallback(destFile, destDir));
   }
 }
 
 function readFile(file, callback) {
   let channel = NetUtil.newChannel(file);
@@ -77,44 +76,54 @@ function readFile(file, callback) {
                                                   inputStream.available());
     executeSoon(function() callback(content));
   });
 }
 
 function test() {
   waitForExplicitFinish();
 
-  let pb = Cc["@mozilla.org/privatebrowsing;1"]
-             .getService(Ci.nsIPrivateBrowsingService);
+  var windowsToClose = [];
+  function testOnWindow(options, callback) {
+    var win = OpenBrowserWindow(options);
+    win.addEventListener("load", function onLoad() {
+      win.removeEventListener("load", onLoad, false);
+      windowsToClose.push(win);
+      executeSoon(function() callback(win));
+    }, false);
+  }
 
   mockTransferRegisterer.register();
 
   registerCleanupFunction(function () {
     mockTransferRegisterer.unregister();
     MockFilePicker.cleanup();
-    pb.privateBrowsingEnabled = false;
-    Services.prefs.clearUserPref("browser.privatebrowsing.keep_current_session");
+    windowsToClose.forEach(function(win) {
+      win.close();
+    });
   });
 
-  triggerSave(function(destFile, destDir) {
-    readFile(destFile, function(content) {
-      is(content, "cookie-not-present", "no cookie should be sent");
-      destDir.remove(true);
+  testOnWindow(undefined, function(win) {
+    triggerSave(win, function(destFile, destDir) {
+      readFile(destFile, function(content) {
+        is(content, "cookie-not-present", "no cookie should be sent");
+        destDir.remove(true);
 
-      Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session", true);
-      pb.privateBrowsingEnabled = true;
-      triggerSave(function(destFile, destDir) {
-        readFile(destFile, function(content) {
-          is(content, "cookie-not-present", "no cookie should be sent");
-          destDir.remove(true);
-          finish();
+        testOnWindow({private: true}, function(win) {
+          triggerSave(win, function(destFile, destDir) {
+            readFile(destFile, function(content) {
+              is(content, "cookie-not-present", "no cookie should be sent");
+              destDir.remove(true);
+              finish();
+            });
+          });
         });
       });
     });
-  });  
+  });
 }
 
 Cc["@mozilla.org/moz/jssubscript-loader;1"]
   .getService(Ci.mozIJSSubScriptLoader)
   .loadSubScript("chrome://mochitests/content/browser/toolkit/content/tests/browser/common/mockTransfer.js",
                  this);
 
 function createTemporarySaveDirectory() {
--- a/browser/branding/aurora/content/aboutDialog.css
+++ b/browser/branding/aurora/content/aboutDialog.css
@@ -8,16 +8,20 @@
   background-color: #000;
   color: #fff;
 }
 
 .text-link {
   color: #fff !important;
 }
 
+.text-link:-moz-focusring {
+  border-color: #fff;
+}
+
 #rightBox {
   /* this margin prevents text from overlapping the planet image */
   margin-left: 280px;
   margin-right: 20px;
 }
 
 #bottomBox {
   background-color: rgba(0,0,0,.7);
--- a/browser/branding/nightly/content/aboutDialog.css
+++ b/browser/branding/nightly/content/aboutDialog.css
@@ -8,16 +8,20 @@
   background-color: #000;
   color: #fff;
 }
 
 .text-link {
   color: #fff !important;
 }
 
+.text-link:-moz-focusring {
+  border-color: #fff;
+}
+
 #rightBox {
   /* this margin prevents text from overlapping the planet image */
   margin-left: 280px;
   margin-right: 20px;
 }
 
 #bottomBox {
   background-color: rgba(0,0,0,.7);
--- a/browser/components/privatebrowsing/test/browser/perwindow/Makefile.in
+++ b/browser/components/privatebrowsing/test/browser/perwindow/Makefile.in
@@ -11,12 +11,14 @@ relativesrcdir  = @relativesrcdir@
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_BROWSER_FILES =  \
 		head.js \
 		browser_privatebrowsing_certexceptionsui.js \
 		browser_privatebrowsing_concurrent.js \
 		browser_privatebrowsing_concurrent_page.html \
 		browser_privatebrowsing_cookieacceptdialog.js \
+		browser_privatebrowsing_crh.js \
 		browser_privatebrowsing_lastpbcontextexited.js \
+		browser_privatebrowsing_opendir.js \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
copy from browser/components/privatebrowsing/test/browser/global/browser_privatebrowsing_crh.js
copy to browser/components/privatebrowsing/test/browser/perwindow/browser_privatebrowsing_crh.js
--- a/browser/components/privatebrowsing/test/browser/global/browser_privatebrowsing_crh.js
+++ b/browser/components/privatebrowsing/test/browser/perwindow/browser_privatebrowsing_crh.js
@@ -1,30 +1,48 @@
 /* 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/. */
 
 // This test makes sure that the Clear Recent History menu item and command 
 // is disabled inside the private browsing mode.
 
 function test() {
-  // initialization
-  let pb = Cc["@mozilla.org/privatebrowsing;1"].
-           getService(Ci.nsIPrivateBrowsingService);
+  waitForExplicitFinish();
+
+  function checkDisableOption(aPrivateMode, aWindow, aCallback) {
+    executeSoon(function() {
+      let crhCommand = aWindow.document.getElementById("Tools:Sanitize");
+      ok(crhCommand, "The clear recent history command should exist");
 
-  let crhCommand = document.getElementById("Tools:Sanitize");
+      is(PrivateBrowsingUtils.isWindowPrivate(aWindow), aPrivateMode,
+        "PrivateBrowsingUtils should report the correct per-window private browsing status");
+      is(crhCommand.hasAttribute("disabled"), aPrivateMode,
+        "Clear Recent History command should be disabled according to the private browsing mode");
 
-  // make sure the command is not disabled to begin with
-  ok(!crhCommand.hasAttribute("disabled"),
-    "Clear Recent History command should not be disabled outside of the private browsing mode");
+      aCallback();
+    });
+  };
 
-  // enter private browsing mode
-  pb.privateBrowsingEnabled = true;
-
-  ok(crhCommand.hasAttribute("disabled"),
-    "Clear Recent History command should be disabled inside of the private browsing mode");
+  let windowsToClose = [];
+  function testOnWindow(options, callback) {
+    let win = OpenBrowserWindow(options);
+    win.addEventListener("load", function onLoad() {
+      win.removeEventListener("load", onLoad, false);
+      windowsToClose.push(win);
+      callback(win);
+    }, false);
+  };
 
-  // leave private browsing mode
-  pb.privateBrowsingEnabled = false;
+  registerCleanupFunction(function() {
+    windowsToClose.forEach(function(win) {
+      win.close();
+    });
+  });
 
-  ok(!crhCommand.hasAttribute("disabled"),
-    "Clear Recent History command should not be disabled after leaving the private browsing mode");
+  testOnWindow({private: true}, function(win) {
+    checkDisableOption(true, win, function() {
+      testOnWindow({}, function(win) {
+        checkDisableOption(false, win, finish);
+      });
+    });
+  });
 }
copy from browser/components/privatebrowsing/test/browser/global/browser_privatebrowsing_opendir.js
copy to browser/components/privatebrowsing/test/browser/perwindow/browser_privatebrowsing_opendir.js
--- a/browser/components/privatebrowsing/test/browser/global/browser_privatebrowsing_opendir.js
+++ b/browser/components/privatebrowsing/test/browser/perwindow/browser_privatebrowsing_opendir.js
@@ -1,109 +1,133 @@
 /* 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/. */
 
 // This test makes sure that the last open directory used inside the private
 // browsing mode is not remembered after leaving that mode.
 
+var windowsToClose = [];
+function testOnWindow(options, callback) {
+  var win = OpenBrowserWindow(options);
+  win.addEventListener("load", function onLoad() {
+    win.removeEventListener("load", onLoad, false);
+    windowsToClose.push(win);
+    callback(win);
+  }, false);
+}
+
+registerCleanupFunction(function() {
+  windowsToClose.forEach(function(win) {
+    win.close();
+  });
+});
+
 function test() {
   // initialization
-  let pb = Cc["@mozilla.org/privatebrowsing;1"].
-           getService(Ci.nsIPrivateBrowsingService);
+  waitForExplicitFinish();
   let ds = Cc["@mozilla.org/file/directory_service;1"].
            getService(Ci.nsIProperties);
   let dir1 = ds.get("ProfD", Ci.nsIFile);
   let dir2 = ds.get("TmpD", Ci.nsIFile);
   let file = dir2.clone();
   file.append("pbtest.file");
   file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
 
   const kPrefName = "browser.open.lastDir";
 
-  function setupCleanSlate() {
-    gLastOpenDirectory.reset();
+  function setupCleanSlate(win) {
+    win.gLastOpenDirectory.reset();
     gPrefService.clearUserPref(kPrefName);
   }
 
-  setupCleanSlate();
-
-  // Test 1: general workflow test
+  setupCleanSlate(window);
 
-  // initial checks
-  ok(!gLastOpenDirectory.path,
-     "Last open directory path should be initially empty");
-  gLastOpenDirectory.path = dir2;
-  is(gLastOpenDirectory.path.path, dir2.path,
-     "The path should be successfully set");
-  gLastOpenDirectory.path = null;
-  is(gLastOpenDirectory.path.path, dir2.path,
-     "The path should be not change when assigning it to null");
-  gLastOpenDirectory.path = dir1;
-  is(gLastOpenDirectory.path.path, dir1.path,
-     "The path should be successfully outside of the private browsing mode");
+  // open one regular and one private window
+  testOnWindow(undefined, function(nonPrivateWindow) {
+    setupCleanSlate(nonPrivateWindow);
+    testOnWindow({private: true}, function(privateWindow) {
+      setupCleanSlate(privateWindow);
+
+      // Test 1: general workflow test
 
-  // enter private browsing mode
-  pb.privateBrowsingEnabled = true;
-
-  is(gLastOpenDirectory.path.path, dir1.path,
-     "The path should not change when entering the private browsing mode");
-  gLastOpenDirectory.path = dir2;
-  is(gLastOpenDirectory.path.path, dir2.path,
-     "The path should successfully change inside the private browsing mode");
+      // initial checks
+      ok(!nonPrivateWindow.gLastOpenDirectory.path,
+         "Last open directory path should be initially empty");
+      nonPrivateWindow.gLastOpenDirectory.path = dir2;
+      is(nonPrivateWindow.gLastOpenDirectory.path.path, dir2.path,
+         "The path should be successfully set");
+      nonPrivateWindow.gLastOpenDirectory.path = null;
+      is(nonPrivateWindow.gLastOpenDirectory.path.path, dir2.path,
+         "The path should be not change when assigning it to null");
+      nonPrivateWindow.gLastOpenDirectory.path = dir1;
+      is(nonPrivateWindow.gLastOpenDirectory.path.path, dir1.path,
+         "The path should be successfully outside of the private browsing mode");
 
-  // leave private browsing mode
-  pb.privateBrowsingEnabled = false;
+      // test the private window
+      is(privateWindow.gLastOpenDirectory.path.path, dir1.path,
+         "The path should not change when entering the private browsing mode");
+      privateWindow.gLastOpenDirectory.path = dir2;
+      is(privateWindow.gLastOpenDirectory.path.path, dir2.path,
+         "The path should successfully change inside the private browsing mode");
 
-  is(gLastOpenDirectory.path.path, dir1.path,
-     "The path should be reset to the same path as before entering the private browsing mode");
+      // test the non-private window
+      is(nonPrivateWindow.gLastOpenDirectory.path.path, dir1.path,
+         "The path should be reset to the same path as before entering the private browsing mode");
 
-  setupCleanSlate();
+      setupCleanSlate(nonPrivateWindow);
+      setupCleanSlate(privateWindow);
 
-  // Test 2: the user first tries to open a file inside the private browsing mode
+      // Test 2: the user first tries to open a file inside the private browsing mode
 
-  pb.privateBrowsingEnabled = true;
-  ok(!gLastOpenDirectory.path,
-     "No original path should exist inside the private browsing mode");
-  gLastOpenDirectory.path = dir1;
-  is(gLastOpenDirectory.path.path, dir1.path, 
-     "The path should be successfully set inside the private browsing mode");
-  pb.privateBrowsingEnabled = false;
-  ok(!gLastOpenDirectory.path,
-     "The path set inside the private browsing mode should not leak when leaving that mode");
+      // test the private window
+      ok(!privateWindow.gLastOpenDirectory.path,
+         "No original path should exist inside the private browsing mode");
+      privateWindow.gLastOpenDirectory.path = dir1;
+      is(privateWindow.gLastOpenDirectory.path.path, dir1.path, 
+         "The path should be successfully set inside the private browsing mode");
+      // test the non-private window
+      ok(!nonPrivateWindow.gLastOpenDirectory.path,
+         "The path set inside the private browsing mode should not leak when leaving that mode");
 
-  setupCleanSlate();
+      setupCleanSlate(nonPrivateWindow);
+      setupCleanSlate(privateWindow);
 
-  // Test 3: the last open directory is set from a previous session, it should be used
-  // in normal mode
+      // Test 3: the last open directory is set from a previous session, it should be used
+      // in normal mode
 
-  gPrefService.setComplexValue(kPrefName, Ci.nsILocalFile, dir1);
-  is(gLastOpenDirectory.path.path, dir1.path,
-     "The pref set from last session should take effect outside the private browsing mode");
+      gPrefService.setComplexValue(kPrefName, Ci.nsILocalFile, dir1);
+      is(nonPrivateWindow.gLastOpenDirectory.path.path, dir1.path,
+         "The pref set from last session should take effect outside the private browsing mode");
 
-  setupCleanSlate();
+      setupCleanSlate(nonPrivateWindow);
+      setupCleanSlate(privateWindow);
 
-  // Test 4: the last open directory is set from a previous session, it should be used
-  // in private browsing mode mode
+      // Test 4: the last open directory is set from a previous session, it should be used
+      // in private browsing mode mode
 
-  gPrefService.setComplexValue(kPrefName, Ci.nsILocalFile, dir1);
-  pb.privateBrowsingEnabled = true;
-  is(gLastOpenDirectory.path.path, dir1.path,
-     "The pref set from last session should take effect inside the private browsing mode");
-  pb.privateBrowsingEnabled = false;
-  is(gLastOpenDirectory.path.path, dir1.path,
-     "The pref set from last session should remain in effect after leaving the private browsing mode");
+      gPrefService.setComplexValue(kPrefName, Ci.nsILocalFile, dir1);
+      // test the private window
+      is(privateWindow.gLastOpenDirectory.path.path, dir1.path,
+         "The pref set from last session should take effect inside the private browsing mode");
+      // test the non-private window
+      is(nonPrivateWindow.gLastOpenDirectory.path.path, dir1.path,
+         "The pref set from last session should remain in effect after leaving the private browsing mode");
 
-  setupCleanSlate();
+      setupCleanSlate(nonPrivateWindow);
+      setupCleanSlate(privateWindow);
 
-  // Test 5: setting the path to a file shouldn't work
+      // Test 5: setting the path to a file shouldn't work
 
-  gLastOpenDirectory.path = file;
-  ok(!gLastOpenDirectory.path,
-     "Setting the path to a file shouldn't work when it's originally null");
-  gLastOpenDirectory.path = dir1;
-  gLastOpenDirectory.path = file;
-  is(gLastOpenDirectory.path.path, dir1.path,
-     "Setting the path to a file shouldn't work when it's not originally null");
+      nonPrivateWindow.gLastOpenDirectory.path = file;
+      ok(!nonPrivateWindow.gLastOpenDirectory.path,
+         "Setting the path to a file shouldn't work when it's originally null");
+      nonPrivateWindow.gLastOpenDirectory.path = dir1;
+      nonPrivateWindow.gLastOpenDirectory.path = file;
+      is(nonPrivateWindow.gLastOpenDirectory.path.path, dir1.path,
+         "Setting the path to a file shouldn't work when it's not originally null");
 
-  // cleanup
-  file.remove(false);
+      // cleanup
+      file.remove(false);
+      finish();
+    });
+  });
 }
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -2992,17 +2992,19 @@ let SessionStoreInternal = {
 
       // Make sure that set/getTabValue will set/read the correct data by
       // wiping out any current value in tab.__SS_extdata.
       delete tab.__SS_extdata;
 
       if (!tabData.entries || tabData.entries.length == 0) {
         // make sure to blank out this tab's content
         // (just purging the tab's history won't be enough)
-        browser.contentDocument.location = "about:blank";
+        browser.loadURIWithFlags("about:blank",
+                                 Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY,
+                                 null, null, null);
         continue;
       }
 
       browser.stop(); // in case about:blank isn't done yet
 
       // wall-paper fix for bug 439675: make sure that the URL to be loaded
       // is always visible in the address bar
       let activeIndex = (tabData.index || tabData.entries.length) - 1;
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -655,19 +655,19 @@ StackFrames.prototype = {
         // Expansion handlers must be set after the properties are added.
         for (let name in ownProperties) {
           this._addExpander(aVar.get(name), ownProperties[name].value);
         }
       }
 
       // Add the variable's __proto__.
       if (prototype.type != "null") {
-        aVar.addProperties({ "__proto__ ": { value: prototype } });
+        aVar.addProperty("__proto__", { value: prototype });
         // Expansion handlers must be set after the properties are added.
-        this._addExpander(aVar.get("__proto__ "), prototype);
+        this._addExpander(aVar.get("__proto__"), prototype);
       }
 
       aVar.fetched = true;
 
       // Signal that properties have been fetched.
       window.dispatchEvent("Debugger:FetchedProperties");
       DebuggerView.Variables.commitHierarchy();
     }.bind(this));
@@ -729,28 +729,30 @@ function SourceScripts() {
 SourceScripts.prototype = {
   get activeThread() DebuggerController.activeThread,
   get debuggerClient() DebuggerController.client,
 
   /**
    * Connect to the current thread client.
    */
   connect: function SS_connect() {
+    dumpn("SourceScripts is connecting...");
     this.debuggerClient.addListener("newScript", this._onNewScript);
     this.debuggerClient.addListener("newGlobal", this._onNewGlobal);
     this._handleTabNavigation();
   },
 
   /**
    * Disconnect from the client.
    */
   disconnect: function SS_disconnect() {
     if (!this.activeThread) {
       return;
     }
+    dumpn("SourceScripts is disconnecting...");
     this.debuggerClient.removeListener("newScript", this._onNewScript);
     this.debuggerClient.removeListener("newGlobal", this._onNewGlobal);
   },
 
   /**
    * Handles any initialization on a tab navigation event issued by the client.
    */
   _handleTabNavigation: function SS__handleTabNavigation() {
@@ -1243,17 +1245,18 @@ XPCOMUtils.defineLazyGetter(L10N, "strin
 
 XPCOMUtils.defineLazyGetter(L10N, "ellipsis", function() {
   return Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
 });
 
 const STACKFRAMES_WIDTH = "devtools.debugger.ui.stackframes-width";
 const VARIABLES_WIDTH = "devtools.debugger.ui.variables-width";
 const PANES_VISIBLE_ON_STARTUP = "devtools.debugger.ui.panes-visible-on-startup";
-const NON_ENUM_VISIBLE = "devtools.debugger.ui.non-enum-visible";
+const VARIABLES_NON_ENUM_VISIBLE = "devtools.debugger.ui.variables-non-enum-visible";
+const VARIABLES_SEARCHBOX_VISIBLE = "devtools.debugger.ui.variables-searchbox-visible";
 const REMOTE_HOST = "devtools.debugger.remote-host";
 const REMOTE_PORT = "devtools.debugger.remote-port";
 const REMOTE_AUTO_CONNECT = "devtools.debugger.remote-autoconnect";
 const REMOTE_CONNECTION_RETRIES = "devtools.debugger.remote-connection-retries";
 const REMOTE_TIMEOUT = "devtools.debugger.remote-timeout";
 
 /**
  * Shortcuts for accessing various debugger preferences.
@@ -1319,31 +1322,51 @@ let Prefs = {
     this._panesVisible = value;
   },
 
   /**
    * Gets a flag specifying if the debugger should show non-enumerable
    * properties and variables in the scope view.
    * @return boolean
    */
-  get nonEnumVisible() {
-    if (this._nonEnumVisible === undefined) {
-      this._nonEnumVisible = Services.prefs.getBoolPref(NON_ENUM_VISIBLE);
+  get variablesNonEnumVisible() {
+    if (this._varNonEnum === undefined) {
+      this._varNonEnum = Services.prefs.getBoolPref(VARIABLES_NON_ENUM_VISIBLE);
     }
-    return this._nonEnumVisible;
+    return this._varNonEnum;
   },
 
   /**
    * Sets a flag specifying if the debugger should show non-enumerable
    * properties and variables in the scope view.
    * @param boolean value
    */
-  set nonEnumVisible(value) {
-    Services.prefs.setBoolPref(NON_ENUM_VISIBLE, value);
-    this._nonEnumVisible = value;
+  set variablesNonEnumVisible(value) {
+    Services.prefs.setBoolPref(VARIABLES_NON_ENUM_VISIBLE, value);
+    this._varNonEnum = value;
+  },
+
+  /**
+   * Gets a flag specifying if the a variables searchbox should be shown.
+   * @return boolean
+   */
+  get variablesSearchboxVisible() {
+    if (this._varSearchbox === undefined) {
+      this._varSearchbox = Services.prefs.getBoolPref(VARIABLES_SEARCHBOX_VISIBLE);
+    }
+    return this._varSearchbox;
+  },
+
+  /**
+   * Sets a flag specifying if the a variables searchbox should be shown.
+   * @param boolean value
+   */
+  set variablesSearchboxVisible(value) {
+    Services.prefs.setBoolPref(VARIABLES_SEARCHBOX_VISIBLE, value);
+    this._varSearchbox = value;
   },
 
   /**
    * Gets the preferred default remote debugging host.
    * @return string
    */
   get remoteHost() {
     if (this._remoteHost === undefined) {
--- a/browser/devtools/debugger/debugger-panes.js
+++ b/browser/devtools/debugger/debugger-panes.js
@@ -1207,17 +1207,17 @@ SourceResults.prototype = {
     this._target.arrow.removeAttribute("open");
   },
 
   /**
    * Toggles between the element collapse/expand state.
    */
   toggle: function SR_toggle(e) {
     if (e instanceof Event) {
-      this._toggled = true;
+      this._userToggled = true;
     }
     this.expanded ^= 1;
   },
 
   /**
    * Gets this element's expanded state.
    * @return boolean
    */
@@ -1225,19 +1225,20 @@ SourceResults.prototype = {
 
   /**
    * Sets this element's expanded state.
    * @param boolean aFlag
    */
   set expanded(aFlag) this[aFlag ? "expand" : "collapse"](),
 
   /**
-   * Returns true if this element was toggled via user interaction.
+   * Returns if this element was ever toggled via user interaction.
+   * @return boolean
    */
-  get toggled() this._toggled,
+  get toggled() this._userToggled,
 
   /**
    * Gets the element associated with this item.
    * @return nsIDOMNode
    */
   get target() this._target,
 
   /**
@@ -1308,17 +1309,17 @@ SourceResults.prototype = {
       matchCount: aMatchCount,
       autoExpand: aExpandFlag,
       instance: this
     });
   },
 
   _store: null,
   _target: null,
-  _toggled: false
+  _userToggled: false
 };
 
 /**
  * An object containing all the matches for a specific line.
  * Iterable via "for (let chunk in lineResults) { }".
  */
 function LineResults() {
   this._store = [];
--- a/browser/devtools/debugger/debugger-toolbar.js
+++ b/browser/devtools/debugger/debugger-toolbar.js
@@ -194,33 +194,36 @@ ToolbarView.prototype = {
 
 /**
  * Functions handling the options UI.
  */
 function OptionsView() {
   dumpn("OptionsView was instantiated");
   this._togglePauseOnExceptions = this._togglePauseOnExceptions.bind(this);
   this._toggleShowPanesOnStartup = this._toggleShowPanesOnStartup.bind(this);
-  this._toggleShowNonEnum = this._toggleShowNonEnum.bind(this);
+  this._toggleShowVariablesNonEnum = this._toggleShowVariablesNonEnum.bind(this);
+  this._toggleShowVariablesSearchbox = this._toggleShowVariablesSearchbox.bind(this);
 }
 
 OptionsView.prototype = {
   /**
    * Initialization function, called when the debugger is started.
    */
   initialize: function DVO_initialize() {
     dumpn("Initializing the OptionsView");
     this._button = document.getElementById("debugger-options");
     this._pauseOnExceptionsItem = document.getElementById("pause-on-exceptions");
     this._showPanesOnStartupItem = document.getElementById("show-panes-on-startup");
-    this._showNonEnumItem = document.getElementById("show-nonenum");
+    this._showVariablesNonEnumItem = document.getElementById("show-vars-nonenum");
+    this._showVariablesSearchboxItem = document.getElementById("show-vars-searchbox");
 
     this._pauseOnExceptionsItem.setAttribute("checked", "false");
     this._showPanesOnStartupItem.setAttribute("checked", Prefs.panesVisibleOnStartup);
-    this._showNonEnumItem.setAttribute("checked", Prefs.nonEnumVisible);
+    this._showVariablesNonEnumItem.setAttribute("checked", Prefs.variablesNonEnumVisible);
+    this._showVariablesSearchboxItem.setAttribute("checked", Prefs.variablesSearchboxVisible);
   },
 
   /**
    * Destruction function, called when the debugger is closed.
    */
   destroy: function DVO_destroy() {
     dumpn("Destroying the OptionsView");
     // Nothing to do here yet.
@@ -254,25 +257,34 @@ OptionsView.prototype = {
   _toggleShowPanesOnStartup: function DVO__toggleShowPanesOnStartup() {
     Prefs.panesVisibleOnStartup =
       this._showPanesOnStartupItem.getAttribute("checked") == "true";
   },
 
   /**
    * Listener handling the 'show non-enumerables' menuitem command.
    */
-  _toggleShowNonEnum: function DVO__toggleShowNonEnum() {
-    DebuggerView.Variables.nonEnumVisible = Prefs.nonEnumVisible =
-      this._showNonEnumItem.getAttribute("checked") == "true";
+  _toggleShowVariablesNonEnum: function DVO__toggleShowVariablesNonEnum() {
+    DebuggerView.Variables.nonEnumVisible = Prefs.variablesNonEnumVisible =
+      this._showVariablesNonEnumItem.getAttribute("checked") == "true";
+  },
+
+  /**
+   * Listener handling the 'show variables searchbox' menuitem command.
+   */
+  _toggleShowVariablesSearchbox: function DVO__toggleShowVariablesSearchbox() {
+    DebuggerView.Variables.searchEnabled = Prefs.variablesSearchboxVisible =
+      this._showVariablesSearchboxItem.getAttribute("checked") == "true";
   },
 
   _button: null,
   _pauseOnExceptionsItem: null,
   _showPanesOnStartupItem: null,
-  _showNonEnumItem: null
+  _showVariablesNonEnumItem: null,
+  _showVariablesSearchboxItem: null
 };
 
 /**
  * Functions handling the chrome globals UI.
  */
 function ChromeGlobalsView() {
   dumpn("ChromeGlobalsView was instantiated");
   MenuContainer.call(this);
@@ -557,38 +569,44 @@ FilterView.prototype = {
     this._searchbox = document.getElementById("searchbox");
     this._searchboxPanel = document.getElementById("searchbox-panel");
     this._globalOperatorButton = document.getElementById("global-operator-button");
     this._globalOperatorLabel = document.getElementById("global-operator-label");
     this._tokenOperatorButton = document.getElementById("token-operator-button");
     this._tokenOperatorLabel = document.getElementById("token-operator-label");
     this._lineOperatorButton = document.getElementById("line-operator-button");
     this._lineOperatorLabel = document.getElementById("line-operator-label");
+    this._variableOperatorButton = document.getElementById("variable-operator-button");
+    this._variableOperatorLabel = document.getElementById("variable-operator-label");
 
     this._globalSearchKey = LayoutHelpers.prettyKey(document.getElementById("globalSearchKey"));
     this._fileSearchKey = LayoutHelpers.prettyKey(document.getElementById("fileSearchKey"));
     this._lineSearchKey = LayoutHelpers.prettyKey(document.getElementById("lineSearchKey"));
     this._tokenSearchKey = LayoutHelpers.prettyKey(document.getElementById("tokenSearchKey"));
+    this._variableSearchKey = LayoutHelpers.prettyKey(document.getElementById("variableSearchKey"));
 
     this._searchbox.addEventListener("click", this._onClick, false);
     this._searchbox.addEventListener("select", this._onSearch, false);
     this._searchbox.addEventListener("input", this._onSearch, false);
     this._searchbox.addEventListener("keypress", this._onKeyPress, false);
     this._searchbox.addEventListener("blur", this._onBlur, false);
 
     this._globalOperatorButton.setAttribute("label", SEARCH_GLOBAL_FLAG);
     this._tokenOperatorButton.setAttribute("label", SEARCH_TOKEN_FLAG);
     this._lineOperatorButton.setAttribute("label", SEARCH_LINE_FLAG);
+    this._variableOperatorButton.setAttribute("label", SEARCH_VARIABLE_FLAG);
 
     this._globalOperatorLabel.setAttribute("value",
       L10N.getFormatStr("searchPanelGlobal", [this._globalSearchKey]));
     this._tokenOperatorLabel.setAttribute("value",
       L10N.getFormatStr("searchPanelToken", [this._tokenSearchKey]));
     this._lineOperatorLabel.setAttribute("value",
       L10N.getFormatStr("searchPanelLine", [this._lineSearchKey]));
+    this._variableOperatorLabel.setAttribute("value",
+      L10N.getFormatStr("searchPanelVariable", [this._variableSearchKey]));
 
     // TODO: bug 806775
     // if (window._isChromeDebugger) {
     //   this.target = DebuggerView.ChromeGlobals;
     // } else {
     this.target = DebuggerView.Sources;
     // }
   },
@@ -623,48 +641,59 @@ FilterView.prototype = {
     this._target = aView;
   },
 
   /**
    * Gets the entered file, line and token entered in the searchbox.
    * @return array
    */
   get searchboxInfo() {
-    let file, line, token, global;
+    let file, line, token, isGlobal, isVariable;
 
     let rawValue = this._searchbox.value;
     let rawLength = rawValue.length;
     let globalFlagIndex = rawValue.indexOf(SEARCH_GLOBAL_FLAG);
+    let variableFlagIndex = rawValue.indexOf(SEARCH_VARIABLE_FLAG);
     let lineFlagIndex = rawValue.lastIndexOf(SEARCH_LINE_FLAG);
     let tokenFlagIndex = rawValue.lastIndexOf(SEARCH_TOKEN_FLAG);
 
-    // This is not a global search, allow file or line flags.
-    if (globalFlagIndex != 0) {
+    // This is not a global or variable search, allow file or line flags.
+    if (globalFlagIndex != 0 && variableFlagIndex != 0) {
       let fileEnd = lineFlagIndex != -1
         ? lineFlagIndex
         : tokenFlagIndex != -1 ? tokenFlagIndex : rawLength;
 
       let lineEnd = tokenFlagIndex != -1
         ? tokenFlagIndex
         : rawLength;
 
       file = rawValue.slice(0, fileEnd);
       line = ~~(rawValue.slice(fileEnd + 1, lineEnd)) || -1;
       token = rawValue.slice(lineEnd + 1);
-      global = false;
+      isGlobal = false;
+      isVariable = false;
     }
     // Global searches dissalow the use of file or line flags.
-    else {
+    else if (globalFlagIndex == 0) {
       file = "";
       line = -1;
       token = rawValue.slice(1);
-      global = true;
+      isGlobal = true;
+      isVariable = false;
+    }
+    // Variable searches dissalow the use of file or line flags.
+    else if (variableFlagIndex == 0) {
+      file = "";
+      line = -1;
+      token = rawValue.slice(1);
+      isGlobal = false;
+      isVariable = true;
     }
 
-    return [file, line, token, global];
+    return [file, line, token, isGlobal, isVariable];
   },
 
   /**
    * Returns the currently searched file.
    * @return string
    */
   get searchedFile() this.searchboxInfo[0],
 
@@ -782,35 +811,43 @@ FilterView.prototype = {
     this._searchboxPanel.openPopup(this._searchbox);
   },
 
   /**
    * The search listener for the search container.
    */
   _onSearch: function DVF__onScriptsSearch() {
     this._searchboxPanel.hidePopup();
-    let [file, line, token, global] = this.searchboxInfo;
+    let [file, line, token, isGlobal, isVariable] = this.searchboxInfo;
 
     // If this is a global search, schedule it for when the user stops typing,
     // or hide the corresponding pane otherwise.
-    if (global) {
+    if (isGlobal) {
       DebuggerView.GlobalSearch.scheduleSearch();
-    } else {
-      DebuggerView.GlobalSearch.clearView();
-      this._performFileSearch(file);
-      this._performLineSearch(line);
-      this._performTokenSearch(token);
+      return;
     }
+
+    // If this is a variable search, defer the action to the corresponding
+    // variables view instance.
+    if (isVariable) {
+      DebuggerView.Variables.performSearch(token);
+      return;
+    }
+
+    DebuggerView.GlobalSearch.clearView();
+    this._performFileSearch(file);
+    this._performLineSearch(line);
+    this._performTokenSearch(token);
   },
 
   /**
    * The key press listener for the search container.
    */
   _onKeyPress: function DVF__onScriptsKeyPress(e) {
-    let [file, line, token, global] = this.searchboxInfo;
+    let [file, line, token, isGlobal, isVariable] = this.searchboxInfo;
     let action;
 
     switch (e.keyCode) {
       case e.DOM_VK_DOWN:
       case e.DOM_VK_RETURN:
       case e.DOM_VK_ENTER:
         action = 0;
         break;
@@ -830,36 +867,45 @@ FilterView.prototype = {
     }
     if (action == -1 || !token) {
       return;
     }
 
     e.preventDefault();
     e.stopPropagation();
 
-    if (global) {
+    // Perform a global search based on the specified operator.
+    if (isGlobal) {
       if (DebuggerView.GlobalSearch.hidden) {
         DebuggerView.GlobalSearch.scheduleSearch();
       } else {
         DebuggerView.GlobalSearch[["focusNextMatch", "focusPrevMatch"][action]]();
       }
-    } else {
-      let editor = DebuggerView.editor;
-      let offset = editor[["findNext", "findPrevious"][action]](true);
-      if (offset > -1) {
-        editor.setSelection(offset, offset + token.length)
-      }
+      return;
+    }
+
+    // Perform a variable search based on the specified operator.
+    if (isVariable) {
+      DebuggerView.Variables.expandFirstSearchResults();
+      return;
+    }
+
+    let editor = DebuggerView.editor;
+    let offset = editor[["findNext", "findPrevious"][action]](true);
+    if (offset > -1) {
+      editor.setSelection(offset, offset + token.length)
     }
   },
 
   /**
    * The blur listener for the search container.
    */
   _onBlur: function DVF__onBlur() {
     DebuggerView.GlobalSearch.clearView();
+    DebuggerView.Variables.performSearch(null);
     this._searchboxPanel.hidePopup();
   },
 
   /**
    * Called when a filtering key sequence was pressed.
    *
    * @param string aOperator
    *        The operator to use for filtering.
@@ -897,16 +943,24 @@ FilterView.prototype = {
   /**
    * Called when the global search filter key sequence was pressed.
    */
   _doGlobalSearch: function DVF__doGlobalSearch() {
     this._doSearch(SEARCH_GLOBAL_FLAG);
     this._searchboxPanel.hidePopup();
   },
 
+  /**
+   * Called when the variable search filter key sequence was pressed.
+   */
+  _doVariableSearch: function DVF__doVariableSearch() {
+    this._doSearch(SEARCH_VARIABLE_FLAG);
+    this._searchboxPanel.hidePopup();
+  },
+
   _searchbox: null,
   _searchboxPanel: null,
   _globalOperatorButton: null,
   _globalOperatorLabel: null,
   _tokenOperatorButton: null,
   _tokenOperatorLabel: null,
   _lineOperatorButton: null,
   _lineOperatorLabel: null,
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -10,16 +10,17 @@ const SOURCE_SYNTAX_HIGHLIGHT_MAX_FILE_S
 const PANES_APPEARANCE_DELAY = 50; // ms
 const BREAKPOINT_LINE_TOOLTIP_MAX_LENGTH = 1000; // chars
 const GLOBAL_SEARCH_LINE_MAX_LENGTH = 300; // chars
 const GLOBAL_SEARCH_EXPAND_MAX_RESULTS = 50;
 const GLOBAL_SEARCH_ACTION_DELAY = 150; // ms
 const SEARCH_GLOBAL_FLAG = "!";
 const SEARCH_LINE_FLAG = ":";
 const SEARCH_TOKEN_FLAG = "#";
+const SEARCH_VARIABLE_FLAG = "*";
 
 /**
  * Object defining the debugger view components.
  */
 let DebuggerView = {
   /**
    * Initializes the debugger view.
    *
@@ -33,18 +34,20 @@ let DebuggerView = {
     this.ChromeGlobals.initialize();
     this.Sources.initialize();
     this.Filtering.initialize();
     this.StackFrames.initialize();
     this.Breakpoints.initialize();
     this.GlobalSearch.initialize();
 
     this.Variables = new VariablesView(document.getElementById("variables"));
+    this.Variables.searchPlaceholder = L10N.getStr("emptyVariablesFilterText");
     this.Variables.emptyText = L10N.getStr("emptyVariablesText");
-    this.Variables.nonEnumVisible = Prefs.nonEnumVisible;
+    this.Variables.nonEnumVisible = Prefs.variablesNonEnumVisible;
+    this.Variables.searchEnabled = Prefs.variablesSearchboxVisible;
     this.Variables.eval = DebuggerController.StackFrames.evaluate;
     this.Variables.lazyEmpty = true;
 
     this._initializePanes();
     this._initializeEditor(aCallback)
   },
 
   /**
--- a/browser/devtools/debugger/debugger.css
+++ b/browser/devtools/debugger/debugger.css
@@ -58,15 +58,30 @@
 #variables .details {
   display: none;
 }
 
 #variables .details[open] {
   display: -moz-box;
 }
 
+.scope[non-header] > .title,
+.variable[non-header] > .title,
+.property[non-header] > .title {
+  display: none;
+}
+
+/**
+ * Variables and properties searching
+ */
+
+.variable[non-match] > .title,
+.property[non-match] > .title {
+  display: none;
+}
+
 /**
  * Toolbar
  */
 
 .devtools-toolbarbutton:not([label]) > .toolbarbutton-text {
   display: none;
 }
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -36,22 +36,26 @@
     <command id="fileSearchCommand"
              oncommand="DebuggerView.Filtering._doFileSearch()"/>
     <command id="lineSearchCommand"
              oncommand="DebuggerView.Filtering._doLineSearch()"/>
     <command id="tokenSearchCommand"
              oncommand="DebuggerView.Filtering._doTokenSearch()"/>
     <command id="globalSearchCommand"
              oncommand="DebuggerView.Filtering._doGlobalSearch()"/>
+    <command id="variableSearchCommand"
+             oncommand="DebuggerView.Filtering._doVariableSearch()"/>
     <command id="togglePauseOnExceptions"
              oncommand="DebuggerView.Options._togglePauseOnExceptions()"/>
     <command id="toggleShowPanesOnStartup"
              oncommand="DebuggerView.Options._toggleShowPanesOnStartup()"/>
     <command id="toggleShowNonEnum"
-             oncommand="DebuggerView.Options._toggleShowNonEnum()"/>
+             oncommand="DebuggerView.Options._toggleShowVariablesNonEnum()"/>
+    <command id="toggleShowVariablesSearchbox"
+             oncommand="DebuggerView.Options._toggleShowVariablesSearchbox()"/>
   </commandset>
 
   <popupset id="debuggerPopupset">
     <menupopup id="sourceEditorContextMenu"
                onpopupshowing="goUpdateSourceEditorMenuItems()">
       <menuitem id="se-cMenu-copy"/>
       <menuseparator/>
       <menuitem id="se-cMenu-selectAll"/>
@@ -70,21 +74,26 @@
                 label="&debuggerUI.pauseExceptions;"
                 accesskey="&debuggerUI.pauseExceptions.key;"
                 command="togglePauseOnExceptions"/>
       <menuitem id="show-panes-on-startup"
                 type="checkbox"
                 label="&debuggerUI.showPanesOnInit;"
                 accesskey="&debuggerUI.showPanesOnInit.key;"
                 command="toggleShowPanesOnStartup"/>
-      <menuitem id="show-nonenum"
+      <menuitem id="show-vars-nonenum"
                 type="checkbox"
                 label="&debuggerUI.showNonEnums;"
                 accesskey="&debuggerUI.showNonEnums.key;"
                 command="toggleShowNonEnum"/>
+      <menuitem id="show-vars-searchbox"
+                type="checkbox"
+                label="&debuggerUI.showVarsSearch;"
+                accesskey="&debuggerUI.showVarsSearch.key;"
+                command="toggleShowVariablesSearchbox"/>
     </menupopup>
   </popupset>
 
   <keyset id="sourceEditorKeys"/>
 
   <keyset id="debuggerKeys">
     <key id="resumeKey"
          keycode="VK_F6"
@@ -110,16 +119,20 @@
     <key id="tokenSearchKey"
          key="T"
          modifiers="control shift"
          command="tokenSearchCommand"/>
     <key id="globalSearchKey"
          key="F"
          modifiers="control shift"
          command="globalSearchCommand"/>
+    <key id="variableSearchKey"
+         key="V"
+         modifiers="control shift"
+         command="variableSearchCommand"/>
   </keyset>
 
   <vbox id="body" flex="1">
     <toolbar id="dbg-toolbar" class="devtools-toolbar">
 #ifdef XP_MACOSX
       <toolbarbutton id="close"
                      class="devtools-closebutton"
                      tooltiptext="&debuggerUI.closeButton.tooltip;"/>
@@ -153,16 +166,17 @@
                      tooltiptext="&debuggerUI.optsButton.tooltip;"
                      popup="debuggerPrefsContextMenu"/>
 #ifndef XP_MACOSX
       <toolbarbutton id="close"
                      class="devtools-closebutton"
                      tooltiptext="&debuggerUI.closeButton.tooltip;"/>
 #endif
     </toolbar>
+
     <panel id="searchbox-panel"
            type="arrow"
            noautofocus="true"
            position="before_start">
       <vbox>
         <label class="description" value="&debuggerUI.searchPanelTitle;"/>
         <hbox align="center">
           <button id="global-operator-button" class="operator"
@@ -174,28 +188,35 @@
                   command="tokenSearchCommand"/>
           <label id="token-operator-label" class="plain operator"/>
         </hbox>
         <hbox align="center">
           <button id="line-operator-button" class="operator"
                   command="lineSearchCommand"/>
           <label id="line-operator-label" class="plain operator"/>
         </hbox>
+        <hbox align="center">
+          <button id="variable-operator-button" class="operator"
+                  command="variableSearchCommand"/>
+          <label id="variable-operator-label" class="plain operator"/>
+        </hbox>
       </vbox>
     </panel>
+
     <vbox id="dbg-content" flex="1">
       <vbox id="globalsearch" hidden="true"/>
       <splitter id="globalsearch-splitter"
                 class="devtools-horizontal-splitter" hidden="true"/>
       <hbox flex="1">
         <vbox id="stackframes+breakpoints">
           <vbox id="stackframes" flex="1"/>
           <splitter class="devtools-horizontal-splitter"/>
           <vbox id="breakpoints"/>
         </vbox>
         <splitter class="devtools-side-splitter"/>
         <vbox id="editor" flex="1"/>
         <splitter class="devtools-side-splitter"/>
         <vbox id="variables"/>
       </hbox>
     </vbox>
+
   </vbox>
 </window>
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -28,16 +28,22 @@ MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_propertyview-04.js \
 	browser_dbg_propertyview-05.js \
 	browser_dbg_propertyview-06.js \
 	browser_dbg_propertyview-07.js \
 	browser_dbg_propertyview-08.js \
 	browser_dbg_propertyview-09.js \
 	browser_dbg_propertyview-10.js \
 	browser_dbg_propertyview-edit.js \
+	browser_dbg_propertyview-data.js \
+	browser_dbg_propertyview-filter-01.js \
+	browser_dbg_propertyview-filter-02.js \
+	browser_dbg_propertyview-filter-03.js \
+	browser_dbg_propertyview-filter-04.js \
+	browser_dbg_propertyview-filter-05.js \
 	browser_dbg_propertyview-reexpand.js \
 	browser_dbg_reload-same-script.js \
 	browser_dbg_pane-collapse.js \
 	browser_dbg_panesize.js \
 	browser_dbg_panesize-inner.js \
 	browser_dbg_stack-01.js \
 	browser_dbg_stack-02.js \
 	browser_dbg_stack-03.js \
--- a/browser/devtools/debugger/test/browser_dbg_bug786070_hide_nonenums.js
+++ b/browser/devtools/debugger/test/browser_dbg_bug786070_hide_nonenums.js
@@ -50,56 +50,56 @@ function testNonEnumProperties() {
 
       is(nonenum.childNodes.length, 1,
         "There should be just one property in the .nonenum container.");
 
       ok(nonenum.hasAttribute("open"),
         ".nonenum container should be visible.");
 
       // Uncheck 'show hidden properties'.
-      gDebugger.DebuggerView.Options._showNonEnumItem.setAttribute("checked", "false");
-      gDebugger.DebuggerView.Options._toggleShowNonEnum();
+      gDebugger.DebuggerView.Options._showVariablesNonEnumItem.setAttribute("checked", "false");
+      gDebugger.DebuggerView.Options._toggleShowVariablesNonEnum();
 
       ok(details.hasAttribute("open"),
         ".details container should stay visible.");
 
       ok(!nonenum.hasAttribute("open"),
         ".nonenum container should become hidden.");
 
       // Check 'show hidden properties'.
-      gDebugger.DebuggerView.Options._showNonEnumItem.setAttribute("checked", "true");
-      gDebugger.DebuggerView.Options._toggleShowNonEnum();
+      gDebugger.DebuggerView.Options._showVariablesNonEnumItem.setAttribute("checked", "true");
+      gDebugger.DebuggerView.Options._toggleShowVariablesNonEnum();
 
       ok(details.hasAttribute("open"),
         ".details container should stay visible.");
 
       ok(nonenum.hasAttribute("open"),
         ".nonenum container should become visible.");
 
       testVar.collapse();
 
       ok(!details.hasAttribute("open"),
         ".details container should be hidden.");
 
       ok(!nonenum.hasAttribute("open"),
         ".nonenum container should be hidden.");
 
       // Uncheck 'show hidden properties'.
-      gDebugger.DebuggerView.Options._showNonEnumItem.setAttribute("checked", "false");
-      gDebugger.DebuggerView.Options._toggleShowNonEnum();
+      gDebugger.DebuggerView.Options._showVariablesNonEnumItem.setAttribute("checked", "false");
+      gDebugger.DebuggerView.Options._toggleShowVariablesNonEnum();
 
       ok(!details.hasAttribute("open"),
         ".details container should stay hidden.");
 
       ok(!nonenum.hasAttribute("open"),
         ".nonenum container should stay hidden.");
 
       // Check 'show hidden properties'.
-      gDebugger.DebuggerView.Options._showNonEnumItem.setAttribute("checked", "true");
-      gDebugger.DebuggerView.Options._toggleShowNonEnum();
+      gDebugger.DebuggerView.Options._showVariablesNonEnumItem.setAttribute("checked", "true");
+      gDebugger.DebuggerView.Options._toggleShowVariablesNonEnum();
 
       gDebugger.DebuggerController.activeThread.resume(function() {
         closeDebuggerAndFinish();
       });
     }}, 0);
   });
 
   gDebuggee.simpleCall();
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-data.js
@@ -0,0 +1,485 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure that the property view correctly populates itself.
+ */
+
+var gPane = null;
+var gTab = null;
+var gDebugger = null;
+var gVariablesView = null;
+var gScope = null;
+var gVariable = null;
+
+function test()
+{
+  debug_tab_pane(TAB1_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gPane = aPane;
+    gDebugger = gPane.contentWindow;
+    gVariablesView = gDebugger.DebuggerView.Variables;
+
+    testVariablesView();
+  });
+}
+
+function testVariablesView()
+{
+  let arr = [
+    42,
+    true,
+    "nasu",
+    undefined,
+    null,
+    [0, 1, 2],
+    { prop1: 9, prop2: 8 }
+  ];
+
+  let obj = {
+    "p0": 42,
+    "p1": true,
+    "p2": "nasu",
+    "p3": undefined,
+    "p4": null,
+    "p5": [3, 4, 5],
+    "p6": { prop1: 7, prop2: 6 },
+    get p7() { return arr; },
+    set p8(value) { arr[0] = value }
+  };
+
+  let test = {
+    someProp0: 42,
+    someProp1: true,
+    someProp2: "nasu",
+    someProp3: undefined,
+    someProp4: null,
+    someProp5: arr,
+    someProp6: obj,
+    get someProp7() { return arr; },
+    set someProp7(value) { arr[0] = value }
+  };
+
+  gVariablesView.rawObject = test;
+
+  testHierarchy();
+  testHeader();
+  testFirstLevelContents();
+  testSecondLevelContents();
+  testThirdLevelContents();
+  testIntegrity(arr, obj);
+
+  closeDebuggerAndFinish();
+}
+
+function testHierarchy() {
+  is(gVariablesView._currHierarchy.size, 13,
+    "There should be 1 scope, 1 var, 1 proto, 8 props, 1 getter and 1 setter.");
+
+  gScope = gVariablesView._currHierarchy.get("");
+  gVariable = gVariablesView._currHierarchy.get(".");
+
+  is(gVariablesView._store.size, 1,
+    "There should be only one scope in the view");
+  is(gScope._store.size, 1,
+    "There should be only one variable in the scope");
+  is(gVariable._store.size, 9,
+    "There should be 1 __proto__ and 8 properties in the variable");
+}
+
+function testHeader() {
+  is(gScope.header, false,
+    "The scope title header should be hidden");
+  is(gVariable.header, false,
+    "The variable title header should be hidden");
+
+  gScope.showHeader();
+  gVariable.showHeader();
+
+  is(gScope.header, true,
+    "The scope title header should now be visible");
+  is(gVariable.header, true,
+    "The variable title header should now be visible");
+
+  gScope.hideHeader();
+  gVariable.hideHeader();
+
+  is(gScope.header, false,
+    "The scope title header should now be hidden");
+  is(gVariable.header, false,
+    "The variable title header should now be hidden");
+}
+
+function testFirstLevelContents() {
+  let someProp0 = gVariable.get("someProp0");
+  let someProp1 = gVariable.get("someProp1");
+  let someProp2 = gVariable.get("someProp2");
+  let someProp3 = gVariable.get("someProp3");
+  let someProp4 = gVariable.get("someProp4");
+  let someProp5 = gVariable.get("someProp5");
+  let someProp6 = gVariable.get("someProp6");
+  let someProp7 = gVariable.get("someProp7");
+  let __proto__ = gVariable.get("__proto__");
+
+  is(someProp0.visible, true, "The first property visible state is correct.");
+  is(someProp1.visible, true, "The second property visible state is correct.");
+  is(someProp2.visible, true, "The third property visible state is correct.");
+  is(someProp3.visible, true, "The fourth property visible state is correct.");
+  is(someProp4.visible, true, "The fifth property visible state is correct.");
+  is(someProp5.visible, true, "The sixth property visible state is correct.");
+  is(someProp6.visible, true, "The seventh property visible state is correct.");
+  is(someProp7.visible, true, "The eight property visible state is correct.");
+  is(__proto__.visible, true, "The __proto__ property visible state is correct.");
+
+  is(someProp0.expanded, false, "The first property expanded state is correct.");
+  is(someProp1.expanded, false, "The second property expanded state is correct.");
+  is(someProp2.expanded, false, "The third property expanded state is correct.");
+  is(someProp3.expanded, false, "The fourth property expanded state is correct.");
+  is(someProp4.expanded, false, "The fifth property expanded state is correct.");
+  is(someProp5.expanded, false, "The sixth property expanded state is correct.");
+  is(someProp6.expanded, false, "The seventh property expanded state is correct.");
+  is(someProp7.expanded, true, "The eight property expanded state is correct.");
+  is(__proto__.expanded, false, "The __proto__ property expanded state is correct.");
+
+  is(someProp0.header, true, "The first property header state is correct.");
+  is(someProp1.header, true, "The second property header state is correct.");
+  is(someProp2.header, true, "The third property header state is correct.");
+  is(someProp3.header, true, "The fourth property header state is correct.");
+  is(someProp4.header, true, "The fifth property header state is correct.");
+  is(someProp5.header, true, "The sixth property header state is correct.");
+  is(someProp6.header, true, "The seventh property header state is correct.");
+  is(someProp7.header, true, "The eight property header state is correct.");
+  is(__proto__.header, true, "The __proto__ property header state is correct.");
+
+  is(someProp0.twisty, false, "The first property twisty state is correct.");
+  is(someProp1.twisty, false, "The second property twisty state is correct.");
+  is(someProp2.twisty, false, "The third property twisty state is correct.");
+  is(someProp3.twisty, false, "The fourth property twisty state is correct.");
+  is(someProp4.twisty, false, "The fifth property twisty state is correct.");
+  is(someProp5.twisty, true, "The sixth property twisty state is correct.");
+  is(someProp6.twisty, true, "The seventh property twisty state is correct.");
+  is(someProp7.twisty, true, "The eight property twisty state is correct.");
+  is(__proto__.twisty, true, "The __proto__ property twisty state is correct.");
+
+  is(someProp0.name, "someProp0", "The first property name is correct.");
+  is(someProp1.name, "someProp1", "The second property name is correct.");
+  is(someProp2.name, "someProp2", "The third property name is correct.");
+  is(someProp3.name, "someProp3", "The fourth property name is correct.");
+  is(someProp4.name, "someProp4", "The fifth property name is correct.");
+  is(someProp5.name, "someProp5", "The sixth property name is correct.");
+  is(someProp6.name, "someProp6", "The seventh property name is correct.");
+  is(someProp7.name, "someProp7", "The eight property name is correct.");
+  is(__proto__.name, "__proto__", "The __proto__ property name is correct.");
+
+  is(someProp0.value, 42, "The first property value is correct.");
+  is(someProp1.value, true, "The second property value is correct.");
+  is(someProp2.value, "nasu", "The third property value is correct.");
+  is(someProp3.value.type, "undefined", "The fourth property value is correct.");
+  is(someProp4.value.type, "null", "The fifth property value is correct.");
+  is(someProp5.value.type, "object", "The sixth property value type is correct.");
+  is(someProp5.value.class, "Array", "The sixth property value class is correct.");
+  is(someProp6.value.type, "object", "The seventh property value type is correct.");
+  is(someProp6.value.class, "Object", "The seventh property value class is correct.");
+  is(someProp7.value, null, "The eight property value is correct.");
+  isnot(someProp7.getter, null, "The eight property getter is correct.");
+  isnot(someProp7.setter, null, "The eight property setter is correct.");
+  is(someProp7.getter.type, "object", "The eight property getter type is correct.");
+  is(someProp7.getter.class, "Function", "The eight property getter class is correct.");
+  is(someProp7.setter.type, "object", "The eight property setter type is correct.");
+  is(someProp7.setter.class, "Function", "The eight property setter class is correct.");
+  is(__proto__.value.type, "object", "The __proto__ property value type is correct.");
+  is(__proto__.value.class, "Object", "The __proto__ property value class is correct.");
+
+
+  someProp0.expand();
+  someProp1.expand();
+  someProp2.expand();
+  someProp3.expand();
+  someProp4.expand();
+  someProp7.expand();
+
+  ok(!someProp0.get("__proto__"), "Number primitives should not have a prototype");
+  ok(!someProp1.get("__proto__"), "Boolean primitives should not have a prototype");
+  ok(!someProp2.get("__proto__"), "String literals should not have a prototype");
+  ok(!someProp3.get("__proto__"), "Undefined values should not have a prototype");
+  ok(!someProp4.get("__proto__"), "Null values should not have a prototype");
+  ok(!someProp7.get("__proto__"), "Getter properties should not have a prototype");
+}
+
+function testSecondLevelContents() {
+  let someProp5 = gVariable.get("someProp5");
+
+  is(someProp5._store.size, 0, "No properties should be in someProp5 before expanding");
+  someProp5.expand();
+  is(someProp5._store.size, 9, "Some properties should be in someProp5 before expanding");
+
+  let arrayItem0 = someProp5.get("0");
+  let arrayItem1 = someProp5.get("1");
+  let arrayItem2 = someProp5.get("2");
+  let arrayItem3 = someProp5.get("3");
+  let arrayItem4 = someProp5.get("4");
+  let arrayItem5 = someProp5.get("5");
+  let arrayItem6 = someProp5.get("6");
+  let __proto__ = someProp5.get("__proto__");
+
+  is(arrayItem0.visible, true, "The first array item visible state is correct.");
+  is(arrayItem1.visible, true, "The second array item visible state is correct.");
+  is(arrayItem2.visible, true, "The third array item visible state is correct.");
+  is(arrayItem3.visible, true, "The fourth array item visible state is correct.");
+  is(arrayItem4.visible, true, "The fifth array item visible state is correct.");
+  is(arrayItem5.visible, true, "The sixth array item visible state is correct.");
+  is(arrayItem6.visible, true, "The seventh array item visible state is correct.");
+  is(__proto__.visible, true, "The __proto__ property visible state is correct.");
+
+  is(arrayItem0.expanded, false, "The first array item expanded state is correct.");
+  is(arrayItem1.expanded, false, "The second array item expanded state is correct.");
+  is(arrayItem2.expanded, false, "The third array item expanded state is correct.");
+  is(arrayItem3.expanded, false, "The fourth array item expanded state is correct.");
+  is(arrayItem4.expanded, false, "The fifth array item expanded state is correct.");
+  is(arrayItem5.expanded, false, "The sixth array item expanded state is correct.");
+  is(arrayItem6.expanded, false, "The seventh array item expanded state is correct.");
+  is(__proto__.expanded, false, "The __proto__ property expanded state is correct.");
+
+  is(arrayItem0.header, true, "The first array item header state is correct.");
+  is(arrayItem1.header, true, "The second array item header state is correct.");
+  is(arrayItem2.header, true, "The third array item header state is correct.");
+  is(arrayItem3.header, true, "The fourth array item header state is correct.");
+  is(arrayItem4.header, true, "The fifth array item header state is correct.");
+  is(arrayItem5.header, true, "The sixth array item header state is correct.");
+  is(arrayItem6.header, true, "The seventh array item header state is correct.");
+  is(__proto__.header, true, "The __proto__ property header state is correct.");
+
+  is(arrayItem0.twisty, false, "The first array item twisty state is correct.");
+  is(arrayItem1.twisty, false, "The second array item twisty state is correct.");
+  is(arrayItem2.twisty, false, "The third array item twisty state is correct.");
+  is(arrayItem3.twisty, false, "The fourth array item twisty state is correct.");
+  is(arrayItem4.twisty, false, "The fifth array item twisty state is correct.");
+  is(arrayItem5.twisty, true, "The sixth array item twisty state is correct.");
+  is(arrayItem6.twisty, true, "The seventh array item twisty state is correct.");
+  is(__proto__.twisty, true, "The __proto__ property twisty state is correct.");
+
+  is(arrayItem0.name, "0", "The first array item name is correct.");
+  is(arrayItem1.name, "1", "The second array item name is correct.");
+  is(arrayItem2.name, "2", "The third array item name is correct.");
+  is(arrayItem3.name, "3", "The fourth array item name is correct.");
+  is(arrayItem4.name, "4", "The fifth array item name is correct.");
+  is(arrayItem5.name, "5", "The sixth array item name is correct.");
+  is(arrayItem6.name, "6", "The seventh array item name is correct.");
+  is(__proto__.name, "__proto__", "The __proto__ property name is correct.");
+
+  is(arrayItem0.value, 42, "The first array item value is correct.");
+  is(arrayItem1.value, true, "The second array item value is correct.");
+  is(arrayItem2.value, "nasu", "The third array item value is correct.");
+  is(arrayItem3.value.type, "undefined", "The fourth array item value is correct.");
+  is(arrayItem4.value.type, "null", "The fifth array item value is correct.");
+  is(arrayItem5.value.type, "object", "The sixth array item value type is correct.");
+  is(arrayItem5.value.class, "Array", "The sixth array item value class is correct.");
+  is(arrayItem6.value.type, "object", "The seventh array item value type is correct.");
+  is(arrayItem6.value.class, "Object", "The seventh array item value class is correct.");
+  is(__proto__.value.type, "object", "The __proto__ property value type is correct.");
+  is(__proto__.value.class, "Array", "The __proto__ property value class is correct.");
+
+
+  let someProp6 = gVariable.get("someProp6");
+
+  is(someProp6._store.size, 0, "No properties should be in someProp6 before expanding");
+  someProp6.expand();
+  is(someProp6._store.size, 10, "Some properties should be in someProp6 before expanding");
+
+  let objectItem0 = someProp6.get("p0");
+  let objectItem1 = someProp6.get("p1");
+  let objectItem2 = someProp6.get("p2");
+  let objectItem3 = someProp6.get("p3");
+  let objectItem4 = someProp6.get("p4");
+  let objectItem5 = someProp6.get("p5");
+  let objectItem6 = someProp6.get("p6");
+  let objectItem7 = someProp6.get("p7");
+  let objectItem8 = someProp6.get("p8");
+  let __proto__ = someProp6.get("__proto__");
+
+  is(objectItem0.visible, true, "The first object item visible state is correct.");
+  is(objectItem1.visible, true, "The second object item visible state is correct.");
+  is(objectItem2.visible, true, "The third object item visible state is correct.");
+  is(objectItem3.visible, true, "The fourth object item visible state is correct.");
+  is(objectItem4.visible, true, "The fifth object item visible state is correct.");
+  is(objectItem5.visible, true, "The sixth object item visible state is correct.");
+  is(objectItem6.visible, true, "The seventh object item visible state is correct.");
+  is(objectItem7.visible, true, "The eight object item visible state is correct.");
+  is(objectItem8.visible, true, "The ninth object item visible state is correct.");
+  is(__proto__.visible, true, "The __proto__ property visible state is correct.");
+
+  is(objectItem0.expanded, false, "The first object item expanded state is correct.");
+  is(objectItem1.expanded, false, "The second object item expanded state is correct.");
+  is(objectItem2.expanded, false, "The third object item expanded state is correct.");
+  is(objectItem3.expanded, false, "The fourth object item expanded state is correct.");
+  is(objectItem4.expanded, false, "The fifth object item expanded state is correct.");
+  is(objectItem5.expanded, false, "The sixth object item expanded state is correct.");
+  is(objectItem6.expanded, false, "The seventh object item expanded state is correct.");
+  is(objectItem7.expanded, true, "The eight object item expanded state is correct.");
+  is(objectItem8.expanded, true, "The ninth object item expanded state is correct.");
+  is(__proto__.expanded, false, "The __proto__ property expanded state is correct.");
+
+  is(objectItem0.header, true, "The first object item header state is correct.");
+  is(objectItem1.header, true, "The second object item header state is correct.");
+  is(objectItem2.header, true, "The third object item header state is correct.");
+  is(objectItem3.header, true, "The fourth object item header state is correct.");
+  is(objectItem4.header, true, "The fifth object item header state is correct.");
+  is(objectItem5.header, true, "The sixth object item header state is correct.");
+  is(objectItem6.header, true, "The seventh object item header state is correct.");
+  is(objectItem7.header, true, "The eight object item header state is correct.");
+  is(objectItem8.header, true, "The ninth object item header state is correct.");
+  is(__proto__.header, true, "The __proto__ property header state is correct.");
+
+  is(objectItem0.twisty, false, "The first object item twisty state is correct.");
+  is(objectItem1.twisty, false, "The second object item twisty state is correct.");
+  is(objectItem2.twisty, false, "The third object item twisty state is correct.");
+  is(objectItem3.twisty, false, "The fourth object item twisty state is correct.");
+  is(objectItem4.twisty, false, "The fifth object item twisty state is correct.");
+  is(objectItem5.twisty, true, "The sixth object item twisty state is correct.");
+  is(objectItem6.twisty, true, "The seventh object item twisty state is correct.");
+  is(objectItem7.twisty, true, "The eight object item twisty state is correct.");
+  is(objectItem8.twisty, true, "The ninth object item twisty state is correct.");
+  is(__proto__.twisty, true, "The __proto__ property twisty state is correct.");
+
+  is(objectItem0.name, "p0", "The first object item name is correct.");
+  is(objectItem1.name, "p1", "The second object item name is correct.");
+  is(objectItem2.name, "p2", "The third object item name is correct.");
+  is(objectItem3.name, "p3", "The fourth object item name is correct.");
+  is(objectItem4.name, "p4", "The fifth object item name is correct.");
+  is(objectItem5.name, "p5", "The sixth object item name is correct.");
+  is(objectItem6.name, "p6", "The seventh object item name is correct.");
+  is(objectItem7.name, "p7", "The eight seventh object item name is correct.");
+  is(objectItem8.name, "p8", "The ninth seventh object item name is correct.");
+  is(__proto__.name, "__proto__", "The __proto__ property name is correct.");
+
+  is(objectItem0.value, 42, "The first object item value is correct.");
+  is(objectItem1.value, true, "The second object item value is correct.");
+  is(objectItem2.value, "nasu", "The third object item value is correct.");
+  is(objectItem3.value.type, "undefined", "The fourth object item value is correct.");
+  is(objectItem4.value.type, "null", "The fifth object item value is correct.");
+  is(objectItem5.value.type, "object", "The sixth object item value type is correct.");
+  is(objectItem5.value.class, "Array", "The sixth object item value class is correct.");
+  is(objectItem6.value.type, "object", "The seventh object item value type is correct.");
+  is(objectItem6.value.class, "Object", "The seventh object item value class is correct.");
+  is(objectItem7.value, null, "The eight object item value is correct.");
+  isnot(objectItem7.getter, null, "The eight object item getter is correct.");
+  isnot(objectItem7.setter, null, "The eight object item setter is correct.");
+  is(objectItem7.setter.type, "undefined", "The eight object item setter type is correct.");
+  is(objectItem7.getter.type, "object", "The eight object item getter type is correct.");
+  is(objectItem7.getter.class, "Function", "The eight object item getter class is correct.");
+  is(objectItem8.value, null, "The ninth object item value is correct.");
+  isnot(objectItem8.getter, null, "The ninth object item getter is correct.");
+  isnot(objectItem8.setter, null, "The ninth object item setter is correct.");
+  is(objectItem8.getter.type, "undefined", "The eight object item getter type is correct.");
+  is(objectItem8.setter.type, "object", "The ninth object item setter type is correct.");
+  is(objectItem8.setter.class, "Function", "The ninth object item setter class is correct.");
+  is(__proto__.value.type, "object", "The __proto__ property value type is correct.");
+  is(__proto__.value.class, "Object", "The __proto__ property value class is correct.");
+}
+
+function testThirdLevelContents() {
+  (function() {
+    let someProp5 = gVariable.get("someProp5");
+    let arrayItem5 = someProp5.get("5");
+    let arrayItem6 = someProp5.get("6");
+
+    is(arrayItem5._store.size, 0, "No properties should be in arrayItem5 before expanding");
+    arrayItem5.expand();
+    is(arrayItem5._store.size, 5, "Some properties should be in arrayItem5 before expanding");
+
+    is(arrayItem6._store.size, 0, "No properties should be in arrayItem6 before expanding");
+    arrayItem6.expand();
+    is(arrayItem6._store.size, 3, "Some properties should be in arrayItem6 before expanding");
+
+    let arraySubItem0 = arrayItem5.get("0");
+    let arraySubItem1 = arrayItem5.get("1");
+    let arraySubItem2 = arrayItem5.get("2");
+    let objectSubItem0 = arrayItem6.get("prop1");
+    let objectSubItem1 = arrayItem6.get("prop2");
+
+    is(arraySubItem0.value, 0, "The first array sub-item value is correct.");
+    is(arraySubItem1.value, 1, "The second array sub-item value is correct.");
+    is(arraySubItem2.value, 2, "The third array sub-item value is correct.");
+
+    is(objectSubItem0.value, 9, "The first object sub-item value is correct.");
+    is(objectSubItem1.value, 8, "The second object sub-item value is correct.");
+
+    let array__proto__ = arrayItem5.get("__proto__");
+    let object__proto__ = arrayItem6.get("__proto__");
+
+    ok(array__proto__, "The array should have a __proto__ property");
+    ok(object__proto__, "The object should have a __proto__ property");
+  })();
+
+  (function() {
+    let someProp6 = gVariable.get("someProp6");
+    let objectItem5 = someProp6.get("p5");
+    let objectItem6 = someProp6.get("p6");
+
+    is(objectItem5._store.size, 0, "No properties should be in objectItem5 before expanding");
+    objectItem5.expand();
+    is(objectItem5._store.size, 5, "Some properties should be in objectItem5 before expanding");
+
+    is(objectItem6._store.size, 0, "No properties should be in objectItem6 before expanding");
+    objectItem6.expand();
+    is(objectItem6._store.size, 3, "Some properties should be in objectItem6 before expanding");
+
+    let arraySubItem0 = objectItem5.get("0");
+    let arraySubItem1 = objectItem5.get("1");
+    let arraySubItem2 = objectItem5.get("2");
+    let objectSubItem0 = objectItem6.get("prop1");
+    let objectSubItem1 = objectItem6.get("prop2");
+
+    is(arraySubItem0.value, 3, "The first array sub-item value is correct.");
+    is(arraySubItem1.value, 4, "The second array sub-item value is correct.");
+    is(arraySubItem2.value, 5, "The third array sub-item value is correct.");
+
+    is(objectSubItem0.value, 7, "The first object sub-item value is correct.");
+    is(objectSubItem1.value, 6, "The second object sub-item value is correct.");
+
+    let array__proto__ = objectItem5.get("__proto__");
+    let object__proto__ = objectItem6.get("__proto__");
+
+    ok(array__proto__, "The array should have a __proto__ property");
+    ok(object__proto__, "The object should have a __proto__ property");
+  })();
+}
+
+function testIntegrity(arr, obj) {
+  is(arr[0], 42, "The first array item should not have changed");
+  is(arr[1], true, "The second array item should not have changed");
+  is(arr[2], "nasu", "The third array item should not have changed");
+  is(arr[3], undefined, "The fourth array item should not have changed");
+  is(arr[4], null, "The fifth array item should not have changed");
+  ok(arr[5] instanceof Array, "The sixth array item should be an Array");
+  is(arr[5][0], 0, "The sixth array item should not have changed");
+  is(arr[5][1], 1, "The sixth array item should not have changed");
+  is(arr[5][2], 2, "The sixth array item should not have changed");
+  ok(arr[6] instanceof Object, "The seventh array item should be an Object");
+  is(arr[6].prop1, 9, "The seventh array item should not have changed");
+  is(arr[6].prop2, 8, "The seventh array item should not have changed");
+
+  is(obj.p0, 42, "The first object property should not have changed");
+  is(obj.p1, true, "The first object property should not have changed");
+  is(obj.p2, "nasu", "The first object property should not have changed");
+  is(obj.p3, undefined, "The first object property should not have changed");
+  is(obj.p4, null, "The first object property should not have changed");
+  ok(obj.p5 instanceof Array, "The sixth object property should be an Array");
+  is(obj.p5[0], 3, "The sixth object property should not have changed");
+  is(obj.p5[1], 4, "The sixth object property should not have changed");
+  is(obj.p5[2], 5, "The sixth object property should not have changed");
+  ok(obj.p6 instanceof Object, "The seventh object property should be an Object");
+  is(obj.p6.prop1, 7, "The seventh object property should not have changed");
+  is(obj.p6.prop2, 6, "The seventh object property should not have changed");
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebugger = null;
+  gVariablesView = null;
+  gScope = null;
+  gVariable = null;
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-filter-01.js
@@ -0,0 +1,483 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure that the property view correctly filters nodes by name.
+ */
+
+const TAB_URL = EXAMPLE_URL + "browser_dbg_with-frame.html";
+
+var gPane = null;
+var gTab = null;
+var gDebugger = null;
+var gDebuggee = null;
+var gSearchBox = null;
+
+requestLongerTimeout(2);
+
+function test()
+{
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gPane = aPane;
+    gDebugger = gPane.contentWindow;
+    gDebuggee = aDebuggee;
+
+    testSearchbox();
+    prepareVariables(testVariablesFiltering);
+  });
+}
+
+function testSearchbox()
+{
+  ok(!gDebugger.DebuggerView.Variables._searchboxNode,
+    "There should not initially be a searchbox available in the variables view.");
+  ok(!gDebugger.DebuggerView.Variables._parent.querySelector(".devtools-searchinput"),
+    "There searchbox element should not be found.");
+
+  gDebugger.DebuggerView.Variables.enableSearch();
+  ok(gDebugger.DebuggerView.Variables._searchboxNode,
+    "There should be a searchbox available after enabling.");
+  ok(gDebugger.DebuggerView.Variables._parent.querySelector(".devtools-searchinput"),
+    "There searchbox element should be found.");
+
+
+  gDebugger.DebuggerView.Variables.disableSearch();
+  ok(!gDebugger.DebuggerView.Variables._searchboxNode,
+    "There shouldn't be a searchbox available after disabling.");
+  ok(!gDebugger.DebuggerView.Variables._parent.querySelector(".devtools-searchinput"),
+    "There searchbox element should not be found.");
+
+  gDebugger.DebuggerView.Variables.enableSearch();
+  ok(gDebugger.DebuggerView.Variables._searchboxNode,
+    "There should be a searchbox available after enabling.");
+  ok(gDebugger.DebuggerView.Variables._parent.querySelector(".devtools-searchinput"),
+    "There searchbox element should be found.");
+
+  let placeholder = "freshly squeezed mango juice";
+
+  gDebugger.DebuggerView.Variables.searchPlaceholder = placeholder;
+  ok(gDebugger.DebuggerView.Variables._searchboxNode.getAttribute("placeholder"),
+    placeholder, "There correct placeholder should be applied to the searchbox.");
+
+
+  gDebugger.DebuggerView.Variables.disableSearch();
+  ok(!gDebugger.DebuggerView.Variables._searchboxNode,
+    "There shouldn't be a searchbox available after disabling again.");
+  ok(!gDebugger.DebuggerView.Variables._parent.querySelector(".devtools-searchinput"),
+    "There searchbox element should not be found.");
+
+  gDebugger.DebuggerView.Variables.enableSearch();
+  ok(gDebugger.DebuggerView.Variables._searchboxNode,
+    "There should be a searchbox available after enabling again.");
+  ok(gDebugger.DebuggerView.Variables._parent.querySelector(".devtools-searchinput"),
+    "There searchbox element should be found.");
+
+  ok(gDebugger.DebuggerView.Variables._searchboxNode.getAttribute("placeholder"),
+    placeholder, "There correct placeholder should be applied to the searchbox again.");
+
+
+  gDebugger.DebuggerView.Variables.searchEnabled = false;
+  ok(!gDebugger.DebuggerView.Variables._searchboxNode,
+    "There shouldn't be a searchbox available after disabling again.");
+  ok(!gDebugger.DebuggerView.Variables._parent.querySelector(".devtools-searchinput"),
+    "There searchbox element should not be found.");
+
+  gDebugger.DebuggerView.Variables.searchEnabled = true;
+  ok(gDebugger.DebuggerView.Variables._searchboxNode,
+    "There should be a searchbox available after enabling again.");
+  ok(gDebugger.DebuggerView.Variables._parent.querySelector(".devtools-searchinput"),
+    "There searchbox element should be found.");
+
+  ok(gDebugger.DebuggerView.Variables._searchboxNode.getAttribute("placeholder"),
+    placeholder, "There correct placeholder should be applied to the searchbox again.");
+}
+
+function testVariablesFiltering()
+{
+  function test1()
+  {
+    write("location");
+
+    is(innerScopeItem.expanded, true,
+      "The innerScope expanded getter should return true");
+    is(mathScopeItem.expanded, true,
+      "The mathScope expanded getter should return true");
+    is(testScopeItem.expanded, true,
+      "The testScope expanded getter should return true");
+    is(loadScopeItem.expanded, true,
+      "The loadScope expanded getter should return true");
+    is(globalScopeItem.expanded, true,
+      "The globalScope expanded getter should return true");
+
+    is(thisItem.expanded, true,
+      "The local scope 'this' should be expanded");
+    is(windowItem.expanded, true,
+      "The local scope 'this.window' should be expanded");
+    is(documentItem.expanded, true,
+      "The local scope 'this.window.document' should be expanded");
+    is(locationItem.expanded, true,
+      "The local scope 'this.window.document.location' should be expanded");
+
+    ignoreExtraMatchedProperties();
+
+    is(innerScope.querySelectorAll(".variable:not([non-match])").length, 1,
+      "There should be 1 variable displayed in the inner scope");
+    is(mathScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the math scope");
+    is(testScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the test scope");
+    is(loadScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the load scope");
+    is(globalScope.querySelectorAll(".variable:not([non-match])").length, 1,
+      "There should be 1 variable displayed in the global scope");
+
+    is(innerScope.querySelectorAll(".property:not([non-match])").length, 6,
+      "There should be 6 properties displayed in the inner scope");
+    is(mathScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the math scope");
+    is(testScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the test scope");
+    is(loadScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the load scope");
+    is(globalScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the global scope");
+
+    is(innerScope.querySelectorAll(".variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
+      "this", "The only inner variable displayed should be 'this'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[0].getAttribute("value"),
+      "window", "The first inner property displayed should be 'window'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[1].getAttribute("value"),
+      "document", "The second inner property displayed should be 'document'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[2].getAttribute("value"),
+      "location", "The third inner property displayed should be 'location'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[3].getAttribute("value"),
+      "__proto__", "The fourth inner property displayed should be '__proto__'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[4].getAttribute("value"),
+      "Location", "The fifth inner property displayed should be 'Location'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[5].getAttribute("value"),
+      "Location", "The sixth inner property displayed should be 'Location'");
+
+    is(globalScope.querySelectorAll(".variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
+      "Location", "The only global variable displayed should be 'Location'");
+  }
+
+  function test2()
+  {
+    innerScopeItem.collapse();
+    mathScopeItem.collapse();
+    testScopeItem.collapse();
+    loadScopeItem.collapse();
+    globalScopeItem.collapse();
+    thisItem.collapse();
+    windowItem.collapse();
+    documentItem.collapse();
+    locationItem.collapse();
+
+    is(innerScopeItem.expanded, false,
+      "The innerScope expanded getter should return false");
+    is(mathScopeItem.expanded, false,
+      "The mathScope expanded getter should return false");
+    is(testScopeItem.expanded, false,
+      "The testScope expanded getter should return false");
+    is(loadScopeItem.expanded, false,
+      "The loadScope expanded getter should return false");
+    is(globalScopeItem.expanded, false,
+      "The globalScope expanded getter should return false");
+
+    is(thisItem.expanded, false,
+      "The local scope 'this' should not be expanded");
+    is(windowItem.expanded, false,
+      "The local scope 'this.window' should not be expanded");
+    is(documentItem.expanded, false,
+      "The local scope 'this.window.document' should not be expanded");
+    is(locationItem.expanded, false,
+      "The local scope 'this.window.document.location' should not be expanded");
+
+    write("location");
+
+    is(thisItem.expanded, true,
+      "The local scope 'this' should be expanded");
+    is(windowItem.expanded, true,
+      "The local scope 'this.window' should be expanded");
+    is(documentItem.expanded, true,
+      "The local scope 'this.window.document' should be expanded");
+    is(locationItem.expanded, true,
+      "The local scope 'this.window.document.location' should be expanded");
+
+    ignoreExtraMatchedProperties();
+
+    is(innerScope.querySelectorAll(".variable:not([non-match])").length, 1,
+      "There should be 1 variable displayed in the inner scope");
+    is(mathScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the math scope");
+    is(testScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the test scope");
+    is(loadScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the load scope");
+    is(globalScope.querySelectorAll(".variable:not([non-match])").length, 1,
+      "There should be 1 variable displayed in the global scope");
+
+    is(innerScope.querySelectorAll(".property:not([non-match])").length, 6,
+      "There should be 6 properties displayed in the inner scope");
+    is(mathScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the math scope");
+    is(testScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the test scope");
+    is(loadScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the load scope");
+    is(globalScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the global scope");
+
+    is(innerScope.querySelectorAll(".variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
+      "this", "The only inner variable displayed should be 'this'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[0].getAttribute("value"),
+      "window", "The first inner property displayed should be 'window'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[1].getAttribute("value"),
+      "document", "The second inner property displayed should be 'document'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[2].getAttribute("value"),
+      "location", "The third inner property displayed should be 'location'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[3].getAttribute("value"),
+      "__proto__", "The fourth inner property displayed should be '__proto__'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[4].getAttribute("value"),
+      "Location", "The fifth inner property displayed should be 'Location'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[5].getAttribute("value"),
+      "Location", "The sixth inner property displayed should be 'Location'");
+
+    is(globalScope.querySelectorAll(".variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
+      "Location", "The only global variable displayed should be 'Location'");
+  }
+
+  var scopes = gDebugger.DebuggerView.Variables._list,
+      innerScope = scopes.querySelectorAll(".scope")[0],
+      mathScope = scopes.querySelectorAll(".scope")[1],
+      testScope = scopes.querySelectorAll(".scope")[2],
+      loadScope = scopes.querySelectorAll(".scope")[3],
+      globalScope = scopes.querySelectorAll(".scope")[4];
+
+  let innerScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+    innerScope.querySelector(".name").getAttribute("value"));
+  let mathScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+    mathScope.querySelector(".name").getAttribute("value"));
+  let testScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+    testScope.querySelector(".name").getAttribute("value"));
+  let loadScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+    loadScope.querySelector(".name").getAttribute("value"));
+  let globalScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+    globalScope.querySelector(".name").getAttribute("value"));
+
+  let thisItem = innerScopeItem.get("this");
+  let windowItem = thisItem.get("window");
+  let documentItem = windowItem.get("document");
+  let locationItem = documentItem.get("location");
+
+  gSearchBox = gDebugger.DebuggerView.Variables._searchboxNode;
+
+  executeSoon(function() {
+    test1();
+    executeSoon(function() {
+      test2();
+      executeSoon(function() {
+        closeDebuggerAndFinish();
+      });
+    });
+  });
+}
+
+function prepareVariables(aCallback)
+{
+  let count = 0;
+  gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
+    // We expect 4 Debugger:FetchedVariables events, one from the global object
+    // scope, two from the |with| scopes and the regular one.
+    if (++count < 4) {
+      info("Number of received Debugger:FetchedVariables events: " + count);
+      return;
+    }
+    gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
+    Services.tm.currentThread.dispatch({ run: function() {
+
+      var frames = gDebugger.DebuggerView.StackFrames._container._list,
+          scopes = gDebugger.DebuggerView.Variables._list,
+          innerScope = scopes.querySelectorAll(".scope")[0],
+          mathScope = scopes.querySelectorAll(".scope")[1],
+          testScope = scopes.querySelectorAll(".scope")[2],
+          loadScope = scopes.querySelectorAll(".scope")[3],
+          globalScope = scopes.querySelectorAll(".scope")[4];
+
+      let innerScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+        innerScope.querySelector(".name").getAttribute("value"));
+      let mathScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+        mathScope.querySelector(".name").getAttribute("value"));
+      let testScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+        testScope.querySelector(".name").getAttribute("value"));
+      let loadScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+        loadScope.querySelector(".name").getAttribute("value"));
+      let globalScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+        globalScope.querySelector(".name").getAttribute("value"));
+
+      is(innerScopeItem.expanded, true,
+        "The innerScope expanded getter should return true");
+      is(mathScopeItem.expanded, false,
+        "The mathScope expanded getter should return false");
+      is(testScopeItem.expanded, false,
+        "The testScope expanded getter should return false");
+      is(loadScopeItem.expanded, false,
+        "The loadScope expanded getter should return false");
+      is(globalScopeItem.expanded, false,
+        "The globalScope expanded getter should return false");
+
+      EventUtils.sendMouseEvent({ type: "mousedown" }, mathScope.querySelector(".arrow"), gDebuggee);
+      EventUtils.sendMouseEvent({ type: "mousedown" }, testScope.querySelector(".arrow"), gDebuggee);
+      EventUtils.sendMouseEvent({ type: "mousedown" }, loadScope.querySelector(".arrow"), gDebuggee);
+      EventUtils.sendMouseEvent({ type: "mousedown" }, globalScope.querySelector(".arrow"), gDebuggee);
+
+      is(innerScopeItem.expanded, true,
+        "The innerScope expanded getter should return true");
+      is(mathScopeItem.expanded, true,
+        "The mathScope expanded getter should return true");
+      is(testScopeItem.expanded, true,
+        "The testScope expanded getter should return true");
+      is(loadScopeItem.expanded, true,
+        "The loadScope expanded getter should return true");
+      is(globalScopeItem.expanded, true,
+        "The globalScope expanded getter should return true");
+
+
+      let thisItem = innerScopeItem.get("this");
+      is(thisItem.expanded, false,
+        "The local scope 'this' should not be expanded yet");
+
+      gDebugger.addEventListener("Debugger:FetchedProperties", function test2() {
+        gDebugger.removeEventListener("Debugger:FetchedProperties", test2, false);
+        Services.tm.currentThread.dispatch({ run: function() {
+
+          let windowItem = thisItem.get("window");
+          is(windowItem.expanded, false,
+            "The local scope 'this.window' should not be expanded yet");
+
+          gDebugger.addEventListener("Debugger:FetchedProperties", function test3() {
+            gDebugger.removeEventListener("Debugger:FetchedProperties", test3, false);
+            Services.tm.currentThread.dispatch({ run: function() {
+
+              let documentItem = windowItem.get("document");
+              is(documentItem.expanded, false,
+                "The local scope 'this.window.document' should not be expanded yet");
+
+              gDebugger.addEventListener("Debugger:FetchedProperties", function test4() {
+                gDebugger.removeEventListener("Debugger:FetchedProperties", test4, false);
+                Services.tm.currentThread.dispatch({ run: function() {
+
+                  let locationItem = documentItem.get("location");
+                  is(locationItem.expanded, false,
+                    "The local scope 'this.window.document.location' should not be expanded yet");
+
+                  gDebugger.addEventListener("Debugger:FetchedProperties", function test5() {
+                    gDebugger.removeEventListener("Debugger:FetchedProperties", test5, false);
+                    Services.tm.currentThread.dispatch({ run: function() {
+
+                      is(thisItem.expanded, true,
+                        "The local scope 'this' should be expanded");
+                      is(windowItem.expanded, true,
+                        "The local scope 'this.window' should be expanded");
+                      is(documentItem.expanded, true,
+                        "The local scope 'this.window.document' should be expanded");
+                      is(locationItem.expanded, true,
+                        "The local scope 'this.window.document.location' should be expanded");
+
+                      executeSoon(function() {
+                        aCallback();
+                      });
+                    }}, 0);
+                  }, false);
+
+                  executeSoon(function() {
+                    EventUtils.sendMouseEvent({ type: "mousedown" },
+                      locationItem.target.querySelector(".arrow"),
+                      gDebuggee.window);
+
+                    is(locationItem.expanded, true,
+                      "The local scope 'this.window.document.location' should be expanded now");
+                  });
+                }}, 0);
+              }, false);
+
+              executeSoon(function() {
+                EventUtils.sendMouseEvent({ type: "mousedown" },
+                  documentItem.target.querySelector(".arrow"),
+                  gDebuggee.window);
+
+                is(documentItem.expanded, true,
+                  "The local scope 'this.window.document' should be expanded now");
+              });
+            }}, 0);
+          }, false);
+
+          executeSoon(function() {
+            EventUtils.sendMouseEvent({ type: "mousedown" },
+              windowItem.target.querySelector(".arrow"),
+              gDebuggee.window);
+
+            is(windowItem.expanded, true,
+              "The local scope 'this.window' should be expanded now");
+          });
+        }}, 0);
+      }, false);
+
+      executeSoon(function() {
+        EventUtils.sendMouseEvent({ type: "mousedown" },
+          thisItem.target.querySelector(".arrow"),
+          gDebuggee.window);
+
+        is(thisItem.expanded, true,
+          "The local scope 'this' should be expanded now");
+      });
+    }}, 0);
+  }, false);
+
+  EventUtils.sendMouseEvent({ type: "click" },
+    gDebuggee.document.querySelector("button"),
+    gDebuggee.window);
+}
+
+function ignoreExtraMatchedProperties()
+{
+  for (let [_, item] of gDebugger.DebuggerView.Variables._currHierarchy) {
+    let name = item.name.toLowerCase();
+    let value = item._valueString || "";
+
+    if ((name.contains("tracemallocdumpallocations")) ||
+        (name.contains("geolocation")) ||
+        (name.contains("webgl"))) {
+      item.target.setAttribute("non-match", "");
+    }
+  }
+}
+
+function clear() {
+  gSearchBox.focus();
+  gSearchBox.value = "";
+}
+
+function write(text) {
+  clear();
+  append(text);
+}
+
+function append(text) {
+  gSearchBox.focus();
+
+  for (let i = 0; i < text.length; i++) {
+    EventUtils.sendChar(text[i]);
+  }
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebugger = null;
+  gDebuggee = null;
+  gSearchBox = null;
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-filter-02.js
@@ -0,0 +1,417 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure that the property view correctly filters nodes by value.
+ */
+
+const TAB_URL = EXAMPLE_URL + "browser_dbg_with-frame.html";
+
+var gPane = null;
+var gTab = null;
+var gDebugger = null;
+var gDebuggee = null;
+var gSearchBox = null;
+
+requestLongerTimeout(2);
+
+function test()
+{
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gPane = aPane;
+    gDebugger = gPane.contentWindow;
+    gDebuggee = aDebuggee;
+
+    testSearchbox();
+    prepareVariables(testVariablesFiltering);
+  });
+}
+
+function testSearchbox()
+{
+  ok(!gDebugger.DebuggerView.Variables._searchboxNode,
+    "There should not initially be a searchbox available in the variables view.");
+  ok(!gDebugger.DebuggerView.Variables._parent.querySelector(".devtools-searchinput"),
+    "There searchbox element should not be found.");
+
+  gDebugger.DebuggerView.Variables.enableSearch();
+  ok(gDebugger.DebuggerView.Variables._searchboxNode,
+    "There should be a searchbox available after enabling.");
+  ok(gDebugger.DebuggerView.Variables._parent.querySelector(".devtools-searchinput"),
+    "There searchbox element should be found.");
+}
+
+function testVariablesFiltering()
+{
+  function test1()
+  {
+    write("htmldocument");
+
+    is(innerScopeItem.expanded, true,
+      "The innerScope expanded getter should return true");
+    is(mathScopeItem.expanded, true,
+      "The mathScope expanded getter should return true");
+    is(testScopeItem.expanded, true,
+      "The testScope expanded getter should return true");
+    is(loadScopeItem.expanded, true,
+      "The loadScope expanded getter should return true");
+    is(globalScopeItem.expanded, true,
+      "The globalScope expanded getter should return true");
+
+    is(thisItem.expanded, true,
+      "The local scope 'this' should be expanded");
+    is(windowItem.expanded, true,
+      "The local scope 'this.window' should be expanded");
+    is(documentItem.expanded, true,
+      "The local scope 'this.window.document' should be expanded");
+    is(locationItem.expanded, true,
+      "The local scope 'this.window.document.location' should be expanded");
+
+    is(innerScope.querySelectorAll(".variable:not([non-match])").length, 1,
+      "There should be 1 variable displayed in the inner scope");
+    is(mathScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the math scope");
+    is(testScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the test scope");
+    is(loadScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the load scope");
+    is(globalScope.querySelectorAll(".variable:not([non-match])").length, 2,
+      "There should be 2 variables displayed in the global scope");
+
+    is(innerScope.querySelectorAll(".property:not([non-match])").length, 8,
+      "There should be 8 properties displayed in the inner scope");
+    is(mathScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the math scope");
+    is(testScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the test scope");
+    is(loadScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the load scope");
+    is(globalScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the global scope");
+
+    is(innerScope.querySelectorAll(".variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
+      "this", "The only inner variable displayed should be 'this'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[0].getAttribute("value"),
+      "document", "The first inner property displayed should be 'document'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[1].getAttribute("value"),
+      "window", "The second inner property displayed should be 'window'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[2].getAttribute("value"),
+      "document", "The third inner property displayed should be 'document'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[3].getAttribute("value"),
+      "location", "The fourth inner property displayed should be 'location'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[4].getAttribute("value"),
+      "__proto__", "The fifth inner property displayed should be '__proto__'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[5].getAttribute("value"),
+      "__proto__", "The sixth inner property displayed should be '__proto__'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[6].getAttribute("value"),
+      "HTMLDocument", "The seventh inner property displayed should be 'HTMLDocument'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[7].getAttribute("value"),
+      "HTMLDocument", "The eight inner property displayed should be 'HTMLDocument'");
+
+    is(globalScope.querySelectorAll(".variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
+      "document", "The first global variable displayed should be 'document'");
+    is(globalScope.querySelectorAll(".variable:not([non-match]) > .title > .name")[1].getAttribute("value"),
+      "HTMLDocument", "The first global variable displayed should be 'HTMLDocument'");
+  }
+
+  function test2()
+  {
+    innerScopeItem.collapse();
+    mathScopeItem.collapse();
+    testScopeItem.collapse();
+    loadScopeItem.collapse();
+    globalScopeItem.collapse();
+    thisItem.collapse();
+    windowItem.collapse();
+    documentItem.collapse();
+    locationItem.collapse();
+
+    is(innerScopeItem.expanded, false,
+      "The innerScope expanded getter should return false");
+    is(mathScopeItem.expanded, false,
+      "The mathScope expanded getter should return false");
+    is(testScopeItem.expanded, false,
+      "The testScope expanded getter should return false");
+    is(loadScopeItem.expanded, false,
+      "The loadScope expanded getter should return false");
+    is(globalScopeItem.expanded, false,
+      "The globalScope expanded getter should return false");
+
+    is(thisItem.expanded, false,
+      "The local scope 'this' should not be expanded");
+    is(windowItem.expanded, false,
+      "The local scope 'this.window' should not be expanded");
+    is(documentItem.expanded, false,
+      "The local scope 'this.window.document' should not be expanded");
+    is(locationItem.expanded, false,
+      "The local scope 'this.window.document.location' should not be expanded");
+
+    write("htmldocument");
+
+    is(innerScope.querySelectorAll(".variable:not([non-match])").length, 1,
+      "There should be 1 variable displayed in the inner scope");
+    is(mathScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the math scope");
+    is(testScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the test scope");
+    is(loadScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the load scope");
+    is(globalScope.querySelectorAll(".variable:not([non-match])").length, 2,
+      "There should be 2 variables displayed in the global scope");
+
+    is(innerScope.querySelectorAll(".property:not([non-match])").length, 8,
+      "There should be 8 properties displayed in the inner scope");
+    is(mathScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the math scope");
+    is(testScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the test scope");
+    is(loadScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the load scope");
+    is(globalScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the global scope");
+
+    is(innerScope.querySelectorAll(".variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
+      "this", "The only inner variable displayed should be 'this'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[0].getAttribute("value"),
+      "document", "The first inner property displayed should be 'document'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[1].getAttribute("value"),
+      "window", "The second inner property displayed should be 'window'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[2].getAttribute("value"),
+      "document", "The third inner property displayed should be 'document'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[3].getAttribute("value"),
+      "location", "The fourth inner property displayed should be 'location'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[4].getAttribute("value"),
+      "__proto__", "The fifth inner property displayed should be '__proto__'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[5].getAttribute("value"),
+      "__proto__", "The sixth inner property displayed should be '__proto__'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[6].getAttribute("value"),
+      "HTMLDocument", "The seventh inner property displayed should be 'HTMLDocument'");
+    is(innerScope.querySelectorAll(".property:not([non-match]) > .title > .name")[7].getAttribute("value"),
+      "HTMLDocument", "The eight inner property displayed should be 'HTMLDocument'");
+
+    is(globalScope.querySelectorAll(".variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
+      "document", "The first global variable displayed should be 'document'");
+    is(globalScope.querySelectorAll(".variable:not([non-match]) > .title > .name")[1].getAttribute("value"),
+      "HTMLDocument", "The first global variable displayed should be 'HTMLDocument'");
+  }
+
+  var scopes = gDebugger.DebuggerView.Variables._list,
+      innerScope = scopes.querySelectorAll(".scope")[0],
+      mathScope = scopes.querySelectorAll(".scope")[1],
+      testScope = scopes.querySelectorAll(".scope")[2],
+      loadScope = scopes.querySelectorAll(".scope")[3],
+      globalScope = scopes.querySelectorAll(".scope")[4];
+
+  let innerScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+    innerScope.querySelector(".name").getAttribute("value"));
+  let mathScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+    mathScope.querySelector(".name").getAttribute("value"));
+  let testScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+    testScope.querySelector(".name").getAttribute("value"));
+  let loadScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+    loadScope.querySelector(".name").getAttribute("value"));
+  let globalScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+    globalScope.querySelector(".name").getAttribute("value"));
+
+  let thisItem = innerScopeItem.get("this");
+  let windowItem = thisItem.get("window");
+  let documentItem = windowItem.get("document");
+  let locationItem = documentItem.get("location");
+
+  gSearchBox = gDebugger.DebuggerView.Variables._searchboxNode;
+
+  executeSoon(function() {
+    test1();
+    executeSoon(function() {
+      test2();
+      executeSoon(function() {
+        closeDebuggerAndFinish();
+      });
+    });
+  });
+}
+
+function prepareVariables(aCallback)
+{
+  let count = 0;
+  gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
+    // We expect 4 Debugger:FetchedVariables events, one from the global object
+    // scope, two from the |with| scopes and the regular one.
+    if (++count < 4) {
+      info("Number of received Debugger:FetchedVariables events: " + count);
+      return;
+    }
+    gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
+    Services.tm.currentThread.dispatch({ run: function() {
+
+      var frames = gDebugger.DebuggerView.StackFrames._container._list,
+          scopes = gDebugger.DebuggerView.Variables._list,
+          innerScope = scopes.querySelectorAll(".scope")[0],
+          mathScope = scopes.querySelectorAll(".scope")[1],
+          testScope = scopes.querySelectorAll(".scope")[2],
+          loadScope = scopes.querySelectorAll(".scope")[3],
+          globalScope = scopes.querySelectorAll(".scope")[4];
+
+      let innerScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+        innerScope.querySelector(".name").getAttribute("value"));
+      let mathScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+        mathScope.querySelector(".name").getAttribute("value"));
+      let testScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+        testScope.querySelector(".name").getAttribute("value"));
+      let loadScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+        loadScope.querySelector(".name").getAttribute("value"));
+      let globalScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+        globalScope.querySelector(".name").getAttribute("value"));
+
+      is(innerScopeItem.expanded, true,
+        "The innerScope expanded getter should return true");
+      is(mathScopeItem.expanded, false,
+        "The mathScope expanded getter should return false");
+      is(testScopeItem.expanded, false,
+        "The testScope expanded getter should return false");
+      is(loadScopeItem.expanded, false,
+        "The loadScope expanded getter should return false");
+      is(globalScopeItem.expanded, false,
+        "The globalScope expanded getter should return false");
+
+      EventUtils.sendMouseEvent({ type: "mousedown" }, mathScope.querySelector(".arrow"), gDebuggee);
+      EventUtils.sendMouseEvent({ type: "mousedown" }, testScope.querySelector(".arrow"), gDebuggee);
+      EventUtils.sendMouseEvent({ type: "mousedown" }, loadScope.querySelector(".arrow"), gDebuggee);
+      EventUtils.sendMouseEvent({ type: "mousedown" }, globalScope.querySelector(".arrow"), gDebuggee);
+
+      is(innerScopeItem.expanded, true,
+        "The innerScope expanded getter should return true");
+      is(mathScopeItem.expanded, true,
+        "The mathScope expanded getter should return true");
+      is(testScopeItem.expanded, true,
+        "The testScope expanded getter should return true");
+      is(loadScopeItem.expanded, true,
+        "The loadScope expanded getter should return true");
+      is(globalScopeItem.expanded, true,
+        "The globalScope expanded getter should return true");
+
+
+      let thisItem = innerScopeItem.get("this");
+      is(thisItem.expanded, false,
+        "The local scope 'this' should not be expanded yet");
+
+      gDebugger.addEventListener("Debugger:FetchedProperties", function test2() {
+        gDebugger.removeEventListener("Debugger:FetchedProperties", test2, false);
+        Services.tm.currentThread.dispatch({ run: function() {
+
+          let windowItem = thisItem.get("window");
+          is(windowItem.expanded, false,
+            "The local scope 'this.window' should not be expanded yet");
+
+          gDebugger.addEventListener("Debugger:FetchedProperties", function test3() {
+            gDebugger.removeEventListener("Debugger:FetchedProperties", test3, false);
+            Services.tm.currentThread.dispatch({ run: function() {
+
+              let documentItem = windowItem.get("document");
+              is(documentItem.expanded, false,
+                "The local scope 'this.window.document' should not be expanded yet");
+
+              gDebugger.addEventListener("Debugger:FetchedProperties", function test4() {
+                gDebugger.removeEventListener("Debugger:FetchedProperties", test4, false);
+                Services.tm.currentThread.dispatch({ run: function() {
+
+                  let locationItem = documentItem.get("location");
+                  is(locationItem.expanded, false,
+                    "The local scope 'this.window.document.location' should not be expanded yet");
+
+                  gDebugger.addEventListener("Debugger:FetchedProperties", function test5() {
+                    gDebugger.removeEventListener("Debugger:FetchedProperties", test5, false);
+                    Services.tm.currentThread.dispatch({ run: function() {
+
+                      is(thisItem.expanded, true,
+                        "The local scope 'this' should be expanded");
+                      is(windowItem.expanded, true,
+                        "The local scope 'this.window' should be expanded");
+                      is(documentItem.expanded, true,
+                        "The local scope 'this.window.document' should be expanded");
+                      is(locationItem.expanded, true,
+                        "The local scope 'this.window.document.location' should be expanded");
+
+                      executeSoon(function() {
+                        aCallback();
+                      });
+                    }}, 0);
+                  }, false);
+
+                  executeSoon(function() {
+                    EventUtils.sendMouseEvent({ type: "mousedown" },
+                      locationItem.target.querySelector(".arrow"),
+                      gDebuggee.window);
+
+                    is(locationItem.expanded, true,
+                      "The local scope 'this.window.document.location' should be expanded now");
+                  });
+                }}, 0);
+              }, false);
+
+              executeSoon(function() {
+                EventUtils.sendMouseEvent({ type: "mousedown" },
+                  documentItem.target.querySelector(".arrow"),
+                  gDebuggee.window);
+
+                is(documentItem.expanded, true,
+                  "The local scope 'this.window.document' should be expanded now");
+              });
+            }}, 0);
+          }, false);
+
+          executeSoon(function() {
+            EventUtils.sendMouseEvent({ type: "mousedown" },
+              windowItem.target.querySelector(".arrow"),
+              gDebuggee.window);
+
+            is(windowItem.expanded, true,
+              "The local scope 'this.window' should be expanded now");
+          });
+        }}, 0);
+      }, false);
+
+      executeSoon(function() {
+        EventUtils.sendMouseEvent({ type: "mousedown" },
+          thisItem.target.querySelector(".arrow"),
+          gDebuggee.window);
+
+        is(thisItem.expanded, true,
+          "The local scope 'this' should be expanded now");
+      });
+    }}, 0);
+  }, false);
+
+  EventUtils.sendMouseEvent({ type: "click" },
+    gDebuggee.document.querySelector("button"),
+    gDebuggee.window);
+}
+
+function clear() {
+  gSearchBox.focus();
+  gSearchBox.value = "";
+}
+
+function write(text) {
+  clear();
+  append(text);
+}
+
+function append(text) {
+  gSearchBox.focus();
+
+  for (let i = 0; i < text.length; i++) {
+    EventUtils.sendChar(text[i]);
+  }
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebugger = null;
+  gDebuggee = null;
+  gSearchBox = null;
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-filter-03.js
@@ -0,0 +1,93 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure that the property view filter prefs work properly.
+ */
+
+const TAB_URL = EXAMPLE_URL + "browser_dbg_with-frame.html";
+
+var gPane = null;
+var gTab = null;
+var gDebugger = null;
+var gDebuggee = null;
+var gPrevPref = null;
+
+function test()
+{
+  gPrevPref = Services.prefs.getBoolPref(
+    "devtools.debugger.ui.variables-searchbox-visible");
+  Services.prefs.setBoolPref(
+    "devtools.debugger.ui.variables-searchbox-visible", false);
+
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gPane = aPane;
+    gDebugger = gPane.contentWindow;
+    gDebuggee = aDebuggee;
+
+    testSearchbox();
+    testPref();
+  });
+}
+
+function testSearchbox()
+{
+  ok(!gDebugger.DebuggerView.Variables._searchboxNode,
+    "There should not initially be a searchbox available in the variables view.");
+  ok(!gDebugger.DebuggerView.Variables._parent.querySelector(".devtools-searchinput"),
+    "There searchbox element should not be found.");
+}
+
+function testPref()
+{
+  is(gDebugger.Prefs.variablesSearchboxVisible, false,
+    "The debugger searchbox should be preffed as hidden.");
+  isnot(gDebugger.DebuggerView.Options._showVariablesSearchboxItem.getAttribute("checked"), "true",
+    "The options menu item should not be checked.");
+
+  gDebugger.DebuggerView.Options._showVariablesSearchboxItem.setAttribute("checked", "true");
+  gDebugger.DebuggerView.Options._toggleShowVariablesSearchbox();
+
+  executeSoon(function() {
+    ok(gDebugger.DebuggerView.Variables._searchboxNode,
+      "There should be a searchbox available in the variables view.");
+    ok(gDebugger.DebuggerView.Variables._parent.querySelector(".devtools-searchinput"),
+      "There searchbox element should be found.");
+    is(gDebugger.Prefs.variablesSearchboxVisible, true,
+      "The debugger searchbox should now be preffed as visible.");
+    is(gDebugger.DebuggerView.Options._showVariablesSearchboxItem.getAttribute("checked"), "true",
+      "The options menu item should now be checked.");
+
+    gDebugger.DebuggerView.Options._showVariablesSearchboxItem.setAttribute("checked", "false");
+    gDebugger.DebuggerView.Options._toggleShowVariablesSearchbox();
+
+    executeSoon(function() {
+      ok(!gDebugger.DebuggerView.Variables._searchboxNode,
+        "There should not be a searchbox available in the variables view.");
+      ok(!gDebugger.DebuggerView.Variables._parent.querySelector(".devtools-searchinput"),
+        "There searchbox element should not be found.");
+      is(gDebugger.Prefs.variablesSearchboxVisible, false,
+        "The debugger searchbox should now be preffed as hidden.");
+      isnot(gDebugger.DebuggerView.Options._showVariablesSearchboxItem.getAttribute("checked"), "true",
+        "The options menu item should now be unchecked.");
+
+      executeSoon(function() {
+        Services.prefs.setBoolPref(
+          "devtools.debugger.ui.variables-searchbox-visible", gPrevPref);
+
+        closeDebuggerAndFinish();
+      });
+    });
+  });
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebugger = null;
+  gDebuggee = null;
+  gPrevPref = null;
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-filter-04.js
@@ -0,0 +1,93 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure that the property view filter prefs work properly.
+ */
+
+const TAB_URL = EXAMPLE_URL + "browser_dbg_with-frame.html";
+
+var gPane = null;
+var gTab = null;
+var gDebugger = null;
+var gDebuggee = null;
+var gPrevPref = null;
+
+function test()
+{
+  gPrevPref = Services.prefs.getBoolPref(
+    "devtools.debugger.ui.variables-searchbox-visible");
+  Services.prefs.setBoolPref(
+    "devtools.debugger.ui.variables-searchbox-visible", true);
+
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gPane = aPane;
+    gDebugger = gPane.contentWindow;
+    gDebuggee = aDebuggee;
+
+    testSearchbox();
+    testPref();
+  });
+}
+
+function testSearchbox()
+{
+  ok(gDebugger.DebuggerView.Variables._searchboxNode,
+    "There should initially be a searchbox available in the variables view.");
+  ok(gDebugger.DebuggerView.Variables._parent.querySelector(".devtools-searchinput"),
+    "There searchbox element should be found.");
+}
+
+function testPref()
+{
+  is(gDebugger.Prefs.variablesSearchboxVisible, true,
+    "The debugger searchbox should be preffed as visible.");
+  is(gDebugger.DebuggerView.Options._showVariablesSearchboxItem.getAttribute("checked"), "true",
+    "The options menu item should be checked.");
+
+  gDebugger.DebuggerView.Options._showVariablesSearchboxItem.setAttribute("checked", "false");
+  gDebugger.DebuggerView.Options._toggleShowVariablesSearchbox();
+
+  executeSoon(function() {
+    ok(!gDebugger.DebuggerView.Variables._searchboxNode,
+      "There should not be a searchbox available in the variables view.");
+    ok(!gDebugger.DebuggerView.Variables._parent.querySelector(".devtools-searchinput"),
+      "There searchbox element should not be found.");
+    is(gDebugger.Prefs.variablesSearchboxVisible, false,
+      "The debugger searchbox should now be preffed as hidden.");
+    isnot(gDebugger.DebuggerView.Options._showVariablesSearchboxItem.getAttribute("checked"), "true",
+      "The options menu item should now be unchecked.");
+
+    gDebugger.DebuggerView.Options._showVariablesSearchboxItem.setAttribute("checked", "true");
+    gDebugger.DebuggerView.Options._toggleShowVariablesSearchbox();
+
+    executeSoon(function() {
+      ok(gDebugger.DebuggerView.Variables._searchboxNode,
+        "There should be a searchbox available in the variables view.");
+      ok(gDebugger.DebuggerView.Variables._parent.querySelector(".devtools-searchinput"),
+        "There searchbox element should be found.");
+      is(gDebugger.Prefs.variablesSearchboxVisible, true,
+        "The debugger searchbox should now be preffed as visible.");
+      is(gDebugger.DebuggerView.Options._showVariablesSearchboxItem.getAttribute("checked"), "true",
+        "The options menu item should now be checked.");
+
+      executeSoon(function() {
+        Services.prefs.setBoolPref(
+          "devtools.debugger.ui.variables-searchbox-visible", gPrevPref);
+
+        closeDebuggerAndFinish();
+      });
+    });
+  });
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebugger = null;
+  gDebuggee = null;
+  gPrevPref = null;
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-filter-05.js
@@ -0,0 +1,303 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure that the property view correctly filters nodes by value.
+ */
+
+const TAB_URL = EXAMPLE_URL + "browser_dbg_with-frame.html";
+
+var gPane = null;
+var gTab = null;
+var gDebugger = null;
+var gDebuggee = null;
+var gSearchBox = null;
+
+function test()
+{
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gPane = aPane;
+    gDebugger = gPane.contentWindow;
+    gDebuggee = aDebuggee;
+
+    prepareVariables(testVariablesFiltering);
+  });
+}
+
+function testVariablesFiltering()
+{
+  function test1()
+  {
+    write("*one");
+    ignoreExtraMatchedProperties();
+
+    is(innerScope.querySelectorAll(".variable:not([non-match])").length, 1,
+      "There should be 1 variable displayed in the inner scope");
+    is(mathScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the math scope");
+    is(testScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the test scope");
+    is(loadScope.querySelectorAll(".variable:not([non-match])").length, 1,
+      "There should be 1 variable displayed in the load scope");
+    is(globalScope.querySelectorAll(".variable:not([non-match])").length, 3,
+      "There should be 3 variables displayed in the global scope");
+
+    is(innerScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the inner scope");
+    is(mathScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the math scope");
+    is(testScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the test scope");
+    is(loadScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the load scope");
+    is(globalScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the global scope");
+
+    is(innerScope.querySelectorAll(".variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
+      "one", "The only inner variable displayed should be 'one'");
+
+    is(loadScope.querySelectorAll(".variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
+      "button", "The only load variable displayed should be 'button'");
+
+    let oneItem = innerScopeItem.get("one");
+    is(oneItem.expanded, false,
+      "The one item in the inner scope should not be expanded");
+
+    EventUtils.sendKey("RETURN");
+    is(oneItem.expanded, true,
+      "The one item in the inner scope should now be expanded");
+  }
+
+  function test2()
+  {
+    write("*two");
+    ignoreExtraMatchedProperties();
+
+    is(innerScope.querySelectorAll(".variable:not([non-match])").length, 1,
+      "There should be 1 variable displayed in the inner scope");
+    is(mathScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the math scope");
+    is(testScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the test scope");
+    is(loadScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the load scope");
+    is(globalScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be 0 variables displayed in the global scope");
+
+    is(innerScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the inner scope");
+    is(mathScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the math scope");
+    is(testScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the test scope");
+    is(loadScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the load scope");
+    is(globalScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the global scope");
+
+    is(innerScope.querySelectorAll(".variable:not([non-match]) > .title > .name")[0].getAttribute("value"),
+      "two", "The only inner variable displayed should be 'two'");
+
+    let twoItem = innerScopeItem.get("two");
+    is(twoItem.expanded, false,
+      "The two item in the inner scope should not be expanded");
+
+    EventUtils.sendKey("RETURN");
+    is(twoItem.expanded, true,
+      "The two item in the inner scope should now be expanded");
+  }
+
+  function test3()
+  {
+    backspace(3);
+    ignoreExtraMatchedProperties();
+
+    is(gSearchBox.value, "*",
+      "Searchbox value is incorrect after 3 backspaces");
+
+    is(innerScope.querySelectorAll(".variable:not([non-match])").length, 3,
+      "There should be 3 variables displayed in the inner scope");
+    isnot(mathScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be some variables displayed in the math scope");
+    isnot(testScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be some variables displayed in the test scope");
+    isnot(loadScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be some variables displayed in the load scope");
+    isnot(globalScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be some variables displayed in the global scope");
+
+    is(innerScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the inner scope");
+    is(mathScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the math scope");
+    is(testScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the test scope");
+    is(loadScope.querySelectorAll(".property:not([non-match])").length, 1,
+      "There should be 1 property displayed in the load scope");
+    isnot(globalScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be some properties displayed in the global scope");
+  }
+
+  function test4()
+  {
+    backspace(1);
+    ignoreExtraMatchedProperties();
+
+    is(gSearchBox.value, "",
+      "Searchbox value is incorrect after 1 backspace");
+
+    is(innerScope.querySelectorAll(".variable:not([non-match])").length, 3,
+      "There should be 3 variables displayed in the inner scope");
+    isnot(mathScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be some variables displayed in the math scope");
+    isnot(testScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be some variables displayed in the test scope");
+    isnot(loadScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be some variables displayed in the load scope");
+    isnot(globalScope.querySelectorAll(".variable:not([non-match])").length, 0,
+      "There should be some variables displayed in the global scope");
+
+    is(innerScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the inner scope");
+    is(mathScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the math scope");
+    is(testScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be 0 properties displayed in the test scope");
+    is(loadScope.querySelectorAll(".property:not([non-match])").length, 1,
+      "There should be 1 property displayed in the load scope");
+    isnot(globalScope.querySelectorAll(".property:not([non-match])").length, 0,
+      "There should be some properties displayed in the global scope");
+  }
+
+  var scopes = gDebugger.DebuggerView.Variables._list,
+      innerScope = scopes.querySelectorAll(".scope")[0],
+      mathScope = scopes.querySelectorAll(".scope")[1],
+      testScope = scopes.querySelectorAll(".scope")[2],
+      loadScope = scopes.querySelectorAll(".scope")[3],
+      globalScope = scopes.querySelectorAll(".scope")[4];
+
+  let innerScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+    innerScope.querySelector(".name").getAttribute("value"));
+  let mathScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+    mathScope.querySelector(".name").getAttribute("value"));
+  let testScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+    testScope.querySelector(".name").getAttribute("value"));
+  let loadScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+    loadScope.querySelector(".name").getAttribute("value"));
+  let globalScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+    globalScope.querySelector(".name").getAttribute("value"));
+
+  gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
+
+  executeSoon(function() {
+    test1();
+    executeSoon(function() {
+      test2();
+      executeSoon(function() {
+        test3();
+        executeSoon(function() {
+          test4();
+          executeSoon(function() {
+            closeDebuggerAndFinish();
+          });
+        });
+      });
+    });
+  });
+}
+
+function prepareVariables(aCallback)
+{
+  let count = 0;
+  gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
+    // We expect 4 Debugger:FetchedVariables events, one from the global object
+    // scope, two from the |with| scopes and the regular one.
+    if (++count < 4) {
+      info("Number of received Debugger:FetchedVariables events: " + count);
+      return;
+    }
+    gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
+    Services.tm.currentThread.dispatch({ run: function() {
+
+      var frames = gDebugger.DebuggerView.StackFrames._container._list,
+          scopes = gDebugger.DebuggerView.Variables._list,
+          innerScope = scopes.querySelectorAll(".scope")[0],
+          mathScope = scopes.querySelectorAll(".scope")[1],
+          testScope = scopes.querySelectorAll(".scope")[2],
+          loadScope = scopes.querySelectorAll(".scope")[3],
+          globalScope = scopes.querySelectorAll(".scope")[4];
+
+      let innerScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+        innerScope.querySelector(".name").getAttribute("value"));
+      let mathScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+        mathScope.querySelector(".name").getAttribute("value"));
+      let testScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+        testScope.querySelector(".name").getAttribute("value"));
+      let loadScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+        loadScope.querySelector(".name").getAttribute("value"));
+      let globalScopeItem = gDebugger.DebuggerView.Variables._currHierarchy.get(
+        globalScope.querySelector(".name").getAttribute("value"));
+
+      EventUtils.sendMouseEvent({ type: "mousedown" }, mathScope.querySelector(".arrow"), gDebuggee);
+      EventUtils.sendMouseEvent({ type: "mousedown" }, testScope.querySelector(".arrow"), gDebuggee);
+      EventUtils.sendMouseEvent({ type: "mousedown" }, loadScope.querySelector(".arrow"), gDebuggee);
+      EventUtils.sendMouseEvent({ type: "mousedown" }, globalScope.querySelector(".arrow"), gDebuggee);
+
+      executeSoon(function() {
+        aCallback();
+      });
+    }}, 0);
+  }, false);
+
+  EventUtils.sendMouseEvent({ type: "click" },
+    gDebuggee.document.querySelector("button"),
+    gDebuggee.window);
+}
+
+function ignoreExtraMatchedProperties()
+{
+  for (let [_, item] of gDebugger.DebuggerView.Variables._currHierarchy) {
+    let name = item.name.toLowerCase();
+    let value = item._valueString || "";
+
+    if ((value.contains("DOM")) ||
+        (value.contains("XPC") && !name.contains("__proto__"))) {
+      item.target.setAttribute("non-match", "");
+    }
+  }
+}
+
+function clear() {
+  gSearchBox.focus();
+  gSearchBox.value = "";
+}
+
+function write(text) {
+  clear();
+  append(text);
+}
+
+function backspace(times) {
+  for (let i = 0; i < times; i++) {
+    EventUtils.sendKey("BACK_SPACE")
+  }
+}
+
+function append(text) {
+  gSearchBox.focus();
+
+  for (let i = 0; i < text.length; i++) {
+    EventUtils.sendChar(text[i]);
+  }
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebugger = null;
+  gDebuggee = null;
+  gSearchBox = null;
+});
rename from browser/devtools/debugger/VariablesView.jsm
rename to browser/devtools/shared/VariablesView.jsm
--- a/browser/devtools/debugger/VariablesView.jsm
+++ b/browser/devtools/shared/VariablesView.jsm
@@ -24,36 +24,52 @@ let EXPORTED_SYMBOLS = ["VariablesView",
  */
 function VariablesView(aParentNode) {
   this._store = new Map();
   this._prevHierarchy = new Map();
   this._currHierarchy = new Map();
   this._parent = aParentNode;
   this._appendEmptyNotice();
 
+  this._onSearchboxInput = this._onSearchboxInput.bind(this);
+  this._onSearchboxKeyPress = this._onSearchboxKeyPress.bind(this);
+
   // Create an internal list container.
   this._list = this.document.createElement("vbox");
   this._parent.appendChild(this._list);
 }
 
 VariablesView.prototype = {
   /**
+   * Helper setter for populating this container with a raw object.
+   *
+   * @param object aData
+   *        The raw object to display. You can only provide this object
+   *        if you want the variables view to work in sync mode.
+   */
+  set rawObject(aObject) {
+    this.empty();
+    this.addScope().addVar().populate(aObject);
+  },
+
+  /**
    * Adds a scope to contain any inspected variables.
    *
    * @param string aName
    *        The scope's name (e.g. "Local", "Global" etc.).
    * @return Scope
    *         The newly created Scope instance.
    */
-  addScope: function VV_addScope(aName) {
+  addScope: function VV_addScope(aName = "") {
     this._removeEmptyNotice();
 
     let scope = new Scope(this, aName);
     this._store.set(scope.id, scope);
     this._currHierarchy.set(aName, scope);
+    scope.header = !!aName;
     return scope;
   },
 
   /**
    * Removes all items from this container.
    *
    * @param number aTimeout [optional]
    *        The number of milliseconds to delay the operation if
@@ -136,16 +152,135 @@ VariablesView.prototype = {
     this._nonEnumVisible = aFlag;
 
     for (let [_, scope] in this) {
       scope._nonEnumVisible = aFlag;
     }
   },
 
   /**
+   * Enables variable and property searching in this view.
+   */
+  enableSearch: function VV_enableSearch() {
+    // If searching was already enabled, no need to re-enable it again.
+    if (this._searchboxContainer) {
+      return;
+    }
+    let document = this.document;
+    let parent = this._parent;
+
+    let container = this._searchboxContainer = document.createElement("hbox");
+    container.className = "devtools-toolbar";
+
+    let searchbox = this._searchboxNode = document.createElement("textbox");
+    searchbox.className = "devtools-searchinput";
+    searchbox.setAttribute("placeholder", this._searchboxPlaceholder);
+    searchbox.setAttribute("type", "search");
+    searchbox.setAttribute("flex", "1");
+    searchbox.addEventListener("input", this._onSearchboxInput, false);
+    searchbox.addEventListener("keypress", this._onSearchboxKeyPress, false);
+
+    container.appendChild(searchbox);
+    parent.insertBefore(container, parent.firstChild);
+  },
+
+  /**
+   * Disables variable and property searching in this view.
+   */
+  disableSearch: function VV_disableSearch() {
+    // If searching was already disabled, no need to re-disable it again.
+    if (!this._searchboxContainer) {
+      return;
+    }
+    this._parent.removeChild(this._searchboxContainer);
+    this._searchboxNode.addEventListener("input", this._onSearchboxInput, false);
+    this._searchboxNode.addEventListener("keypress", this._onSearchboxKeyPress, false);
+
+    this._searchboxContainer = null;
+    this._searchboxNode = null;
+  },
+
+  /**
+   * Sets if the variable and property searching is enabled.
+   */
+  set searchEnabled(aFlag) aFlag ? this.enableSearch() : this.disableSearch(),
+
+  /**
+   * Gets if the variable and property searching is enabled.
+   */
+  get searchEnabled() !!this._searchboxContainer,
+
+  /**
+   * Performs a case insensitive search for variables or properties matching
+   * the query, and hides non-matched items.
+   *
+   * @param string aQuery
+   *        The variable or property to search for.
+   */
+  performSearch: function VV_performSerch(aQuery) {
+    if (!aQuery) {
+      for (let [_, item] of this._currHierarchy) {
+        item._match = true;
+      }
+    } else {
+      for (let [_, scope] in this) {
+        scope._performSearch(aQuery.toLowerCase());
+      }
+    }
+  },
+
+  /**
+   * Expands the first search results in this container.
+   */
+  expandFirstSearchResults: function VV_expandFirstSearchResults() {
+    for (let [_, scope] in this) {
+      for (let [_, variable] in scope) {
+        if (variable._isMatch) {
+          variable.expand();
+          break;
+        }
+      }
+    }
+  },
+
+  /**
+   * Sets the text displayed for the searchbox in this container.
+   * @param string aValue
+   */
+  set searchPlaceholder(aValue) {
+    if (this._searchboxNode) {
+      this._searchboxNode.setAttribute("placeholder", aValue);
+    }
+    this._searchboxPlaceholder = aValue;
+  },
+
+  /**
+   * Listener handling the searchbox input event.
+   */
+  _onSearchboxInput: function VV__onSearchboxInput() {
+    this.performSearch(this._searchboxNode.value);
+  },
+
+  /**
+   * Listener handling the searchbox key press event.
+   */
+  _onSearchboxKeyPress: function VV__onSearchboxKeyPress(e) {
+    switch(e.keyCode) {
+      case e.DOM_VK_RETURN:
+      case e.DOM_VK_ENTER:
+        this._onSearchboxInput();
+        return;
+      case e.DOM_VK_ESCAPE:
+        this._searchboxNode.value = "";
+        this._onSearchboxInput();
+        return;
+    }
+  },
+
+  /**
    * Sets the text displayed in this container when there are no available items.
    * @param string aValue
    */
   set emptyText(aValue) {
     if (this._emptyTextNode) {
       this._emptyTextNode.setAttribute("value", aValue);
     }
     this._emptyTextValue = aValue;
@@ -200,18 +335,21 @@ VariablesView.prototype = {
   eval: null,
   lazyEmpty: false,
   _store: null,
   _prevHierarchy: null,
   _currHierarchy: null,
   _emptyTimeout: null,
   _enumVisible: true,
   _nonEnumVisible: true,
+  _parent: null,
   _list: null,
-  _parent: null,
+  _searchboxNode: null,
+  _searchboxContainer: null,
+  _searchboxPlaceholder: "",
   _emptyTextNode: null,
   _emptyTextValue: ""
 };
 
 /**
  * A Scope is an object holding Variable instances.
  * Iterable via "for (let [name, variable] in instance) { }".
  *
@@ -252,24 +390,25 @@ Scope.prototype = {
    *             - { value: { type: "undefined" } }
    *             - { value: { type: "null" } }
    *             - { value: { type: "object", class: "Object" } }
    *             - { get: { type: "object", class: "Function" },
    *                 set: { type: "undefined" } }
    * @return Variable
    *         The newly created Variable instance, null if it already exists.
    */
-  addVar: function S_addVar(aName, aDescriptor = {}) {
+  addVar: function S_addVar(aName = "", aDescriptor = {}) {
     if (this._store.has(aName)) {
       return null;
     }
 
     let variable = new Variable(this, aName, aDescriptor);
     this._store.set(aName, variable);
     this._variablesView._currHierarchy.set(variable._absoluteName, variable);
+    variable.header = !!aName;
     return variable;
   },
 
   /**
    * Gets the variable in this container having the specified name.
    *
    * @return Variable
    *         The matched variable, or null if nothing is found.
@@ -304,17 +443,17 @@ Scope.prototype = {
 
   /**
    * Expands the scope, showing all the added details.
    *
    * @param boolean aSkipAnimationFlag
    *        Pass true to not show an opening animation.
    */
   expand: function S_expand(aSkipAnimationFlag) {
-    if (this._locked) {
+    if (this._isExpanded || this._locked) {
       return;
     }
     if (this._variablesView._enumVisible) {
       this._arrow.setAttribute("open", "");
       this._enum.setAttribute("open", "");
     }
     if (this._variablesView._nonEnumVisible) {
       this._nonenum.setAttribute("open", "");
@@ -329,17 +468,17 @@ Scope.prototype = {
       this.onexpand(this);
     }
   },
 
   /**
    * Collapses the scope, hiding all the added details.
    */
   collapse: function S_collapse() {
-    if (this._locked) {
+    if (!this._isExpanded || this._locked) {
       return;
     }
     this._arrow.removeAttribute("open");
     this._enum.removeAttribute("open");
     this._nonenum.removeAttribute("open");
     this._enum.removeAttribute("animated");
     this._nonenum.removeAttribute("animated");
     this._isExpanded = false;
@@ -348,24 +487,43 @@ Scope.prototype = {
       this.oncollapse(this);
     }
   },
 
   /**
    * Toggles between the scope's collapsed and expanded state.
    */
   toggle: function S_toggle() {
+    this._wasToggled = true;
     this.expanded ^= 1;
 
     if (this.ontoggle) {
       this.ontoggle(this);
     }
   },
 
   /**
+   * Shows the scope's title header.
+   */
+  showHeader: function S_showHeader() {
+    this._target.removeAttribute("non-header");
+    this._isHeaderVisible = true;
+  },
+
+  /**
+   * Hides the scope's title header.
+   * This action will automatically expand the scope.
+   */
+  hideHeader: function S_hideHeader() {
+    this.expand();
+    this._target.setAttribute("non-header", "");
+    this._isHeaderVisible = false;
+  },
+
+  /**
    * Shows the scope's expand/collapse arrow.
    */
   showArrow: function S_showArrow() {
     this._arrow.removeAttribute("invisible");
     this._isArrowVisible = true;
   },
 
   /**
@@ -384,16 +542,22 @@ Scope.prototype = {
 
   /**
    * Gets the expanded state.
    * @return boolean
    */
   get expanded() this._isExpanded,
 
   /**
+   * Gets the header visibility state.
+   * @return boolean
+   */
+  get header() this._isHeaderVisible,
+
+  /**
    * Gets the twisty visibility state.
    * @return boolean
    */
   get twisty() this._isArrowVisible,
 
   /**
    * Sets the visibility state.
    * @param boolean aFlag
@@ -402,16 +566,22 @@ Scope.prototype = {
 
   /**
    * Sets the expanded state.
    * @param boolean aFlag
    */
   set expanded(aFlag) aFlag ? this.expand() : this.collapse(),
 
   /**
+   * Sets the header visibility state.
+   * @param boolean aFlag
+   */
+  set header(aFlag) aFlag ? this.showHeader() : this.hideHeader(),
+
+  /**
    * Sets the twisty visibility state.
    * @param boolean aFlag
    */
   set twisty(aFlag) aFlag ? this.showArrow() : this.hideArrow(),
 
   /**
    * Gets the id associated with this item.
    * @return string
@@ -527,16 +697,85 @@ Scope.prototype = {
         this._nonenum.setAttribute("open", "");
       } else {
         this._nonenum.removeAttribute("open");
       }
     }
   },
 
   /**
+   * Performs a case insensitive search for variables or properties matching
+   * the query, and hides non-matched items.
+   *
+   * @param string aLowerCaseQuery
+   *        The lowercased name of the variable or property to search for.
+   */
+  _performSearch: function S__performSearch(aLowerCaseQuery) {
+    for (let [_, variable] in this) {
+      let currentObject = variable;
+      let lowerCaseName = variable._nameString.toLowerCase();
+      let lowerCaseValue = variable._valueString.toLowerCase();
+
+      // Non-matched variables or properties require a corresponding attribute.
+      if (!lowerCaseName.contains(aLowerCaseQuery) &&
+          !lowerCaseValue.contains(aLowerCaseQuery)) {
+        variable._match = false;
+      }
+      // Variable or property is matched.
+      else {
+        variable._match = true;
+
+        // If the variable was ever expanded, there's a possibility it may
+        // contain some matched properties, so make sure they're visible
+        // ("expand downwards").
+
+        if (variable._wasToggled) {
+          variable.expand(true);
+        }
+
+        // If the variable is contained in another scope (variable or property),
+        // the parent may not be a match, thus hidden. It should be visible
+        // ("expand upwards").
+
+        while ((variable = variable.ownerView) &&  /* Parent object exists. */
+               (variable instanceof Scope ||
+                variable instanceof Variable ||
+                variable instanceof Property)) {
+
+          // Show and expand the parent, as it is certainly accessible.
+          variable._match = true;
+          variable.expand(true);
+        }
+      }
+
+      // Proceed with the search recursively inside this variable or property.
+      if (variable._wasToggled || variable.expanded || variable.getter || variable.setter) {
+        currentObject._performSearch(aLowerCaseQuery);
+      }
+    }
+  },
+
+  /**
+   * Sets if this object instance is a match or non-match.
+   * @param boolean aStatus
+   */
+  set _match(aStatus) {
+    if (this._isMatch == aStatus) {
+      return;
+    }
+    if (aStatus) {
+      this._isMatch = true;
+      this.target.removeAttribute("non-match");
+    } else {
+      this._isMatch = false;
+      this.target.setAttribute("non-match", "");
+    }
+  },
+
+  /**
    * Gets top level variables view instance.
    * @return VariablesView
    */
   get _variablesView() {
     let parentView = this.ownerView;
     let topView;
 
     while (topView = parentView.ownerView) {
@@ -560,24 +799,28 @@ Scope.prototype = {
   /**
    * Gets the default window holding this scope.
    * @return nsIDOMWindow
    */
   get window() this.ownerView.window,
 
   ownerView: null,
   eval: null,
+  fetched: false,
   _committed: false,
   _locked: false,
   _isShown: true,
   _isExpanded: false,
+  _wasToggled: false,
+  _isHeaderVisible: true,
   _isArrowVisible: true,
+  _isMatch: true,
   _store: null,
-  _idString: null,
-  _nameString: null,
+  _idString: "",
+  _nameString: "",
   _target: null,
   _arrow: null,
   _name: null,
   _title: null,
   _enum: null,
   _nonenum: null
 };
 
@@ -621,24 +864,25 @@ create({ constructor: Variable, proto: S
    *             - { value: { type: "undefined" } }
    *             - { value: { type: "null" } }
    *             - { value: { type: "object", class: "Object" } }
    *             - { get: { type: "object", class: "Function" },
    *                 set: { type: "undefined" } }
    * @return Property
    *         The newly created Property instance, null if it already exists.
    */
-  addProperty: function V_addProperty(aName, aDescriptor = {}) {
+  addProperty: function V_addProperty(aName = "", aDescriptor = {}) {
     if (this._store.has(aName)) {
       return null;
     }
 
     let property = new Property(this, aName, aDescriptor);
     this._store.set(aName, property);
     this._variablesView._currHierarchy.set(property._absoluteName, property);
+    property.header = !!aName;
     return property;
   },
 
   /**
    * Adds properties for this variable.
    *
    * @param object aProperties
    *        An object containing some { name: descriptor } data properties,
@@ -659,16 +903,108 @@ create({ constructor: Variable, proto: S
     let sortedPropertyNames = Object.keys(aProperties).sort();
 
     for (let name of sortedPropertyNames) {
       this.addProperty(name, aProperties[name]);
     }
   },
 
   /**
+   * Populates this variable to contain all the properties of an object.
+   *
+   * @param object aObject
+   *        The raw object you want to display.
+   */
+  populate: function V_populate(aObject) {
+    // Retrieve the properties only once.
+    if (this.fetched) {
+      return;
+    }
+
+    // Sort all of the properties before adding them.
+    let sortedPropertyNames = Object.getOwnPropertyNames(aObject).sort();
+    let prototype = Object.getPrototypeOf(aObject);
+
+    // Add all the variable properties.
+    for (let name of sortedPropertyNames) {
+      let descriptor = Object.getOwnPropertyDescriptor(aObject, name);
+      if (descriptor.get || descriptor.set) {
+        this._addRawNonValueProperty(name, descriptor);
+      } else {
+        this._addRawValueProperty(name, descriptor, aObject[name]);
+      }
+    }
+    // Add the variable's __proto__.
+    if (prototype) {
+      this._addRawValueProperty("__proto__", {}, prototype);
+    }
+
+    this.fetched = true;
+  },
+
+  /**
+   * Adds a property for this variable based on a raw value descriptor.
+   *
+   * @param string aName
+   *        The property's name.
+   * @param object aDescriptor
+   *        Specifies the exact property descriptor as returned by a call to
+   *        Object.getOwnPropertyDescriptor.
+   * @param object aValue
+   *        The raw property value you want to display.
+   */
+  _addRawValueProperty: function V__addRawValueProperty(aName, aDescriptor, aValue) {
+    let descriptor = Object.create(aDescriptor);
+    descriptor.value = VariablesView.getGrip(aValue);
+
+    let propertyItem = this.addProperty(aName, descriptor);
+
+    // Add an 'onexpand' callback for the property, lazily handling
+    // the addition of new child properties.
+    if (!VariablesView.isPrimitive(descriptor)) {
+      propertyItem.onexpand = this.populate.bind(propertyItem, aValue);
+    }
+
+    return propertyItem;
+  },
+
+  /**
+   * Adds a property for this variable based on a getter/setter descriptor.
+   *
+   * @param string aName
+   *        The property's name.
+   * @param object aDescriptor
+   *        Specifies the exact property descriptor as returned by a call to
+   *        Object.getOwnPropertyDescriptor.
+   */
+  _addRawNonValueProperty: function V__addRawNonValueProperty(aName, aDescriptor) {
+    let descriptor = Object.create(aDescriptor);
+    descriptor.get = VariablesView.getGrip(aDescriptor.get);
+    descriptor.set = VariablesView.getGrip(aDescriptor.set);
+
+    let propertyItem = this.addProperty(aName, descriptor);
+    return propertyItem;
+  },
+
+  /**
+   * Returns this variable's value from the descriptor if available,
+   */
+  get value() this._initialDescriptor.value,
+
+  /**
+   * Returns this variable's getter from the descriptor if available,
+   */
+  get getter() this._initialDescriptor.get,
+
+  /**
+   * Returns this variable's getter from the descriptor if available,
+   */
+  get setter() this._initialDescriptor.set,
+
+  /**
    * Sets the specific grip for this variable.
    * The grip should contain the value or the type & class, as defined in the
    * remote debugger protocol. For convenience, undefined and null are
    * both considered types.
    *
    * @param any aGrip
    *        Specifies the value and/or type & class of the variable.
    *        e.g. - 42
@@ -749,18 +1085,18 @@ create({ constructor: Variable, proto: S
 
     this._title.appendChild(separatorLabel);
     this._title.appendChild(valueLabel);
 
     if (VariablesView.isPrimitive(aDescriptor)) {
       this.hideArrow();
     }
     if (aDescriptor.get || aDescriptor.set) {
-      this.addProperty("get ", { value: aDescriptor.get });
-      this.addProperty("set ", { value: aDescriptor.set });
+      this.addProperty("get", { value: aDescriptor.get });
+      this.addProperty("set", { value: aDescriptor.set });
       this.expand(true);
       separatorLabel.hidden = true;
       valueLabel.hidden = true;
     }
   },
 
   /**
    * Creates a tooltip for this variable.
@@ -1088,16 +1424,41 @@ VariablesView.isPrimitive = function VV_
   if (["undefined", "null"].indexOf(type + "") != -1) {
     return true;
   }
 
   return false;
 };
 
 /**
+ * Returns a standard grip for a value.
+ *
+ * @param any aValue
+ *        The raw value to get a grip for.
+ * @return any
+ *         The value's grip.
+ */
+VariablesView.getGrip = function VV_getGrip(aValue) {
+  if (aValue === undefined) {
+    return { type: "undefined" };
+  }
+  if (aValue === null) {
+    return { type: "null" };
+  }
+  if (typeof aValue == "object" || typeof aValue == "function") {
+    if (aValue.constructor) {
+      return { type: "object", class: aValue.constructor.name };
+    } else {
+      return { type: "object", class: "Object" };
+    }
+  }
+  return aValue;
+};
+
+/**
  * Returns a custom formatted property string for a grip.
  *
  * @param any aGrip
  *        @see Variable._setGrip
  * @param boolean aConciseFlag
  *        Return a concisely formatted property string.
  * @return string
  *         The formatted property string.
--- a/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
@@ -44,16 +44,21 @@
 <!ENTITY debuggerUI.pauseExceptions     "Pause on exceptions">
 <!ENTITY debuggerUI.pauseExceptions.key "E">
 
 <!-- LOCALIZATION NOTE (debuggerUI.showPanesOnInit): This is the label for the
   -  checkbox that toggles visibility of panes when opening the debugger. -->
 <!ENTITY debuggerUI.showPanesOnInit     "Show panes on startup">
 <!ENTITY debuggerUI.showPanesOnInit.key "S">
 
+<!-- LOCALIZATION NOTE (debuggerUI.showVarsSearch): This is the label for the
+  -  checkbox that toggles visibility of a designated variables searchbox. -->
+<!ENTITY debuggerUI.showVarsSearch      "Show variables searchbox">
+<!ENTITY debuggerUI.showVarsSearch.key  "V">
+
 <!-- LOCALIZATION NOTE (debuggerUI.showNonEnums): This is the label for the
   -  checkbox that toggles visibility of hidden (non-enumerable) variables and
   -  properties in stack views. -->
 <!ENTITY debuggerUI.showNonEnums        "Show hidden properties">
 <!ENTITY debuggerUI.showNonEnums.key    "P">
 
 <!-- LOCALIZATION NOTE (debuggerUI.searchPanelTitle): This is the text that
   -  appears in the filter panel popup as a description. -->
--- a/browser/locales/en-US/chrome/browser/devtools/debugger.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/debugger.properties
@@ -98,32 +98,41 @@ noMatchingScriptsText=No matching script
 # LOCALIZATION NOTE (noMatchingStringsText): The text to display in the
 # global search results when there are no matching strings after filtering.
 noMatchingStringsText=No matches found
 
 # LOCALIZATION NOTE (emptyFilterText): This is the text that appears in the
 # filter text box when it is empty and the scripts container is selected.
 emptyFilterText=Filter scripts (%S)
 
-# LOCALIZATION NOTE (emptyFilterText): This is the text that appears in the
-# filter text box when it is empty and the chrome globals container is selected.
+# LOCALIZATION NOTE (emptyChromeGlobalsFilterText): This is the text that
+# appears in the filter text box when it is empty and the chrome globals
+# container is selected.
 emptyChromeGlobalsFilterText=Filter chrome globals (%S)
 
+# LOCALIZATION NOTE (emptyVariablesFilterText): This is the text that
+# appears in the filter text box for the variables view container.
+emptyVariablesFilterText=Filter variables
+
 # LOCALIZATION NOTE (searchPanelGlobal): This is the text that appears in the
 # filter panel popup for the global search operation.
 searchPanelGlobal=Search in all files (%S)
 
 # LOCALIZATION NOTE (searchPanelToken): This is the text that appears in the
 # filter panel popup for the token search operation.
 searchPanelToken=Find in this file (%S)
 
 # LOCALIZATION NOTE (searchPanelLine): This is the text that appears in the
 # filter panel popup for the line search operation.
 searchPanelLine=Jump to line (%S)
 
+# LOCALIZATION NOTE (searchPanelVariable): This is the text that appears in the
+# filter panel popup for the variables search operation.
+searchPanelVariable=Filter variables (%S)
+
 # LOCALIZATION NOTE (breakpointMenuItem): The text for all the elements that
 # are displayed in the breakpoints menu item popup.
 breakpointMenuItem.enableSelf=Enable breakpoint
 breakpointMenuItem.disableSelf=Disable breakpoint
 breakpointMenuItem.deleteSelf=Remove breakpoint
 breakpointMenuItem.enableOthers=Enable others
 breakpointMenuItem.disableOthers=Disable others
 breakpointMenuItem.deleteOthers=Remove others
--- a/browser/locales/en-US/chrome/browser/sanitize.dtd
+++ b/browser/locales/en-US/chrome/browser/sanitize.dtd
@@ -1,16 +1,15 @@
 <!-- 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/. -->
 
 <!ENTITY sanitizePrefs2.title          "Settings for Clearing History">
 <!ENTITY sanitizeDialog2.title         "Clear Recent History">
 
-<!ENTITY sanitizeItems.label          "Clear the following items now:">
 <!ENTITY clearDataSettings2.label     "When I quit &brandShortName;, it should automatically clear all:">
 
 <!-- XXX rearrange entities to match physical layout when l10n isn't an issue -->
 <!-- LOCALIZATION NOTE (clearTimeDuration.*): "Time range to clear" dropdown.
      See UI mockup at bug 480169 -->
 <!ENTITY clearTimeDuration.label          "Time range to clear: ">
 <!ENTITY clearTimeDuration.accesskey      "T">
 <!ENTITY clearTimeDuration.lastHour       "Last Hour">
--- a/browser/themes/gnomestripe/devtools/debugger.css
+++ b/browser/themes/gnomestripe/devtools/debugger.css
@@ -224,17 +224,17 @@
   color: #048;
   font-weight: 600;
 }
 
 .variable > .title > .value {
   -moz-padding-start: 6px;
 }
 
-.variable > .details {
+.variable:not([non-header]) > .details {
   -moz-margin-start: 10px;
 }
 
 /**
  * Property element
  */
 
 .property {
@@ -251,17 +251,17 @@
 .property > .title > .name {
   color: #881090;
 }
 
 .property > .title > .value {
   -moz-padding-start: 6px;
 }
 
-.property > .details {
+.property:not([non-header]) > .details {
   -moz-margin-start: 10px;
 }
 
 /**
  * Non enumerable, configurable and writable variables and properties.
  */
 
 .variable[proto] > .title > .name,
@@ -315,16 +315,30 @@
 .variable[non-configurable] > tooltip > label[value="configurable"],
 .property[non-configurable] > tooltip > label[value="configurable"],
 .variable[non-writable] > tooltip > label[value="writable"],
 .property[non-writable] > tooltip > label[value="writable"] {
   text-decoration: line-through;
 }
 
 /**
+ * Variables and properties searching
+ */
+
+#variables .devtools-searchinput {
+  min-height: 24px;
+}
+
+.variable[non-match],
+.property[non-match] {
+  border: none;
+  margin: 0;
+}
+
+/**
  * Token value colors
  */
 
 .token-undefined {
   color: #bbb;
 }
 
 .token-null {
--- a/browser/themes/pinstripe/devtools/debugger.css
+++ b/browser/themes/pinstripe/devtools/debugger.css
@@ -226,17 +226,17 @@
   color: #048;
   font-weight: 600;
 }
 
 .variable > .title > .value {
   -moz-padding-start: 6px;
 }
 
-.variable > .details {
+.variable:not([non-header]) > .details {
   -moz-margin-start: 10px;
 }
 
 /**
  * Property element
  */
 
 .property {
@@ -253,17 +253,17 @@
 .property > .title > .name {
   color: #881090;
 }
 
 .property > .title > .value {
   -moz-padding-start: 6px;
 }
 
-.property > .details {
+.property:not([non-header]) > .details {
   -moz-margin-start: 10px;
 }
 
 /**
  * Non enumerable, configurable and writable variables and properties.
  */
 
 .variable[proto] > .title > .name,
@@ -317,16 +317,30 @@
 .variable[non-configurable] > tooltip > label[value="configurable"],
 .property[non-configurable] > tooltip > label[value="configurable"],
 .variable[non-writable] > tooltip > label[value="writable"],
 .property[non-writable] > tooltip > label[value="writable"] {
   text-decoration: line-through;
 }
 
 /**
+ * Variables and properties searching
+ */
+
+#variables .devtools-searchinput {
+  min-height: 24px;
+}
+
+.variable[non-match],
+.property[non-match] {
+  border: none;
+  margin: 0;
+}
+
+/**
  * Token value colors
  */
 
 .token-undefined {
   color: #bbb;
 }
 
 .token-null {
--- a/browser/themes/winstripe/devtools/debugger.css
+++ b/browser/themes/winstripe/devtools/debugger.css
@@ -232,17 +232,17 @@
   color: #048;
   font-weight: 600;
 }
 
 .variable > .title > .value {
   -moz-padding-start: 6px;
 }
 
-.variable > .details {
+.variable:not([non-header]) > .details {
   -moz-margin-start: 10px;
 }
 
 /**
  * Property element
  */
 
 .property {
@@ -259,17 +259,17 @@
 .property > .title > .name {
   color: #881090;
 }
 
 .property > .title > .value {
   -moz-padding-start: 6px;
 }
 
-.property > .details {
+.property:not([non-header]) > .details {
   -moz-margin-start: 10px;
 }
 
 /**
  * Non enumerable, configurable and writable variables and properties.
  */
 
 .variable[proto] > .title > .name,
@@ -323,16 +323,30 @@
 .variable[non-configurable] > tooltip > label[value="configurable"],
 .property[non-configurable] > tooltip > label[value="configurable"],
 .variable[non-writable] > tooltip > label[value="writable"],
 .property[non-writable] > tooltip > label[value="writable"] {
   text-decoration: line-through;
 }
 
 /**
+ * Variables and properties searching
+ */
+
+#variables .devtools-searchinput {
+  min-height: 24px;
+}
+
+.variable[non-match],
+.property[non-match] {
+  border: none;
+  margin: 0;
+}
+
+/**
  * Token value colors
  */
 
 .token-undefined {
   color: #bbb;
 }
 
 .token-null {
--- a/build/virtualenv/packages.txt
+++ b/build/virtualenv/packages.txt
@@ -12,11 +12,12 @@ mozprofile.pth:testing/mozbase/mozprofil
 mozrunner.pth:testing/mozbase/mozrunner
 marionette.pth:testing/marionette/client
 blessings.pth:python/blessings
 mozbuild.pth:python/mozbuild
 pymake.pth:build/pymake
 optional:setup.py:python/psutil:build_ext:--inplace
 optional:psutil.pth:python/psutil
 which.pth:python/which
+mock.pth:python/mock-1.0.0
 mozilla.pth:build
 mozilla.pth:config
 copy:build/buildconfig.py
--- a/config/Preprocessor.py
+++ b/config/Preprocessor.py
@@ -377,16 +377,18 @@ class Preprocessor:
   #   Strips blank lines from the output.
   def filter_emptyLines(self, aLine):
     if aLine == '\n':
       return ''
     return aLine
   # slashslash
   #   Strips everything after //
   def filter_slashslash(self, aLine):
+    if (aLine.find('//') == -1):
+      return aLine
     [aLine, rest] = aLine.split('//', 1)
     if rest:
       aLine += '\n'
     return aLine
   # spaces
   #   Collapses sequences of spaces into a single space
   def filter_spaces(self, aLine):
     return re.sub(' +', ' ', aLine).strip(' ')
--- a/config/config.mk
+++ b/config/config.mk
@@ -347,21 +347,16 @@ endif
 
 ifdef BOTH_MANIFESTS
 MAKE_JARS_FLAGS += --both-manifests
 endif
 
 TAR_CREATE_FLAGS = -cvhf
 TAR_CREATE_FLAGS_QUIET = -chf
 
-ifeq ($(OS_ARCH),BSD_OS)
-TAR_CREATE_FLAGS = -cvLf
-TAR_CREATE_FLAGS_QUIET = -cLf
-endif
-
 ifeq ($(OS_ARCH),OS2)
 TAR_CREATE_FLAGS = -cvf
 TAR_CREATE_FLAGS_QUIET = -cf
 endif
 
 #
 # Personal makefile customizations go in these optional make include files.
 #
--- a/configure.in
+++ b/configure.in
@@ -397,17 +397,16 @@ if test -n "$MOZ_WINCONSOLE"; then
 fi
 
 MOZ_TOOL_VARIABLES
 
 dnl ========================================================
 dnl Special win32 checks
 dnl ========================================================
 
-# With win8, sdk target=602, WINVER=602
 MOZ_ARG_ENABLE_BOOL(metro,
 [  --enable-metro           Enable Windows Metro build targets],
     MOZ_METRO=1,
     MOZ_METRO=)
 if test -n "$MOZ_METRO"; then
     AC_DEFINE(MOZ_METRO)
     # Target the Windows 8 Kit
     WINSDK_TARGETVER=602
@@ -1141,19 +1140,16 @@ solaris*)
     if test -z "$GNU_CXX"; then
        if test "`$CXX -V 2>&1 | egrep -c 'Sun.*C\+\+ '`" != "0"; then
            SOLARIS_SUNPRO_CXX=1
        fi
     fi
     AC_SUBST(SOLARIS_SUNPRO_CC)
     AC_SUBST(SOLARIS_SUNPRO_CXX)
     ;;
-BSD_386)
-    HOST_OS_ARCH=BSD
-    ;;
 OS_2)
     HOST_OS_ARCH=OS2
     ;;
 esac
 
 case "$OS_ARCH" in
 WINNT)
     if test -z "$CROSS_COMPILE" ; then
@@ -1185,19 +1181,16 @@ MINGW*_NT*)
     OS_RELEASE=`expr $OS_ARCH : '.*NT-\(.*\)'`
     OS_ARCH=WINNT
     OS_TARGET=WINNT
     ;;
 AIX)
     OS_RELEASE=`uname -v`.`uname -r`
     OS_TEST=${target_cpu}
     ;;
-BSD_386)
-    OS_ARCH=BSD
-    ;;
 OS_2)
     OS_ARCH=OS2
     OS_TARGET=OS2
     OS_RELEASE=`uname -v`
     ;;
 Darwin)
     case "${target_cpu}" in
     powerpc*)
@@ -1926,35 +1919,16 @@ case "$target" in
         ;;
     esac
     if test "$COMPILE_ENVIRONMENT"; then
         MOZ_CHECK_HEADERS(sys/inttypes.h)
     fi
     AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES)
     ;;
 
-*-bsdi*)
-    dnl -pedantic doesn't play well with BSDI's _very_ modified gcc (shlicc2)
-    _PEDANTIC=
-    case $OS_RELEASE in
-	4.*|5.*)
-            STRIP="$STRIP -d"
-            ;;
-	*)
-	    DSO_CFLAGS=''
-	    DSO_LDOPTS='-r'
-	    _WARNINGS_CFLAGS="-Wall"
-	    _WARNINGS_CXXFLAGS="-Wall"
-	    # The test above doesn't work properly, at least on 3.1.
-	    MKSHLIB_FORCE_ALL=''
-	    MKSHLIB_UNFORCE_ALL=''
-	;;
-    esac
-    ;;
-
 *-darwin*)
     MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@'
     MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@'
     MOZ_OPTIMIZE_FLAGS="-O3"
     _PEDANTIC=
     # Statically disable jemalloc on 10.5 and 32-bit 10.6.  See bug 702250.
     if test "$HAVE_64BIT_OS"; then
         MOZ_MEMORY=1
@@ -3827,22 +3801,16 @@ fi
 
 dnl Mozilla specific options
 dnl ========================================================
 dnl The macros used for command line options
 dnl are defined in build/autoconf/altoptions.m4.
 
 dnl If the compiler supports these attributes, define them as
 dnl convenience macros.
-if test "$ac_cv_attribute_always_inline" = yes ; then
-  AC_DEFINE(NS_ALWAYS_INLINE, [__attribute__((always_inline))])
-else
-  AC_DEFINE(NS_ALWAYS_INLINE,)
-fi
-
 if test "$ac_cv_attribute_malloc" = yes ; then
   AC_DEFINE(NS_ATTR_MALLOC, [__attribute__((malloc))])
 else
   AC_DEFINE(NS_ATTR_MALLOC,)
 fi
 
 if test "$ac_cv_attribute_warn_unused" = yes ; then
   AC_DEFINE(NS_WARN_UNUSED_RESULT, [__attribute__((warn_unused_result))])
@@ -4410,21 +4378,25 @@ esac
 case "$MOZ_BUILD_APP" in
 browser)
   AC_DEFINE(MOZ_PHOENIX)
   ;;
 
 xulrunner)
   AC_DEFINE(MOZ_XULRUNNER)
   ;;
+b2g)
+  AC_DEFINE(MOZ_B2G)
+  ;;
 esac
 
 AC_SUBST(MOZ_BUILD_APP)
 AC_SUBST(MOZ_PHOENIX)
 AC_SUBST(MOZ_XULRUNNER)
+AC_SUBST(MOZ_B2G)
 
 AC_DEFINE_UNQUOTED(MOZ_BUILD_APP,$MOZ_BUILD_APP)
 
 dnl ========================================================
 dnl Check android sdk version depending on mobile target
 dnl ========================================================
 
 if test -z "$gonkdir" ; then
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -124,17 +124,16 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_
 #include "nsIWebNavigation.h"
 #include "nsILoadContext.h"
 #include "nsTextFragment.h"
 #include "mozilla/Selection.h"
 #include "nsSVGUtils.h"
 #include "nsISVGChildFrame.h"
 #include "nsRenderingContext.h"
 #include "gfxSVGGlyphs.h"
-#include "mozilla/dom/EncodingUtils.h"
 
 #ifdef IBMBIDI
 #include "nsIBidiKeyboard.h"
 #endif
 #include "nsCycleCollectionParticipant.h"
 
 // for ReportToConsole
 #include "nsIStringBundle.h"
@@ -1524,18 +1523,17 @@ nsContentUtils::Shutdown()
   delete sOSText;
   sOSText = nullptr;
   delete sAltText;  
   sAltText = nullptr;
   delete sModifierSeparator;
   sModifierSeparator = nullptr;
 
   NS_IF_RELEASE(sSameOriginChecker);
-  
-  EncodingUtils::Shutdown();
+
   nsTextEditorState::ShutDown();
 }
 
 /**
  * Checks whether two nodes come from the same origin. aTrustedNode is
  * considered 'safe' in that a user can operate on it and that it isn't
  * a js-object that implements nsIDOMNode.
  * Never call this function with the first node provided by script, it
--- a/content/base/src/nsDOMFileReader.cpp
+++ b/content/base/src/nsDOMFileReader.cpp
@@ -5,17 +5,16 @@
 
 #include "nsDOMFileReader.h"
 
 #include "nsContentCID.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsDOMFile.h"
 #include "nsError.h"
-#include "nsCharsetAlias.h"
 #include "nsICharsetConverterManager.h"
 #include "nsIConverterInputStream.h"
 #include "nsIFile.h"
 #include "nsIFileStreams.h"
 #include "nsIInputStream.h"
 #include "nsIMIMEService.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsNetCID.h"
@@ -36,29 +35,31 @@
 #include "nsIScriptGlobalObject.h"
 #include "nsCExternalHandlerService.h"
 #include "nsIStreamConverterService.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsLayoutStatics.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsBlobProtocolHandler.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/dom/EncodingUtils.h"
 #include "xpcpublic.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsDOMJSUtils.h"
 #include "nsDOMEventTargetHelper.h"
 
 #include "jsfriendapi.h"
 
 using namespace mozilla;
 
 #define LOAD_STR "load"
 #define LOADSTART_STR "loadstart"
 #define LOADEND_STR "loadend"
 
+using mozilla::dom::EncodingUtils;
 using mozilla::dom::FileIOObject;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMFileReader)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMFileReader,
                                                   FileIOObject)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFile)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrincipal)
@@ -458,18 +459,19 @@ nsDOMFileReader::GetAsText(const nsACStr
   if (!aCharset.IsEmpty()) {
     charsetGuess = aCharset;
   } else {
     rv = nsContentUtils::GuessCharset(aFileData, aDataLen, charsetGuess);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsAutoCString charset;
-  rv = nsCharsetAlias::GetPreferred(charsetGuess, charset);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (!EncodingUtils::FindEncodingForLabel(charsetGuess, charset)) {
+    return NS_ERROR_DOM_ENCODING_NOT_SUPPORTED_ERR;
+  }
 
   rv = ConvertStream(aFileData, aDataLen, charset.get(), aResult);
 
   return NS_OK;
 }
 
 nsresult
 nsDOMFileReader::GetAsDataURL(nsIDOMBlob *aFile,
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -141,16 +141,17 @@
 #include "nsObjectLoadingContent.h"
 #include "nsHtml5TreeOpExecutor.h"
 #ifdef MOZ_MEDIA
 #include "nsHTMLMediaElement.h"
 #endif // MOZ_MEDIA
 
 #include "mozAutoDocUpdate.h"
 #include "nsGlobalWindow.h"
+#include "mozilla/dom/EncodingUtils.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsEventStateManager.h"
 
 #include "nsSMILAnimationController.h"
 #include "imgIContainer.h"
 #include "nsSVGUtils.h"
 
@@ -3039,18 +3040,17 @@ nsDocument::TryChannelCharset(nsIChannel
     return true;
   }
 
   if (aChannel) {
     nsAutoCString charsetVal;
     nsresult rv = aChannel->GetContentCharset(charsetVal);
     if (NS_SUCCEEDED(rv)) {
       nsAutoCString preferred;
-      rv = nsCharsetAlias::GetPreferred(charsetVal, preferred);
-      if(NS_SUCCEEDED(rv)) {
+      if(EncodingUtils::FindEncodingForLabel(charsetVal, preferred)) {
         aCharset = preferred;
         aCharsetSource = kCharsetFromChannel;
         return true;
       } else if (aExecutor && !charsetVal.IsEmpty()) {
         aExecutor->ComplainAboutBogusProtocolCharset(this);
       }
     }
   }
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -24,17 +24,16 @@
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsGUIEvent.h"
 #include "prprf.h"
 #include "nsIDOMEventListener.h"
 #include "nsIJSContextStack.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsWeakPtr.h"
-#include "nsCharsetAlias.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMWindow.h"
 #include "nsIMIMEService.h"
 #include "nsCExternalHandlerService.h"
 #include "nsIVariant.h"
 #include "nsVariant.h"
@@ -67,16 +66,17 @@
 #include "nsIContentSecurityPolicy.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 #include "nsStringBuffer.h"
 #include "nsDOMFile.h"
 #include "nsIFileChannel.h"
 #include "mozilla/Telemetry.h"
 #include "jsfriendapi.h"
 #include "sampler.h"
+#include "mozilla/dom/EncodingUtils.h"
 #include "mozilla/dom/XMLHttpRequestBinding.h"
 #include "nsIDOMFormData.h"
 #include "DictionaryHelpers.h"
 #include "mozilla/Attributes.h"
 #include "nsIPermissionManager.h"
 #include "nsMimeTypes.h"
 
 #include "nsWrapperCacheInlines.h"
@@ -741,34 +741,32 @@ nsXMLHttpRequest::DetectCharset()
   }
 
   nsCOMPtr<nsIChannel> channel = do_QueryInterface(mReadRequest);
   if (!channel) {
     channel = mChannel;
   }
 
   nsAutoCString charsetVal;
-  nsresult rv = channel ? channel->GetContentCharset(charsetVal) :
-                NS_ERROR_FAILURE;
-  if (NS_SUCCEEDED(rv)) {
-    rv = nsCharsetAlias::GetPreferred(charsetVal, mResponseCharset);
-  }
-
-  if (NS_FAILED(rv) || mResponseCharset.IsEmpty()) {
+  bool ok = channel &&
+            NS_SUCCEEDED(channel->GetContentCharset(charsetVal)) &&
+            EncodingUtils::FindEncodingForLabel(charsetVal, mResponseCharset);
+  if (!ok || mResponseCharset.IsEmpty()) {
     // MS documentation states UTF-8 is default for responseText
     mResponseCharset.AssignLiteral("UTF-8");
   }
 
   if (mResponseType == XML_HTTP_RESPONSE_TYPE_JSON &&
       !mResponseCharset.EqualsLiteral("UTF-8")) {
     // The XHR spec says only UTF-8 is supported for responseType == "json"
     LogMessage("JSONCharsetWarning", GetOwner());
     mResponseCharset.AssignLiteral("UTF-8");
   }
 
+  nsresult rv;
   nsCOMPtr<nsICharsetConverterManager> ccm =
     do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return ccm->GetUnicodeDecoderRaw(mResponseCharset.get(),
                                    getter_AddRefs(mDecoder));
 }
 
--- a/content/base/test/test_XHRSendData.html
+++ b/content/base/test/test_XHRSendData.html
@@ -25,17 +25,17 @@ var gen = runTests();
 function continueTest() { gen.next(); }
 
 function runTests() {
 
 xhr = new XMLHttpRequest();
 xhr.open("GET", "file_XHRSendData_doc.xml", false);
 xhr.send();
 testDoc1 = xhr.responseXML;
-is(testDoc1.inputEncoding, "ISO-8859-1", "wrong encoding");
+is(testDoc1.inputEncoding, "windows-1252", "wrong encoding");
 
 testDoc2 = document.implementation.createDocument("", "", null);
 testDoc2.appendChild(testDoc2.createComment(" doc 2 "));
 testDoc2.appendChild(testDoc2.createElement("res"));
 testDoc2.documentElement.appendChild(testDoc2.createTextNode("text"));
 is(testDoc2.inputEncoding, null, "wrong encoding");
 
 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
@@ -116,32 +116,32 @@ tests = [{ body: null,
          },
          { body: "hi",
            contentType: "foo/bar; charset=uTf-8",
            resBody: "hi",
            resContentType: "foo/bar; charset=uTf-8",
          },
          { body: testDoc1,
            resBody: "<!-- comment -->\n<out>hi</out>",
-           resContentType: "application/xml; charset=ISO-8859-1",
+           resContentType: "application/xml; charset=windows-1252",
          },
          { body: testDoc1,
            contentType: "foo/bar",
            resBody: "<!-- comment -->\n<out>hi</out>",
-           resContentType: "foo/bar; charset=ISO-8859-1",
+           resContentType: "foo/bar; charset=windows-1252",
          },
          { body: testDoc1,
            contentType: "foo/bar; charset=ascii; baz=bin",
            resBody: "<!-- comment -->\n<out>hi</out>",
-           resContentType: "foo/bar; charset=ISO-8859-1; baz=bin",
+           resContentType: "foo/bar; charset=windows-1252; baz=bin",
          },
          { body: testDoc1,
-           contentType: "foo/bar; charset=IsO-8859-1",
+           contentType: "foo/bar; charset=wIndows-1252",
            resBody: "<!-- comment -->\n<out>hi</out>",
-           resContentType: "foo/bar; charset=IsO-8859-1",
+           resContentType: "foo/bar; charset=wIndows-1252",
          },
          { body: testDoc2,
            resBody: "<!-- doc 2 -->\n<res>text</res>",
            resContentType: "application/xml; charset=UTF-8",
          },
          { body: testDoc2,
            contentType: "foo/bar",
            resBody: "<!-- doc 2 -->\n<res>text</res>",
--- a/content/base/test/test_bug431701.html
+++ b/content/base/test/test_bug431701.html
@@ -59,25 +59,25 @@ function xhrDoc(idx) {
 }
 
 // Each row has the document getter function, then the characterSet,
 // inputEncoding expected for that document.
 
 var tests = [
  [ frameDoc("one"), "ISO-8859-1", "ISO-8859-1" ],
  [ frameDoc("two"), "UTF-8", "UTF-8" ],
- [ frameDoc("three"), "ISO-8859-1", "ISO-8859-1" ],
+ [ frameDoc("three"), "windows-1252", "windows-1252" ],
  [ frameDoc("four"), "UTF-8", "UTF-8" ],
  [ frameDoc("five"), "UTF-8", "UTF-8" ],
  [ frameDoc("six"), "UTF-8", "UTF-8" ],
- [ frameDoc("seven"), "ISO-8859-1", "ISO-8859-1" ],
+ [ frameDoc("seven"), "windows-1252", "windows-1252" ],
  [ createDoc, "UTF-8", null ],
  [ xhrDoc(4), "UTF-8", "UTF-8" ],
  [ xhrDoc(5), "UTF-8", "UTF-8" ],
- [ xhrDoc(6), "ISO-8859-1", "ISO-8859-1" ],
+ [ xhrDoc(6), "windows-1252", "windows-1252" ],
 ];
 
 function doTest(idx) {
   var [docGetter, expectedCharacterSet,
        expectedInputEncoding] = tests[idx];
   var doc = docGetter();
 
   // Have to be careful here to catch null vs ""
--- a/content/base/test/test_fileapi.html
+++ b/content/base/test/test_fileapi.html
@@ -439,17 +439,17 @@ function createFileWithData(fileData) {
 
   return fileList.files[0];
 }
 
 function convertToUTF16(s) {
   res = "";
   for (var i = 0; i < s.length; ++i) {
     c = s.charCodeAt(i);
-    res += String.fromCharCode(c >>> 8, c & 255);
+    res += String.fromCharCode(c & 255, c >>> 8);
   }
   return res;
 }
 
 function convertToUTF8(s) {
   return unescape(encodeURIComponent(s));
 }
 
--- a/content/events/public/nsEventNameList.h
+++ b/content/events/public/nsEventNameList.h
@@ -458,28 +458,31 @@ WINDOW_ONLY_EVENT(deviceproximity,
 WINDOW_ONLY_EVENT(userproximity,
                   NS_USER_PROXIMITY,
                   EventNameType_None,
                   NS_EVENT)
 WINDOW_ONLY_EVENT(devicelight,
                   NS_DEVICE_LIGHT,
                   EventNameType_None,
                   NS_EVENT)
+
+#ifdef MOZ_B2G
 WINDOW_ONLY_EVENT(moztimechange,
                   NS_MOZ_TIME_CHANGE_EVENT,
                   EventNameType_None,
                   NS_EVENT)
 WINDOW_ONLY_EVENT(moznetworkupload,
                   NS_NETWORK_UPLOAD_EVENT,
                   EventNameType_None,
                   NS_EVENT)
 WINDOW_ONLY_EVENT(moznetworkdownload,
                   NS_NETWORK_DOWNLOAD_EVENT,
                   EventNameType_None,
                   NS_EVENT)
+#endif // MOZ_B2G
 
 TOUCH_EVENT(touchstart,
             NS_TOUCH_START,
             EventNameType_All,
             NS_TOUCH_EVENT)
 TOUCH_EVENT(touchend,
             NS_TOUCH_END,
             EventNameType_All,
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -281,31 +281,33 @@ nsEventListenerManager::AddEventListener
   } else if (aTypeAtom == nsGkAtoms::ondeviceorientation) {
     EnableDevice(NS_DEVICE_ORIENTATION);
   } else if (aTypeAtom == nsGkAtoms::ondeviceproximity || aTypeAtom == nsGkAtoms::onuserproximity) {
     EnableDevice(NS_DEVICE_PROXIMITY);
   } else if (aTypeAtom == nsGkAtoms::ondevicelight) {
     EnableDevice(NS_DEVICE_LIGHT);
   } else if (aTypeAtom == nsGkAtoms::ondevicemotion) {
     EnableDevice(NS_DEVICE_MOTION);
+#ifdef MOZ_B2G
   } else if (aTypeAtom == nsGkAtoms::onmoztimechange) {
     nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
     if (window) {
       window->EnableTimeChangeNotifications();
     }
   } else if (aTypeAtom == nsGkAtoms::onmoznetworkupload) {
     nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
     if (window) {
       window->EnableNetworkEvent(NS_NETWORK_UPLOAD_EVENT);
     }
   } else if (aTypeAtom == nsGkAtoms::onmoznetworkdownload) {
     nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
     if (window) {
       window->EnableNetworkEvent(NS_NETWORK_DOWNLOAD_EVENT);
     }
+#endif // MOZ_B2G
   } else if (aTypeAtom == nsGkAtoms::ontouchstart ||
              aTypeAtom == nsGkAtoms::ontouchend ||
              aTypeAtom == nsGkAtoms::ontouchmove ||
              aTypeAtom == nsGkAtoms::ontouchenter ||
              aTypeAtom == nsGkAtoms::ontouchleave ||
              aTypeAtom == nsGkAtoms::ontouchcancel) {
     mMayHaveTouchEventListener = true;
     nsPIDOMWindow* window = GetInnerWindowForTarget();
@@ -417,52 +419,60 @@ nsEventListenerManager::RemoveEventListe
   }
 
   nsListenerStruct* ls;
   aFlags &= ~NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
 
   uint32_t count = mListeners.Length();
   uint32_t typeCount = 0;
   bool deviceType = IsDeviceType(aType);
+#ifdef MOZ_B2G
   bool timeChangeEvent = (aType == NS_MOZ_TIME_CHANGE_EVENT);
   bool networkEvent = (aType == NS_NETWORK_UPLOAD_EVENT ||
                        aType == NS_NETWORK_DOWNLOAD_EVENT);
+#endif // MOZ_B2G
 
   for (uint32_t i = 0; i < count; ++i) {
     ls = &mListeners.ElementAt(i);
     if (EVENT_TYPE_EQUALS(ls, aType, aUserType, aAllEvents)) {
       ++typeCount;
       if (ls->mListener == aListener &&
           (ls->mFlags & ~NS_PRIV_EVENT_UNTRUSTED_PERMITTED) == aFlags) {
         nsRefPtr<nsEventListenerManager> kungFuDeathGrip = this;
         mListeners.RemoveElementAt(i);
         --count;
         mNoListenerForEvent = NS_EVENT_TYPE_NULL;
         mNoListenerForEventAtom = nullptr;
 
-        if (!deviceType && !timeChangeEvent && !networkEvent) {
+        if (!deviceType
+#ifdef MOZ_B2G
+            && !timeChangeEvent && !networkEvent
+#endif // MOZ_B2G
+            ) {
           return;
         }
         --typeCount;
       }
     }
   }
 
   if (!aAllEvents && deviceType && typeCount == 0) {
     DisableDevice(aType);
+#ifdef MOZ_B2G
   } else if (timeChangeEvent && typeCount == 0) {
     nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
     if (window) {
       window->DisableTimeChangeNotifications();
     }
   } else if (!aAllEvents && networkEvent && typeCount == 0) {
     nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
     if (window) {
       window->DisableNetworkEvent(aType);
     }
+#endif // MOZ_B2G
   }
 }
 
 static inline bool
 ListenerCanHandle(nsListenerStruct* aLs, nsEvent* aEvent)
 {
   // This is slightly different from EVENT_TYPE_EQUALS in that it returns
   // true even when aEvent->message == NS_USER_DEFINED_EVENT and
@@ -997,32 +1007,32 @@ nsEventListenerManager::RemoveEventListe
 }
 
 void
 nsEventListenerManager::AddListenerForAllEvents(nsIDOMEventListener* aListener,
                                                 bool aUseCapture,
                                                 bool aWantsUntrusted,
                                                 bool aSystemEventGroup)
 {
-  PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
+  int32_t flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
   if (aWantsUntrusted) {
     flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
   }
   if (aSystemEventGroup) {
     flags |= NS_EVENT_FLAG_SYSTEM_EVENT;
   }
   AddEventListener(aListener, NS_EVENT_TYPE_ALL, nullptr, flags, false, true);
 }
 
 void
 nsEventListenerManager::RemoveListenerForAllEvents(nsIDOMEventListener* aListener, 
                                                    bool aUseCapture,
                                                    bool aSystemEventGroup)
 {
-  PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
+  int32_t flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
   if (aSystemEventGroup) {
     flags |= NS_EVENT_FLAG_SYSTEM_EVENT;
   }
   RemoveEventListener(aListener, NS_EVENT_TYPE_ALL, nullptr, flags, true);
 }
 
 bool
 nsEventListenerManager::HasMutationListeners()
--- a/content/html/content/src/nsFormSubmission.cpp
+++ b/content/html/content/src/nsFormSubmission.cpp
@@ -23,30 +23,32 @@
 #include "nsIDOMFile.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsStringStream.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsNetUtil.h"
 #include "nsLinebreakConverter.h"
 #include "nsICharsetConverterManager.h"
-#include "nsCharsetAlias.h"
 #include "nsEscape.h"
 #include "nsUnicharUtils.h"
 #include "nsIMultiplexInputStream.h"
 #include "nsIMIMEInputStream.h"
 #include "nsIMIMEService.h"
 #include "nsIConsoleService.h"
 #include "nsIScriptError.h"
 #include "nsIStringBundle.h"
 #include "nsCExternalHandlerService.h"
 #include "nsIFileStreams.h"
 #include "nsContentUtils.h"
 
+#include "mozilla/dom/EncodingUtils.h"
+
 using namespace mozilla;
+using mozilla::dom::EncodingUtils;
 
 static void
 SendJSWarning(nsIDocument* aDocument,
               const char* aWarningName,
               const PRUnichar** aWarningArgs, uint32_t aWarningArgsLen)
 {
   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                   "HTML", aDocument,
@@ -769,18 +771,17 @@ GetSubmitCharset(nsGenericHTMLElement* a
     // get charset from charsets one by one
     do {
       spPos = acceptCharsetValue.FindChar(PRUnichar(' '), offset);
       int32_t cnt = ((-1==spPos)?(charsetLen-offset):(spPos-offset));
       if (cnt > 0) {
         nsAutoString uCharset;
         acceptCharsetValue.Mid(uCharset, offset, cnt);
 
-        if (NS_SUCCEEDED(nsCharsetAlias::GetPreferred(NS_LossyConvertUTF16toASCII(uCharset),
-                                                      oCharset)))
+        if (EncodingUtils::FindEncodingForLabel(uCharset, oCharset))
           return;
       }
       offset = spPos + 1;
     } while (spPos != -1);
   }
   // if there are no accept-charset or all the charset are not supported
   // Get the charset from document
   nsIDocument* doc = aForm->GetDocument();
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -446,21 +446,23 @@ nsGenericHTMLElement::SetClassName(const
 
 NS_IMPL_STRING_ATTR(nsGenericHTMLElement, AccessKey, accesskey)
 
 NS_IMETHODIMP
 nsGenericHTMLElement::GetAccessKeyLabel(nsAString& aLabel)
 {
   nsPresContext *presContext = GetPresContext();
 
-  if (presContext &&
-    presContext->EventStateManager()->GetAccessKeyLabelPrefix(aLabel)) {
-      nsAutoString suffix;
-      GetAccessKey(suffix);
+  if (presContext) {
+    nsAutoString suffix;
+    GetAccessKey(suffix);
+    if (!suffix.IsEmpty() && 
+        presContext->EventStateManager()->GetAccessKeyLabelPrefix(aLabel)) {
       aLabel.Append(suffix);
+    }
   }
 
   return NS_OK;
 }
 
 static bool IS_TABLE_CELL(nsIAtom* frameType) {
   return nsGkAtoms::tableCellFrame == frameType ||
     nsGkAtoms::bcTableCellFrame == frameType;
--- a/content/html/content/src/nsHTMLCanvasElement.cpp
+++ b/content/html/content/src/nsHTMLCanvasElement.cpp
@@ -617,16 +617,21 @@ nsHTMLCanvasElement::ToBlob(nsIFileCallb
   void* imgData = nullptr;
   rv = NS_ReadInputStreamToBuffer(stream, &imgData, imgSize);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // The DOMFile takes ownership of the buffer
   nsRefPtr<nsDOMMemoryFile> blob =
     new nsDOMMemoryFile(imgData, imgSize, type);
 
+  JSContext* cx = nsContentUtils::GetCurrentJSContext();
+  if (cx) {
+    JS_updateMallocCounter(cx, imgSize);
+  }
+
   nsRefPtr<ToBlobRunnable> runnable = new ToBlobRunnable(aCallback, blob);
   return NS_DispatchToCurrentThread(runnable);
 }
 
 NS_IMETHODIMP
 nsHTMLCanvasElement::MozGetAsFile(const nsAString& aName,
                                   const nsAString& aType,
                                   uint8_t optional_argc,
@@ -662,16 +667,21 @@ nsHTMLCanvasElement::MozGetAsFileImpl(co
   rv = stream->Available(&imgSize);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(imgSize <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
 
   void* imgData = nullptr;
   rv = NS_ReadInputStreamToBuffer(stream, &imgData, (uint32_t)imgSize);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  JSContext* cx = nsContentUtils::GetCurrentJSContext();
+  if (cx) {
+    JS_updateMallocCounter(cx, imgSize);
+  }
+
   // The DOMFile takes ownership of the buffer
   nsRefPtr<nsDOMMemoryFile> file =
     new nsDOMMemoryFile(imgData, (uint32_t)imgSize, aName, type);
 
   file.forget(aResult);
   return NS_OK;
 }
 
--- a/content/html/content/test/test_bug583533.html
+++ b/content/html/content/test/test_bug583533.html
@@ -67,12 +67,19 @@ https://bugzilla.mozilla.org/show_bug.cg
         label += altText + separatorText;
     if (isShift)
         label += shiftText + separatorText;
 
     label += document.getElementById("e").accessKey;
 
     is(label, document.getElementById("e").accessKeyLabel, "JS and C++ agree on accessKeyLabel");
 
+    /** Test for Bug 808964 **/
+
+    var div = document.createElement("div");
+    document.body.appendChild(div);
+
+    is(div.accessKeyLabel, "", "accessKeyLabel should be empty string");
+
 </script>
 </pre>
 </body>
 </html>
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/dom/AudioContextBinding.h"
 #include "AudioDestinationNode.h"
 #include "AudioBufferSourceNode.h"
 #include "AudioBuffer.h"
 #include "GainNode.h"
 #include "DelayNode.h"
 #include "PannerNode.h"
 #include "AudioListener.h"
+#include "DynamicsCompressorNode.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(AudioContext)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(AudioContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mWindow)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDestination)
@@ -110,16 +111,24 @@ AudioContext::CreateDelay(float aMaxDela
 
 already_AddRefed<PannerNode>
 AudioContext::CreatePanner()
 {
   nsRefPtr<PannerNode> pannerNode = new PannerNode(this);
   return pannerNode.forget();
 }
 
+already_AddRefed<DynamicsCompressorNode>
+AudioContext::CreateDynamicsCompressor()
+{
+  nsRefPtr<DynamicsCompressorNode> compressorNode =
+    new DynamicsCompressorNode(this);
+  return compressorNode.forget();
+}
+
 AudioListener*
 AudioContext::Listener()
 {
   if (!mListener) {
     mListener = new AudioListener(this);
   }
   return mListener;
 }
--- a/content/media/webaudio/AudioContext.h
+++ b/content/media/webaudio/AudioContext.h
@@ -23,16 +23,17 @@ class ErrorResult;
 
 namespace dom {
 
 class AudioBuffer;
 class AudioBufferSourceNode;
 class AudioDestinationNode;
 class AudioListener;
 class DelayNode;
+class DynamicsCompressorNode;
 class GainNode;
 class PannerNode;
 
 class AudioContext MOZ_FINAL : public nsWrapperCache,
                                public EnableWebAudioCheck
 {
   explicit AudioContext(nsIDOMWindow* aParentWindow);
 
@@ -71,16 +72,19 @@ public:
   CreateGain();
 
   already_AddRefed<DelayNode>
   CreateDelay(float aMaxDelayTime);
 
   already_AddRefed<PannerNode>
   CreatePanner();
 
+  already_AddRefed<DynamicsCompressorNode>
+  CreateDynamicsCompressor();
+
 private:
   nsCOMPtr<nsIDOMWindow> mWindow;
   nsRefPtr<AudioDestinationNode> mDestination;
   nsRefPtr<AudioListener> mListener;
 };
 
 }
 }
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/DynamicsCompressorNode.cpp
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "DynamicsCompressorNode.h"
+#include "mozilla/dom/DynamicsCompressorNodeBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(DynamicsCompressorNode)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DynamicsCompressorNode, AudioNode)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mThreshold)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mKnee)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRatio)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mReduction)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mAttack)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRelease)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DynamicsCompressorNode, AudioNode)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->mThreshold, AudioParam, "threshold value")
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->mKnee, AudioParam, "knee value")
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->mRatio, AudioParam, "ratio value")
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->mReduction, AudioParam, "reduction value")
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->mAttack, AudioParam, "attack value")
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->mRelease, AudioParam, "release value")
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DynamicsCompressorNode)
+NS_INTERFACE_MAP_END_INHERITING(AudioNode)
+
+NS_IMPL_ADDREF_INHERITED(DynamicsCompressorNode, AudioNode)
+NS_IMPL_RELEASE_INHERITED(DynamicsCompressorNode, AudioNode)
+
+DynamicsCompressorNode::DynamicsCompressorNode(AudioContext* aContext)
+  : AudioNode(aContext)
+  , mThreshold(new AudioParam(aContext, -24.f, -100.f, 0.f))
+  , mKnee(new AudioParam(aContext, 30.f, 0.f, 40.f))
+  , mRatio(new AudioParam(aContext, 12.f, 1.f, 20.f))
+  , mReduction(new AudioParam(aContext, 0.f, -20.f, 0.f))
+  , mAttack(new AudioParam(aContext, 0.003f, 0.f, 1.f))
+  , mRelease(new AudioParam(aContext, 0.25f, 0.f, 1.f))
+{
+}
+
+JSObject*
+DynamicsCompressorNode::WrapObject(JSContext* aCx, JSObject* aScope,
+                                   bool* aTriedToWrap)
+{
+  return DynamicsCompressorNodeBinding::Wrap(aCx, aScope, this, aTriedToWrap);
+}
+
+}
+}
+
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/DynamicsCompressorNode.h
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef DynamicsCompressorNode_h_
+#define DynamicsCompressorNode_h_
+
+#include "AudioNode.h"
+#include "AudioParam.h"
+
+namespace mozilla {
+namespace dom {
+
+class AudioContext;
+
+class DynamicsCompressorNode : public AudioNode
+{
+public:
+  explicit DynamicsCompressorNode(AudioContext* aContext);
+
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DynamicsCompressorNode, AudioNode)
+
+  virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
+                               bool* aTriedToWrap);
+
+  virtual uint32_t MaxNumberOfInputs() const MOZ_FINAL MOZ_OVERRIDE
+  {
+    return 1;
+  }
+  virtual uint32_t MaxNumberOfOutputs() const MOZ_FINAL MOZ_OVERRIDE
+  {
+    return 1;
+  }
+
+  AudioParam* Threshold() const
+  {
+    return mThreshold;
+  }
+
+  AudioParam* Knee() const
+  {
+    return mKnee;
+  }
+
+  AudioParam* Ratio() const
+  {
+    return mRatio;
+  }
+
+  AudioParam* Reduction() const
+  {
+    return mReduction;
+  }
+
+  AudioParam* Attack() const
+  {
+    return mAttack;
+  }
+
+  // Called GetRelease to prevent clashing with the nsISupports::Release name
+  AudioParam* GetRelease() const
+  {
+    return mRelease;
+  }
+
+private:
+  nsRefPtr<AudioParam> mThreshold;
+  nsRefPtr<AudioParam> mKnee;
+  nsRefPtr<AudioParam> mRatio;
+  nsRefPtr<AudioParam> mReduction;
+  nsRefPtr<AudioParam> mAttack;
+  nsRefPtr<AudioParam> mRelease;
+};
+
+}
+}
+
+#endif
+
--- a/content/media/webaudio/Makefile.in
+++ b/content/media/webaudio/Makefile.in
@@ -19,31 +19,33 @@ CPPSRCS := \
   AudioBufferSourceNode.cpp \
   AudioContext.cpp \
   AudioDestinationNode.cpp \
   AudioListener.cpp \
   AudioNode.cpp \
   AudioParam.cpp \
   AudioSourceNode.cpp \
   DelayNode.cpp \
+  DynamicsCompressorNode.cpp \
   EnableWebAudioCheck.cpp \
   GainNode.cpp \
   PannerNode.cpp \
   $(NULL)
 
 EXPORTS_NAMESPACES := mozilla/dom
 EXPORTS_mozilla/dom := \
   AudioBuffer.h \
   AudioBufferSourceNode.h \
   AudioDestinationNode.h \
   AudioListener.h \
   AudioNode.h \
   AudioParam.h \
   AudioSourceNode.h \
   DelayNode.h \
+  DynamicsCompressorNode.h \
   GainNode.h \
   PannerNode.h \
   $(NULL)
 
 PARALLEL_DIRS := test
 
 ifdef ENABLE_TESTS
 TOOL_DIRS += compiledtest
--- a/content/media/webaudio/test/Makefile.in
+++ b/content/media/webaudio/test/Makefile.in
@@ -12,14 +12,15 @@ include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_FILES := \
   test_bug808374.html \
   test_AudioBuffer.html \
   test_AudioContext.html \
   test_AudioListener.html \
   test_badConnect.html \
   test_delayNode.html \
+  test_dynamicsCompressorNode.html \
   test_gainNode.html \
   test_pannerNode.html \
   test_singleSourceDest.html \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_dynamicsCompressorNode.html
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test DynamicsCompressorNode</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function near(a, b, msg) {
+  ok(Math.abs(a - b) < 1e-4, msg);
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  SpecialPowers.setBoolPref("media.webaudio.enabled", true);
+
+  var context = new mozAudioContext();
+  var buffer = context.createBuffer(1, 2048, 44100);
+  for (var i = 0; i < 2048; ++i) {
+    buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / 44100);
+  }
+
+  var destination = context.destination;
+
+  var source = context.createBufferSource();
+
+  var compressor = context.createDynamicsCompressor();
+
+  source.buffer = buffer;
+
+  source.connect(compressor);
+  compressor.connect(destination);
+
+  // Verify default values
+  with (compressor) {
+    near(threshold.defaultValue, -24, "Correct default value for threshold");
+    near(knee.defaultValue, 30, "Correct default value for knee");
+    near(ratio.defaultValue, 12, "Correct default value for ratio");
+    near(reduction.defaultValue, 0, "Correct default value for reduction");
+    near(attack.defaultValue, 0.003, "Correct default value for attack");
+    near(release.defaultValue, 0.25, "Correct default value for release");
+  }
+
+  // Verify min/max values
+  with (compressor) {
+    near(threshold.minValue, -100, "Correct min value for threshold");
+    near(knee.minValue, 0, "Correct min value for knee");
+    near(ratio.minValue, 1, "Correct min value for ratio");
+    near(reduction.minValue, -20, "Correct min value for reduction");
+    near(attack.minValue, 0, "Correct min value for attack");
+    near(release.minValue, 0, "Correct min value for release");
+    near(threshold.maxValue, 0, "Correct max value for threshold");
+    near(knee.maxValue, 40, "Correct max value for knee");
+    near(ratio.maxValue, 20, "Correct max value for ratio");
+    near(reduction.maxValue, 0, "Correct max value for reduction");
+    near(attack.maxValue, 1, "Correct max value for attack");
+    near(release.maxValue, 1, "Correct max value for release");
+  }
+
+  source.start(0);
+  SimpleTest.executeSoon(function() {
+    source.stop(0);
+    source.disconnect();
+    compressor.disconnect();
+
+    SpecialPowers.clearUserPref("media.webaudio.enabled");
+    SimpleTest.finish();
+  });
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp
+++ b/content/xslt/src/xslt/txMozillaStylesheetCompiler.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "nsCOMArray.h"
 #include "nsIAuthPrompt.h"
-#include "nsCharsetAlias.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMDocument.h"
 #include "nsIDocument.h"
 #include "nsIExpatSink.h"
 #include "nsIChannelEventSink.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsILoadGroup.h"
 #include "nsINameSpaceManager.h"
@@ -34,20 +33,22 @@
 #include "txMozillaXSLTProcessor.h"
 #include "txStylesheetCompiler.h"
 #include "txXMLUtils.h"
 #include "nsAttrName.h"
 #include "nsIScriptError.h"
 #include "nsIURL.h"
 #include "nsCrossSiteListenerProxy.h"
 #include "nsError.h"
+#include "mozilla/Attributes.h"
 #include "mozilla/dom/Element.h"
-#include "mozilla/Attributes.h"
+#include "mozilla/dom/EncodingUtils.h"
 
 using namespace mozilla;
+using mozilla::dom::EncodingUtils;
 
 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
 
 static void
 getSpec(nsIChannel* aChannel, nsAString& aSpec)
 {
     if (!aChannel) {
         return;
@@ -253,17 +254,17 @@ txStylesheetSink::OnStartRequest(nsIRequ
     int32_t charsetSource = kCharsetFromDocTypeDefault;
 
     nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
 
     // check channel's charset...
     nsAutoCString charsetVal;
     nsAutoCString charset;
     if (NS_SUCCEEDED(channel->GetContentCharset(charsetVal))) {
-        if (NS_SUCCEEDED(nsCharsetAlias::GetPreferred(charsetVal, charset))) {
+        if (EncodingUtils::FindEncodingForLabel(charsetVal, charset)) {
             charsetSource = kCharsetFromChannel;
         }
     }
 
     if (charset.IsEmpty()) {
       charset.AssignLiteral("UTF-8");
     }
 
--- a/content/xslt/src/xslt/txMozillaTextOutput.cpp
+++ b/content/xslt/src/xslt/txMozillaTextOutput.cpp
@@ -7,22 +7,22 @@
 #include "nsContentCID.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentFragment.h"
 #include "nsIDocumentTransformer.h"
 #include "nsNetUtil.h"
 #include "nsCharsetSource.h"
-#include "nsCharsetAlias.h"
 #include "nsIPrincipal.h"
 #include "txURIUtils.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsContentUtils.h"
 #include "nsGkAtoms.h"
+#include "mozilla/dom/EncodingUtils.h"
 
 using namespace mozilla::dom;
 
 txMozillaTextOutput::txMozillaTextOutput(nsITransformObserver* aObserver)
 {
     MOZ_COUNT_CTOR(txMozillaTextOutput);
     mObserver = do_GetWeakReference(aObserver);
 }
@@ -144,21 +144,20 @@ txMozillaTextOutput::createResultDocumen
 
     NS_ASSERTION(mDocument, "Need document");
 
     // Reset and set up document
     URIUtils::ResetWithSource(mDocument, aSourceDocument);
 
     // Set the charset
     if (!mOutputFormat.mEncoding.IsEmpty()) {
-        NS_LossyConvertUTF16toASCII charset(mOutputFormat.mEncoding);
         nsAutoCString canonicalCharset;
 
-        if (NS_SUCCEEDED(nsCharsetAlias::GetPreferred(charset,
-                                                      canonicalCharset))) {
+        if (EncodingUtils::FindEncodingForLabel(mOutputFormat.mEncoding,
+                                                canonicalCharset)) {
             mDocument->SetDocumentCharacterSetSource(kCharsetFromOtherComponent);
             mDocument->SetDocumentCharacterSet(canonicalCharset);
         }
     }
 
     // Notify the contentsink that the document is created
     nsCOMPtr<nsITransformObserver> observer = do_QueryReferent(mObserver);
     if (observer) {
--- a/content/xslt/src/xslt/txMozillaXMLOutput.cpp
+++ b/content/xslt/src/xslt/txMozillaXMLOutput.cpp
@@ -26,17 +26,17 @@
 #include "nsCSSStyleSheet.h"
 #include "txStringUtils.h"
 #include "txURIUtils.h"
 #include "nsIHTMLDocument.h"
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsIDocumentTransformer.h"
 #include "mozilla/css/Loader.h"
 #include "mozilla/dom/Element.h"
-#include "nsCharsetAlias.h"
+#include "mozilla/dom/EncodingUtils.h"
 #include "nsContentUtils.h"
 #include "txXMLUtils.h"
 #include "nsContentSink.h"
 #include "nsINode.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsError.h"
 #include "nsIFrame.h"
 
@@ -821,19 +821,19 @@ txMozillaXMLOutput::createResultDocument
     mCurrentNode = mDocument;
     mNodeInfoManager = mDocument->NodeInfoManager();
 
     // Reset and set up the document
     URIUtils::ResetWithSource(mDocument, aSourceDocument);
 
     // Set the charset
     if (!mOutputFormat.mEncoding.IsEmpty()) {
-        NS_LossyConvertUTF16toASCII charset(mOutputFormat.mEncoding);
         nsAutoCString canonicalCharset;
-        if (NS_SUCCEEDED(nsCharsetAlias::GetPreferred(charset, canonicalCharset))) {
+        if (EncodingUtils::FindEncodingForLabel(mOutputFormat.mEncoding,
+                                                canonicalCharset)) {
             mDocument->SetDocumentCharacterSetSource(kCharsetFromOtherComponent);
             mDocument->SetDocumentCharacterSet(canonicalCharset);
         }
     }
 
     // Set the mime-type
     if (!mOutputFormat.mMediaType.IsEmpty()) {
         mDocument->SetContentType(mOutputFormat.mMediaType);
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -10455,32 +10455,34 @@ nsDocShell::AddToSessionHistory(nsIURI *
         if (aCloneChildren && mOSHE) {
             uint32_t cloneID;
             mOSHE->GetID(&cloneID);
             nsCOMPtr<nsISHEntry> newEntry;
             CloneAndReplace(mOSHE, this, cloneID, entry, true, getter_AddRefs(newEntry));
             NS_ASSERTION(entry == newEntry, "The new session history should be in the new entry");
         }
 
+        int32_t index = 0;   
+        mSessionHistory->GetIndex(&index);
+
         // This is the root docshell
-        if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {            
+        if (-1 != index &&
+            LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {            
             // Replace current entry in session history.
-            int32_t  index = 0;   
-            mSessionHistory->GetIndex(&index);
             nsCOMPtr<nsISHistoryInternal>   shPrivate(do_QueryInterface(mSessionHistory));
             // Replace the current entry with the new entry
             if (shPrivate)
                 rv = shPrivate->ReplaceEntry(index, entry);          
         }
         else {
             // Add to session history
             nsCOMPtr<nsISHistoryInternal>
                 shPrivate(do_QueryInterface(mSessionHistory));
             NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
-            mSessionHistory->GetIndex(&mPreviousTransIndex);
+            mPreviousTransIndex = index;
             rv = shPrivate->AddEntry(entry, shouldPersist);
             mSessionHistory->GetIndex(&mLoadedTransIndex);
 #ifdef DEBUG_PAGE_CACHE
             printf("Previous index: %d, Loaded index: %d\n\n",
                    mPreviousTransIndex, mLoadedTransIndex);
 #endif
         }
     }
--- a/docshell/test/browser/Makefile.in
+++ b/docshell/test/browser/Makefile.in
@@ -27,11 +27,12 @@ MOCHITEST_BROWSER_FILES =	\
 		browser_bug554155.js \
 		browser_bug655273.js \
 		browser_bug655270.js \
 		file_bug655270.html \
 		favicon_bug655270.ico \
 		browser_bug670318.js \
 		file_bug670318.html \
 		browser_bug673467.js \
+		browser_bug808035.js \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/docshell/test/browser/browser_bug808035.js
@@ -0,0 +1,33 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test for bug 808035.
+// When we open a new tab, the initial URI is the transient <about:blank> and 
+// then requested URI would be loaded. When the URI's shceme is "javascript:",
+// we can *replace* the transient <about:blank> with an actual requet
+// through <javascript:location.replace("http://example.org/")>.
+//
+// There's no session history entry corresponding to the transient
+// <about:blank>. But we should make sure there exists a session history entry
+// for <http://example.org>.
+
+function test() {
+  const NEW_URI = "http://test1.example.org/";
+  const REQUESTED_URI = "javascript:void(location.replace('" + NEW_URI +
+                        "'))";
+
+  waitForExplicitFinish();
+
+  let tab = gBrowser.addTab(REQUESTED_URI);
+  let browser = tab.linkedBrowser;
+
+  browser.addEventListener('load', function(aEvent) {
+    browser.removeEventListener('load', arguments.callee, true);
+
+    is(browser.contentWindow.location.href, NEW_URI, "The URI is OK.");
+    is(browser.contentWindow.history.length, 1, "There exists a SH entry.");
+
+    gBrowser.removeTab(tab);
+    finish();
+  }, true);
+}
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -869,17 +869,17 @@ this.DOMApplicationRegistry = {
                                                                 aOfflineCacheObserver) {
     // if the manifest has an appcache_path property, use it to populate the appcache
     if (aManifest.appcache_path) {
       let appcacheURI = Services.io.newURI(aManifest.fullAppcachePath(), null, null);
       let updateService = Cc["@mozilla.org/offlinecacheupdate-service;1"]
                             .getService(Ci.nsIOfflineCacheUpdateService);
       let docURI = Services.io.newURI(aManifest.fullLaunchPath(), null, null);
       let cacheUpdate = aProfileDir ? updateService.scheduleCustomProfileUpdate(appcacheURI, docURI, aProfileDir)
-                                    : updateService.scheduleUpdate(appcacheURI, docURI, null);
+                                    : updateService.scheduleAppUpdate(appcacheURI, docURI, aApp.localId, false);
       cacheUpdate.addObserver(new AppcacheObserver(aApp), false);
       if (aOfflineCacheObserver) {
         cacheUpdate.addObserver(aOfflineCacheObserver, false);
       }
     }
   },
 
   checkForUpdate: function(aData, aMm) {
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -2370,28 +2370,44 @@ nsDOMClassInfo::RegisterExternalClasses(
 
 #define DOM_CLASSINFO_EVENT_MAP_ENTRIES                                       \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)                                      \
 
 #define DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES                                    \
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMUIEvent)                                    \
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
 
+#ifdef MOZ_B2G
+#define DOM_CLASSINFO_WINDOW_MAP_ENTRIES(_support_indexed_db)                  \
+  DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindow)                                        \
+  DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindowB2G)                                     \
+  DOM_CLASSINFO_MAP_ENTRY(nsIDOMJSWindow)                                      \
+  DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)                                   \
+  DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers)                              \
+  DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMStorageIndexedDB,                  \
+                                      _support_indexed_db)                     \
+  DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMWindowPerformance,                 \
+                                      nsGlobalWindow::HasPerformanceSupport()) \
+  DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver,                   \
+                                      nsDOMTouchEvent::PrefEnabled())          \
+  DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIWindowCrypto, domCryptoEnabled)
+#else // !MOZ_B2G
 #define DOM_CLASSINFO_WINDOW_MAP_ENTRIES(_support_indexed_db)                  \
   DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindow)                                        \
   DOM_CLASSINFO_MAP_ENTRY(nsIDOMJSWindow)                                      \
   DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)                                   \
   DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers)                              \
   DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMStorageIndexedDB,                  \
                                       _support_indexed_db)                     \
   DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMWindowPerformance,                 \
                                       nsGlobalWindow::HasPerformanceSupport()) \
   DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver,                   \
                                       nsDOMTouchEvent::PrefEnabled())          \
   DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIWindowCrypto, domCryptoEnabled)
+#endif // MOZ_B2G
 
 nsresult
 nsDOMClassInfo::Init()
 {
   /* Errors that can trigger early returns are done first,
      otherwise nsDOMClassInfo is left in a half inited state. */
   MOZ_STATIC_ASSERT(sizeof(uintptr_t) == sizeof(void*),
                     "BAD! You'll need to adjust the size of uintptr_t to the "
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1021,18 +1021,20 @@ nsGlobalWindow::CleanUp(bool aIgnoreModa
 
   if (mObserver) {
     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     if (os) {
       os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
       os->RemoveObserver(mObserver, "dom-storage2-changed");
     }
 
+#ifdef MOZ_B2G
     DisableNetworkEvent(NS_NETWORK_UPLOAD_EVENT);
     DisableNetworkEvent(NS_NETWORK_DOWNLOAD_EVENT);
+#endif // MOZ_B2G
 
     if (mIdleService) {
       mIdleService->RemoveIdleObserver(mObserver, MIN_IDLE_NOTIFICATION_TIME_S);
     }
 
     // Drop its reference to this dying window, in case for some bogus reason
     // the object stays around.
     mObserver->Forget();
@@ -1221,16 +1223,19 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalW
 
 DOMCI_DATA(Window, nsGlobalWindow)
 
 // QueryInterface implementation for nsGlobalWindow
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow)
   // Make sure this matches the cast in nsGlobalWindow::FromWrapper()
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptGlobalObject)
   NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
+#ifdef MOZ_B2G
+  NS_INTERFACE_MAP_ENTRY(nsIDOMWindowB2G)
+#endif // MOZ_B2G
   NS_INTERFACE_MAP_ENTRY(nsIDOMJSWindow)
   if (aIID.Equals(NS_GET_IID(nsIDOMWindowInternal))) {
     foundInterface = static_cast<nsIDOMWindowInternal*>(this);
     if (!sWarnedAboutWindowInternal) {
       sWarnedAboutWindowInternal = true;
       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                       "Extensions", mDoc,
                                       nsContentUtils::eDOM_PROPERTIES,
@@ -9146,32 +9151,34 @@ nsGlobalWindow::Observe(nsISupports* aSu
     GetApplicationCache(getter_AddRefs(applicationCache));
     nsCOMPtr<nsIObserver> observer = do_QueryInterface(applicationCache);
     if (observer)
       observer->Observe(aSubject, aTopic, aData);
 
     return NS_OK;
   }
 
+#ifdef MOZ_B2G
   if (!nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC) ||
       !nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC)) {
     nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nullptr, nullptr);
     nsresult rv = event->InitEvent(
       !nsCRT::strcmp(aTopic, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC)
         ? NETWORK_UPLOAD_EVENT_NAME
         : NETWORK_DOWNLOAD_EVENT_NAME,
       false, false);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = event->SetTrusted(true);
     NS_ENSURE_SUCCESS(rv, rv);
 
     bool dummy;
     return DispatchEvent(event, &dummy);
   }
+#endif // MOZ_B2G
 
   NS_WARNING("unrecognized topic in nsGlobalWindow::Observe");
   return NS_ERROR_FAILURE;
 }
 
 nsresult
 nsGlobalWindow::CloneStorageEvent(const nsAString& aType,
                                   nsCOMPtr<nsIDOMStorageEvent>& aEvent)
@@ -11215,16 +11222,17 @@ nsGlobalModalWindow::SetNewDocument(nsID
 void
 nsGlobalWindow::SetHasAudioAvailableEventListeners()
 {
   if (mDoc) {
     mDoc->NotifyAudioAvailableListener();
   }
 }
 
+#ifdef MOZ_B2G
 void
 nsGlobalWindow::EnableNetworkEvent(uint32_t aType)
 {
   nsCOMPtr<nsIPermissionManager> permMgr =
     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
   if (!permMgr) {
     NS_ERROR("No PermissionManager available!");
     return;
@@ -11266,16 +11274,17 @@ nsGlobalWindow::DisableNetworkEvent(uint
     case NS_NETWORK_UPLOAD_EVENT:
       os->RemoveObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC);
       break;
     case NS_NETWORK_DOWNLOAD_EVENT:
       os->RemoveObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC);
       break;
   }
 }
+#endif // MOZ_B2G
 
 #define EVENT(name_, id_, type_, struct_)                                    \
   NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx,                  \
                                              jsval *vp) {                    \
     nsEventListenerManager *elm = GetListenerManager(false);                 \
     if (elm) {                                                               \
       elm->GetEventHandler(nsGkAtoms::on##name_, vp);                        \
     } else {                                                                 \
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -65,16 +65,20 @@
 #include "nsWrapperCacheInlines.h"
 #include "nsIDOMApplicationRegistry.h"
 #include "nsIIdleObserver.h"
 #include "nsIDOMWakeLock.h"
 
 // JS includes
 #include "jsapi.h"
 
+#ifdef MOZ_B2G
+#include "nsIDOMWindowB2G.h"
+#endif // MOZ_B2G
+
 #define DEFAULT_HOME_PAGE "www.mozilla.org"
 #define PREF_BROWSER_STARTUP_HOMEPAGE "browser.startup.homepage"
 
 // Amount of time allowed between alert/prompt/confirm before enabling
 // the stop dialog checkbox.
 #define DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT 3 // 3 sec
 
 // Maximum number of successive dialogs before we prompt users to disable
@@ -268,16 +272,19 @@ class nsGlobalWindow : public nsPIDOMWin
                        public nsSupportsWeakReference,
                        public nsIInterfaceRequestor,
                        public nsWrapperCache,
                        public PRCListStr,
                        public nsIDOMWindowPerformance,
                        public nsITouchEventReceiver,
                        public nsIInlineEventHandlers,
                        public nsIWindowCrypto
+#ifdef MOZ_B2G
+                     , public nsIDOMWindowB2G
+#endif // MOZ_B2G
 {
 public:
   friend class nsDOMMozURLProperty;
 
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
   typedef mozilla::dom::Navigator Navigator;
   typedef nsDataHashtable<nsUint64HashKey, nsGlobalWindow*> WindowByIdTable;
@@ -317,16 +324,21 @@ public:
   virtual bool IsBlackForCC();
 
   // nsIScriptObjectPrincipal
   virtual nsIPrincipal* GetPrincipal();
 
   // nsIDOMWindow
   NS_DECL_NSIDOMWINDOW
 
+#ifdef MOZ_B2G
+  // nsIDOMWindowB2G
+  NS_DECL_NSIDOMWINDOWB2G
+#endif // MOZ_B2G
+
   // nsIDOMWindowPerformance
   NS_DECL_NSIDOMWINDOWPERFORMANCE
 
   // nsIDOMJSWindow
   NS_DECL_NSIDOMJSWINDOW
 
   // nsIDOMEventTarget
   NS_DECL_NSIDOMEVENTTARGET
@@ -541,18 +553,20 @@ public:
   virtual nsresult DispatchSyncPopState();
 
   virtual void EnableDeviceSensor(uint32_t aType);
   virtual void DisableDeviceSensor(uint32_t aType);
 
   virtual void EnableTimeChangeNotifications();
   virtual void DisableTimeChangeNotifications();
 
+#ifdef MOZ_B2G
   virtual void EnableNetworkEvent(uint32_t aType);
   virtual void DisableNetworkEvent(uint32_t aType);
+#endif // MOZ_B2G
 
   virtual nsresult SetArguments(nsIArray *aArguments, nsIPrincipal *aOrigin);
 
   static bool DOMWindowDumpEnabled();
 
   void MaybeForgiveSpamCount();
   bool IsClosedOrClosing() {
     return (mIsClosed ||
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -569,27 +569,29 @@ public:
   /**
    * Tell this window that it should remove itself from sensor change notifications.
    */
   virtual void DisableDeviceSensor(uint32_t aType) = 0;
 
   virtual void EnableTimeChangeNotifications() = 0;
   virtual void DisableTimeChangeNotifications() = 0;
 
+#ifdef MOZ_B2G
   /**
    * Tell the window that it should start to listen to the network event of the
    * given aType.
    */
   virtual void EnableNetworkEvent(uint32_t aType) = 0;
 
   /**
    * Tell the window that it should stop to listen to the network event of the
    * given aType.
    */
   virtual void DisableNetworkEvent(uint32_t aType) = 0;
+#endif // MOZ_B2G
 
   /**
    * Set a arguments for this window. This will be set on the window
    * right away (if there's an existing document) and it will also be
    * installed on the window when the next document is loaded. Each
    * language impl is responsible for converting to an array of args
    * as appropriate for that language.
    */
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -176,16 +176,25 @@ DOMInterfaces = {
 
 'DOMTokenList': {
     'nativeType': 'nsDOMTokenList',
     'binaryNames': {
         '__stringifier': 'Stringify'
     }
 },
 
+'DynamicsCompressorNode': [
+{
+    'resultNotAddRefed': [ 'threshold', 'knee', 'ratio',
+                           'reduction', 'attack', 'release' ],
+    'binaryNames': {
+        'release': 'getRelease'
+    }
+}],
+
 'Event': [
 {
     'workers': True,
 }],
 
 'EventListener': [
 {
     'workers': True,
--- a/dom/bluetooth/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/BluetoothHfpManager.cpp
@@ -20,17 +20,17 @@
 #include "nsContentUtils.h"
 #include "nsIAudioManager.h"
 #include "nsIObserverService.h"
 #include "nsIRadioInterfaceLayer.h"
 
 #include <unistd.h> /* usleep() */
 
 #define MOZSETTINGS_CHANGED_ID "mozsettings-changed"
-#define AUDIO_VOLUME_MASTER "audio.volume.master"
+#define AUDIO_VOLUME_MASTER "audio.volume.bt_sco"
 #define HANDSFREE_UUID mozilla::dom::bluetooth::BluetoothServiceUuidStr::Handsfree
 #define HEADSET_UUID mozilla::dom::bluetooth::BluetoothServiceUuidStr::Headset
 
 using namespace mozilla;
 using namespace mozilla::ipc;
 USING_BLUETOOTH_NAMESPACE
 
 /* CallState for sCINDItems[CINDType::CALL].value
@@ -595,27 +595,26 @@ BluetoothHfpManager::Connect(const nsASt
 
   nsString serviceUuidStr;
   if (aIsHandsfree) {
     serviceUuidStr = NS_ConvertUTF8toUTF16(HANDSFREE_UUID);
   } else {
     serviceUuidStr = NS_ConvertUTF8toUTF16(HEADSET_UUID);
   }
 
-  nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
+  mRunnable = aRunnable;
 
   nsresult rv = bs->GetSocketViaService(aDevicePath,
                                         serviceUuidStr,
                                         BluetoothSocketType::RFCOMM,
                                         true,
                                         true,
                                         this,
-                                        runnable);
+                                        mRunnable);
 
-  runnable.forget();
   return NS_FAILED(rv) ? false : true;
 }
 
 bool
 BluetoothHfpManager::Listen()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -897,16 +896,24 @@ BluetoothHfpManager::CallStateChanged(in
   }
 
   SetupCIND(aCallIndex, aCallState, false);
 }
 
 void
 BluetoothHfpManager::OnConnectSuccess()
 {
+  if (mRunnable) {
+    BluetoothReply* reply = new BluetoothReply(BluetoothReplySuccess(true));
+    mRunnable->SetReply(reply);
+    if (NS_FAILED(NS_DispatchToMainThread(mRunnable))) {
+      NS_WARNING("Failed to dispatch to main thread!");
+    }
+    mRunnable.forget();
+  }
   // Cache device path for NotifySettings() since we can't get socket address
   // when a headset disconnect with us
   GetSocketAddr(mDevicePath);
   mSocketStatus = GetConnectionStatus();
 
   nsCOMPtr<nsIRILContentHelper> ril =
     do_GetService("@mozilla.org/ril/content-helper;1");
   if (!ril) {
@@ -915,16 +922,27 @@ BluetoothHfpManager::OnConnectSuccess()
   ril->EnumerateCalls(mListener->GetCallback());
 
   NotifySettings();
 }
 
 void
 BluetoothHfpManager::OnConnectError()
 {
+  if (mRunnable) {
+    nsString errorStr;
+    errorStr.AssignLiteral("Failed to connect with a bluetooth headset!");
+    BluetoothReply* reply = new BluetoothReply(BluetoothReplyError(errorStr));
+    mRunnable->SetReply(reply);
+    if (NS_FAILED(NS_DispatchToMainThread(mRunnable))) {
+      NS_WARNING("Failed to dispatch to main thread!");
+    }
+    mRunnable.forget();
+  }
+
   CloseSocket();
   mSocketStatus = GetConnectionStatus();
   // If connecting for some reason didn't work, restart listening
   Listen();
 }
 
 void
 BluetoothHfpManager::OnDisconnect()
--- a/dom/bluetooth/BluetoothHfpManager.h
+++ b/dom/bluetooth/BluetoothHfpManager.h
@@ -52,13 +52,14 @@ private:
 
   int mCurrentVgs;
   int mCurrentCallIndex;
   bool mReceiveVgsFlag;
   nsString mDevicePath;
   enum mozilla::ipc::SocketConnectionStatus mSocketStatus;
   nsTArray<int> mCurrentCallStateArray;
   nsAutoPtr<BluetoothRilListener> mListener;
+  nsRefPtr<BluetoothReplyRunnable> mRunnable;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/BluetoothManager.cpp
+++ b/dom/bluetooth/BluetoothManager.cpp
@@ -261,11 +261,24 @@ BluetoothManager::Notify(const Bluetooth
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling manager signal: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
     NS_WARNING(warningMsg.get());
 #endif
   }
 }
 
+NS_IMETHODIMP
+BluetoothManager::IsConnected(uint16_t aProfileId, bool* aConnected)
+{
+  BluetoothService* bs = BluetoothService::Get();
+  if (!bs) {
+    NS_WARNING("BluetoothService not available!");
+    return NS_ERROR_FAILURE;
+  }
+
+  *aConnected = bs->IsConnected(aProfileId);
+  return NS_OK;
+}
 NS_IMPL_EVENT_HANDLER(BluetoothManager, enabled)
 NS_IMPL_EVENT_HANDLER(BluetoothManager, disabled)
 NS_IMPL_EVENT_HANDLER(BluetoothManager, adapteradded)
+
--- a/dom/bluetooth/BluetoothOppManager.cpp
+++ b/dom/bluetooth/BluetoothOppManager.cpp
@@ -154,19 +154,20 @@ private:
 BluetoothOppManager::BluetoothOppManager() : mConnected(false)
                                            , mConnectionId(1)
                                            , mLastCommand(0)
                                            , mRemoteObexVersion(0)
                                            , mRemoteConnectionFlags(0)
                                            , mRemoteMaxPacketLength(0)
                                            , mAbortFlag(false)
                                            , mPacketLeftLength(0)
-                                           , mReceiving(false)
                                            , mPutFinal(false)
                                            , mWaitingForConfirmationFlag(false)
+                                           , mReceivedDataBufferOffset(0)
+                                           , mBodySegmentLength(0)
 {
   mConnectedDeviceAddress.AssignLiteral("00:00:00:00:00:00");
   mSocketStatus = GetConnectionStatus();
 }
 
 BluetoothOppManager::~BluetoothOppManager()
 {
 }
@@ -283,57 +284,65 @@ BluetoothOppManager::StopSendingFile()
 
 bool
 BluetoothOppManager::ConfirmReceivingFile(bool aConfirm)
 {
   if (!mWaitingForConfirmationFlag) {
     NS_WARNING("We are not waiting for a confirmation now.");
     return false;
   }
+  mWaitingForConfirmationFlag = false;
 
   NS_ASSERTION(mPacketLeftLength == 0,
                "Should not be in the middle of receiving a PUT packet.");
 
-  mWaitingForConfirmationFlag = false;
-  ReplyToPut(mPutFinal, aConfirm);
-
-  if (aConfirm) {
+  if (!aConfirm) {
+    DeleteReceivedFile();
+    FileTransferComplete(mConnectedDeviceAddress, false, true, sFileName,
+                         sSentFileLength, sContentType);
+    ReplyToPut(mPutFinal, false);
+  } else {
     StartFileTransfer(mConnectedDeviceAddress, true,
                       sFileName, sFileLength, sContentType);
-  } else {
-    DeleteReceivedFile();
-  }
+
+    bool success = WriteToFile(mBodySegment.get(), mBodySegmentLength);
+    ReplyToPut(mPutFinal, success);
 
-  if (mPutFinal || !aConfirm) {
-    mReceiving = false;
-    FileTransferComplete(mConnectedDeviceAddress, aConfirm, true, sFileName,
-                         sSentFileLength, sContentType);
+    if (!success) {
+      DeleteReceivedFile();
+      FileTransferComplete(mConnectedDeviceAddress, false, true, sFileName,
+                           sSentFileLength, sContentType);
+    } else if (mPutFinal) {
+      FileTransferComplete(mConnectedDeviceAddress, true, true, sFileName,
+                           sSentFileLength, sContentType);
+    }
   }
 
   return true;
 }
 
 void
 BluetoothOppManager::AfterOppConnected()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mConnected = true;
   mUpdateProgressCounter = 1;
   sSentFileLength = 0;
+  mReceivedDataBufferOffset = 0;
   mAbortFlag = false;
+  mWaitingForConfirmationFlag = true;
 }
 
 void
 BluetoothOppManager::AfterOppDisconnected()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mConnected = false;
-  mReceiving = false;
   mLastCommand = 0;
   mBlob = nullptr;
 
   if (mInputStream) {
     mInputStream->Close();
     mInputStream = nullptr;
   }
 
@@ -367,16 +376,72 @@ BluetoothOppManager::DeleteReceivedFile(
   if (mOutputStream) {
     mOutputStream->Close();
     mOutputStream = nullptr;
   }
 
   f->Remove(false);
 }
 
+bool
+BluetoothOppManager::CreateFile()
+{
+  nsString path;
+  path.AssignLiteral(TARGET_FOLDER);
+
+  MOZ_ASSERT(mPacketLeftLength == 0);
+
+  nsCOMPtr<nsIFile> f;
+  nsresult rv;
+  rv = NS_NewLocalFile(path + sFileName, false, getter_AddRefs(f));
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Couldn't new a local file");
+    return false;
+  }
+
+  rv = f->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 00644);
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Couldn't create the file");
+    return false;
+  }
+
+  /*
+   * The function CreateUnique() may create a file with a different file
+   * name from the original sFileName. Therefore we have to retrieve
+   * the file name again.
+   */
+  f->GetLeafName(sFileName);
+
+  NS_NewLocalFileOutputStream(getter_AddRefs(mOutputStream), f);
+  if (!mOutputStream) {
+    NS_WARNING("Couldn't new an output stream");
+    return false;
+  }
+
+  return true;
+}
+
+bool
+BluetoothOppManager::WriteToFile(const uint8_t* aData, int aDataLength)
+{
+  if (!mOutputStream) {
+    NS_WARNING("No available output stream");
+    return false;
+  }
+
+  uint32_t wrote = 0;
+  mOutputStream->Write((const char*)aData, aDataLength, &wrote);
+  if (aDataLength != wrote) {
+    NS_WARNING("Writing to the file failed");
+    return false;
+  }
+
+  return true;
+}
+
 // Virtual function of class SocketConsumer
 void
 BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
 {
   uint8_t opCode;
   int packetLength;
   int receivedLength = aMessage->mSize;
 
@@ -508,143 +573,121 @@ BluetoothOppManager::ReceiveSocketData(U
   } else {
     // Remote request or unknown mLastCommand
     ObexHeaderSet pktHeaders(opCode);
 
     if (opCode == ObexRequestCode::Connect) {
       // Section 3.3.1 "Connect", IrOBEX 1.2
       // [opcode:1][length:2][version:1][flags:1][MaxPktSizeWeCanReceive:2]
       // [Headers:var]
-      ParseHeadersAndFindBody(&aMessage->mData[7],
-                              receivedLength - 7,
-                              &pktHeaders);
+      ParseHeaders(&aMessage->mData[7],
+                   receivedLength - 7,
+                   &pktHeaders);
       ReplyToConnect();
       AfterOppConnected();
     } else if (opCode == ObexRequestCode::Disconnect) {
       // Section 3.3.2 "Disconnect", IrOBEX 1.2
       // [opcode:1][length:2][Headers:var]
-      ParseHeadersAndFindBody(&aMessage->mData[3],
-                              receivedLength - 3,
-                              &pktHeaders);
+      ParseHeaders(&aMessage->mData[3],
+                  receivedLength - 3,
+                  &pktHeaders);
       ReplyToDisconnect();
       AfterOppDisconnected();
     } else if (opCode == ObexRequestCode::Put ||
                opCode == ObexRequestCode::PutFinal) {
-      // Section 3.3.3 "Put", IrOBEX 1.2
-      // [opcode:1][length:2][Headers:var]
-      int headerStartIndex = 3;
-
-      if (!mReceiving) {
-        nsString path;
-        path.AssignLiteral(TARGET_FOLDER);
-
-        MOZ_ASSERT(mPacketLeftLength == 0);
-        ParseHeadersAndFindBody(&aMessage->mData[headerStartIndex],
-                                receivedLength - headerStartIndex,
-                                &pktHeaders);
+      int headerStartIndex = 0;
 
-        pktHeaders.GetName(sFileName);
-        pktHeaders.GetContentType(sContentType);
-        pktHeaders.GetLength(&sFileLength);
+      if (mReceivedDataBufferOffset == 0) {
+        // Section 3.3.3 "Put", IrOBEX 1.2
+        // [opcode:1][length:2][Headers:var]
+        headerStartIndex = 3;
 
-        nsCOMPtr<nsIFile> f;
-        nsresult rv;
-        rv = NS_NewLocalFile(path + sFileName, false, getter_AddRefs(f));
-        if (NS_FAILED(rv)) {
-          NS_WARNING("Couldn't new a local file");
-        }
-
-        rv = f->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 00644);
-        if (NS_FAILED(rv)) {
-          NS_WARNING("Couldn't create the file");
-        }
+        // The largest buffer size is 65535 because packetLength is a
+        // 2-byte value (0 ~ 0xFFFF).
+        mReceivedDataBuffer = new uint8_t[packetLength];
+        mPacketLeftLength = packetLength;
 
         /*
-         * The function CreateUnique() may create a file with a different file
-         * name from the original sFileName. Therefore we have to retrieve
-         * the file name again.
+         * A PUT request from remote devices may be divided into multiple parts.
+         * In other words, one request may need to be received multiple times,
+         * so here we keep a variable mPacketLeftLength to indicate if current
+         * PUT request is done.
          */
-        f->GetLeafName(sFileName);
-
-        NS_NewLocalFileOutputStream(getter_AddRefs(mOutputStream), f);
-        if (!mOutputStream) {
-          NS_WARNING("Couldn't new an output stream");
-        }
-
-        mReceiving = true;
-        mWaitingForConfirmationFlag = true;
+        mPutFinal = (opCode == ObexRequestCode::PutFinal);
       }
 
-      /*
-       * A PUT request from remote devices may be divided into multiple parts.
-       * In other words, one request may need to be received multiple times,
-       * so here we keep a variable mPacketLeftLength to indicate if current
-       * PUT request is done.
-       */
-      mPutFinal = (opCode == ObexRequestCode::PutFinal);
-
-      uint32_t wrote = 0;
-      if (mPacketLeftLength == 0) {
-        NS_ASSERTION(packetLength >= receivedLength,
-                     "Invalid packet length");
-        mPacketLeftLength = packetLength - receivedLength;
-
-        int headerBodyOffset =
-          ParseHeadersAndFindBody(&aMessage->mData[headerStartIndex],
-                                  receivedLength - headerStartIndex,
-                                  &pktHeaders);
+      memcpy(mReceivedDataBuffer.get() + mReceivedDataBufferOffset,
+             &aMessage->mData[headerStartIndex],
+             receivedLength - headerStartIndex);
 
-        if (headerBodyOffset != -1) {
-          /*
-           * Adding by 3 is because the format of a header is like:
-           *     [HeaderId:1 (BODY)][HeaderLength:2][Data:n]
-           * and headerStartIndex + headerBodyOffset points to HeaderId,
-           * so adding 3 is to point to the beginning of data.
-           *
-           */
-          int fileBodyIndex = headerStartIndex + headerBodyOffset + 3;
-
-          mOutputStream->Write((char*)&aMessage->mData[fileBodyIndex],
-                               receivedLength - fileBodyIndex, &wrote);
-          NS_ASSERTION(receivedLength - fileBodyIndex == wrote,
-                       "Writing to the file failed");
-        }
-      } else {
-        NS_ASSERTION(mPacketLeftLength >= receivedLength,
-                     "Invalid packet length");
-        mPacketLeftLength -= receivedLength;
-
-        mOutputStream->Write((char*)&aMessage->mData[0],
-                             receivedLength,
-                             &wrote);
-        NS_ASSERTION(receivedLength == wrote, "Writing to the file failed");
-      }
-
-      sSentFileLength += wrote;
-      if (sSentFileLength > kUpdateProgressBase * mUpdateProgressCounter &&
-          !mWaitingForConfirmationFlag) {
-        UpdateProgress(mConnectedDeviceAddress, true,
-                       sSentFileLength, sFileLength);
-        mUpdateProgressCounter = sSentFileLength / kUpdateProgressBase + 1;
-      }
+      mPacketLeftLength -= receivedLength;
+      mReceivedDataBufferOffset += receivedLength - headerStartIndex;
 
       if (mPacketLeftLength == 0) {
+        ParseHeaders(mReceivedDataBuffer.get(),
+                     mReceivedDataBufferOffset,
+                     &pktHeaders);
+
+        if (pktHeaders.Has(ObexHeaderId::Name)) {
+          pktHeaders.GetName(sFileName);
+        }
+
+        if (pktHeaders.Has(ObexHeaderId::Type)) {
+          pktHeaders.GetContentType(sContentType);
+        }
+
+        if (pktHeaders.Has(ObexHeaderId::Length)) {
+          pktHeaders.GetLength(&sFileLength);
+        }
+
+        if (pktHeaders.Has(ObexHeaderId::Body) ||
+            pktHeaders.Has(ObexHeaderId::EndOfBody)) {
+          uint8_t* bodyPtr;
+          pktHeaders.GetBody(&bodyPtr);
+          mBodySegment = bodyPtr;
+
+          pktHeaders.GetBodyLength(&mBodySegmentLength);
+
+          if (!mWaitingForConfirmationFlag) {
+            if (!WriteToFile(mBodySegment.get(), mBodySegmentLength)) {
+              DeleteReceivedFile();
+              FileTransferComplete(mConnectedDeviceAddress,
+                                   false, true, sFileName,
+                                   sSentFileLength, sContentType);
+            }
+          }
+        }
+
+        mReceivedDataBufferOffset = 0;
+
         if (mWaitingForConfirmationFlag) {
-          ReceivingFileConfirmation(mConnectedDeviceAddress, sFileName,
-                                    sFileLength, sContentType);
+          // Note that we create file before sending system message here,
+          // so that the correct file name will be used.
+          if (!CreateFile()) {
+            ReplyToPut(mPutFinal, false);
+          } else {
+            ReceivingFileConfirmation(mConnectedDeviceAddress, sFileName,
+                                      sFileLength, sContentType);
+          }
         } else {
-          ReplyToPut(mPutFinal, mAbortFlag ? false : true);
+          ReplyToPut(mPutFinal, !mAbortFlag);
+
+          // Send progress notification
+          sSentFileLength += mBodySegmentLength;
+          if (sSentFileLength > kUpdateProgressBase * mUpdateProgressCounter) {
+            UpdateProgress(mConnectedDeviceAddress, true,
+                           sSentFileLength, sFileLength);
+            mUpdateProgressCounter = sSentFileLength / kUpdateProgressBase + 1;
+          }
 
           if (mAbortFlag) {
-            mReceiving = false;
             FileTransferComplete(mConnectedDeviceAddress, false, true,
                                  sFileName, sSentFileLength, sContentType);
             DeleteReceivedFile();
           } else if (mPutFinal) {
-            mReceiving = false;
             FileTransferComplete(mConnectedDeviceAddress, true, true,
                                  sFileName, sSentFileLength, sContentType);
           }
         }
       }
     }
   }
 }
--- a/dom/bluetooth/BluetoothOppManager.h
+++ b/dom/bluetooth/BluetoothOppManager.h
@@ -78,16 +78,18 @@ private:
   void UpdateProgress(const nsString& aDeviceAddress,
                       bool aReceived,
                       uint32_t aProcessedLength,
                       uint32_t aFileLength);
   void ReceivingFileConfirmation(const nsString& aAddress,
                                  const nsString& aFileName,
                                  uint32_t aFileLength,
                                  const nsString& aContentType);
+  bool CreateFile();
+  bool WriteToFile(const uint8_t* aData, int aDataLength);
   void DeleteReceivedFile();
   void ReplyToConnect();
   void ReplyToDisconnect();
   void ReplyToPut(bool aFinal, bool aContinue);
   void AfterOppConnected();
   void AfterOppDisconnected();
   virtual void OnConnectSuccess() MOZ_OVERRIDE;
   virtual void OnConnectError() MOZ_OVERRIDE;
@@ -96,23 +98,27 @@ private:
   bool mConnected;
   int mConnectionId;
   int mLastCommand;
   uint8_t mRemoteObexVersion;
   uint8_t mRemoteConnectionFlags;
   int mRemoteMaxPacketLength;
   bool mAbortFlag;
   int mPacketLeftLength;
+  int mBodySegmentLength;
+  int mReceivedDataBufferOffset;
   nsString mConnectedDeviceAddress;
-  bool mReceiving;
   bool mPutFinal;
   bool mWaitingForConfirmationFlag;
   int mUpdateProgressCounter;
   enum mozilla::ipc::SocketConnectionStatus mSocketStatus;
 
+  nsAutoPtr<uint8_t> mBodySegment;
+  nsAutoPtr<uint8_t> mReceivedDataBuffer;
+
   nsCOMPtr<nsIDOMBlob> mBlob;
   nsCOMPtr<nsIThread> mReadFileThread;
   nsCOMPtr<nsIOutputStream> mOutputStream;
   nsCOMPtr<nsIInputStream> mInputStream;
 };
 
 END_BLUETOOTH_NAMESPACE
 
--- a/dom/bluetooth/BluetoothService.h
+++ b/dom/bluetooth/BluetoothService.h
@@ -268,16 +268,19 @@ public:
   Connect(const nsAString& aDeviceAddress,
           const nsAString& aAdapterPath,
           uint16_t aProfileId,
           BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual void
   Disconnect(uint16_t aProfileId, BluetoothReplyRunnable* aRunnable) = 0;
 
+  virtual bool
+  IsConnected(uint16_t aProfileId) = 0;
+
   virtual void
   SendFile(const nsAString& aDeviceAddress,
            BlobParent* aBlobParent,
            BlobChild* aBlobChild,
            BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual void
   StopSendingFile(const nsAString& aDeviceAddress,
--- a/dom/bluetooth/ObexBase.cpp
+++ b/dom/bluetooth/ObexBase.cpp
@@ -63,32 +63,25 @@ AppendHeaderConnectionId(uint8_t* aRetBu
 void
 SetObexPacketInfo(uint8_t* aRetBuf, uint8_t aOpcode, int aPacketLength)
 {
   aRetBuf[0] = aOpcode;
   aRetBuf[1] = (aPacketLength & 0xFF00) >> 8;
   aRetBuf[2] = aPacketLength & 0x00FF;
 }
 
-int
-ParseHeadersAndFindBody(uint8_t* aHeaderStart,
-                        int aTotalLength,
-                        ObexHeaderSet* aRetHandlerSet)
+void
+ParseHeaders(const uint8_t* aHeaderStart,
+             int aTotalLength,
+             ObexHeaderSet* aRetHandlerSet)
 {
-  uint8_t* ptr = aHeaderStart;
+  const uint8_t* ptr = aHeaderStart;
 
   while (ptr - aHeaderStart < aTotalLength) {
-    ObexHeaderId headerId = (ObexHeaderId)*ptr;
-
-    if (headerId == ObexHeaderId::Body ||
-        headerId == ObexHeaderId::EndOfBody) {
-      return ptr - aHeaderStart;
-    }
-
-    ++ptr;
+    ObexHeaderId headerId = (ObexHeaderId)*ptr++;
 
     int contentLength = 0;
     uint8_t highByte, lowByte;
 
     // Defined in 2.1 OBEX Headers, IrOBEX 1.2
     switch (headerId >> 6)
     {
       case 0x00:
@@ -113,13 +106,11 @@ ParseHeadersAndFindBody(uint8_t* aHeader
     }
 
     uint8_t* content = new uint8_t[contentLength];
     memcpy(content, ptr, contentLength);
     aRetHandlerSet->AddHeader(new ObexHeader(headerId, contentLength, content));
 
     ptr += contentLength;
   }
-
-  return -1;
 }
 
 END_BLUETOOTH_NAMESPACE
--- a/dom/bluetooth/ObexBase.h
+++ b/dom/bluetooth/ObexBase.h
@@ -184,26 +184,68 @@ public:
 
     for (int i = 0; i < length; ++i) {
       if (mHeaders[i]->mId == ObexHeaderId::Length) {
         uint8_t* ptr = mHeaders[i]->mData.get();
         *aRetLength = ((uint32_t)ptr[0] << 24) |
                       ((uint32_t)ptr[1] << 16) |
                       ((uint32_t)ptr[2] << 8) |
                       ((uint32_t)ptr[3]);
-        break;
+        return;
+      }
+    }
+  }
+
+  void GetBodyLength(int* aRetBodyLength)
+  {
+    int length = mHeaders.Length();
+    *aRetBodyLength = 0;
+
+    for (int i = 0; i < length; ++i) {
+      if (mHeaders[i]->mId == ObexHeaderId::Body ||
+          mHeaders[i]->mId == ObexHeaderId::EndOfBody) {
+        *aRetBodyLength = mHeaders[i]->mDataLength;
+        return;
       }
     }
   }
+
+  void GetBody(uint8_t** aRetBody)
+  {
+    int length = mHeaders.Length();
+    *aRetBody = nullptr;
+
+    for (int i = 0; i < length; ++i) {
+      if (mHeaders[i]->mId == ObexHeaderId::Body ||
+          mHeaders[i]->mId == ObexHeaderId::EndOfBody) {
+        uint8_t* ptr = mHeaders[i]->mData.get();
+        *aRetBody = new uint8_t[mHeaders[i]->mDataLength];
+        memcpy(*aRetBody, ptr, mHeaders[i]->mDataLength);
+        return;
+      }
+    }
+  }
+
+  bool Has(ObexHeaderId aId)
+  {
+    int length = mHeaders.Length();
+    for (int i = 0; i < length; ++i) {
+      if (mHeaders[i]->mId == aId) {
+        return true;
+      }
+    }
+
+    return false;
+  }
 };
 
 int AppendHeaderName(uint8_t* aRetBuf, const char* aName, int aLength);
 int AppendHeaderBody(uint8_t* aRetBuf, uint8_t* aData, int aLength);
 int AppendHeaderLength(uint8_t* aRetBuf, int aObjectLength);
 int AppendHeaderConnectionId(uint8_t* aRetBuf, int aConnectionId);
 void SetObexPacketInfo(uint8_t* aRetBuf, uint8_t aOpcode, int aPacketLength);
-int ParseHeadersAndFindBody(uint8_t* aHeaderStart,
-                            int aTotalLength,
-                            ObexHeaderSet* aRetHanderSet);
+void ParseHeaders(const uint8_t* aHeaderStart,
+                  int aTotalLength,
+                  ObexHeaderSet* aRetHanderSet);
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
+++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
@@ -386,8 +386,15 @@ BluetoothServiceChildProcess::StartInter
 }
 
 nsresult
 BluetoothServiceChildProcess::StopInternal()
 {
   MOZ_NOT_REACHED("This should never be called!");
   return NS_ERROR_FAILURE;
 }
+
+bool
+BluetoothServiceChildProcess::IsConnected(uint16_t aProfileId)
+{
+  MOZ_NOT_REACHED("This should never be called!");
+  return false;
+}
--- a/dom/bluetooth/ipc/BluetoothServiceChildProcess.h
+++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.h
@@ -134,16 +134,19 @@ public:
           const nsAString& aAdapterPath,
           const uint16_t aProfileId,
           BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual void
   Disconnect(const uint16_t aProfileId,
              BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
+  virtual bool
+  IsConnected(uint16_t aProfileId) MOZ_OVERRIDE;
+
   virtual void
   SendFile(const nsAString& aDeviceAddress,
            BlobParent* aBlobParent,
            BlobChild* aBlobChild,
            BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual void
   StopSendingFile(const nsAString& aDeviceAddress,
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -2382,16 +2382,33 @@ BluetoothDBusService::Disconnect(const u
   // Currently, just fire success because Disconnect() doesn't fail, 
   // but we still make aRunnable pass into this function for future
   // once Disconnect will fail.
   nsString replyError;
   BluetoothValue v = true;
   DispatchBluetoothReply(aRunnable, v, replyError);
 }
 
+bool
+BluetoothDBusService::IsConnected(const uint16_t aProfileId)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
+
+  if (aProfileId == (uint16_t)(BluetoothServiceUuid::Handsfree >> 32)
+      || aProfileId == (uint16_t)(BluetoothServiceUuid::Headset >> 32)) {
+    BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
+    return hfp->GetConnectionStatus() == SocketConnectionStatus::SOCKET_CONNECTED;
+  } else if (aProfileId == (uint16_t)(BluetoothServiceUuid::ObjectPush >> 32)) {
+    BluetoothOppManager* opp = BluetoothOppManager::Get();
+    return opp->GetConnectionStatus() == SocketConnectionStatus::SOCKET_CONNECTED;
+  }
+
+  return false;
+}
+
 class ConnectBluetoothSocketRunnable : public nsRunnable
 {
 public:
   ConnectBluetoothSocketRunnable(BluetoothReplyRunnable* aRunnable,
                                  UnixSocketConsumer* aConsumer,
                                  const nsAString& aObjectPath,
                                  const nsAString& aServiceUUID,
                                  BluetoothSocketType aType,
@@ -2419,20 +2436,16 @@ public:
     nsString replyError;
     BluetoothUnixSocketConnector* c =
       new BluetoothUnixSocketConnector(mType, mChannel, mAuth, mEncrypt);
     if (!mConsumer->ConnectSocket(c, NS_ConvertUTF16toUTF8(address).get())) {
       replyError.AssignLiteral("SocketConnectionError");
       DispatchBluetoothReply(mRunnable, v, replyError);
       return NS_ERROR_FAILURE;
     }
-    // Bluetooth value needs to be set to something to succeed.
-    v = true;
-    DispatchBluetoothReply(mRunnable, v, replyError);
-
     return NS_OK;
   }
 
 private:
   nsRefPtr<BluetoothReplyRunnable> mRunnable;
   nsRefPtr<UnixSocketConsumer> mConsumer;
   nsString mObjectPath;
   nsString mServiceUUID;
--- a/dom/bluetooth/linux/BluetoothDBusService.h
+++ b/dom/bluetooth/linux/BluetoothDBusService.h
@@ -134,16 +134,19 @@ public:
   PrepareAdapterInternal(const nsAString& aPath);
 
   virtual bool
   Connect(const nsAString& aDeviceAddress,
           const nsAString& aAdapterPath,
           const uint16_t aProfileId,
           BluetoothReplyRunnable* aRunnable);
 
+  virtual bool
+  IsConnected(uint16_t aProfileId);
+
   virtual void
   Disconnect(const uint16_t aProfileId, BluetoothReplyRunnable* aRunnable);
 
   virtual void
   SendFile(const nsAString& aDeviceAddress,
            BlobParent* aBlobParent,
            BlobChild* aBlobChild,
            BluetoothReplyRunnable* aRunnable);
--- a/dom/bluetooth/nsIDOMBluetoothManager.idl
+++ b/dom/bluetooth/nsIDOMBluetoothManager.idl
@@ -4,19 +4,21 @@
  * 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 "nsIDOMEventTarget.idl"
 
 interface nsIDOMDOMRequest;
 interface nsIDOMBluetoothAdapter;
 
-[scriptable, builtinclass, uuid(d27ec867-949f-4585-b718-d2352e420ec6)]
+[scriptable, builtinclass, uuid(3300693f-ae91-4a3f-b887-bf502c6a97ee)]
 interface nsIDOMBluetoothManager : nsIDOMEventTarget
 {
   readonly attribute bool enabled;
 
   nsIDOMDOMRequest getDefaultAdapter();
 
+  bool isConnected(in unsigned short aProfile);
+
   [implicit_jscontext] attribute jsval onenabled;
   [implicit_jscontext] attribute jsval ondisabled;
   [implicit_jscontext] attribute jsval onadapteradded;
 };
--- a/dom/camera/GonkNativeWindow.cpp
+++ b/dom/camera/GonkNativeWindow.cpp
@@ -440,16 +440,17 @@ int GonkNativeWindow::cancelBuffer(ANati
     mSlots[buf].mFrameNumber = 0;
     mDequeueCondition.signal();
     return OK;
 }
 
 int GonkNativeWindow::perform(int operation, va_list args)
 {
     switch (operation) {
+        case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
         case NATIVE_WINDOW_SET_BUFFERS_SIZE:
         case NATIVE_WINDOW_SET_SCALING_MODE:
         case NATIVE_WINDOW_SET_CROP:
         case NATIVE_WINDOW_CONNECT:
         case NATIVE_WINDOW_DISCONNECT:
             // deprecated. must return NO_ERROR.
             return NO_ERROR;
         case NATIVE_WINDOW_SET_USAGE:
@@ -459,22 +460,22 @@ int GonkNativeWindow::perform(int operat
         case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
             return dispatchSetBuffersGeometry(args);
         case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
             return dispatchSetBuffersTimestamp(args);
         case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
             return dispatchSetBuffersDimensions(args);
         case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
             return dispatchSetBuffersFormat(args);
-        case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
         case NATIVE_WINDOW_LOCK:
         case NATIVE_WINDOW_UNLOCK_AND_POST:
         case NATIVE_WINDOW_API_CONNECT:
         case NATIVE_WINDOW_API_DISCONNECT:
         default:
+            NS_WARNING("Unsupported operation");
             return INVALID_OPERATION;
     }
 }
 
 int GonkNativeWindow::query(int what, int* outValue) const
 {
     Mutex::Autolock lock(mMutex);
 
--- a/dom/encoding/EncodingUtils.cpp
+++ b/dom/encoding/EncodingUtils.cpp
@@ -1,337 +1,72 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/EncodingUtils.h"
-#include "nsAutoPtr.h"
-#include "nsContentUtils.h"
+#include "nsUConvPropertySearch.h"
 
 namespace mozilla {
 namespace dom {
 
-EncodingUtils* gEncodings = nullptr;
-
-struct LabelEncoding
-{
-  const char* mLabel;
-  const char* mEncoding;
+static const char* labelsEncodings[][3] = {
+#include "labelsencodings.properties.h"
 };
 
-static const LabelEncoding labelsEncodings[] = {
-  {"unicode-1-1-utf-8", "utf-8"},
-  {"utf-8", "utf-8"},
-  {"utf8", "utf-8"},
-  {"866", "ibm866"},
-  {"cp866", "ibm866"},
-  {"csibm866", "ibm866"},
-  {"ibm866", "ibm866"},
-  {"csisolatin2", "iso-8859-2"},
-  {"iso-8859-2", "iso-8859-2"},
-  {"iso-ir-101", "iso-8859-2"},
-  {"iso8859-2", "iso-8859-2"},
-  {"iso88592", "iso-8859-2"},
-  {"iso_8859-2", "iso-8859-2"},
-  {"iso_8859-2:1987", "iso-8859-2"},
-  {"l2", "iso-8859-2"},
-  {"latin2", "iso-8859-2"},
-  {"csisolatin3", "iso-8859-3"},
-  {"iso-8859-3", "iso-8859-3"},
-  {"iso-ir-109", "iso-8859-3"},
-  {"iso8859-3", "iso-8859-3"},
-  {"iso88593", "iso-8859-3"},
-  {"iso_8859-3", "iso-8859-3"},
-  {"iso_8859-3:1988", "iso-8859-3"},
-  {"l3", "iso-8859-3"},
-  {"latin3", "iso-8859-3"},
-  {"csisolatin4", "iso-8859-4"},
-  {"iso-8859-4", "iso-8859-4"},
-  {"iso-ir-110", "iso-8859-4"},
-  {"iso8859-4", "iso-8859-4"},
-  {"iso88594", "iso-8859-4"},
-  {"iso_8859-4", "iso-8859-4"},
-  {"iso_8859-4:1988", "iso-8859-4"},
-  {"l4", "iso-8859-4"},
-  {"latin4", "iso-8859-4"},
-  {"csisolatincyrillic", "iso-8859-5"},
-  {"cyrillic", "iso-8859-5"},
-  {"iso-8859-5", "iso-8859-5"},
-  {"iso-ir-144", "iso-8859-5"},
-  {"iso8859-5", "iso-8859-5"},
-  {"iso88595", "iso-8859-5"},
-  {"iso_8859-5", "iso-8859-5"},
-  {"iso_8859-5:1988", "iso-8859-5"},
-  {"arabic", "iso-8859-6"},
-  {"asmo-708", "iso-8859-6"},
-  {"csiso88596e", "iso-8859-6"},
-  {"csiso88596i", "iso-8859-6"},
-  {"csisolatinarabic", "iso-8859-6"},
-  {"ecma-114", "iso-8859-6"},
-  {"iso-8859-6", "iso-8859-6"},
-  {"iso-8859-6-e", "iso-8859-6"},
-  {"iso-8859-6-i", "iso-8859-6"},
-  {"iso-ir-127", "iso-8859-6"},
-  {"iso8859-6", "iso-8859-6"},
-  {"iso88596", "iso-8859-6"},
-  {"iso_8859-6", "iso-8859-6"},
-  {"iso_8859-6:1987", "iso-8859-6"},
-  {"csisolatingreek", "iso-8859-7"},
-  {"ecma-118", "iso-8859-7"},
-  {"elot_928", "iso-8859-7"},
-  {"greek", "iso-8859-7"},
-  {"greek8", "iso-8859-7"},
-  {"iso-8859-7", "iso-8859-7"},
-  {"iso-ir-126", "iso-8859-7"},
-  {"iso8859-7", "iso-8859-7"},
-  {"iso88597", "iso-8859-7"},
-  {"iso_8859-7", "iso-8859-7"},
-  {"iso_8859-7:1987", "iso-8859-7"},
-  {"sun_eu_greek", "iso-8859-7"},
-  {"csiso88598e", "iso-8859-8"},
-  {"csisolatinhebrew", "iso-8859-8"},
-  {"hebrew", "iso-8859-8"},
-  {"iso-8859-8", "iso-8859-8"},
-  {"iso-8859-8-e", "iso-8859-8"},
-  {"iso-ir-138", "iso-8859-8"},
-  {"iso8859-8", "iso-8859-8"},
-  {"iso88598", "iso-8859-8"},
-  {"iso_8859-8", "iso-8859-8"},
-  {"iso_8859-8:1988", "iso-8859-8"},
-  {"visual", "iso-8859-8"},
-  {"csiso88598i", "iso-8859-8-i"},
-  {"iso-8859-8-i", "iso-8859-8-i"},
-  {"logical", "iso-8859-8-i"},
-  {"csisolatin6", "iso-8859-10"},
-  {"iso-8859-10", "iso-8859-10"},
-  {"iso-ir-157", "iso-8859-10"},
-  {"iso8859-10", "iso-8859-10"},
-  {"iso885910", "iso-8859-10"},
-  {"l6", "iso-8859-10"},
-  {"latin6", "iso-8859-10"},
-  {"iso-8859-13", "iso-8859-13"},
-  {"iso8859-13", "iso-8859-13"},
-  {"iso885913", "iso-8859-13"},
-  {"iso-8859-14", "iso-8859-14"},
-  {"iso8859-14", "iso-8859-14"},
-  {"iso885914", "iso-8859-14"},
-  {"csisolatin9", "iso-8859-15"},
-  {"iso-8859-15", "iso-8859-15"},
-  {"iso8859-15", "iso-8859-15"},
-  {"iso885915", "iso-8859-15"},
-  {"iso_8859-15", "iso-8859-15"},
-  {"l9", "iso-8859-15"},
-  {"iso-8859-16", "iso-8859-16"},
-  {"cskoi8r", "koi8-r"},
-  {"koi", "koi8-r"},
-  {"koi8", "koi8-r"},
-  {"koi8-r", "koi8-r"},
-  {"koi8_r", "koi8-r"},
-  {"koi8-u", "koi8-u"},
-  {"csmacintosh", "macintosh"},
-  {"mac", "macintosh"},
-  {"macintosh", "macintosh"},
-  {"x-mac-roman", "macintosh"},
-  {"dos-874", "windows-874"},
-  {"iso-8859-11", "windows-874"},
-  {"iso8859-11", "windows-874"},
-  {"iso885911", "windows-874"},
-  {"tis-620", "windows-874"},
-  {"windows-874", "windows-874"},
-  {"cp1250", "windows-1250"},
-  {"windows-1250", "windows-1250"},
-  {"x-cp1250", "windows-1250"},
-  {"cp1251", "windows-1251"},
-  {"windows-1251", "windows-1251"},
-  {"x-cp1251", "windows-1251"},
-  {"ansi_x3.4-1968", "windows-1252"},
-  {"ascii", "windows-1252"},
-  {"cp1252", "windows-1252"},
-  {"cp819", "windows-1252"},
-  {"csisolatin1", "windows-1252"},
-  {"ibm819", "windows-1252"},
-  {"iso-8859-1", "windows-1252"},
-  {"iso-ir-100", "windows-1252"},
-  {"iso8859-1", "windows-1252"},
-  {"iso88591", "windows-1252"},
-  {"iso_8859-1", "windows-1252"},
-  {"iso_8859-1:1987", "windows-1252"},
-  {"l1", "windows-1252"},
-  {"latin1", "windows-1252"},
-  {"us-ascii", "windows-1252"},
-  {"windows-1252", "windows-1252"},
-  {"x-cp1252", "windows-1252"},
-  {"cp1253", "windows-1253"},
-  {"windows-1253", "windows-1253"},
-  {"x-cp1253", "windows-1253"},
-  {"cp1254", "windows-1254"},
-  {"csisolatin5", "windows-1254"},
-  {"iso-8859-9", "windows-1254"},
-  {"iso-ir-148", "windows-1254"},
-  {"iso8859-9", "windows-1254"},
-  {"iso88599", "windows-1254"},
-  {"iso_8859-9", "windows-1254"},
-  {"iso_8859-9:1989", "windows-1254"},
-  {"l5", "windows-1254"},
-  {"latin5", "windows-1254"},
-  {"windows-1254", "windows-1254"},
-  {"x-cp1254", "windows-1254"},
-  {"cp1255", "windows-1255"},
-  {"windows-1255", "windows-1255"},
-  {"x-cp1255", "windows-1255"},
-  {"cp1256", "windows-1256"},
-  {"windows-1256", "windows-1256"},
-  {"x-cp1256", "windows-1256"},
-  {"cp1257", "windows-1257"},
-  {"windows-1257", "windows-1257"},
-  {"x-cp1257", "windows-1257"},
-  {"cp1258", "windows-1258"},
-  {"windows-1258", "windows-1258"},
-  {"x-cp1258", "windows-1258"},
-  {"x-mac-cyrillic", "x-mac-cyrillic"},
-  {"x-mac-ukrainian", "x-mac-cyrillic"},
-  {"chinese", "gbk"},
-  {"csgb2312", "gbk"},
-  {"csiso58gb231280", "gbk"},
-  {"gb2312", "gbk"},
-  {"gb_2312", "gbk"},
-  {"gb_2312-80", "gbk"},
-  {"gbk", "gbk"},
-  {"iso-ir-58", "gbk"},
-  {"x-gbk", "gbk"},
-  {"gb18030", "gb18030"},
-  {"hz-gb-2312", "hz-gb-2312"},
-  {"big5", "big5"},
-  {"big5-hkscs", "big5"},
-  {"cn-big5", "big5"},
-  {"csbig5", "big5"},
-  {"x-x-big5", "big5"},
-  {"cseucpkdfmtjapanese", "euc-jp"},
-  {"euc-jp", "euc-jp"},
-  {"x-euc-jp", "euc-jp"},
-  {"csiso2022jp", "iso-2022-jp"},
-  {"iso-2022-jp", "iso-2022-jp"},
-  {"csshiftjis", "shift_jis"},
-  {"ms_kanji", "shift_jis"},
-  {"shift-jis", "shift_jis"},
-  {"shift_jis", "shift_jis"},
-  {"sjis", "shift_jis"},
-  {"windows-31j", "shift_jis"},
-  {"x-sjis", "shift_jis"},
-  {"cseuckr", "euc-kr"},
-  {"csksc56011987", "euc-kr"},
-  {"euc-kr", "euc-kr"},
-  {"iso-ir-149", "euc-kr"},
-  {"korean", "euc-kr"},
-  {"ks_c_5601-1987", "euc-kr"},
-  {"ks_c_5601-1989", "euc-kr"},
-  {"ksc5601", "euc-kr"},
-  {"ksc_5601", "euc-kr"},
-  {"windows-949", "euc-kr"},
-  {"csiso2022kr", "iso-2022-kr"},
-  {"iso-2022-kr", "iso-2022-kr"},
-  {"utf-16", "utf-16le"},
-  {"utf-16le", "utf-16le"},
-  {"utf-16be", "utf-16be"},
-  {"x-user-defined", "x-user-defined"},
-};
-
-EncodingUtils::EncodingUtils()
-{
-  MOZ_ASSERT(!gEncodings);
-
-  const uint32_t numLabels = ArrayLength(labelsEncodings);
-  mLabelsEncodings.Init(numLabels);
-
-  for (uint32_t i = 0; i < numLabels; i++) {
-    mLabelsEncodings.Put(NS_ConvertASCIItoUTF16(labelsEncodings[i].mLabel),
-                         labelsEncodings[i].mEncoding);
-  }
-}
-
-EncodingUtils::~EncodingUtils()
-{
-  MOZ_ASSERT(gEncodings && gEncodings == this);
-}
-
-void
-EncodingUtils::Shutdown()
-{
-  NS_IF_RELEASE(gEncodings);
-}
-
-already_AddRefed<EncodingUtils>
-EncodingUtils::GetOrCreate()
-{
-  if (!gEncodings) {
-    gEncodings = new EncodingUtils();
-    NS_ADDREF(gEncodings);
-  }
-  NS_ADDREF(gEncodings);
-  return gEncodings;
-}
-
 uint32_t
 EncodingUtils::IdentifyDataOffset(const char* aData,
                                   const uint32_t aLength,
-                                  const char*& aRetval)
+                                  nsACString& aRetval)
 {
   // Truncating to pre-clear return value in case of failure.
-  aRetval = "";
+  aRetval.Truncate();
 
   // Minimum bytes in input stream data that represents
   // the Byte Order Mark is 2. Max is 3.
   if (aLength < 2) {
     return 0;
   }
 
   if (aData[0] == '\xFF' && aData[1] == '\xFE') {
-    aRetval = "utf-16le";
+    aRetval.AssignLiteral("UTF-16LE");
     return 2;
   }
 
   if (aData[0] == '\xFE' && aData[1] == '\xFF') {
-    aRetval = "utf-16be";
+    aRetval.AssignLiteral("UTF-16BE");
     return 2;
   }
 
   // Checking utf-8 byte order mark.
   // Minimum bytes in input stream data that represents
   // the Byte Order Mark for utf-8 is 3.
   if (aLength < 3) {
     return 0;
   }
 
   if (aData[0] == '\xEF' && aData[1] == '\xBB' && aData[2] == '\xBF') {
-    aRetval = "utf-8";
+    aRetval.AssignLiteral("UTF-8");
     return 3;
   }
   return 0;
 }
 
 bool
-EncodingUtils::FindEncodingForLabel(const nsAString& aLabel,
-                                    const char*& aOutEncoding)
+EncodingUtils::FindEncodingForLabel(const nsACString& aLabel,
+                                    nsACString& aOutEncoding)
 {
-  nsRefPtr<EncodingUtils> self = EncodingUtils::GetOrCreate();
-  MOZ_ASSERT(self);
-
-  // Save aLabel first because it may be the same as aOutEncoding.
-  nsString label(aLabel);
-  // Truncating to clear aOutEncoding in case of failure.
-  aOutEncoding = EmptyCString().get();
+  // Save aLabel first because it may refer the same string as aOutEncoding.
+  nsCString label(aLabel);
 
   EncodingUtils::TrimSpaceCharacters(label);
   if (label.IsEmpty()) {
+    aOutEncoding.Truncate();
     return false;
   }
 
-  nsContentUtils::ASCIIToLower(label);
-  const char* encoding = self->mLabelsEncodings.Get(label);
-  if (!encoding) {
-    return false;
-  }
-  aOutEncoding = encoding;
-  return true;
+  ToLowerCase(label);
+  return NS_SUCCEEDED(nsUConvPropertySearch::SearchPropertyValue(
+      labelsEncodings, ArrayLength(labelsEncodings), label, aOutEncoding));
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/encoding/EncodingUtils.h
+++ b/dom/encoding/EncodingUtils.h
@@ -9,68 +9,72 @@
 #include "nsString.h"
 
 namespace mozilla {
 namespace dom {
 
 class EncodingUtils
 {
 public:
-  NS_INLINE_DECL_REFCOUNTING(EncodingUtils)
 
   /**
    * Implements decode algorithm's step 1 & 2 from Encoding spec.
    * http://encoding.spec.whatwg.org/#decode
+   * The returned name may not be lowercased due to compatibility with
+   * our internal implementations.
    *
    * @param     aData, incoming byte stream of data.
    * @param     aLength, incoming byte stream length.
    * @param     aRetval, outgoing encoding corresponding to valid data
    *            byte order mark.
    * @return    offset after the BOM bytes in byte stream
    *            where the actual data starts.
    */
   static uint32_t IdentifyDataOffset(const char* aData,
                                      const uint32_t aLength,
-                                     const char*& aRetval);
+                                     nsACString& aRetval);
 
   /**
    * Implements get an encoding algorithm from Encoding spec.
    * http://encoding.spec.whatwg.org/#concept-encoding-get
    * Given a label, this function returns the corresponding encoding or a
    * false.
+   * The returned name may not be lowercased due to compatibility with
+   * our internal implementations.
    *
    * @param      aLabel, incoming label describing charset to be decoded.
    * @param      aRetEncoding, returning corresponding encoding for label.
    * @return     false if no encoding was found for label.
    *             true if valid encoding found.
    */
+  static bool FindEncodingForLabel(const nsACString& aLabel,
+                                   nsACString& aOutEncoding);
+
   static bool FindEncodingForLabel(const nsAString& aLabel,
-                                   const char*& aOutEncoding);
+                                   nsACString& aOutEncoding)
+  {
+    return FindEncodingForLabel(NS_ConvertUTF16toUTF8(aLabel), aOutEncoding);
+  }
 
   /**
    * Remove any leading and trailing space characters, following the
    * definition of space characters from Encoding spec.
    * http://encoding.spec.whatwg.org/#terminology
    * Note that nsAString::StripWhitespace() doesn't exactly match the
    * definition. It also removes all matching chars in the string,
    * not just leading and trailing.
    *
    * @param      aString, string to be trimmed.
    */
-  static void TrimSpaceCharacters(nsString& aString)
+  template<class T>
+  static void TrimSpaceCharacters(T& aString)
   {
     aString.Trim(" \t\n\f\r");
   }
 
-  /* Called to free up Encoding instance. */
-  static void Shutdown();
-
-protected:
-  nsDataHashtable<nsStringHashKey, const char *> mLabelsEncodings;
-  EncodingUtils();
-  virtual ~EncodingUtils();
-  static already_AddRefed<EncodingUtils> GetOrCreate();
+private:
+  EncodingUtils() MOZ_DELETE;
 };
 
 } // dom
 } // mozilla
 
 #endif // mozilla_dom_encodingutils_h_
--- a/dom/encoding/Makefile.in
+++ b/dom/encoding/Makefile.in
@@ -28,11 +28,25 @@ EXPORTS_mozilla/dom = \
   $(NULL)
 
 CPPSRCS = \
 	EncodingUtils.cpp \
 	TextDecoder.cpp \
 	TextEncoder.cpp \
 	$(NULL)
 
+LOCAL_INCLUDES = \
+	-I$(topsrcdir)/intl/locale/src \
+	$(NULL)
+
 include $(topsrcdir)/dom/dom-config.mk
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/config/rules.mk
+
+EncodingUtils.$(OBJ_SUFFIX): labelsencodings.properties.h
+
+PROPS2ARRAYS = $(topsrcdir)/intl/locale/src/props2arrays.py
+labelsencodings.properties.h: $(PROPS2ARRAYS) labelsencodings.properties
+	$(PYTHON) $^ $@
+
+GARBAGE += \
+	charsetalias.properties.h \
+	$(NULL)
--- a/dom/encoding/TextDecoder.cpp
+++ b/dom/encoding/TextDecoder.cpp
@@ -23,33 +23,33 @@ TextDecoder::Init(const nsAString& aEnco
 
   // Let encoding be the result of getting an encoding from label.
   // If encoding is failure, throw a TypeError.
   if (!EncodingUtils::FindEncodingForLabel(label, mEncoding)) {
     aRv.ThrowTypeError(MSG_ENCODING_NOT_SUPPORTED, &label);
     return;
   }
 
-  mIsUTF16Family = !strcmp(mEncoding, "utf-16le") ||
-                   !strcmp(mEncoding, "utf-16be");
+  mIsUTF16Family = mEncoding.EqualsLiteral("UTF-16LE") ||
+                   mEncoding.EqualsLiteral("UTF-16BE");
 
   // If the constructor is called with an options argument,
   // and the fatal property of the dictionary is set,
   // set the internal fatal flag of the decoder object.
   mFatal = aFatal.fatal;
 
   // Create a decoder object for mEncoding.
   nsCOMPtr<nsICharsetConverterManager> ccm =
     do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID);
   if (!ccm) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
 
-  ccm->GetUnicodeDecoder(mEncoding, getter_AddRefs(mDecoder));
+  ccm->GetUnicodeDecoderRaw(mEncoding.get(), getter_AddRefs(mDecoder));
   if (!mDecoder) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
 
   if (mFatal) {
     mDecoder->SetInputErrorBehavior(nsIUnicodeDecoder::kOnError_Signal);
   }
@@ -163,22 +163,22 @@ TextDecoder::HandleBOM(const char*& aDat
   }
 
   memcpy(mInitialBytes + mOffset, aData, 2 - mOffset);
   // copied data will be fed later.
   aData += 2 - mOffset;
   aLength -= 2 - mOffset;
   mOffset = 2;
 
-  const char* encoding = "";
+  nsAutoCString encoding;
   if (!EncodingUtils::IdentifyDataOffset(mInitialBytes, 2, encoding) ||
-      strcmp(encoding, mEncoding)) {
+      !encoding.Equals(mEncoding)) {
     // If the stream doesn't start with BOM or the BOM doesn't match the
     // encoding, feed a BOM to workaround decoder's bug (bug 634541).
-    FeedBytes(!strcmp(mEncoding, "utf-16le") ? "\xFF\xFE" : "\xFE\xFF");
+    FeedBytes(mEncoding.EqualsLiteral("UTF-16LE") ? "\xFF\xFE" : "\xFE\xFF");
   }
   FeedBytes(mInitialBytes, &aOutString);
 }
 
 void
 TextDecoder::FeedBytes(const char* aBytes, nsAString* aOutString)
 {
   PRUnichar buf[3];
@@ -196,22 +196,23 @@ TextDecoder::FeedBytes(const char* aByte
 void
 TextDecoder::GetEncoding(nsAString& aEncoding)
 {
   // Our utf-16 converter does not comply with the Encoding Standard.
   // As a result the utf-16le converter is used for the encoding label
   // "utf-16".
   // This workaround should not be exposed to the public API and so "utf-16"
   // is returned by GetEncoding() if the internal encoding name is "utf-16le".
-  if (!strcmp(mEncoding, "utf-16le")) {
+  if (mEncoding.EqualsLiteral("UTF-16LE")) {
     aEncoding.AssignLiteral("utf-16");
     return;
   }
 
-  aEncoding.AssignASCII(mEncoding);
+  CopyASCIItoUTF16(mEncoding, aEncoding);
+  nsContentUtils::ASCIIToLower(aEncoding);
 }
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(TextDecoder)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(TextDecoder)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextDecoder)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
--- a/dom/encoding/TextDecoder.h
+++ b/dom/encoding/TextDecoder.h
@@ -87,17 +87,17 @@ public:
    * @param      aRv, error result.
    */
   void Decode(const ArrayBufferView* aView,
               const TextDecodeOptions& aOptions,
               nsAString& aOutDecodedString,
               ErrorResult& aRv);
 
 private:
-  const char* mEncoding;
+  nsCString mEncoding;
   nsCOMPtr<nsIUnicodeDecoder> mDecoder;
   nsCOMPtr<nsISupports> mGlobal;
   bool mFatal;
   uint8_t mOffset;
   char mInitialBytes[3];
   bool mIsUTF16Family;
 
   /**
--- a/dom/encoding/TextEncoder.cpp
+++ b/dom/encoding/TextEncoder.cpp
@@ -21,32 +21,32 @@ TextEncoder::Init(const nsAString& aEnco
   // Let encoding be the result of getting an encoding from label.
   // If encoding is failure, or is none of utf-8, utf-16, and utf-16be,
   // throw a TypeError.
   if (!EncodingUtils::FindEncodingForLabel(label, mEncoding)) {
     aRv.ThrowTypeError(MSG_ENCODING_NOT_SUPPORTED, &label);
     return;
   }
 
-  if (PL_strcasecmp(mEncoding, "utf-8") &&
-      PL_strcasecmp(mEncoding, "utf-16le") &&
-      PL_strcasecmp(mEncoding, "utf-16be")) {
+  if (!mEncoding.EqualsLiteral("UTF-8") &&
+      !mEncoding.EqualsLiteral("UTF-16LE") &&
+      !mEncoding.EqualsLiteral("UTF-16BE")) {
     aRv.ThrowTypeError(MSG_DOM_ENCODING_NOT_UTF);
     return;
   }
 
   // Create an encoder object for mEncoding.
   nsCOMPtr<nsICharsetConverterManager> ccm =
     do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID);
   if (!ccm) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
 
-  ccm->GetUnicodeEncoder(mEncoding, getter_AddRefs(mEncoder));
+  ccm->GetUnicodeEncoderRaw(mEncoding.get(), getter_AddRefs(mEncoder));
   if (!mEncoder) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
 }
 
 JSObject*
 TextEncoder::Encode(JSContext* aCx,
@@ -101,21 +101,23 @@ TextEncoder::Encode(JSContext* aCx,
 void
 TextEncoder::GetEncoding(nsAString& aEncoding)
 {
   // Our utf-16 converter does not comply with the Encoding Standard.
   // As a result the utf-16le converter is used for the encoding label
   // "utf-16".
   // This workaround should not be exposed to the public API and so "utf-16"
   // is returned by GetEncoding() if the internal encoding name is "utf-16le".
-  if (!strcmp(mEncoding, "utf-16le")) {
+  if (mEncoding.EqualsLiteral("UTF-16LE")) {
     aEncoding.AssignLiteral("utf-16");
     return;
   }
-  aEncoding.AssignASCII(mEncoding);
+
+  CopyASCIItoUTF16(mEncoding, aEncoding);
+  nsContentUtils::ASCIIToLower(aEncoding);
 }
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(TextEncoder)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(TextEncoder)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextEncoder)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
--- a/dom/encoding/TextEncoder.h
+++ b/dom/encoding/TextEncoder.h
@@ -80,17 +80,17 @@ public:
    *                   the previous encoding is reused/continued.
    * @return JSObject* The Uint8Array wrapped in a JS object.
    */
   JSObject* Encode(JSContext* aCx,
                    const nsAString& aString,
                    const TextEncodeOptions& aOptions,
                    ErrorResult& aRv);
 private:
-  const char* mEncoding;
+  nsCString mEncoding;
   nsCOMPtr<nsIUnicodeEncoder> mEncoder;
   nsCOMPtr<nsISupports> mGlobal;
 
   /**
    * Validates provided encoding and throws an exception if invalid encoding.
    * If no encoding is provided then mEncoding is default initialised to "utf-8".
    *
    * @param aEncoding    Optional encoding (case insensitive) provided.
new file mode 100644
--- /dev/null
+++ b/dom/encoding/labelsencodings.properties
@@ -0,0 +1,223 @@
+# 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/.
+#
+# The list is taken from http://encoding.spec.whatwg.org/#encodings
+# The encoding name may not be lowercased due to compatibility with
+# our internal implementations.
+#
+
+unicode-1-1-utf-8=UTF-8
+utf-8=UTF-8
+utf8=UTF-8
+866=IBM866
+cp866=IBM866
+csibm866=IBM866
+ibm866=IBM866
+csisolatin2=ISO-8859-2
+iso-8859-2=ISO-8859-2
+iso-ir-101=ISO-8859-2
+iso8859-2=ISO-8859-2
+iso88592=ISO-8859-2
+iso_8859-2=ISO-8859-2
+iso_8859-2:1987=ISO-8859-2
+l2=ISO-8859-2
+latin2=ISO-8859-2
+csisolatin3=ISO-8859-3
+iso-8859-3=ISO-8859-3
+iso-ir-109=ISO-8859-3
+iso8859-3=ISO-8859-3
+iso88593=ISO-8859-3
+iso_8859-3=ISO-8859-3
+iso_8859-3:1988=ISO-8859-3
+l3=ISO-8859-3
+latin3=ISO-8859-3
+csisolatin4=ISO-8859-4
+iso-8859-4=ISO-8859-4
+iso-ir-110=ISO-8859-4
+iso8859-4=ISO-8859-4
+iso88594=ISO-8859-4
+iso_8859-4=ISO-8859-4
+iso_8859-4:1988=ISO-8859-4
+l4=ISO-8859-4
+latin4=ISO-8859-4
+csisolatincyrillic=ISO-8859-5
+cyrillic=ISO-8859-5
+iso-8859-5=ISO-8859-5
+iso-ir-144=ISO-8859-5
+iso8859-5=ISO-8859-5
+iso88595=ISO-8859-5
+iso_8859-5=ISO-8859-5
+iso_8859-5:1988=ISO-8859-5
+arabic=ISO-8859-6
+asmo-708=ISO-8859-6
+csiso88596e=ISO-8859-6
+csiso88596i=ISO-8859-6
+csisolatinarabic=ISO-8859-6
+ecma-114=ISO-8859-6
+iso-8859-6=ISO-8859-6
+iso-8859-6-e=ISO-8859-6
+iso-8859-6-i=ISO-8859-6
+iso-ir-127=ISO-8859-6
+iso8859-6=ISO-8859-6
+iso88596=ISO-8859-6
+iso_8859-6=ISO-8859-6
+iso_8859-6:1987=ISO-8859-6
+csisolatingreek=ISO-8859-7
+ecma-118=ISO-8859-7
+elot_928=ISO-8859-7
+greek=ISO-8859-7
+greek8=ISO-8859-7
+iso-8859-7=ISO-8859-7
+iso-ir-126=ISO-8859-7
+iso8859-7=ISO-8859-7
+iso88597=ISO-8859-7
+iso_8859-7=ISO-8859-7
+iso_8859-7:1987=ISO-8859-7
+sun_eu_greek=ISO-8859-7
+csiso88598e=ISO-8859-8
+csisolatinhebrew=ISO-8859-8
+hebrew=ISO-8859-8
+iso-8859-8=ISO-8859-8
+iso-8859-8-e=ISO-8859-8
+iso-ir-138=ISO-8859-8
+iso8859-8=ISO-8859-8
+iso88598=ISO-8859-8
+iso_8859-8=ISO-8859-8
+iso_8859-8:1988=ISO-8859-8
+visual=ISO-8859-8
+csiso88598i=ISO-8859-8-I
+iso-8859-8-i=ISO-8859-8-I
+logical=ISO-8859-8-I
+csisolatin6=ISO-8859-10
+iso-8859-10=ISO-8859-10
+iso-ir-157=ISO-8859-10
+iso8859-10=ISO-8859-10
+iso885910=ISO-8859-10
+l6=ISO-8859-10
+latin6=ISO-8859-10
+iso-8859-13=ISO-8859-13
+iso8859-13=ISO-8859-13
+iso885913=ISO-8859-13
+iso-8859-14=ISO-8859-14
+iso8859-14=ISO-8859-14
+iso885914=ISO-8859-14
+csisolatin9=ISO-8859-15
+iso-8859-15=ISO-8859-15
+iso8859-15=ISO-8859-15
+iso885915=ISO-8859-15
+iso_8859-15=ISO-8859-15
+l9=ISO-8859-15
+iso-8859-16=ISO-8859-16
+cskoi8r=KOI8-R
+koi=KOI8-R
+koi8=KOI8-R
+koi8-r=KOI8-R
+koi8_r=KOI8-R
+koi8-u=KOI8-U
+csmacintosh=macintosh
+mac=macintosh
+macintosh=macintosh
+x-mac-roman=macintosh
+dos-874=windows-874
+iso-8859-11=windows-874
+iso8859-11=windows-874
+iso885911=windows-874
+tis-620=windows-874
+windows-874=windows-874
+cp1250=windows-1250
+windows-1250=windows-1250
+x-cp1250=windows-1250
+cp1251=windows-1251
+windows-1251=windows-1251
+x-cp1251=windows-1251
+ansi_x3.4-1968=windows-1252
+ascii=windows-1252
+cp1252=windows-1252
+cp819=windows-1252
+csisolatin1=windows-1252
+ibm819=windows-1252
+iso-8859-1=windows-1252
+iso-ir-100=windows-1252
+iso8859-1=windows-1252
+iso88591=windows-1252
+iso_8859-1=windows-1252
+iso_8859-1:1987=windows-1252
+l1=windows-1252
+latin1=windows-1252
+us-ascii=windows-1252
+windows-1252=windows-1252
+x-cp1252=windows-1252
+cp1253=windows-1253
+windows-1253=windows-1253
+x-cp1253=windows-1253
+cp1254=windows-1254
+csisolatin5=windows-1254
+iso-8859-9=windows-1254
+iso-ir-148=windows-1254
+iso8859-9=windows-1254
+iso88599=windows-1254
+iso_8859-9=windows-1254
+iso_8859-9:1989=windows-1254
+l5=windows-1254
+latin5=windows-1254
+windows-1254=windows-1254
+x-cp1254=windows-1254
+cp1255=windows-1255
+windows-1255=windows-1255
+x-cp1255=windows-1255
+cp1256=windows-1256
+windows-1256=windows-1256
+x-cp1256=windows-1256
+cp1257=windows-1257
+windows-1257=windows-1257
+x-cp1257=windows-1257
+cp1258=windows-1258
+windows-1258=windows-1258
+x-cp1258=windows-1258
+x-mac-cyrillic=x-mac-cyrillic
+x-mac-ukrainian=x-mac-cyrillic
+chinese=gbk
+csgb2312=gbk
+csiso58gb231280=gbk
+gb2312=gbk
+gb_2312=gbk
+gb_2312-80=gbk
+gbk=gbk
+iso-ir-58=gbk
+x-gbk=gbk
+gb18030=gb18030
+hz-gb-2312=HZ-GB-2312
+big5=Big5
+big5-hkscs=Big5
+cn-big5=Big5
+csbig5=Big5
+x-x-big5=Big5
+cseucpkdfmtjapanese=EUC-JP
+euc-jp=EUC-JP
+x-euc-jp=EUC-JP
+csiso2022jp=ISO-2022-JP
+iso-2022-jp=ISO-2022-JP
+csshiftjis=Shift_JIS
+ms_kanji=Shift_JIS
+shift-jis=Shift_JIS
+shift_jis=Shift_JIS
+sjis=Shift_JIS
+windows-31j=Shift_JIS
+x-sjis=Shift_JIS
+cseuckr=EUC-KR
+csksc56011987=EUC-KR
+euc-kr=EUC-KR
+iso-ir-149=EUC-KR
+korean=EUC-KR
+ks_c_5601-1987=EUC-KR
+ks_c_5601-1989=EUC-KR
+ksc5601=EUC-KR
+ksc_5601=EUC-KR
+windows-949=EUC-KR
+csiso2022kr=ISO-2022-KR
+iso-2022-kr=ISO-2022-KR
+utf-16=UTF-16LE
+utf-16le=UTF-16LE
+utf-16be=UTF-16BE
+x-user-defined=x-user-defined
--- a/dom/file/ArchiveRequest.cpp
+++ b/dom/file/ArchiveRequest.cpp
@@ -231,17 +231,17 @@ ArchiveRequest::GetFilesResult(JSContext
                                JS::Value* aValue,
                                nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList)
 {
   JSObject* array = JS_NewArrayObject(aCx, aFileList.Length(), nullptr);
   if (!array) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  for (PRUint32 i = 0; i < aFileList.Length(); ++i) {
+  for (uint32_t i = 0; i < aFileList.Length(); ++i) {
     nsCOMPtr<nsIDOMFile> file = aFileList[i];
 
     JS::Value value;
     nsresult rv = nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx),
                                              file, &NS_GET_IID(nsIDOMFile), &value);
     if (NS_FAILED(rv) || !JS_SetElement(aCx, array, i, &value)) {
       return NS_ERROR_FAILURE;
     }
--- a/dom/file/LockedFile.cpp
+++ b/dom/file/LockedFile.cpp
@@ -7,17 +7,16 @@
 #include "LockedFile.h"
 
 #include "nsIAppShell.h"
 #include "nsIDOMFile.h"
 #include "nsIFileStorage.h"
 #include "nsISeekableStream.h"
 
 #include "jsfriendapi.h"
-#include "nsCharsetAlias.h"
 #include "nsEventDispatcher.h"
 #include "nsNetUtil.h"
 #include "nsDOMClassInfoID.h"
 #include "nsDOMEvent.h"
 #include "nsJSUtils.h"
 #include "nsStringStream.h"
 #include "nsWidgetsCID.h"
 #include "xpcpublic.h"
@@ -28,19 +27,22 @@
 #include "FileRequest.h"
 #include "FileService.h"
 #include "FileStreamWrappers.h"
 #include "MemoryStreams.h"
 #include "MetadataHelper.h"
 #include "nsError.h"
 #include "nsContentUtils.h"
 
+#include "mozilla/dom/EncodingUtils.h"
+
 #define STREAM_COPY_BLOCK_SIZE 32768
 
 USING_FILE_NAMESPACE
+using mozilla::dom::EncodingUtils;
 
 namespace {
 
 NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
 class ReadHelper : public FileHelper
 {
 public:
@@ -1049,18 +1051,19 @@ ReadTextHelper::GetSuccessResult(JSConte
   else {
     const nsCString& data = mStream->Data();
     uint32_t dataLen = data.Length();
     rv = nsContentUtils::GuessCharset(data.get(), dataLen, charsetGuess);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCString charset;
-  rv = nsCharsetAlias::GetPreferred(charsetGuess, charset);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (!EncodingUtils::FindEncodingForLabel(charsetGuess, charset)) {
+    return NS_ERROR_DOM_ENCODING_NOT_SUPPORTED_ERR;
+  }
 
   nsString tmpString;
   rv = nsContentUtils::ConvertStringFromCharset(charset, mStream->Data(),
                                                 tmpString);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!xpc::StringToJsval(aCx, tmpString, aVal)) {
     NS_WARNING("Failed to convert string!");
--- a/dom/interfaces/base/Makefile.in
+++ b/dom/interfaces/base/Makefile.in
@@ -52,13 +52,19 @@ XPIDLSRCS =					\
 	nsITabChild.idl				\
 	nsITabParent.idl			\
 	nsIDOMGlobalPropertyInitializer.idl	\
 	nsIDOMGlobalObjectConstructor.idl \
 	nsIStructuredCloneContainer.idl		\
 	nsIIdleObserver.idl			\
 	$(NULL)
 
+ifdef MOZ_B2G
+XPIDLSRCS += \
+  nsIDOMWindowB2G.idl \
+  $(NULL)
+endif
+
 include $(topsrcdir)/config/rules.mk
 
 XPIDL_FLAGS += \
   -I$(topsrcdir)/dom/interfaces/events \
   $(NULL)
--- a/dom/interfaces/base/nsIDOMWindow.idl
+++ b/dom/interfaces/base/nsIDOMWindow.idl
@@ -27,17 +27,17 @@ interface nsIDOMMozURLProperty : nsISupp
  * The nsIDOMWindow interface is the primary interface for a DOM
  * window object. It represents a single window object that may
  * contain child windows if the document in the window contains a
  * HTML frameset document or if the document contains iframe elements.
  *
  * @see <http://www.whatwg.org/html/#window>
  */
 
-[scriptable, uuid(148ab425-5d38-40fd-9fe0-0eae9fed81df)]
+[scriptable, uuid(1534ecd7-e298-420e-9063-e6c2d1243d49)]
 interface nsIDOMWindow : nsISupports
 {
   // the current browsing context
   readonly attribute nsIDOMWindow                       window;
 
   /* [replaceable] self */
   readonly attribute nsIDOMWindow                       self;
 
@@ -491,23 +491,19 @@ interface nsIDOMWindow : nsISupports
   /**
    * Non-HTML5 window-specific event attributes
    */
   [implicit_jscontext] attribute jsval ondevicemotion;
   [implicit_jscontext] attribute jsval ondeviceorientation;
   [implicit_jscontext] attribute jsval ondeviceproximity;
   [implicit_jscontext] attribute jsval onuserproximity;
   [implicit_jscontext] attribute jsval ondevicelight;
-  [implicit_jscontext] attribute jsval onmoztimechange;
 
   [implicit_jscontext] attribute jsval onmouseenter;
   [implicit_jscontext] attribute jsval onmouseleave;
-
-  [implicit_jscontext] attribute jsval onmoznetworkupload;
-  [implicit_jscontext] attribute jsval onmoznetworkdownload;
 };
 
 [scriptable, uuid(2146c906-57f7-486c-a1b4-8cdb57ef577f)]
 interface nsIDOMWindowPerformance : nsISupports
 {
   /**
    * A namespace to hold performance related data and statistics.
    */
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/base/nsIDOMWindowB2G.idl
@@ -0,0 +1,14 @@
+/* -*- Mode: IDL; 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/. */
+
+#include "nsISupports.idl"
+
+[scriptable, uuid(96bde2ae-9b74-4f4d-b674-664a67a35b7e)]
+interface nsIDOMWindowB2G : nsISupports
+{
+  [implicit_jscontext] attribute jsval onmoztimechange;
+  [implicit_jscontext] attribute jsval onmoznetworkupload;
+  [implicit_jscontext] attribute jsval onmoznetworkdownload;
+};
\ No newline at end of file
--- a/dom/ipc/AppProcessPermissions.cpp
+++ b/dom/ipc/AppProcessPermissions.cpp
@@ -36,20 +36,16 @@ AssertAppProcessPermission(PBrowserParen
   if (app && !tab->IsBrowserElement()) {
     if (!NS_SUCCEEDED(app->HasPermission(aPermission, &hasPermission))) {
       hasPermission = false;
     }
   }
 
   if (!hasPermission) {
     printf_stderr("Security problem: Content process does not have `%s' permission.  It will be killed.\n", aPermission);
-    if (!strcmp(aPermission, "indexedDB-chrome-settings-read") || !strcmp(aPermission, "indexedDB-chrome-settings-write")) {
-      printf_stderr("XXX FIXXME BUG 808327: We ignore indexedDB-chrome-settings-* for now.");
-      return true;
-    }
     ContentParent* process = static_cast<ContentParent*>(aActor->Manager());
     process->KillHard();
   }
   return hasPermission;
 }
 
 bool
 AssertAppProcessPermission(PContentParent* aActor, const char* aPermission)
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1787,16 +1787,32 @@ TabChild::NotifyPainted()
 }
 
 bool
 TabChild::IsAsyncPanZoomEnabled()
 {
     return mScrolling == ASYNC_PAN_ZOOM;
 }
 
+void
+TabChild::MakeVisible()
+{
+    if (mWidget) {
+        mWidget->Show(true);
+    }
+}
+
+void
+TabChild::MakeHidden()
+{
+    if (mWidget) {
+        mWidget->Show(false);
+    }
+}
+
 NS_IMETHODIMP
 TabChild::GetMessageManager(nsIContentFrameMessageManager** aResult)
 {
   if (mTabChildGlobal) {
     NS_ADDREF(*aResult = mTabChildGlobal);
     return NS_OK;
   }
   *aResult = nullptr;
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -287,16 +287,24 @@ public:
     void GetDPI(float* aDPI);
 
     void SetBackgroundColor(const nscolor& aColor);
 
     void NotifyPainted();
 
     bool IsAsyncPanZoomEnabled();
 
+    /**
+     * Signal to this TabChild that it should be made visible:
+     * activated widget, retained layer tree, etc.  (Respectively,
+     * made not visible.)
+     */
+    void MakeVisible();
+    void MakeHidden();
+
 protected:
     virtual PRenderFrameChild* AllocPRenderFrame(ScrollingBehavior* aScrolling,
                                                  LayersBackend* aBackend,
                                                  int32_t* aMaxTextureSize,
                                                  uint64_t* aLayersId) MOZ_OVERRIDE;
     virtual bool DeallocPRenderFrame(PRenderFrameChild* aFrame) MOZ_OVERRIDE;
     virtual bool RecvDestroy() MOZ_OVERRIDE;
 
--- a/dom/locales/en-US/chrome/layout/htmlparser.properties
+++ b/dom/locales/en-US/chrome/layout/htmlparser.properties
@@ -9,17 +9,16 @@ EncNoDeclaration=The character encoding 
 EncLateMetaFrame=The character encoding declaration of the framed HTML document was not found when prescanning the first 1024 bytes of the file. When viewed without the document framing it, the page will reload automatically. The encoding declaration needs to be moved to be within the first 1024 bytes of the file.
 EncLateMeta=The character encoding declaration of the HTML document was not found when prescanning the first 1024 bytes of the file. When viewed in a differently-configured browser, this page will reload automatically. The encoding declaration needs to be moved to be within the first 1024 bytes of the file.
 EncLateMetaReload=The page was reloaded, because the character encoding declaration of the HTML document was not found when prescanning the first 1024 bytes of the file. The encoding declaration needs to be moved to be within the first 1024 bytes of the file.
 EncLateMetaTooLate=The character encoding declaration of document was found too late for it to take effect. The encoding declaration needs to be moved to be within the first 1024 bytes of the file.
 EncMetaUnsupported=An unsupported character encoding was declared for the HTML document using a meta tag. The declaration was ignored.
 EncProtocolUnsupported=An unsupported character encoding was declared on the transfer protocol level. The declaration was ignored.
 EncBomlessUtf16=Detected UTF-16-encoded Basic Latin-only text without a byte order mark and without a transfer protocol-level declaration. Encoding this content in UTF-16 is inefficient and the character encoding should have been declared in any case.
 EncMetaUtf16=A meta tag was used to declare the character encoding as UTF-16. This was interpreted as an UTF-8 declaration instead.
-EncMetaNonRoughSuperset=A meta tag was used to declare a character encoding the does not encode the Basic Latin range roughly like US-ASCII. The declaration was ignored.
 
 # The bulk of the messages below are derived from 
 # http://hg.mozilla.org/projects/htmlparser/file/1f633cef7de7/src/nu/validator/htmlparser/impl/ErrorReportingTokenizer.java
 # which is available under the MIT license.
 
 # Tokenizer errors
 errGarbageAfterLtSlash=Garbage after “</”.
 errLtSlashGt=Saw “</>”. Probable causes: Unescaped “<” (escape as “&lt;”) or mistyped end tag.
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -445,21 +445,21 @@ PeerConnection.prototype = {
         dict.maxRetransmitTime != undefined &&
         dict.maxRetransmitNum != undefined) {
       throw new Error("Both maxRetransmitTime and maxRetransmitNum cannot be provided");
     }
 
     // Must determine the type where we still know if entries are undefined.
     let type;
     if (dict.maxRetransmitTime != undefined) {
-      type = Ci.IPeerConnection.DATACHANNEL_PARTIAL_RELIABLE_TIMED;
+      type = Ci.IPeerConnection.kDataChannelPartialReliableTimed;
     } else if (dict.maxRetransmitNum != undefined) {
-      type = Ci.IPeerConnection.DATACHANNEL_PARTIAL_RELIABLE_REXMIT;
+      type = Ci.IPeerConnection.kDataChannelPartialReliableRexmit;
     } else {
-      type = Ci.IPeerConnection.DATACHANNEL_RELIABLE;
+      type = Ci.IPeerConnection.kDataChannelReliable;
     }
 
     // Synchronous since it doesn't block.
     let channel = this._pc.createDataChannel(
       label, type, dict.outOfOrderAllowed, dict.maxRetransmitTime,
       dict.maxRetransmitNum
     );
     return channel;
--- a/dom/media/bridge/IPeerConnection.idl
+++ b/dom/media/bridge/IPeerConnection.idl
@@ -64,16 +64,21 @@ interface IPeerConnection : nsISupports
   const long kActionPRAnswer = 2;
 
   const long kIceGathering = 0;
   const long kIceWaiting = 1;
   const long kIceChecking = 2;
   const long kIceConnected = 3;
   const long kIceFailed = 4;
 
+  /* for 'type' in DataChannelInit dictionary */
+  const unsigned short kDataChannelReliable = 0;
+  const unsigned short kDataChannelPartialReliableRexmit = 1;
+  const unsigned short kDataChannelPartialReliableTimed = 2;
+
   /* Must be called first. Observer events will be dispatched on the thread provided */
   void initialize(in IPeerConnectionObserver observer, in nsIDOMWindow window,
                   [optional] in nsIThread thread);
 
   /* JSEP calls */
   [implicit_jscontext] void createOffer(in jsval constraints);
   [implicit_jscontext] void createAnswer(in jsval constraints);
   void setLocalDescription(in long action, in string sdp);
--- a/dom/network/interfaces/nsIDOMMobileConnection.idl
+++ b/dom/network/interfaces/nsIDOMMobileConnection.idl
@@ -8,19 +8,28 @@ interface nsIDOMEventListener;
 interface nsIDOMDOMRequest;
 interface nsIDOMMozMobileICCInfo;
 interface nsIDOMMozMobileConnectionInfo;
 interface nsIDOMMozMobileNetworkInfo;
 interface nsIDOMMozMobileCellInfo;
 interface nsIDOMMozIccManager;
 interface nsIDOMMozMobileCFInfo;
 
-[scriptable, builtinclass, uuid(0540db59-8b4f-41c2-a1b8-4097780558b7)]
+[scriptable, builtinclass, uuid(cc4947eb-aa39-4c25-878d-618dc4d4d2bc)]
 interface nsIDOMMozMobileConnection : nsIDOMEventTarget
 {
+  const long ICC_SERVICE_CLASS_VOICE = (1 << 0);
+  const long ICC_SERVICE_CLASS_DATA = (1 << 1);
+  const long ICC_SERVICE_CLASS_FAX = (1 << 2);
+  const long ICC_SERVICE_CLASS_SMS = (1 << 3);
+  const long ICC_SERVICE_CLASS_DATA_SYNC = (1 << 4);
+  const long ICC_SERVICE_CLASS_DATA_ASYNC = (1 << 5);
+  const long ICC_SERVICE_CLASS_PACKET = (1 << 6);
+  const long ICC_SERVICE_CLASS_PAD = (1 << 7);
+
   /**
    * Indicates the state of the device's ICC card.
    *
    * Possible values: null, 'absent', 'pinRequired', 'pukRequired',
    * 'networkLocked', 'ready'.
    */
   readonly attribute DOMString cardState;
 
--- a/dom/network/src/MobileConnection.cpp
+++ b/dom/network/src/MobileConnection.cpp
@@ -393,17 +393,17 @@ MobileConnection::CancelMMI(nsIDOMDOMReq
   if (!mProvider) {
     return NS_ERROR_FAILURE;
   }
 
   return mProvider->CancelMMI(GetOwner(), request);
 }
 
 NS_IMETHODIMP
-MobileConnection::GetCallForwardingOption(PRUint16 aReason,
+MobileConnection::GetCallForwardingOption(uint16_t aReason,
                                           nsIDOMDOMRequest** aRequest)
 {
   *aRequest = nullptr;
 
   if (!mProvider) {
     return NS_ERROR_FAILURE;
   }
 
--- a/dom/payment/Payment.jsm
+++ b/dom/payment/Payment.jsm
@@ -74,62 +74,65 @@ let PaymentManager =  {
         // information.
         let paymentRequests = [];
         let jwtTypes = [];
         for (let i in msg.jwts) {
           let pr = this.getPaymentRequestInfo(msg.jwts[i]);
           if (!pr) {
             continue;
           }
+          if (!(pr instanceof Ci.nsIDOMPaymentRequestInfo)) {
+            return;
+          }
           // We consider jwt type repetition an error.
           if (jwtTypes[pr.type]) {
-            this.paymentFailed("DUPLICATE_JWT_TYPE");
+            this.paymentFailed("PAY_REQUEST_ERROR_DUPLICATED_JWT_TYPE");
             return;
           }
           jwtTypes[pr.type] = true;
           paymentRequests.push(pr);
         }
 
         if (!paymentRequests.length) {
-          this.paymentFailed("NO_VALID_PAYMENT_REQUEST");
+          this.paymentFailed("PAY_REQUEST_ERROR_NO_VALID_REQUEST_FOUND");
           return;
         }
 
         // After getting the list of valid payment requests, we ask the user
         // for confirmation before sending any request to any payment provider.
         // If there is more than one choice, we also let the user select the one
         // that he prefers.
         let glue = Cc["@mozilla.org/payment/ui-glue;1"]
                    .createInstance(Ci.nsIPaymentUIGlue);
         if (!glue) {
           debug("Could not create nsIPaymentUIGlue instance");
-          this.paymentFailed("CREATE_PAYMENT_GLUE_FAILED");
+          this.paymentFailed("INTERNAL_ERROR_CREATE_PAYMENT_GLUE_FAILED");
           return;
         }
 
         let confirmPaymentSuccessCb = function successCb(aResult) {
           // Get the appropriate payment provider data based on user's choice.
           let selectedProvider = this.registeredProviders[aResult];
           if (!selectedProvider || !selectedProvider.uri) {
             debug("Could not retrieve a valid provider based on user's " +
                   "selection");
-            this.paymentFailed("NO_VALID_SELECTED_PROVIDER");
+            this.paymentFailed("INTERNAL_ERROR_NO_VALID_SELECTED_PROVIDER");
             return;
           }
 
           let jwt;
           for (let i in paymentRequests) {
             if (paymentRequests[i].type == aResult) {
               jwt = paymentRequests[i].jwt;
               break;
             }
           }
           if (!jwt) {
             debug("The selected request has no JWT information associated");
-            this.paymentFailed("NO_JWT_ASSOCIATED_TO_REQUEST");
+            this.paymentFailed("INTERNAL_ERROR_NO_JWT_ASSOCIATED_TO_REQUEST");
             return;
           }
 
           this.showPaymentFlow(selectedProvider, jwt);
         };
 
         let confirmPaymentErrorCb = this.paymentFailed;
 
@@ -209,147 +212,126 @@ let PaymentManager =  {
   },
 
   /**
    * Helper function to get the payment request info according to the jwt
    * type. Payment provider's data is stored as a preference.
    */
   getPaymentRequestInfo: function getPaymentRequestInfo(aJwt) {
     if (!aJwt) {
-      return null;
+      this.paymentFailed("INTERNAL_ERROR_CALL_WITH_MISSING_JWT");
+      return true;
     }
 
     // First thing, we check that the jwt type is an allowed type and has a
     // payment provider flow information associated.
 
     // A jwt string consists in three parts separated by period ('.'): header,
     // payload and signature.
     let segments = aJwt.split('.');
     if (segments.length !== 3) {
       debug("Error getting payment provider's uri. " +
             "Not enough or too many segments");
-      return null;
+      this.paymentFailed("PAY_REQUEST_ERROR_WRONG_SEGMENTS_COUNT");
+      return true;
     }
 
     let payloadObject;
     try {
       // We only care about the payload segment, which contains the jwt type
       // that should match with any of the stored payment provider's data and
       // the payment request information to be shown to the user.
       let payload = atob(segments[1]);
       debug("Payload " + payload);
+      if (!payload.length) {
+        this.paymentFailed("PAY_REQUEST_ERROR_EMPTY_PAYLOAD");
+        return true;
+      }
 
       // We get rid off the quotes and backslashes so we can parse the JSON
       // object.
       if (payload.charAt(0) === '"') {
         payload = payload.substr(1);
       }
       if (payload.charAt(payload.length - 1) === '"') {
         payload = payload.slice(0, -1);
       }
       payload = payload.replace(/\\/g, '');
 
       payloadObject = JSON.parse(payload);
+      if (!payloadObject) {
+        this.paymentFailed("PAY_REQUEST_ERROR_ERROR_PARSING_JWT_PAYLOAD");
+        return true;
+      }
     } catch (e) {
-      debug("Error decoding jwt " + e);
-      return null;
+      this.paymentFailed("PAY_REQUEST_ERROR_ERROR_DECODING_JWT");
+      return true;
     }
 
-    if (!payloadObject || !payloadObject.typ || !payloadObject.request) {
-      debug("Error decoding jwt. Not valid jwt. " +
-            "No payload or jwt type or request found");
-      return null;
+    if (!payloadObject.typ) {
+      this.paymentFailed("PAY_REQUEST_ERROR_NO_TYP_PARAMETER");
+      return true;
+    }
+
+    if (!payloadObject.request) {
+      this.paymentFailed("PAY_REQUEST_ERROR_NO_REQUEST_PARAMETER");
+      return true;
     }
 
     // Once we got the jwt 'typ' value we look for a match within the payment
-    // providers stored preferences.
+    // providers stored preferences. If the jwt 'typ' is not recognized as one
+    // of the allowed values for registered payment providers, we skip the jwt
+    // validation but we don't fire any error. This way developers might have
+    // a default set of well formed JWTs that might be used in different B2G
+    // devices with a different set of allowed payment providers.
     let provider = this.registeredProviders[payloadObject.typ];
-    if (!provider || !provider.uri || !provider.name) {
+    if (!provider) {
       debug("Not registered payment provider for jwt type: " +
             payloadObject.typ);
-      return null;
+      return false;
+    }
+
+    if (!provider.uri || !provider.name) {
+      this.paymentFailed("INTERNAL_ERROR_WRONG_REGISTERED_PAY_PROVIDER");
+      return true;
     }
 
     // We only allow https for payment providers uris.
     if (!/^https/.exec(provider.uri.toLowerCase())) {
+      // We should never get this far.
       debug("Payment provider uris must be https: " + provider.uri);
-      return null;
+      this.paymentFailed("INTERNAL_ERROR_NON_HTTPS_PROVIDER_URI");
+      return true;
     }
 
     let pldRequest = payloadObject.request;
-    let request;
-    if (pldRequest.refund) {
-      // The request is a refund request.
-      request = Cc["@mozilla.org/payment/request-refund-info;1"]
-                .createInstance(Ci.nsIDOMPaymentRequestRefundInfo);
-
-      // Refund request should contain a refund reason.
-      if (!request || !pldRequest.reason) {
-        debug("Not valid refund request");
-        return null;
-      }
-      request.wrappedJSObject.init(aJwt,
-                                   payloadObject.typ,
-                                   provider.name,
-                                   pldRequest.reason);
-    } else {
-      // The request is a payment request.
-      request = Cc["@mozilla.org/payment/request-payment-info;1"]
-                .createInstance(Ci.nsIDOMPaymentRequestPaymentInfo);
-
-      // The payment request should contain at least a 'name', 'description' and
-      // 'price' parameters.
-      if (!request || !pldRequest.name || !pldRequest.description ||
-          !pldRequest.price) {
-        debug("Not valid payment request");
-        return null;
-      }
-
-      // The payment request 'price' parameter is a collection of objects with
-      // 'currency' and 'amount' members.
-      let productPrices = [];
-      if (!Array.isArray(pldRequest.price)) {
-        pldRequest.price = [pldRequest.price];
-      }
-
-      for (let i in pldRequest.price) {
-        if (!pldRequest.price[i].currency || !pldRequest.price[i].amount) {
-          debug("Not valid payment request. " +
-                "Price parameter is not well formed");
-          return null;
-        }
-        let price = Cc["@mozilla.org/payment/product-price;1"]
-                    .createInstance(Ci.nsIDOMPaymentProductPrice);
-        price.wrappedJSObject.init(pldRequest.price[i].currency,
-                                   pldRequest.price[i].amount);
-        productPrices.push(price);
-      }
-      request.wrappedJSObject.init(aJwt,
-                                   payloadObject.typ,
-                                   provider.name,
-                                   pldRequest.name,
-                                   pldRequest.description,
-                                   productPrices);
+    let request = Cc["@mozilla.org/payment/request-info;1"]
+                  .createInstance(Ci.nsIDOMPaymentRequestInfo);
+    if (!request) {
+      this.paymentFailed("INTERNAL_ERROR_ERROR_CREATING_PAY_REQUEST");
+      return true;
     }
-
+    request.wrappedJSObject.init(aJwt,
+                                 payloadObject.typ,
+                                 provider.name);
     return request;
   },
 
   showPaymentFlow: function showPaymentFlow(aPaymentProvider, aJwt) {
     let paymentFlowInfo = Cc["@mozilla.org/payment/flow-info;1"]
                           .createInstance(Ci.nsIPaymentFlowInfo);
     paymentFlowInfo.uri = aPaymentProvider.uri;
     paymentFlowInfo.requestMethod = aPaymentProvider.requestMethod;
     paymentFlowInfo.jwt = aJwt;
 
     let glue = Cc["@mozilla.org/payment/ui-glue;1"]
                .createInstance(Ci.nsIPaymentUIGlue);
     if (!glue) {
       debug("Could not create nsIPaymentUIGlue instance");
-      this.paymentFailed("CREATE_PAYMENT_GLUE_FAILED");
+      this.paymentFailed("INTERNAL_ERROR_CREATE_PAYMENT_GLUE_FAILED");
       return false;
     }
     glue.showPaymentFlow(paymentFlowInfo, this.paymentFailed.bind(this));
   },
 
   // nsIObserver
 
   observe: function observe(subject, topic, data) {
--- a/dom/payment/Payment.manifest
+++ b/dom/payment/Payment.manifest
@@ -1,18 +1,9 @@
 component {a920adc0-c36e-4fd0-8de0-aac1ac6ebbd0} Payment.js
 contract @mozilla.org/payment/content-helper;1 {a920adc0-c36e-4fd0-8de0-aac1ac6ebbd0}
 category JavaScript-navigator-property mozPay @mozilla.org/payment/content-helper;1
 
 component {b8bce4e7-fbf0-4719-a634-b1bf9018657c} PaymentFlowInfo.js
 contract @mozilla.org/payment/flow-info;1 {b8bce4e7-fbf0-4719-a634-b1bf9018657c}
 
-component {3d7dcabf-b77c-4bb3-b225-46011898ec32} PaymentRequestInfo.js
-contract @mozilla.org/payment/product-price;1 {3d7dcabf-b77c-4bb3-b225-46011898ec32}
-
 component {0a58c67d-f003-48da-81d1-bd8f605f4b1c} PaymentRequestInfo.js
 contract @mozilla.org/payment/request-info;1 {0a58c67d-f003-48da-81d1-bd8f605f4b1c}
-
-component {7f2e3274-3956-42e1-b7ce-59b8cd23d177} PaymentRequestInfo.js
-contract @mozilla.org/payment/request-payment-info;1 {7f2e3274-3956-42e1-b7ce-59b8cd23d177}
-
-component {e75566c6-dfb1-4f6b-b21d-078536c883b0} PaymentRequestInfo.js
-contract @mozilla.org/payment/request-refund-info;1 {e75566c6-dfb1-4f6b-b21d-078536c883b0}
--- a/dom/payment/PaymentRequestInfo.js
+++ b/dom/payment/PaymentRequestInfo.js
@@ -5,130 +5,37 @@
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const PAYMENTREQUESTINFO_CID =
   Components.ID("{0a58c67d-f003-48da-81d1-bd8f605f4b1c}");
-const PAYMENTPRODUCTPRICE_CID =
-  Components.ID("{3d7dcabf-b77c-4bb3-b225-46011898ec32}");
-const PAYMENTREQUESTPAYMENTINFO_CID =
-  Components.ID("{7f2e3274-3956-42e1-b7ce-59b8cd23d177}");
-const PAYMENTREQUESTREFUNDINFO_CID =
-  Components.ID("{e75566c6-dfb1-4f6b-b21d-078536c883b0}");
-
-// nsIDOMPaymentProductPrice
-
-function PaymentProductPrice() {
-  this.wrappedJSObject = this;
-};
-
-PaymentProductPrice.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMPaymentProductPrice]),
-  classID: PAYMENTPRODUCTPRICE_CID,
-  classInfo: XPCOMUtils.generateCI({
-    classID: PAYMENTPRODUCTPRICE_CID,
-    contractID: "@mozilla.org/payment/product-price;1",
-    classDescription: "Payment product price",
-    flags: Ci.nsIClassInfo.DOM_OBJECT,
-    interfaces: [Ci.nsIDOMPaymentProductPrice]
-  }),
-  currency: null,
-  amount: null,
-
-  init: function init(aCurrency, aAmount) {
-    this.currency = aCurrency;
-    this.amount = aAmount;
-  }
-};
-
 
 // nsIDOMPaymentRequestInfo
 
 function PaymentRequestInfo() {
+  this.wrappedJSObject = this;
 };
 
 PaymentRequestInfo.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMPaymentRequestInfo]),
   classID: PAYMENTREQUESTINFO_CID,
   classInfo: XPCOMUtils.generateCI({
     classID: PAYMENTREQUESTINFO_CID,
     contractID: "@mozilla.org/payment/request-info;1",
     classDescription: "Payment request information",
     flags: Ci.nsIClassInfo.DOM_OBJECT,
     interfaces: [Ci.nsIDOMPaymentRequestInfo]
   }),
   jwt: null,
   type: null,
   providerName: null,
 
-  initRequest: function initRequest(aJwt, aType, aProviderName) {
+  init: function init(aJwt, aType, aProviderName) {
     this.jwt = aJwt;
     this.type = aType;
     this.providerName = aProviderName;
   }
 };
 
-// nsIDOMPaymentRequestPaymentInfo
-
-function PaymentRequestPaymentInfo() {
-  this.wrappedJSObject = this;
-};
-
-PaymentRequestPaymentInfo.prototype = {
-  __proto__: PaymentRequestInfo.prototype,
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMPaymentRequestPaymentInfo]),
-  classID: PAYMENTREQUESTPAYMENTINFO_CID,
-  classInfo: XPCOMUtils.generateCI({
-    classID: PAYMENTREQUESTPAYMENTINFO_CID,
-    contractID: "@mozilla.org/payment/request-payment-info;1",
-    classDescription: "Payment request payment information",
-    flags: Ci.nsIClassInfo.DOM_OBJECT,
-    interfaces: [Ci.nsIDOMPaymentRequestPaymentInfo]
-  }),
-  productName: null,
-  productDescription: null,
-  productPrice: null,
-
-  init: function init(aJwt, aType, aProviderName,
-                      aProductName, aProductDescription, aProductPrice) {
-    this.__proto__.initRequest.call(this, aJwt, aType, aProviderName);
-    this.productName = aProductName;
-    this.productDescription = aProductDescription;
-    this.productPrice = aProductPrice;
-  }
-};
-
-// nsIDOMPaymentRequestRefundInfo
-
-function PaymentRequestRefundInfo() {
-  this.wrappedJSObject = this;
-};
-
-PaymentRequestRefundInfo.prototype = {
-  __proto__: PaymentRequestInfo.prototype,
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMPaymentRequestRefundInfo]),
-  classID: PAYMENTREQUESTREFUNDINFO_CID,
-  classInfo: XPCOMUtils.generateCI({
-    classID: PAYMENTREQUESTREFUNDINFO_CID,
-    contractID: "@mozilla.org/payment/request-refund-info;1",
-    classDescription: "Payment request refund information",
-    flags: Ci.nsIClassInfo.DOM_OBJECT,
-    interfaces: [Ci.nsIDOMPaymentRequestRefundInfo]
-  }),
-  reason: null,
-
-  init: function init(aJwt, aType, aProviderName, aReason) {
-    this.__proto__.initRequest.call(this, aJwt, aType, aProviderName);
-    this.reason = aReason;
-  }
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([
-  PaymentProductPrice,
-  PaymentRequestInfo,
-  PaymentRequestPaymentInfo,
-  PaymentRequestRefundInfo
-]);
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentRequestInfo]);
--- a/dom/payment/interfaces/nsIDOMPaymentRequestInfo.idl
+++ b/dom/payment/interfaces/nsIDOMPaymentRequestInfo.idl
@@ -1,50 +1,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(2a9bc152-ce8d-4ac5-a2b0-7fb52501178e)]
-interface nsIDOMPaymentProductPrice : nsISupports
-{
-  // Each price has a currency associated.
-  readonly attribute DOMString currency;
-
-  // Total amount of the product being sold.
-  readonly attribute double amount;
-};
-
-[scriptable, uuid(95b89ed3-074d-4c31-a26d-5f0abed420a2)]
+[scriptable, uuid(93462984-0e9a-4016-bdb4-a24a88c08a29)]
 interface nsIDOMPaymentRequestInfo : nsISupports
 {
   // Base64 encoded and digitally signed payment request.
   readonly attribute DOMString jwt;
 
   // JWT type that identifies the payment provider owner of the payment request
   // format.
   readonly attribute DOMString type;
 
   // Payment provider name.
   readonly attribute DOMString providerName;
 };
-
-[scriptable, uuid(7a9f78a6-84c6-4f8a-bb3e-3d9ae34727db)]
-interface nsIDOMPaymentRequestPaymentInfo : nsIDOMPaymentRequestInfo
-{
-  // Name of the product being sold.
-  readonly attribute DOMString productName;
-
-  // Human readable description about the product being sold.
-  readonly attribute DOMString productDescription;
-
-  // Could be a single nsIDOMPaymentProductPrice or an array of them.
-  readonly attribute jsval productPrice;
-};
-
-[scriptable, uuid(9759800a-7766-48c3-a6a6-efbe6ab54054)]
-interface nsIDOMPaymentRequestRefundInfo : nsIDOMPaymentRequestInfo
-{
-  // If the requests is a refund request, it must contain a refund reason.
-  readonly attribute DOMString reason;
-};
-
--- a/dom/plugins/test/reftest/reftest.list
+++ b/dom/plugins/test/reftest/reftest.list
@@ -21,9 +21,10 @@ random-if(/^Windows\x20NT\x206\.1/.test(
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == plugin-background.html plugin-background-ref.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == plugin-background-1-step.html plugin-background-ref.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == plugin-background-2-step.html plugin-background-ref.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == plugin-background-5-step.html plugin-background-ref.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == plugin-background-10-step.html plugin-background-ref.html
 random-if(!haveTestPlugin) == plugin-transform-1.html plugin-transform-1-ref.html
 fails-if(!haveTestPlugin) == plugin-transform-2.html plugin-transform-2-ref.html
 skip-if(!haveTestPlugin) == shrink-1.html shrink-1-ref.html
+# skip-if(!haveTestPlugin) == update-1.html update-1-ref.html bug 807728
 fails-if(!haveTestPlugin) == windowless-layers.html windowless-layers-ref.html
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/reftest/update-1-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<body>
+  <embed id="plugin" type="application/x-test"
+         drawmode="solid" color="FFFF0000" width="30" height="50">
+  </embed>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/reftest/update-1.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+  <title>Test for bug 807728</title>
+  <script>
+function do_test()
+{
+    var plugin = document.getElementById("plugin");
+    var color = "FF000000";
+    var color1 = "FF000001";
+    var color2 = "FF000002";
+    var last_paint_count = 0;
+    // Enough paints to test reusing a surface after it has been
+    // moved from front to back buffer.
+    var paints_required = 10;
+    var final_color = "FFFF0000";
+
+    function wait_for_paints() {
+        var paint_count = plugin.getPaintCount();
+        if (paint_count >= paints_required && color == final_color) {
+            document.documentElement.removeAttribute("class");
+            return;
+        }
+        if (paint_count != last_paint_count) {
+            last_paint_count = paint_count;
+            if (paint_count + 1 >= paints_required) {
+                color = final_color;
+            } else if (color != color1) {
+                color = color1;
+            } else {
+                color = color2;
+            }
+            plugin.setColor(color);
+        }       
+        setTimeout(wait_for_paints, 0);
+    }
+
+    wait_for_paints();
+}
+  </script>
+</head>
+<body onload="do_test()">
+  <embed id="plugin" type="application/x-test"
+         drawmode="solid" color="FF000000" width="30" height="50">
+  </embed>
+</body>
+</html>
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -812,20 +812,17 @@ RILContentHelper.prototype = {
         break;
       case "RIL:USSDReceived":
         let res = JSON.stringify({message: msg.json.message,
                                   sessionEnded: msg.json.sessionEnded});
         Services.obs.notifyObservers(null, kUssdReceivedTopic, res);
         break;
       case "RIL:SendMMI:Return:OK":
       case "RIL:CancelMMI:Return:OK":
-        request = this.takeRequest(msg.json.requestId);
-        if (request) {
-          Services.DOMRequest.fireSuccess(request, msg.json.result);
-        }
+        this.handleSendCancelMMIOK(msg.json);
         break;
       case "RIL:SendMMI:Return:KO":
       case "RIL:CancelMMI:Return:KO":
         request = this.takeRequest(msg.json.requestId);
         if (request) {
           Services.DOMRequest.fireError(request, msg.json.errorMsg);
         }
         break;
@@ -940,57 +937,76 @@ RILContentHelper.prototype = {
 
     if (changed) {
       this._deliverCallback("_voicemailCallbacks",
                             "voicemailNotification",
                             [this.voicemailStatus]);
     }
   },
 
+  _cfRulesToMobileCfInfo: function _cfRulesToMobileCfInfo(rules) {
+    for (let i = 0; i < rules.length; i++) {
+      let rule = rules[i];
+      let info = new MobileCFInfo();
+
+      for (let key in rule) {
+        info[key] = rule[key];
+      }
+
+      rules[i] = info;
+    }
+  },
+
   handleGetCallForwardingOption: function handleGetCallForwardingOption(message) {
     let requestId = message.requestId;
     let request = this.takeRequest(requestId);
     if (!request) {
       return;
     }
 
     if (!message.success) {
       Services.DOMRequest.fireError(request, message.errorMsg);
       return;
     }
 
-    let rules = message.rules;
-    for (let i = 0; i < rules.length; i++) {
-      let rule = rules[i];
-      let info = new MobileCFInfo();
-
-      for (let key in rule) {
-        info[key] = rule[key];
-      }
-
-      rules[i] = info;
-    }
-
-    Services.DOMRequest.fireSuccess(request, rules);
+    this._cfRulesToMobileCfInfo(message.rules);
+    Services.DOMRequest.fireSuccess(request, message.rules);
   },
 
   handleSetCallForwardingOption: function handleSetCallForwardingOption(message) {
     let requestId = message.requestId;
     let request = this.takeRequest(requestId);
     if (!request) {
       return;
     }
 
     if (!message.success) {
       Services.DOMRequest.fireError(request, message.errorMsg);
       return;
     }
     Services.DOMRequest.fireSuccess(request, null);
   },
 
+  handleSendCancelMMIOK: function handleSendCancelMMIOK(message) {
+    let request = this.takeRequest(message.requestId);
+    if (!request) {
+      return;
+    }
+
+    // MMI query call forwarding options request returns a set of rules that
+    // will be exposed in the form of an array of nsIDOMMozMobileCFInfo
+    // instances.
+    if (message.success && message.rules) {
+      this._cfRulesToMobileCfInfo(message.rules);
+      message.result = message.rules;
+    }
+
+    Services.DOMRequest.fireSuccess(request, message.result);
+  },
+
   _getRandomId: function _getRandomId() {
     return gUUIDGenerator.generateUUID().toString();
   },
 
   _deliverCallback: function _deliverCallback(callbackType, name, args) {
     let thisCallbacks = this[callbackType];
     if (!thisCallbacks) {
       return;
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -1896,31 +1896,60 @@ this.GECKO_RADIO_TECH = [
   "evdob",
   "ehrpd",
   "lte",
   "hspa+",
 ];
 
 this.GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN = -1;
 
+// Call forwarding action. Must be in sync with nsIDOMMozMobileCFInfo interface
+this.CALL_FORWARD_ACTION_DISABLE = 0;
+this.CALL_FORWARD_ACTION_ENABLE = 1;
+this.CALL_FORWARD_ACTION_QUERY_STATUS = 2;
+this.CALL_FORWARD_ACTION_REGISTRATION = 3;
+this.CALL_FORWARD_ACTION_ERASURE = 4;
+
+// Call forwarding reason. Must be in sync with nsIDOMMozMobileCFInfo interface
+this.CALL_FORWARD_REASON_UNCONDITIONAL = 0;
+this.CALL_FORWARD_REASON_MOBILE_BUSY = 1;
+this.CALL_FORWARD_REASON_NO_REPLY = 2;
+this.CALL_FORWARD_REASON_NOT_REACHABLE = 3;
+this.CALL_FORWARD_REASON_ALL_CALL_FORWARDING = 4;
+this.CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING = 5;
+
 // MMI procedure as defined in TS.22.030 6.5.2
 this.MMI_PROCEDURE_ACTIVATION = "*";
 this.MMI_PROCEDURE_DEACTIVATION = "#";
 this.MMI_PROCEDURE_INTERROGATION = "*#";
 this.MMI_PROCEDURE_REGISTRATION = "**";
 this.MMI_PROCEDURE_ERASURE = "##";
 
+this.MMI_PROC_TO_CF_ACTION = {};
+MMI_PROC_TO_CF_ACTION[MMI_PROCEDURE_ACTIVATION] = CALL_FORWARD_ACTION_ENABLE;
+MMI_PROC_TO_CF_ACTION[MMI_PROCEDURE_DEACTIVATION] = CALL_FORWARD_ACTION_DISABLE;
+MMI_PROC_TO_CF_ACTION[MMI_PROCEDURE_INTERROGATION] = CALL_FORWARD_ACTION_QUERY_STATUS;
+MMI_PROC_TO_CF_ACTION[MMI_PROCEDURE_REGISTRATION] = CALL_FORWARD_ACTION_REGISTRATION;
+MMI_PROC_TO_CF_ACTION[MMI_PROCEDURE_ERASURE] = CALL_FORWARD_ACTION_ERASURE;
+
 // MMI call forwarding service codes as defined in TS.22.030 Annex B
 this.MMI_SC_CFU = "21";
 this.MMI_SC_CF_BUSY = "67";
 this.MMI_SC_CF_NO_REPLY = "61";
 this.MMI_SC_CF_NOT_REACHABLE = "62";
 this.MMI_SC_CF_ALL = "002";
 this.MMI_SC_CF_ALL_CONDITIONAL = "004";
 
+this.MMI_SC_TO_CF_REASON = {};
+MMI_SC_TO_CF_REASON[MMI_SC_CFU] = CALL_FORWARD_REASON_UNCONDITIONAL;
+MMI_SC_TO_CF_REASON[MMI_SC_CF_BUSY] = CALL_FORWARD_REASON_MOBILE_BUSY;
+MMI_SC_TO_CF_REASON[MMI_SC_CF_NOT_REACHABLE] = CALL_FORWARD_REASON_NOT_REACHABLE;
+MMI_SC_TO_CF_REASON[MMI_SC_CF_ALL] = CALL_FORWARD_REASON_ALL_CALL_FORWARDING;
+MMI_SC_TO_CF_REASON[MMI_SC_CF_ALL_CONDITIONAL] = CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING;
+
 // MMI service codes for PIN/PIN2/PUK/PUK2 management as defined in TS.22.030
 // sec 6.6
 this.MMI_SC_PIN = "04";
 this.MMI_SC_PIN2 = "042";
 this.MMI_SC_PUK = "05";
 this.MMI_SC_PUK2 = "052";
 
 // MMI service code for IMEI presentation as defined in TS.22.030 sec 6.7
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -2371,18 +2371,32 @@ let RIL = {
     switch (sc) {
       // Call forwarding
       case MMI_SC_CFU:
       case MMI_SC_CF_BUSY:
       case MMI_SC_CF_NO_REPLY:
       case MMI_SC_CF_NOT_REACHABLE:
       case MMI_SC_CF_ALL:
       case MMI_SC_CF_ALL_CONDITIONAL:
-        // TODO: Bug 793192 - MMI Codes: support call forwarding.
-        _sendMMIError("CALL_FORWARDING_NOT_SUPPORTED_VIA_MMI");
+        // Call forwarding requires at least an action, given by the MMI
+        // procedure, and a reason, given by the MMI service code, but there
+        // is no way that we get this far without a valid procedure or service
+        // code.
+        options.action = MMI_PROC_TO_CF_ACTION[mmi.procedure];
+        options.rilMessageType = "sendMMI";
+        options.reason = MMI_SC_TO_CF_REASON[sc];
+        options.number = mmi.sia;
+        options.serviceClass = mmi.sib;
+        if (options.action == CALL_FORWARD_ACTION_QUERY_STATUS) {
+          this.queryCallForwardStatus(options);
+          return;
+        }
+
+        options.timeSeconds = mmi.sic;
+        this.setCallForward(options);
         return;
 
       // Change the current ICC PIN number.
       case MMI_SC_PIN:
         // As defined in TS.122.030 6.6.2 to change the ICC PIN we should expect
         // an MMI code of the form **04*OLD_PIN*NEW_PIN*NEW_PIN#, where old PIN
         // should be entered as the SIA parameter and the new PIN as SIB and
         // SIC.
@@ -2890,16 +2904,23 @@ let RIL = {
        // No ecclist system property, so use our own list.
        numbers = DEFAULT_EMERGENCY_NUMBERS;
      }
 
      return numbers.indexOf(number) != -1;
    },
 
   /**
+   * Report STK Service is running.
+   */
+  reportStkServiceIsRunning: function reportStkServiceIsRunning() {
+    Buf.simpleRequest(REQUEST_REPORT_STK_SERVICE_IS_RUNNING);
+  },
+
+  /**
    * Process ICC status.
    */
   _processICCStatus: function _processICCStatus(iccStatus) {
     this.iccStatus = iccStatus;
 
     if ((!iccStatus) || (iccStatus.cardState == CARD_STATE_ABSENT)) {
       if (DEBUG) debug("ICC absent");
       if (this.cardState == GECKO_CARDSTATE_ABSENT) {
@@ -2956,16 +2977,17 @@ let RIL = {
       return;
     }
 
     // This was moved down from CARD_APPSTATE_READY
     this.requestNetworkInfo();
     this.getSignalStrength();
     if (newCardState == GECKO_CARDSTATE_READY) {
       this.fetchICCRecords();
+      this.reportStkServiceIsRunning();
     }
 
     this.cardState = newCardState;
     this.sendDOMMessage({rilMessageType: "cardstatechange",
                          cardState: this.cardState});
   },
 
   /** 
--- a/dom/system/gonk/tests/test_ril_worker_mmi.js
+++ b/dom/system/gonk/tests/test_ril_worker_mmi.js
@@ -14,27 +14,46 @@ function parseMMI(mmi) {
     },
     postMessage: function fakePostMessage(message) {
       // Do nothing
     }
   });
   return worker.RIL._parseMMI(mmi);
 }
 
-function testSendMMI(mmi, error) {
-  let postedMessage;
-  let worker = newWorker({
+function getWorker() {
+  let _postedMessage;
+  let _worker = newWorker({
     postRILMessage: function fakePostRILMessage(data) {
     },
     postMessage: function fakePostMessage(message) {
-      postedMessage = message;
+      _postedMessage = message;
+    },
+  });
+
+  return {
+    get postedMessage() {
+      return _postedMessage;
+    },
+    get worker() {
+      return _worker;
     }
-  })
+  };
+}
+
+function testSendMMI(mmi, error) {
+  let workerhelper = getWorker();
+  let worker = workerhelper.worker;
+
+  do_print("worker.postMessage " + worker.postMessage);
+
   worker.RIL.sendMMI({mmi: mmi});
 
+  let postedMessage = workerhelper.postedMessage;
+
   do_check_eq(postedMessage.rilMessageType, "sendMMI");
   do_check_eq(postedMessage.errorMsg, error);
 }
 
 add_test(function test_parseMMI_empty() {
   let mmi = parseMMI("");
 
   do_check_null(mmi);
@@ -304,41 +323,169 @@ add_test(function test_sendMMI_invalid()
 });
 
 add_test(function test_sendMMI_dial_string() {
   testSendMMI("123", "NO_VALID_MMI_STRING");
 
   run_next_test();
 });
 
-add_test(function test_sendMMI_call_forwarding() {
-  // TODO: Bug 793192 - MMI Codes: support call forwarding
-  testSendMMI("*21#", "CALL_FORWARDING_NOT_SUPPORTED_VIA_MMI");
+function setCallForwardSuccess(mmi) {
+  let workerhelper = getWorker();
+  let worker = workerhelper.worker;
+
+  worker.RIL.setCallForward = function fakeSetCallForward(options) {
+    worker.RIL[REQUEST_SET_CALL_FORWARD](0, {
+      rilRequestError: ERROR_SUCCESS
+    });
+  };
+
+  worker.RIL.sendMMI({mmi: mmi});
+
+  let postedMessage = workerhelper.postedMessage;
+
+  do_check_eq(postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
+  do_check_true(postedMessage.success);
+}
+
+add_test(function test_sendMMI_call_forwarding_activation() {
+  setCallForwardSuccess("*21*12345*99*10#");
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_deactivation() {
+  setCallForwardSuccess("#21*12345*99*10#");
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_interrogation() {
+  let workerhelper = getWorker();
+  let worker = workerhelper.worker;
+
+  worker.Buf.readUint32 = function fakeReadUint32() {
+    return worker.Buf.int32Array.pop();
+  };
+
+  worker.Buf.readString = function fakeReadString() {
+    return "+34666222333";
+  };
+
+  worker.RIL.queryCallForwardStatus = function fakeQueryCallForward(options) {
+    worker.Buf.int32Array = [
+      0,   // rules.timeSeconds
+      145, // rules.toa
+      49,  // rules.serviceClass
+      Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_REASON_UNCONDITIONAL, // rules.reason
+      1,   // rules.active
+      1    // rulesLength
+    ];
+    worker.RIL[REQUEST_QUERY_CALL_FORWARD_STATUS](1, {
+      rilRequestError: ERROR_SUCCESS
+    });
+  };
+
+  worker.RIL.sendMMI({mmi: "*#21#"});
+
+  let postedMessage = workerhelper.postedMessage;
+
+  do_check_eq(postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
+  do_check_true(postedMessage.success);
+  do_check_true(Array.isArray(postedMessage.rules));
+  do_check_eq(postedMessage.rules.length, 1);
+  do_check_true(postedMessage.rules[0].active);
+  do_check_eq(postedMessage.rules[0].reason,
+              Ci.nsIDOMMozMobileCFInfo.CALL_FORWARD_REASON_UNCONDITIONAL);
+  do_check_eq(postedMessage.rules[0].number, "+34666222333");
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_interrogation_no_rules() {
+  let workerhelper = getWorker();
+  let worker = workerhelper.worker;
+
+  worker.Buf.readUint32 = function fakeReadUint32() {
+    return 0;
+  };
+
+  worker.RIL.queryCallForwardStatus = function fakeQueryCallForward(options) {
+    worker.RIL[REQUEST_QUERY_CALL_FORWARD_STATUS](1, {
+      rilRequestError: ERROR_SUCCESS
+    });
+  };
+
+  worker.RIL.sendMMI({mmi: "*#21#"});
+
+  let postedMessage = workerhelper.postedMessage;
+
+  do_check_eq(postedMessage.errorMsg,
+              "Invalid rule length while querying call forwarding status.");
+  do_check_false(postedMessage.success);
+
+  run_next_test();
+});
+
+
+add_test(function test_sendMMI_call_forwarding_registration() {
+  setCallForwardSuccess("**21*12345*99*10#");
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_erasure() {
+  setCallForwardSuccess("##21*12345*99#");
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_CFB() {
+  setCallForwardSuccess("*67*12345*99*10#");
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_CFNRy() {
+  setCallForwardSuccess("*61*12345*99*10#");
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_CFNRc() {
+  setCallForwardSuccess("*62*12345*99*10#");
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_CFAll() {
+  setCallForwardSuccess("*004*12345*99*10#");
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_CFAllConditional() {
+  setCallForwardSuccess("*002*12345*99*10#");
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_change_PIN() {
-  let postedMessage;
-  let worker = newWorker({
-    postRILMessage: function fakePostRILMessage(data) {
-    },
-    postMessage: function fakePostMessage(message) {
-      postedMessage = message;
-    },
-  });
+  let workerhelper = getWorker();
+  let worker = workerhelper.worker;
 
-  worker.RIL.changeICCPIN = function fakeChangeICCPIN(options){
+  worker.RIL.changeICCPIN = function fakeChangeICCPIN(options) {
     worker.RIL[REQUEST_ENTER_SIM_PIN](0, {
       rilRequestError: ERROR_SUCCESS
     });
   }
 
   worker.RIL.sendMMI({mmi: "**04*1234*4567*4567#"});
 
+  let postedMessage = workerhelper.postedMessage;
+
   do_check_eq (postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
   do_check_true(postedMessage.success);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_change_PIN_no_new_PIN() {
   testSendMMI("**04*1234**4567#", "MISSING_SUPPLEMENTARY_INFORMATION");
@@ -360,33 +507,29 @@ add_test(function test_sendMMI_change_PI
 
 add_test(function test_sendMMI_change_PIN_new_PIN_mismatch() {
   testSendMMI("**04*4567*1234*4567#", "NEW_PIN_MISMATCH");
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_change_PIN2() {
-  let postedMessage;
-  let worker = newWorker({
-    postRILMessage: function fakePostRILMessage(data) {
-    },
-    postMessage: function fakePostMessage(message) {
-      postedMessage = message;
-    },
-  });
+  let workerhelper = getWorker();
+  let worker = workerhelper.worker;
 
   worker.RIL.changeICCPIN2 = function fakeChangeICCPIN2(options){
     worker.RIL[REQUEST_ENTER_SIM_PIN2](0, {
       rilRequestError: ERROR_SUCCESS
     });
   }
 
   worker.RIL.sendMMI({mmi: "**042*1234*4567*4567#"});
 
+  let postedMessage = workerhelper.postedMessage;
+
   do_check_eq (postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
   do_check_true(postedMessage.success);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_change_PIN2_no_new_PIN2() {
   testSendMMI("**042*1234**4567#", "MISSING_SUPPLEMENTARY_INFORMATION");
@@ -408,33 +551,29 @@ add_test(function test_sendMMI_change_PI
 
 add_test(function test_sendMMI_change_PIN2_new_PIN2_mismatch() {
   testSendMMI("**042*4567*1234*4567#", "NEW_PIN_MISMATCH");
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_unblock_PIN() {
-  let postedMessage;
-  let worker = newWorker({
-    postRILMessage: function fakePostRILMessage(data) {
-    },
-    postMessage: function fakePostMessage(message) {
-      postedMessage = message;
-    },
-  });
+  let workerhelper = getWorker();
+  let worker = workerhelper.worker;
 
   worker.RIL.enterICCPUK = function fakeEnterICCPUK(options){
     worker.RIL[REQUEST_ENTER_SIM_PUK](0, {
       rilRequestError: ERROR_SUCCESS
     });
   }
 
   worker.RIL.sendMMI({mmi: "**05*1234*4567*4567#"});
 
+  let postedMessage = workerhelper.postedMessage;
+
   do_check_eq (postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
   do_check_true(postedMessage.success);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_unblock_PIN_no_new_PIN() {
   testSendMMI("**05*1234**4567#", "MISSING_SUPPLEMENTARY_INFORMATION");
@@ -456,33 +595,29 @@ add_test(function test_sendMMI_unblock_P
 
 add_test(function test_sendMMI_unblock_PIN_new_PIN_mismatch() {
   testSendMMI("**05*4567*1234*4567#", "NEW_PIN_MISMATCH");
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_unblock_PIN2() {
-  let postedMessage;
-  let worker = newWorker({
-    postRILMessage: function fakePostRILMessage(data) {
-    },
-    postMessage: function fakePostMessage(message) {
-      postedMessage = message;
-    },
-  });
+  let workerhelper = getWorker();
+  let worker = workerhelper.worker;
 
   worker.RIL.enterICCPUK2 = function fakeEnterICCPUK2(options){
     worker.RIL[REQUEST_ENTER_SIM_PUK2](0, {
       rilRequestError: ERROR_SUCCESS
     });
   }
 
   worker.RIL.sendMMI({mmi: "**052*1234*4567*4567#"});
 
+  let postedMessage = workerhelper.postedMessage;
+
   do_check_eq (postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
   do_check_true(postedMessage.success);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_unblock_PIN2_no_new_PIN2() {
   testSendMMI("**052*1234**4567#", "MISSING_SUPPLEMENTARY_INFORMATION");
@@ -504,62 +639,54 @@ add_test(function test_sendMMI_unblock_P
 
 add_test(function test_sendMMI_unblock_PIN2_new_PIN_mismatch() {
   testSendMMI("**052*4567*1234*4567#", "NEW_PIN_MISMATCH");
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_get_IMEI() {
-  let postedMessage;
+  let workerhelper = getWorker();
+  let worker = workerhelper.worker;
   let mmiOptions;
-  let worker = newWorker({
-    postRILMessage: function fakePostRILMessage(data) {
-    },
-    postMessage: function fakePostMessage(message) {
-      postedMessage = message;
-    },
-  });
 
   worker.RIL.getIMEI = function getIMEI(options){
     mmiOptions = options;
     worker.RIL[REQUEST_SEND_USSD](0, {
       rilRequestError: ERROR_SUCCESS,
     });
   }
 
   worker.RIL.sendMMI({mmi: "*#06#"});
 
+  let postedMessage = workerhelper.postedMessage;
+
   do_check_true(mmiOptions.mmi);
   do_check_eq (postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
   do_check_true(postedMessage.success);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_get_IMEI_error() {
-  let postedMessage;
+  let workerhelper = getWorker();
+  let worker = workerhelper.worker;
   let mmiOptions;
-  let worker = newWorker({
-    postRILMessage: function fakePostRILMessage(data) {
-    },
-    postMessage: function fakePostMessage(message) {
-      postedMessage = message;
-    },
-  });
 
   worker.RIL.getIMEI = function getIMEI(options){
     mmiOptions = options;
     worker.RIL[REQUEST_SEND_USSD](0, {
       rilRequestError: ERROR_RADIO_NOT_AVAILABLE,
     });
   }
 
   worker.RIL.sendMMI({mmi: "*#06#"});
 
+  let postedMessage = workerhelper.postedMessage;
+
   do_check_true(mmiOptions.mmi);
   do_check_eq (postedMessage.errorMsg, GECKO_ERROR_RADIO_NOT_AVAILABLE);
   do_check_false(postedMessage.success);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_call_barring() {
@@ -570,62 +697,54 @@ add_test(function test_sendMMI_call_barr
 
 add_test(function test_sendMMI_call_waiting() {
   testSendMMI("*43#", "CALL_WAITING_NOT_SUPPORTED_VIA_MMI");
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_USSD() {
-  let postedMessage;
+  let workerhelper = getWorker();
+  let worker = workerhelper.worker;
   let ussdOptions;
-  let worker = newWorker({
-    postRILMessage: function fakePostRILMessage(data) {
-    },
-    postMessage: function fakePostMessage(message) {
-      postedMessage = message;
-    },
-  });
 
   worker.RIL.sendUSSD = function fakeSendUSSD(options){
     ussdOptions = options;
     worker.RIL[REQUEST_SEND_USSD](0, {
       rilRequestError: ERROR_SUCCESS
     });
   }
 
   worker.RIL.sendMMI({mmi: "*123#"});
 
+  let postedMessage = workerhelper.postedMessage;
+
   do_check_eq(ussdOptions.ussd, "*123#");
   do_check_eq (postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
   do_check_true(postedMessage.success);
   do_check_true(worker.RIL._ussdSession);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_USSD_error() {
-  let postedMessage;
+  let workerhelper = getWorker();
+  let worker = workerhelper.worker;
   let ussdOptions;
-  let worker = newWorker({
-    postRILMessage: function fakePostRILMessage(data) {
-    },
-    postMessage: function fakePostMessage(message) {
-      postedMessage = message;
-    },
-  });
 
   worker.RIL.sendUSSD = function fakeSendUSSD(options){
     ussdOptions = options;
     worker.RIL[REQUEST_SEND_USSD](0, {
       rilRequestError: ERROR_GENERIC_FAILURE
     });
   }
 
   worker.RIL.sendMMI({mmi: "*123#"});
 
+  let postedMessage = workerhelper.postedMessage;
+
   do_check_eq(ussdOptions.ussd, "*123#");
   do_check_eq (postedMessage.errorMsg, GECKO_ERROR_GENERIC_FAILURE);
   do_check_false(postedMessage.success);
   do_check_false(worker.RIL._ussdSession);
 
   run_next_test();
 });
--- a/dom/webidl/AudioContext.webidl
+++ b/dom/webidl/AudioContext.webidl
@@ -28,12 +28,15 @@ interface mozAudioContext {
 
     [Creator]
     GainNode createGain();
     [Creator]
     DelayNode createDelay(optional float maxDelayTime = 1);
     [Creator]
     PannerNode createPanner();
 
+    [Creator]
+    DynamicsCompressorNode createDynamicsCompressor();
+
 };
 
 typedef mozAudioContext AudioContext;
 
new file mode 100644
--- /dev/null
+++ b/dom/webidl/DynamicsCompressorNode.webidl
@@ -0,0 +1,24 @@
+/* -*- Mode: IDL; 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/.
+ *
+ * The origin of this IDL file is
+ * https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+[PrefControlled]
+interface DynamicsCompressorNode : AudioNode {
+
+    readonly attribute AudioParam threshold; // in Decibels
+    readonly attribute AudioParam knee; // in Decibels
+    readonly attribute AudioParam ratio; // unit-less
+    readonly attribute AudioParam reduction; // in Decibels
+    readonly attribute AudioParam attack; // in Seconds
+    readonly attribute AudioParam release; // in Seconds
+
+};
+
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -21,16 +21,17 @@ webidl_files = \
   CanvasRenderingContext2D.webidl \
   ClientRectList.webidl \
   CSSStyleDeclaration.webidl \
   DelayNode.webidl \
   DOMImplementation.webidl \
   DOMTokenList.webidl \
   DOMSettableTokenList.webidl \
   DOMStringMap.webidl \
+  DynamicsCompressorNode.webidl \
   Function.webidl \
   EventHandler.webidl \
   EventListener.webidl \
   EventTarget.webidl \
   FileList.webidl \
   FileReaderSync.webidl \
   GainNode.webidl \
   HTMLCollection.webidl \
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -46,16 +46,18 @@ var WifiManager = (function() {
     return parseInt(sdkVersion, 10);
   }
 
   let sdkVersion = getSdkVersion();
 
   var controlWorker = new ChromeWorker(WIFIWORKER_WORKER);
   var eventWorker = new ChromeWorker(WIFIWORKER_WORKER);
 
+  var manager = {};
+
   // Callbacks to invoke when a reply arrives from the controlWorker.
   var controlCallbacks = Object.create(null);
   var idgen = 0;
 
   function controlMessage(obj, callback) {
     var id = idgen++;
     obj.id = id;
     if (callback)
@@ -237,26 +239,29 @@ var WifiManager = (function() {
   // A note about background scanning:
   // Normally, background scanning shouldn't be necessary as wpa_supplicant
   // has the capability to automatically schedule its own scans at appropriate
   // intervals. However, with some drivers, this appears to get stuck after
   // three scans, so we enable the driver's background scanning to work around
   // that when we're not connected to any network. This ensures that we'll
   // automatically reconnect to networks if one falls out of range.
   var reEnableBackgroundScan = false;
-  var backgroundScanEnabled = false;
+
+  // NB: This is part of the internal API.
+  manager.backgroundScanEnabled = false;
   function setBackgroundScan(enable, callback) {
     var doEnable = (enable === "ON");
-    if (doEnable === backgroundScanEnabled) {
+    if (doEnable === manager.backgroundScanEnabled) {
       callback(false, true);
       return;
     }
 
-    backgroundScanEnabled = doEnable;
-    doBooleanCommand("SET pno " + (backgroundScanEnabled ? "1" : "0"), "OK",
+    manager.backgroundScanEnabled = doEnable;
+    doBooleanCommand("SET pno " + (manager.backgroundScanEnabled ? "1" : "0"),
+                     "OK",
                      function(ok) {
                        callback(true, ok);
                      });
   }
 
   var scanModeActive = false;
 
   function doSetScanModeCommand(setActive, callback) {
@@ -611,18 +616,16 @@ var WifiManager = (function() {
   function runDhcpRenew(ifname, callback) {
     controlMessage({ cmd: "dhcp_do_request", ifname: ifname }, function(data) {
       if (!data.status)
         dhcpInfo = data;
       callback(data.status ? null : data);
     });
   }
 
-  var manager = {};
-
   var suppressEvents = false;
   function notify(eventName, eventObject) {
     if (suppressEvents)
       return;
     var handler = manager["on" + eventName];
     if (handler) {
       if (!eventObject)
         eventObject = ({});
@@ -639,17 +642,17 @@ var WifiManager = (function() {
         fields.state !== "DISCONNECTED" &&
         fields.state !== "INTERFACE_DISABLED" &&
         fields.state !== "INACTIVE" &&
         fields.state !== "SCANNING") {
       return false;
     }
 
     // Stop background scanning if we're trying to connect to a network.
-    if (backgroundScanEnabled &&
+    if (manager.backgroundScanEnabled &&
         (fields.state === "ASSOCIATING" ||
          fields.state === "ASSOCIATED" ||
          fields.state === "FOUR_WAY_HANDSHAKE" ||
          fields.state === "GROUP_HANDSHAKE" ||
          fields.state === "COMPLETED")) {
       setBackgroundScan("OFF", function() {});
     }
     fields.prevState = manager.state;
@@ -702,32 +705,19 @@ var WifiManager = (function() {
     }
 
     if (ip_address)
       dhcpInfo = { ip_address: ip_address };
 
     notifyStateChange({ state: state, fromStatus: true });
 
     // If we parse the status and the supplicant has already entered the
-    // COMPLETED state, then we need to set up DHCP right away. Otherwise, if
-    // we're not actively connecting to a network, we need to turn on
-    // background scanning.
-    switch (state) {
-      case "COMPLETED":
-        onconnected();
-        break;
-
-      case "DISCONNECTED":
-      case "INACTIVE":
-      case "SCANNING":
-        setBackgroundScan("ON", function(){});
-
-      default:
-        break;
-    }
+    // COMPLETED state, then we need to set up DHCP right away.
+    if (state === "COMPLETED")
+      onconnected();
   }
 
   // try to connect to the supplicant
   var connectTries = 0;
   var retryTimer = null;
   function connectCallback(ok) {
     if (ok === 0) {
       // Tell the event worker to start waiting for events.
@@ -809,16 +799,27 @@ var WifiManager = (function() {
      "COMPLETED", "DORMANT", "UNINITIALIZED"];
 
   var driverEventMap = { STOPPED: "driverstopped", STARTED: "driverstarted", HANGED: "driverhung" };
 
   // handle events sent to us by the event worker
   function handleEvent(event) {
     debug("Event coming in: " + event);
     if (event.indexOf("CTRL-EVENT-") !== 0 && event.indexOf("WPS") !== 0) {
+      // Handle connection fail exception on WEP-128, while password length
+      // is not 5 nor 13 bytes.
+      if (event.indexOf("Association request to the driver failed") !== -1) {
+        notify("passwordmaybeincorrect");
+        if (manager.authenticationFailuresCount > MAX_RETRIES_ON_AUTHENTICATION_FAILURE) {
+          notify("disconnected");
+          manager.authenticationFailuresCount = 0;
+        }
+        return true;
+      }
+
       if (event.indexOf("WPA:") == 0 &&
           event.indexOf("pre-shared key may be incorrect") != -1) {
         notify("passwordmaybeincorrect");
       }
 
       // This is ugly, but we need to grab the SSID here. While we're at it,
       // we grab the BSSID as well.
       var match = /Trying to associate with ([^ ]+) \(SSID='([^']+)' freq=\d+ MHz\)/.exec(event);
@@ -846,17 +847,19 @@ var WifiManager = (function() {
       fields.state = supplicantStatesMap[fields.state];
 
       // The BSSID field is only valid in the ASSOCIATING and ASSOCIATED
       // states, except when we "reauth", except this seems to depend on the
       // driver, so simply check to make sure that we don't have a null BSSID.
       if (fields.BSSID !== "00:00:00:00:00:00")
         manager.connectionInfo.bssid = fields.BSSID;
 
-      notifyStateChange(fields);
+      if (notifyStateChange(fields) && fields.state === "COMPLETED") {
+        onconnected();
+      }
       return true;
     }
     if (eventData.indexOf("CTRL-EVENT-DRIVER-STATE") === 0) {
       var handlerName = driverEventMap[eventData];
       if (handlerName)
         notify(handlerName);
       return true;
     }
@@ -886,25 +889,26 @@ var WifiManager = (function() {
       manager.connectionInfo.ssid = null;
       manager.connectionInfo.id = -1;
       if (manager.authenticationFailuresCount > MAX_RETRIES_ON_AUTHENTICATION_FAILURE) {
         notify("disconnected", {BSSID: bssid});
         manager.authenticationFailuresCount = 0;
       }
       return true;
     }
+    // Association reject is triggered mostly on incorrect WEP key.
+    if (eventData.indexOf("CTRL-EVENT-ASSOC-REJECT") === 0) {
+      notify("passwordmaybeincorrect");
+      if (manager.authenticationFailuresCount > MAX_RETRIES_ON_AUTHENTICATION_FAILURE) {
+        notify("disconnected");
+        manager.authenticationFailuresCount = 0;
+      }
+      return true;
+    }
     if (eventData.indexOf("CTRL-EVENT-CONNECTED") === 0) {
-      // Format: CTRL-EVENT-CONNECTED - Connection to 00:1e:58:ec:d5:6d completed (reauth) [id=1 id_str=]
-      var bssid = eventData.split(" ")[4];
-      var id = eventData.substr(eventData.indexOf("id=")).split(" ")[0];
-
-      // Don't call onconnected if we ignored this state change (since we were
-      // already connected).
-      if (notifyStateChange({ state: "CONNECTED", BSSID: bssid, id: id }))
-        onconnected();
       return true;
     }
     if (eventData.indexOf("CTRL-EVENT-SCAN-RESULTS") === 0) {
       debug("Notifying of scan results available");
       if (reEnableBackgroundScan) {
         reEnableBackgroundScan = false;
         setBackgroundScan("ON", function() {});
       }
@@ -1510,16 +1514,46 @@ function WifiWorker() {
 
   this.currentNetwork = null;
   this.ipAddress = "";
 
   this._lastConnectionInfo = null;
   this._connectionInfoTimer = null;
   this._reconnectOnDisconnect = false;
 
+  // XXX On some phones (Otoro and Unagi) the wifi driver doesn't play nicely
+  // with the automatic scans that wpa_supplicant does (it appears that the
+  // driver forgets that it's returned scan results and then refuses to try to
+  // rescan. In order to detect this case we start a timer when we enter the
+  // SCANNING state and reset it whenever we either get scan results or leave
+  // the SCANNING state. If the timer fires, we assume that we are stuck and
+  // forceably try to unstick the supplican, also turning on background
+  // scanning to avoid having to constantly poke the supplicant.
+
+  // How long we wait is controlled by the SCAN_STUCK_WAIT constant.
+  const SCAN_STUCK_WAIT = 12000;
+  this._scanStuckTimer = null;
+  this._turnOnBackgroundScan = false;
+
+  function startScanStuckTimer() {
+    self._scanStuckTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    self._scanStuckTimer.initWithCallback(scanIsStuck, SCAN_STUCK_WAIT,
+                                          Ci.nsITimer.TYPE_ONE_SHOT);
+  }
+
+  function scanIsStuck() {
+    // Uh-oh, we've waited too long for scan results. Disconnect (which
+    // guarantees that we leave the SCANNING state and tells wpa_supplicant to
+    // wait for our next command) ensure that background scanning is on and
+    // then try again.
+    debug("Determined that scanning is stuck, turning on background scanning!");
+    WifiManager.disconnect(function(ok) {});
+    self._turnOnBackgroundScan = true;
+  }
+
   // A list of requests to turn wifi on or off.
   this._stateRequests = [];
 
   // Given a connection status network, takes a network from
   // self.configuredNetworks and prepares it for the DOM.
   netToDOM = function(net) {
     var ssid = dequote(net.ssid);
     var capabilities = (net.key_mgmt === "NONE" && net.wep_key0)
@@ -1621,16 +1655,18 @@ function WifiWorker() {
       self.waitForScan(function firstScan() {});
     });
 
     // Check if we need to dequeue requests first.
     self._notifyAfterStateChange(true, true);
 
     // Notify everybody, even if they didn't ask us to come up.
     self._fireEvent("wifiUp", {});
+    if (WifiManager.state === "SCANNING")
+      startScanStuckTimer();
   };
 
   WifiManager.onsupplicantlost = function() {
     WifiManager.enabled = WifiManager.supplicantStarted = false;
     self._updateWifiSetting(false);
     WifiManager.state = "UNINITIALIZED";
     debug("Supplicant died!");
 
@@ -1667,16 +1703,22 @@ function WifiWorker() {
     debug("State change: " + this.prevState + " -> " + this.state);
 
     if (self._connectionInfoTimer &&
         this.state !== "CONNECTED" &&
         this.state !== "COMPLETED") {
       self._stopConnectionInfoTimer();
     }
 
+    if (this.state !== "SCANNING" &&
+        self._scanStuckTimer) {
+      self._scanStuckTimer.cancel();
+      self._scanStuckTimer = null;
+    }
+
     switch (this.state) {
       case "DORMANT":
         // The dormant state is a bad state to be in since we won't
         // automatically connect. Try to knock us out of it. We only
         // hit this state when we've failed to run DHCP, so trying
         // again isn't the worst thing we can do. Eventually, we'll
         // need to detect if we're looping in this state and bail out.
         WifiManager.reconnect(function(){});
@@ -1729,27 +1771,32 @@ function WifiWorker() {
         break;
       case "CONNECTED":
         break;
       case "DISCONNECTED":
         self._fireEvent("ondisconnect", {});
         self.currentNetwork = null;
         self.ipAddress = "";
 
+        if (self._turnOnBackgroundScan) {
+          self._turnOnBackgroundScan = false;
+          WifiManager.setBackgroundScan("ON", function(did_something, ok) {
+            WifiManager.reassociate(function() {});
+          });
+        }
+
         WifiManager.connectionDropped(function() {
           // We've disconnected from a network because of a call to forgetNetwork.
           // Reconnect to the next available network (if any).
           if (self._reconnectOnDisconnect) {
             self._reconnectOnDisconnect = false;
             WifiManager.reconnect(function(){});
           }
         });
 
-        WifiManager.setBackgroundScan("ON", function(){});
-
         WifiNetworkInterface.state =
           Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED;
         WifiNetworkInterface.ip = null;
         WifiNetworkInterface.netmask = null;
         WifiNetworkInterface.broadcast = null;
         WifiNetworkInterface.gateway = null;
         WifiNetworkInterface.dns1 = null;
         WifiNetworkInterface.dns2 = null;
@@ -1762,16 +1809,22 @@ function WifiWorker() {
         self._fireEvent("onwpstimeout", {});
         break;
       case "WPS_FAIL":
         self._fireEvent("onwpsfail", {});
         break;
       case "WPS_OVERLAP_DETECTED":
         self._fireEvent("onwpsoverlap", {});
         break;
+      case "SCANNING":
+        // If we're already scanning in the background, we don't need to worry
+        // about getting stuck while scanning.
+        if (!WifiManager.backgroundScanEnabled && WifiManager.enabled)
+          startScanStuckTimer();
+        break;
     }
   };
 
   WifiManager.ondhcpconnected = function() {
     if (this.info) {
       WifiNetworkInterface.state =
         Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED;
       WifiNetworkInterface.ip = this.info.ipaddr_str;
@@ -1793,16 +1846,23 @@ function WifiWorker() {
       self._lastConnectionInfo = null;
       self._fireEvent("onconnect", { network: netToDOM(self.currentNetwork) });
     } else {
       WifiManager.reassociate(function(){});
     }
   };
 
   WifiManager.onscanresultsavailable = function() {
+    if (self._scanStuckTimer) {
+      // We got scan results! We must not be stuck for now, try again.
+      self._scanStuckTimer.cancel();
+      self._scanStuckTimer.initWithCallback(scanIsStuck, SCAN_STUCK_WAIT,
+                                            Ci.nsITimer.TYPE_ONE_SHOT);
+    }
+
     if (self.wantScanResults.length === 0) {
       debug("Scan results available, but we don't need them");
       return;
     }
 
     debug("Scan results are available! Asking for them.");
     WifiManager.getScanResults(function(r) {
       // Failure.
--- a/editor/libeditor/text/nsTextEditRules.cpp
+++ b/editor/libeditor/text/nsTextEditRules.cpp
@@ -1222,18 +1222,23 @@ nsTextEditRules::RemoveIMETextFromPWBuf(
     // manage the password buffer
     mPasswordText.Cut(mPasswordIMEIndex, mPasswordIMEText.Length());
     aStart = mPasswordIMEIndex;
   }
 
   mPasswordIMEText.Assign(*aIMEString);
 }
 
-NS_IMETHODIMP nsTextEditRules::Notify(class nsITimer *) {
-  nsresult res = HideLastPWInput();
+NS_IMETHODIMP nsTextEditRules::Notify(nsITimer *)
+{
+  MOZ_ASSERT(mTimer);
+
+  // Check whether our text editor's password flag was changed before this
+  // "hide password character" timer actually fires.
+  nsresult res = IsPasswordEditor() ? HideLastPWInput() : NS_OK;
   ASSERT_PASSWORD_LENGTHS_EQUAL();
   mLastLength = 0;
   return res;
 }
 
 nsresult nsTextEditRules::HideLastPWInput() {
   if (!mLastLength) {
     // Special case, we're trying to replace a range that no longer exists
--- a/gfx/2d/Blur.cpp
+++ b/gfx/2d/Blur.cpp
@@ -7,16 +7,19 @@
 #include <algorithm>
 #include <math.h>
 #include <string.h>
 
 #include "mozilla/CheckedInt.h"
 #include "mozilla/Constants.h"
 #include "mozilla/Util.h"
 
+#include "2D.h"
+#include "Tools.h"
+
 using namespace std;