Merge m-c to b-i
authorPhil Ringnalda <philringnalda@gmail.com>
Fri, 11 Sep 2015 22:07:15 -0700
changeset 294756 d42f083c47651e0f14c6cf399703e27d3d54cf63
parent 294755 49e5ae13cfff0b1acc4f9c2d6a6a7a3ae2ba2900 (current diff)
parent 294575 9771bd5e56edd07e21cf008dcadc20d7ed970ce3 (diff)
child 294757 a3a1cbbac1c76289b8f52998c7e3b6a42798153a
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to b-i
browser/devtools/performance/test/browser_perf_recordings-io-01.js
browser/devtools/performance/test/browser_perf_recordings-io-02.js
browser/devtools/performance/test/browser_perf_recordings-io-03.js
browser/devtools/performance/test/browser_perf_recordings-io-04.js
browser/devtools/performance/test/browser_perf_recordings-io-05.js
browser/devtools/performance/test/browser_perf_recordings-io-06.js
dom/ipc/StructuredCloneIPCHelper.cpp
dom/ipc/StructuredCloneIPCHelper.h
intl/uconv/tools/gen-big5hkscs-2001-mozilla.pl
intl/uconv/tools/mozilla-xscii-hkscs-2001-uf.txt
intl/uconv/tools/mozilla-xscii-hkscs-2001-ut.txt
intl/uconv/ucvtw/big5.uf
intl/uconv/ucvtw/big5.ut
intl/uconv/ucvtw/hkscs.uf
intl/uconv/ucvtw/hkscs.ut
intl/uconv/ucvtw/nsBIG5HKSCSToUnicode.cpp
intl/uconv/ucvtw/nsBIG5HKSCSToUnicode.h
intl/uconv/ucvtw/nsUCvTWCID.h
intl/uconv/ucvtw/nsUCvTWDll.h
intl/uconv/ucvtw/nsUnicodeToBIG5HKSCS.cpp
intl/uconv/ucvtw/nsUnicodeToBIG5HKSCS.h
intl/uconv/ucvtw/readme.txt
mfbt/double-conversion/fix-aarch64-macro.patch
mfbt/double-conversion/fix-gcc-warnings.patch
services/sync/Makefile.in
testing/marionette/client/marionette/tests/unit/test_appcache.py
testing/marionette/driver/marionette_driver/application_cache.py
testing/mozbase/mozrunner/mozrunner/utils.py
testing/mozharness/configs/builds/releng_base_mac_cross_builds.py
testing/web-platform/meta/2dcontext/shadows/2d.shadow.enable.blur.html.ini
testing/web-platform/meta/2dcontext/shadows/2d.shadow.enable.x.html.ini
testing/web-platform/meta/2dcontext/shadows/2d.shadow.enable.y.html.ini
testing/web-platform/meta/encoding/textdecoder-labels.html.ini
toolkit/devtools/performance/recording-common.js
toolkit/devtools/sourcemap/tests/unit/Utils.jsm
--- a/accessible/jsat/Gestures.jsm
+++ b/accessible/jsat/Gestures.jsm
@@ -6,20 +6,16 @@
 /* exported GestureSettings, GestureTracker */
 
 /******************************************************************************
   All gestures have the following pathways when being resolved(v)/rejected(x):
                Tap -> DoubleTap        (x)
                    -> Dwell            (x)
                    -> Swipe            (x)
 
-        AndroidTap -> TripleTap        (x)
-                   -> TapHold          (x)
-                   -> Swipe            (x)
-
          DoubleTap -> TripleTap        (x)
                    -> TapHold          (x)
                    -> Explore          (x)
 
          TripleTap -> DoubleTapHold    (x)
                    -> Explore          (x)
 
              Dwell -> DwellEnd         (v)
@@ -72,22 +68,16 @@ const MAX_CONSECUTIVE_GESTURE_DELAY = 20
 const DWELL_THRESHOLD = 250;
 // Minimal swipe distance in inches
 const SWIPE_MIN_DISTANCE = 0.4;
 // Maximum distance the pointer could move during a tap in inches
 const TAP_MAX_RADIUS = 0.2;
 // Directness coefficient. It is based on the maximum 15 degree angle between
 // consequent pointer move lines.
 const DIRECTNESS_COEFF = 1.44;
-// An android flag.
-const IS_ANDROID = Utils.MozBuildApp === 'mobile/android' &&
-  Utils.AndroidSdkVersion >= 14;
-// A single pointer down/up sequence periodically precedes the tripple swipe
-// gesture on Android. This delay acounts for that.
-const ANDROID_TRIPLE_SWIPE_DELAY = 50;
 // The virtual touch ID generated by a mouse event.
 const MOUSE_ID = 'mouse';
 // Amount in inches from the edges of the screen for it to be an edge swipe
 const EDGE = 0.1;
 // Multiply timeouts by this constant, x2 works great too for slower users.
 const TIMEOUT_MULTIPLIER = 1;
 
 /**
@@ -206,22 +196,16 @@ this.GestureTracker = { // jshint ignore
    */
   _init: function GestureTracker__init(aDetail, aTimeStamp, aGesture = Tap) {
     // Only create a new gesture on |pointerdown| event.
     if (aDetail.type !== 'pointerdown') {
       return;
     }
     let points = aDetail.points;
     let GestureConstructor = aGesture;
-    if (IS_ANDROID && GestureConstructor === Tap && points.length === 1 &&
-      points[0].identifier !== MOUSE_ID) {
-      // Handle Android events when EBT is enabled. Two finger gestures are
-      // translated to one.
-      GestureConstructor = AndroidTap;
-    }
     this._create(GestureConstructor);
     this._update(aDetail, aTimeStamp);
   },
 
   /**
    * Handle the incoming pointer event with the existing gesture object(if
    * present) or with the newly created one.
    * @param  {Object} aDetail A new pointer event detail.
@@ -738,64 +722,16 @@ TapGesture.prototype.pointerdown = funct
 function Tap(aTimeStamp, aPoints, aLastEvent) {
   // If the pointer travels, reject to Swipe.
   TapGesture.call(this, aTimeStamp, aPoints, aLastEvent, Dwell, Swipe, DoubleTap);
 }
 
 Tap.prototype = Object.create(TapGesture.prototype);
 Tap.prototype.type = 'tap';
 
-/**
- * Tap (multi) gesture on Android.
- * @param {Number} aTimeStamp An original pointer event's timeStamp that started
- * the gesture resolution sequence.
- * @param {Object} aPoints An existing set of points (from previous events).
- * @param {?String} aLastEvent Last pointer event type.
- */
-function AndroidTap(aTimeStamp, aPoints, aLastEvent) {
-  // If the pointer travels, reject to Swipe. On dwell threshold reject to
-  // TapHold.
-  TapGesture.call(this, aTimeStamp, aPoints, aLastEvent, TapHold, Swipe, TripleTap);
-}
-AndroidTap.prototype = Object.create(TapGesture.prototype);
-// Android double taps are translated to single taps.
-AndroidTap.prototype.type = 'doubletap';
-
-/**
- * Clear the pointerup handler timer in case of the 3 pointer swipe.
- */
-AndroidTap.prototype.clearThreeFingerSwipeTimer = function AndroidTap_clearThreeFingerSwipeTimer() {
-  clearTimeout(this._threeFingerSwipeTimer);
-  delete this._threeFingerSwipeTimer;
-};
-
-AndroidTap.prototype.pointerdown = function AndroidTap_pointerdown(aPoints, aTimeStamp) {
-  this.clearThreeFingerSwipeTimer();
-  TapGesture.prototype.pointerdown.call(this, aPoints, aTimeStamp);
-};
-
-AndroidTap.prototype.pointermove = function AndroidTap_pointermove(aPoints) {
-  this.clearThreeFingerSwipeTimer();
-  this._moved = true;
-  TapGesture.prototype.pointermove.call(this, aPoints);
-};
-
-AndroidTap.prototype.pointerup = function AndroidTap_pointerup(aPoints) {
-  if (this._moved) {
-    // If there was a pointer move - handle the real gesture.
-    TapGesture.prototype.pointerup.call(this, aPoints);
-  } else {
-    // Primptively delay the multi pointer gesture resolution, because Android
-    // sometimes fires a pointerdown/poitnerup sequence before the real events.
-    this._threeFingerSwipeTimer = setTimeout(() => {
-      delete this._threeFingerSwipeTimer;
-      TapGesture.prototype.pointerup.call(this, aPoints);
-    }, ANDROID_TRIPLE_SWIPE_DELAY);
-  }
-};
 
 /**
  * Double Tap gesture.
  * @param {Number} aTimeStamp An original pointer event's timeStamp that started
  * the gesture resolution sequence.
  * @param {Object} aPoints An existing set of points (from previous events).
  * @param {?String} aLastEvent Last pointer event type.
  */
--- a/accessible/jsat/PointerAdapter.jsm
+++ b/accessible/jsat/PointerAdapter.jsm
@@ -34,18 +34,24 @@ let PointerRelay = { // jshint ignore:li
    * A mapping of events we should be intercepting. Entries with a value of
    * |true| are used for compiling high-level gesture events. Entries with a
    * value of |false| are cancelled and do not propogate to content.
    */
   get _eventsOfInterest() {
     delete this._eventsOfInterest;
 
     switch (Utils.widgetToolkit) {
+      case 'android':
+        this._eventsOfInterest = {
+          'touchstart' : true,
+          'touchmove' : true,
+          'touchend' : true };
+        break;
+
       case 'gonk':
-      case 'android':
         this._eventsOfInterest = {
           'touchstart' : true,
           'touchmove' : true,
           'touchend' : true,
           'mousedown' : false,
           'mousemove' : false,
           'mouseup': false,
           'click': false };
@@ -112,22 +118,17 @@ let PointerRelay = { // jshint ignore:li
       identifier: MOUSE_ID,
       screenX: aEvent.screenX,
       screenY: aEvent.screenY,
       target: aEvent.target
     }];
 
     if (Utils.widgetToolkit === 'android' &&
       changedTouches.length === 1 && changedTouches[0].identifier === 1) {
-      changedTouches = [{
-        identifier: 0,
-        screenX: changedTouches[0].screenX + 5,
-        screenY: changedTouches[0].screenY + 5,
-        target: changedTouches[0].target
-      }, changedTouches[0]];
+      return;
     }
 
     if (changedTouches.length === 1 &&
         changedTouches[0].identifier === SYNTH_ID) {
       return;
     }
 
     aEvent.preventDefault();
--- a/accessible/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/windows/msaa/AccessibleWrap.cpp
@@ -1303,45 +1303,64 @@ AccessibleWrap::GetChildIDFor(Accessible
 #else
   return - reinterpret_cast<intptr_t>(aAccessible);
 #endif
 }
 
 HWND
 AccessibleWrap::GetHWNDFor(Accessible* aAccessible)
 {
-  if (aAccessible) {
-    DocAccessible* document = aAccessible->Document();
-    if(!document)
+  if (!aAccessible) {
+    return nullptr;
+  }
+
+  // Accessibles in child processes are said to have the HWND of the window
+  // their tab is within.  Popups are always in the parent process, and so
+  // never proxied, which means this is basically correct.
+  if (aAccessible->IsProxy()) {
+    ProxyAccessible* proxy = aAccessible->Proxy();
+    if (!proxy) {
       return nullptr;
+    }
+
+    Accessible* outerDoc = proxy->OuterDocOfRemoteBrowser();
+    NS_ASSERTION(outerDoc, "no outer doc for accessible remote tab!");
+    if (!outerDoc) {
+      return nullptr;
+    }
+
+    return GetHWNDFor(outerDoc);
+  }
 
-    // Popup lives in own windows, use its HWND until the popup window is
-    // hidden to make old JAWS versions work with collapsed comboboxes (see
-    // discussion in bug 379678).
-    nsIFrame* frame = aAccessible->GetFrame();
-    if (frame) {
-      nsIWidget* widget = frame->GetNearestWidget();
-      if (widget && widget->IsVisible()) {
-        nsIPresShell* shell = document->PresShell();
-        nsViewManager* vm = shell->GetViewManager();
-        if (vm) {
-          nsCOMPtr<nsIWidget> rootWidget;
-          vm->GetRootWidget(getter_AddRefs(rootWidget));
-          // Make sure the accessible belongs to popup. If not then use
-          // document HWND (which might be different from root widget in the
-          // case of window emulation).
-          if (rootWidget != widget)
-            return static_cast<HWND>(widget->GetNativeData(NS_NATIVE_WINDOW));
-        }
+  DocAccessible* document = aAccessible->Document();
+  if(!document)
+    return nullptr;
+
+  // Popup lives in own windows, use its HWND until the popup window is
+  // hidden to make old JAWS versions work with collapsed comboboxes (see
+  // discussion in bug 379678).
+  nsIFrame* frame = aAccessible->GetFrame();
+  if (frame) {
+    nsIWidget* widget = frame->GetNearestWidget();
+    if (widget && widget->IsVisible()) {
+      nsIPresShell* shell = document->PresShell();
+      nsViewManager* vm = shell->GetViewManager();
+      if (vm) {
+        nsCOMPtr<nsIWidget> rootWidget;
+        vm->GetRootWidget(getter_AddRefs(rootWidget));
+        // Make sure the accessible belongs to popup. If not then use
+        // document HWND (which might be different from root widget in the
+        // case of window emulation).
+        if (rootWidget != widget)
+          return static_cast<HWND>(widget->GetNativeData(NS_NATIVE_WINDOW));
       }
     }
+  }
 
-    return static_cast<HWND>(document->GetNativeWindow());
-  }
-  return nullptr;
+  return static_cast<HWND>(document->GetNativeWindow());
 }
 
 IDispatch*
 AccessibleWrap::NativeAccessible(Accessible* aAccessible)
 {
   if (!aAccessible) {
     NS_WARNING("Not passing in an aAccessible");
     return nullptr;
--- a/addon-sdk/source/lib/node/os.js
+++ b/addon-sdk/source/lib/node/os.js
@@ -6,37 +6,23 @@
 
 module.metadata = {
   "stability": "unstable"
 };
 
 const { Cc, Ci } = require('chrome');
 const system = require('../sdk/system');
 const runtime = require('../sdk/system/runtime');
-const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
+const oscpu = Cc["@mozilla.org/network/protocol;1?name=http"]
+                 .getService(Ci.nsIHttpProtocolHandler).oscpu;
+const hostname = Cc["@mozilla.org/network/dns-service;1"]
+                 .getService(Ci.nsIDNSService).myHostName;
 const isWindows = system.platform === 'win32';
 const endianness = ((new Uint32Array((new Uint8Array([1,2,3,4])).buffer))[0] === 0x04030201) ? 'LE' : 'BE';
 
-XPCOMUtils.defineLazyGetter(this, "oscpu", () => {
-  try {
-    return Cc["@mozilla.org/network/protocol;1?name=http"].getService(Ci.nsIHttpProtocolHandler).oscpu;
-  } catch (e) {
-    return "";
-  }
-});
-
-XPCOMUtils.defineLazyGetter(this, "hostname", () => {
-  try {
-    // On some platforms (Linux according to try), this service does not exist and fails.
-    return Cc["@mozilla.org/network/dns-service;1"].getService(Ci.nsIDNSService).myHostName;
-  } catch (e) {
-    return "";
-  }
-});
-
 /**
  * Returns a path to a temp directory
  */
 exports.tmpdir = () => system.pathFor('TmpD');
 
 /**
  * Returns the endianness of the architecture: either 'LE' or 'BE'
  */
--- a/b2g/installer/Makefile.in
+++ b/b2g/installer/Makefile.in
@@ -107,19 +107,16 @@ endif
 
 DEFINES += -DMOZ_ICU_VERSION=$(MOZ_ICU_VERSION)
 ifdef MOZ_NATIVE_ICU
 DEFINES += -DMOZ_NATIVE_ICU
 endif
 ifdef MOZ_SHARED_ICU
 DEFINES += -DMOZ_SHARED_ICU
 endif
-ifdef MOZ_JEMALLOC4
-DEFINES += -DMOZ_JEMALLOC4
-endif
 DEFINES += -DMOZ_ICU_DBG_SUFFIX=$(MOZ_ICU_DBG_SUFFIX)
 
 ifdef MOZ_WIDGET_GTK
 DEFINES += -DMOZ_GTK=1
 ifdef MOZ_ENABLE_GTK3
 DEFINES += -DMOZ_GTK3=1
 endif
 endif
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -108,21 +108,16 @@
 @BINPATH@/libicui18n.so.@MOZ_ICU_VERSION@
 @BINPATH@/libicuuc.so.@MOZ_ICU_VERSION@
 #endif
 #endif
 #endif
 #ifdef MOZ_SHARED_MOZGLUE
 @BINPATH@/@DLL_PREFIX@mozglue@DLL_SUFFIX@
 #endif
-#ifdef MOZ_REPLACE_MALLOC
-#ifndef MOZ_JEMALLOC4
-@BINPATH@/@DLL_PREFIX@replace_jemalloc@DLL_SUFFIX@
-#endif
-#endif
 #ifdef ANDROID
 @RESPATH@/AndroidManifest.xml
 @RESPATH@/resources.arsc
 @RESPATH@/classes.dex
 @RESPATH@/res/drawable
 @RESPATH@/res/drawable-hdpi
 @RESPATH@/res/layout
 #endif
@@ -622,19 +617,16 @@
 @RESPATH@/components/Nfc.js
 @RESPATH@/components/NfcContentHelper.manifest
 @RESPATH@/components/NfcContentHelper.js
 #endif
 #ifdef MOZ_SECUREELEMENT
 @RESPATH@/components/DOMSecureElement.manifest
 @RESPATH@/components/DOMSecureElement.js
 #endif
-#ifdef MOZ_ENABLE_DBUS
-@RESPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@
-#endif
 @RESPATH@/components/nsINIProcessor.manifest
 @RESPATH@/components/nsINIProcessor.js
 @RESPATH@/components/nsPrompter.manifest
 @RESPATH@/components/nsPrompter.js
 #ifdef MOZ_SERVICES_SYNC
 @RESPATH@/components/SyncComponents.manifest
 @RESPATH@/components/Weave.js
 @RESPATH@/components/WeaveCrypto.manifest
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -47,16 +47,18 @@ pref("extensions.getAddons.getWithPerfor
 pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/firefox/search?q=%TERMS%&platform=%OS%&appver=%VERSION%");
 pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/firefox/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%/%COMPATIBILITY_MODE%?src=firefox");
 pref("extensions.webservice.discoverURL", "https://services.addons.mozilla.org/%LOCALE%/firefox/discovery/pane/%VERSION%/%OS%/%COMPATIBILITY_MODE%");
 pref("extensions.getAddons.recommended.url", "https://services.addons.mozilla.org/%LOCALE%/%APP%/api/%API_VERSION%/list/recommended/all/%MAX_RESULTS%/%OS%/%VERSION%?src=firefox");
 pref("extensions.getAddons.link.url", "https://addons.mozilla.org/%LOCALE%/firefox/");
 
 // Blocklist preferences
 pref("extensions.blocklist.enabled", true);
+// OneCRL freshness checking depends on this value, so if you change it,
+// please also update security.onecrl.maximum_staleness_in_seconds.
 pref("extensions.blocklist.interval", 86400);
 // Controls what level the blocklist switches from warning about items to forcibly
 // blocking them.
 pref("extensions.blocklist.level", 2);
 pref("extensions.blocklist.url", "https://blocklist.addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PING_COUNT%/%TOTAL_PING_COUNT%/%DAYS_SINCE_LAST_PING%/");
 pref("extensions.blocklist.detailsURL", "https://www.mozilla.org/%LOCALE%/blocklist/");
 pref("extensions.blocklist.itemURL", "https://blocklist.addons.mozilla.org/%LOCALE%/%APP%/blocked/%blockID%");
 
@@ -268,23 +270,17 @@ pref("browser.urlbar.doubleClickSelectsA
 #else
 pref("browser.urlbar.doubleClickSelectsAll", false);
 #endif
 
 // Control autoFill behavior
 pref("browser.urlbar.autoFill", true);
 pref("browser.urlbar.autoFill.typed", true);
 
-#ifdef NIGHTLY_BUILD
-// Use the new unifiedComplete component
 pref("browser.urlbar.unifiedcomplete", true);
-#else
-// Don't use the new unifiedComplete component
-pref("browser.urlbar.unifiedcomplete", false);
-#endif
 
 // 0: Match anywhere (e.g., middle of words)
 // 1: Match on word boundaries and then try matching anywhere
 // 2: Match only on word boundaries (e.g., after / or .)
 // 3: Match at the beginning of the url or title
 pref("browser.urlbar.matchBehavior", 1);
 pref("browser.urlbar.filter.javascript", true);
 
@@ -1746,18 +1742,18 @@ pref("dom.identity.enabled", false);
 
 // Block insecure active content on https pages
 pref("security.mixed_content.block_active_content", true);
 
 // 1 = allow MITM for certificate pinning checks.
 pref("security.cert_pinning.enforcement_level", 1);
 
 // Required blocklist freshness for OneCRL OCSP bypass
-// (default should be at least as large as extensions.blocklist.interval)
-pref("security.onecrl.maximum_staleness_in_seconds", 0);
+// (default is 1.25x extensions.blocklist.interval, or 30 hours)
+pref("security.onecrl.maximum_staleness_in_seconds", 108000);
 
 // Override the Gecko-default value of false for Firefox.
 pref("plain_text.wrap_long_lines", true);
 
 // If this turns true, Moz*Gesture events are not called stopPropagation()
 // before content.
 pref("dom.debug.propagate_gesture_events_through_content", false);
 
--- a/browser/base/content/aboutaccounts/aboutaccounts.js
+++ b/browser/base/content/aboutaccounts/aboutaccounts.js
@@ -122,22 +122,25 @@ let wrapper = {
 
     // Ideally we'd just merge urlParams with new URL(url).searchParams, but our
     // URLSearchParams implementation doesn't support iteration (bug 1085284).
     let urlParamStr = urlParams.toString();
     if (urlParamStr) {
       url += (url.includes("?") ? "&" : "?") + urlParamStr;
     }
     this.url = url;
-    iframe.src = url;
+    // Set the iframe's location with loadURI/LOAD_FLAGS_BYPASS_HISTORY to
+    // avoid having a new history entry being added.
+    let webNav = iframe.frameLoader.docShell.QueryInterface(Ci.nsIWebNavigation);
+    webNav.loadURI(url, Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY, null, null, null);
   },
 
   retry: function () {
     let webNav = this.iframe.frameLoader.docShell.QueryInterface(Ci.nsIWebNavigation);
-    webNav.loadURI(this.url, null, null, null, null);
+    webNav.loadURI(this.url, Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY, null, null, null);
   },
 
   iframeListener: {
     QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
                                          Ci.nsISupportsWeakReference,
                                          Ci.nsISupports]),
 
     onStateChange: function(aWebProgress, aRequest, aState, aStatus) {
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -120,16 +120,31 @@ let gSyncUI = {
     try {
       firstSync = Services.prefs.getCharPref("services.sync.firstSync");
     } catch (e) { }
 
     return Weave.Status.checkSetup() == Weave.CLIENT_NOT_CONFIGURED ||
            firstSync == "notReady";
   },
 
+  _needsVerification() {
+    // For callers who care about the distinction between "needs setup" and
+    // "setup but needs verification"
+    // See _needsSetup for the subtleties here.
+    if (Weave.Status._authManager._signedInUser === undefined) {
+      // a legacy sync user - no "verified" concept there.
+      return false;
+    }
+    if (!Weave.Status._authManager._signedInUser) {
+      // no user configured at all, so not in a "need verification" state.
+      return false;
+    }
+    return !Weave.Status._authManager._signedInUser.verified;
+  },
+
   // Note that we don't show login errors in a notification bar here, but do
   // still need to track a login-failed state so the "Tools" menu updates
   // with the correct state.
   _loginFailed: function () {
     this.log.debug("_loginFailed has sync state=${sync}",
                    { sync: Weave.Status.login});
     return Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED;
   },
@@ -149,31 +164,17 @@ let gSyncUI = {
       // unhiding this element makes the menubar show the login failure state.
       document.getElementById("sync-reauth-state").hidden = false;
     } else if (needsSetup) {
       document.getElementById("sync-setup-state").hidden = false;
     } else {
       document.getElementById("sync-syncnow-state").hidden = false;
     }
 
-    if (!gBrowser)
-      return;
-
-    let syncButton = document.getElementById("sync-button");
-    let statusButton = document.getElementById("PanelUI-fxa-icon");
-    if (needsSetup) {
-      if (syncButton) {
-        syncButton.removeAttribute("tooltiptext");
-      }
-      if (statusButton) {
-        statusButton.removeAttribute("tooltiptext");
-      }
-    }
-
-    this._updateLastSyncTime();
+    this._updateSyncButtonsTooltip();
   },
 
   // Functions called by observers
   onActivityStart() {
     if (!gBrowser)
       return;
 
     this.log.debug("onActivityStart with numActive", this._numActiveSyncTasks);
@@ -306,49 +307,70 @@ let gSyncUI = {
   openPrefs: function (entryPoint) {
     openPreferences("paneSync", { urlParams: { entrypoint: entryPoint } });
   },
 
   openSignInAgainPage: function (entryPoint = "syncbutton") {
     gFxAccounts.openSignInAgainPage(entryPoint);
   },
 
-  // Helpers
-  _updateLastSyncTime: function SUI__updateLastSyncTime() {
+  /* Update the tooltip for the Sync Toolbar button and the Sync spinner in the
+     FxA hamburger area.
+     If Sync is configured, the tooltip is when the last sync occurred,
+     otherwise the tooltip reflects the fact that Sync needs to be
+     (re-)configured.
+  */
+  _updateSyncButtonsTooltip: function() {
     if (!gBrowser)
       return;
 
     let syncButton = document.getElementById("sync-button");
     let statusButton = document.getElementById("PanelUI-fxa-icon");
 
-    let lastSync;
+    let email;
     try {
-      lastSync = new Date(Services.prefs.getCharPref("services.sync.lastSync"));
-    }
-    catch (e) { };
-    if (!lastSync || this._needsSetup()) {
-      if (syncButton) {
-        syncButton.removeAttribute("tooltiptext");
-      }
-      if (statusButton) {
-        statusButton.removeAttribute("tooltiptext");
+      email = Services.prefs.getCharPref("services.sync.username");
+    } catch (ex) {}
+
+    // This is a little messy as the Sync buttons are 1/2 Sync related and
+    // 1/2 FxA related - so for some strings we use Sync strings, but for
+    // others we reach into gFxAccounts for strings.
+    let tooltiptext;
+    if (this._needsVerification()) {
+      // "needs verification"
+      tooltiptext = gFxAccounts.strings.formatStringFromName("verifyDescription", [email], 1);
+    } else if (this._needsSetup()) {
+      // "needs setup".
+      tooltiptext = this._stringBundle.GetStringFromName("signInToSync.description");
+    } else if (this._loginFailed()) {
+      // "need to reconnect/re-enter your password"
+      tooltiptext = gFxAccounts.strings.formatStringFromName("reconnectDescription", [email], 1);
+    } else {
+      // Sync appears configured - format the "last synced at" time.
+      try {
+        let lastSync = new Date(Services.prefs.getCharPref("services.sync.lastSync"));
+        // Show the day-of-week and time (HH:MM) of last sync
+        let lastSyncDateString = lastSync.toLocaleFormat("%a %H:%M");
+        tooltiptext = this._stringBundle.formatStringFromName("lastSync2.label", [lastSyncDateString], 1);
       }
-      return;
+      catch (e) {
+        // pref doesn't exist (which will be the case until we've seen the
+        // first successful sync) or is invalid (which should be impossible!)
+        // Just leave tooltiptext as the empty string in these cases, which
+        // will cause the tooltip to be removed below.
+      }
     }
-
-    // Show the day-of-week and time (HH:MM) of last sync
-    let lastSyncDateString = lastSync.toLocaleFormat("%a %H:%M");
-    let lastSyncLabel =
-      this._stringBundle.formatStringFromName("lastSync2.label", [lastSyncDateString], 1);
-
-    if (syncButton) {
-      syncButton.setAttribute("tooltiptext", lastSyncLabel);
-    }
-    if (statusButton) {
-      statusButton.setAttribute("tooltiptext", lastSyncLabel);
+    for (let button of [syncButton, statusButton]) {
+      if (button) {
+        if (tooltiptext) {
+          button.setAttribute("tooltiptext", tooltiptext);
+        } else {
+          button.removeAttribute("tooltiptext");
+        }
+      }
     }
   },
 
   clearError: function SUI_clearError(errorString) {
     Weave.Notifications.removeAll(errorString);
     this.updateUI();
   },
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -6928,18 +6928,18 @@ var gIdentityHandler = {
     // whitelist below and don't resolve to file:// URIs internally.
     let unknown = false;
     try {
       uri.host;
     } catch (e) { unknown = true; }
 
     // Chrome URIs however get special treatment. Some chrome URIs are
     // whitelisted to provide a positive security signal to the user.
-    let whitelist = /^about:(accounts|addons|app-manager|config|crashes|customizing|downloads|healthreport|home|license|newaddon|permissions|preferences|privatebrowsing|rights|sessionrestore|support|welcomeback)/i;
-    let isChromeUI = uri.schemeIs("about") && whitelist.test(uri.spec);
+    let whitelist = /^(?:accounts|addons|app-manager|cache|config|crashes|customizing|downloads|healthreport|home|license|newaddon|permissions|preferences|privatebrowsing|rights|sessionrestore|support|welcomeback)(?:[?#]|$)/i;
+    let isChromeUI = uri.schemeIs("about") && whitelist.test(uri.path);
     let mode = this.IDENTITY_MODE_UNKNOWN;
 
     if (isChromeUI) {
       mode = this.IDENTITY_MODE_CHROMEUI;
     } else if (unknown) {
       // Use default mode.
     } else if (state & nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL) {
       if (state & nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT) {
@@ -7210,21 +7210,27 @@ var gIdentityHandler = {
     // Update per-site permissions section.
     this.updateSitePermissions();
   },
 
   _isURILoadedFromFile(uri) {
     // Create a channel for the sole purpose of getting the resolved URI
     // of the request to determine if it's loaded from the file system.
     let chanOptions = {uri, loadUsingSystemPrincipal: true};
-    let resolvedURI = NetUtil.newChannel(chanOptions).URI;
-    if (resolvedURI.schemeIs("jar")) {
-      // Given a URI "jar:<jar-file-uri>!/<jar-entry>"
-      // create a new URI using <jar-file-uri>!/<jar-entry>
-      resolvedURI = NetUtil.newURI(resolvedURI.path);
+    let resolvedURI;
+    try {
+      resolvedURI = NetUtil.newChannel(chanOptions).URI;
+      if (resolvedURI.schemeIs("jar")) {
+        // Given a URI "jar:<jar-file-uri>!/<jar-entry>"
+        // create a new URI using <jar-file-uri>!/<jar-entry>
+        resolvedURI = NetUtil.newURI(resolvedURI.path);
+      }
+    } catch (ex) {
+      // NetUtil's methods will throw for malformed URIs and the like
+      return false;
     }
 
     // Check the URI again after resolving.
     return resolvedURI.schemeIs("file");
   },
 
   /**
    * Click handler for the identity-box element in primary chrome.
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -2485,16 +2485,17 @@
             // fire the beforeunload event in the process.  Close the other
             // window if this was its last tab.
             if (!remoteBrowser._beginRemoveTab(aOtherTab, true, true))
               return;
 
             let modifiedAttrs = [];
             if (aOtherTab.hasAttribute("muted")) {
               aOurTab.setAttribute("muted", "true");
+              ourBrowser.mute();
               modifiedAttrs.push("muted");
             }
             if (aOtherTab.hasAttribute("soundplaying")) {
               aOurTab.setAttribute("soundplaying", "true");
               modifiedAttrs.push("soundplaying");
             }
 
             // If the other tab is pending (i.e. has not been restored, yet)
--- a/browser/base/content/test/general/browser_audioTabIcon.js
+++ b/browser/base/content/test/general/browser_audioTabIcon.js
@@ -208,16 +208,20 @@ function* test_swapped_browser(oldTab, n
   ok(newTab.hasAttribute("muted"), "Expected the correct muted attribute on the new tab");
   is(newTab.hasAttribute("soundplaying"), isPlaying, "Expected the correct soundplaying attribute on the new tab");
 
   // Wait to see if an audio-playback event is dispatched.  This should not happen!
   yield AudioPlaybackPromise;
 
   ok(newTab.hasAttribute("muted"), "Expected the correct muted attribute on the new tab");
   is(newTab.hasAttribute("soundplaying"), isPlaying, "Expected the correct soundplaying attribute on the new tab");
+
+  let icon = document.getAnonymousElementByAttribute(newTab, "anonid",
+                                                     "soundplaying-icon");
+  yield test_tooltip(icon, "Unmute tab", true);
 }
 
 function* test_browser_swapping(tab, browser) {
   // First, test swapping with a playing but muted tab.
   yield play(tab);
 
   let icon = document.getAnonymousElementByAttribute(tab, "anonid",
                                                      "soundplaying-icon");
--- a/browser/base/content/test/general/browser_syncui.js
+++ b/browser/base/content/test/general/browser_syncui.js
@@ -29,45 +29,84 @@ function promiseObserver(topic) {
     let obs = (subject, topic, data) => {
       Services.obs.removeObserver(obs, topic);
       resolve(subject);
     }
     Services.obs.addObserver(obs, topic, false);
   });
 }
 
+function checkButtonTooltips(stringPrefix) {
+  for (let butId of ["sync-button", "PanelUI-fxa-icon"]) {
+    let text = document.getElementById(butId).getAttribute("tooltiptext");
+    let desc = `Text is "${text}", expecting it to start with "${stringPrefix}"`
+    Assert.ok(text.startsWith(stringPrefix), desc);
+  }
+}
+
 add_task(function* prepare() {
+  // add the Sync button to the toolbar so we can get it!
+  CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_NAVBAR);
+  registerCleanupFunction(() => {
+    CustomizableUI.removeWidgetFromArea("sync-button");
+  });
+
   let xps = Components.classes["@mozilla.org/weave/service;1"]
                               .getService(Components.interfaces.nsISupports)
                               .wrappedJSObject;
   yield xps.whenLoaded();
+  // Put Sync and the UI into a known state.
+  Weave.Status.login = Weave.LOGIN_FAILED_NO_USERNAME;
+  Services.obs.notifyObservers(null, "weave:ui:clear-error", null);
+
   checkBroadcasterVisible("sync-setup-state");
+  checkButtonTooltips("Sign In To Sync");
   // mock out the "_needsSetup()" function so we don't short-circuit.
   let oldNeedsSetup = window.gSyncUI._needsSetup;
   window.gSyncUI._needsSetup = () => false;
   registerCleanupFunction(() => {
     window.gSyncUI._needsSetup = oldNeedsSetup;
+    // and an observer to set the state back to what it should be now we've
+    // restored the stub.
+    Services.obs.notifyObservers(null, "weave:ui:clear-error", null);
   });
   // and a notification to have the state change away from "needs setup"
   Services.obs.notifyObservers(null, "weave:ui:clear-error", null);
   checkBroadcasterVisible("sync-syncnow-state");
 });
 
+add_task(function* testSyncNeedsVerification() {
+  Assert.equal(Notifications.notifications.length, 0, "start with no notifications");
+  // mock out the "_needsVerification()" function
+  let oldNeedsVerification = window.gSyncUI._needsVerification;
+  window.gSyncUI._needsVerification = () => true;
+  try {
+    // a notification for the state change
+    Services.obs.notifyObservers(null, "weave:ui:clear-error", null);
+    checkButtonTooltips("Verify");
+  } finally {
+    window.gSyncUI._needsVerification = oldNeedsVerification;
+  }
+});
+
+
 add_task(function* testSyncLoginError() {
   Assert.equal(Notifications.notifications.length, 0, "start with no notifications");
   checkBroadcasterVisible("sync-syncnow-state");
 
   // Pretend we are in a "login failed" error state
   Weave.Status.sync = Weave.LOGIN_FAILED;
   Weave.Status.login = Weave.LOGIN_FAILED_LOGIN_REJECTED;
   Services.obs.notifyObservers(null, "weave:ui:sync:error", null);
 
   Assert.equal(Notifications.notifications.length, 0, "no notifications shown on login error");
   // But the menu *should* reflect the login error.
   checkBroadcasterVisible("sync-reauth-state");
+  // The tooltips for the buttons should also reflect it.
+  checkButtonTooltips("Reconnect");
 
   // Now pretend we just had a successful login - the error notification should go away.
   Weave.Status.sync = Weave.STATUS_OK;
   Weave.Status.login = Weave.LOGIN_SUCCEEDED;
   Services.obs.notifyObservers(null, "weave:service:login:start", null);
   Services.obs.notifyObservers(null, "weave:service:login:finish", null);
   Assert.equal(Notifications.notifications.length, 0, "no notifications left");
   // The menus should be back to "all good"
@@ -91,32 +130,41 @@ function testButtonActions(startNotifica
   // pretend a sync is starting.
   Services.obs.notifyObservers(null, startNotification, null);
   checkButtonsStatus(true);
   // and has stopped
   Services.obs.notifyObservers(null, endNotification, null);
   checkButtonsStatus(false);
 }
 
-add_task(function* testButtonActivities() {
-  // add the Sync button to the panel so we can get it!
+function doTestButtonActivities() {
+  testButtonActions("weave:service:login:start", "weave:service:login:finish");
+  testButtonActions("weave:service:login:start", "weave:service:login:error");
+
+  testButtonActions("weave:service:sync:start", "weave:service:sync:finish");
+  testButtonActions("weave:service:sync:start", "weave:service:sync:error");
+
+  // and ensure the counters correctly handle multiple in-flight syncs
+  Services.obs.notifyObservers(null, "weave:service:sync:start", null);
+  checkButtonsStatus(true);
+  // sync stops.
+  Services.obs.notifyObservers(null, "weave:service:sync:finish", null);
+  // Button should not be active.
+  checkButtonsStatus(false);
+}
+
+add_task(function* testButtonActivitiesInNavBar() {
+  // check the button's functionality while the button is in the NavBar - which
+  // it already is.
+  doTestButtonActivities();
+});
+
+add_task(function* testButtonActivitiesInPanel() {
+  // check the button's functionality while the button is in the panel - it's
+  // currently in the NavBar - move it to the panel and open it.
   CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
-  // check the button's functionality
   yield PanelUI.show();
   try {
-    testButtonActions("weave:service:login:start", "weave:service:login:finish");
-    testButtonActions("weave:service:login:start", "weave:service:login:error");
-
-    testButtonActions("weave:service:sync:start", "weave:service:sync:finish");
-    testButtonActions("weave:service:sync:start", "weave:service:sync:error");
-
-    // and ensure the counters correctly handle multiple in-flight syncs
-    Services.obs.notifyObservers(null, "weave:service:sync:start", null);
-    checkButtonsStatus(true);
-    // sync stops.
-    Services.obs.notifyObservers(null, "weave:service:sync:finish", null);
-    // Button should not be active.
-    checkButtonsStatus(false);
+    doTestButtonActivities();
   } finally {
     PanelUI.hide();
-    CustomizableUI.removeWidgetFromArea("sync-button");
   }
 });
--- a/browser/base/content/test/general/content_aboutAccounts.js
+++ b/browser/base/content/test/general/content_aboutAccounts.js
@@ -31,17 +31,17 @@ addEventListener("DOMContentLoaded", fun
   // We use DOMContentLoaded here as that fires for our iframe even when we've
   // arranged for the URL in the iframe to cause an error.
   addEventListener("DOMContentLoaded", function iframeLoaded(event) {
     if (iframe.contentWindow.location.href == "about:blank" ||
         event.target != iframe.contentDocument) {
       return;
     }
     removeEventListener("DOMContentLoaded", iframeLoaded, true);
-    sendAsyncMessage("test:iframe:load", {url: iframe.getAttribute("src")});
+    sendAsyncMessage("test:iframe:load", {url: iframe.contentDocument.location.href});
     // And an event listener for the test responses, which we send to the test
     // via a message.
     iframe.contentWindow.addEventListener("FirefoxAccountsTestResponse", function (event) {
       sendAsyncMessage("test:response", {data: event.detail.data});
     }, true);
   }, true);
 }, true);
 
@@ -74,14 +74,14 @@ addMessageListener("test:load-with-mocke
     let iframe = content.document.getElementById("remote");
     iframe.addEventListener("load", function iframeLoaded(event) {
       if (iframe.contentWindow.location.href == "about:blank" ||
           event.target != iframe) {
         return;
       }
       iframe.removeEventListener("load", iframeLoaded, true);
       sendAsyncMessage("test:load-with-mocked-profile-path-response",
-                       {url: iframe.getAttribute("src")});
+                       {url: iframe.contentDocument.location.href});
     }, true);
   });
   let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
   webNav.loadURI(message.data.url, webNav.LOAD_FLAGS_NONE, null, null, null);
 }, true);
--- a/browser/base/content/test/popupNotifications/browser.ini
+++ b/browser/base/content/test/popupNotifications/browser.ini
@@ -1,12 +1,14 @@
 [DEFAULT]
 support-files =
   head.js
 
+[browser_displayURI.js]
+skip-if = (os == "linux" && (debug || asan))
 [browser_popupNotification.js]
 skip-if = (os == "linux" && (debug || asan)) || e10s # e10s - Bug ?????? - popup notification test probably confused re content process notifications etc
 [browser_popupNotification_2.js]
 skip-if = (os == "linux" && (debug || asan)) || e10s # e10s - Bug ?????? - popup notification test probably confused re content process notifications etc
 [browser_popupNotification_3.js]
 skip-if = (os == "linux" && (debug || asan)) || e10s # e10s - Bug ?????? - popup notification test probably confused re content process notifications etc
 [browser_popupNotification_4.js]
 skip-if = (os == "linux" && (debug || asan)) || e10s # e10s - Bug ?????? - popup notification test probably confused re content process notifications etc
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/popupNotifications/browser_displayURI.js
@@ -0,0 +1,28 @@
+/*
+ * Make sure that the origin is shown for ContentPermissionPrompt
+ * consumers e.g. geolocation.
+*/
+
+add_task(function* test_displayURI() {
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: "https://test1.example.com/",
+  }, function*(browser) {
+    let popupShownPromise = new Promise((resolve, reject) => {
+      onPopupEvent("popupshown", function() {
+        resolve(this);
+      });
+    });
+    yield ContentTask.spawn(browser, null, function*() {
+      content.navigator.geolocation.getCurrentPosition(function (pos) {
+        // Do nothing
+      });
+    });
+    let panel = yield popupShownPromise;
+    let notification = panel.children[0];
+    let body = document.getAnonymousElementByAttribute(notification,
+                                                       "class",
+                                                       "popup-notification-body");
+    ok(body.innerHTML.includes("example.com"), "Check that at least the eTLD+1 is present in the markup");
+  });
+});
--- a/browser/components/loop/content/js/contacts.js
+++ b/browser/components/loop/content/js/contacts.js
@@ -150,17 +150,17 @@ loop.contacts = (function(_, mozL10n) {
         )
       );
     }
   });
 
   const ContactDropdown = React.createClass({displayName: "ContactDropdown",
     propTypes: {
       // If the contact is blocked or not.
-      blocked: React.PropTypes.bool.isRequired,
+      blocked: React.PropTypes.bool,
       canEdit: React.PropTypes.bool,
       handleAction: React.PropTypes.func.isRequired
     },
 
     getInitialState: function () {
       return {
         openDirUp: false
       };
@@ -170,16 +170,23 @@ loop.contacts = (function(_, mozL10n) {
       // This method is called once when the dropdown menu is added to the DOM
       // inside the contact item.  If the menu extends outside of the visible
       // area of the scrollable list, it is re-rendered in different direction.
 
       let menuNode = this.getDOMNode();
       let menuNodeRect = menuNode.getBoundingClientRect();
 
       let listNode = document.getElementsByClassName("contact-list")[0];
+      // XXX Workaround the contact-list element not being available in tests.
+      // Assumptions about the embedded DOM are a bad idea, and this needs
+      // reworking. For example, tests use a virtual DOM. Really we should
+      // rework this view with the DropdownMenuMixin, which would save some of this pain.
+      if (!listNode) {
+        return;
+      }
       let listNodeRect = listNode.getBoundingClientRect();
 
       if (menuNodeRect.top + menuNodeRect.height >=
           listNodeRect.top + listNodeRect.height) {
         this.setState({
           openDirUp: true
         });
       }
@@ -194,16 +201,32 @@ loop.contacts = (function(_, mozL10n) {
       let blockAction = this.props.blocked ? "unblock" : "block";
       let blockLabel = this.props.blocked ? "unblock_contact_menu_button"
                                           : "block_contact_menu_button";
 
       return (
         React.createElement("ul", {className: cx({ "dropdown-menu": true,
                             "dropdown-menu-up": this.state.openDirUp })}, 
           React.createElement("li", {className: cx({ "dropdown-menu-item": true,
+                              "disabled": this.props.blocked,
+                              "video-call-item": true }), 
+              "data-action": "video-call", 
+              onClick: this.onItemClick}, 
+            React.createElement("i", {className: "icon icon-video-call"}), 
+            mozL10n.get("video_call_menu_button")
+          ), 
+          React.createElement("li", {className: cx({ "dropdown-menu-item": true,
+                              "disabled": this.props.blocked,
+                              "audio-call-item": true }), 
+              "data-action": "audio-call", 
+              onClick: this.onItemClick}, 
+            React.createElement("i", {className: "icon icon-audio-call"}), 
+            mozL10n.get("audio_call_menu_button")
+          ), 
+          React.createElement("li", {className: cx({ "dropdown-menu-item": true,
                               "disabled": !this.props.canEdit }), 
               "data-action": "edit", 
               onClick: this.onItemClick}, 
             mozL10n.get("edit_contact_title")
           ), 
           React.createElement("li", {className: "dropdown-menu-item", 
               "data-action": blockAction, 
               onClick: this.onItemClick}, 
@@ -303,17 +326,17 @@ loop.contacts = (function(_, mozL10n) {
             React.createElement("div", {className: "username"}, React.createElement("strong", null, names.firstName), " ", names.lastName, 
               React.createElement("i", {className: cx({"icon icon-blocked": this.props.contact.blocked})})
             ), 
             React.createElement("div", {className: "email"}, email.value)
           ), 
           React.createElement("div", {className: "icons"}, 
             React.createElement("i", {className: "icon icon-contact-video-call", 
                onClick: this.handleAction.bind(null, "video-call")}), 
-            React.createElement("i", {className: "icon icon-vertical-ellipsis", 
+            React.createElement("i", {className: "icon icon-vertical-ellipsis icon-contact-menu-button", 
                onClick: this.showDropdownMenu})
           ), 
           this.state.showMenu
             ? React.createElement(ContactDropdown, {blocked: this.props.contact.blocked, 
                                canEdit: this.canEdit(), 
                                handleAction: this.handleAction})
             : null
           
--- a/browser/components/loop/content/js/contacts.jsx
+++ b/browser/components/loop/content/js/contacts.jsx
@@ -150,17 +150,17 @@ loop.contacts = (function(_, mozL10n) {
         </div>
       );
     }
   });
 
   const ContactDropdown = React.createClass({
     propTypes: {
       // If the contact is blocked or not.
-      blocked: React.PropTypes.bool.isRequired,
+      blocked: React.PropTypes.bool,
       canEdit: React.PropTypes.bool,
       handleAction: React.PropTypes.func.isRequired
     },
 
     getInitialState: function () {
       return {
         openDirUp: false
       };
@@ -170,16 +170,23 @@ loop.contacts = (function(_, mozL10n) {
       // This method is called once when the dropdown menu is added to the DOM
       // inside the contact item.  If the menu extends outside of the visible
       // area of the scrollable list, it is re-rendered in different direction.
 
       let menuNode = this.getDOMNode();
       let menuNodeRect = menuNode.getBoundingClientRect();
 
       let listNode = document.getElementsByClassName("contact-list")[0];
+      // XXX Workaround the contact-list element not being available in tests.
+      // Assumptions about the embedded DOM are a bad idea, and this needs
+      // reworking. For example, tests use a virtual DOM. Really we should
+      // rework this view with the DropdownMenuMixin, which would save some of this pain.
+      if (!listNode) {
+        return;
+      }
       let listNodeRect = listNode.getBoundingClientRect();
 
       if (menuNodeRect.top + menuNodeRect.height >=
           listNodeRect.top + listNodeRect.height) {
         this.setState({
           openDirUp: true
         });
       }
@@ -194,16 +201,32 @@ loop.contacts = (function(_, mozL10n) {
       let blockAction = this.props.blocked ? "unblock" : "block";
       let blockLabel = this.props.blocked ? "unblock_contact_menu_button"
                                           : "block_contact_menu_button";
 
       return (
         <ul className={cx({ "dropdown-menu": true,
                             "dropdown-menu-up": this.state.openDirUp })}>
           <li className={cx({ "dropdown-menu-item": true,
+                              "disabled": this.props.blocked,
+                              "video-call-item": true })}
+              data-action="video-call"
+              onClick={this.onItemClick}>
+            <i className="icon icon-video-call" />
+            {mozL10n.get("video_call_menu_button")}
+          </li>
+          <li className={cx({ "dropdown-menu-item": true,
+                              "disabled": this.props.blocked,
+                              "audio-call-item": true })}
+              data-action="audio-call"
+              onClick={this.onItemClick}>
+            <i className="icon icon-audio-call" />
+            {mozL10n.get("audio_call_menu_button")}
+          </li>
+          <li className={cx({ "dropdown-menu-item": true,
                               "disabled": !this.props.canEdit })}
               data-action="edit"
               onClick={this.onItemClick}>
             {mozL10n.get("edit_contact_title")}
           </li>
           <li className="dropdown-menu-item"
               data-action={blockAction}
               onClick={this.onItemClick}>
@@ -303,17 +326,17 @@ loop.contacts = (function(_, mozL10n) {
             <div className="username"><strong>{names.firstName}</strong> {names.lastName}
               <i className={cx({"icon icon-blocked": this.props.contact.blocked})} />
             </div>
             <div className="email">{email.value}</div>
           </div>
           <div className="icons">
             <i className="icon icon-contact-video-call"
                onClick={this.handleAction.bind(null, "video-call")} />
-            <i className="icon icon-vertical-ellipsis"
+            <i className="icon icon-vertical-ellipsis icon-contact-menu-button"
                onClick={this.showDropdownMenu} />
           </div>
           {this.state.showMenu
             ? <ContactDropdown blocked={this.props.contact.blocked}
                                canEdit={this.canEdit()}
                                handleAction={this.handleAction} />
             : null
           }
--- a/browser/components/loop/test/desktop-local/contacts_test.js
+++ b/browser/components/loop/test/desktop-local/contacts_test.js
@@ -3,131 +3,139 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 describe("loop.contacts", function() {
   "use strict";
 
   var expect = chai.expect;
   var TestUtils = React.addons.TestUtils;
 
+  var CALL_TYPES = loop.shared.utils.CALL_TYPES;
+
   var fakeAddContactButtonText = "Fake Add Contact Button";
   var fakeAddContactTitleText = "Fake Add Contact Title";
   var fakeEditContactButtonText = "Fake Edit Contact";
   var fakeDoneButtonText = "Fake Done";
+
+  var sandbox, fakeWindow, fakeMozLoop, mozL10nGetSpy, listView, notifications;
+  var fakeManyContacts, fakeFewerContacts;
+  var oldMozLoop = navigator.mozLoop;
+
   // The fake contacts array is copied each time mozLoop.contacts.getAll() is called.
-  var fakeManyContacts = [{
-    id: 1,
-    _guid: 1,
-    name: ["Ally Avocado"],
-    email: [{
-      "pref": true,
-      "type": ["work"],
-      "value": "ally@mail.com"
-    }],
-    tel: [{
-      "pref": true,
-      "type": ["mobile"],
-      "value": "+31-6-12345678"
-    }],
-    category: ["google"],
-    published: 1406798311748,
-    updated: 1406798311748
-  }, {
-    id: 2,
-    _guid: 2,
-    name: ["Bob Banana"],
-    email: [{
-      "pref": true,
-      "type": ["work"],
-      "value": "bob@gmail.com"
-    }],
-    tel: [{
-      "pref": true,
-      "type": ["mobile"],
-      "value": "+1-214-5551234"
-    }],
-    category: ["local"],
-    published: 1406798311748,
-    updated: 1406798311748
-  }, {
-    id: 3,
-    _guid: 3,
-    name: ["Caitlin Cantaloupe"],
-    email: [{
-      "pref": true,
-      "type": ["work"],
-      "value": "caitlin.cant@hotmail.com"
-    }],
-    category: ["local"],
-    published: 1406798311748,
-    updated: 1406798311748
-  }, {
-    id: 4,
-    _guid: 4,
-    name: ["Dave Dragonfruit"],
-    email: [{
-      "pref": true,
-      "type": ["work"],
-      "value": "dd@dragons.net"
-    }],
-    category: ["google"],
-    published: 1406798311748,
-    updated: 1406798311748
-  }, {
-    id: 5,
-    _guid: 5,
-    name: ["Erin J. Bazile"],
-    email: [{
-      "pref": true,
-      "type": ["work"],
-      "value": "erinjbazile@armyspy.com"
-    }],
-    category: ["google"],
-    published: 1406798311748,
-    updated: 1406798311748
-  }, {
-    id: 6,
-    _guid: 6,
-    name: ["Kelly F. Maldanado"],
-    email: [{
-      "pref": true,
-      "type": ["work"],
-      "value": "kellyfmaldonado@jourrapide.com"
-    }],
-    category: ["google"],
-    published: 1406798311748,
-    updated: 1406798311748
-  }, {
-    id: 7,
-    _guid: 7,
-    name: ["John J. Brown"],
-    email: [{
-      "pref": true,
-      "type": ["work"],
-      "value": "johnjbrow@johndoe.com"
-    }],
-    category: ["google"],
-    published: 1406798311748,
-    updated: 1406798311748,
-    blocked: true
-  }];
-  var fakeFewerContacts = fakeManyContacts.slice(0, 4);
-  var sandbox;
-  var fakeWindow;
-  var notifications;
-  var listView;
-  var oldMozLoop = navigator.mozLoop;
-  var mozL10nGetSpy;
+  function getFakeContacts() {
+    // Return a copy, so that tests that affect it, don't have impact on each other.
+    return [].concat([
+      {
+        id: 1,
+        _guid: 1,
+        name: ["Ally Avocado"],
+        email: [{
+          "pref": true,
+          "type": ["work"],
+          "value": "ally@mail.com"
+        }],
+        tel: [{
+          "pref": true,
+          "type": ["mobile"],
+          "value": "+31-6-12345678"
+        }],
+        category: ["google"],
+        published: 1406798311748,
+        updated: 1406798311748
+      }, {
+        id: 2,
+        _guid: 2,
+        name: ["Bob Banana"],
+        email: [{
+          "pref": true,
+          "type": ["work"],
+          "value": "bob@gmail.com"
+        }],
+        tel: [{
+          "pref": true,
+          "type": ["mobile"],
+          "value": "+1-214-5551234"
+        }],
+        category: ["local"],
+        published: 1406798311748,
+        updated: 1406798311748
+      }, {
+        id: 3,
+        _guid: 3,
+        name: ["Caitlin Cantaloupe"],
+        email: [{
+          "pref": true,
+          "type": ["work"],
+          "value": "caitlin.cant@hotmail.com"
+        }],
+        category: ["local"],
+        published: 1406798311748,
+        updated: 1406798311748
+      }, {
+        id: 4,
+        _guid: 4,
+        name: ["Dave Dragonfruit"],
+        email: [{
+          "pref": true,
+          "type": ["work"],
+          "value": "dd@dragons.net"
+        }],
+        category: ["google"],
+        published: 1406798311748,
+        updated: 1406798311748
+      }, {
+        id: 5,
+        _guid: 5,
+        name: ["Erin J. Bazile"],
+        email: [{
+          "pref": true,
+          "type": ["work"],
+          "value": "erinjbazile@armyspy.com"
+        }],
+        category: ["google"],
+        published: 1406798311748,
+        updated: 1406798311748
+      }, {
+        id: 6,
+        _guid: 6,
+        name: ["Kelly F. Maldanado"],
+        email: [{
+          "pref": true,
+          "type": ["work"],
+          "value": "kellyfmaldonado@jourrapide.com"
+        }],
+        category: ["google"],
+        published: 1406798311748,
+        updated: 1406798311748
+      }, {
+        id: 7,
+        _guid: 7,
+        name: ["John J. Brown"],
+        email: [{
+          "pref": true,
+          "type": ["work"],
+          "value": "johnjbrow@johndoe.com"
+        }],
+        category: ["google"],
+        published: 1406798311748,
+        updated: 1406798311748,
+        blocked: true
+      }
+    ]);
+  }
 
   beforeEach(function() {
     sandbox = sinon.sandbox.create();
 
     mozL10nGetSpy = sandbox.spy(document.mozL10n, "get");
 
-    navigator.mozLoop = {
+    fakeManyContacts = getFakeContacts();
+    fakeFewerContacts = fakeManyContacts.slice(0, 4);
+
+    fakeMozLoop = navigator.mozLoop = {
       getStrings: function(entityName) {
         var textContentValue = "fakeText";
         if (entityName === "add_contact_title") {
           textContentValue = fakeAddContactTitleText;
         } else if (entityName === "add_contact_button") {
           textContentValue = fakeAddContactButtonText;
         } else if (entityName === "edit_contact_title") {
           textContentValue = fakeEditContactButtonText;
@@ -141,43 +149,43 @@ describe("loop.contacts", function() {
           return true;
         } else if (pref === "contacts.gravatars.show") {
           return false;
         }
         return "";
       },
       setLoopPref: sandbox.stub(),
       getUserAvatar: function() {
-        if (navigator.mozLoop.getLoopPref("contacts.gravatars.show")) {
+        if (this.getLoopPref("contacts.gravatars.show")) {
           return "gravatarsEnabled";
         }
         return "gravatarsDisabled";
       },
       contacts: {
         getAll: function(callback) {
           callback(null, [].concat(fakeFewerContacts));
         },
         add: sandbox.stub(),
         on: sandbox.stub()
       },
       calls: {
-        startDirectCall: function() {},
-        clearCallInProgress: function() {}
+        startDirectCall: sinon.stub(),
+        clearCallInProgress: sinon.stub()
       },
       generateUUID: sandbox.stub()
     };
 
     fakeWindow = {
       close: sandbox.stub()
     };
     loop.shared.mixins.setRootObject(fakeWindow);
 
     notifications = new loop.shared.models.NotificationCollection();
 
-    document.mozL10n.initialize(navigator.mozLoop);
+    document.mozL10n.initialize(fakeMozLoop);
   });
 
   afterEach(function() {
     listView = null;
     loop.shared.mixins.setRootObject(window);
     navigator.mozLoop = oldMozLoop;
     sandbox.restore();
   });
@@ -192,165 +200,165 @@ describe("loop.contacts", function() {
       // Sanity check the reverse:
       gravatars = node.querySelectorAll(".contact img[src=gravatarsDisabled]");
       expect(gravatars.length).to.equal(enabled ? 0 : fakeFewerContacts.length);
     }
 
     it("should show the gravatars promo box", function() {
       listView = TestUtils.renderIntoDocument(
         React.createElement(loop.contacts.ContactsList, {
-          mozLoop: navigator.mozLoop,
+          mozLoop: fakeMozLoop,
           notifications: notifications,
           switchToContactAdd: sandbox.stub(),
           switchToContactEdit: sandbox.stub()
         }));
 
       var promo = listView.getDOMNode().querySelector(".contacts-gravatar-promo");
       expect(promo).to.not.equal(null);
 
       var avatars = listView.getDOMNode().querySelectorAll(".contacts-gravatar-avatars img");
       expect(avatars).to.have.length(2, "two example avatars are shown");
 
       checkGravatarContacts(false);
     });
 
     it("should not show the gravatars promo box when the 'contacts.gravatars.promo' pref is set", function() {
-      sandbox.stub(navigator.mozLoop, "getLoopPref", function(pref) {
+      sandbox.stub(fakeMozLoop, "getLoopPref", function(pref) {
         if (pref === "contacts.gravatars.promo") {
           return false;
         } else if (pref === "contacts.gravatars.show") {
           return true;
         }
         return "";
       });
 
       listView = TestUtils.renderIntoDocument(
         React.createElement(loop.contacts.ContactsList, {
-          mozLoop: navigator.mozLoop,
+          mozLoop: fakeMozLoop,
           notifications: notifications,
           switchToContactAdd: sandbox.stub(),
           switchToContactEdit: sandbox.stub()
         }));
 
       var promo = listView.getDOMNode().querySelector(".contacts-gravatar-promo");
       expect(promo).to.equal(null);
 
       checkGravatarContacts(true);
     });
 
     it("should hide the gravatars promo box when the 'use' button is clicked", function() {
       listView = TestUtils.renderIntoDocument(
         React.createElement(loop.contacts.ContactsList, {
-          mozLoop: navigator.mozLoop,
+          mozLoop: fakeMozLoop,
           notifications: notifications,
           switchToContactAdd: sandbox.stub(),
           switchToContactEdit: sandbox.stub()
         }));
 
       React.addons.TestUtils.Simulate.click(listView.getDOMNode().querySelector(
         ".contacts-gravatar-promo .secondary:last-child"));
 
-      sinon.assert.calledTwice(navigator.mozLoop.setLoopPref);
+      sinon.assert.calledTwice(fakeMozLoop.setLoopPref);
 
       var promo = listView.getDOMNode().querySelector(".contacts-gravatar-promo");
       expect(promo).to.equal(null);
     });
 
     it("should should set the prefs correctly when the 'use' button is clicked", function() {
       listView = TestUtils.renderIntoDocument(
         React.createElement(loop.contacts.ContactsList, {
-          mozLoop: navigator.mozLoop,
+          mozLoop: fakeMozLoop,
           notifications: notifications,
           switchToContactAdd: sandbox.stub(),
           switchToContactEdit: sandbox.stub()
         }));
 
       React.addons.TestUtils.Simulate.click(listView.getDOMNode().querySelector(
         ".contacts-gravatar-promo .secondary:last-child"));
 
-      sinon.assert.calledTwice(navigator.mozLoop.setLoopPref);
-      sinon.assert.calledWithExactly(navigator.mozLoop.setLoopPref, "contacts.gravatars.promo", false);
-      sinon.assert.calledWithExactly(navigator.mozLoop.setLoopPref, "contacts.gravatars.show", true);
+      sinon.assert.calledTwice(fakeMozLoop.setLoopPref);
+      sinon.assert.calledWithExactly(fakeMozLoop.setLoopPref, "contacts.gravatars.promo", false);
+      sinon.assert.calledWithExactly(fakeMozLoop.setLoopPref, "contacts.gravatars.show", true);
     });
 
     it("should hide the gravatars promo box when the 'close' button is clicked", function() {
       listView = TestUtils.renderIntoDocument(
         React.createElement(loop.contacts.ContactsList, {
-          mozLoop: navigator.mozLoop,
+          mozLoop: fakeMozLoop,
           notifications: notifications,
           switchToContactAdd: sandbox.stub(),
           switchToContactEdit: sandbox.stub()
         }));
 
       React.addons.TestUtils.Simulate.click(listView.getDOMNode().querySelector(
         ".contacts-gravatar-promo .secondary:first-child"));
 
       var promo = listView.getDOMNode().querySelector(".contacts-gravatar-promo");
       expect(promo).to.equal(null);
     });
 
     it("should set prefs correctly when the 'close' button is clicked", function() {
       listView = TestUtils.renderIntoDocument(
         React.createElement(loop.contacts.ContactsList, {
-          mozLoop: navigator.mozLoop,
+          mozLoop: fakeMozLoop,
           notifications: notifications,
           switchToContactAdd: sandbox.stub(),
           switchToContactEdit: sandbox.stub()
         }));
 
       React.addons.TestUtils.Simulate.click(listView.getDOMNode().querySelector(
         ".contacts-gravatar-promo .secondary:first-child"));
 
-      sinon.assert.calledOnce(navigator.mozLoop.setLoopPref);
-      sinon.assert.calledWithExactly(navigator.mozLoop.setLoopPref,
+      sinon.assert.calledOnce(fakeMozLoop.setLoopPref);
+      sinon.assert.calledWithExactly(fakeMozLoop.setLoopPref,
         "contacts.gravatars.promo", false);
     });
 
     it("should hide the gravatars promo box when the 'close' X button is clicked", function() {
       listView = TestUtils.renderIntoDocument(
         React.createElement(loop.contacts.ContactsList, {
-          mozLoop: navigator.mozLoop,
+          mozLoop: fakeMozLoop,
           notifications: notifications,
           switchToContactAdd: sandbox.stub(),
           switchToContactEdit: sandbox.stub()
         }));
 
       React.addons.TestUtils.Simulate.click(listView.getDOMNode().querySelector(
         ".contacts-gravatar-promo .button-close"));
 
       var promo = listView.getDOMNode().querySelector(".contacts-gravatar-promo");
       expect(promo).to.equal(null);
     });
 
     it("should set prefs correctly when the 'close' X button is clicked", function() {
       listView = TestUtils.renderIntoDocument(
         React.createElement(loop.contacts.ContactsList, {
-          mozLoop: navigator.mozLoop,
+          mozLoop: fakeMozLoop,
           notifications: notifications,
           switchToContactAdd: sandbox.stub(),
           switchToContactEdit: sandbox.stub()
         }));
 
       React.addons.TestUtils.Simulate.click(listView.getDOMNode().querySelector(
         ".contacts-gravatar-promo .button-close"));
 
-      sinon.assert.calledOnce(navigator.mozLoop.setLoopPref);
-      sinon.assert.calledWithExactly(navigator.mozLoop.setLoopPref,
+      sinon.assert.calledOnce(fakeMozLoop.setLoopPref);
+      sinon.assert.calledWithExactly(fakeMozLoop.setLoopPref,
         "contacts.gravatars.promo", false);
     });
   });
 
   describe("ContactsControllerView - contactAdd", function() {
     var view;
 
     beforeEach(function() {
       view = TestUtils.renderIntoDocument(
         React.createElement(loop.contacts.ContactsControllerView, {
           initialSelectedTabComponent: "contactAdd",
-          mozLoop: navigator.mozLoop,
+          mozLoop: fakeMozLoop,
           notifications: notifications
         }));
     });
 
     it("should switch component to Contact List view", function() {
       view.switchComponentView("contactList")();
 
       expect(view.refs.contacts_list).to.not.eql(null);
@@ -359,17 +367,17 @@ describe("loop.contacts", function() {
 
   describe("ContactsControllerView - contactEdit", function() {
     var view;
 
     beforeEach(function() {
       view = TestUtils.renderIntoDocument(
         React.createElement(loop.contacts.ContactsControllerView, {
           initialSelectedTabComponent: "contactEdit",
-          mozLoop: navigator.mozLoop,
+          mozLoop: fakeMozLoop,
           notifications: notifications
         }));
     });
 
     it("should switch component to Contact List view", function() {
       view.switchComponentView("contactList")();
 
       expect(view.refs.contacts_list).to.not.eql(null);
@@ -378,17 +386,17 @@ describe("loop.contacts", function() {
 
   describe("ContactsControllerView - contactList", function() {
     var view;
 
     beforeEach(function() {
       view = TestUtils.renderIntoDocument(
         React.createElement(loop.contacts.ContactsControllerView, {
           initialSelectedTabComponent: "contactList",
-          mozLoop: navigator.mozLoop,
+          mozLoop: fakeMozLoop,
           notifications: notifications
         }));
     });
 
     it("should switch component to Contact Add view", function() {
       view.handleAddEditContact("contactAdd")({});
 
       expect(view.refs.contacts_add).to.not.eql(null);
@@ -398,29 +406,25 @@ describe("loop.contacts", function() {
       view.handleAddEditContact("contactEdit")();
 
       expect(view.refs.contacts_edit).to.not.eql(null);
     });
   });
 
   describe("ContactsList", function () {
     var node;
-    beforeEach(function() {
-      sandbox.stub(navigator.mozLoop.calls, "startDirectCall");
-      sandbox.stub(navigator.mozLoop.calls, "clearCallInProgress");
-    });
 
     describe("#RenderNoContacts", function() {
       beforeEach(function() {
-        sandbox.stub(navigator.mozLoop.contacts, "getAll", function(cb) {
+        sandbox.stub(fakeMozLoop.contacts, "getAll", function(cb) {
           cb(null, []);
         });
         listView = TestUtils.renderIntoDocument(
           React.createElement(loop.contacts.ContactsList, {
-            mozLoop: navigator.mozLoop,
+            mozLoop: fakeMozLoop,
             notifications: notifications,
             switchToContactAdd: sandbox.stub(),
             switchToContactEdit: sandbox.stub()
           }));
         node = listView.getDOMNode();
       });
 
       it("should not show a contacts title if no contacts", function() {
@@ -437,22 +441,22 @@ describe("loop.contacts", function() {
                                        "no_contacts_message_heading2");
         sinon.assert.calledWithExactly(mozL10nGetSpy,
                                        "no_contacts_import_or_add2");
       });
     });
 
     describe("#RenderWithContacts", function() {
       beforeEach(function() {
-        sandbox.stub(navigator.mozLoop.contacts, "getAll", function(cb) {
+        sandbox.stub(fakeMozLoop.contacts, "getAll", function(cb) {
           cb(null, [].concat(fakeFewerContacts));
         });
         listView = TestUtils.renderIntoDocument(
           React.createElement(loop.contacts.ContactsList, {
-            mozLoop: navigator.mozLoop,
+            mozLoop: fakeMozLoop,
             notifications: notifications,
             switchToContactAdd: sandbox.stub(),
             switchToContactEdit: sandbox.stub()
           }));
         node = listView.getDOMNode();
       });
 
       it("should show a contacts title", function() {
@@ -466,25 +470,25 @@ describe("loop.contacts", function() {
              .querySelector(".contact-filter-container");
 
            expect(filterView).to.eql(null);
          });
     });
 
     describe("ContactsFiltering", function() {
       beforeEach(function() {
-        navigator.mozLoop.contacts = {
+        fakeMozLoop.contacts = {
           getAll: function(callback) {
             callback(null, [].concat(fakeManyContacts));
           },
           on: sandbox.stub()
         };
         listView = TestUtils.renderIntoDocument(
           React.createElement(loop.contacts.ContactsList, {
-            mozLoop: navigator.mozLoop,
+            mozLoop: fakeMozLoop,
             notifications: notifications,
             switchToContactAdd: sandbox.stub(),
             switchToContactEdit: sandbox.stub()
           }));
         node = listView.getDOMNode();
       });
 
       it("should filter a non-existent user name", function() {
@@ -569,52 +573,22 @@ describe("loop.contacts", function() {
         React.addons.TestUtils.Simulate.change(input,
                                                { target: { value: "12345678" } });
         var contactList = listView.getDOMNode().querySelectorAll(".contact");
 
         expect(contactList.length).to.eql(1);
       });
     });
 
-    describe("#handleContactAction", function() {
-      beforeEach(function() {
-        sandbox.stub(navigator.mozLoop.contacts, "getAll", function(cb) {
-          cb(null, []);
-        });
-        listView = TestUtils.renderIntoDocument(
-          React.createElement(loop.contacts.ContactsList, {
-            mozLoop: navigator.mozLoop,
-            notifications: notifications,
-            switchToContactAdd: sandbox.stub(),
-            switchToContactEdit: sandbox.stub()
-          }));
-        node = listView.getDOMNode();
-      });
-
-      it("should call window.close when called with 'video-call' action",
-        function() {
-          listView.handleContactAction({}, "video-call");
-
-          sinon.assert.calledOnce(fakeWindow.close);
-      });
-
-      it("should call window.close when called with 'audio-call' action",
-        function() {
-          listView.handleContactAction({}, "audio-call");
-
-          sinon.assert.calledOnce(fakeWindow.close);
-        });
-    });
-
     describe("#handleContactAddEdit", function() {
 
       beforeEach(function() {
         listView = TestUtils.renderIntoDocument(
           React.createElement(loop.contacts.ContactsList, {
-            mozLoop: navigator.mozLoop,
+            mozLoop: fakeMozLoop,
             notifications: notifications,
             switchToContactAdd: sandbox.stub(),
             switchToContactEdit: sandbox.stub()
           }));
       });
 
       it("should call switchToContactAdd function when Add Contact button is clicked",
         function() {
@@ -630,69 +604,155 @@ describe("loop.contacts", function() {
           listView.handleContactAction({}, "edit");
 
           sinon.assert.calledOnce(listView.props.switchToContactEdit);
         });
     });
 
     describe("#handleImportButtonClick", function() {
       beforeEach(function() {
-        sandbox.stub(navigator.mozLoop.contacts, "getAll", function(cb) {
+        sandbox.stub(fakeMozLoop.contacts, "getAll", function(cb) {
           cb(null, []);
         });
         listView = TestUtils.renderIntoDocument(
           React.createElement(loop.contacts.ContactsList, {
-            mozLoop: navigator.mozLoop,
+            mozLoop: fakeMozLoop,
             notifications: notifications,
             switchToContactAdd: sandbox.stub(),
             switchToContactEdit: sandbox.stub()
           }));
         node = listView.getDOMNode();
       });
 
       it("should notify the end user from a successful import", function() {
         sandbox.stub(notifications, "successL10n");
-        navigator.mozLoop.startImport = function(opts, cb) {
+        fakeMozLoop.startImport = function(opts, cb) {
           cb(null, {success: 42});
         };
 
         listView.handleImportButtonClick();
 
         sinon.assert.calledWithExactly(
           notifications.successL10n,
           "import_contacts_success_message",
           // Num is for the plural selection.
           {num: 42, total: 42});
       });
 
       it("should notify the end user from any encountered error", function() {
         sandbox.stub(notifications, "errorL10n");
-        navigator.mozLoop.startImport = function(opts, cb) {
+        fakeMozLoop.startImport = function(opts, cb) {
           cb(new Error("fake error"));
         };
 
         listView.handleImportButtonClick();
 
         sinon.assert.calledWithExactly(notifications.errorL10n,
                                        "import_contacts_failure_message");
       });
     });
+    describe("Individual Contacts", function() {
+      describe("Contact Menu", function() {
+        var view, contactMenu, contact;
+
+        function mountTestComponent(options) {
+          var props = _.extend({
+            mozLoop: fakeMozLoop,
+            notifications: notifications,
+            switchToContactAdd: sandbox.stub(),
+            switchToContactEdit: sandbox.stub()
+          }, options);
+          return TestUtils.renderIntoDocument(
+            React.createElement(loop.contacts.ContactsList, props));
+        }
+
+        beforeEach(function() {
+          contact = fakeFewerContacts[0];
+
+          fakeMozLoop.contacts.getAll = function(callback) {
+            callback(null, [contact]);
+          };
+
+          view = mountTestComponent();
+          node = view.getDOMNode();
+
+          // Open the menu
+          var menuButton = node.querySelector(".icon-contact-menu-button");
+          TestUtils.Simulate.click(menuButton);
+
+          // Get the menu for use in the tests.
+          contactMenu = node.querySelector(".contact > .dropdown-menu");
+        });
+
+        describe("Video Conversation button", function() {
+          it("should call startDirectCall when the button is clicked", function() {
+            TestUtils.Simulate.click(contactMenu.querySelector(".video-call-item"));
+
+            sinon.assert.calledOnce(fakeMozLoop.calls.startDirectCall);
+            sinon.assert.calledWithExactly(fakeMozLoop.calls.startDirectCall,
+              contact,
+              CALL_TYPES.AUDIO_VIDEO);
+          });
+
+          it("should close the window when the button is clicked", function() {
+            TestUtils.Simulate.click(contactMenu.querySelector(".video-call-item"));
+
+            sinon.assert.calledOnce(fakeWindow.close);
+          });
+
+          it("should not do anything if the contact is blocked", function() {
+            contact.blocked = true;
+
+            TestUtils.Simulate.click(contactMenu.querySelector(".video-call-item"));
+
+            sinon.assert.notCalled(fakeMozLoop.calls.startDirectCall);
+            sinon.assert.notCalled(fakeWindow.close);
+          });
+        });
+
+        describe("Audio Conversation button", function() {
+          it("should call startDirectCall when the button is clicked", function() {
+            TestUtils.Simulate.click(contactMenu.querySelector(".audio-call-item"));
+
+            sinon.assert.calledOnce(fakeMozLoop.calls.startDirectCall);
+            sinon.assert.calledWithExactly(fakeMozLoop.calls.startDirectCall,
+              contact,
+              CALL_TYPES.AUDIO_ONLY);
+          });
+
+          it("should close the window when the button is clicked", function() {
+            TestUtils.Simulate.click(contactMenu.querySelector(".audio-call-item"));
+
+            sinon.assert.calledOnce(fakeWindow.close);
+          });
+
+          it("should not do anything if the contact is blocked", function() {
+            contact.blocked = true;
+
+            TestUtils.Simulate.click(contactMenu.querySelector(".audio-call-item"));
+
+            sinon.assert.notCalled(fakeMozLoop.calls.startDirectCall);
+            sinon.assert.notCalled(fakeWindow.close);
+          });
+        });
+      });
+    });
   });
 
   describe("ContactDetailsForm", function() {
     describe("#render", function() {
       describe("add mode", function() {
         var view;
 
         beforeEach(function() {
           view = TestUtils.renderIntoDocument(
             React.createElement(loop.contacts.ContactDetailsForm, {
               contactFormData: {},
               mode: "add",
-              mozLoop: navigator.mozLoop,
+              mozLoop: fakeMozLoop,
               switchToInitialView: sandbox.stub()
             }));
         });
 
         it("should render 'add' header", function() {
 
           var header = view.getDOMNode().querySelector("header");
           expect(header).to.not.equal(null);
@@ -816,17 +876,17 @@ describe("loop.contacts", function() {
       describe("edit mode", function() {
         var view;
 
         beforeEach(function() {
           view = TestUtils.renderIntoDocument(
             React.createElement(loop.contacts.ContactDetailsForm, {
               contactFormData: {},
               mode: "edit",
-              mozLoop: navigator.mozLoop,
+              mozLoop: fakeMozLoop,
               switchToInitialView: sandbox.stub()
             }));
         });
 
         it("should render 'edit' header", function() {
           var header = view.getDOMNode().querySelector("header");
           expect(header).to.not.equal(null);
           expect(header.textContent).to.eql(fakeEditContactButtonText);
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -2521,17 +2521,17 @@ ContentPermissionPrompt.prototype = {
     let types = aRequest.types.QueryInterface(Ci.nsIArray);
     if (types.length != 1) {
       aRequest.cancel();
       return;
     }
 
     if (!aOptions)
       aOptions = {};
-    aOptions.displayOrigin = requestPrincipal.URI;
+    aOptions.displayURI = requestPrincipal.URI;
 
     return chromeWin.PopupNotifications.show(browser, aNotificationId, aMessage, aAnchorId,
                                              mainAction, secondaryActions, aOptions);
   },
 
   _promptPush : function(aRequest) {
     var message = gBrowserBundle.GetStringFromName("push.enablePush2");
 
--- a/browser/config/tooltool-manifests/macosx64/cross-releng.manifest
+++ b/browser/config/tooltool-manifests/macosx64/cross-releng.manifest
@@ -5,18 +5,26 @@
 {
 "size": 70350828, 
 "digest": "6cd04e8ec44c6fef159349c22bd0476891e4a2d46479f9586283eaf3305e42f79c720d40dfec0e78d8899c1651189b12e285de60862ffd0612b0dac7a0c336c6", 
 "algorithm": "sha512", 
 "unpack": true,
 "filename": "clang.tar.bz2"
 },
 {
-"size": 2581027, 
-"digest": "9b59abef2bd4ae3a5b792de96e1336d879c1c5b6b07382797ae1bcc299e74ddf805bc95b7bc813cf3b4586db5eb4d0f41d09b2f85f0629cf27e57a4de851129c", 
+"size": 80458572,
+"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"algorithm": "sha512", 
+"filename": "gcc.tar.xz",
+"unpack": true
+},
+{
+"size": 3008804, 
+"visibility": "public", 
+"digest": "ba6937f14f3d8b26dcb2d39490dee6b0a8afb60f672f5debb71d7b62c1ec52103201b4b1a3d258f945567de531384b36ddb2ce4aa73dc63d72305b11c146847c", 
 "algorithm": "sha512", 
 "unpack": true,
 "filename": "cctools.tar.gz"
 },
 {
 "size": 35215976, 
 "visibility": "internal", 
 "digest": "8be736545ddab25ebded188458ce974d5c9a7e29f3c50d2ebfbcb878f6aff853dd2ff5a3528bdefc64396a10101a1b50fd2fe52000140df33643cebe1ea759da", 
@@ -25,10 +33,26 @@
 "filename": "MacOSX10.7.sdk.tar.bz2"
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
 "unpack": true,
 "filename": "sccache.tar.bz2"
+},
+{
+"size": 57060, 
+"visibility": "public", 
+"digest": "9649ca595f4cf088d118da26201f92cc94cda7af49c7c48112ee31cd13c83b2935b3e145de9dd78060cff2480b4c2e7ff5fb24235876956fed13c87852071998", 
+"algorithm": "sha512", 
+"unpack": true,
+"filename": "dmg.tar.xz"
+},
+{
+"size": 188880, 
+"visibility": "public", 
+"digest": "1ffddd43efb03aed897ee42035d9d8d758a8d66ab6c867599ef755e1a586768fc22011ce03698af61454920b00fe8bed08c9a681e7bd324d7f8f78c026c83943", 
+"algorithm": "sha512", 
+"unpack": true,
+"filename": "genisoimage.tar.xz"
 }
 ]
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -11,16 +11,17 @@ browser.jar:
     content/browser/devtools/readdir.js                                (projecteditor/lib/helpers/readdir.js)
     content/browser/devtools/projecteditor-loader.xul                        (projecteditor/chrome/content/projecteditor-loader.xul)
     content/browser/devtools/projecteditor-test.xul                          (projecteditor/chrome/content/projecteditor-test.xul)
     content/browser/devtools/projecteditor-loader.js                         (projecteditor/chrome/content/projecteditor-loader.js)
     content/browser/devtools/netmonitor.xul                            (netmonitor/netmonitor.xul)
     content/browser/devtools/netmonitor.css                            (netmonitor/netmonitor.css)
     content/browser/devtools/netmonitor-controller.js                  (netmonitor/netmonitor-controller.js)
     content/browser/devtools/netmonitor-view.js                        (netmonitor/netmonitor-view.js)
+    content/browser/devtools/NetworkPanel.xhtml                        (webconsole/NetworkPanel.xhtml)
     content/browser/devtools/webconsole.xul                            (webconsole/webconsole.xul)
 *   content/browser/devtools/scratchpad.xul                            (scratchpad/scratchpad.xul)
     content/browser/devtools/scratchpad.js                             (scratchpad/scratchpad.js)
     content/browser/devtools/splitview.css                             (shared/splitview.css)
     content/browser/devtools/theme-switching.js                        (shared/theme-switching.js)
     content/browser/devtools/frame-script-utils.js                     (shared/frame-script-utils.js)
     content/browser/devtools/styleeditor.xul                           (styleeditor/styleeditor.xul)
     content/browser/devtools/styleeditor.css                           (styleeditor/styleeditor.css)
--- a/browser/devtools/netmonitor/netmonitor-controller.js
+++ b/browser/devtools/netmonitor/netmonitor-controller.js
@@ -318,47 +318,16 @@ let NetMonitorController = {
       this._currentActivity = aType;
       return reconfigureTab({ cacheDisabled: true, performReload: false }).then(standBy);
     }
     this._currentActivity = ACTIVITY_TYPE.NONE;
     return promise.reject(new Error("Invalid activity type"));
   },
 
   /**
-   * Selects the specified request in the waterfall and opens the details view.
-   *
-   * @param string requestId
-   *        The actor ID of the request to inspect.
-   * @return object
-   *         A promise resolved once the task finishes.
-   */
-  inspectRequest: function(requestId) {
-    // Look for the request in the existing ones or wait for it to appear, if
-    // the network monitor is still loading.
-    let deferred = promise.defer();
-    let request = null;
-    let inspector = function() {
-      let predicate = i => i.value === requestId;
-      request = NetMonitorView.RequestsMenu.getItemForPredicate(predicate);
-      if (request) {
-        window.off(EVENTS.REQUEST_ADDED, inspector);
-        NetMonitorView.RequestsMenu.filterOn("all");
-        NetMonitorView.RequestsMenu.selectedItem = request;
-        deferred.resolve();
-      }
-    }
-
-    inspector();
-    if (!request) {
-      window.on(EVENTS.REQUEST_ADDED, inspector);
-    }
-    return deferred.promise;
-  },
-
-  /**
    * Getter that tells if the server supports sending custom network requests.
    * @type boolean
    */
   get supportsCustomRequest() {
     return this.webConsoleClient &&
            (this.webConsoleClient.traits.customNetworkRequest ||
             !this._target.isApp);
   },
--- a/browser/devtools/performance/test/browser.ini
+++ b/browser/devtools/performance/test/browser.ini
@@ -77,51 +77,52 @@ skip-if = os == 'linux' # Bug 1172120
 [browser_perf-overview-render-03.js]
 [browser_perf-overview-render-04.js]
 skip-if = os == 'linux' # bug 1186322
 [browser_perf-overview-selection-01.js]
 [browser_perf-overview-selection-02.js]
 [browser_perf-overview-selection-03.js]
 [browser_perf-overview-time-interval.js]
 [browser_perf-states.js]
+skip-if = os == 'linux' # bug 1203888
 [browser_perf-refresh.js]
 [browser_perf-ui-recording.js]
 skip-if = os == 'linux' # bug 1186322
 [browser_perf-recording-notices-01.js]
 skip-if = os == 'linux' # bug 1186322
 [browser_perf-recording-notices-02.js]
 skip-if = os == 'linux' # bug 1186322
 [browser_perf-recording-notices-03.js]
 skip-if = os == 'linux' # bug 1186322
 [browser_perf-recording-notices-04.js]
 skip-if = os == 'linux' # bug 1186322
 [browser_perf-recording-notices-05.js]
 skip-if = os == 'linux' # bug 1186322
-[browser_perf_recordings-io-01.js]
+[browser_perf-recordings-io-01.js]
 skip-if = os == 'linux' # bug 1186322
-[browser_perf_recordings-io-02.js]
+[browser_perf-recordings-io-02.js]
 skip-if = os == 'linux' # bug 1186322
-[browser_perf_recordings-io-03.js]
+[browser_perf-recordings-io-03.js]
 skip-if = os == 'linux' # bug 1186322
-[browser_perf_recordings-io-04.js]
+[browser_perf-recordings-io-04.js]
 skip-if = os == 'linux' # bug 1186322
-[browser_perf_recordings-io-05.js]
+[browser_perf-recordings-io-05.js]
 skip-if = os == 'linux' # bug 1186322
-[browser_perf_recordings-io-06.js]
+[browser_perf-recordings-io-06.js]
 skip-if = os == 'linux' # bug 1186322
 [browser_perf-range-changed-render.js]
 skip-if = os == 'linux' # bug 1186322
 [browser_perf-recording-selected-01.js]
 skip-if = os == 'linux' # bug 1186322
 [browser_perf-recording-selected-02.js]
 skip-if = os == 'linux' # bug 1186322
 [browser_perf-recording-selected-03.js]
 skip-if = os == 'linux' # bug 1186322
 [browser_perf-recording-selected-04.js]
-skip-if = os == 'linux' # bug 1186322
+skip-if = os == 'linux' || debug # bug 1186322 for Linux, bug 1203895 for leaks
 [browser_perf-theme-toggle-01.js]
 [browser_profiler_tree-abstract-01.js]
 [browser_profiler_tree-abstract-02.js]
 [browser_profiler_tree-abstract-03.js]
 [browser_profiler_tree-abstract-04.js]
 [browser_profiler_tree-view-01.js]
 [browser_profiler_tree-view-02.js]
 [browser_profiler_tree-view-03.js]
rename from browser/devtools/performance/test/browser_perf_recordings-io-01.js
rename to browser/devtools/performance/test/browser_perf-recordings-io-01.js
rename from browser/devtools/performance/test/browser_perf_recordings-io-02.js
rename to browser/devtools/performance/test/browser_perf-recordings-io-02.js
rename from browser/devtools/performance/test/browser_perf_recordings-io-03.js
rename to browser/devtools/performance/test/browser_perf-recordings-io-03.js
rename from browser/devtools/performance/test/browser_perf_recordings-io-04.js
rename to browser/devtools/performance/test/browser_perf-recordings-io-04.js
rename from browser/devtools/performance/test/browser_perf_recordings-io-05.js
rename to browser/devtools/performance/test/browser_perf-recordings-io-05.js
rename from browser/devtools/performance/test/browser_perf_recordings-io-06.js
rename to browser/devtools/performance/test/browser_perf-recordings-io-06.js
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/NetworkPanel.xhtml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" [
+<!ENTITY % webConsoleDTD SYSTEM "chrome://browser/locale/devtools/webConsole.dtd" >
+%webConsoleDTD;
+]>
+
+<!-- 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/. -->
+
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+  <link rel="stylesheet" href="chrome://browser/skin/devtools/webconsole_networkpanel.css" type="text/css"/>
+</head>
+<body role="application">
+<table id="header">
+  <tr>
+    <th class="property-name"
+        scope="row">&networkPanel.requestURLColon;</th>
+    <td class="property-value"
+        id="headUrl"></td>
+  </tr>
+  <tr>
+    <th class="property-name"
+        scope="row">&networkPanel.requestMethodColon;</th>
+    <td class="property-value"
+        id="headMethod"></td>
+  </tr>
+  <tr>
+    <th class="property-name"
+        scope="row">&networkPanel.statusCodeColon;</th>
+    <td class="property-value"
+        id="headStatus"></td>
+  </tr>
+</table>
+
+<div class="group">
+  <h1>
+    &networkPanel.requestHeaders;
+    <span id="requestHeadersInfo" class="info"></span>
+  </h1>
+  <table class="property-table" id="requestHeadersContent"></table>
+
+  <div id="requestCookie" style="display:none">
+    <h1>&networkPanel.requestCookie;</h1>
+    <table class="property-table" id="requestCookieContent"></table>
+  </div>
+
+  <div id="requestBody" style="display:none">
+    <h1>&networkPanel.requestBody;</h1>
+    <table class="property-table" id="requestBodyContent"></table>
+  </div>
+  <div id="requestFormData" style="display:none">
+    <h1>&networkPanel.requestFormData;</h1>
+    <table class="property-table" id="requestFormDataContent"></table>
+  </div>
+  <p id="requestBodyFetchLink" style="display:none"></p>
+</div>
+
+<div class="group" id="responseContainer" style="display:none">
+  <h1>
+    &networkPanel.responseHeaders;
+    <span id="responseHeadersInfo" class="info">&Delta;</span>
+  </h1>
+  <table class="property-table" id="responseHeadersContent"></table>
+
+  <div id="responseCookie" style="display:none">
+    <h1>&networkPanel.responseCookie;</h1>
+    <table class="property-table" id="responseCookieContent"></table>
+  </div>
+
+  <div id="responseBody" style="display:none">
+    <h1>
+      &networkPanel.responseBody;
+      <span class="info" id="responseBodyInfo">&Delta;</span>
+    </h1>
+    <table class="property-table" id="responseBodyContent"></table>
+  </div>
+  <div id="responseBodyCached" style="display:none">
+    <h1>
+      &networkPanel.responseBodyCached;
+      <span class="info" id="responseBodyCachedInfo">&Delta;</span>
+    </h1>
+    <table class="property-table" id="responseBodyCachedContent"></table>
+  </div>
+  <div id="responseNoBody" style="display:none">
+    <h1>
+      &networkPanel.responseNoBody;
+      <span id="responseNoBodyInfo" class="info">&Delta;</span>
+    </h1>
+  </div>
+  <div id="responseBodyUnknownType" style="display:none">
+    <h1>
+      &networkPanel.responseBodyUnknownType;
+      <span id="responseBodyUnknownTypeInfo" class="info">&Delta;</span>
+    </h1>
+    <table class="property-table" id="responseBodyUnknownTypeContent"></table>
+  </div>
+  <div id="responseImage" style="display:none">
+    <h1>
+      &networkPanel.responseImage;
+      <span id="responseImageInfo" class="info"></span>
+    </h1>
+    <div id="responseImageNodeDiv">
+      <img id="responseImageNode" />
+    </div>
+  </div>
+  <div id="responseImageCached" style="display:none">
+    <h1>
+      &networkPanel.responseImageCached;
+      <span id="responseImageCachedInfo" class="info"></span>
+    </h1>
+    <div id="responseImageNodeDiv">
+      <img id="responseImageCachedNode" />
+    </div>
+  </div>
+  <p id="responseBodyFetchLink" style="display:none"></p>
+</div>
+</body>
+</html>
--- a/browser/devtools/webconsole/moz.build
+++ b/browser/devtools/webconsole/moz.build
@@ -5,11 +5,12 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 
 EXTRA_JS_MODULES.devtools.webconsole += [
     'console-commands.js',
     'console-output.js',
     'hudservice.js',
+    'network-panel.js',
     'panel.js',
     'webconsole.js',
 ]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/network-panel.js
@@ -0,0 +1,835 @@
+/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const {Cc, Ci, Cu} = require("chrome");
+
+loader.lazyGetter(this, "NetworkHelper", () => require("devtools/toolkit/webconsole/network-helper"));
+loader.lazyImporter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm");
+loader.lazyServiceGetter(this, "mimeService", "@mozilla.org/mime;1", "nsIMIMEService");
+
+let WebConsoleUtils = require("devtools/toolkit/webconsole/utils").Utils;
+
+const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
+let l10n = new WebConsoleUtils.l10n(STRINGS_URI);
+
+
+/**
+ * Creates a new NetworkPanel.
+ *
+ * @constructor
+ * @param nsIDOMNode aParent
+ *        Parent node to append the created panel to.
+ * @param object aHttpActivity
+ *        HttpActivity to display in the panel.
+ * @param object aWebConsoleFrame
+ *        The parent WebConsoleFrame object that owns this network panel
+ *        instance.
+ */
+function NetworkPanel(aParent, aHttpActivity, aWebConsoleFrame)
+{
+  let doc = aParent.ownerDocument;
+  this.httpActivity = aHttpActivity;
+  this.webconsole = aWebConsoleFrame;
+  this._responseBodyFetch = this._responseBodyFetch.bind(this);
+  this._requestBodyFetch = this._requestBodyFetch.bind(this);
+
+  // Create the underlaying panel
+  this.panel = createElement(doc, "panel", {
+    label: l10n.getStr("NetworkPanel.label"),
+    titlebar: "normal",
+    noautofocus: "true",
+    noautohide: "true",
+    close: "true"
+  });
+
+  // Create the iframe that displays the NetworkPanel XHTML.
+  this.iframe = createAndAppendElement(this.panel, "iframe", {
+    src: "chrome://browser/content/devtools/NetworkPanel.xhtml",
+    type: "content",
+    flex: "1"
+  });
+
+  let self = this;
+
+  // Destroy the panel when it's closed.
+  this.panel.addEventListener("popuphidden", function onPopupHide() {
+    self.panel.removeEventListener("popuphidden", onPopupHide, false);
+    self.panel.parentNode.removeChild(self.panel);
+    self.panel = null;
+    self.iframe = null;
+    self.httpActivity = null;
+    self.webconsole = null;
+
+    if (self.linkNode) {
+      self.linkNode._panelOpen = false;
+      self.linkNode = null;
+    }
+  }, false);
+
+  // Set the document object and update the content once the panel is loaded.
+  this.iframe.addEventListener("load", function onLoad() {
+    if (!self.iframe) {
+      return;
+    }
+
+    self.iframe.removeEventListener("load", onLoad, true);
+    self.update();
+  }, true);
+
+  this.panel.addEventListener("popupshown", function onPopupShown() {
+    self.panel.removeEventListener("popupshown", onPopupShown, true);
+    self.update();
+  }, true);
+
+  // Create the footer.
+  let footer = createElement(doc, "hbox", { align: "end" });
+  createAndAppendElement(footer, "spacer", { flex: 1 });
+
+  createAndAppendElement(footer, "resizer", { dir: "bottomend" });
+  this.panel.appendChild(footer);
+
+  aParent.appendChild(this.panel);
+}
+exports.NetworkPanel = NetworkPanel;
+
+NetworkPanel.prototype =
+{
+  /**
+   * The current state of the output.
+   */
+  _state: 0,
+
+  /**
+   * State variables.
+   */
+  _INIT: 0,
+  _DISPLAYED_REQUEST_HEADER: 1,
+  _DISPLAYED_REQUEST_BODY: 2,
+  _DISPLAYED_RESPONSE_HEADER: 3,
+  _TRANSITION_CLOSED: 4,
+
+  _fromDataRegExp: /Content-Type\:\s*application\/x-www-form-urlencoded/,
+
+  _contentType: null,
+
+  /**
+   * Function callback invoked whenever the panel content is updated. This is
+   * used only by tests.
+   *
+   * @private
+   * @type function
+   */
+  _onUpdate: null,
+
+  get document() {
+    return this.iframe && this.iframe.contentWindow ?
+           this.iframe.contentWindow.document : null;
+  },
+
+  /**
+   * Small helper function that is nearly equal to l10n.getFormatStr
+   * except that it prefixes aName with "NetworkPanel.".
+   *
+   * @param string aName
+   *        The name of an i10n string to format. This string is prefixed with
+   *        "NetworkPanel." before calling the HUDService.getFormatStr function.
+   * @param array aArray
+   *        Values used as placeholder for the i10n string.
+   * @returns string
+   *          The i10n formated string.
+   */
+  _format: function NP_format(aName, aArray)
+  {
+    return l10n.getFormatStr("NetworkPanel." + aName, aArray);
+  },
+
+  /**
+   * Returns the content type of the response body. This is based on the
+   * response.content.mimeType property. If this value is not available, then
+   * the content type is guessed by the file extension of the request URL.
+   *
+   * @return string
+   *         Content type or empty string if no content type could be figured
+   *         out.
+   */
+  get contentType()
+  {
+    if (this._contentType) {
+      return this._contentType;
+    }
+
+    let request = this.httpActivity.request;
+    let response = this.httpActivity.response;
+
+    let contentType = "";
+    let types = response.content ?
+                (response.content.mimeType || "").split(/,|;/) : [];
+    for (let i = 0; i < types.length; i++) {
+      if (types[i] in NetworkHelper.mimeCategoryMap) {
+        contentType = types[i];
+        break;
+      }
+    }
+
+    if (contentType) {
+      this._contentType = contentType;
+      return contentType;
+    }
+
+    // Try to get the content type from the request file extension.
+    let uri = NetUtil.newURI(request.url);
+    if ((uri instanceof Ci.nsIURL) && uri.fileExtension) {
+      try {
+         contentType = mimeService.getTypeFromExtension(uri.fileExtension);
+      }
+      catch(ex) {
+        // Added to prevent failures on OS X 64. No Flash?
+        Cu.reportError(ex);
+      }
+    }
+
+    this._contentType = contentType;
+    return contentType;
+  },
+
+  /**
+   *
+   * @returns boolean
+   *          True if the response is an image, false otherwise.
+   */
+  get _responseIsImage()
+  {
+    return this.contentType &&
+           NetworkHelper.mimeCategoryMap[this.contentType] == "image";
+  },
+
+  /**
+   *
+   * @returns boolean
+   *          True if the response body contains text, false otherwise.
+   */
+  get _isResponseBodyTextData()
+  {
+    return this.contentType ?
+           NetworkHelper.isTextMimeType(this.contentType) : false;
+  },
+
+  /**
+   * Tells if the server response is cached.
+   *
+   * @returns boolean
+   *          Returns true if the server responded that the request is already
+   *          in the browser's cache, false otherwise.
+   */
+  get _isResponseCached()
+  {
+    return this.httpActivity.response.status == 304;
+  },
+
+  /**
+   * Tells if the request body includes form data.
+   *
+   * @returns boolean
+   *          Returns true if the posted body contains form data.
+   */
+  get _isRequestBodyFormData()
+  {
+    let requestBody = this.httpActivity.request.postData.text;
+    if (typeof requestBody == "object" && requestBody.type == "longString") {
+      requestBody = requestBody.initial;
+    }
+    return this._fromDataRegExp.test(requestBody);
+  },
+
+  /**
+   * Appends the node with id=aId by the text aValue.
+   *
+   * @private
+   * @param string aId
+   * @param string aValue
+   * @return nsIDOMElement
+   *         The DOM element with id=aId.
+   */
+  _appendTextNode: function NP__appendTextNode(aId, aValue)
+  {
+    let textNode = this.document.createTextNode(aValue);
+    let elem = this.document.getElementById(aId);
+    elem.appendChild(textNode);
+    return elem;
+  },
+
+  /**
+   * Generates some HTML to display the key-value pair of the aList data. The
+   * generated HTML is added to node with id=aParentId.
+   *
+   * @param string aParentId
+   *        Id of the parent node to append the list to.
+   * @oaram array aList
+   *        Array that holds the objects you want to display. Each object must
+   *        have two properties: name and value.
+   * @param boolean aIgnoreCookie
+   *        If true, the key-value named "Cookie" is not added to the list.
+   * @returns void
+   */
+  _appendList: function NP_appendList(aParentId, aList, aIgnoreCookie)
+  {
+    let parent = this.document.getElementById(aParentId);
+    let doc = this.document;
+
+    aList.sort(function(a, b) {
+      return a.name.toLowerCase() < b.name.toLowerCase();
+    });
+
+    aList.forEach((aItem) => {
+      let name = aItem.name;
+      if (aIgnoreCookie && (name == "Cookie" || name == "Set-Cookie")) {
+        return;
+      }
+
+      let value = aItem.value;
+      let longString = null;
+      if (typeof value == "object" && value.type == "longString") {
+        value = value.initial;
+        longString = true;
+      }
+
+      /**
+       * The following code creates the HTML:
+       * <tr>
+       * <th scope="row" class="property-name">${line}:</th>
+       * <td class="property-value">${aList[line]}</td>
+       * </tr>
+       * and adds it to parent.
+       */
+      let row = doc.createElement("tr");
+      let textNode = doc.createTextNode(name + ":");
+      let th = doc.createElement("th");
+      th.setAttribute("scope", "row");
+      th.setAttribute("class", "property-name");
+      th.appendChild(textNode);
+      row.appendChild(th);
+
+      textNode = doc.createTextNode(value);
+      let td = doc.createElement("td");
+      td.setAttribute("class", "property-value");
+      td.appendChild(textNode);
+
+      if (longString) {
+        let a = doc.createElement("a");
+        a.href = "#";
+        a.className = "longStringEllipsis";
+        a.addEventListener("mousedown", this._longStringClick.bind(this, aItem));
+        a.textContent = l10n.getStr("longStringEllipsis");
+        td.appendChild(a);
+      }
+
+      row.appendChild(td);
+
+      parent.appendChild(row);
+    });
+  },
+
+  /**
+   * The click event handler for the ellipsis which allows the user to retrieve
+   * the full header value.
+   *
+   * @private
+   * @param object aHeader
+   *        The header object with the |name| and |value| properties.
+   * @param nsIDOMEvent aEvent
+   *        The DOM click event object.
+   */
+  _longStringClick: function NP__longStringClick(aHeader, aEvent)
+  {
+    aEvent.preventDefault();
+
+    let longString = this.webconsole.webConsoleClient.longString(aHeader.value);
+
+    longString.substring(longString.initial.length, longString.length,
+      function NP__onLongStringSubstring(aResponse)
+      {
+        if (aResponse.error) {
+          Cu.reportError("NP__onLongStringSubstring error: " + aResponse.error);
+          return;
+        }
+
+        aHeader.value = aHeader.value.initial + aResponse.substring;
+
+        let textNode = aEvent.target.previousSibling;
+        textNode.textContent += aResponse.substring;
+        textNode.parentNode.removeChild(aEvent.target);
+      });
+  },
+
+  /**
+   * Displays the node with id=aId.
+   *
+   * @private
+   * @param string aId
+   * @return nsIDOMElement
+   *         The element with id=aId.
+   */
+  _displayNode: function NP__displayNode(aId)
+  {
+    let elem = this.document.getElementById(aId);
+    elem.style.display = "block";
+  },
+
+  /**
+   * Sets the request URL, request method, the timing information when the
+   * request started and the request header content on the NetworkPanel.
+   * If the request header contains cookie data, a list of sent cookies is
+   * generated and a special sent cookie section is displayed + the cookie list
+   * added to it.
+   *
+   * @returns void
+   */
+  _displayRequestHeader: function NP__displayRequestHeader()
+  {
+    let request = this.httpActivity.request;
+    let requestTime = new Date(this.httpActivity.startedDateTime);
+
+    this._appendTextNode("headUrl", request.url);
+    this._appendTextNode("headMethod", request.method);
+    this._appendTextNode("requestHeadersInfo",
+                         l10n.timestampString(requestTime));
+
+    this._appendList("requestHeadersContent", request.headers, true);
+
+    if (request.cookies.length > 0) {
+      this._displayNode("requestCookie");
+      this._appendList("requestCookieContent", request.cookies);
+    }
+  },
+
+  /**
+   * Displays the request body section of the NetworkPanel and set the request
+   * body content on the NetworkPanel.
+   *
+   * @returns void
+   */
+  _displayRequestBody: function NP__displayRequestBody()
+  {
+    let postData = this.httpActivity.request.postData;
+    this._displayNode("requestBody");
+    this._appendTextNode("requestBodyContent", postData.text);
+  },
+
+  /*
+   * Displays the `sent form data` section. Parses the request header for the
+   * submitted form data displays it inside of the `sent form data` section.
+   *
+   * @returns void
+   */
+  _displayRequestForm: function NP__processRequestForm()
+  {
+    let postData = this.httpActivity.request.postData.text;
+    let requestBodyLines = postData.split("\n");
+    let formData = requestBodyLines[requestBodyLines.length - 1].
+                      replace(/\+/g, " ").split("&");
+
+    function unescapeText(aText)
+    {
+      try {
+        return decodeURIComponent(aText);
+      }
+      catch (ex) {
+        return decodeURIComponent(unescape(aText));
+      }
+    }
+
+    let formDataArray = [];
+    for (let i = 0; i < formData.length; i++) {
+      let data = formData[i];
+      let idx = data.indexOf("=");
+      let key = data.substring(0, idx);
+      let value = data.substring(idx + 1);
+      formDataArray.push({
+        name: unescapeText(key),
+        value: unescapeText(value)
+      });
+    }
+
+    this._appendList("requestFormDataContent", formDataArray);
+    this._displayNode("requestFormData");
+  },
+
+  /**
+   * Displays the response section of the NetworkPanel, sets the response status,
+   * the duration between the start of the request and the receiving of the
+   * response header as well as the response header content on the the NetworkPanel.
+   *
+   * @returns void
+   */
+  _displayResponseHeader: function NP__displayResponseHeader()
+  {
+    let timing = this.httpActivity.timings;
+    let response = this.httpActivity.response;
+
+    this._appendTextNode("headStatus",
+                         [response.httpVersion, response.status,
+                          response.statusText].join(" "));
+
+    // Calculate how much time it took from the request start, until the
+    // response started to be received.
+    let deltaDuration = 0;
+    ["dns", "connect", "send", "wait"].forEach(function (aValue) {
+      let ms = timing[aValue];
+      if (ms > -1) {
+        deltaDuration += ms;
+      }
+    });
+
+    this._appendTextNode("responseHeadersInfo",
+      this._format("durationMS", [deltaDuration]));
+
+    this._displayNode("responseContainer");
+    this._appendList("responseHeadersContent", response.headers, true);
+
+    if (response.cookies.length > 0) {
+      this._displayNode("responseCookie");
+      this._appendList("responseCookieContent", response.cookies);
+    }
+  },
+
+  /**
+   * Displays the respones image section, sets the source of the image displayed
+   * in the image response section to the request URL and the duration between
+   * the receiving of the response header and the end of the request. Once the
+   * image is loaded, the size of the requested image is set.
+   *
+   * @returns void
+   */
+  _displayResponseImage: function NP__displayResponseImage()
+  {
+    let self = this;
+    let timing = this.httpActivity.timings;
+    let request = this.httpActivity.request;
+    let response = this.httpActivity.response;
+    let cached = "";
+
+    if (this._isResponseCached) {
+      cached = "Cached";
+    }
+
+    let imageNode = this.document.getElementById("responseImage" +
+                                                 cached + "Node");
+
+    let text = response.content.text;
+    if (typeof text == "object" && text.type == "longString") {
+      this._showResponseBodyFetchLink();
+    }
+    else {
+      imageNode.setAttribute("src",
+        "data:" + this.contentType + ";base64," + text);
+    }
+
+    // This function is called to set the imageInfo.
+    function setImageInfo() {
+      self._appendTextNode("responseImage" + cached + "Info",
+        self._format("imageSizeDeltaDurationMS",
+          [ imageNode.width, imageNode.height, timing.receive ]
+        )
+      );
+    }
+
+    // Check if the image is already loaded.
+    if (imageNode.width != 0) {
+      setImageInfo();
+    }
+    else {
+      // Image is not loaded yet therefore add a load event.
+      imageNode.addEventListener("load", function imageNodeLoad() {
+        imageNode.removeEventListener("load", imageNodeLoad, false);
+        setImageInfo();
+      }, false);
+    }
+
+    this._displayNode("responseImage" + cached);
+  },
+
+  /**
+   * Displays the response body section, sets the the duration between
+   * the receiving of the response header and the end of the request as well as
+   * the content of the response body on the NetworkPanel.
+   *
+   * @returns void
+   */
+  _displayResponseBody: function NP__displayResponseBody()
+  {
+    let timing = this.httpActivity.timings;
+    let response = this.httpActivity.response;
+    let cached =  this._isResponseCached ? "Cached" : "";
+
+    this._appendTextNode("responseBody" + cached + "Info",
+      this._format("durationMS", [timing.receive]));
+
+    this._displayNode("responseBody" + cached);
+
+    let text = response.content.text;
+    if (typeof text == "object") {
+      text = text.initial;
+      this._showResponseBodyFetchLink();
+    }
+
+    this._appendTextNode("responseBody" + cached + "Content", text);
+  },
+
+  /**
+   * Show the "fetch response body" link.
+   * @private
+   */
+  _showResponseBodyFetchLink: function NP__showResponseBodyFetchLink()
+  {
+    let content = this.httpActivity.response.content;
+
+    let elem = this._appendTextNode("responseBodyFetchLink",
+      this._format("fetchRemainingResponseContentLink",
+                   [content.text.length - content.text.initial.length]));
+
+    elem.style.display = "block";
+    elem.addEventListener("mousedown", this._responseBodyFetch);
+  },
+
+  /**
+   * Click event handler for the link that allows users to fetch the remaining
+   * response body.
+   *
+   * @private
+   * @param nsIDOMEvent aEvent
+   */
+  _responseBodyFetch: function NP__responseBodyFetch(aEvent)
+  {
+    aEvent.target.style.display = "none";
+    aEvent.target.removeEventListener("mousedown", this._responseBodyFetch);
+
+    let content = this.httpActivity.response.content;
+    let longString = this.webconsole.webConsoleClient.longString(content.text);
+    longString.substring(longString.initial.length, longString.length,
+      (aResponse) =>
+      {
+        if (aResponse.error) {
+          Cu.reportError("NP__onLongStringSubstring error: " + aResponse.error);
+          return;
+        }
+
+        content.text = content.text.initial + aResponse.substring;
+        let cached =  this._isResponseCached ? "Cached" : "";
+
+        if (this._responseIsImage) {
+          let imageNode = this.document.getElementById("responseImage" +
+                                                       cached + "Node");
+          imageNode.src =
+            "data:" + this.contentType + ";base64," + content.text;
+        }
+        else {
+          this._appendTextNode("responseBody" + cached + "Content",
+                               aResponse.substring);
+        }
+      });
+  },
+
+  /**
+   * Displays the `Unknown Content-Type hint` and sets the duration between the
+   * receiving of the response header on the NetworkPanel.
+   *
+   * @returns void
+   */
+  _displayResponseBodyUnknownType: function NP__displayResponseBodyUnknownType()
+  {
+    let timing = this.httpActivity.timings;
+
+    this._displayNode("responseBodyUnknownType");
+    this._appendTextNode("responseBodyUnknownTypeInfo",
+      this._format("durationMS", [timing.receive]));
+
+    this._appendTextNode("responseBodyUnknownTypeContent",
+      this._format("responseBodyUnableToDisplay.content", [this.contentType]));
+  },
+
+  /**
+   * Displays the `no response body` section and sets the the duration between
+   * the receiving of the response header and the end of the request.
+   *
+   * @returns void
+   */
+  _displayNoResponseBody: function NP_displayNoResponseBody()
+  {
+    let timing = this.httpActivity.timings;
+
+    this._displayNode("responseNoBody");
+    this._appendTextNode("responseNoBodyInfo",
+      this._format("durationMS", [timing.receive]));
+  },
+
+  /**
+   * Updates the content of the NetworkPanel's iframe.
+   *
+   * @returns void
+   */
+  update: function NP_update()
+  {
+    if (!this.document || this.document.readyState != "complete") {
+      return;
+    }
+
+    let updates = this.httpActivity.updates;
+    let timing = this.httpActivity.timings;
+    let request = this.httpActivity.request;
+    let response = this.httpActivity.response;
+
+    switch (this._state) {
+      case this._INIT:
+        this._displayRequestHeader();
+        this._state = this._DISPLAYED_REQUEST_HEADER;
+        // FALL THROUGH
+
+      case this._DISPLAYED_REQUEST_HEADER:
+        // Process the request body if there is one.
+        if (!this.httpActivity.discardRequestBody && request.postData.text) {
+          this._updateRequestBody();
+          this._state = this._DISPLAYED_REQUEST_BODY;
+        }
+        // FALL THROUGH
+
+      case this._DISPLAYED_REQUEST_BODY:
+        if (!response.headers.length || !Object.keys(timing).length) {
+          break;
+        }
+        this._displayResponseHeader();
+        this._state = this._DISPLAYED_RESPONSE_HEADER;
+        // FALL THROUGH
+
+      case this._DISPLAYED_RESPONSE_HEADER:
+        if (updates.indexOf("responseContent") == -1 ||
+            updates.indexOf("eventTimings") == -1) {
+          break;
+        }
+
+        this._state = this._TRANSITION_CLOSED;
+        if (this.httpActivity.discardResponseBody) {
+          break;
+        }
+
+        if (!response.content || !response.content.text) {
+          this._displayNoResponseBody();
+        }
+        else if (this._responseIsImage) {
+          this._displayResponseImage();
+        }
+        else if (!this._isResponseBodyTextData) {
+          this._displayResponseBodyUnknownType();
+        }
+        else if (response.content.text) {
+          this._displayResponseBody();
+        }
+        break;
+    }
+
+    if (this._onUpdate) {
+      this._onUpdate();
+    }
+  },
+
+  /**
+   * Update the panel to hold the current information we have about the request
+   * body.
+   * @private
+   */
+  _updateRequestBody: function NP__updateRequestBody()
+  {
+    let postData = this.httpActivity.request.postData;
+    if (typeof postData.text == "object" && postData.text.type == "longString") {
+      let elem = this._appendTextNode("requestBodyFetchLink",
+        this._format("fetchRemainingRequestContentLink",
+                     [postData.text.length - postData.text.initial.length]));
+
+      elem.style.display = "block";
+      elem.addEventListener("mousedown", this._requestBodyFetch);
+      return;
+    }
+
+    // Check if we send some form data. If so, display the form data special.
+    if (this._isRequestBodyFormData) {
+      this._displayRequestForm();
+    }
+    else {
+      this._displayRequestBody();
+    }
+  },
+
+  /**
+   * Click event handler for the link that allows users to fetch the remaining
+   * request body.
+   *
+   * @private
+   * @param nsIDOMEvent aEvent
+   */
+  _requestBodyFetch: function NP__requestBodyFetch(aEvent)
+  {
+    aEvent.target.style.display = "none";
+    aEvent.target.removeEventListener("mousedown", this._responseBodyFetch);
+
+    let postData = this.httpActivity.request.postData;
+    let longString = this.webconsole.webConsoleClient.longString(postData.text);
+    longString.substring(longString.initial.length, longString.length,
+       (aResponse) =>
+      {
+        if (aResponse.error) {
+          Cu.reportError("NP__onLongStringSubstring error: " + aResponse.error);
+          return;
+        }
+
+        postData.text = postData.text.initial + aResponse.substring;
+        this._updateRequestBody();
+      });
+  },
+};
+
+/**
+ * Creates a DOMNode and sets all the attributes of aAttributes on the created
+ * element.
+ *
+ * @param nsIDOMDocument aDocument
+ *        Document to create the new DOMNode.
+ * @param string aTag
+ *        Name of the tag for the DOMNode.
+ * @param object aAttributes
+ *        Attributes set on the created DOMNode.
+ *
+ * @returns nsIDOMNode
+ */
+function createElement(aDocument, aTag, aAttributes)
+{
+  let node = aDocument.createElement(aTag);
+  if (aAttributes) {
+    for (let attr in aAttributes) {
+      node.setAttribute(attr, aAttributes[attr]);
+    }
+  }
+  return node;
+}
+
+/**
+ * Creates a new DOMNode and appends it to aParent.
+ *
+ * @param nsIDOMNode aParent
+ *        A parent node to append the created element.
+ * @param string aTag
+ *        Name of the tag for the DOMNode.
+ * @param object aAttributes
+ *        Attributes set on the created DOMNode.
+ *
+ * @returns nsIDOMNode
+ */
+function createAndAppendElement(aParent, aTag, aAttributes)
+{
+  let node = createElement(aParent.ownerDocument, aTag, aAttributes);
+  aParent.appendChild(node);
+  return node;
+}
--- a/browser/devtools/webconsole/test/browser.ini
+++ b/browser/devtools/webconsole/test/browser.ini
@@ -184,16 +184,18 @@ skip-if = buildapp == 'mulet'
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_console_variables_view_while_debugging_and_inspecting.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_eval_in_debugger_stackframe.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_eval_in_debugger_stackframe2.js]
 [browser_jsterm_inspect.js]
 [browser_longstring_hang.js]
+[browser_netpanel_longstring_expand.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_output_breaks_after_console_dir_uninspectable.js]
 [browser_output_longstring_expand.js]
 [browser_repeated_messages_accuracy.js]
 skip-if = buildapp == 'mulet'
 [browser_result_format_as_string.js]
 [browser_warn_user_about_replaced_api.js]
 [browser_webconsole_abbreviate_source_url.js]
 [browser_webconsole_allow_mixedcontent_securityerrors.js]
@@ -220,16 +222,17 @@ skip-if = e10s # Bug 1042253 - webconsol
 [browser_webconsole_bug_588342_document_focus.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_bug_588730_text_node_insertion.js]
 [browser_webconsole_bug_588967_input_expansion.js]
 [browser_webconsole_bug_589162_css_filter.js]
 [browser_webconsole_bug_592442_closing_brackets.js]
 [browser_webconsole_bug_593003_iframe_wrong_hud.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
+[browser_webconsole_bug_594477_clickable_output.js]
 [browser_webconsole_bug_594497_history_arrow_keys.js]
 [browser_webconsole_bug_595223_file_uri.js]
 [browser_webconsole_bug_595350_multiple_windows_and_tabs.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_bug_595934_message_categories.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
@@ -237,24 +240,27 @@ skip-if = e10s # Bug 1042253 - webconsol
 [browser_webconsole_bug_597136_network_requests_from_chrome.js]
 [browser_webconsole_bug_597460_filter_scroll.js]
 [browser_webconsole_bug_597756_reopen_closed_tab.js]
 [browser_webconsole_bug_599725_response_headers.js]
 [browser_webconsole_bug_600183_charset.js]
 [browser_webconsole_bug_601177_log_levels.js]
 [browser_webconsole_bug_601352_scroll.js]
 [browser_webconsole_bug_601667_filter_buttons.js]
+[browser_webconsole_bug_602572_log_bodies_checkbox.js]
+skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_bug_603750_websocket.js]
 [browser_webconsole_bug_611795.js]
 [browser_webconsole_bug_613013_console_api_iframe.js]
 [browser_webconsole_bug_613280_jsterm_copy.js]
 [browser_webconsole_bug_613642_maintain_scroll.js]
 [browser_webconsole_bug_613642_prune_scroll.js]
 [browser_webconsole_bug_614793_jsterm_scroll.js]
 [browser_webconsole_bug_618078_network_exceptions.js]
+[browser_webconsole_bug_618311_close_panels.js]
 [browser_webconsole_bug_621644_jsterm_dollar.js]
 [browser_webconsole_bug_622303_persistent_filters.js]
 [browser_webconsole_bug_623749_ctrl_a_select_all_winnt.js]
 skip-if = os != "win"
 [browser_webconsole_bug_630733_response_redirect_headers.js]
 [browser_webconsole_bug_632275_getters_document_width.js]
 [browser_webconsole_bug_632347_iterators_generators.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
@@ -323,16 +329,17 @@ skip-if = buildapp == 'mulet' || e10s # 
 [browser_webconsole_inspect-parsed-documents.js]
 [browser_webconsole_js_input_expansion.js]
 [browser_webconsole_jsterm.js]
 skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout)
 [browser_webconsole_live_filtering_of_message_types.js]
 [browser_webconsole_live_filtering_on_search_strings.js]
 [browser_webconsole_message_node_id.js]
 [browser_webconsole_netlogging.js]
+[browser_webconsole_network_panel.js]
 [browser_webconsole_notifications.js]
 [browser_webconsole_open-links-without-callback.js]
 [browser_webconsole_promise.js]
 [browser_webconsole_output_copy_newlines.js]
 [browser_webconsole_output_order.js]
 [browser_webconsole_property_provider.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_scratchpad_panel_link.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_netpanel_longstring_expand.js
@@ -0,0 +1,312 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that the network panel works with LongStringActors.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/" +
+                 "test/test-console.html";
+const TEST_IMG = "http://example.com/browser/browser/devtools/webconsole/" +
+                 "test/test-image.png";
+
+const TEST_IMG_BASE64 =
+  "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAVRJ" +
+  "REFUOI2lk7FLw0AUxr+YpC1CBqcMWfsvCCLdXFzqEJCgDl1EQRGxg9AhSBEJONhFhG52UCuF" +
+  "Djq5dxD8FwoO0qGDOBQkl7vLOeWa2EQDffDBvTu+373Hu1OEEJgntGgxGD6J+7fLXKbt5VNU" +
+  "yhsKAChRBQcPFVFeWskFGH694mZroCQqCLlAwPxcgJBP254CmAD5B7C7dgHLMLF3uzoL4DQE" +
+  "od+Z5sP1FizDxGgyBqfhLID9AahX29J89bwPFgMsSEAQglAf9WobhPpScbPXr4FQHyzIADTs" +
+  "DizDRMPuIOC+zEeTMZo9BwH3EfAMACccbtfGaDKGZZg423yUZrdrg3EqxQlPr0BTdTR7joRE" +
+  "N2uqnlBmCwW1hIJagtev4f3zA16/JvfiigMSYyzqJXlw/XKUyOORMUaBor6YavgdjKa8xGOn" +
+  "idadmwtwsnMu18q83/kHSou+bFNDDr4AAAAASUVORK5CYII=";
+
+let testDriver;
+
+function test() {
+  loadTab(TEST_URI).then(() => {
+    openConsole().then(testNetworkPanel);
+  });
+}
+
+function testNetworkPanel() {
+  testDriver = testGen();
+  testDriver.next();
+}
+
+function checkIsVisible(aPanel, aList) {
+  for (let id in aList) {
+    let node = aPanel.document.getElementById(id);
+    let isVisible = aList[id];
+    is(node.style.display, (isVisible ? "block" : "none"),
+       id + " isVisible=" + isVisible);
+  }
+}
+
+function checkNodeContent(aPanel, aId, aContent) {
+  let node = aPanel.document.getElementById(aId);
+  if (node == null) {
+    ok(false, "Tried to access node " + aId + " that doesn't exist!");
+  } else if (node.textContent.indexOf(aContent) != -1) {
+    ok(true, "checking content of " + aId);
+  } else {
+    ok(false, "Got false value for " + aId + ": " + node.textContent +
+       " doesn't have " + aContent);
+  }
+}
+
+function checkNodeKeyValue(aPanel, aId, aKey, aValue) {
+  let node = aPanel.document.getElementById(aId);
+
+  let headers = node.querySelectorAll("th");
+  for (let i = 0; i < headers.length; i++) {
+    if (headers[i].textContent == (aKey + ":")) {
+      is(headers[i].nextElementSibling.textContent, aValue,
+         "checking content of " + aId + " for key " + aKey);
+      return;
+    }
+  }
+
+  ok(false, "content check failed for " + aId + ", key " + aKey);
+}
+
+function* testGen() {
+  let hud = HUDService.getHudByWindow(content);
+  let filterBox = hud.ui.filterBox;
+
+  let headerValue = (new Array(456)).join("fooz bar");
+  let headerValueGrip = {
+    type: "longString",
+    initial: headerValue.substr(0, 123),
+    length: headerValue.length,
+    actor: "faktor",
+    _fullString: headerValue,
+  };
+
+  let imageContentGrip = {
+    type: "longString",
+    initial: TEST_IMG_BASE64.substr(0, 143),
+    length: TEST_IMG_BASE64.length,
+    actor: "faktor2",
+    _fullString: TEST_IMG_BASE64,
+  };
+
+  let postDataValue = (new Array(123)).join("post me");
+  let postDataGrip = {
+    type: "longString",
+    initial: postDataValue.substr(0, 172),
+    length: postDataValue.length,
+    actor: "faktor3",
+    _fullString: postDataValue,
+  };
+
+  let httpActivity = {
+    updates: ["responseContent", "eventTimings"],
+    discardRequestBody: false,
+    discardResponseBody: false,
+    startedDateTime: (new Date()).toISOString(),
+    request: {
+      url: TEST_IMG,
+      method: "GET",
+      cookies: [],
+      headers: [
+        { name: "foo", value: "bar" },
+        { name: "loongstring", value: headerValueGrip },
+      ],
+      postData: { text: postDataGrip },
+    },
+    response: {
+      httpVersion: "HTTP/3.14",
+      status: 2012,
+      statusText: "ddahl likes tacos :)",
+      headers: [
+        { name: "Content-Type", value: "image/png" },
+      ],
+      content: { mimeType: "image/png", text: imageContentGrip },
+      cookies: [],
+    },
+    timings: { wait: 15, receive: 23 },
+  };
+
+  let networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+
+  is(filterBox._netPanel, networkPanel,
+     "Network panel stored on the anchor object");
+
+  networkPanel._onUpdate = function() {
+    networkPanel._onUpdate = null;
+    executeSoon(function() {
+      testDriver.next();
+    });
+  };
+
+  yield undefined;
+
+  info("test 1: check if a header value is expandable");
+
+  checkIsVisible(networkPanel, {
+    requestCookie: false,
+    requestFormData: false,
+    requestBody: false,
+    requestBodyFetchLink: true,
+    responseContainer: true,
+    responseBody: false,
+    responseNoBody: false,
+    responseImage: true,
+    responseImageCached: false,
+    responseBodyFetchLink: true,
+  });
+
+  checkNodeKeyValue(networkPanel, "requestHeadersContent", "foo", "bar");
+  checkNodeKeyValue(networkPanel, "requestHeadersContent", "loongstring",
+                    headerValueGrip.initial + "[\u2026]");
+
+  let webConsoleClient = networkPanel.webconsole.webConsoleClient;
+  let longStringFn = webConsoleClient.longString;
+
+  let expectedGrip = headerValueGrip;
+
+  function longStringClientProvider(aLongString) {
+    is(aLongString, expectedGrip,
+       "longString grip is correct");
+
+    return {
+      initial: expectedGrip.initial,
+      length: expectedGrip.length,
+      substring: function(aStart, aEnd, aCallback) {
+        is(aStart, expectedGrip.initial.length,
+           "substring start is correct");
+        is(aEnd, expectedGrip.length,
+           "substring end is correct");
+
+        executeSoon(function() {
+          aCallback({
+            substring: expectedGrip._fullString.substring(aStart, aEnd),
+          });
+
+          executeSoon(function() {
+            testDriver.next();
+          });
+        });
+      },
+    };
+  }
+
+  webConsoleClient.longString = longStringClientProvider;
+
+  let clickable = networkPanel.document
+                  .querySelector("#requestHeadersContent .longStringEllipsis");
+  ok(clickable, "long string ellipsis is shown");
+
+  EventUtils.sendMouseEvent({ type: "mousedown"}, clickable,
+                             networkPanel.document.defaultView);
+
+  yield undefined;
+
+  clickable = networkPanel.document
+              .querySelector("#requestHeadersContent .longStringEllipsis");
+  ok(!clickable, "long string ellipsis is not shown");
+
+  checkNodeKeyValue(networkPanel, "requestHeadersContent", "loongstring",
+                    expectedGrip._fullString);
+
+  info("test 2: check that response body image fetching works");
+  expectedGrip = imageContentGrip;
+
+  let imgNode = networkPanel.document.getElementById("responseImageNode");
+  ok(!imgNode.getAttribute("src"), "no image is displayed");
+
+  clickable = networkPanel.document.querySelector("#responseBodyFetchLink");
+  EventUtils.sendMouseEvent({ type: "mousedown"}, clickable,
+                             networkPanel.document.defaultView);
+
+  yield undefined;
+
+  imgNode = networkPanel.document.getElementById("responseImageNode");
+  is(imgNode.getAttribute("src"), "data:image/png;base64," + TEST_IMG_BASE64,
+     "displayed image is correct");
+  is(clickable.style.display, "none", "#responseBodyFetchLink is not visible");
+
+  info("test 3: expand the request body");
+
+  expectedGrip = postDataGrip;
+
+  clickable = networkPanel.document.querySelector("#requestBodyFetchLink");
+  EventUtils.sendMouseEvent({ type: "mousedown"}, clickable,
+                             networkPanel.document.defaultView);
+  yield undefined;
+
+  is(clickable.style.display, "none", "#requestBodyFetchLink is not visible");
+
+  checkIsVisible(networkPanel, {
+    requestBody: true,
+    requestBodyFetchLink: false,
+  });
+
+  checkNodeContent(networkPanel, "requestBodyContent",
+                   expectedGrip._fullString);
+
+  webConsoleClient.longString = longStringFn;
+
+  networkPanel.panel.hidePopup();
+
+  info("test 4: reponse body long text");
+
+  httpActivity.response.content.mimeType = "text/plain";
+  httpActivity.response.headers[0].value = "text/plain";
+
+  expectedGrip = imageContentGrip;
+
+  // Reset response.content.text to avoid caching of the full string.
+  httpActivity.response.content.text = expectedGrip;
+
+  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+  is(filterBox._netPanel, networkPanel,
+     "Network panel stored on httpActivity object");
+
+  networkPanel._onUpdate = function() {
+    networkPanel._onUpdate = null;
+    executeSoon(function() {
+      testDriver.next();
+    });
+  };
+
+  yield undefined;
+
+  checkIsVisible(networkPanel, {
+    requestCookie: false,
+    requestFormData: false,
+    requestBody: true,
+    requestBodyFetchLink: false,
+    responseContainer: true,
+    responseBody: true,
+    responseNoBody: false,
+    responseImage: false,
+    responseImageCached: false,
+    responseBodyFetchLink: true,
+  });
+
+  checkNodeContent(networkPanel, "responseBodyContent", expectedGrip.initial);
+
+  webConsoleClient.longString = longStringClientProvider;
+
+  clickable = networkPanel.document.querySelector("#responseBodyFetchLink");
+  EventUtils.sendMouseEvent({ type: "mousedown"}, clickable,
+                             networkPanel.document.defaultView);
+
+  yield undefined;
+
+  webConsoleClient.longString = longStringFn;
+  is(clickable.style.display, "none", "#responseBodyFetchLink is not visible");
+  checkNodeContent(networkPanel, "responseBodyContent",
+                   expectedGrip._fullString);
+
+  networkPanel.panel.hidePopup();
+
+  // All done!
+  testDriver = null;
+  executeSoon(finishTest);
+
+  yield undefined;
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_594477_clickable_output.js
@@ -0,0 +1,132 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ *  Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/" +
+                 "test/test-console.html";
+let HUD;
+let outputItem;
+let outputNode;
+
+let test = asyncTest(function* () {
+  yield loadTab(TEST_URI);
+
+  HUD = yield openConsole();
+  outputNode = HUD.outputNode;
+
+  // reload the tab
+  BrowserReload();
+  yield loadBrowser(gBrowser.selectedBrowser);
+
+  let event = yield clickEvents();
+  yield testClickAgain(event);
+  yield networkPanelHidden();
+
+  HUD = outputItem = outputNode = null;
+});
+
+function clickEvents() {
+  let deferred = promise.defer();
+
+  waitForMessages({
+    webconsole: HUD,
+    messages: [{
+      text: "test-console.html",
+      category: CATEGORY_NETWORK,
+      severity: SEVERITY_LOG,
+    }],
+  }).then(([result]) => {
+    let msg = [...result.matched][0];
+    outputItem = msg.querySelector(".message-body .url");
+    ok(outputItem, "found a network message");
+    document.addEventListener("popupshown", function onPanelShown(event) {
+      document.removeEventListener("popupshown", onPanelShown, false);
+      deferred.resolve(event);
+    }, false);
+
+    // Send the mousedown and click events such that the network panel opens.
+    EventUtils.sendMouseEvent({type: "mousedown"}, outputItem);
+    EventUtils.sendMouseEvent({type: "click"}, outputItem);
+  });
+
+  return deferred.promise;
+}
+
+function testClickAgain(event) {
+  info("testClickAgain");
+
+  let deferred = promise.defer();
+
+  document.addEventListener("popupshown", networkPanelShowFailure, false);
+
+  // The network panel should not open for the second time.
+  EventUtils.sendMouseEvent({type: "mousedown"}, outputItem);
+  EventUtils.sendMouseEvent({type: "click"}, outputItem);
+
+  executeSoon(function() {
+    document.addEventListener("popuphidden", function onHidden() {
+      document.removeEventListener("popuphidden", onHidden, false);
+      deferred.resolve();
+    }, false);
+    event.target.hidePopup();
+  });
+
+  return deferred.promise;
+}
+
+function networkPanelShowFailure() {
+  ok(false, "the network panel should not show");
+}
+
+function networkPanelHidden() {
+  let deferred = promise.defer();
+
+  info("networkPanelHidden");
+
+  // The network panel should not show because this is a mouse event that starts
+  // in a position and ends in another.
+  EventUtils.sendMouseEvent({type: "mousedown", clientX: 3, clientY: 4},
+    outputItem);
+  EventUtils.sendMouseEvent({type: "click", clientX: 5, clientY: 6},
+    outputItem);
+
+  // The network panel should not show because this is a middle-click.
+  EventUtils.sendMouseEvent({type: "mousedown", button: 1},
+    outputItem);
+  EventUtils.sendMouseEvent({type: "click", button: 1},
+    outputItem);
+
+  // The network panel should not show because this is a right-click.
+  EventUtils.sendMouseEvent({type: "mousedown", button: 2},
+    outputItem);
+  EventUtils.sendMouseEvent({type: "click", button: 2},
+    outputItem);
+
+  executeSoon(function() {
+    document.removeEventListener("popupshown", networkPanelShowFailure, false);
+
+    // Done with the network output. Now test the jsterm output and the property
+    // panel.
+    HUD.jsterm.execute("document").then((msg) => {
+      info("jsterm execute 'document' callback");
+
+      HUD.jsterm.once("variablesview-open", deferred.resolve);
+      outputItem = msg.querySelector(".message-body a");
+      ok(outputItem, "jsterm output message found");
+
+      // Send the mousedown and click events such that the property panel opens.
+      EventUtils.sendMouseEvent({type: "mousedown"}, outputItem);
+      EventUtils.sendMouseEvent({type: "click"}, outputItem);
+    });
+  });
+
+  return deferred.promise;
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_602572_log_bodies_checkbox.js
@@ -0,0 +1,186 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ *
+ * Contributor(s):
+ *   Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+"use strict";
+
+let menuitems = [];
+let menupopups = [];
+let huds = [];
+let tabs = [];
+let runCount = 0;
+
+const TEST_URI1 = "data:text/html;charset=utf-8,Web Console test for " +
+                  "bug 602572: log bodies checkbox. tab 1";
+const TEST_URI2 = "data:text/html;charset=utf-8,Web Console test for " +
+                  "bug 602572: log bodies checkbox. tab 2";
+
+function test() {
+  if (runCount == 0) {
+    requestLongerTimeout(2);
+  }
+
+  // open tab 2
+  function openTab() {
+    loadTab(TEST_URI2).then((tab) => {
+      tabs.push(tab.tab);
+      openConsole().then((hud) => {
+        hud.iframeWindow.requestAnimationFrame(startTest);
+      });
+    });
+  }
+
+  // open tab 1
+  loadTab(TEST_URI1).then((tab) => {
+    tabs.push(tab.tab);
+    openConsole().then((hud) => {
+      hud.iframeWindow.requestAnimationFrame(() => {
+        info("iframe1 root height " + hud.ui.rootElement.clientHeight);
+
+        openTab();
+      });
+    });
+  });
+}
+
+function startTest() {
+  // Find the relevant elements in the Web Console of tab 2.
+  let win2 = tabs[runCount * 2 + 1].linkedBrowser.contentWindow;
+  huds[1] = HUDService.getHudByWindow(win2);
+  info("startTest: iframe2 root height " + huds[1].ui.rootElement.clientHeight);
+
+  if (runCount == 0) {
+    menuitems[1] = huds[1].ui.rootElement.querySelector("#saveBodies");
+  } else {
+    menuitems[1] = huds[1].ui.rootElement
+                             .querySelector("#saveBodiesContextMenu");
+  }
+  menupopups[1] = menuitems[1].parentNode;
+
+  // Open the context menu from tab 2.
+  menupopups[1].addEventListener("popupshown", onpopupshown2, false);
+  executeSoon(function() {
+    menupopups[1].openPopup();
+  });
+}
+
+function onpopupshown2(evt) {
+  menupopups[1].removeEventListener(evt.type, onpopupshown2, false);
+
+  // By default bodies are not logged.
+  isnot(menuitems[1].getAttribute("checked"), "true",
+        "menuitems[1] is not checked");
+
+  ok(!huds[1].ui._saveRequestAndResponseBodies, "bodies are not logged");
+
+  // Enable body logging.
+  huds[1].ui.setSaveRequestAndResponseBodies(true).then(() => {
+    menupopups[1].hidePopup();
+  });
+
+  menupopups[1].addEventListener("popuphidden", function _onhidden(evtPopup) {
+    menupopups[1].removeEventListener(evtPopup.type, _onhidden, false);
+
+    info("menupopups[1] hidden");
+
+    // Reopen the context menu.
+    huds[1].ui.once("save-bodies-ui-toggled", () => testpopup2b(evtPopup));
+    menupopups[1].openPopup();
+  }, false);
+}
+
+function testpopup2b() {
+  is(menuitems[1].getAttribute("checked"), "true", "menuitems[1] is checked");
+
+  menupopups[1].addEventListener("popuphidden", function _onhidden(evtPopup) {
+    menupopups[1].removeEventListener(evtPopup.type, _onhidden, false);
+
+    info("menupopups[1] hidden");
+
+    // Switch to tab 1 and open the Web Console context menu from there.
+    gBrowser.selectedTab = tabs[runCount * 2];
+    waitForFocus(function() {
+      // Find the relevant elements in the Web Console of tab 1.
+      let win1 = tabs[runCount * 2].linkedBrowser.contentWindow;
+      huds[0] = HUDService.getHudByWindow(win1);
+
+      info("iframe1 root height " + huds[0].ui.rootElement.clientHeight);
+
+      menuitems[0] = huds[0].ui.rootElement.querySelector("#saveBodies");
+      menupopups[0] = huds[0].ui.rootElement.querySelector("menupopup");
+
+      menupopups[0].addEventListener("popupshown", onpopupshown1, false);
+      executeSoon(() => menupopups[0].openPopup());
+    }, tabs[runCount * 2].linkedBrowser.contentWindow);
+  }, false);
+
+  executeSoon(function() {
+    menupopups[1].hidePopup();
+  });
+}
+
+function onpopupshown1(evt) {
+  menupopups[0].removeEventListener(evt.type, onpopupshown1, false);
+
+  // The menuitem checkbox must not be in sync with the other tabs.
+  isnot(menuitems[0].getAttribute("checked"), "true",
+        "menuitems[0] is not checked");
+
+  // Enable body logging for tab 1 as well.
+  huds[0].ui.setSaveRequestAndResponseBodies(true).then(() => {
+    menupopups[0].hidePopup();
+  });
+
+  // Close the menu, and switch back to tab 2.
+  menupopups[0].addEventListener("popuphidden", function _onhidden(evtPopup) {
+    menupopups[0].removeEventListener(evtPopup.type, _onhidden, false);
+
+    info("menupopups[0] hidden");
+
+    gBrowser.selectedTab = tabs[runCount * 2 + 1];
+    waitForFocus(function() {
+      // Reopen the context menu from tab 2.
+      huds[1].ui.once("save-bodies-ui-toggled", () => testpopup2c(evtPopup));
+      menupopups[1].openPopup();
+    }, tabs[runCount * 2 + 1].linkedBrowser.contentWindow);
+  }, false);
+}
+
+function testpopup2c() {
+  is(menuitems[1].getAttribute("checked"), "true", "menuitems[1] is checked");
+
+  menupopups[1].addEventListener("popuphidden", function _onhidden(evtPopup) {
+    menupopups[1].removeEventListener(evtPopup.type, _onhidden, false);
+
+    info("menupopups[1] hidden");
+
+    // Done if on second run
+    closeConsole(gBrowser.selectedTab).then(function() {
+      if (runCount == 0) {
+        runCount++;
+        info("start second run");
+        executeSoon(test);
+      } else {
+        gBrowser.removeCurrentTab();
+        gBrowser.selectedTab = tabs[2];
+        gBrowser.removeCurrentTab();
+        gBrowser.selectedTab = tabs[1];
+        gBrowser.removeCurrentTab();
+        gBrowser.selectedTab = tabs[0];
+        gBrowser.removeCurrentTab();
+        huds = menuitems = menupopups = tabs = null;
+        executeSoon(finishTest);
+      }
+    });
+  }, false);
+
+  executeSoon(function() {
+    menupopups[1].hidePopup();
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_618311_close_panels.js
@@ -0,0 +1,93 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/" +
+                 "test/test-console.html";
+
+let test = asyncTest(function* () {
+  yield loadTab(TEST_URI);
+
+  let hud = yield openConsole();
+
+  BrowserReload();
+
+  let results = yield waitForMessages({
+    webconsole: hud,
+    messages: [{
+      text: "test-console.html",
+      category: CATEGORY_NETWORK,
+      severity: SEVERITY_LOG,
+    }],
+  });
+
+  yield performTest(hud, results);
+});
+
+function performTest(HUD, results) {
+  let deferred = promise.defer();
+
+  let networkMessage = [...results[0].matched][0];
+  ok(networkMessage, "network message element");
+
+  let networkLink = networkMessage.querySelector(".url");
+  ok(networkLink, "found network message link");
+
+  let popupset = document.getElementById("mainPopupSet");
+  ok(popupset, "found #mainPopupSet");
+
+  let popupsShown = 0;
+  let hiddenPopups = 0;
+
+  let onpopupshown = function() {
+    document.removeEventListener("popupshown", onpopupshown, false);
+    popupsShown++;
+
+    executeSoon(function() {
+      let popups = popupset.querySelectorAll("panel[hudId=" + HUD.hudId + "]");
+      is(popups.length, 1, "found one popup");
+
+      document.addEventListener("popuphidden", onpopuphidden, false);
+
+      registerCleanupFunction(function() {
+        is(hiddenPopups, 1, "correct number of popups hidden");
+        if (hiddenPopups != 1) {
+          document.removeEventListener("popuphidden", onpopuphidden, false);
+        }
+      });
+
+      executeSoon(closeConsole);
+    });
+  };
+
+  let onpopuphidden = function() {
+    document.removeEventListener("popuphidden", onpopuphidden, false);
+    hiddenPopups++;
+
+    executeSoon(function() {
+      let popups = popupset.querySelectorAll("panel[hudId=" + HUD.hudId + "]");
+      is(popups.length, 0, "no popups found");
+
+      executeSoon(deferred.resolve);
+    });
+  };
+
+  document.addEventListener("popupshown", onpopupshown, false);
+
+  registerCleanupFunction(function() {
+    is(popupsShown, 1, "correct number of popups shown");
+    if (popupsShown != 1) {
+      document.removeEventListener("popupshown", onpopupshown, false);
+    }
+  });
+
+  EventUtils.sendMouseEvent({ type: "mousedown" }, networkLink,
+                              HUD.iframeWindow);
+  EventUtils.sendMouseEvent({ type: "mouseup" }, networkLink, HUD.iframeWindow);
+  EventUtils.sendMouseEvent({ type: "click" }, networkLink, HUD.iframeWindow);
+
+  return deferred.promise;
+}
--- a/browser/devtools/webconsole/test/browser_webconsole_netlogging.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_netlogging.js
@@ -186,27 +186,25 @@ function testFormSubmission() {
     let form = content.document.querySelector("form");
     form.submit();
   }`);
 }
 
 function testNetworkPanel() {
   // Open the NetworkPanel. The functionality of the NetworkPanel is tested
   // within separate test files.
-  hud.ui.openNetworkPanel(lastRequest.actor).then(() => {
-    let toolbox = gDevTools.getToolbox(hud.target);
-    is(toolbox.currentToolId, "netmonitor", "Network panel was opened");
-    let panel = toolbox.getCurrentPanel();
-    let selected = panel.panelWin.NetMonitorView.RequestsMenu.selectedItem;
-    is(selected.attachment.method, lastRequest.request.method,
-       "The correct request is selected");
-    is(selected.attachment.url, lastRequest.request.url,
-       "The correct request is definitely selected");
+  let networkPanel = hud.ui.openNetworkPanel(hud.ui.filterBox, lastRequest);
+
+  networkPanel.panel.addEventListener("popupshown", function onPopupShown() {
+    networkPanel.panel.removeEventListener("popupshown", onPopupShown, true);
+
+    is(hud.ui.filterBox._netPanel, networkPanel,
+       "Network panel stored on anchor node");
+    ok(true, "NetworkPanel was opened");
 
     // All tests are done. Shutdown.
+    networkPanel.panel.hidePopup();
     lastRequest = null;
     HUDService.lastFinishedRequest.callback = null;
     browser = requestCallback = hud = null;
     executeSoon(finishTest);
-  }).then(null, error => {
-    ok(false, "Got an error: " + error.message + "\n" + error.stack);
-  });
+  }, true);
 }
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_network_panel.js
@@ -0,0 +1,551 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+// Tests that the network panel works.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/" +
+                 "test/test-console.html";
+const TEST_IMG = "http://example.com/browser/browser/devtools/webconsole/" +
+                 "test/test-image.png";
+const TEST_ENCODING_ISO_8859_1 = "http://example.com/browser/browser/" +
+                                 "devtools/webconsole/test/" +
+                                 "test-encoding-ISO-8859-1.html";
+
+const TEST_IMG_BASE64 =
+  "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAVRJ" +
+  "REFUOI2lk7FLw0AUxr+YpC1CBqcMWfsvCCLdXFzqEJCgDl1EQRGxg9AhSBEJONhFhG52UCuF" +
+  "Djq5dxD8FwoO0qGDOBQkl7vLOeWa2EQDffDBvTu+373Hu1OEEJgntGgxGD6J+7fLXKbt5VNU" +
+  "yhsKAChRBQcPFVFeWskFGH694mZroCQqCLlAwPxcgJBP254CmAD5B7C7dgHLMLF3uzoL4DQE" +
+  "od+Z5sP1FizDxGgyBqfhLID9AahX29J89bwPFgMsSEAQglAf9WobhPpScbPXr4FQHyzIADTs" +
+  "DizDRMPuIOC+zEeTMZo9BwH3EfAMACccbtfGaDKGZZg423yUZrdrg3EqxQlPr0BTdTR7joRE" +
+  "N2uqnlBmCwW1hIJagtev4f3zA16/JvfiigMSYyzqJXlw/XKUyOORMUaBor6YavgdjKa8xGOn" +
+  "idadmwtwsnMu18q83/kHSou+bFNDDr4AAAAASUVORK5CYII=";
+
+let testDriver, hud;
+
+function test() {
+  loadTab(TEST_URI).then(() => {
+    openConsole().then(testNetworkPanel);
+  });
+}
+
+function testNetworkPanel(aHud) {
+  hud = aHud;
+  testDriver = testGen();
+  testDriver.next();
+}
+
+function checkIsVisible(aPanel, aList) {
+  for (let id in aList) {
+    let node = aPanel.document.getElementById(id);
+    let isVisible = aList[id];
+    is(node.style.display, (isVisible ? "block" : "none"),
+       id + " isVisible=" + isVisible);
+  }
+}
+
+function checkNodeContent(aPanel, aId, aContent) {
+  let node = aPanel.document.getElementById(aId);
+  if (node == null) {
+    ok(false, "Tried to access node " + aId + " that doesn't exist!");
+  } else if (node.textContent.indexOf(aContent) != -1) {
+    ok(true, "checking content of " + aId);
+  } else {
+    ok(false, "Got false value for " + aId + ": " + node.textContent +
+              " doesn't have " + aContent);
+  }
+}
+
+function checkNodeKeyValue(aPanel, aId, aKey, aValue) {
+  let node = aPanel.document.getElementById(aId);
+
+  let headers = node.querySelectorAll("th");
+  for (let i = 0; i < headers.length; i++) {
+    if (headers[i].textContent == (aKey + ":")) {
+      is(headers[i].nextElementSibling.textContent, aValue,
+         "checking content of " + aId + " for key " + aKey);
+      return;
+    }
+  }
+
+  ok(false, "content check failed for " + aId + ", key " + aKey);
+}
+
+function* testGen() {
+  let filterBox = hud.ui.filterBox;
+
+  let httpActivity = {
+    updates: [],
+    discardRequestBody: true,
+    discardResponseBody: true,
+    startedDateTime: (new Date()).toISOString(),
+    request: {
+      url: "http://www.testpage.com",
+      method: "GET",
+      cookies: [],
+      headers: [
+        { name: "foo", value: "bar" },
+      ],
+    },
+    response: {
+      headers: [],
+      content: {},
+      cookies: [],
+    },
+    timings: {},
+  };
+
+  let networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+
+  is(filterBox._netPanel, networkPanel,
+     "Network panel stored on the anchor object");
+
+  networkPanel._onUpdate = function() {
+    networkPanel._onUpdate = null;
+    executeSoon(function() {
+      testDriver.next();
+    });
+  };
+
+  yield undefined;
+
+  info("test 1");
+
+  checkIsVisible(networkPanel, {
+    requestCookie: false,
+    requestFormData: false,
+    requestBody: false,
+    responseContainer: false,
+    responseBody: false,
+    responseNoBody: false,
+    responseImage: false,
+    responseImageCached: false
+  });
+
+  checkNodeContent(networkPanel, "header", "http://www.testpage.com");
+  checkNodeContent(networkPanel, "header", "GET");
+  checkNodeKeyValue(networkPanel, "requestHeadersContent", "foo", "bar");
+
+  // Test request body.
+  info("test 2: request body");
+  httpActivity.discardRequestBody = false;
+  httpActivity.request.postData = { text: "hello world" };
+  networkPanel.update();
+
+  checkIsVisible(networkPanel, {
+    requestBody: true,
+    requestFormData: false,
+    requestCookie: false,
+    responseContainer: false,
+    responseBody: false,
+    responseNoBody: false,
+    responseImage: false,
+    responseImageCached: false
+  });
+  checkNodeContent(networkPanel, "requestBodyContent", "hello world");
+
+  // Test response header.
+  info("test 3: response header");
+  httpActivity.timings.wait = 10;
+  httpActivity.response.httpVersion = "HTTP/3.14";
+  httpActivity.response.status = 999;
+  httpActivity.response.statusText = "earthquake win";
+  httpActivity.response.content.mimeType = "text/html";
+  httpActivity.response.headers.push(
+    { name: "Content-Type", value: "text/html" },
+    { name: "leaveHouses", value: "true" }
+  );
+
+  networkPanel.update();
+
+  checkIsVisible(networkPanel, {
+    requestBody: true,
+    requestFormData: false,
+    requestCookie: false,
+    responseContainer: true,
+    responseBody: false,
+    responseNoBody: false,
+    responseImage: false,
+    responseImageCached: false
+  });
+
+  checkNodeContent(networkPanel, "header", "HTTP/3.14 999 earthquake win");
+  checkNodeKeyValue(networkPanel, "responseHeadersContent", "leaveHouses",
+                    "true");
+  checkNodeContent(networkPanel, "responseHeadersInfo", "10ms");
+
+  info("test 4");
+
+  httpActivity.discardResponseBody = false;
+  httpActivity.timings.receive = 2;
+  networkPanel.update();
+
+  checkIsVisible(networkPanel, {
+    requestBody: true,
+    requestCookie: false,
+    requestFormData: false,
+    responseContainer: true,
+    responseBody: false,
+    responseNoBody: false,
+    responseImage: false,
+    responseImageCached: false
+  });
+
+  info("test 5");
+
+  httpActivity.updates.push("responseContent", "eventTimings");
+  networkPanel.update();
+
+  checkNodeContent(networkPanel, "responseNoBodyInfo", "2ms");
+  checkIsVisible(networkPanel, {
+    requestBody: true,
+    requestCookie: false,
+    responseContainer: true,
+    responseBody: false,
+    responseNoBody: true,
+    responseImage: false,
+    responseImageCached: false
+  });
+
+  networkPanel.panel.hidePopup();
+
+  // Second run: Test for cookies and response body.
+  info("test 6: cookies and response body");
+  httpActivity.request.cookies.push(
+    { name: "foo", value: "bar" },
+    { name: "hello", value: "world" }
+  );
+  httpActivity.response.content.text = "get out here";
+
+  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+  is(filterBox._netPanel, networkPanel,
+     "Network panel stored on httpActivity object");
+
+  networkPanel._onUpdate = function() {
+    networkPanel._onUpdate = null;
+    executeSoon(function() {
+      testDriver.next();
+    });
+  };
+
+  yield undefined;
+
+  checkIsVisible(networkPanel, {
+    requestBody: true,
+    requestFormData: false,
+    requestCookie: true,
+    responseContainer: true,
+    responseCookie: false,
+    responseBody: true,
+    responseNoBody: false,
+    responseImage: false,
+    responseImageCached: false
+  });
+
+  checkNodeKeyValue(networkPanel, "requestCookieContent", "foo", "bar");
+  checkNodeKeyValue(networkPanel, "requestCookieContent", "hello", "world");
+  checkNodeContent(networkPanel, "responseBodyContent", "get out here");
+  checkNodeContent(networkPanel, "responseBodyInfo", "2ms");
+
+  networkPanel.panel.hidePopup();
+
+  // Third run: Test for response cookies.
+  info("test 6b: response cookies");
+  httpActivity.response.cookies.push(
+    { name: "foobar", value: "boom" },
+    { name: "foobaz", value: "omg" }
+  );
+
+  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+  is(filterBox._netPanel, networkPanel,
+     "Network panel stored on httpActivity object");
+
+  networkPanel._onUpdate = function() {
+    networkPanel._onUpdate = null;
+    executeSoon(function() {
+      testDriver.next();
+    });
+  };
+
+  yield undefined;
+
+  checkIsVisible(networkPanel, {
+    requestBody: true,
+    requestFormData: false,
+    requestCookie: true,
+    responseContainer: true,
+    responseCookie: true,
+    responseBody: true,
+    responseNoBody: false,
+    responseImage: false,
+    responseImageCached: false,
+    responseBodyFetchLink: false,
+  });
+
+  checkNodeKeyValue(networkPanel, "responseCookieContent", "foobar", "boom");
+  checkNodeKeyValue(networkPanel, "responseCookieContent", "foobaz", "omg");
+
+  networkPanel.panel.hidePopup();
+
+  // Check image request.
+  info("test 7: image request");
+  httpActivity.response.headers[1].value = "image/png";
+  httpActivity.response.content.mimeType = "image/png";
+  httpActivity.response.content.text = TEST_IMG_BASE64;
+  httpActivity.request.url = TEST_IMG;
+
+  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+  networkPanel._onUpdate = function() {
+    networkPanel._onUpdate = null;
+    executeSoon(function() {
+      testDriver.next();
+    });
+  };
+
+  yield undefined;
+
+  checkIsVisible(networkPanel, {
+    requestBody: true,
+    requestFormData: false,
+    requestCookie: true,
+    responseContainer: true,
+    responseBody: false,
+    responseNoBody: false,
+    responseImage: true,
+    responseImageCached: false,
+    responseBodyFetchLink: false,
+  });
+
+  let imgNode = networkPanel.document.getElementById("responseImageNode");
+  is(imgNode.getAttribute("src"), "data:image/png;base64," + TEST_IMG_BASE64,
+      "Displayed image is correct");
+
+  function checkImageResponseInfo() {
+    checkNodeContent(networkPanel, "responseImageInfo", "2ms");
+    checkNodeContent(networkPanel, "responseImageInfo", "16x16px");
+  }
+
+  // Check if the image is loaded already.
+  imgNode.addEventListener("load", function onLoad() {
+    imgNode.removeEventListener("load", onLoad, false);
+    checkImageResponseInfo();
+    networkPanel.panel.hidePopup();
+    testDriver.next();
+  }, false);
+  yield undefined;
+
+  // Check cached image request.
+  info("test 8: cached image request");
+  httpActivity.response.httpVersion = "HTTP/1.1";
+  httpActivity.response.status = 304;
+  httpActivity.response.statusText = "Not Modified";
+
+  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+  networkPanel._onUpdate = function() {
+    networkPanel._onUpdate = null;
+    executeSoon(function() {
+      testDriver.next();
+    });
+  };
+
+  yield undefined;
+
+  checkIsVisible(networkPanel, {
+    requestBody: true,
+    requestFormData: false,
+    requestCookie: true,
+    responseContainer: true,
+    responseBody: false,
+    responseNoBody: false,
+    responseImage: false,
+    responseImageCached: true
+  });
+
+  imgNode = networkPanel.document.getElementById("responseImageCachedNode");
+  is(imgNode.getAttribute("src"), "data:image/png;base64," + TEST_IMG_BASE64,
+     "Displayed image is correct");
+
+  networkPanel.panel.hidePopup();
+
+  // Test sent form data.
+  info("test 9: sent form data");
+  httpActivity.request.postData.text = [
+    "Content-Type:      application/x-www-form-urlencoded",
+    "Content-Length: 59",
+    "name=rob&age=20"
+  ].join("\n");
+
+  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+  networkPanel._onUpdate = function() {
+    networkPanel._onUpdate = null;
+    executeSoon(function() {
+      testDriver.next();
+    });
+  };
+
+  yield undefined;
+
+  checkIsVisible(networkPanel, {
+    requestBody: false,
+    requestFormData: true,
+    requestCookie: true,
+    responseContainer: true,
+    responseBody: false,
+    responseNoBody: false,
+    responseImage: false,
+    responseImageCached: true
+  });
+
+  checkNodeKeyValue(networkPanel, "requestFormDataContent", "name", "rob");
+  checkNodeKeyValue(networkPanel, "requestFormDataContent", "age", "20");
+  networkPanel.panel.hidePopup();
+
+  // Test no space after Content-Type:
+  info("test 10: no space after Content-Type header in post data");
+  httpActivity.request.postData.text = "Content-Type:application/x-www-" +
+                                       "form-urlencoded\n";
+
+  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+  networkPanel._onUpdate = function() {
+    networkPanel._onUpdate = null;
+    executeSoon(function() {
+      testDriver.next();
+    });
+  };
+
+  yield undefined;
+
+  checkIsVisible(networkPanel, {
+    requestBody: false,
+    requestFormData: true,
+    requestCookie: true,
+    responseContainer: true,
+    responseBody: false,
+    responseNoBody: false,
+    responseImage: false,
+    responseImageCached: true
+  });
+
+  networkPanel.panel.hidePopup();
+
+  // Test cached data.
+
+  info("test 11: cached data");
+
+  httpActivity.request.url = TEST_ENCODING_ISO_8859_1;
+  httpActivity.response.headers[1].value = "application/json";
+  httpActivity.response.content.mimeType = "application/json";
+  httpActivity.response.content.text = "my cached data is here!";
+
+  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+  networkPanel._onUpdate = function() {
+    networkPanel._onUpdate = null;
+    executeSoon(function() {
+      testDriver.next();
+    });
+  };
+
+  yield undefined;
+
+  checkIsVisible(networkPanel, {
+    requestBody: false,
+    requestFormData: true,
+    requestCookie: true,
+    responseContainer: true,
+    responseBody: false,
+    responseBodyCached: true,
+    responseNoBody: false,
+    responseImage: false,
+    responseImageCached: false
+  });
+
+  checkNodeContent(networkPanel, "responseBodyCachedContent",
+                   "my cached data is here!");
+
+  networkPanel.panel.hidePopup();
+
+  // Test a response with a content type that can't be displayed in the
+  // NetworkPanel.
+  info("test 12: unknown content type");
+  httpActivity.response.headers[1].value = "application/x-shockwave-flash";
+  httpActivity.response.content.mimeType = "application/x-shockwave-flash";
+
+  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+  networkPanel._onUpdate = function() {
+    networkPanel._onUpdate = null;
+    executeSoon(function() {
+      testDriver.next();
+    });
+  };
+
+  yield undefined;
+
+  checkIsVisible(networkPanel, {
+    requestBody: false,
+    requestFormData: true,
+    requestCookie: true,
+    responseContainer: true,
+    responseBody: false,
+    responseBodyCached: false,
+    responseBodyUnknownType: true,
+    responseNoBody: false,
+    responseImage: false,
+    responseImageCached: false
+  });
+
+  let responseString =
+    WCUL10n.getFormatStr("NetworkPanel.responseBodyUnableToDisplay.content",
+                      ["application/x-shockwave-flash"]);
+  checkNodeContent(networkPanel,
+                   "responseBodyUnknownTypeContent",
+                   responseString);
+  networkPanel.panel.hidePopup();
+
+  /*
+
+  // This test disabled. See bug 603620.
+
+  // Test if the NetworkPanel figures out the content type based on an URL as
+  // well.
+  delete httpActivity.response.header["Content-Type"];
+  httpActivity.url = "http://www.test.com/someCrazyFile.swf?done=right&ending=txt";
+
+  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
+  networkPanel.isDoneCallback = function NP_doneCallback() {
+    networkPanel.isDoneCallback = null;
+    testDriver.next();
+  }
+
+  yield undefined;
+
+  checkIsVisible(networkPanel, {
+    requestBody: false,
+    requestFormData: true,
+    requestCookie: true,
+    responseContainer: true,
+    responseBody: false,
+    responseBodyCached: false,
+    responseBodyUnknownType: true,
+    responseNoBody: false,
+    responseImage: false,
+    responseImageCached: false
+  });
+
+  // Systems without Flash installed will return an empty string here. Ignore.
+  if (networkPanel.document.getElementById("responseBodyUnknownTypeContent").textContent !== "")
+    checkNodeContent(networkPanel, "responseBodyUnknownTypeContent", responseString);
+  else
+    ok(true, "Flash not installed");
+
+  networkPanel.panel.hidePopup(); */
+
+  // All done!
+  testDriver = hud = null;
+  executeSoon(finishTest);
+
+  yield undefined;
+}
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -15,16 +15,18 @@ loader.lazyServiceGetter(this, "clipboar
                          "@mozilla.org/widget/clipboardhelper;1",
                          "nsIClipboardHelper");
 loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
 loader.lazyGetter(this, "EventEmitter", () => require("devtools/toolkit/event-emitter"));
 loader.lazyGetter(this, "AutocompletePopup",
                   () => require("devtools/shared/autocomplete-popup").AutocompletePopup);
 loader.lazyGetter(this, "ToolSidebar",
                   () => require("devtools/framework/sidebar").ToolSidebar);
+loader.lazyGetter(this, "NetworkPanel",
+                  () => require("devtools/webconsole/network-panel").NetworkPanel);
 loader.lazyGetter(this, "ConsoleOutput",
                   () => require("devtools/webconsole/console-output").ConsoleOutput);
 loader.lazyGetter(this, "Messages",
                   () => require("devtools/webconsole/console-output").Messages);
 loader.lazyGetter(this, "asyncStorage",
                   () => require("devtools/toolkit/shared/async-storage"));
 loader.lazyRequireGetter(this, "EnvironmentClient", "devtools/toolkit/client/main", true);
 loader.lazyRequireGetter(this, "ObjectClient", "devtools/toolkit/client/main", true);
@@ -1666,17 +1668,21 @@ WebConsoleFrame.prototype = {
       messageNode.classList.add("mixed-content");
       this.makeMixedContentNode(body);
     }
 
     let statusNode = this.document.createElementNS(XHTML_NS, "a");
     statusNode.className = "status";
     body.appendChild(statusNode);
 
-    let onClick = () => this.openNetworkPanel(networkInfo.actor);
+    let onClick = () => {
+      if (!messageNode._panelOpen) {
+        this.openNetworkPanel(messageNode, networkInfo);
+      }
+    };
 
     this._addMessageLinkCallback(urlNode, onClick);
     this._addMessageLinkCallback(statusNode, onClick);
 
     networkInfo.node = messageNode;
 
     this._updateNetMessage(actorId);
 
@@ -1958,27 +1964,144 @@ WebConsoleFrame.prototype = {
     if (messageNode._netPanel) {
       messageNode._netPanel.update();
     }
 
     return updated;
   },
 
   /**
-   * Opens the network monitor and highlights the specified request.
+   * Opens a NetworkPanel.
    *
-   * @param string requestId
-   *        The actor ID of the network request.
+   * @param nsIDOMNode aNode
+   *        The message node you want the panel to be anchored to.
+   * @param object aHttpActivity
+   *        The HTTP activity object that holds network request and response
+   *        information. This object is given to the NetworkPanel constructor.
+   * @return object
+   *         The new NetworkPanel instance.
    */
-  openNetworkPanel: function WCF_openNetworkPanel(requestId)
+  openNetworkPanel: function WCF_openNetworkPanel(aNode, aHttpActivity)
   {
-    let toolbox = gDevTools.getToolbox(this.owner.target);
-    return toolbox.selectTool("netmonitor").then(panel => {
-      return panel.panelWin.NetMonitorController.inspectRequest(requestId);
-    });
+    let actor = aHttpActivity.actor;
+
+    if (actor) {
+      this.webConsoleClient.getRequestHeaders(actor, (aResponse) => {
+        if (aResponse.error) {
+          Cu.reportError("WCF_openNetworkPanel getRequestHeaders:" +
+                         aResponse.error);
+          return;
+        }
+
+        aHttpActivity.request.headers = aResponse.headers;
+
+        this.webConsoleClient.getRequestCookies(actor, onRequestCookies);
+      });
+    }
+
+    let onRequestCookies = (aResponse) => {
+      if (aResponse.error) {
+        Cu.reportError("WCF_openNetworkPanel getRequestCookies:" +
+                       aResponse.error);
+        return;
+      }
+
+      aHttpActivity.request.cookies = aResponse.cookies;
+
+      this.webConsoleClient.getResponseHeaders(actor, onResponseHeaders);
+    };
+
+    let onResponseHeaders = (aResponse) => {
+      if (aResponse.error) {
+        Cu.reportError("WCF_openNetworkPanel getResponseHeaders:" +
+                       aResponse.error);
+        return;
+      }
+
+      aHttpActivity.response.headers = aResponse.headers;
+
+      this.webConsoleClient.getResponseCookies(actor, onResponseCookies);
+    };
+
+    let onResponseCookies = (aResponse) => {
+      if (aResponse.error) {
+        Cu.reportError("WCF_openNetworkPanel getResponseCookies:" +
+                       aResponse.error);
+        return;
+      }
+
+      aHttpActivity.response.cookies = aResponse.cookies;
+
+      this.webConsoleClient.getRequestPostData(actor, onRequestPostData);
+    };
+
+    let onRequestPostData = (aResponse) => {
+      if (aResponse.error) {
+        Cu.reportError("WCF_openNetworkPanel getRequestPostData:" +
+                       aResponse.error);
+        return;
+      }
+
+      aHttpActivity.request.postData = aResponse.postData;
+      aHttpActivity.discardRequestBody = aResponse.postDataDiscarded;
+
+      this.webConsoleClient.getResponseContent(actor, onResponseContent);
+    };
+
+    let onResponseContent = (aResponse) => {
+      if (aResponse.error) {
+        Cu.reportError("WCF_openNetworkPanel getResponseContent:" +
+                       aResponse.error);
+        return;
+      }
+
+      aHttpActivity.response.content = aResponse.content;
+      aHttpActivity.discardResponseBody = aResponse.contentDiscarded;
+
+      this.webConsoleClient.getEventTimings(actor, onEventTimings);
+    };
+
+    let onEventTimings = (aResponse) => {
+      if (aResponse.error) {
+        Cu.reportError("WCF_openNetworkPanel getEventTimings:" +
+                       aResponse.error);
+        return;
+      }
+
+      aHttpActivity.timings = aResponse.timings;
+
+      openPanel();
+    };
+
+    let openPanel = () => {
+      aNode._netPanel = netPanel;
+
+      let panel = netPanel.panel;
+      panel.openPopup(aNode, "after_pointer", 0, 0, false, false);
+      panel.sizeTo(450, 500);
+      panel.setAttribute("hudId", this.hudId);
+
+      panel.addEventListener("popuphiding", function WCF_netPanel_onHide() {
+        panel.removeEventListener("popuphiding", WCF_netPanel_onHide);
+
+        aNode._panelOpen = false;
+        aNode._netPanel = null;
+      });
+
+      aNode._panelOpen = true;
+    };
+
+    let netPanel = new NetworkPanel(this.popupset, aHttpActivity, this);
+    netPanel.linkNode = aNode;
+
+    if (!actor) {
+      openPanel();
+    }
+
+    return netPanel;
   },
 
   /**
    * Handler for page location changes.
    *
    * @param string aURI
    *        New page location.
    * @param string aTitle
--- a/browser/installer/Makefile.in
+++ b/browser/installer/Makefile.in
@@ -136,19 +136,16 @@ DEFINES += -DLPROJ_ROOT=$(LPROJ_ROOT)
 
 DEFINES += -DMOZ_ICU_VERSION=$(MOZ_ICU_VERSION)
 ifdef MOZ_NATIVE_ICU
 DEFINES += -DMOZ_NATIVE_ICU
 endif
 ifdef MOZ_SHARED_ICU
 DEFINES += -DMOZ_SHARED_ICU
 endif
-ifdef MOZ_JEMALLOC4
-DEFINES += -DMOZ_JEMALLOC4
-endif
 DEFINES += -DMOZ_ICU_DBG_SUFFIX=$(MOZ_ICU_DBG_SUFFIX)
 ifdef CLANG_CXX
 DEFINES += -DCLANG_CXX
 endif
 ifdef CLANG_CL
 DEFINES += -DCLANG_CL
 endif
 ifeq (x86,$(CPU_ARCH))
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -118,21 +118,16 @@
 @BINPATH@/libicuuc.@MOZ_ICU_VERSION@.dylib
 #elif defined(XP_UNIX)
 @BINPATH@/libicudata.so.@MOZ_ICU_VERSION@
 @BINPATH@/libicui18n.so.@MOZ_ICU_VERSION@
 @BINPATH@/libicuuc.so.@MOZ_ICU_VERSION@
 #endif
 #endif
 #endif
-#ifdef MOZ_REPLACE_MALLOC
-#ifndef MOZ_JEMALLOC4
-@BINPATH@/@DLL_PREFIX@replace_jemalloc@DLL_SUFFIX@
-#endif
-#endif
 #ifdef MOZ_GTK3
 @BINPATH@/@DLL_PREFIX@mozgtk@DLL_SUFFIX@
 @BINPATH@/gtk2/@DLL_PREFIX@mozgtk@DLL_SUFFIX@
 #endif
 
 [browser]
 ; [Base Browser Files]
 #ifndef XP_UNIX
--- a/browser/locales/en-US/chrome/browser/devtools/webConsole.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/webConsole.dtd
@@ -6,16 +6,34 @@
   - keep it in English, or another language commonly spoken among web developers.
   - You want to make that choice consistent across the developer tools.
   - A good criteria is the language in which you'd find the best
   - documentation on web development on the web. -->
 
 <!ENTITY window.title "Web Console">
 <!ENTITY browserConsole.title "Browser Console">
 
+<!ENTITY networkPanel.requestURLColon             "Request URL:">
+<!ENTITY networkPanel.requestMethodColon          "Request Method:">
+<!ENTITY networkPanel.statusCodeColon             "Status Code:">
+
+<!ENTITY networkPanel.requestHeaders              "Request Headers">
+<!ENTITY networkPanel.requestCookie               "Sent Cookie">
+<!ENTITY networkPanel.requestBody                 "Request Body">
+<!ENTITY networkPanel.requestFormData             "Sent Form Data">
+
+<!ENTITY networkPanel.responseHeaders             "Response Headers">
+<!ENTITY networkPanel.responseCookie              "Received Cookie">
+<!ENTITY networkPanel.responseBody                "Response Body">
+<!ENTITY networkPanel.responseBodyCached          "Cached Data">
+<!ENTITY networkPanel.responseBodyUnknownType     "Unknown Content Type">
+<!ENTITY networkPanel.responseNoBody              "No Response Body">
+<!ENTITY networkPanel.responseImage               "Received Image">
+<!ENTITY networkPanel.responseImageCached         "Cached Image">
+
 <!-- LOCALIZATION NOTE (saveBodies.label): You can see this string in the Web
    - Console context menu. -->
 <!ENTITY saveBodies.label     "Log Request and Response Bodies">
 <!ENTITY saveBodies.accesskey "L">
 
 <!-- LOCALIZATION NOTE (openURL.label): You can see this string in the Web
    - Console context menu. -->
 <!ENTITY openURL.label     "Open URL in New Tab">
--- a/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
@@ -35,22 +35,39 @@ update.accesskey=U
 cmd.commandkey=K
 webConsoleCmd.accesskey=W
 
 # LOCALIZATION NOTE (timestampFormat): %1$02S = hours (24-hour clock),
 # %2$02S = minutes, %3$02S = seconds, %4$03S = milliseconds.
 timestampFormat=%02S:%02S:%02S.%03S
 
 helperFuncUnsupportedTypeError=Can't call pprint on this type of object.
+NetworkPanel.label=Inspect Network Request
 
 # LOCALIZATION NOTE (NetworkPanel.deltaDurationMS): this string is used to
 # show the duration between two network events (e.g request and response
 # header or response header and response body). Parameters: %S is the duration.
 NetworkPanel.durationMS=%Sms
 
+# LOCALIZATION NOTE (NetworkPanel.imageSizeDeltaDurationMS): this string is
+# used to show the duration between the response header and the response body
+# event. It also shows the size of the received or cached image. Parameters:
+# %1$S is the width of the inspected image, %2$S is the height of the
+# inspected image, %3$S is the duration between the response header and the
+# response body event. Example: 150x100px, Δ50ms.
+NetworkPanel.imageSizeDeltaDurationMS=%1$Sx%2$Spx, Δ%3$Sms
+
+# LOCALIZATION NOTE (NetworkPanel.responseBodyUnableToDisplay.content): this
+# string is displayed within the response body section of the NetworkPanel if
+# the content type of the network request can't be displayed. E.g. any kind of
+# text is easy to display, but some audio or flash data received from the
+# server can't be displayed. Parameters: %S is the content type that can't be
+# displayed, examples are application/x-shockwave-flash, music/crescendo.
+NetworkPanel.responseBodyUnableToDisplay.content=Unable to display responses of type "%S"
+
 ConsoleAPIDisabled=The Web Console logging API (console.log, console.info, console.warn, console.error) has been disabled by a script on this page.
 
 # LOCALIZATION NOTE (webConsoleWindowTitleAndURL): the Web Console floating
 # panel title. For RTL languages you need to set the LRM in the string to give
 # the URL the correct direction. Parameters: %S is the web page URL.
 webConsoleWindowTitleAndURL=Web Console - %S
 
 # LOCALIZATION NOTE (webConsoleXhrIndicator): the indicator displayed before
--- a/browser/locales/en-US/chrome/browser/pageInfo.dtd
+++ b/browser/locales/en-US/chrome/browser/pageInfo.dtd
@@ -1,14 +1,14 @@
 <!-- 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  pageInfoWindow.width  "600">
-<!ENTITY  pageInfoWindow.height "500">
+<!ENTITY  pageInfoWindow.height "550">
 
 <!ENTITY  copy.key              "C">
 <!ENTITY  copy.label            "Copy">
 <!ENTITY  copy.accesskey        "C">
 <!ENTITY  selectall.key         "A">
 <!ENTITY  selectall.label       "Select All">
 <!ENTITY  selectall.accesskey   "A">
 <!ENTITY  closeWindow.key       "w">
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -325,16 +325,17 @@ browser.jar:
   skin/classic/browser/devtools/command-eyedropper.png        (../shared/devtools/images/command-eyedropper.png)
   skin/classic/browser/devtools/command-eyedropper@2x.png     (../shared/devtools/images/command-eyedropper@2x.png)
   skin/classic/browser/devtools/command-rulers.png            (../shared/devtools/images/command-rulers.png)
   skin/classic/browser/devtools/command-rulers@2x.png         (../shared/devtools/images/command-rulers@2x.png)
   skin/classic/browser/devtools/alerticon-warning.png (../shared/devtools/images/alerticon-warning.png)
   skin/classic/browser/devtools/alerticon-warning@2x.png      (../shared/devtools/images/alerticon-warning@2x.png)
 * skin/classic/browser/devtools/ruleview.css          (../shared/devtools/ruleview.css)
 * skin/classic/browser/devtools/webconsole.css                  (../shared/devtools/webconsole.css)
+  skin/classic/browser/devtools/webconsole_networkpanel.css     (../shared/devtools/webconsole_networkpanel.css)
   skin/classic/browser/devtools/webconsole.svg                  (../shared/devtools/images/webconsole.svg)
   skin/classic/browser/devtools/commandline.css              (../shared/devtools/commandline.css)
   skin/classic/browser/devtools/markup-view.css       (../shared/devtools/markup-view.css)
   skin/classic/browser/devtools/editor-error.png       (../shared/devtools/images/editor-error.png)
   skin/classic/browser/devtools/editor-breakpoint.png  (../shared/devtools/images/editor-breakpoint.png)
   skin/classic/browser/devtools/editor-debug-location.png (../shared/devtools/images/editor-debug-location.png)
   skin/classic/browser/devtools/editor-debug-location@2x.png (../shared/devtools/images/editor-debug-location@2x.png)
   skin/classic/browser/devtools/breadcrumbs-divider@2x.png      (../shared/devtools/images/breadcrumbs-divider@2x.png)
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -427,16 +427,17 @@ browser.jar:
   skin/classic/browser/devtools/commandline.css             (../shared/devtools/commandline.css)
   skin/classic/browser/devtools/markup-view.css             (../shared/devtools/markup-view.css)
   skin/classic/browser/devtools/editor-error.png             (../shared/devtools/images/editor-error.png)
   skin/classic/browser/devtools/editor-breakpoint.png        (../shared/devtools/images/editor-breakpoint.png)
   skin/classic/browser/devtools/editor-breakpoint@2x.png        (../shared/devtools/images/editor-breakpoint@2x.png)
   skin/classic/browser/devtools/editor-debug-location.png    (../shared/devtools/images/editor-debug-location.png)
   skin/classic/browser/devtools/editor-debug-location@2x.png    (../shared/devtools/images/editor-debug-location@2x.png)
 * skin/classic/browser/devtools/webconsole.css                  (../shared/devtools/webconsole.css)
+  skin/classic/browser/devtools/webconsole_networkpanel.css     (../shared/devtools/webconsole_networkpanel.css)
   skin/classic/browser/devtools/webconsole.svg                  (../shared/devtools/images/webconsole.svg)
   skin/classic/browser/devtools/breadcrumbs-divider@2x.png      (../shared/devtools/images/breadcrumbs-divider@2x.png)
   skin/classic/browser/devtools/breadcrumbs-scrollbutton.png    (../shared/devtools/images/breadcrumbs-scrollbutton.png)
   skin/classic/browser/devtools/breadcrumbs-scrollbutton@2x.png (../shared/devtools/images/breadcrumbs-scrollbutton@2x.png)
   skin/classic/browser/devtools/animationinspector.css          (../shared/devtools/animationinspector.css)
 * skin/classic/browser/devtools/canvasdebugger.css          (../shared/devtools/canvasdebugger.css)
   skin/classic/browser/devtools/debugger.css                (../shared/devtools/debugger.css)
   skin/classic/browser/devtools/eyedropper.css              (../shared/devtools/eyedropper.css)
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/devtools/webconsole_networkpanel.css
@@ -0,0 +1,100 @@
+/* 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/. */
+
+body {
+  font-family: sans-serif;
+  font-size: 11px;
+  background: #EEE;
+  color: #000;
+}
+
+#header {
+  padding: 5px;
+  overflow-x:auto;
+  display: block;
+}
+
+h1 {
+  font-size: 13px;
+  line-height: 15px;
+  padding: 3px 10px;
+  vertical-align: bottom;
+  margin: 0px;
+  background: linear-gradient(#BBB, #999);
+  border-radius: 2px;
+  text-shadow: #FFF 0px 1px 0px;
+}
+
+h1 .info {
+  font-size: 11px;
+  line-height: 15px;
+  vertical-align: bottom;
+  float: right;
+  color: #333;
+  padding-right: 3px;
+}
+
+.property-table {
+  padding: 2px 5px;
+  background: linear-gradient(#FFF, #F8F8F8);
+  color: #333;
+  width: 100%;
+  max-height: 330px;
+  overflow: auto;
+  display: block;
+}
+
+.property-name {
+  font-size: 11px;
+  font-weight: bold;
+  padding-right: 4px;
+  color: #000;
+  white-space: nowrap;
+  text-align: end;
+  vertical-align: top;
+  width: 10%;
+}
+
+.property-value {
+  padding-right: 5px;
+  font-size: 11px;
+  word-wrap: break-word;
+  width: 90%;
+}
+
+div.group {
+  margin-top: 10px;
+}
+
+div.group,
+#header {
+  background: #FFF;
+  border-color: #E1E1E1;
+  border-style: solid;
+  border-width: 1px;
+  box-shadow: 0 1px 1.5px rgba(0, 0, 0, 0.2);
+  border-radius: 4px 4px 4px 4px;
+}
+
+img#responseImageNode {
+  box-shadow: rgba(0,0,0,0.2) 0px 3px 3.5px;
+  max-width: 100%;
+}
+
+#responseImageNodeDiv {
+  padding: 5px;
+}
+
+#responseBodyFetchLink, #requestBodyFetchLink {
+  padding: 5px;
+  margin: 0;
+  cursor: pointer;
+  font-weight: bold;
+  font-size: 1.1em;
+  text-decoration: underline;
+}
+
+.longStringEllipsis {
+  margin-left: 0.6em;
+}
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -452,16 +452,17 @@ browser.jar:
         skin/classic/browser/devtools/command-rulers@2x.png         (../shared/devtools/images/command-rulers@2x.png)
         skin/classic/browser/devtools/markup-view.css               (../shared/devtools/markup-view.css)
         skin/classic/browser/devtools/editor-error.png              (../shared/devtools/images/editor-error.png)
         skin/classic/browser/devtools/editor-breakpoint.png         (../shared/devtools/images/editor-breakpoint.png)
         skin/classic/browser/devtools/editor-breakpoint@2x.png         (../shared/devtools/images/editor-breakpoint@2x.png)
         skin/classic/browser/devtools/editor-debug-location.png     (../shared/devtools/images/editor-debug-location.png)
         skin/classic/browser/devtools/editor-debug-location@2x.png     (../shared/devtools/images/editor-debug-location@2x.png)
 *       skin/classic/browser/devtools/webconsole.css                (../shared/devtools/webconsole.css)
+        skin/classic/browser/devtools/webconsole_networkpanel.css   (../shared/devtools/webconsole_networkpanel.css)
         skin/classic/browser/devtools/webconsole.svg                (../shared/devtools/images/webconsole.svg)
         skin/classic/browser/devtools/breadcrumbs-divider@2x.png    (../shared/devtools/images/breadcrumbs-divider@2x.png)
         skin/classic/browser/devtools/breadcrumbs-scrollbutton.png  (../shared/devtools/images/breadcrumbs-scrollbutton.png)
         skin/classic/browser/devtools/breadcrumbs-scrollbutton@2x.png (../shared/devtools/images/breadcrumbs-scrollbutton@2x.png)
         skin/classic/browser/devtools/animationinspector.css        (../shared/devtools/animationinspector.css)
         skin/classic/browser/devtools/eyedropper.css                (../shared/devtools/eyedropper.css)
 *       skin/classic/browser/devtools/canvasdebugger.css            (../shared/devtools/canvasdebugger.css)
         skin/classic/browser/devtools/debugger.css                  (../shared/devtools/debugger.css)
--- a/build/clang-plugin/clang-plugin.cpp
+++ b/build/clang-plugin/clang-plugin.cpp
@@ -275,16 +275,18 @@ static CustomTypeAnnotation StackClass =
 static CustomTypeAnnotation GlobalClass =
     CustomTypeAnnotation("moz_global_class", "global");
 static CustomTypeAnnotation NonHeapClass =
     CustomTypeAnnotation("moz_nonheap_class", "non-heap");
 static CustomTypeAnnotation HeapClass =
     CustomTypeAnnotation("moz_heap_class", "heap");
 static CustomTypeAnnotation MustUse =
     CustomTypeAnnotation("moz_must_use", "must-use");
+static CustomTypeAnnotation NonMemMovable =
+  CustomTypeAnnotation("moz_non_memmovable", "non-memmove()able");
 
 class MozChecker : public ASTConsumer, public RecursiveASTVisitor<MozChecker> {
   DiagnosticsEngine &Diag;
   const CompilerInstance &CI;
   DiagnosticsMatcher matcher;
 
 public:
   MozChecker(const CompilerInstance &CI) : Diag(CI.getDiagnostics()), CI(CI) {}
@@ -469,102 +471,16 @@ bool isClassRefCounted(const CXXRecordDe
 
 bool isClassRefCounted(QualType T) {
   while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
     T = arrTy->getElementType();
   CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
   return clazz ? isClassRefCounted(clazz) : false;
 }
 
-/// A cached data of whether classes are memmovable, and if not, what
-/// declaration
-/// makes them non-movable
-typedef DenseMap<const CXXRecordDecl *, const CXXRecordDecl *>
-    InferredMovability;
-InferredMovability inferredMovability;
-
-bool isClassNonMemMovable(QualType T);
-const CXXRecordDecl *isClassNonMemMovableWorker(QualType T);
-
-const CXXRecordDecl *isClassNonMemMovableWorker(const CXXRecordDecl *D) {
-  // If we have a definition, then we want to standardize our reference to point
-  // to the definition node. If we don't have a definition, that means that
-  // either
-  // we only have a forward declaration of the type in our file, or we are being
-  // passed a template argument which is not used, and thus never instantiated
-  // by
-  // clang.
-  // As the argument isn't used, we can't memmove it (as we don't know it's
-  // size),
-  // which means not reporting an error is OK.
-  if (!D->hasDefinition()) {
-    return 0;
-  }
-  D = D->getDefinition();
-
-  // Are we explicitly marked as non-memmovable class?
-  if (MozChecker::hasCustomAnnotation(D, "moz_non_memmovable")) {
-    return D;
-  }
-
-  // Look through all base cases to figure out if the parent is a non-memmovable
-  // class.
-  for (CXXRecordDecl::base_class_const_iterator base = D->bases_begin();
-       base != D->bases_end(); ++base) {
-    const CXXRecordDecl *result = isClassNonMemMovableWorker(base->getType());
-    if (result) {
-      return result;
-    }
-  }
-
-  // Look through all members to figure out if a member is a non-memmovable
-  // class.
-  for (RecordDecl::field_iterator field = D->field_begin(), e = D->field_end();
-       field != e; ++field) {
-    const CXXRecordDecl *result = isClassNonMemMovableWorker(field->getType());
-    if (result) {
-      return result;
-    }
-  }
-
-  return 0;
-}
-
-const CXXRecordDecl *isClassNonMemMovableWorker(QualType T) {
-  while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
-    T = arrTy->getElementType();
-  const CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
-  return clazz ? isClassNonMemMovableWorker(clazz) : 0;
-}
-
-bool isClassNonMemMovable(const CXXRecordDecl *D) {
-  InferredMovability::iterator it = inferredMovability.find(D);
-  if (it != inferredMovability.end())
-    return !!it->second;
-  const CXXRecordDecl *result = isClassNonMemMovableWorker(D);
-  inferredMovability.insert(std::make_pair(D, result));
-  return !!result;
-}
-
-bool isClassNonMemMovable(QualType T) {
-  while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
-    T = arrTy->getElementType();
-  const CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
-  return clazz ? isClassNonMemMovable(clazz) : false;
-}
-
-const CXXRecordDecl *findWhyClassIsNonMemMovable(QualType T) {
-  while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
-    T = arrTy->getElementType();
-  CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
-  InferredMovability::iterator it = inferredMovability.find(clazz);
-  assert(it != inferredMovability.end());
-  return it->second;
-}
-
 template <class T> bool IsInSystemHeader(const ASTContext &AC, const T &D) {
   auto &SourceManager = AC.getSourceManager();
   auto ExpansionLoc = SourceManager.getExpansionLoc(D.getLocStart());
   if (ExpansionLoc.isInvalid()) {
     return false;
   }
   return SourceManager.isInSystemHeader(ExpansionLoc);
 }
@@ -714,17 +630,19 @@ AST_MATCHER(CXXRecordDecl, hasRefCntMemb
 
 AST_MATCHER(QualType, hasVTable) { return typeHasVTable(Node); }
 
 AST_MATCHER(CXXRecordDecl, hasNeedsNoVTableTypeAttr) {
   return MozChecker::hasCustomAnnotation(&Node, "moz_needs_no_vtable_type");
 }
 
 /// This matcher will select classes which are non-memmovable
-AST_MATCHER(QualType, isNonMemMovable) { return isClassNonMemMovable(Node); }
+AST_MATCHER(QualType, isNonMemMovable) {
+  return NonMemMovable.hasEffectiveAnnotation(Node);
+}
 
 /// This matcher will select classes which require a memmovable template arg
 AST_MATCHER(CXXRecordDecl, needsMemMovable) {
   return MozChecker::hasCustomAnnotation(&Node, "moz_needs_memmovable_type");
 }
 
 AST_MATCHER(CXXConstructorDecl, isInterestingImplicitCtor) {
   const CXXConstructorDecl *decl = Node.getCanonicalDecl();
@@ -798,16 +716,17 @@ void CustomTypeAnnotation::dumpAnnotatio
     case RK_TemplateInherited: {
       const CXXRecordDecl *Decl = T->getAsCXXRecordDecl();
       assert(Decl && "This type should be a C++ class");
 
       Diag.Report(Decl->getLocation(), TemplID) << Pretty << T << Reason.Type;
       break;
     }
     default:
+      // FIXME (bug 1203263): note the original annotation.
       return;
     }
 
     T = Reason.Type;
     Reason = directAnnotationReason(T);
   }
 }
 
@@ -1318,49 +1237,43 @@ void DiagnosticsMatcher::NeedsNoVTableTy
 void DiagnosticsMatcher::NonMemMovableChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
   unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Error,
       "Cannot instantiate %0 with non-memmovable template argument %1");
   unsigned note1ID = Diag.getDiagnosticIDs()->getCustomDiagID(
       DiagnosticIDs::Note, "instantiation of %0 requested here");
-  unsigned note2ID = Diag.getDiagnosticIDs()->getCustomDiagID(
-      DiagnosticIDs::Note, "%0 is non-memmovable because of the "
-                           "MOZ_NON_MEMMOVABLE annotation on %1");
-  unsigned note3ID =
-      Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Note, "%0");
 
   // Get the specialization
   const ClassTemplateSpecializationDecl *specialization =
       Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("specialization");
   SourceLocation requestLoc = specialization->getPointOfInstantiation();
   const CXXRecordDecl *templ =
       specialization->getSpecializedTemplate()->getTemplatedDecl();
 
   // Report an error for every template argument which is non-memmovable
   const TemplateArgumentList &args =
       specialization->getTemplateInstantiationArgs();
   for (unsigned i = 0; i < args.size(); ++i) {
     QualType argType = args[i].getAsType();
-    if (isClassNonMemMovable(args[i].getAsType())) {
-      const CXXRecordDecl *reason = findWhyClassIsNonMemMovable(argType);
+    if (NonMemMovable.hasEffectiveAnnotation(args[i].getAsType())) {
       Diag.Report(specialization->getLocation(), errorID) << specialization
                                                           << argType;
       // XXX It would be really nice if we could get the instantiation stack
       // information
       // from Sema such that we could print a full template instantiation stack,
       // however,
       // it seems as though that information is thrown out by the time we get
       // here so we
       // can only report one level of template specialization (which in many
       // cases won't
       // be useful)
       Diag.Report(requestLoc, note1ID) << specialization;
-      Diag.Report(reason->getLocation(), note2ID) << argType << reason;
+      NonMemMovable.dumpAnnotationReason(Diag, argType, requestLoc);
     }
   }
 }
 
 void DiagnosticsMatcher::ExplicitImplicitChecker::run(
     const MatchFinder::MatchResult &Result) {
   DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
   unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
--- a/build/clang-plugin/tests/TestInheritTypeAnnotationsFromTemplateArgs.cpp
+++ b/build/clang-plugin/tests/TestInheritTypeAnnotationsFromTemplateArgs.cpp
@@ -1,17 +1,37 @@
 #define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS                 \
   __attribute__((annotate("moz_inherit_type_annotations_from_template_args")))
 #define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class")))
+#define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable")))
+#define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type")))
 
 class Normal {};
 class MOZ_STACK_CLASS Stack {};
 class IndirectStack : Stack {}; // expected-note {{'IndirectStack' is a stack type because it inherits from a stack type 'Stack'}}
+class ContainsStack { Stack m; }; // expected-note {{'ContainsStack' is a stack type because member 'm' is a stack type 'Stack'}}
+class MOZ_NON_MEMMOVABLE Pointery {};
+class IndirectPointery : Pointery {}; // expected-note {{'IndirectPointery' is a non-memmove()able type because it inherits from a non-memmove()able type 'Pointery'}}
+class ContainsPointery { Pointery m; }; // expected-note {{'ContainsPointery' is a non-memmove()able type because member 'm' is a non-memmove()able type 'Pointery'}}
 
 template<class T>
-class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Template {}; // expected-note 2 {{'Template<Stack>' is a stack type because it has a template argument stack type 'Stack'}} expected-note {{'Template<IndirectStack>' is a stack type because it has a template argument stack type 'IndirectStack'}}
+class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Template {}; // expected-note-re 5 {{'Template<{{.*}}>' is a stack type because it has a template argument stack type '{{.*}}'}} expected-note-re 5 {{'Template<{{.*}}>' is a non-memmove()able type because it has a template argument non-memmove()able type '{{.*}}'}}
 class IndirectTemplate : Template<Stack> {}; // expected-note {{'IndirectTemplate' is a stack type because it inherits from a stack type 'Template<Stack>'}}
+class ContainsTemplate { Template<Stack> m; }; // expected-note {{'ContainsTemplate' is a stack type because member 'm' is a stack type 'Template<Stack>'}}
 
 static Template<Stack> a; // expected-error {{variable of type 'Template<Stack>' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
 static Template<IndirectStack> b; // expected-error {{variable of type 'Template<IndirectStack>' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
-static Template<Normal> c;
+static Template<ContainsStack> c; // expected-error {{variable of type 'Template<ContainsStack>' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
 static IndirectTemplate d; // expected-error {{variable of type 'IndirectTemplate' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
+static ContainsTemplate e; // expected-error {{variable of type 'ContainsTemplate' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
+static Template<Normal> f;
 
+template<class T>
+class MOZ_NEEDS_MEMMOVABLE_TYPE Mover { char mForceInstantiation[sizeof(T)]; }; // expected-error-re 5 {{Cannot instantiate 'Mover<{{.*}}>' with non-memmovable template argument '{{.*}}'}}
+class IndirectTemplatePointery : Template<Pointery> {}; // expected-note {{'IndirectTemplatePointery' is a non-memmove()able type because it inherits from a non-memmove()able type 'Template<Pointery>'}}
+class ContainsTemplatePointery { Template<Pointery> m; }; // expected-note {{'ContainsTemplatePointery' is a non-memmove()able type because member 'm' is a non-memmove()able type 'Template<Pointery>'}}
+
+static Mover<Template<Pointery>> n; // expected-note {{instantiation of 'Mover<Template<Pointery> >' requested here}}
+static Mover<Template<IndirectPointery>> o; // expected-note {{instantiation of 'Mover<Template<IndirectPointery> >' requested here}}
+static Mover<Template<ContainsPointery>> p; // expected-note {{instantiation of 'Mover<Template<ContainsPointery> >' requested here}}
+static Mover<IndirectTemplatePointery> q; // expected-note {{instantiation of 'Mover<IndirectTemplatePointery>' requested here}}
+static Mover<ContainsTemplatePointery> r; // expected-note {{instantiation of 'Mover<ContainsTemplatePointery>' requested here}}
+static Mover<Template<Normal>> s;
--- a/build/clang-plugin/tests/TestNonMemMovable.cpp
+++ b/build/clang-plugin/tests/TestNonMemMovable.cpp
@@ -1,61 +1,61 @@
 #define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable")))
 #define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type")))
 
 /*
   These are a bunch of structs with variable levels of memmovability.
   They will be used as template parameters to the various NeedyTemplates
 */
-struct MOZ_NON_MEMMOVABLE NonMovable {}; // expected-note-re + {{'{{.*}}' is non-memmovable because of the MOZ_NON_MEMMOVABLE annotation on 'NonMovable'}}
+struct MOZ_NON_MEMMOVABLE NonMovable {};
 struct Movable {};
 
 // Subclasses
-struct S_NonMovable : NonMovable {};
+struct S_NonMovable : NonMovable {}; // expected-note 48 {{'S_NonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'NonMovable'}}
 struct S_Movable : Movable {};
 
 // Members
 struct W_NonMovable {
-  NonMovable m;
+  NonMovable m; // expected-note 32 {{'W_NonMovable' is a non-memmove()able type because member 'm' is a non-memmove()able type 'NonMovable'}}
 };
 struct W_Movable {
   Movable m;
 };
 
 // Wrapped Subclasses
 struct WS_NonMovable {
-  S_NonMovable m;
+  S_NonMovable m; // expected-note 32 {{'WS_NonMovable' is a non-memmove()able type because member 'm' is a non-memmove()able type 'S_NonMovable'}}
 };
 struct WS_Movable {
   S_Movable m;
 };
 
 // Combinations of the above
-struct SW_NonMovable : W_NonMovable {};
+struct SW_NonMovable : W_NonMovable {}; // expected-note 16 {{'SW_NonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'W_NonMovable'}}
 struct SW_Movable : W_Movable {};
 
-struct SWS_NonMovable : WS_NonMovable {};
+struct SWS_NonMovable : WS_NonMovable {}; // expected-note 16 {{'SWS_NonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'WS_NonMovable'}}
 struct SWS_Movable : WS_Movable {};
 
 // Basic templated wrapper
 template <class T>
 struct Template_Inline {
-  T m;
+  T m; // expected-note-re 56 {{'Template_Inline<{{.*}}>' is a non-memmove()able type because member 'm' is a non-memmove()able type '{{.*}}'}}
 };
 
 template <class T>
 struct Template_Ref {
   T* m;
 };
 
 template <class T>
 struct Template_Unused {};
 
 template <class T>
-struct MOZ_NON_MEMMOVABLE Template_NonMovable {}; // expected-note-re + {{'{{.*}}' is non-memmovable because of the MOZ_NON_MEMMOVABLE annotation on 'Template_NonMovable<{{.*}}>'}}
+struct MOZ_NON_MEMMOVABLE Template_NonMovable {};
 
 /*
   These tests take the following form:
   DECLARATIONS => Declarations of the templates which are either marked with MOZ_NEEDS_MEMMOVABLE_TYPE
                   or which instantiate a MOZ_NEEDS_MEMMOVABLE_TYPE through some mechanism.
   BAD N        => Instantiations of the wrapper template with each of the non-memmovable types.
                   The prefix S_ means subclass, W_ means wrapped. Each of these rows should produce an error
                   on the NeedyTemplate in question, and a note at the instantiation location of that template.
@@ -494,17 +494,17 @@ template <class T>
 struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate6 {T m;}; // expected-error-re 27 {{Cannot instantiate 'NeedyTemplate6<{{.*}}>' with non-memmovable template argument '{{.*}}'}}
 template <class T>
 struct W_NeedyTemplate6 {
   NeedyTemplate6<T> m; // expected-note-re 27 {{instantiation of 'NeedyTemplate6<{{.*}}>' requested here}}
 };
 template <class T>
 struct SW_NeedyTemplate6 : W_NeedyTemplate6<T> {};
 // We create a different NonMovable type here, as NeedyTemplate6 will already be instantiated with NonMovable
-struct MOZ_NON_MEMMOVABLE NonMovable2 {}; // expected-note {{'NonMovable2' is non-memmovable because of the MOZ_NON_MEMMOVABLE annotation on 'NonMovable2'}}
+struct MOZ_NON_MEMMOVABLE NonMovable2 {};
 template <class T = NonMovable2>
 struct Defaulted_SW_NeedyTemplate6 {
   SW_NeedyTemplate6<T> m;
 };
 void bad6() {
   Defaulted_SW_NeedyTemplate6<NonMovable> a1;
   Defaulted_SW_NeedyTemplate6<S_NonMovable> a2;
   Defaulted_SW_NeedyTemplate6<W_NonMovable> a3;
@@ -743,18 +743,18 @@ void good8() {
   SpecializedNonMovable is a non-movable class which has an explicit specialization of NeedyTemplate
   for it. Instantiations of NeedyTemplateN<SpecializedNonMovable> should be legal as the explicit
   specialization isn't annotated with MOZ_NEEDS_MEMMOVABLE_TYPE.
 
   However, as it is MOZ_NON_MEMMOVABLE, derived classes and members shouldn't be able to be used to
   instantiate NeedyTemplate.
 */
 
-struct MOZ_NON_MEMMOVABLE SpecializedNonMovable {}; // expected-note 8 {{'S_SpecializedNonMovable' is non-memmovable because of the MOZ_NON_MEMMOVABLE annotation on 'SpecializedNonMovable'}} expected-note 8 {{'Template_Inline<SpecializedNonMovable>' is non-memmovable because of the MOZ_NON_MEMMOVABLE annotation on 'SpecializedNonMovable'}}
-struct S_SpecializedNonMovable : SpecializedNonMovable {};
+struct MOZ_NON_MEMMOVABLE SpecializedNonMovable {};
+struct S_SpecializedNonMovable : SpecializedNonMovable {}; // expected-note 8 {{'S_SpecializedNonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'SpecializedNonMovable'}}
 
 // Specialize all of the NeedyTemplates with SpecializedNonMovable.
 template <>
 struct NeedyTemplate1<SpecializedNonMovable> {};
 template <>
 struct NeedyTemplate2<SpecializedNonMovable> {};
 template <>
 struct NeedyTemplate3<SpecializedNonMovable> {};
--- a/build/gecko_templates.mozbuild
+++ b/build/gecko_templates.mozbuild
@@ -20,17 +20,17 @@ def GeckoBinary(linkage='dependent', msv
     `msvcrt` indicates which Microsoft Visual Studio CRT, for Windows build,
     ought to be linked: 'static' or 'dynamic'.
 
     `mozglue` indicates whether to link against the mozglue library, and if
     so, what linkage to apply. Valid values are None (mozglue not linked),
     'program' (mozglue linked to an executable program), or 'library' (mozglue
     linked to a shared library).
     '''
-    if msvcrt == 'dynamic' or CONFIG['OS_ARCH'] != 'WINNT':
+    if msvcrt == 'dynamic' or CONFIG['OS_ARCH'] != 'WINNT' or CONFIG['MOZ_ASAN']:
         xpcomglue = 'xpcomglue'
     elif msvcrt == 'static':
         USE_STATIC_LIBS = True
         xpcomglue = 'xpcomglue_staticruntime'
         if not CONFIG['GNU_CC']:
             mozglue = None
             if linkage == 'dependent':
                 USE_LIBS += [
--- a/build/macosx/cross-mozconfig.common
+++ b/build/macosx/cross-mozconfig.common
@@ -1,15 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MOZ_AUTOMATION_L10N_CHECK=0
-#TODO: bug 935237 - fix packaging
-MOZ_AUTOMATION_PACKAGE=0
 #TODO: bug 543111 - fix Breakpad
 MOZ_AUTOMATION_BUILD_SYMBOLS=0
 MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
 
 if [ "x$IS_NIGHTLY" = "xyes" ]; then
   # Some nightlies (eg: Mulet) don't want these set.
   MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
   MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
@@ -32,19 +30,23 @@ export CPP="$topsrcdir/clang/bin/clang $
 export LLVMCONFIG=$topsrcdir/clang/bin/llvm-config
 export LDFLAGS="-Wl,-syslibroot,$CROSS_SYSROOT -Wl,-dead_strip"
 export TOOLCHAIN_PREFIX=$CROSS_CCTOOLS_PATH/bin/x86_64-apple-darwin10-
 #TODO: bug 1184202 - would be nice if these could be detected with TOOLCHAIN_PREFIX automatically
 export AR=${TOOLCHAIN_PREFIX}ar
 export RANLIB=${TOOLCHAIN_PREFIX}ranlib
 export STRIP=${TOOLCHAIN_PREFIX}strip
 export OTOOL=${TOOLCHAIN_PREFIX}otool
+export GENISOIMAGE=$topsrcdir/genisoimage/genisoimage
+export DMG_TOOL=$topsrcdir/dmg/dmg
 
-export HOST_CC=gcc
-export HOST_CXX=g++
+# The system gcc installed on CentOS 6 is 4.4, which our
+# build system rejects.
+export HOST_CC="$topsrcdir/gcc/bin/gcc"
+export HOST_CXX="$topsrcdir/gcc/bin/g++"
 export HOST_LDFLAGS="-g"
 
 ac_add_options --target=x86_64-apple-darwin
 ac_add_options --with-macos-private-frameworks=$CROSS_PRIVATE_FRAMEWORKS
 
 . "$topsrcdir/build/mozconfig.cache"
 
 export SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE=/builds/crash-stats-api.token
--- a/build/macosx/mozconfig.rust
+++ b/build/macosx/mozconfig.rust
@@ -1,5 +1,7 @@
 # Options to enable rust in automation builds.
 
+if test `uname -s` != Linux; then
 RUSTC="$topsrcdir/rustc/bin/rustc"
 mk_add_options "export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$topsrcdir/rustc/lib"
 ac_add_options --enable-rust
+fi
--- a/build/unix/build-clang/build-clang.py
+++ b/build/unix/build-clang/build-clang.py
@@ -6,16 +6,18 @@
 import os
 import os.path
 import shutil
 import subprocess
 import platform
 import json
 import argparse
 
+centOS6 = False
+
 
 def check_run(args):
     r = subprocess.call(args)
     assert r == 0
 
 
 def run_in(path, args):
     d = os.getcwd()
@@ -89,21 +91,27 @@ def build_one_stage_aux(stage_dir, llvm_
     targets = ["x86", "x86_64"]
     # The Darwin equivalents of binutils appear to have intermittent problems
     # with objects in compiler-rt that are compiled for arm.  Since the arm
     # support is only necessary for iOS (which we don't support), only enable
     # arm support on Linux.
     if not is_darwin():
         targets.append("arm")
 
+    global centOS6
+    if centOS6:
+        python_path = "/usr/bin/python2.7"
+    else:
+        python_path = "/usr/local/bin/python2.7"
+
     configure_opts = ["--enable-optimized",
                       "--enable-targets=" + ",".join(targets),
                       "--disable-assertions",
                       "--disable-libedit",
-                      "--with-python=/usr/local/bin/python2.7",
+                      "--with-python=%s" % python_path,
                       "--prefix=%s" % inst_dir,
                       "--with-gcc-toolchain=%s" % gcc_toolchain_dir,
                       "--disable-compiler-version-checks"]
     build_package(llvm_source_dir, build_dir, configure_opts, [])
 
 if __name__ == "__main__":
     # The directories end up in the debug info, so the easy way of getting
     # a reproducible build is to run it in a know absolute directory.
@@ -114,17 +122,21 @@ if __name__ == "__main__":
     source_dir = base_dir + "/src"
     build_dir = base_dir + "/build"
 
     llvm_source_dir = source_dir + "/llvm"
     clang_source_dir = source_dir + "/clang"
     compiler_rt_source_dir = source_dir + "/compiler-rt"
     libcxx_source_dir = source_dir + "/libcxx"
 
-    gcc_dir = "/tools/gcc-4.7.3-0moz1"
+    global centOS6
+    if centOS6:
+        gcc_dir = "/home/worker/workspace/build/src/gcc"
+    else:
+        gcc_dir = "/tools/gcc-4.7.3-0moz1"
 
     if is_darwin():
         os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.7'
 
     parser = argparse.ArgumentParser()
     parser.add_argument('-c', '--config', required=True,
                         type=argparse.FileType('r'),
                         help="Clang configuration file")
--- a/build/unix/elfhack/Makefile.in
+++ b/build/unix/elfhack/Makefile.in
@@ -1,15 +1,13 @@
 #
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-INTERNAL_TOOLS = 1
-
 OS_CXXFLAGS := $(filter-out -fno-exceptions,$(OS_CXXFLAGS)) -fexceptions
 
 include $(topsrcdir)/config/rules.mk
 
 test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX): %$(DLL_SUFFIX): %.$(OBJ_SUFFIX) elfhack
 	$(MKSHLIB) $(LDFLAGS) $< -nostartfiles
 	@echo ===
 	@echo === If you get failures below, please file a bug describing the error
--- a/build/unix/elfhack/inject/Makefile.in
+++ b/build/unix/elfhack/inject/Makefile.in
@@ -1,15 +1,13 @@
 #
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-INTERNAL_TOOLS = 1
-
 include $(topsrcdir)/config/rules.mk
 
 export:: $(CSRCS:.c=.$(OBJ_SUFFIX))
 
 $(CSRCS): %.c: ../inject.c
 	cp $< $@
 
 GARBAGE += $(CSRCS)
--- a/config/config.mk
+++ b/config/config.mk
@@ -237,21 +237,16 @@ endif # MOZ_DEBUG
 
 endif # WINNT && !GNU_CC
 
 #
 # Build using PIC by default
 #
 _ENABLE_PIC=1
 
-# No sense in profiling tools
-ifdef INTERNAL_TOOLS
-NO_PROFILE_GUIDED_OPTIMIZE = 1
-endif
-
 # Don't build SIMPLE_PROGRAMS with PGO, since they don't need it anyway,
 # and we don't have the same build logic to re-link them in the second pass.
 ifdef SIMPLE_PROGRAMS
 NO_PROFILE_GUIDED_OPTIMIZE = 1
 endif
 
 # No sense in profiling unit tests
 ifdef CPP_UNIT_TESTS
@@ -381,16 +376,22 @@ CXXFLAGS += $(WARNINGS_AS_ERRORS)
 CFLAGS   += $(WARNINGS_AS_ERRORS)
 endif # ALLOW_COMPILER_WARNINGS
 
 ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_)
 #// Currently, unless USE_STATIC_LIBS is defined, the multithreaded
 #// DLL version of the RTL is used...
 #//
 #//------------------------------------------------------------------------
+ifdef MOZ_ASAN
+# ASAN-instrumented code tries to link against the dynamic CRT, which can't be
+# used in the same link as the static CRT.
+USE_STATIC_LIBS=
+endif # MOZ_ASAN
+
 ifdef USE_STATIC_LIBS
 RTL_FLAGS=-MT          # Statically linked multithreaded RTL
 ifdef MOZ_DEBUG
 ifndef MOZ_NO_DEBUG_RTL
 RTL_FLAGS=-MTd         # Statically linked multithreaded MSVC4.0 debug RTL
 endif
 endif # MOZ_DEBUG
 
--- a/configure.in
+++ b/configure.in
@@ -845,16 +845,18 @@ fi
 MOZ_PATH_PROG(XARGS, xargs)
 if test -z "$XARGS" -o "$XARGS" = ":"; then
     AC_MSG_ERROR([xargs not found in \$PATH .])
 fi
 
 MOZ_PATH_PROG(RPMBUILD, rpmbuild, :)
 AC_SUBST(RPMBUILD)
 
+MOZ_PATH_PROG(GENISOIMAGE, genisoimage, :)
+
 if test "$COMPILE_ENVIRONMENT"; then
 
 dnl ========================================================
 dnl = Mac OS X toolchain support
 dnl ========================================================
 
 dnl The universal machinery sets UNIVERSAL_BINARY to inform packager.mk
 dnl that a universal binary is being produced and MOZ_CAN_RUN_PROGRAMS
@@ -8775,16 +8777,17 @@ AC_SUBST(FIREFOX_VERSION)
 AC_SUBST(MOZ_UA_OS_AGNOSTIC)
 if test -n "$MOZ_UA_OS_AGNOSTIC"; then
   AC_DEFINE(MOZ_UA_OS_AGNOSTIC)
 fi
 
 AC_SUBST(MOZ_APP_STATIC_INI)
 
 AC_SUBST(MOZ_PKG_SPECIAL)
+AC_SUBST(MOZ_SIMPLE_PACKAGE_NAME)
 
 AC_SUBST(MOZILLA_OFFICIAL)
 
 # Build revisions should always be present in official builds
 if test "$MOZILLA_OFFICIAL"; then
     MOZ_INCLUDE_SOURCE_INFO=1
 fi
 
@@ -8980,16 +8983,18 @@ AC_SUBST_LIST(LIBAV_FFT_ASFLAGS)
 AC_SUBST(MOZ_PACKAGE_JSSHELL)
 AC_SUBST(MOZ_FOLD_LIBS)
 AC_SUBST(MOZ_FOLD_LIBS_FLAGS)
 AC_SUBST(SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE)
 
 AC_SUBST(MOZ_ENABLE_SZIP)
 AC_SUBST(MOZ_SZIP_FLAGS)
 
+AC_SUBST(DMG_TOOL)
+
 dnl Host JavaScript runtime, if any, to use during cross compiles.
 AC_SUBST(JS_BINARY)
 
 if test "$MOZ_DEBUG"; then
     MOZ_EM_DEBUG=1
 fi
 AC_SUBST(MOZ_EM_DEBUG)
 
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -4974,16 +4974,17 @@ nsDocShell::DisplayLoadError(nsresult aE
         break;
       case NS_ERROR_INTERCEPTION_FAILED:
       case NS_ERROR_OPAQUE_INTERCEPTION_DISABLED:
       case NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE:
       case NS_ERROR_INTERCEPTED_ERROR_RESPONSE:
       case NS_ERROR_INTERCEPTED_USED_RESPONSE:
       case NS_ERROR_CLIENT_REQUEST_OPAQUE_INTERCEPTION:
       case NS_ERROR_BAD_OPAQUE_REDIRECT_INTERCEPTION:
+      case NS_ERROR_INTERCEPTION_CANCELED:
         // ServiceWorker intercepted request, but something went wrong.
         nsContentUtils::MaybeReportInterceptionErrorToConsole(GetDocument(),
                                                               aError);
         error.AssignLiteral("corruptedContentError");
         break;
       default:
         break;
     }
@@ -7626,16 +7627,17 @@ nsDocShell::EndPageLoad(nsIWebProgress* 
                aStatus == NS_ERROR_REMOTE_XUL ||
                aStatus == NS_ERROR_OFFLINE ||
                aStatus == NS_ERROR_INTERCEPTION_FAILED ||
                aStatus == NS_ERROR_OPAQUE_INTERCEPTION_DISABLED ||
                aStatus == NS_ERROR_BAD_OPAQUE_INTERCEPTION_REQUEST_MODE ||
                aStatus == NS_ERROR_INTERCEPTED_ERROR_RESPONSE ||
                aStatus == NS_ERROR_INTERCEPTED_USED_RESPONSE ||
                aStatus == NS_ERROR_CLIENT_REQUEST_OPAQUE_INTERCEPTION ||
+               aStatus == NS_ERROR_INTERCEPTION_CANCELED ||
                NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) {
       // Errors to be shown for any frame
       DisplayLoadError(aStatus, url, nullptr, aChannel);
     } else if (aStatus == NS_ERROR_DOCUMENT_NOT_CACHED) {
       // Non-caching channels will simply return NS_ERROR_OFFLINE.
       // Caching channels would have to look at their flags to work
       // out which error to return. Or we can fix up the error here.
       if (!(mLoadType & LOAD_CMD_HISTORY)) {
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -163,23 +163,30 @@ struct AnimationProperty
   // cascade and for OMTA.
   //
   // For CSS Animations, which are overridden by !important rules in the
   // cascade, we actually determine this from the CSS cascade
   // computations, and then use it for OMTA.
   // **NOTE**: For CSS animations, we only bother setting mWinsInCascade
   // accurately for properties that we can animate on the compositor.
   // For other properties, we make it always be true.
+  // **NOTE 2**: This member is not included when comparing AnimationProperty
+  // objects for equality.
   bool mWinsInCascade;
 
   InfallibleTArray<AnimationPropertySegment> mSegments;
 
+  // NOTE: This operator does *not* compare the mWinsInCascade member.
+  // This is because AnimationProperty objects are compared when recreating
+  // CSS animations to determine if mutation observer change records need to
+  // be created or not. However, at the point when these objects are compared
+  // the mWinsInCascade will not have been set on the new objects so we ignore
+  // this member to avoid generating spurious change records.
   bool operator==(const AnimationProperty& aOther) const {
     return mProperty == aOther.mProperty &&
-           mWinsInCascade == aOther.mWinsInCascade &&
            mSegments == aOther.mSegments;
   }
   bool operator!=(const AnimationProperty& aOther) const {
     return !(*this == aOther);
   }
 };
 
 struct ElementPropertyTransition;
--- a/dom/animation/test/chrome/test_animation_observers.html
+++ b/dom/animation/test/chrome/test_animation_observers.html
@@ -732,16 +732,82 @@ function assert_records(expected, desc) 
     // And we should get no notifications.
     yield await_frame();
     assert_records([], "records after attempted animation start");
 
     e.style = "";
   });
 });
 
+addAsyncAnimTest("tree_ordering", { observe: div, subtree: true }, function*() {
+
+  // Create a tree with two children:
+  //
+  //         div
+  //        /  \
+  //   childA  childB
+  var childA = document.createElement("div");
+  var childB = document.createElement("div");
+
+  div.appendChild(childA);
+  div.appendChild(childB);
+
+  // Start an animation on each (using order: childB, div, childA)
+  //
+  // We include multiple animations on some nodes so that we can test batching
+  // works as expected later in this test.
+  childB.style = "animation: anim 100s";
+  div.style    = "animation: anim 100s, anim 100s, anim 100s";
+  childA.style = "animation: anim 100s, anim 100s";
+
+  var divAnimations = div.getAnimations();
+  var childAAnimations = childA.getAnimations();
+  var childBAnimations = childB.getAnimations();
+
+  // The order in which we get the corresponding records is currently
+  // based on the order we visit these nodes when updating styles.
+  //
+  // That is because we don't do any document-level batching of animation
+  // mutation records when we flush styles. We may introduce that in the
+  // future but for now all we are interested in testing here is that the order
+  // these records are dispatched is consistent between runs.
+  //
+  // We currently expect to get records in order childA, childB, div
+  yield await_frame();
+  assert_records([{ added: childAAnimations, changed: [], removed: [] },
+                  { added: childBAnimations, changed: [], removed: [] },
+                  { added: divAnimations, changed: [], removed: [] }],
+                 "records after simultaneous animation start");
+
+  // The one case where we *do* currently perform document-level (or actually
+  // timeline-level) batching is when animations are updated from a refresh
+  // driver tick. In particular, this means that when animations finish
+  // naturally the removed records should be dispatched according to the
+  // position of the elements in the tree.
+  //
+  // Fast-forward to *just* before the end of the animation.
+  var fastForward = animation => animation.currentTime = 99999;
+  divAnimations.forEach(fastForward);
+  childAAnimations.forEach(fastForward);
+  childBAnimations.forEach(fastForward);
+
+  yield await_event(div, "animationend");
+
+  // We should get records in order div, childA, childB
+  assert_records([{ added: [], changed: [], removed: divAnimations },
+                  { added: [], changed: [], removed: childAAnimations },
+                  { added: [], changed: [], removed: childBAnimations }],
+                 "records after finishing");
+
+  // Clean up
+  div.style = "";
+  childA.remove();
+  childB.remove();
+});
+
 // Run the tests.
 
 SimpleTest.waitForExplicitFinish();
 
 runAllAsyncTests().then(function() {
   SimpleTest.finish();
 }, function(aError) {
   ok(false, "Something failed: " + aError);
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -811,17 +811,17 @@ nsIContent::PreHandleEvent(EventChainPre
       case eFormSelect:
       case eFormChange:
       case eLoad:
       case eFormReset:
       case eResize:
       case eScroll:
         stopEvent = true;
         break;
-      case NS_USER_DEFINED_EVENT:
+      case eUnidentifiedEvent:
         if (aVisitor.mDOMEvent) {
           nsAutoString eventType;
           aVisitor.mDOMEvent->GetType(eventType);
           if (eventType.EqualsLiteral("abort") ||
               eventType.EqualsLiteral("error") ||
               eventType.EqualsLiteral("select") ||
               eventType.EqualsLiteral("change") ||
               eventType.EqualsLiteral("load") ||
--- a/dom/base/TextInputProcessor.cpp
+++ b/dom/base/TextInputProcessor.cpp
@@ -247,17 +247,17 @@ TextInputProcessor::IsValidStateForCompo
 bool
 TextInputProcessor::IsValidEventTypeForComposition(
                       const WidgetKeyboardEvent& aKeyboardEvent) const
 {
   // The key event type of composition methods must be "" or "keydown".
   if (aKeyboardEvent.mMessage == eKeyDown) {
     return true;
   }
-  if (aKeyboardEvent.mMessage == NS_USER_DEFINED_EVENT &&
+  if (aKeyboardEvent.mMessage == eUnidentifiedEvent &&
       aKeyboardEvent.userType &&
       nsDependentAtomString(aKeyboardEvent.userType).EqualsLiteral("on")) {
     return true;
   }
   return false;
 }
 
 TextInputProcessor::EventDispatcherResult
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3455,16 +3455,18 @@ nsContentUtils::MaybeReportInterceptionE
   } else if (aError == NS_ERROR_INTERCEPTED_ERROR_RESPONSE) {
     messageName = "InterceptedErrorResponse";
   } else if (aError == NS_ERROR_INTERCEPTED_USED_RESPONSE) {
     messageName = "InterceptedUsedResponse";
   } else if (aError == NS_ERROR_CLIENT_REQUEST_OPAQUE_INTERCEPTION) {
     messageName = "ClientRequestOpaqueInterception";
   } else if (aError == NS_ERROR_BAD_OPAQUE_REDIRECT_INTERCEPTION) {
     messageName = "BadOpaqueRedirectInterception";
+  } else if (aError == NS_ERROR_INTERCEPTION_CANCELED) {
+    messageName = "InterceptionCanceled";
   }
 
   if (messageName) {
     return ReportToConsole(nsIScriptError::warningFlag,
                            NS_LITERAL_CSTRING("Service Worker Interception"),
                            aDocument,
                            nsContentUtils::eDOM_PROPERTIES,
                            messageName);
@@ -3677,17 +3679,17 @@ nsContentUtils::GetEventMessage(nsIAtom*
 {
   if (aName) {
     EventNameMapping mapping;
     if (sAtomEventTable->Get(aName, &mapping)) {
       return mapping.mMessage;
     }
   }
 
-  return NS_USER_DEFINED_EVENT;
+  return eUnidentifiedEvent;
 }
 
 // static
 mozilla::EventClassID
 nsContentUtils::GetEventClassID(const nsAString& aName)
 {
   EventNameMapping mapping;
   if (sStringEventTable->Get(aName, &mapping))
@@ -3700,34 +3702,34 @@ nsIAtom*
 nsContentUtils::GetEventMessageAndAtom(const nsAString& aName,
                                        mozilla::EventClassID aEventClassID,
                                        EventMessage* aEventMessage)
 {
   EventNameMapping mapping;
   if (sStringEventTable->Get(aName, &mapping)) {
     *aEventMessage =
       mapping.mEventClassID == aEventClassID ? mapping.mMessage :
-                                               NS_USER_DEFINED_EVENT;
+                                               eUnidentifiedEvent;
     return mapping.mAtom;
   }
 
   // If we have cached lots of user defined event names, clear some of them.
   if (sUserDefinedEvents->Count() > 127) {
     while (sUserDefinedEvents->Count() > 64) {
       nsIAtom* first = sUserDefinedEvents->ObjectAt(0);
       sStringEventTable->Remove(Substring(nsDependentAtomString(first), 2));
       sUserDefinedEvents->RemoveObjectAt(0);
     }
   }
 
-  *aEventMessage = NS_USER_DEFINED_EVENT;
+  *aEventMessage = eUnidentifiedEvent;
   nsCOMPtr<nsIAtom> atom = do_GetAtom(NS_LITERAL_STRING("on") + aName);
   sUserDefinedEvents->AppendObject(atom);
   mapping.mAtom = atom;
-  mapping.mMessage = NS_USER_DEFINED_EVENT;
+  mapping.mMessage = eUnidentifiedEvent;
   mapping.mType = EventNameType_None;
   mapping.mEventClassID = eBasicEventClass;
   sStringEventTable->Put(aName, mapping);
   return mapping.mAtom;
 }
 
 static
 nsresult GetEventAndTarget(nsIDocument* aDoc, nsISupports* aTarget,
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1096,17 +1096,17 @@ public:
    *
    * @param aName the event name to look up
    * @param aType the type of content
    */
   static bool IsEventAttributeName(nsIAtom* aName, int32_t aType);
 
   /**
    * Return the event message for the event with the given name. The name is
-   * the event name with the 'on' prefix. Returns NS_USER_DEFINED_EVENT if the
+   * the event name with the 'on' prefix. Returns eUnidentifiedEvent if the
    * event doesn't match a known event name.
    *
    * @param aName the event name to look up
    */
   static mozilla::EventMessage GetEventMessage(nsIAtom* aName);
 
   /**
    * Return the EventClassID for the event with the given name. The name is the
@@ -1115,17 +1115,17 @@ public:
    *
    * @param aName the event name to look up
    */
   static mozilla::EventClassID GetEventClassID(const nsAString& aName);
 
   /**
    * Return the event message and atom for the event with the given name.
    * The name is the event name *without* the 'on' prefix.
-   * Returns NS_USER_DEFINED_EVENT on the aEventID if the
+   * Returns eUnidentifiedEvent on the aEventID if the
    * event doesn't match a known event name in the category.
    *
    * @param aName the event name to look up
    * @param aEventClassID only return event id for aEventClassID
    */
   static nsIAtom* GetEventMessageAndAtom(const nsAString& aName,
                                          mozilla::EventClassID aEventClassID,
                                          mozilla::EventMessage* aEventMessage);
--- a/dom/base/nsDOMMutationObserver.h
+++ b/dom/base/nsDOMMutationObserver.h
@@ -319,16 +319,17 @@ public:
     r->AddObserver();
     return r;
   }
 
   static nsMutationReceiver* Create(nsINode* aRegisterTarget,
                                     nsMutationReceiverBase* aParent)
   {
     nsMutationReceiver* r = new nsMutationReceiver(aRegisterTarget, aParent);
+    aParent->AddClone(r);
     r->AddObserver();
     return r;
   }
 
   nsMutationReceiver* GetParent()
   {
     return static_cast<nsMutationReceiver*>(mParent.get());
   }
@@ -380,17 +381,16 @@ public:
 protected:
   nsMutationReceiver(nsINode* aTarget, nsDOMMutationObserver* aObserver);
 
   nsMutationReceiver(nsINode* aRegisterTarget, nsMutationReceiverBase* aParent)
   : nsMutationReceiverBase(aRegisterTarget, aParent)
   {
     NS_ASSERTION(!static_cast<nsMutationReceiver*>(aParent)->GetParent(),
                  "Shouldn't create deep observer hierarchies!");
-    aParent->AddClone(this);
   }
 
   virtual void AddMutationObserver() override
   {
     mRegisterTarget->AddMutationObserver(this);
   }
 };
 
@@ -404,16 +404,17 @@ public:
     r->AddObserver();
     return r;
   }
 
   static nsAnimationReceiver* Create(nsINode* aRegisterTarget,
                                      nsMutationReceiverBase* aParent)
   {
     nsAnimationReceiver* r = new nsAnimationReceiver(aRegisterTarget, aParent);
+    aParent->AddClone(r);
     r->AddObserver();
     return r;
   }
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONADDED
   NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONCHANGED
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -820,17 +820,17 @@ nsDOMWindowUtils::SendWheelEvent(float a
 
   // get the widget to send the event to
   nsPoint offset;
   nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
   if (!widget) {
     return NS_ERROR_NULL_POINTER;
   }
 
-  WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, widget);
+  WidgetWheelEvent wheelEvent(true, eWheel, widget);
   wheelEvent.modifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
   wheelEvent.deltaX = aDeltaX;
   wheelEvent.deltaY = aDeltaY;
   wheelEvent.deltaZ = aDeltaZ;
   wheelEvent.deltaMode = aDeltaMode;
   wheelEvent.isMomentum =
     (aOptions & WHEEL_EVENT_CAUSED_BY_MOMENTUM) != 0;
   wheelEvent.mIsNoLineOrPageDelta =
@@ -1922,46 +1922,46 @@ nsDOMWindowUtils::SendQueryContentEvent(
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return NS_ERROR_FAILURE;
   }
 
   EventMessage message;
   switch (aType) {
     case QUERY_SELECTED_TEXT:
-      message = NS_QUERY_SELECTED_TEXT;
+      message = eQuerySelectedText;
       break;
     case QUERY_TEXT_CONTENT:
-      message = NS_QUERY_TEXT_CONTENT;
+      message = eQueryTextContent;
       break;
     case QUERY_CARET_RECT:
-      message = NS_QUERY_CARET_RECT;
+      message = eQueryCaretRect;
       break;
     case QUERY_TEXT_RECT:
       message = NS_QUERY_TEXT_RECT;
       break;
     case QUERY_EDITOR_RECT:
-      message = NS_QUERY_EDITOR_RECT;
+      message = eQueryEditorRect;
       break;
     case QUERY_CHARACTER_AT_POINT:
-      message = NS_QUERY_CHARACTER_AT_POINT;
+      message = eQueryCharacterAtPoint;
       break;
     default:
       return NS_ERROR_INVALID_ARG;
   }
 
   nsCOMPtr<nsIWidget> targetWidget = widget;
   LayoutDeviceIntPoint pt(aX, aY);
 
   bool useNativeLineBreak =
     !(aAdditionalFlags & QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK);
 
-  if (message == NS_QUERY_CHARACTER_AT_POINT) {
+  if (message == eQueryCharacterAtPoint) {
     // Looking for the widget at the point.
-    WidgetQueryContentEvent dummyEvent(true, NS_QUERY_CONTENT_STATE, widget);
+    WidgetQueryContentEvent dummyEvent(true, eQueryContentState, widget);
     dummyEvent.mUseNativeLineBreak = useNativeLineBreak;
     InitEvent(dummyEvent, &pt);
     nsIFrame* popupFrame =
       nsLayoutUtils::GetPopupFrameForEventCoordinates(presContext->GetRootPresContext(), &dummyEvent);
 
     nsIntRect widgetBounds;
     nsresult rv = widget->GetClientBounds(widgetBounds);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -1980,20 +1980,20 @@ nsDOMWindowUtils::SendQueryContentEvent(
   }
 
   pt += widget->WidgetToScreenOffset() - targetWidget->WidgetToScreenOffset();
 
   WidgetQueryContentEvent queryEvent(true, message, targetWidget);
   InitEvent(queryEvent, &pt);
 
   switch (message) {
-    case NS_QUERY_TEXT_CONTENT:
+    case eQueryTextContent:
       queryEvent.InitForQueryTextContent(aOffset, aLength, useNativeLineBreak);
       break;
-    case NS_QUERY_CARET_RECT:
+    case eQueryCaretRect:
       queryEvent.InitForQueryCaretRect(aOffset, useNativeLineBreak);
       break;
     case NS_QUERY_TEXT_RECT:
       queryEvent.InitForQueryTextRect(aOffset, aLength, useNativeLineBreak);
       break;
     default:
       queryEvent.mUseNativeLineBreak = useNativeLineBreak;
       break;
@@ -2050,35 +2050,36 @@ nsDOMWindowUtils::SendContentCommandEven
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
 
   // get the widget to send the event to
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget)
     return NS_ERROR_FAILURE;
 
   EventMessage msg;
-  if (aType.EqualsLiteral("cut"))
-    msg = NS_CONTENT_COMMAND_CUT;
-  else if (aType.EqualsLiteral("copy"))
-    msg = NS_CONTENT_COMMAND_COPY;
-  else if (aType.EqualsLiteral("paste"))
-    msg = NS_CONTENT_COMMAND_PASTE;
-  else if (aType.EqualsLiteral("delete"))
-    msg = NS_CONTENT_COMMAND_DELETE;
-  else if (aType.EqualsLiteral("undo"))
-    msg = NS_CONTENT_COMMAND_UNDO;
-  else if (aType.EqualsLiteral("redo"))
-    msg = NS_CONTENT_COMMAND_REDO;
-  else if (aType.EqualsLiteral("pasteTransferable"))
-    msg = NS_CONTENT_COMMAND_PASTE_TRANSFERABLE;
-  else
+  if (aType.EqualsLiteral("cut")) {
+    msg = eContentCommandCut;
+  } else if (aType.EqualsLiteral("copy")) {
+    msg = eContentCommandCopy;
+  } else if (aType.EqualsLiteral("paste")) {
+    msg = eContentCommandPaste;
+  } else if (aType.EqualsLiteral("delete")) {
+    msg = eContentCommandDelete;
+  } else if (aType.EqualsLiteral("undo")) {
+    msg = eContentCommandUndo;
+  } else if (aType.EqualsLiteral("redo")) {
+    msg = eContentCommandRedo;
+  } else if (aType.EqualsLiteral("pasteTransferable")) {
+    msg = eContentCommandPasteTransferable;
+  } else {
     return NS_ERROR_FAILURE;
+  }
 
   WidgetContentCommandEvent event(true, msg, widget);
-  if (msg == NS_CONTENT_COMMAND_PASTE_TRANSFERABLE) {
+  if (msg == eContentCommandPasteTransferable) {
     event.mTransferable = aTransferable;
   }
 
   nsEventStatus status;
   return widget->DispatchEvent(&event, status);
 }
 
 NS_IMETHODIMP
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -3943,23 +3943,17 @@ nsresult
 nsDocument::SetSubDocumentFor(Element* aElement, nsIDocument* aSubDoc)
 {
   NS_ENSURE_TRUE(aElement, NS_ERROR_UNEXPECTED);
 
   if (!aSubDoc) {
     // aSubDoc is nullptr, remove the mapping
 
     if (mSubDocuments) {
-      SubDocMapEntry *entry =
-        static_cast<SubDocMapEntry*>
-                   (PL_DHashTableSearch(mSubDocuments, aElement));
-
-      if (entry) {
-        PL_DHashTableRawRemove(mSubDocuments, entry);
-      }
+      PL_DHashTableRemove(mSubDocuments, aElement);
     }
   } else {
     if (!mSubDocuments) {
       // Create a new hashtable
 
       static const PLDHashTableOps hash_table_ops =
       {
         PL_DHashVoidPtrKeyStub,
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -87,17 +87,17 @@
 #include "nsIAppsService.h"
 #include "GeckoProfiler.h"
 
 #include "jsapi.h"
 #include "mozilla/dom/HTMLIFrameElement.h"
 #include "nsSandboxFlags.h"
 #include "mozilla/layers/CompositorChild.h"
 
-#include "mozilla/dom/StructuredCloneIPCHelper.h"
+#include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/WebBrowserPersistLocalDocument.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::hal;
@@ -2442,20 +2442,20 @@ nsFrameLoader::DoLoadMessageManagerScrip
 
 class nsAsyncMessageToChild : public nsSameProcessAsyncMessageBase,
                               public nsRunnable
 {
 public:
   nsAsyncMessageToChild(JSContext* aCx,
                         nsFrameLoader* aFrameLoader,
                         const nsAString& aMessage,
-                        StructuredCloneIPCHelper& aHelper,
+                        StructuredCloneData& aData,
                         JS::Handle<JSObject *> aCpows,
                         nsIPrincipal* aPrincipal)
-    : nsSameProcessAsyncMessageBase(aCx, aMessage, aHelper, aCpows, aPrincipal)
+    : nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal)
     , mFrameLoader(aFrameLoader)
   {
   }
 
   NS_IMETHOD Run()
   {
     nsInProcessTabChildGlobal* tabChild =
       static_cast<nsInProcessTabChildGlobal*>(mFrameLoader->mChildMessageManager.get());
@@ -2467,39 +2467,39 @@ public:
     return NS_OK;
   }
   nsRefPtr<nsFrameLoader> mFrameLoader;
 };
 
 bool
 nsFrameLoader::DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
-                                  StructuredCloneIPCHelper& aHelper,
+                                  StructuredCloneData& aData,
                                   JS::Handle<JSObject *> aCpows,
                                   nsIPrincipal* aPrincipal)
 {
   TabParent* tabParent = mRemoteBrowser;
   if (tabParent) {
     ClonedMessageData data;
     nsIContentParent* cp = tabParent->Manager();
-    if (!BuildClonedMessageDataForParent(cp, aHelper, data)) {
+    if (!BuildClonedMessageDataForParent(cp, aData, data)) {
       return false;
     }
     InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
     jsipc::CPOWManager* mgr = cp->GetCPOWManager();
     if (aCpows && (!mgr || !mgr->Wrap(aCx, aCpows, &cpows))) {
       return false;
     }
     return tabParent->SendAsyncMessage(nsString(aMessage), data, cpows,
                                        IPC::Principal(aPrincipal));
   }
 
   if (mChildMessageManager) {
     nsCOMPtr<nsIRunnable> ev = new nsAsyncMessageToChild(aCx, this, aMessage,
-                                                         aHelper, aCpows,
+                                                         aData, aCpows,
                                                          aPrincipal);
     NS_DispatchToCurrentThread(ev);
     return true;
   }
 
   // We don't have any targets to send our asynchronous message to.
   return false;
 }
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -36,20 +36,23 @@ class nsITabParent;
 class nsIDocShellTreeItem;
 class nsIDocShellTreeOwner;
 class mozIApplication;
 
 namespace mozilla {
 namespace dom {
 class ContentParent;
 class PBrowserParent;
-class StructuredCloneIPCHelper;
 class TabParent;
 } // namespace dom
 
+namespace ipc {
+class StructuredCloneData;
+} // namespace ipc
+
 namespace layout {
 class RenderFrameParent;
 } // namespace layout
 } // namespace mozilla
 
 #if defined(MOZ_WIDGET_GTK)
 typedef struct _GtkWidget GtkWidget;
 #endif
@@ -85,17 +88,17 @@ public:
 
   /**
    * MessageManagerCallback methods that we override.
    */
   virtual bool DoLoadMessageManagerScript(const nsAString& aURL,
                                           bool aRunInGlobalScope) override;
   virtual bool DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
-                                  mozilla::dom::StructuredCloneIPCHelper& aHelper,
+                                  mozilla::dom::ipc::StructuredCloneData& aData,
                                   JS::Handle<JSObject *> aCpows,
                                   nsIPrincipal* aPrincipal) override;
   virtual bool CheckPermission(const nsAString& aPermission) override;
   virtual bool CheckManifestURL(const nsAString& aManifestURL) override;
   virtual bool CheckAppHasPermission(const nsAString& aPermission) override;
 
   /**
    * Called from the layout frame associated with this frame loader;
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -32,19 +32,19 @@
 #include "mozilla/IntentionalCrash.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/nsIContentParent.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/dom/ProcessGlobal.h"
 #include "mozilla/dom/SameProcessMessageQueue.h"
 #include "mozilla/dom/ScriptSettings.h"
-#include "mozilla/dom/StructuredCloneIPCHelper.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/ipc/BlobParent.h"
+#include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "nsPrintfCString.h"
 #include "nsXULAppAPI.h"
 #include "nsQueryObject.h"
 #include <algorithm>
 
 #ifdef MOZ_CRASHREPORTER
@@ -271,23 +271,23 @@ struct DataBlobs<Child>
   {
     return aData.blobsChild();
   }
 };
 
 template<ActorFlavorEnum Flavor>
 static bool
 BuildClonedMessageData(typename BlobTraits<Flavor>::ConcreteContentManagerType* aManager,
-                       StructuredCloneIPCHelper& aHelper,
+                       StructuredCloneData& aData,
                        ClonedMessageData& aClonedData)
 {
   SerializedStructuredCloneBuffer& buffer = aClonedData.data();
-  buffer.data = aHelper.Data();
-  buffer.dataLength = aHelper.DataLength();
-  const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = aHelper.BlobImpls();
+  buffer.data = aData.Data();
+  buffer.dataLength = aData.DataLength();
+  const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = aData.BlobImpls();
 
   if (!blobImpls.IsEmpty()) {
     typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
     InfallibleTArray<ProtocolType*>& blobList = DataBlobs<Flavor>::Blobs(aClonedData);
     uint32_t length = blobImpls.Length();
     blobList.SetCapacity(length);
     for (uint32_t i = 0; i < length; ++i) {
       typename BlobTraits<Flavor>::BlobType* protocolActor =
@@ -298,69 +298,69 @@ BuildClonedMessageData(typename BlobTrai
       blobList.AppendElement(protocolActor);
     }
   }
   return true;
 }
 
 bool
 MessageManagerCallback::BuildClonedMessageDataForParent(nsIContentParent* aParent,
-                                                        StructuredCloneIPCHelper& aHelper,
+                                                        StructuredCloneData& aData,
                                                         ClonedMessageData& aClonedData)
 {
-  return BuildClonedMessageData<Parent>(aParent, aHelper, aClonedData);
+  return BuildClonedMessageData<Parent>(aParent, aData, aClonedData);
 }
 
 bool
 MessageManagerCallback::BuildClonedMessageDataForChild(nsIContentChild* aChild,
-                                                       StructuredCloneIPCHelper& aHelper,
+                                                       StructuredCloneData& aData,
                                                        ClonedMessageData& aClonedData)
 {
-  return BuildClonedMessageData<Child>(aChild, aHelper, aClonedData);
+  return BuildClonedMessageData<Child>(aChild, aData, aClonedData);
 }
 
 template<ActorFlavorEnum Flavor>
 static void
-UnpackClonedMessageData(const ClonedMessageData& aData,
-                        StructuredCloneIPCHelper& aHelper)
+UnpackClonedMessageData(const ClonedMessageData& aClonedData,
+                        StructuredCloneData& aData)
 {
-  const SerializedStructuredCloneBuffer& buffer = aData.data();
+  const SerializedStructuredCloneBuffer& buffer = aClonedData.data();
   typedef typename BlobTraits<Flavor>::ProtocolType ProtocolType;
-  const InfallibleTArray<ProtocolType*>& blobs = DataBlobs<Flavor>::Blobs(aData);
+  const InfallibleTArray<ProtocolType*>& blobs = DataBlobs<Flavor>::Blobs(aClonedData);
 
-  aHelper.UseExternalData(buffer.data, buffer.dataLength);
+  aData.UseExternalData(buffer.data, buffer.dataLength);
 
   if (!blobs.IsEmpty()) {
     uint32_t length = blobs.Length();
-    aHelper.BlobImpls().SetCapacity(length);
+    aData.BlobImpls().SetCapacity(length);
     for (uint32_t i = 0; i < length; ++i) {
       auto* blob =
         static_cast<typename BlobTraits<Flavor>::BlobType*>(blobs[i]);
       MOZ_ASSERT(blob);
 
       nsRefPtr<BlobImpl> blobImpl = blob->GetBlobImpl();
       MOZ_ASSERT(blobImpl);
 
-      aHelper.BlobImpls().AppendElement(blobImpl);
+      aData.BlobImpls().AppendElement(blobImpl);
     }
   }
 }
 
 void
-mozilla::dom::ipc::UnpackClonedMessageDataForParent(const ClonedMessageData& aData,
-                                                    StructuredCloneIPCHelper& aHelper)
+mozilla::dom::ipc::UnpackClonedMessageDataForParent(const ClonedMessageData& aClonedData,
+                                                    StructuredCloneData& aData)
 {
-  UnpackClonedMessageData<Parent>(aData, aHelper);
+  UnpackClonedMessageData<Parent>(aClonedData, aData);
 }
 
 void
-mozilla::dom::ipc::UnpackClonedMessageDataForChild(const ClonedMessageData& aData,
-                                                   StructuredCloneIPCHelper& aHelper)
+mozilla::dom::ipc::UnpackClonedMessageDataForChild(const ClonedMessageData& aClonedData,
+                                                   StructuredCloneData& aData)
 {
-  UnpackClonedMessageData<Child>(aData, aHelper);
+  UnpackClonedMessageData<Child>(aClonedData, aData);
 }
 
 bool
 SameProcessCpowHolder::ToObject(JSContext* aCx,
                                 JS::MutableHandle<JSObject*> aObjp)
 {
   if (!mObj) {
     return true;
@@ -647,23 +647,23 @@ JSONCreator(const char16_t* aBuf, uint32
   nsAString* result = static_cast<nsAString*>(aData);
   result->Append(static_cast<const char16_t*>(aBuf),
                  static_cast<uint32_t>(aLen));
   return true;
 }
 
 static bool
 GetParamsForMessage(JSContext* aCx,
-                    const JS::Value& aData,
-                    StructuredCloneIPCHelper& aHelper)
+                    const JS::Value& aValue,
+                    StructuredCloneData& aData)
 {
   // First try to use structured clone on the whole thing.
-  JS::RootedValue v(aCx, aData);
+  JS::RootedValue v(aCx, aValue);
   ErrorResult rv;
-  aHelper.Write(aCx, v, rv);
+  aData.Write(aCx, v, rv);
   if (!rv.Failed()) {
     return true;
   }
 
   rv.SuppressException();
   JS_ClearPendingException(aCx);
 
   nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
@@ -686,26 +686,25 @@ GetParamsForMessage(JSContext* aCx,
   NS_ENSURE_TRUE(JS_Stringify(aCx, &v, nullptr, JS::NullHandleValue,
                               JSONCreator, &json), false);
   NS_ENSURE_TRUE(!json.IsEmpty(), false);
 
   JS::Rooted<JS::Value> val(aCx, JS::NullValue());
   NS_ENSURE_TRUE(JS_ParseJSON(aCx, static_cast<const char16_t*>(json.get()),
                               json.Length(), &val), false);
 
-  aHelper.Write(aCx, val, rv);
+  aData.Write(aCx, val, rv);
   if (NS_WARN_IF(rv.Failed())) {
     rv.SuppressException();
     return false;
   }
 
   return true;
 }
 
-
 // nsISyncMessageSender
 
 static bool sSendingSyncMessage = false;
 
 NS_IMETHODIMP
 nsFrameMessageManager::SendSyncMessage(const nsAString& aMessageName,
                                        JS::Handle<JS::Value> aJSON,
                                        JS::Handle<JS::Value> aObjects,
@@ -748,30 +747,30 @@ nsFrameMessageManager::SendMessage(const
   aRetval.setUndefined();
   NS_ENSURE_TRUE(mCallback, NS_ERROR_NOT_INITIALIZED);
 
   if (sSendingSyncMessage && aIsSync) {
     // No kind of blocking send should be issued on top of a sync message.
     return NS_ERROR_UNEXPECTED;
   }
 
-  StructuredCloneIPCHelper helper;
-  if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, helper)) {
+  StructuredCloneData data;
+  if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, data)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
   JS::Rooted<JSObject*> objects(aCx);
   if (aArgc >= 3 && aObjects.isObject()) {
     objects = &aObjects.toObject();
   }
 
-  nsTArray<StructuredCloneIPCHelper> retval;
+  nsTArray<StructuredCloneData> retval;
 
   sSendingSyncMessage |= aIsSync;
-  bool ok = mCallback->DoSendBlockingMessage(aCx, aMessageName, helper, objects,
+  bool ok = mCallback->DoSendBlockingMessage(aCx, aMessageName, data, objects,
                                              aPrincipal, &retval, aIsSync);
   if (aIsSync) {
     sSendingSyncMessage = false;
   }
 
   if (!ok) {
     return NS_OK;
   }
@@ -795,58 +794,58 @@ nsFrameMessageManager::SendMessage(const
 
   aRetval.setObject(*dataArray);
   return NS_OK;
 }
 
 nsresult
 nsFrameMessageManager::DispatchAsyncMessageInternal(JSContext* aCx,
                                                     const nsAString& aMessage,
-                                                    StructuredCloneIPCHelper& aHelper,
+                                                    StructuredCloneData& aData,
                                                     JS::Handle<JSObject *> aCpows,
                                                     nsIPrincipal* aPrincipal)
 {
   if (mIsBroadcaster) {
     int32_t len = mChildManagers.Count();
     for (int32_t i = 0; i < len; ++i) {
       static_cast<nsFrameMessageManager*>(mChildManagers[i])->
-         DispatchAsyncMessageInternal(aCx, aMessage, aHelper, aCpows, aPrincipal);
+         DispatchAsyncMessageInternal(aCx, aMessage, aData, aCpows, aPrincipal);
     }
     return NS_OK;
   }
 
   if (!mCallback) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
-  if (!mCallback->DoSendAsyncMessage(aCx, aMessage, aHelper, aCpows, aPrincipal)) {
+  if (!mCallback->DoSendAsyncMessage(aCx, aMessage, aData, aCpows, aPrincipal)) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 nsresult
 nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName,
                                             const JS::Value& aJSON,
                                             const JS::Value& aObjects,
                                             nsIPrincipal* aPrincipal,
                                             JSContext* aCx,
                                             uint8_t aArgc)
 {
-  StructuredCloneIPCHelper helper;
-  if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, helper)) {
+  StructuredCloneData data;
+  if (aArgc >= 2 && !GetParamsForMessage(aCx, aJSON, data)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
   JS::Rooted<JSObject*> objects(aCx);
   if (aArgc >= 3 && aObjects.isObject()) {
     objects = &aObjects.toObject();
   }
 
-  return DispatchAsyncMessageInternal(aCx, aMessageName, helper, objects,
+  return DispatchAsyncMessageInternal(aCx, aMessageName, data, objects,
                                       aPrincipal);
 }
 
 
 // nsIMessageSender
 
 NS_IMETHODIMP
 nsFrameMessageManager::SendAsyncMessage(const nsAString& aMessageName,
@@ -1065,35 +1064,35 @@ public:
 
 // nsIMessageListener
 
 nsresult
 nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
                                       nsIFrameLoader* aTargetFrameLoader,
                                       const nsAString& aMessage,
                                       bool aIsSync,
-                                      StructuredCloneIPCHelper* aCloneHelper,
+                                      StructuredCloneData* aCloneData,
                                       mozilla::jsipc::CpowHolder* aCpows,
                                       nsIPrincipal* aPrincipal,
-                                      nsTArray<StructuredCloneIPCHelper>* aRetVal)
+                                      nsTArray<StructuredCloneData>* aRetVal)
 {
   return ReceiveMessage(aTarget, aTargetFrameLoader, mClosed, aMessage, aIsSync,
-                        aCloneHelper, aCpows, aPrincipal, aRetVal);
+                        aCloneData, aCpows, aPrincipal, aRetVal);
 }
 
 nsresult
 nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
                                       nsIFrameLoader* aTargetFrameLoader,
                                       bool aTargetClosed,
                                       const nsAString& aMessage,
                                       bool aIsSync,
-                                      StructuredCloneIPCHelper* aCloneHelper,
+                                      StructuredCloneData* aCloneData,
                                       mozilla::jsipc::CpowHolder* aCpows,
                                       nsIPrincipal* aPrincipal,
-                                      nsTArray<StructuredCloneIPCHelper>* aRetVal)
+                                      nsTArray<StructuredCloneData>* aRetVal)
 {
   nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
     mListeners.Get(aMessage);
   if (listeners) {
 
     MMListenerRemover lr(this);
 
     nsAutoTObserverArray<nsMessageListenerInfo, 1>::EndLimitedIterator
@@ -1164,19 +1163,19 @@ nsFrameMessageManager::ReceiveMessage(ns
         if (!cpows) {
           return NS_ERROR_UNEXPECTED;
         }
       }
 
       JS::Rooted<JS::Value> cpowsv(cx, JS::ObjectValue(*cpows));
 
       JS::Rooted<JS::Value> json(cx, JS::NullValue());
-      if (aCloneHelper && aCloneHelper->DataLength()) {
+      if (aCloneData && aCloneData->DataLength()) {
         ErrorResult rv;
-        aCloneHelper->Read(cx, &json, rv);
+        aCloneData->Read(cx, &json, rv);
         if (NS_WARN_IF(rv.Failed())) {
           rv.SuppressException();
           JS_ClearPendingException(cx);
           return NS_OK;
         }
       }
       JS::Rooted<JSString*> jsMessage(cx,
         JS_NewUCStringCopyN(cx,
@@ -1263,18 +1262,18 @@ nsFrameMessageManager::ReceiveMessage(ns
         }
 
         if (!JS_CallFunctionValue(cx, thisObject, funval,
                                   JS::HandleValueArray(argv), &rval)) {
           continue;
         }
         if (aRetVal) {
           ErrorResult rv;
-          StructuredCloneIPCHelper* helper = aRetVal->AppendElement();
-          helper->Write(cx, rval, rv);
+          StructuredCloneData* data = aRetVal->AppendElement();
+          data->Write(cx, rval, rv);
           if (NS_WARN_IF(rv.Failed())) {
             aRetVal->RemoveElementAt(aRetVal->Length() - 1);
             nsString msg = aMessage + NS_LITERAL_STRING(": message reply cannot be cloned. Are you trying to send an XPCOM object?");
 
             nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
             if (console) {
               nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
               error->Init(msg, EmptyString(), EmptyString(),
@@ -1287,17 +1286,17 @@ nsFrameMessageManager::ReceiveMessage(ns
           }
         }
       }
     }
   }
   nsRefPtr<nsFrameMessageManager> kungfuDeathGrip = mParentManager;
   return mParentManager ? mParentManager->ReceiveMessage(aTarget, aTargetFrameLoader,
                                                          aTargetClosed, aMessage,
-                                                         aIsSync, aCloneHelper,
+                                                         aIsSync, aCloneData,
                                                          aCpows, aPrincipal,
                                                          aRetVal) : NS_OK;
 }
 
 void
 nsFrameMessageManager::AddChildManager(nsFrameMessageManager* aManager)
 {
   mChildManagers.AppendObject(aManager);
@@ -1891,20 +1890,20 @@ nsFrameMessageManager* nsFrameMessageMan
 nsFrameMessageManager* nsFrameMessageManager::sSameProcessParentManager = nullptr;
 
 class nsAsyncMessageToSameProcessChild : public nsSameProcessAsyncMessageBase,
                                          public nsRunnable
 {
 public:
   nsAsyncMessageToSameProcessChild(JSContext* aCx,
                                    const nsAString& aMessage,
-                                   StructuredCloneIPCHelper& aHelper,
+                                   StructuredCloneData& aData,
                                    JS::Handle<JSObject *> aCpows,
                                    nsIPrincipal* aPrincipal)
-    : nsSameProcessAsyncMessageBase(aCx, aMessage, aHelper, aCpows, aPrincipal)
+    : nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal)
   {
   }
 
   NS_IMETHOD Run()
   {
     nsFrameMessageManager* ppm = nsFrameMessageManager::GetChildProcessManager();
     ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm), nullptr, ppm);
     return NS_OK;
@@ -1933,22 +1932,22 @@ public:
     ProcessGlobal* global = ProcessGlobal::Get();
     MOZ_ASSERT(!aRunInGlobalScope);
     global->LoadScript(aURL);
     return true;
   }
 
   virtual bool DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
-                                  StructuredCloneIPCHelper& aHelper,
+                                  StructuredCloneData& aData,
                                   JS::Handle<JSObject *> aCpows,
                                   nsIPrincipal* aPrincipal) override
   {
     nsCOMPtr<nsIRunnable> ev =
-      new nsAsyncMessageToSameProcessChild(aCx, aMessage, aHelper, aCpows,
+      new nsAsyncMessageToSameProcessChild(aCx, aMessage, aData, aCpows,
                                            aPrincipal);
     NS_DispatchToCurrentThread(ev);
     return true;
   }
 
   bool CheckPermission(const nsAString& aPermission) override
   {
     // In a single-process scenario, the child always has all capabilities.
@@ -1987,56 +1986,56 @@ public:
   }
   virtual ~ChildProcessMessageManagerCallback()
   {
     MOZ_COUNT_DTOR(ChildProcessMessageManagerCallback);
   }
 
   virtual bool DoSendBlockingMessage(JSContext* aCx,
                                      const nsAString& aMessage,
-                                     StructuredCloneIPCHelper& aHelper,
+                                     StructuredCloneData& aData,
                                      JS::Handle<JSObject *> aCpows,
                                      nsIPrincipal* aPrincipal,
-                                     nsTArray<StructuredCloneIPCHelper>* aRetVal,
+                                     nsTArray<StructuredCloneData>* aRetVal,
                                      bool aIsSync) override
   {
     mozilla::dom::ContentChild* cc =
       mozilla::dom::ContentChild::GetSingleton();
     if (!cc) {
       return true;
     }
     ClonedMessageData data;
-    if (!BuildClonedMessageDataForChild(cc, aHelper, data)) {
+    if (!BuildClonedMessageDataForChild(cc, aData, data)) {
       return false;
     }
     InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
     if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
       return false;
     }
     if (aIsSync) {
       return cc->SendSyncMessage(PromiseFlatString(aMessage), data, cpows,
                                  IPC::Principal(aPrincipal), aRetVal);
     }
     return cc->SendRpcMessage(PromiseFlatString(aMessage), data, cpows,
                               IPC::Principal(aPrincipal), aRetVal);
   }
 
   virtual bool DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
-                                  StructuredCloneIPCHelper& aHelper,
+                                  StructuredCloneData& aData,
                                   JS::Handle<JSObject *> aCpows,
                                   nsIPrincipal* aPrincipal) override
   {
     mozilla::dom::ContentChild* cc =
       mozilla::dom::ContentChild::GetSingleton();
     if (!cc) {
       return true;
     }
     ClonedMessageData data;
-    if (!BuildClonedMessageDataForChild(cc, aHelper, data)) {
+    if (!BuildClonedMessageDataForChild(cc, aData, data)) {
       return false;
     }
     InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
     if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
       return false;
     }
     return cc->SendAsyncMessage(PromiseFlatString(aMessage), data, cpows,
                                 IPC::Principal(aPrincipal));
@@ -2046,20 +2045,20 @@ public:
 
 
 class nsAsyncMessageToSameProcessParent : public nsSameProcessAsyncMessageBase,
                                           public SameProcessMessageQueue::Runnable
 {
 public:
   nsAsyncMessageToSameProcessParent(JSContext* aCx,
                                     const nsAString& aMessage,
-                                    StructuredCloneIPCHelper& aHelper,
+                                    StructuredCloneData& aData,
                                     JS::Handle<JSObject *> aCpows,
                                     nsIPrincipal* aPrincipal)
-    : nsSameProcessAsyncMessageBase(aCx, aMessage, aHelper, aCpows, aPrincipal)
+    : nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal)
   {
   }
 
   virtual nsresult HandleMessage() override
   {
     nsFrameMessageManager* ppm = nsFrameMessageManager::sSameProcessParentManager;
     ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm), nullptr, ppm);
     return NS_OK;
@@ -2078,43 +2077,43 @@ public:
   }
   virtual ~SameChildProcessMessageManagerCallback()
   {
     MOZ_COUNT_DTOR(SameChildProcessMessageManagerCallback);
   }
 
   virtual bool DoSendBlockingMessage(JSContext* aCx,
                                      const nsAString& aMessage,
-                                     StructuredCloneIPCHelper& aHelper,
+                                     StructuredCloneData& aData,
                                      JS::Handle<JSObject *> aCpows,
                                      nsIPrincipal* aPrincipal,
-                                     nsTArray<StructuredCloneIPCHelper>* aRetVal,
+                                     nsTArray<StructuredCloneData>* aRetVal,
                                      bool aIsSync) override
   {
     SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
     queue->Flush();
 
     if (nsFrameMessageManager::sSameProcessParentManager) {
       SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows);
       nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
       ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()), nullptr, aMessage,
-                          true, &aHelper, &cpows, aPrincipal, aRetVal);
+                          true, &aData, &cpows, aPrincipal, aRetVal);
     }
     return true;
   }
 
   virtual bool DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
-                                  StructuredCloneIPCHelper& aHelper,
+                                  StructuredCloneData& aData,
                                   JS::Handle<JSObject *> aCpows,
                                   nsIPrincipal* aPrincipal) override
   {
     SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
     nsRefPtr<nsAsyncMessageToSameProcessParent> ev =
-      new nsAsyncMessageToSameProcessParent(aCx, aMessage, aHelper, aCpows, aPrincipal);
+      new nsAsyncMessageToSameProcessParent(aCx, aMessage, aData, aCpows, aPrincipal);
     queue->Push(ev);
     return true;
   }
 
 };
 
 
 // This creates the global parent process message manager.
@@ -2204,38 +2203,38 @@ nsFrameMessageManager::MarkForCC()
   if (mRefCnt.IsPurple()) {
     mRefCnt.RemovePurple();
   }
   return true;
 }
 
 nsSameProcessAsyncMessageBase::nsSameProcessAsyncMessageBase(JSContext* aCx,
                                                              const nsAString& aMessage,
-                                                             StructuredCloneIPCHelper& aHelper,
+                                                             StructuredCloneData& aData,
                                                              JS::Handle<JSObject*> aCpows,
                                                              nsIPrincipal* aPrincipal)
   : mRuntime(js::GetRuntime(aCx)),
     mMessage(aMessage),
     mCpows(aCx, aCpows),
     mPrincipal(aPrincipal)
 {
-  if (!mHelper.Copy(aHelper)) {
+  if (!mData.Copy(aData)) {
 #ifdef MOZ_CRASHREPORTER
     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AsyncMessageOOM"),
                                        NS_ConvertUTF16toUTF8(aMessage));
 #endif
-    NS_ABORT_OOM(aHelper.DataLength());
+    NS_ABORT_OOM(aData.DataLength());
   }
 }
 
 void
 nsSameProcessAsyncMessageBase::ReceiveMessage(nsISupports* aTarget,
                                               nsIFrameLoader* aTargetFrameLoader,
                                               nsFrameMessageManager* aManager)
 {
   if (aManager) {
     SameProcessCpowHolder cpows(mRuntime, mCpows);
 
     nsRefPtr<nsFrameMessageManager> mm = aManager;
-    mm->ReceiveMessage(aTarget, aTargetFrameLoader, mMessage, false, &mHelper,
+    mm->ReceiveMessage(aTarget, aTargetFrameLoader, mMessage, false, &mData,
                        &cpows, mPrincipal, nullptr);
   }
 }
--- a/dom/base/nsFrameMessageManager.h
+++ b/dom/base/nsFrameMessageManager.h
@@ -23,17 +23,17 @@
 #include "mozilla/Services.h"
 #include "nsIObserverService.h"
 #include "nsThreadUtils.h"
 #include "nsWeakPtr.h"
 #include "mozilla/Attributes.h"
 #include "js/RootingAPI.h"
 #include "nsTObserverArray.h"
 #include "mozilla/dom/SameProcessMessageQueue.h"
-#include "mozilla/dom/StructuredCloneIPCHelper.h"
+#include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/jsipc/CpowHolder.h"
 
 class nsIFrameLoader;
 
 namespace mozilla {
 namespace dom {
 
 class nsIContentParent;
@@ -59,28 +59,28 @@ public:
 
   virtual bool DoLoadMessageManagerScript(const nsAString& aURL, bool aRunInGlobalScope)
   {
     return true;
   }
 
   virtual bool DoSendBlockingMessage(JSContext* aCx,
                                      const nsAString& aMessage,
-                                     StructuredCloneIPCHelper& aHelper,
+                                     StructuredCloneData& aData,
                                      JS::Handle<JSObject*> aCpows,
                                      nsIPrincipal* aPrincipal,
-                                     nsTArray<StructuredCloneIPCHelper>* aRetVal,
+                                     nsTArray<StructuredCloneData>* aRetVal,
                                      bool aIsSync)
   {
     return true;
   }
 
   virtual bool DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
-                                  StructuredCloneIPCHelper& aHelper,
+                                  StructuredCloneData& aData,
                                   JS::Handle<JSObject*> aCpows,
                                   nsIPrincipal* aPrincipal)
   {
     return true;
   }
 
   virtual bool CheckPermission(const nsAString& aPermission)
   {
@@ -105,28 +105,28 @@ public:
   virtual bool KillChild()
   {
     // By default, does nothing.
     return false;
   }
 
 protected:
   bool BuildClonedMessageDataForParent(nsIContentParent* aParent,
-                                       StructuredCloneIPCHelper& aHelper,
+                                       StructuredCloneData& aData,
                                        ClonedMessageData& aClonedData);
   bool BuildClonedMessageDataForChild(nsIContentChild* aChild,
-                                      StructuredCloneIPCHelper& aHelper,
+                                      StructuredCloneData& aData,
                                       ClonedMessageData& aClonedData);
 };
 
-void UnpackClonedMessageDataForParent(const ClonedMessageData& aData,
-                                      StructuredCloneIPCHelper& aHelper);
+void UnpackClonedMessageDataForParent(const ClonedMessageData& aClonedData,
+                                      StructuredCloneData& aData);
 
-void UnpackClonedMessageDataForChild(const ClonedMessageData& aData,
-                                     StructuredCloneIPCHelper& aHelper);
+void UnpackClonedMessageDataForChild(const ClonedMessageData& aClonedData,
+                                     StructuredCloneData& aData);
 
 } // namespace ipc
 } // namespace dom
 } // namespace mozilla
 
 struct nsMessageListenerInfo
 {
   bool operator==(const nsMessageListenerInfo& aOther) const
@@ -158,17 +158,17 @@ private:
 
 class nsFrameMessageManager final : public nsIContentFrameMessageManager,
                                     public nsIMessageBroadcaster,
                                     public nsIFrameScriptLoader,
                                     public nsIGlobalProcessScriptLoader,
                                     public nsIProcessChecker
 {
   friend class mozilla::dom::MessageManagerReporter;
-  typedef mozilla::dom::StructuredCloneIPCHelper StructuredCloneIPCHelper;
+  typedef mozilla::dom::ipc::StructuredCloneData StructuredCloneData;
 public:
   nsFrameMessageManager(mozilla::dom::ipc::MessageManagerCallback* aCallback,
                         nsFrameMessageManager* aParentManager,
                         /* mozilla::dom::ipc::MessageManagerFlags */ uint32_t aFlags);
 
 private:
   ~nsFrameMessageManager();
 
@@ -187,19 +187,19 @@ public:
   NS_DECL_NSIGLOBALPROCESSSCRIPTLOADER
   NS_DECL_NSIPROCESSCHECKER
 
   static nsFrameMessageManager*
   NewProcessMessageManager(bool aIsRemote);
 
   nsresult ReceiveMessage(nsISupports* aTarget, nsIFrameLoader* aTargetFrameLoader,
                           const nsAString& aMessage,
-                          bool aIsSync, StructuredCloneIPCHelper* aCloneHelper,
+                          bool aIsSync, StructuredCloneData* aCloneData,
                           mozilla::jsipc::CpowHolder* aCpows, nsIPrincipal* aPrincipal,
-                          nsTArray<StructuredCloneIPCHelper>* aRetVal);
+                          nsTArray<StructuredCloneData>* aRetVal);
 
   void AddChildManager(nsFrameMessageManager* aManager);
   void RemoveChildManager(nsFrameMessageManager* aManager)
   {
     mChildManagers.RemoveObject(aManager);
   }
   void Disconnect(bool aRemoveFromParent = true);
   void Close();
@@ -214,17 +214,17 @@ public:
   nsresult DispatchAsyncMessage(const nsAString& aMessageName,
                                 const JS::Value& aJSON,
                                 const JS::Value& aObjects,
                                 nsIPrincipal* aPrincipal,
                                 JSContext* aCx,
                                 uint8_t aArgc);
   nsresult DispatchAsyncMessageInternal(JSContext* aCx,
                                         const nsAString& aMessage,
-                                        StructuredCloneIPCHelper& aHelper,
+                                        StructuredCloneData& aData,
                                         JS::Handle<JSObject*> aCpows,
                                         nsIPrincipal* aPrincipal);
   void RemoveFromParent();
   nsFrameMessageManager* GetParentManager() { return mParentManager; }
   void SetParentManager(nsFrameMessageManager* aParent)
   {
     NS_ASSERTION(!mParentManager, "We have parent manager already!");
     NS_ASSERTION(mChrome, "Should not set parent manager!");
@@ -255,19 +255,19 @@ private:
                        nsIPrincipal* aPrincipal,
                        JSContext* aCx,
                        uint8_t aArgc,
                        JS::MutableHandle<JS::Value> aRetval,
                        bool aIsSync);
 
   nsresult ReceiveMessage(nsISupports* aTarget, nsIFrameLoader* aTargetFrameLoader,
                           bool aTargetClosed, const nsAString& aMessage,
-                          bool aIsSync, StructuredCloneIPCHelper* aCloneHelper,
+                          bool aIsSync, StructuredCloneData* aCloneData,
                           mozilla::jsipc::CpowHolder* aCpows, nsIPrincipal* aPrincipal,
-                          nsTArray<StructuredCloneIPCHelper>* aRetVal);
+                          nsTArray<StructuredCloneData>* aRetVal);
 
   NS_IMETHOD LoadScript(const nsAString& aURL,
                         bool aAllowDelayedLoad,
                         bool aRunInGlobalScope);
   NS_IMETHOD RemoveDelayedScript(const nsAString& aURL);
   NS_IMETHOD GetDelayedScripts(JSContext* aCx, JS::MutableHandle<JS::Value> aList);
 
 protected:
@@ -321,33 +321,33 @@ private:
        ReceiveMessage(..., ...);
        return NS_OK;
      }
    };
  */
 class nsSameProcessAsyncMessageBase
 {
 public:
-  typedef mozilla::dom::StructuredCloneIPCHelper StructuredCloneIPCHelper;
+  typedef mozilla::dom::ipc::StructuredCloneData StructuredCloneData;
 
   nsSameProcessAsyncMessageBase(JSContext* aCx,
                                 const nsAString& aMessage,
-                                StructuredCloneIPCHelper& aHelper,
+                                StructuredCloneData& aData,
                                 JS::Handle<JSObject*> aCpows,
                                 nsIPrincipal* aPrincipal);
 
   void ReceiveMessage(nsISupports* aTarget, nsIFrameLoader* aTargetFrameLoader,
                       nsFrameMessageManager* aManager);
 
 private:
   nsSameProcessAsyncMessageBase(const nsSameProcessAsyncMessageBase&);
 
   JSRuntime* mRuntime;
   nsString mMessage;
-  StructuredCloneIPCHelper mHelper;
+  StructuredCloneData mData;
   JS::PersistentRooted<JSObject*> mCpows;
   nsCOMPtr<nsIPrincipal> mPrincipal;
 };
 
 class nsScriptCacheCleaner;
 
 struct nsMessageManagerScriptHolder
 {
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -935,16 +935,17 @@ GK_ATOM(paint_order, "paint-order")
 GK_ATOM(palettename, "palettename")
 GK_ATOM(panel, "panel")
 GK_ATOM(param, "param")
 GK_ATOM(parameter, "parameter")
 GK_ATOM(parent, "parent")
 GK_ATOM(parentapp, "parentapp")
 GK_ATOM(parentfocused, "parentfocused")
 GK_ATOM(parsetype, "parsetype")
+GK_ATOM(password, "password")
 GK_ATOM(pattern, "pattern")
 GK_ATOM(patternSeparator, "pattern-separator")
 GK_ATOM(perMille, "per-mille")
 GK_ATOM(percent, "percent")
 GK_ATOM(persist, "persist")
 GK_ATOM(phase, "phase")
 GK_ATOM(picture, "picture")
 GK_ATOM(ping, "ping")
@@ -2313,17 +2314,16 @@ GK_ATOM(itemset, "itemset")
 GK_ATOM(lineNumber, "line-number")
 GK_ATOM(linkedPanel, "linkedpanel")
 GK_ATOM(live, "live")
 GK_ATOM(menuitemcheckbox, "menuitemcheckbox")
 GK_ATOM(menuitemradio, "menuitemradio")
 GK_ATOM(mixed, "mixed")
 GK_ATOM(multiline, "multiline")
 GK_ATOM(navigation, "navigation")
-GK_ATOM(password, "password")
 GK_ATOM(polite, "polite")
 GK_ATOM(posinset, "posinset")
 GK_ATOM(presentation, "presentation")
 GK_ATOM(progressbar, "progressbar")
 GK_ATOM(region, "region")
 GK_ATOM(rowgroup, "rowgroup")
 GK_ATOM(rowheader, "rowheader")
 GK_ATOM(search, "search")
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -661,20 +661,22 @@ public:
   virtual bool unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
                        JS::Handle<jsid> id) const override;
 
   static void ObjectMoved(JSObject *obj, const JSObject *old);
 
   static const nsOuterWindowProxy singleton;
 
 protected:
-  static nsGlobalWindow* GetWindow(JSObject *proxy)
+  static nsGlobalWindow* GetOuterWindow(JSObject *proxy)
   {
-    return nsGlobalWindow::FromSupports(
+    nsGlobalWindow* outerWindow = nsGlobalWindow::FromSupports(
       static_cast<nsISupports*>(js::GetProxyExtra(proxy, 0).toPrivate()));
+    MOZ_ASSERT_IF(outerWindow, outerWindow->IsOuterWindow());
+    return outerWindow;
   }
 
   // False return value means we threw an exception.  True return value
   // but false "found" means we didn't have a subframe at that index.
   bool GetSubframeWindow(JSContext *cx, JS::Handle<JSObject*> proxy,
                          JS::Handle<jsid> id,
                          JS::MutableHandle<JS::Value> vp,
                          bool &found) const;
@@ -706,25 +708,25 @@ nsOuterWindowProxy::className(JSContext 
     MOZ_ASSERT(js::IsProxy(proxy));
 
     return "Window";
 }
 
 void
 nsOuterWindowProxy::finalize(JSFreeOp *fop, JSObject *proxy) const
 {
-  nsGlobalWindow* global = GetWindow(proxy);
-  if (global) {
-    global->ClearWrapper();
+  nsGlobalWindow* outerWindow = GetOuterWindow(proxy);
+  if (outerWindow) {
+    outerWindow->ClearWrapper();
 
     // Ideally we would use OnFinalize here, but it's possible that
     // EnsureScriptEnvironment will later be called on the window, and we don't
     // want to create a new script object in that case. Therefore, we need to
     // write a non-null value that will reliably crash when dereferenced.
-    global->PoisonOuterWindowProxy(proxy);
+    outerWindow->PoisonOuterWindowProxy(proxy);
   }
 }
 
 bool
 nsOuterWindowProxy::getPropertyDescriptor(JSContext* cx,
                                           JS::Handle<JSObject*> proxy,
                                           JS::Handle<jsid> id,
                                           JS::MutableHandle<JSPropertyDescriptor> desc) const
@@ -980,26 +982,26 @@ nsOuterWindowProxy::GetSubframeWindow(JS
                                       JS::Handle<JSObject*> proxy,
                                       JS::Handle<jsid> id) const
 {
   int32_t index = GetArrayIndexFromId(cx, id);
   if (!IsArrayIndex(index)) {
     return nullptr;
   }
 
-  nsGlobalWindow* win = GetWindow(proxy);
+  nsGlobalWindow* win = GetOuterWindow(proxy);
   MOZ_ASSERT(win->IsOuterWindow());
   return win->IndexedGetterOuter(index);
 }
 
 bool
 nsOuterWindowProxy::AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy,
                                                JS::AutoIdVector &props) const
 {
-  uint32_t length = GetWindow(proxy)->Length();
+  uint32_t length = GetOuterWindow(proxy)->Length();
   MOZ_ASSERT(int32_t(length) >= 0);
   if (!props.reserve(props.length() + length)) {
     return false;
   }
   for (int32_t i = 0; i < int32_t(length); ++i) {
     props.append(INT_TO_JSID(i));
   }
 
@@ -1018,19 +1020,19 @@ nsOuterWindowProxy::unwatch(JSContext *c
                             JS::Handle<jsid> id) const
 {
   return js::UnwatchGuts(cx, proxy, id);
 }
 
 void
 nsOuterWindowProxy::ObjectMoved(JSObject *obj, const JSObject *old)
 {
-  nsGlobalWindow* global = GetWindow(obj);
-  if (global) {
-    global->UpdateWrapper(obj, old);
+  nsGlobalWindow* outerWindow = GetOuterWindow(obj);
+  if (outerWindow) {
+    outerWindow->UpdateWrapper(obj, old);
   }
 }
 
 const nsOuterWindowProxy
 nsOuterWindowProxy::singleton;
 
 class nsChromeOuterWindowProxy : public nsOuterWindowProxy
 {
--- a/dom/base/nsInProcessTabChildGlobal.cpp
+++ b/dom/base/nsInProcessTabChildGlobal.cpp
@@ -16,73 +16,74 @@
 #include "xpcpublic.h"
 #include "nsIMozBrowserFrame.h"
 #include "nsDOMClassInfoID.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/dom/SameProcessMessageQueue.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
+using namespace mozilla::dom::ipc;
 
 bool
 nsInProcessTabChildGlobal::DoSendBlockingMessage(JSContext* aCx,
                                                  const nsAString& aMessage,
-                                                 StructuredCloneIPCHelper& aHelper,
+                                                 StructuredCloneData& aData,
                                                  JS::Handle<JSObject *> aCpows,
                                                  nsIPrincipal* aPrincipal,
-                                                 nsTArray<StructuredCloneIPCHelper>* aRetVal,
+                                                 nsTArray<StructuredCloneData>* aRetVal,
                                                  bool aIsSync)
 {
   SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
   queue->Flush();
 
   if (mChromeMessageManager) {
     SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows);
     nsRefPtr<nsFrameMessageManager> mm = mChromeMessageManager;
     nsCOMPtr<nsIFrameLoader> fl = GetFrameLoader();
-    mm->ReceiveMessage(mOwner, fl, aMessage, true, &aHelper, &cpows, aPrincipal,
+    mm->ReceiveMessage(mOwner, fl, aMessage, true, &aData, &cpows, aPrincipal,
                        aRetVal);
   }
   return true;
 }
 
 class nsAsyncMessageToParent : public nsSameProcessAsyncMessageBase,
                                public SameProcessMessageQueue::Runnable
 {
 public:
   nsAsyncMessageToParent(JSContext* aCx,
                          nsInProcessTabChildGlobal* aTabChild,
                          const nsAString& aMessage,
-                         StructuredCloneIPCHelper& aHelper,
+                         StructuredCloneData& aData,
                          JS::Handle<JSObject *> aCpows,
                          nsIPrincipal* aPrincipal)
-    : nsSameProcessAsyncMessageBase(aCx, aMessage, aHelper, aCpows, aPrincipal),
+    : nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal),
       mTabChild(aTabChild)
   {
   }
 
   virtual nsresult HandleMessage() override
   {
     nsCOMPtr<nsIFrameLoader> fl = mTabChild->GetFrameLoader();
     ReceiveMessage(mTabChild->mOwner, fl, mTabChild->mChromeMessageManager);
     return NS_OK;
   }
   nsRefPtr<nsInProcessTabChildGlobal> mTabChild;
 };
 
 bool
 nsInProcessTabChildGlobal::DoSendAsyncMessage(JSContext* aCx,
                                               const nsAString& aMessage,
-                                              StructuredCloneIPCHelper& aHelper,
+                                              StructuredCloneData& aData,
                                               JS::Handle<JSObject *> aCpows,
                                               nsIPrincipal* aPrincipal)
 {
   SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
   nsRefPtr<nsAsyncMessageToParent> ev =
-    new nsAsyncMessageToParent(aCx, this, aMessage, aHelper, aCpows, aPrincipal);
+    new nsAsyncMessageToParent(aCx, this, aMessage, aData, aCpows, aPrincipal);
   queue->Push(ev);
   return true;
 }
 
 nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
                                                      nsIContent* aOwner,
                                                      nsFrameMessageManager* aChrome)
 : mDocShell(aShell), mInitialized(false), mLoadingScript(false),
--- a/dom/base/nsInProcessTabChildGlobal.h
+++ b/dom/base/nsInProcessTabChildGlobal.h
@@ -30,17 +30,17 @@ class EventChainPreVisitor;
 class nsInProcessTabChildGlobal : public mozilla::DOMEventTargetHelper,
                                   public nsMessageManagerScriptExecutor,
                                   public nsIInProcessContentFrameMessageManager,
                                   public nsIGlobalObject,
                                   public nsIScriptObjectPrincipal,
                                   public nsSupportsWeakReference,
                                   public mozilla::dom::ipc::MessageManagerCallback
 {
-  typedef mozilla::dom::StructuredCloneIPCHelper StructuredCloneIPCHelper;
+  typedef mozilla::dom::ipc::StructuredCloneData StructuredCloneData;
 
 public:
   nsInProcessTabChildGlobal(nsIDocShell* aShell, nsIContent* aOwner,
                             nsFrameMessageManager* aChrome);
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsInProcessTabChildGlobal,
                                                          mozilla::DOMEventTargetHelper)
 
@@ -78,24 +78,24 @@ public:
 
   NS_DECL_NSIINPROCESSCONTENTFRAMEMESSAGEMANAGER
 
   /**
    * MessageManagerCallback methods that we override.
    */
   virtual bool DoSendBlockingMessage(JSContext* aCx,
                                       const nsAString& aMessage,
-                                      StructuredCloneIPCHelper& aHelper,
+                                      StructuredCloneData& aData,
                                       JS::Handle<JSObject *> aCpows,
                                       nsIPrincipal* aPrincipal,
-                                      nsTArray<StructuredCloneIPCHelper>* aRetVal,
+                                      nsTArray<StructuredCloneData>* aRetVal,
                                       bool aIsSync) override;
   virtual bool DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
-                                  StructuredCloneIPCHelper& aHelper,
+                                  StructuredCloneData& aData,
                                   JS::Handle<JSObject *> aCpows,
                                   nsIPrincipal* aPrincipal) override;
 
   virtual nsresult PreHandleEvent(
                      mozilla::EventChainPreVisitor& aVisitor) override;
   NS_IMETHOD AddEventListener(const nsAString& aType,
                               nsIDOMEventListener* aListener,
                               bool aUseCapture)
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -2957,17 +2957,18 @@ nsObjectLoadingContent::LoadFallback(Fal
   NS_ASSERTION(thisContent, "must be a content");
 
   if (!thisContent->IsHTMLElement() || mContentType.IsEmpty()) {
     // Don't let custom fallback handlers run outside HTML, tags without a
     // determined type should always just be alternate content
     aType = eFallbackAlternate;
   }
 
-  if (thisContent->IsHTMLElement(nsGkAtoms::object) &&
+  if ((thisContent->IsHTMLElement(nsGkAtoms::object) ||
+       thisContent->IsHTMLElement(nsGkAtoms::applet)) &&
       (aType == eFallbackUnsupported ||
        aType == eFallbackDisabled ||
        aType == eFallbackBlocklisted))
   {
     // Show alternate content instead, if it exists
     for (nsIContent* child = thisContent->GetFirstChild();
          child; child = child->GetNextSibling()) {
       if (!child->IsHTMLElement(nsGkAtoms::param) &&
--- a/dom/base/nsPropertyTable.cpp
+++ b/dom/base/nsPropertyTable.cpp
@@ -102,17 +102,17 @@ nsPropertyTable::TransferOrDeleteAllProp
                                       prop->mDtorData, prop->mTransfer);
         if (NS_FAILED(rv)) {
           DeleteAllPropertiesFor(aObject);
           aOtherTable->DeleteAllPropertiesFor(aObject);
 
           break;
         }
 
-        PL_DHashTableRawRemove(&prop->mObjectValueMap, entry);
+        prop->mObjectValueMap.RemoveEntry(entry);
       }
     }
     else {
       prop->DeletePropertyFor(aObject);
     }
   }
 
   return rv;
@@ -159,17 +159,17 @@ nsPropertyTable::GetPropertyInternal(nsP
   if (propertyList) {
     PropertyListMapEntry *entry =
         static_cast<PropertyListMapEntry*>
                    (PL_DHashTableSearch(&propertyList->mObjectValueMap, aObject));
     if (entry) {
       propValue = entry->value;
       if (aRemove) {
         // don't call propertyList->mDtorFunc.  That's the caller's job now.
-        PL_DHashTableRawRemove(&propertyList->mObjectValueMap, entry);
+        propertyList->mObjectValueMap.RemoveEntry(entry);
       }
       rv = NS_OK;
     }
   }
 
   if (aResult)
     *aResult = rv;
 
@@ -296,17 +296,17 @@ nsPropertyTable::PropertyList::DeletePro
 {
   PropertyListMapEntry *entry =
       static_cast<PropertyListMapEntry*>
                  (PL_DHashTableSearch(&mObjectValueMap, aObject));
   if (!entry)
     return false;
 
   void* value = entry->value;
-  PL_DHashTableRawRemove(&mObjectValueMap, entry);
+  mObjectValueMap.RemoveEntry(entry);
 
   if (mDtorFunc)
     mDtorFunc(const_cast<void*>(aObject.get()), mName, value, mDtorData);
 
   return true;
 }
 
 size_t
--- a/dom/base/nsQueryContentEventResult.cpp
+++ b/dom/base/nsQueryContentEventResult.cpp
@@ -14,18 +14,19 @@ using namespace mozilla;
 NS_INTERFACE_MAP_BEGIN(nsQueryContentEventResult)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIQueryContentEventResult)
   NS_INTERFACE_MAP_ENTRY(nsIQueryContentEventResult)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(nsQueryContentEventResult)
 NS_IMPL_RELEASE(nsQueryContentEventResult)
 
-nsQueryContentEventResult::nsQueryContentEventResult() :
-  mEventID(0), mSucceeded(false)
+nsQueryContentEventResult::nsQueryContentEventResult()
+  : mEventMessage(eVoidEvent)
+  , mSucceeded(false)
 {
 }
 
 nsQueryContentEventResult::~nsQueryContentEventResult()
 {
 }
 
 NS_IMETHODIMP
@@ -49,130 +50,129 @@ nsQueryContentEventResult::GetTentativeC
   }
   if (NS_WARN_IF(notFound)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   *aOffset = mTentativeCaretOffset;
   return NS_OK;
 }
 
-static bool IsRectEnabled(uint32_t aEventID)
+static bool IsRectEnabled(EventMessage aEventMessage)
 {
-  return aEventID == NS_QUERY_CARET_RECT ||
-         aEventID == NS_QUERY_TEXT_RECT ||
-         aEventID == NS_QUERY_EDITOR_RECT ||
-         aEventID == NS_QUERY_CHARACTER_AT_POINT;
+  return aEventMessage == eQueryCaretRect ||
+         aEventMessage == NS_QUERY_TEXT_RECT ||
+         aEventMessage == eQueryEditorRect ||
+         aEventMessage == eQueryCharacterAtPoint;
 }
 
 NS_IMETHODIMP
 nsQueryContentEventResult::GetReversed(bool *aReversed)
 {
   NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE);
-  NS_ENSURE_TRUE(mEventID == NS_QUERY_SELECTED_TEXT,
-                 NS_ERROR_NOT_AVAILABLE);
+  NS_ENSURE_TRUE(mEventMessage == eQuerySelectedText, NS_ERROR_NOT_AVAILABLE);
   *aReversed = mReversed;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsQueryContentEventResult::GetLeft(int32_t *aLeft)
 {
   NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE);
-  NS_ENSURE_TRUE(IsRectEnabled(mEventID),
+  NS_ENSURE_TRUE(IsRectEnabled(mEventMessage),
                  NS_ERROR_NOT_AVAILABLE);
   *aLeft = mRect.x;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsQueryContentEventResult::GetWidth(int32_t *aWidth)
 {
   NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE);
-  NS_ENSURE_TRUE(IsRectEnabled(mEventID),
+  NS_ENSURE_TRUE(IsRectEnabled(mEventMessage),
                  NS_ERROR_NOT_AVAILABLE);
   *aWidth = mRect.width;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsQueryContentEventResult::GetTop(int32_t *aTop)
 {
   NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE);
-  NS_ENSURE_TRUE(IsRectEnabled(mEventID),
+  NS_ENSURE_TRUE(IsRectEnabled(mEventMessage),
                  NS_ERROR_NOT_AVAILABLE);
   *aTop = mRect.y;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsQueryContentEventResult::GetHeight(int32_t *aHeight)
 {
   NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE);
-  NS_ENSURE_TRUE(IsRectEnabled(mEventID),
+  NS_ENSURE_TRUE(IsRectEnabled(mEventMessage),
                  NS_ERROR_NOT_AVAILABLE);
   *aHeight = mRect.height;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsQueryContentEventResult::GetText(nsAString &aText)
 {
   NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE);
-  NS_ENSURE_TRUE(mEventID == NS_QUERY_SELECTED_TEXT ||
-                 mEventID == NS_QUERY_TEXT_CONTENT,
+  NS_ENSURE_TRUE(mEventMessage == eQuerySelectedText ||
+                 mEventMessage == eQueryTextContent,
                  NS_ERROR_NOT_AVAILABLE);
   aText = mString;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsQueryContentEventResult::GetSucceeded(bool *aSucceeded)
 {
-  NS_ENSURE_TRUE(mEventID != 0, NS_ERROR_NOT_INITIALIZED);
+  NS_ENSURE_TRUE(mEventMessage != eVoidEvent, NS_ERROR_NOT_INITIALIZED);
   *aSucceeded = mSucceeded;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsQueryContentEventResult::GetNotFound(bool *aNotFound)
 {
   NS_ENSURE_TRUE(mSucceeded, NS_ERROR_NOT_AVAILABLE);
-  NS_ENSURE_TRUE(mEventID == NS_QUERY_SELECTED_TEXT ||
-                 mEventID == NS_QUERY_CHARACTER_AT_POINT,
+  NS_ENSURE_TRUE(mEventMessage == eQuerySelectedText ||
+                 mEventMessage == eQueryCharacterAtPoint,
                  NS_ERROR_NOT_AVAILABLE);
   *aNotFound = (mOffset == WidgetQueryContentEvent::NOT_FOUND);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsQueryContentEventResult::GetTentativeCaretOffsetNotFound(bool* aNotFound)
 {
   if (NS_WARN_IF(!mSucceeded)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
-  if (NS_WARN_IF(mEventID != NS_QUERY_CHARACTER_AT_POINT)) {
+  if (NS_WARN_IF(mEventMessage != eQueryCharacterAtPoint)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   *aNotFound = (mTentativeCaretOffset == WidgetQueryContentEvent::NOT_FOUND);
   return NS_OK;
 }
 
 void
 nsQueryContentEventResult::SetEventResult(nsIWidget* aWidget,
                                           const WidgetQueryContentEvent &aEvent)
 {
-  mEventID = aEvent.mMessage;
+  mEventMessage = aEvent.mMessage;
   mSucceeded = aEvent.mSucceeded;
   mReversed = aEvent.mReply.mReversed;
   mRect = aEvent.mReply.mRect;
   mOffset = aEvent.mReply.mOffset;
   mTentativeCaretOffset = aEvent.mReply.mTentativeCaretOffset;
   mString = aEvent.mReply.mString;
 
-  if (!IsRectEnabled(mEventID) || !aWidget || !mSucceeded) {
+  if (!IsRectEnabled(mEventMessage) || !aWidget || !mSucceeded) {
     return;
   }
 
   nsIWidget* topWidget = aWidget->GetTopLevelWidget();
   if (!topWidget || topWidget == aWidget) {
     return;
   }
 
--- a/dom/base/nsQueryContentEventResult.h
+++ b/dom/base/nsQueryContentEventResult.h
@@ -24,17 +24,17 @@ public:
   NS_DECL_NSIQUERYCONTENTEVENTRESULT
 
   void SetEventResult(nsIWidget* aWidget,
                       const mozilla::WidgetQueryContentEvent &aEvent);
 
 protected:
   ~nsQueryContentEventResult();
 
-  uint32_t mEventID;
+  mozilla::EventMessage mEventMessage;
 
   uint32_t mOffset;
   uint32_t mTentativeCaretOffset;
   nsString mString;
   mozilla::LayoutDeviceIntRect mRect;
 
   bool mSucceeded;
   bool mReversed;
--- a/dom/base/nsStructuredCloneContainer.h
+++ b/dom/base/nsStructuredCloneContainer.h
@@ -4,31 +4,31 @@
  * 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 nsStructuredCloneContainer_h__
 #define nsStructuredCloneContainer_h__
 
 #include "nsIStructuredCloneContainer.h"
 #include "mozilla/Attributes.h"
-#include "mozilla/dom/StructuredCloneIPCHelper.h"
+#include "mozilla/dom/ipc/StructuredCloneData.h"
 
 #define NS_STRUCTUREDCLONECONTAINER_CONTRACTID \
   "@mozilla.org/docshell/structured-clone-container;1"
 #define NS_STRUCTUREDCLONECONTAINER_CID \
 { /* 38bd0634-0fd4-46f0-b85f-13ced889eeec */       \
   0x38bd0634,                                      \
   0x0fd4,                                          \
   0x46f0,                                          \
   {0xb8, 0x5f, 0x13, 0xce, 0xd8, 0x89, 0xee, 0xec} \
 }
 
 class nsStructuredCloneContainer final
   : public nsIStructuredCloneContainer
-  , public mozilla::dom::StructuredCloneIPCHelper
+  , public mozilla::dom::ipc::StructuredCloneData
 {
   public:
     nsStructuredCloneContainer();
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSISTRUCTUREDCLONECONTAINER
 
   private:
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -254,16 +254,17 @@ support-files =
   performance_observer.html
   test_anonymousContent_style_csp.html^headers^
 
 [test_anonymousContent_api.html]
 [test_anonymousContent_append_after_reflow.html]
 [test_anonymousContent_insert.html]
 [test_anonymousContent_manipulate_content.html]
 [test_anonymousContent_style_csp.html]
+[test_applet_alternate_content.html]
 [test_appname_override.html]
 [test_async_setTimeout_stack.html]
 [test_async_setTimeout_stack_across_globals.html]
 [test_audioWindowUtils.html]
 [test_audioNotification.html]
 skip-if = buildapp == 'mulet'
 [test_audioNotificationStopOnNavigation.html]
 skip-if = buildapp == 'mulet'
copy from dom/base/test/test_bug810494.html
copy to dom/base/test/test_applet_alternate_content.html
--- a/dom/base/test/test_bug810494.html
+++ b/dom/base/test/test_applet_alternate_content.html
@@ -1,48 +1,42 @@
 <!DOCTYPE HTML>
 <html>
 <!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=810494
+https://bugzilla.mozilla.org/show_bug.cgi?id=1200602
 -->
 <head>
   <meta charset="utf-8">
-  <title>Test for Bug 810494</title>
+  <title>Test for Bug 1200602</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/SpecialPowers.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=810494">Mozilla Bug 810494</a>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1200602">Mozilla Bug 1200602</a>
 <pre id="test">
 <script type="application/javascript;version=1.8">
 
-function test(tag, type) {
+function test() {
   "use strict";
-  info("testing " + tag + " tag with type " + type);
 
-  const OBJLC = SpecialPowers.Ci.nsIObjectLoadingContent;
-  let obj = document.createElement(tag);
-  obj.type = type;
+  const objLC = SpecialPowers.Ci.nsIObjectLoadingContent;
+  let obj = document.createElement("applet");
+  obj.appendChild(document.createTextNode("alternate content"));
   document.body.appendChild(obj);
 
-  obj instanceof OBJLC;
+  obj instanceof objLC;
   obj = SpecialPowers.wrap(obj);
 
   // We expect this tag to simply go to alternate content, not get a
   // pluginProblem binding or fire any events.
-  ok(obj.displayedType == OBJLC.TYPE_NULL, "expected null type");
-  ok(obj.pluginFallbackType == OBJLC.PLUGIN_ALTERNATE,
+  ok(obj.displayedType == objLC.TYPE_NULL, "expected null type");
+  ok(obj.pluginFallbackType == objLC.PLUGIN_ALTERNATE,
      "expected alternate fallback mode");
 }
 
 // Test all non-plugin types these tags can load to make sure none of them
 // trigger plugin-specific fallbacks when loaded with no URI
-test("object", "text/html");     // Document
-test("object", "image/png");     // Image
-test("object", "image/svg+xml"); // SVG Document
-
-test("embed", "image/png");      // Image
-test("embed", "image/svg+xml");  // SVG Document
+test();
 </script>
 </pre>
 </body>
 </html>
--- a/dom/bindings/GenerateCSS2PropertiesWebIDL.py
+++ b/dom/bindings/GenerateCSS2PropertiesWebIDL.py
@@ -4,26 +4,17 @@
 
 import sys
 import string
 
 propList = eval(sys.stdin.read())
 props = ""
 for [name, prop, id, flags, pref] in propList:
     extendedAttrs = ["Throws", "TreatNullAs=EmptyString"]
-    # To limit the overhead of Func= annotations, we only generate them when
-    # necessary, which is when the
-    # CSS_PROPERTY_ALWAYS_ENABLED_IN_CHROME_OR_CERTIFIED_APP flag is set.
-    # Otherwise, we try to get by with just a Pref= annotation or no annotation
-    # at all.
-    if "CSS_PROPERTY_ALWAYS_ENABLED_IN_CHROME_OR_CERTIFIED_APP" in flags:
-        extendedAttrs.append('Func="IsCSSPropertyExposedToJS<eCSSProperty_%s>"' % id)
-    # The following is an 'elif' because it is the responsibility of
-    # IsCSSPropertyExposedToJS to handle the pref if there is one.
-    elif pref is not "":
+    if pref is not "":
         extendedAttrs.append('Pref="%s"' % pref)
     if not prop.startswith("Moz"):
         prop = prop[0].lower() + prop[1:]
     # Unfortunately, even some of the getters here are fallible
     # (e.g. on nsComputedDOMStyle).
     props += "  [%s] attribute DOMString %s;\n" % (", ".join(extendedAttrs),
                                                    prop)
     # Per spec, what's actually supposed to happen here is that we're supposed
--- a/dom/bluetooth/bluedroid/BluetoothSocket.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothSocket.cpp
@@ -35,17 +35,17 @@ EnsureBluetoothSocketHalLoad()
 
   sBluetoothSocketInterface = btInf->GetBluetoothSocketInterface();
   NS_ENSURE_TRUE(sBluetoothSocketInterface, false);
 
   return true;
 }
 
 class mozilla::dom::bluetooth::DroidSocketImpl
-  : public ipc::UnixFdWatcher
+  : public mozilla::ipc::UnixFdWatcher
   , public DataSocketIO
 {
 public:
   /* The connection status in DroidSocketImpl indicates the current
    * phase of the socket connection. The initial settign should always
    * be DISCONNECTED, when no connection is present.
    *
    * To establish a connection on the server, DroidSocketImpl moves
@@ -69,17 +69,17 @@ public:
     SOCKET_IS_LISTENING,
     SOCKET_IS_CONNECTING,
     SOCKET_IS_CONNECTED
   };
 
   DroidSocketImpl(MessageLoop* aConsumerLoop,
                   MessageLoop* aIOLoop,
                   BluetoothSocket* aConsumer)
-    : ipc::UnixFdWatcher(aIOLoop)
+    : mozilla::ipc::UnixFdWatcher(aIOLoop)
     , DataSocketIO(aConsumerLoop)
     , mConsumer(aConsumer)
     , mShuttingDownOnIOThread(false)
     , mConnectionStatus(SOCKET_IS_DISCONNECTED)
   {
     MOZ_COUNT_CTOR_INHERITED(DroidSocketImpl, DataSocketIO);
   }
 
--- a/dom/broadcastchannel/BroadcastChannelChild.cpp
+++ b/dom/broadcastchannel/BroadcastChannelChild.cpp
@@ -6,21 +6,21 @@
 
 #include "BroadcastChannelChild.h"
 #include "BroadcastChannel.h"
 #include "jsapi.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
-#include "mozilla/dom/StructuredCloneIPCHelper.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/ipc/PBackgroundChild.h"
+#include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "WorkerPrivate.h"
 
 namespace mozilla {
 
 using namespace ipc;
 
 namespace dom {
 
@@ -80,27 +80,27 @@ BroadcastChannelChild::RecvNotify(const 
     globalObject = workerPrivate->GlobalScope();
   }
 
   if (!globalObject || !jsapi.Init(globalObject)) {
     NS_WARNING("Failed to initialize AutoJSAPI object.");
     return true;
   }
 
-  StructuredCloneIPCHelper cloneHelper;
-  cloneHelper.BlobImpls().AppendElements(blobs);
+  ipc::StructuredCloneData cloneData;
+  cloneData.BlobImpls().AppendElements(blobs);
 
   const SerializedStructuredCloneBuffer& buffer = aData.data();
-  cloneHelper.UseExternalData(buffer.data, buffer.dataLength);
+  cloneData.UseExternalData(buffer.data, buffer.dataLength);
 
   JSContext* cx = jsapi.cx();
   JS::Rooted<JS::Value> value(cx, JS::NullValue());
   if (buffer.dataLength) {
     ErrorResult rv;
-    cloneHelper.Read(cx, &value, rv);
+    cloneData.Read(cx, &value, rv);
     if (NS_WARN_IF(rv.Failed())) {
       return true;
     }
   }
 
   RootedDictionary<MessageEventInit> init(cx);
   init.mBubbles = false;
   init.mCancelable = false;
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -3946,26 +3946,26 @@ gfxFontGroup *CanvasRenderingContext2D::
     ErrorResult err;
     NS_NAMED_LITERAL_STRING(kDefaultFontStyle, "10px sans-serif");
     static float kDefaultFontSize = 10.0;
     nsCOMPtr<nsIPresShell> presShell = GetPresShell();
     bool fontUpdated = SetFontInternal(kDefaultFontStyle, err);
     if (err.Failed() || !fontUpdated) {
       gfxFontStyle style;
       style.size = kDefaultFontSize;
+      gfxTextPerfMetrics* tp = nullptr;
+      if (presShell && !presShell->IsDestroying()) {
+        tp = presShell->GetPresContext()->GetTextPerfMetrics();
+      }
       CurrentState().fontGroup =
         gfxPlatform::GetPlatform()->CreateFontGroup(FontFamilyList(eFamily_sans_serif),
-                                                    &style,
+                                                    &style, tp,
                                                     nullptr);
       if (CurrentState().fontGroup) {
         CurrentState().font = kDefaultFontStyle;
-        if (presShell && !presShell->IsDestroying()) {
-          CurrentState().fontGroup->SetTextPerfMetrics(
-            presShell->GetPresContext()->GetTextPerfMetrics());
-        }
       } else {
         NS_ERROR("Default canvas font is invalid");
       }
     }
   }
 
   return CurrentState().fontGroup;
 }
--- a/dom/encoding/domainsfallbacks.properties
+++ b/dom/encoding/domainsfallbacks.properties
@@ -49,18 +49,18 @@ xn--lgbbat1ad8j=windows-1256
 
 ee=windows-1257
 
 eg=windows-1256
 xn--wgbh1c=windows-1256
 
 gr=ISO-8859-7
 
-hk=Big5-HKSCS
-xn--j6w193g=Big5-HKSCS
+hk=Big5
+xn--j6w193g=Big5
 
 hr=windows-1250
 
 hu=ISO-8859-2
 
 iq=windows-1256
 
 ir=windows-1256
--- a/dom/encoding/encodingsgroups.properties
+++ b/dom/encoding/encodingsgroups.properties
@@ -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/.
 
 # x-unicode is assumed for encodings not listed here
 
 Big5=zh-TW
-Big5-HKSCS=zh=HK
 EUC-JP=ja
 EUC-KR=ko
 gb18030=zh-CN
 gbk=zh-CN
 IBM866=x-cyrillic
 ISO-2022-JP=ja
 ISO-8859-3=x-western
 ISO-8859-4=x-western
--- a/dom/encoding/labelsencodings.properties
+++ b/dom/encoding/labelsencodings.properties
@@ -184,17 +184,17 @@ gb2312=gbk
 gb_2312=gbk
 gb_2312-80=gbk
 gbk=gbk
 iso-ir-58=gbk
 x-gbk=gbk
 gb18030=gb18030
 hz-gb-2312=replacement
 big5=Big5
-big5-hkscs=Big5-HKSCS
+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
--- a/dom/encoding/test/test_TextDecoder.js
+++ b/dom/encoding/test/test_TextDecoder.js
@@ -39,16 +39,17 @@ function runTextDecoderOptions()
     testDecodeStreamOption(data, expectedString);
   }, "testDecodeStreamOption");
   test(testDecodeStreamCompositions, "testDecodeStreamCompositions");
   test(function() {
     testDecodeABVOption(data, expectedString);
   }, "testDecodeABVOption");
   test(testDecoderForThaiEncoding, "testDecoderForThaiEncoding");
   test(testInvalid2022JP, "testInvalid2022JP");
+  test(testDecoderForBig5, "testDecoderForBig5");
 }
 
 /*
 * function testConstructor()
 *
 * - This function tests the constructor optional arguments.
 * - Stream option remains null for this test.
 * - The stream option is passed to the decode function.
@@ -350,18 +351,17 @@ function testDecoderGetEncoding()
     {encoding: "windows-1254", labels: ["cp1254", "csisolatin5", "iso-8859-9", "iso-ir-148", "iso8859-9", "iso88599", "iso_8859-9", "iso_8859-9:1989", "l5", "latin5", "windows-1254", "x-cp1254"]},
     {encoding: "windows-1255", labels: ["cp1255", "windows-1255", "x-cp1255"]},
     {encoding: "windows-1256", labels: ["cp1256", "windows-1256", "x-cp1256"]},
     {encoding: "windows-1257", labels: ["cp1257", "windows-1257", "x-cp1257"]},
     {encoding: "windows-1258", labels: ["cp1258", "windows-1258", "x-cp1258"]},
     {encoding: "x-mac-cyrillic", labels: ["x-mac-cyrillic", "x-mac-ukrainian"]},
     {encoding: "gbk", labels: ["chinese", "csgb2312", "csiso58gb231280", "gb2312", "gb_2312", "gb_2312-80", "gbk", "iso-ir-58", "x-gbk"]},
     {encoding: "gb18030", labels: ["gb18030"]},
-    {encoding: "big5", labels: ["big5", "cn-big5", "csbig5", "x-x-big5"]},
-    {encoding: "big5-hkscs", labels: ["big5-hkscs"]},
+    {encoding: "big5", labels: ["big5", "cn-big5", "csbig5", "x-x-big5", "big5-hkscs"]},
     {encoding: "euc-jp", labels: ["cseucpkdfmtjapanese", "euc-jp", "x-euc-jp"]},
     {encoding: "iso-2022-jp", labels: ["csiso2022jp", "iso-2022-jp"]},
     {encoding: "shift_jis", labels: ["csshiftjis", "ms_kanji", "shift-jis", "shift_jis", "sjis", "windows-31j", "x-sjis"]},
     {encoding: "euc-kr", labels: ["cseuckr", "csksc56011987", "euc-kr", "iso-ir-149", "korean", "ks_c_5601-1987", "ks_c_5601-1989", "ksc5601", "ksc_5601", "windows-949"]},
     {encoding: "utf-16le", labels: ["utf-16", "utf-16le"]},
     {encoding: "utf-16be", labels: ["utf-16be"]},
     {encoding: "x-user-defined", labels: ["x-user-defined"]},
     {error: "RangeError", labels: ["x-windows-949", "\u0130SO-8859-1", "csiso2022kr", "iso-2022-kr", "iso-2022-cn", "iso-2022-cn-ext", "replacement", "hz-gb-2312"]},
@@ -458,8 +458,83 @@ function testInvalid2022JP()
       if (e.name !== "TypeError") {
         throw e;
       }
       failureCount++;
     }
   });
   assert_equals(failureCount, 0, failureCount + " of " + inputs.length + " tests failed");
 }
+
+function testDecoderForBig5()
+{
+  const inputs = [
+    [ 0x61, 0x62 ],
+    [ 0x87, 0x40 ],
+    [ 0xFE, 0xFE ],
+    [ 0xFE, 0xFD ],
+    [ 0x88, 0x62 ],
+    [ 0x88, 0x64 ],
+    [ 0x88, 0x66 ],
+    [ 0x88, 0xA3 ],
+    [ 0x88, 0xA5 ],
+    [ 0x88, 0xA7 ],
+    [ 0x99, 0xD4 ],
+    [ 0x99, 0xD5 ],
+    [ 0x99, 0xD6 ],
+    [ 0x61, 0x87, 0x40, 0x62 ],
+    [ 0x61, 0xFE, 0xFE, 0x62 ],
+    [ 0x61, 0xFE, 0xFD, 0x62 ],
+    [ 0x61, 0x88, 0x62, 0x62 ],
+    [ 0x61, 0x88, 0x64, 0x62 ],
+    [ 0x61, 0x88, 0x66, 0x62 ],
+    [ 0x61, 0x88, 0xA3, 0x62 ],
+    [ 0x61, 0x88, 0xA5, 0x62 ],
+    [ 0x61, 0x88, 0xA7, 0x62 ],
+    [ 0x61, 0x99, 0xD4, 0x62 ],
+    [ 0x61, 0x99, 0xD5, 0x62 ],
+    [ 0x61, 0x99, 0xD6, 0x62 ],
+    [ 0x80, 0x61 ],
+    [ 0xFF, 0x61 ],
+    [ 0xFE, 0x39 ],
+    [ 0x87, 0x66 ],
+    [ 0x81, 0x40 ],
+    [ 0x61, 0x81 ],
+  ];
+  const expectations = [
+    "\u0061\u0062",
+    "\u43F0",
+    "\u79D4",
+    "\uD864\uDD0D",
+    "\u00CA\u0304",
+    "\u00CA\u030C",
+    "\u00CA",
+    "\u00EA\u0304",
+    "\u00EA\u030C",
+    "\u00EA",
+    "\u8991",
+    "\uD85E\uDD67",
+    "\u8A29",
+    "\u0061\u43F0\u0062",
+    "\u0061\u79D4\u0062",
+    "\u0061\uD864\uDD0D\u0062",
+    "\u0061\u00CA\u0304\u0062",
+    "\u0061\u00CA\u030C\u0062",
+    "\u0061\u00CA\u0062",
+    "\u0061\u00EA\u0304\u0062",
+    "\u0061\u00EA\u030C\u0062",
+    "\u0061\u00EA\u0062",
+    "\u0061\u8991\u0062",
+    "\u0061\uD85E\uDD67\u0062",
+    "\u0061\u8A29\u0062",
+    "\uFFFD\u0061",
+    "\uFFFD\u0061",
+    "\uFFFD\u0039",
+    "\uFFFD\u0066",
+    "\uFFFD\u0040",
+    "\u0061\uFFFD",
+  ];
+
+  for (var i = 0; i < inputs.length; i++) {
+    testCharset({encoding: "big5", input: inputs[i], expected: expectations[i],
+      msg: "decoder test #" + i + " for big5."});
+  }
+}
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -791,33 +791,33 @@ ContentEventHandler::GetLineBreakType(bo
   return aUseNativeLineBreak ?
     LINE_BREAK_TYPE_NATIVE : LINE_BREAK_TYPE_XP;
 }
 
 nsresult
 ContentEventHandler::HandleQueryContentEvent(WidgetQueryContentEvent* aEvent)
 {
   switch (aEvent->mMessage) {
-    case NS_QUERY_SELECTED_TEXT:
+    case eQuerySelectedText:
       return OnQuerySelectedText(aEvent);
-    case NS_QUERY_TEXT_CONTENT:
+    case eQueryTextContent:
       return OnQueryTextContent(aEvent);
-    case NS_QUERY_CARET_RECT:
+    case eQueryCaretRect:
       return OnQueryCaretRect(aEvent);
     case NS_QUERY_TEXT_RECT:
       return OnQueryTextRect(aEvent);
-    case NS_QUERY_EDITOR_RECT:
+    case eQueryEditorRect:
       return OnQueryEditorRect(aEvent);
-    case NS_QUERY_CONTENT_STATE:
+    case eQueryContentState:
       return OnQueryContentState(aEvent);
-    case NS_QUERY_SELECTION_AS_TRANSFERABLE:
+    case eQuerySelectionAsTransferable:
       return OnQuerySelectionAsTransferable(aEvent);
-    case NS_QUERY_CHARACTER_AT_POINT:
+    case eQueryCharacterAtPoint:
       return OnQueryCharacterAtPoint(aEvent);
-    case NS_QUERY_DOM_WIDGET_HITTEST:
+    case eQueryDOMWidgetHittest:
       return OnQueryDOMWidgetHittest(aEvent);
     default:
       return NS_ERROR_NOT_IMPLEMENTED;
   }
   return NS_OK;
 }
 
 // Similar to nsFrameSelection::GetFrameForNodeOffset,
@@ -1262,17 +1262,17 @@ ContentEventHandler::OnQueryCharacterAtP
     nsView* view = nsView::GetViewFor(aEvent->widget);
     NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
     rootFrame = view->GetFrame();
     NS_ENSURE_TRUE(rootFrame, NS_ERROR_FAILURE);
     rootWidget = rootFrame->GetNearestWidget();
     NS_ENSURE_TRUE(rootWidget, NS_ERROR_FAILURE);
   }
 
-  WidgetQueryContentEvent eventOnRoot(true, NS_QUERY_CHARACTER_AT_POINT,
+  WidgetQueryContentEvent eventOnRoot(true, eQueryCharacterAtPoint,
                                       rootWidget);
   eventOnRoot.mUseNativeLineBreak = aEvent->mUseNativeLineBreak;
   eventOnRoot.refPoint = aEvent->refPoint;
   if (rootWidget != aEvent->widget) {
     eventOnRoot.refPoint += aEvent->widget->WidgetToScreenOffset() -
       rootWidget->WidgetToScreenOffset();
   }
   nsPoint ptInRoot =
--- a/dom/events/ContentEventHandler.h
+++ b/dom/events/ContentEventHandler.h
@@ -37,33 +37,33 @@ class MOZ_STACK_CLASS ContentEventHandle
 public:
   typedef dom::Selection Selection;
 
   explicit ContentEventHandler(nsPresContext* aPresContext);
 
   // Handle aEvent in the current process.
   nsresult HandleQueryContentEvent(WidgetQueryContentEvent* aEvent);
 
-  // NS_QUERY_SELECTED_TEXT event handler
+  // eQuerySelectedText event handler
   nsresult OnQuerySelectedText(WidgetQueryContentEvent* aEvent);
-  // NS_QUERY_TEXT_CONTENT event handler
+  // eQueryTextContent event handler
   nsresult OnQueryTextContent(WidgetQueryContentEvent* aEvent);
-  // NS_QUERY_CARET_RECT event handler
+  // eQueryCaretRect event handler
   nsresult OnQueryCaretRect(WidgetQueryContentEvent* aEvent);
   // NS_QUERY_TEXT_RECT event handler
   nsresult OnQueryTextRect(WidgetQueryContentEvent* aEvent);
-  // NS_QUERY_EDITOR_RECT event handler
+  // eQueryEditorRect event handler
   nsresult OnQueryEditorRect(WidgetQueryContentEvent* aEvent);
-  // NS_QUERY_CONTENT_STATE event handler
+  // eQueryContentState event handler
   nsresult OnQueryContentState(WidgetQueryContentEvent* aEvent);
-  // NS_QUERY_SELECTION_AS_TRANSFERABLE event handler
+  // eQuerySelectionAsTransferable event handler
   nsresult OnQuerySelectionAsTransferable(WidgetQueryContentEvent* aEvent);
-  // NS_QUERY_CHARACTER_AT_POINT event handler
+  // eQueryCharacterAtPoint event handler
   nsresult OnQueryCharacterAtPoint(WidgetQueryContentEvent* aEvent);
-  // NS_QUERY_DOM_WIDGET_HITTEST event handler
+  // eQueryDOMWidgetHittest event handler
   nsresult OnQueryDOMWidgetHittest(WidgetQueryContentEvent* aEvent);
 
   // NS_SELECTION_* event
   nsresult OnSelectionEvent(WidgetSelectionEvent* aEvent);
 
 protected:
   nsPresContext* mPresContext;
   nsCOMPtr<nsIPresShell> mPresShell;
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -265,17 +265,17 @@ Event::GetType(nsAString& aType)
     aType = mEvent->typeString;
     return NS_OK;
   }
   const char* name = GetEventName(mEvent->mMessage);
 
   if (name) {
     CopyASCIItoUTF16(name, aType);
     return NS_OK;
-  } else if (mEvent->mMessage == NS_USER_DEFINED_EVENT && mEvent->userType) {
+  } else if (mEvent->mMessage == eUnidentifiedEvent && mEvent->userType) {
     aType = Substring(nsDependentAtomString(mEvent->userType), 2); // Remove "on"
     mEvent->typeString = aType;
     return NS_OK;
   }
 
   aType.Truncate();
   return NS_OK;
 }
@@ -562,17 +562,17 @@ Event::SetEventType(const nsAString& aEv
 {
   if (mIsMainThreadEvent) {
     mEvent->typeString.Truncate();
     mEvent->userType =
       nsContentUtils::GetEventMessageAndAtom(aEventTypeArg, mEvent->mClass,
                                              &(mEvent->mMessage));
   } else {
     mEvent->userType = nullptr;
-    mEvent->mMessage = NS_USER_DEFINED_EVENT;
+    mEvent->mMessage = eUnidentifiedEvent;
     mEvent->typeString = aEventTypeArg;
   }
 }
 
 NS_IMETHODIMP
 Event::InitEvent(const nsAString& aEventTypeArg,
                  bool aCanBubbleArg,
                  bool aCancelableArg)
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -50,17 +50,17 @@
 
 namespace mozilla {
 
 using namespace dom;
 using namespace hal;
 
 #define EVENT_TYPE_EQUALS(ls, message, userType, typeString, allEvents) \
   ((ls->mEventMessage == message &&                                     \
-    (ls->mEventMessage != NS_USER_DEFINED_EVENT ||                      \
+    (ls->mEventMessage != eUnidentifiedEvent ||                         \
     (mIsMainThreadELM && ls->mTypeAtom == userType) ||                  \
     (!mIsMainThreadELM && ls->mTypeString.Equals(typeString)))) ||      \
    (allEvents && ls->mAllEvents))
 
 static const uint32_t kAllMutationBits =
   NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED |
   NS_EVENT_BITS_MUTATION_NODEINSERTED |
   NS_EVENT_BITS_MUTATION_NODEREMOVED |
@@ -288,17 +288,17 @@ EventListenerManager::AddEventListenerIn
 
   if (aFlags.mInSystemGroup) {
     mMayHaveSystemGroupListeners = true;
   }
   if (aFlags.mCapture) {
     mMayHaveCapturingListeners = true;
   }
 
-  if (aEventMessage == NS_AFTERPAINT) {
+  if (aEventMessage == eAfterPaint) {
     mMayHavePaintEventListener = true;
     nsPIDOMWindow* window = GetInnerWindowForTarget();
     if (window) {
       window->SetHasPaintEventListeners();
     }
   } else if (aEventMessage >= eLegacyMutationEventFirst &&
              aEventMessage <= eLegacyMutationEventLast) {
     // For mutation listeners, we need to update the global bit on the DOM window.
@@ -564,23 +564,23 @@ EventListenerManager::RemoveEventListene
   }
 }
 
 bool
 EventListenerManager::ListenerCanHandle(Listener* aListener,
                                         WidgetEvent* aEvent)
 {
   // This is slightly different from EVENT_TYPE_EQUALS in that it returns
-  // true even when aEvent->mMessage == NS_USER_DEFINED_EVENT and
-  // aListener=>mEventMessage != NS_USER_DEFINED_EVENT as long as the atoms are
+  // true even when aEvent->mMessage == eUnidentifiedEvent and
+  // aListener=>mEventMessage != eUnidentifiedEvent as long as the atoms are
   // the same
   if (aListener->mAllEvents) {
     return true;
   }
-  if (aEvent->mMessage == NS_USER_DEFINED_EVENT) {
+  if (aEvent->mMessage == eUnidentifiedEvent) {
     if (mIsMainThreadELM) {
       return aListener->mTypeAtom == aEvent->userType;
     }
     return aListener->mTypeString.Equals(aEvent->typeString);
   }
   MOZ_ASSERT(mIsMainThreadELM);
   return aListener->mEventMessage == aEvent->mMessage;
 }
--- a/dom/events/EventListenerManager.h
+++ b/dom/events/EventListenerManager.h
@@ -337,17 +337,17 @@ public:
     }
 
     if (!mMayHaveSystemGroupListeners && aEvent->mFlags.mInSystemGroup) {
       return;
     }
 
     // Check if we already know that there is no event listener for the event.
     if (mNoListenerForEvent == aEvent->mMessage &&
-        (mNoListenerForEvent != NS_USER_DEFINED_EVENT ||
+        (mNoListenerForEvent != eUnidentifiedEvent ||
          mNoListenerForEventAtom == aEvent->userType)) {
       return;
     }
     HandleEventInternal(aPresContext, aEvent, aDOMEvent, aCurrentTarget,
                         aEventStatus);
   }
 
   /**
--- a/dom/events/EventNameList.h
+++ b/dom/events/EventNameList.h
@@ -290,21 +290,21 @@ EVENT(mouseover,
       eMouseOver,
       EventNameType_All,
       eMouseEventClass)
 EVENT(mouseup,
       eMouseUp,
       EventNameType_All,
       eMouseEventClass)
 EVENT(mozfullscreenchange,
-      NS_FULLSCREENCHANGE,
+      eFullscreenChange,
       EventNameType_HTML,
       eBasicEventClass)
 EVENT(mozfullscreenerror,
-      NS_FULLSCREENERROR,
+      eFullscreenError,
       EventNameType_HTML,
       eBasicEventClass)
 EVENT(mozpointerlockchange,
       NS_POINTERLOCKCHANGE,
       EventNameType_HTML,
       eBasicEventClass)
 EVENT(mozpointerlockerror,
       NS_POINTERLOCKERROR,
@@ -413,38 +413,38 @@ EVENT(volumechange,
       eVolumeChange,
       EventNameType_HTML,
       eBasicEventClass)
 EVENT(waiting,
       eWaiting,
       EventNameType_HTML,
       eBasicEventClass)
 EVENT(wheel,
-      NS_WHEEL_WHEEL,
+      eWheel,
       EventNameType_All,
       eWheelEventClass)
 EVENT(copy,
       eCopy,
       EventNameType_HTMLXUL,
       eClipboardEventClass)
 EVENT(cut,
       eCut,
       EventNameType_HTMLXUL,
       eClipboardEventClass)
 EVENT(paste,
       ePaste,
       EventNameType_HTMLXUL,
       eClipboardEventClass)
 // Gecko-specific extensions that apply to elements
 EVENT(beforescriptexecute,
-      NS_BEFORE_SCRIPT_EXECUTE,
+      eBeforeScriptExecute,
       EventNameType_HTMLXUL,
       eBasicEventClass)
 EVENT(afterscriptexecute,
-      NS_AFTER_SCRIPT_EXECUTE,
+      eAfterScriptExecute,
       EventNameType_HTMLXUL,
       eBasicEventClass)
 
 FORWARDED_EVENT(blur,
                 eBlur,
                 EventNameType_HTMLXUL,
                 eFocusEventClass)
 ERROR_EVENT(error,
@@ -628,26 +628,26 @@ NON_IDL_EVENT(DOMFocusIn,
               EventNameType_HTMLXUL,
               eUIEventClass)
 NON_IDL_EVENT(DOMFocusOut,
               eLegacyDOMFocusOut,
               EventNameType_HTMLXUL,
               eUIEventClass)
                                   
 NON_IDL_EVENT(DOMMouseScroll,
-              NS_MOUSE_SCROLL,
+              eLegacyMouseLineOrPageScroll,
               EventNameType_HTMLXUL,
               eMouseScrollEventClass)
 NON_IDL_EVENT(MozMousePixelScroll,
-              NS_MOUSE_PIXEL_SCROLL,
+              eLegacyMousePixelScroll,
               EventNameType_HTMLXUL,
               eMouseScrollEventClass)
                                                 
 NON_IDL_EVENT(open,
-              NS_OPEN,
+              eOpen,
               EventNameType_None,
               eBasicEventClass)
 
 NON_IDL_EVENT(dataavailable,
               NS_MEDIARECORDER_DATAAVAILABLE,
               EventNameType_None,
               eBasicEventClass)
 
@@ -801,17 +801,17 @@ NON_IDL_EVENT(repeat,
               eBasicEventClass)
 #endif
 NON_IDL_EVENT(repeatEvent,
               NS_SMIL_REPEAT,
               EventNameType_None,
               eSMILTimeEventClass)
 
 NON_IDL_EVENT(MozAfterPaint,
-              NS_AFTERPAINT,
+              eAfterPaint,
               EventNameType_None,
               eBasicEventClass)
 
 NON_IDL_EVENT(MozScrolledAreaChanged,
               NS_SCROLLEDAREACHANGED,
               EventNameType_None,
               eScrollAreaEventClass)
 
@@ -904,25 +904,25 @@ NON_IDL_EVENT(MozEdgeUICompleted,
               EventNameType_None,
               eSimpleGestureEventClass)
 
 NON_IDL_EVENT(transitionend,
               NS_TRANSITION_END,
               EventNameType_None,
               eTransitionEventClass)
 NON_IDL_EVENT(animationstart,
-              NS_ANIMATION_START,
+              eAnimationStart,
               EventNameType_None,
               eAnimationEventClass)
 NON_IDL_EVENT(animationend,
-              NS_ANIMATION_END,
+              eAnimationEnd,
               EventNameType_None,
               eAnimationEventClass)
 NON_IDL_EVENT(animationiteration,
-              NS_ANIMATION_ITERATION,
+              eAnimationIteration,
               EventNameType_None,
               eAnimationEventClass)
 
 NON_IDL_EVENT(audioprocess,
               NS_AUDIO_PROCESS,
               EventNameType_None,
               eBasicEventClass)
 
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -706,29 +706,29 @@ EventStateManager::PreHandleEvent(nsPres
       //       TextComposition::IsComposing() is false even before
       //       compositionend if there is no composing string.
       WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
       nsRefPtr<TextComposition> composition =
         IMEStateManager::GetTextCompositionFor(keyEvent);
       keyEvent->mIsComposing = !!composition;
     }
     break;
-  case NS_WHEEL_WHEEL:
-  case NS_WHEEL_START:
-  case NS_WHEEL_STOP:
+  case eWheel:
+  case eWheelOperationStart:
+  case eWheelOperationEnd:
     {
       NS_ASSERTION(aEvent->mFlags.mIsTrusted,
                    "Untrusted wheel event shouldn't be here");
 
       nsIContent* content = GetFocusedContent();
       if (content) {
         mCurrentTargetContent = content;
       }
 
-      if (aEvent->mMessage != NS_WHEEL_WHEEL) {
+      if (aEvent->mMessage != eWheel) {
         break;
       }
 
       WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
       WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent);
 
       // If we won't dispatch a DOM event for this event, nothing to do anymore.
       if (!wheelEvent->IsAllowedToDispatchDOMEvent()) {
@@ -742,70 +742,66 @@ EventStateManager::PreHandleEvent(nsPres
       DeltaAccumulator::GetInstance()->
         InitLineOrPageDelta(aTargetFrame, this, wheelEvent);
     }
     break;
   case eSetSelection:
     IMEStateManager::HandleSelectionEvent(aPresContext, GetFocusedContent(),
                                           aEvent->AsSelectionEvent());
     break;
-  case NS_CONTENT_COMMAND_CUT:
-  case NS_CONTENT_COMMAND_COPY:
-  case NS_CONTENT_COMMAND_PASTE:
-  case NS_CONTENT_COMMAND_DELETE:
-  case NS_CONTENT_COMMAND_UNDO:
-  case NS_CONTENT_COMMAND_REDO:
-  case NS_CONTENT_COMMAND_PASTE_TRANSFERABLE:
-    {
-      DoContentCommandEvent(aEvent->AsContentCommandEvent());
-    }
+  case eContentCommandCut:
+  case eContentCommandCopy:
+  case eContentCommandPaste:
+  case eContentCommandDelete:
+  case eContentCommandUndo:
+  case eContentCommandRedo:
+  case eContentCommandPasteTransferable:
+    DoContentCommandEvent(aEvent->AsContentCommandEvent());
     break;
-  case NS_CONTENT_COMMAND_SCROLL:
-    {
-      DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
-    }
+  case eContentCommandScroll:
+    DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
     break;
   case NS_COMPOSITION_START:
     if (aEvent->mFlags.mIsTrusted) {
       // If the event is trusted event, set the selected text to data of
       // composition event.
       WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
-      WidgetQueryContentEvent selectedText(true, NS_QUERY_SELECTED_TEXT,
+      WidgetQueryContentEvent selectedText(true, eQuerySelectedText,
                                            compositionEvent->widget);
       HandleQueryContentEvent(&selectedText);
       NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text");
       compositionEvent->mData = selectedText.mReply.mString;
     }
     break;
   default:
     break;
   }
   return NS_OK;
 }
 
 void
 EventStateManager::HandleQueryContentEvent(WidgetQueryContentEvent* aEvent)
 {
   switch (aEvent->mMessage) {
-    case NS_QUERY_SELECTED_TEXT:
-    case NS_QUERY_TEXT_CONTENT:
-    case NS_QUERY_CARET_RECT:
+    case eQuerySelectedText:
+    case eQueryTextContent:
+    case eQueryCaretRect:
     case NS_QUERY_TEXT_RECT:
-    case NS_QUERY_EDITOR_RECT:
+    case eQueryEditorRect:
       if (!IsTargetCrossProcess(aEvent)) {
         break;
       }
       // Will not be handled locally, remote the event
       GetCrossProcessTarget()->HandleQueryContentEvent(*aEvent);
       return;
     // Following events have not been supported in e10s mode yet.
-    case NS_QUERY_CONTENT_STATE:
-    case NS_QUERY_SELECTION_AS_TRANSFERABLE:
-    case NS_QUERY_CHARACTER_AT_POINT:
-    case NS_QUERY_DOM_WIDGET_HITTEST:
+    case eQueryContentState:
+    case eQuerySelectionAsTransferable:
+    case eQueryCharacterAtPoint:
+    case eQueryDOMWidgetHittest:
       break;
     default:
       return;
   }
 
   // If there is an IMEContentObserver, we need to handle QueryContentEvent
   // with it.
   if (mIMEContentObserver) {
@@ -2188,18 +2184,18 @@ EventStateManager::SendLineScrollEvent(n
     targetContent = GetFocusedContent();
   if (!targetContent)
     return;
 
   while (targetContent->IsNodeOfType(nsINode::eTEXT)) {
     targetContent = targetContent->GetParent();
   }
 
-  WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted, NS_MOUSE_SCROLL,
-                               aEvent->widget);
+  WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted,
+                               eLegacyMouseLineOrPageScroll, aEvent->widget);
   event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
   event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
   event.refPoint = aEvent->refPoint;
   event.widget = aEvent->widget;
   event.time = aEvent->time;
   event.timeStamp = aEvent->timeStamp;
   event.modifiers = aEvent->modifiers;
   event.buttons = aEvent->buttons;
@@ -2228,18 +2224,18 @@ EventStateManager::SendPixelScrollEvent(
     if (!targetContent)
       return;
   }
 
   while (targetContent->IsNodeOfType(nsINode::eTEXT)) {
     targetContent = targetContent->GetParent();
   }
 
-  WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted, NS_MOUSE_PIXEL_SCROLL,
-                               aEvent->widget);
+  WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted,
+                               eLegacyMousePixelScroll, aEvent->widget);
   event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
   event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
   event.refPoint = aEvent->refPoint;
   event.widget = aEvent->widget;
   event.time = aEvent->time;
   event.timeStamp = aEvent->timeStamp;
   event.modifiers = aEvent->modifiers;
   event.buttons = aEvent->buttons;
@@ -3007,31 +3003,31 @@ EventStateManager::PostHandleEvent(nsPre
 
       nsIPresShell *shell = presContext->GetPresShell();
       if (shell) {
         nsRefPtr<nsFrameSelection> frameSelection = shell->FrameSelection();
         frameSelection->SetDragState(false);
       }
     }
     break;
-  case NS_WHEEL_STOP:
+  case eWheelOperationEnd:
     {
       MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
       ScrollbarsForWheel::MayInactivate();
       WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
       nsIScrollableFrame* scrollTarget =
         ComputeScrollTarget(aTargetFrame, wheelEvent,
                             COMPUTE_DEFAULT_ACTION_TARGET);
       if (scrollTarget) {
         scrollTarget->ScrollSnap();
       }
     }
     break;
-  case NS_WHEEL_WHEEL:
-  case NS_WHEEL_START:
+  case eWheel:
+  case eWheelOperationStart:
     {
       MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
 
       if (*aStatus == nsEventStatus_eConsumeNoDefault) {
         ScrollbarsForWheel::Inactivate();
         break;
       }
 
@@ -3047,17 +3043,17 @@ EventStateManager::PostHandleEvent(nsPre
       }
       switch (action) {
         case WheelPrefs::ACTION_SCROLL: {
           // For scrolling of default action, we should honor the mouse wheel
           // transaction.
 
           ScrollbarsForWheel::PrepareToScrollText(this, aTargetFrame, wheelEvent);
 
-          if (aEvent->mMessage != NS_WHEEL_WHEEL ||
+          if (aEvent->mMessage != eWheel ||
               (!wheelEvent->deltaX && !wheelEvent->deltaY)) {
             break;
           }
 
           nsIScrollableFrame* scrollTarget =
             ComputeScrollTarget(aTargetFrame, wheelEvent,
                                 COMPUTE_DEFAULT_ACTION_TARGET);
 
@@ -3080,28 +3076,28 @@ EventStateManager::PostHandleEvent(nsPre
             DoScrollText(scrollTarget, wheelEvent);
           } else {
             WheelTransaction::EndTransaction();
             ScrollbarsForWheel::Inactivate();
           }
           break;
         }
         case WheelPrefs::ACTION_HISTORY: {
-          // If this event doesn't cause NS_MOUSE_SCROLL event or the direction
-          // is oblique, don't perform history back/forward.
+          // If this event doesn't cause eLegacyMouseLineOrPageScroll event or
+          // the direction is oblique, don't perform history back/forward.
           int32_t intDelta = wheelEvent->GetPreferredIntDelta();
           if (!intDelta) {
             break;
           }
           DoScrollHistory(intDelta);
           break;
         }
         case WheelPrefs::ACTION_ZOOM: {
-          // If this event doesn't cause NS_MOUSE_SCROLL event or the direction
-          // is oblique, don't perform zoom in/out.
+          // If this event doesn't cause eLegacyMouseLineOrPageScroll event or
+          // the direction is oblique, don't perform zoom in/out.
           int32_t intDelta = wheelEvent->GetPreferredIntDelta();
           if (!intDelta) {
             break;
           }
           DoScrollZoom(aTargetFrame, intDelta);
           break;
         }
         case WheelPrefs::ACTION_NONE:
@@ -5034,35 +5030,35 @@ EventStateManager::DoContentCommandEvent
   NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
   nsCOMPtr<nsPIDOMWindow> window(mDocument->GetWindow());
   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
   NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
   const char* cmd;
   switch (aEvent->mMessage) {
-    case NS_CONTENT_COMMAND_CUT:
+    case eContentCommandCut:
       cmd = "cmd_cut";
       break;
-    case NS_CONTENT_COMMAND_COPY:
+    case eContentCommandCopy:
       cmd = "cmd_copy";
       break;
-    case NS_CONTENT_COMMAND_PASTE:
+    case eContentCommandPaste:
       cmd = "cmd_paste";
       break;
-    case NS_CONTENT_COMMAND_DELETE:
+    case eContentCommandDelete:
       cmd = "cmd_delete";
       break;
-    case NS_CONTENT_COMMAND_UNDO:
+    case eContentCommandUndo:
       cmd = "cmd_undo";
       break;
-    case NS_CONTENT_COMMAND_REDO:
+    case eContentCommandRedo:
       cmd = "cmd_redo";
       break;
-    case NS_CONTENT_COMMAND_PASTE_TRANSFERABLE:
+    case eContentCommandPasteTransferable:
       cmd = "cmd_pasteTransferable";
       break;
     default:
       return NS_ERROR_NOT_IMPLEMENTED;
   }
   nsCOMPtr<nsIController> controller;
   nsresult rv = root->GetControllerForCommand(cmd, getter_AddRefs(controller));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -5072,17 +5068,17 @@ EventStateManager::DoContentCommandEvent
     aEvent->mIsEnabled = false;
   } else {
     bool canDoIt;
     rv = controller->IsCommandEnabled(cmd, &canDoIt);
     NS_ENSURE_SUCCESS(rv, rv);
     aEvent->mIsEnabled = canDoIt;
     if (canDoIt && !aEvent->mOnlyEnabledCheck) {
       switch (aEvent->mMessage) {
-        case NS_CONTENT_COMMAND_PASTE_TRANSFERABLE: {
+        case eContentCommandPasteTransferable: {
           nsCOMPtr<nsICommandController> commandController = do_QueryInterface(controller);
           NS_ENSURE_STATE(commandController);
 
           nsCOMPtr<nsICommandParams> params = do_CreateInstance("@mozilla.org/embedcomp/command-params;1", &rv);
           NS_ENSURE_SUCCESS(rv, rv);
 
           rv = params->SetISupportsValue("transferable", aEvent->mTransferable);
           NS_ENSURE_SUCCESS(rv, rv);
@@ -5571,17 +5567,17 @@ EventStateManager::WheelPrefs::HasUserPr
 
   return mMultiplierX[index] != 1.0 ||
          mMultiplierY[index] != 1.0;
 }
 
 bool
 EventStateManager::WheelEventIsScrollAction(WidgetWheelEvent* aEvent)
 {
-  return aEvent->mMessage == NS_WHEEL_WHEEL &&
+  return aEvent->mMessage == eWheel &&
          WheelPrefs::GetInstance()->ComputeActionFor(aEvent) == WheelPrefs::ACTION_SCROLL;
 }
 
 bool
 EventStateManager::WheelEventNeedsDeltaMultipliers(WidgetWheelEvent* aEvent)
 {
   return WheelPrefs::GetInstance()->HasUserPrefsForDelta(aEvent);
 }
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -104,18 +104,18 @@ public:
    * DOM and frame processing.
    */
   nsresult PostHandleEvent(nsPresContext* aPresContext,
                            WidgetEvent* aEvent,
                            nsIFrame* aTargetFrame,
                            nsEventStatus* aStatus);
 
   /**
-   * DispatchLegacyMouseScrollEvents() dispatches NS_MOUSE_SCROLL event and
-   * NS_MOUSE_PIXEL_SCROLL event for compatiblity with old Gecko.
+   * DispatchLegacyMouseScrollEvents() dispatches eLegacyMouseLineOrPageScroll
+   * event and eLegacyMousePixelScroll event for compatibility with old Gecko.
    */
   void DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame,
                                        WidgetWheelEvent* aEvent,
                                        nsEventStatus* aStatus);
 
   void NotifyDestroyPresContext(nsPresContext* aPresContext);
   void SetPresContext(nsPresContext* aPresContext);
   void ClearFrameRefs(nsIFrame* aFrame);
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -46,36 +46,36 @@ ToChar(bool aBool)
 {
   return aBool ? "true" : "false";
 }
 
 static const char*
 ToChar(EventMessage aEventMessage)
 {
   switch (aEventMessage) {
-    case NS_QUERY_SELECTED_TEXT:
-      return "NS_QUERY_SELECTED_TEXT";
-    case NS_QUERY_TEXT_CONTENT:
-      return "NS_QUERY_TEXT_CONTENT";
-    case NS_QUERY_CARET_RECT:
-      return "NS_QUERY_CARET_RECT";
+    case eQuerySelectedText:
+      return "eQuerySelectedText";
+    case eQueryTextContent:
+      return "eQueryTextContent";
+    case eQueryCaretRect:
+      return "eQueryCaretRect";
     case NS_QUERY_TEXT_RECT:
       return "NS_QUERY_TEXT_RECT";
-    case NS_QUERY_EDITOR_RECT:
-      return "NS_QUERY_EDITOR_RECT";
-    case NS_QUERY_CONTENT_STATE:
-      return "NS_QUERY_CONTENT_STATE";
-    case NS_QUERY_SELECTION_AS_TRANSFERABLE:
-      return "NS_QUERY_SELECTION_AS_TRANSFERABLE";
-    case NS_QUERY_CHARACTER_AT_POINT:
-      return "NS_QUERY_CHARACTER_AT_POINT";
-    case NS_QUERY_DOM_WIDGET_HITTEST:
-      return "NS_QUERY_DOM_WIDGET_HITTEST";
+    case eQueryEditorRect:
+      return "eQueryEditorRect";
+    case eQueryContentState:
+      return "eQueryContentState";
+    case eQuerySelectionAsTransferable:
+      return "eQuerySelectionAsTransferable";
+    case eQueryCharacterAtPoint:
+      return "eQueryCharacterAtPoint";
+    case eQueryDOMWidgetHittest:
+      return "eQueryDOMWidgetHittest";
     default:
-      return "Unsupprted message";
+      return "Unsupported message";
   }
 }
 
 class WritingModeToString final : public nsAutoCString
 {
 public:
   explicit WritingModeToString(const WritingMode& aWritingMode)
   {
@@ -564,18 +564,17 @@ nsresult
 IMEContentObserver::HandleQueryContentEvent(WidgetQueryContentEvent* aEvent)
 {
   MOZ_LOG(sIMECOLog, LogLevel::Debug,
     ("IMECO: 0x%p IMEContentObserver::HandleQueryContentEvent(aEvent={ "
      "mMessage=%s })", this, ToChar(aEvent->mMessage)));
 
   // If the instance has cache, it should use the cached selection which was
   // sent to the widget.
-  if (aEvent->mMessage == NS_QUERY_SELECTED_TEXT &&
-      aEvent->mUseNativeLineBreak &&
+  if (aEvent->mMessage == eQuerySelectedText && aEvent->mUseNativeLineBreak &&
       mSelectionData.IsValid()) {
     aEvent->mReply.mContentsRoot = mRootContent;
     aEvent->mReply.mHasSelection = !mSelectionData.IsCollapsed();
     aEvent->mReply.mOffset = mSelectionData.mOffset;
     aEvent->mReply.mString = mSelectionData.String();
     aEvent->mReply.mWritingMode = mSelectionData.GetWritingMode();
     aEvent->mReply.mReversed = mSelectionData.mReversed;
     aEvent->mSucceeded = true;
@@ -616,17 +615,17 @@ IMEContentObserver::OnMouseButtonEvent(n
       return false;
   }
   if (NS_WARN_IF(!mWidget) || NS_WARN_IF(mWidget->Destroyed())) {
     return false;
   }
 
   nsRefPtr<IMEContentObserver> kungFuDeathGrip(this);
 
-  WidgetQueryContentEvent charAtPt(true, NS_QUERY_CHARACTER_AT_POINT,
+  WidgetQueryContentEvent charAtPt(true, eQueryCharacterAtPoint,
                                    aMouseEvent->widget);
   charAtPt.refPoint = aMouseEvent->refPoint;
   ContentEventHandler handler(aPresContext);
   handler.OnQueryCharacterAtPoint(&charAtPt);
   if (NS_WARN_IF(!charAtPt.mSucceeded) ||
       charAtPt.mReply.mOffset == WidgetQueryContentEvent::NOT_FOUND) {
     return false;
   }
@@ -1104,17 +1103,17 @@ IMEContentObserver::UpdateSelectionCache
   if (!mUpdatePreference.WantSelectionChange()) {
     return false;
   }
 
   mSelectionData.Clear();
 
   // XXX Cannot we cache some information for reducing the cost to compute
   //     selection offset and writing mode?
-  WidgetQueryContentEvent selection(true, NS_QUERY_SELECTED_TEXT, mWidget);
+  WidgetQueryContentEvent selection(true, eQuerySelectedText, mWidget);
   ContentEventHandler handler(GetPresContext());
   handler.OnQuerySelectedText(&selection);
   if (NS_WARN_IF(!selection.mSucceeded)) {
     return false;
   }
 
   mFocusedWidget = selection.mReply.mFocusedWidget;
   mSelectionData.mOffset = selection.mReply.mOffset;
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -410,19 +410,17 @@ TextComposition::NotityUpdateComposition
   nsEventStatus status;
 
   // When compositon start, notify the rect of first offset character.
   // When not compositon start, notify the rect of selected composition
   // string if compositionchange event.
   if (aCompositionEvent->mMessage == NS_COMPOSITION_START) {
     nsCOMPtr<nsIWidget> widget = mPresContext->GetRootWidget();
     // Update composition start offset
-    WidgetQueryContentEvent selectedTextEvent(true,
-                                              NS_QUERY_SELECTED_TEXT,
-                                              widget);
+    WidgetQueryContentEvent selectedTextEvent(true, eQuerySelectedText, widget);
     widget->DispatchEvent(&selectedTextEvent, status);
     if (selectedTextEvent.mSucceeded) {
       mCompositionStartOffset = selectedTextEvent.mReply.mOffset;
     } else {
       // Unknown offset
       NS_WARNING("Cannot get start offset of IME composition");
       mCompositionStartOffset = 0;
     }
@@ -610,18 +608,17 @@ TextComposition::CompositionEventDispatc
     return NS_OK; // cannot dispatch any events anymore
   }
 
   nsRefPtr<nsPresContext> presContext = mTextComposition->mPresContext;
   nsEventStatus status = nsEventStatus_eIgnore;
   switch (mEventMessage) {
     case NS_COMPOSITION_START: {
       WidgetCompositionEvent compStart(true, NS_COMPOSITION_START, widget);
-      WidgetQueryContentEvent selectedText(true, NS_QUERY_SELECTED_TEXT,
-                                           widget);
+      WidgetQueryContentEvent selectedText(true, eQuerySelectedText, widget);
       ContentEventHandler handler(presContext);
       handler.OnQuerySelectedText(&selectedText);
       NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text");
       compStart.mData = selectedText.mReply.mString;
       compStart.mFlags.mIsSynthesizedForTests =
         mTextComposition->IsSynthesizedForTests();
       IMEStateManager::DispatchCompositionEvent(mEventTarget, presContext,
                                                 &compStart, &status, nullptr,
--- a/dom/events/WheelHandlingHelper.cpp
+++ b/dom/events/WheelHandlingHelper.cpp
@@ -89,17 +89,17 @@ WheelTransaction::OwnScrollbars(bool aOw
   sOwnScrollbars = aOwn;
 }
 
 /* static */ void
 WheelTransaction::BeginTransaction(nsIFrame* aTargetFrame,
                                    WidgetWheelEvent* aEvent)
 {
   NS_ASSERTION(!sTargetFrame, "previous transaction is not finished!");
-  MOZ_ASSERT(aEvent->mMessage == NS_WHEEL_WHEEL,
+  MOZ_ASSERT(aEvent->mMessage == eWheel,
              "Transaction must be started with a wheel event");
   ScrollbarsForWheel::OwnWheelTransaction(false);
   sTargetFrame = aTargetFrame;
   sScrollSeriesCounter = 0;
   if (!UpdateTransaction(aEvent)) {
     NS_ERROR("BeginTransaction is called even cannot scroll the frame");
     EndTransaction();
   }
@@ -171,17 +171,17 @@ WheelTransaction::OnEvent(WidgetEvent* a
     // was not fired by timer, then the scroll event will scroll old frame,
     // therefore, we should call OnTimeout here and ensure to finish the old
     // transaction.
     OnTimeout(nullptr, nullptr);
     return;
   }
 
   switch (aEvent->mMessage) {
-    case NS_WHEEL_WHEEL:
+    case eWheel:
       if (sMouseMoved != 0 &&
           OutOfTime(sMouseMoved, GetIgnoreMoveDelayTime())) {
         // Terminate the current mousewheel transaction if the mouse moved more
         // than ignoremovedelay milliseconds ago
         EndTransaction();
       }
       return;
     case eMouseMove:
@@ -410,17 +410,17 @@ nsWeakFrame ScrollbarsForWheel::sActivat
 bool ScrollbarsForWheel::sHadWheelStart = false;
 bool ScrollbarsForWheel::sOwnWheelTransaction = false;
 
 /* static */ void
 ScrollbarsForWheel::PrepareToScrollText(EventStateManager* aESM,
                                         nsIFrame* aTargetFrame,
                                         WidgetWheelEvent* aEvent)
 {
-  if (aEvent->mMessage == NS_WHEEL_START) {
+  if (aEvent->mMessage == eWheelOperationStart) {
     WheelTransaction::OwnScrollbars(false);
     if (!IsActive()) {
       TemporarilyActivateAllPossibleScrollTargets(aESM, aTargetFrame, aEvent);
       sHadWheelStart = true;
     }
   } else {
     DeactivateAllTemporarilyActivatedScrollTargets();
   }
--- a/dom/events/WheelHandlingHelper.h
+++ b/dom/events/WheelHandlingHelper.h
@@ -90,18 +90,18 @@ protected:
   static const DeltaValues directions[kNumberOfTargets];
   static nsWeakFrame sActiveOwner;
   static nsWeakFrame sActivatedScrollTargets[kNumberOfTargets];
   static bool sHadWheelStart;
   static bool sOwnWheelTransaction;
 
 
   /**
-   * These two methods are called upon NS_WHEEL_START/NS_WHEEL_STOP events
-   * to show/hide the right scrollbars.
+   * These two methods are called upon eWheelOperationStart/eWheelOperationEnd
+   * events to show/hide the right scrollbars.
    */
   static void TemporarilyActivateAllPossibleScrollTargets(
                 EventStateManager* aESM,
                 nsIFrame* aTargetFrame,
                 WidgetWheelEvent* aEvent);
   static void DeactivateAllTemporarilyActivatedScrollTargets();
 };
 
--- a/dom/fetch/ChannelInfo.cpp
+++ b/dom/fetch/ChannelInfo.cpp
@@ -79,17 +79,17 @@ ChannelInfo::InitFromChromeGlobal(nsIGlo
     nsContentUtils::IsSystemPrincipal(aGlobal->PrincipalOrNull()));
 
   mSecurityInfo.Truncate();
   mRedirected = false;
   mInited = true;
 }
 
 void
-ChannelInfo::InitFromIPCChannelInfo(const ipc::IPCChannelInfo& aChannelInfo)
+ChannelInfo::InitFromIPCChannelInfo(const mozilla::ipc::IPCChannelInfo& aChannelInfo)
 {
   MOZ_ASSERT(!mInited, "Cannot initialize the object twice");
 
   mSecurityInfo = aChannelInfo.securityInfo();
   mRedirectedURISpec = aChannelInfo.redirectedURI();
   mRedirected = aChannelInfo.redirected();
 
   mInited = true;
@@ -167,17 +167,17 @@ ChannelInfo::ResurrectInfoOnChannel(nsIC
       }
       static_cast<nsJARChannel*>(jarChannel.get())->OverrideURI(redirectedURI);
     }
   }
 
   return NS_OK;
 }
 
-ipc::IPCChannelInfo
+mozilla::ipc::IPCChannelInfo
 ChannelInfo::AsIPCChannelInfo() const
 {
   // This may be called when mInited is false, for example if we try to store
   // a synthesized Response object into the Cache.  Uninitialized and empty
   // ChannelInfo objects are indistinguishable at the IPC level, so this is
   // fine.
 
   IPCChannelInfo ipcInfo;
--- a/dom/filehandle/ActorsChild.h
+++ b/dom/filehandle/ActorsChild.h
@@ -84,18 +84,18 @@ class BackgroundFileHandleChild
   // function is called.
   nsRefPtr<FileHandleBase> mTemporaryStrongFileHandle;
 
   // mFileHandle is weak and is valid until the NoteActorDestroyed() member
   // function is called.
   FileHandleBase* mFileHandle;
 
 public:
-  BackgroundFileHandleChild(DEBUGONLY(PRThread* aOwningThread,)
-                            FileHandleBase* aFileHandle);
+  explicit BackgroundFileHandleChild(DEBUGONLY(PRThread* aOwningThread,)
+                                     FileHandleBase* aFileHandle);
 
   void
   SendDeleteMeInternal();
 
 private:
   ~BackgroundFileHandleChild();
 
   void
@@ -131,18 +131,18 @@ class BackgroundFileRequestChild final
   friend class FileHandleBase;
 
   nsRefPtr<FileRequestBase> mFileRequest;
   nsRefPtr<FileHandleBase> mFileHandle;
   bool mActorDestroyed;
 
 private:
   // Only created by FileHandleBase.
-  BackgroundFileRequestChild(DEBUGONLY(PRThread* aOwningThread,)
-                             FileRequestBase* aFileRequest);
+  explicit BackgroundFileRequestChild(DEBUGONLY(PRThread* aOwningThread,)
+                                      FileRequestBase* aFileRequest);
 
   // Only destroyed by BackgroundFileHandleChild.
   ~BackgroundFileRequestChild();
 
   void
   HandleResponse(nsresult aResponse);
 
   void
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -464,22 +464,18 @@ HTMLImageElement::AfterSetAttr(int32_t a
 nsresult
 HTMLImageElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
 {
   // If we are a map and get a mouse click, don't let it be handled by
   // the Generic Element as this could cause a click event to fire
   // twice, once by the image frame for the map and once by the Anchor
   // element. (bug 39723)
   WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
-  if (mouseEvent && mouseEvent->IsLeftClickEvent()) {
-    bool isMap = false;
-    GetIsMap(&isMap);
-    if (isMap) {
-      aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
-    }
+  if (mouseEvent && mouseEvent->IsLeftClickEvent() && IsMap()) {
+    aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
   }
   return nsGenericHTMLElement::PreHandleEvent(aVisitor);
 }
 
 bool
 HTMLImageElement::IsHTMLFocusable(bool aWithMouse,
                                   bool *aIsFocusable, int32_t *aTabIndex)
 {
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -2476,16 +2476,20 @@ HTMLInputElement::FireChangeEventIfNeede
 
 FileList*
 HTMLInputElement::GetFiles()
 {
   if (mType != NS_FORM_INPUT_FILE) {
     return nullptr;
   }
 
+  if (HasAttr(kNameSpaceID_None, nsGkAtoms::directory)) {
+    return nullptr;
+  }
+
   if (!mFileList) {
     mFileList = new FileList(static_cast<nsIContent*>(this));
     UpdateFileList();
   }
 
   return mFileList;
 }
 
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -719,16 +719,17 @@ void HTMLMediaElement::AbortExistingLoad
   if (mDecoder) {
     fireTimeUpdate = mDecoder->GetCurrentTime() != 0.0;
     ShutdownDecoder();
   }
   if (mSrcStream) {
     EndSrcMediaStreamPlayback();
   }
 
+  RemoveMediaElementFromURITable();
   mLoadingSrc = nullptr;
   mMediaSource = nullptr;
 
   if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING ||
       mNetworkState == nsIDOMHTMLMediaElement::NETWORK_IDLE)
   {
     DispatchAsyncEvent(NS_LITERAL_STRING("abort"));
   }
@@ -927,16 +928,17 @@ void HTMLMediaElement::SelectResource()
   } else if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
     nsCOMPtr<nsIURI> uri;
     nsresult rv = NewURIFromString(src, getter_AddRefs(uri));
     if (NS_SUCCEEDED(rv)) {
       LOG(LogLevel::Debug, ("%p Trying load from src=%s", this, NS_ConvertUTF16toUTF8(src).get()));
       NS_ASSERTION(!mIsLoadingFromSourceChildren,
         "Should think we're not loading from source children by default");
 
+      RemoveMediaElementFromURITable();
       mLoadingSrc = uri;
       mMediaSource = mSrcMediaSource;
       UpdatePreloadAction();
       if (mPreloadAction == HTMLMediaElement::PRELOAD_NONE &&
           !IsMediaStreamURI(mLoadingSrc)) {
         // preload:none media, suspend the load here before we make any
         // network requests.
         SuspendLoad();
@@ -1065,16 +1067,17 @@ void HTMLMediaElement::LoadFromSourceChi
     NewURIFromString(src, getter_AddRefs(uri));
     if (!uri) {
       DispatchAsyncSourceError(child);
       const char16_t* params[] = { src.get() };
       ReportLoadError("MediaLoadInvalidURI", params, ArrayLength(params));
       continue;
     }
 
+    RemoveMediaElementFromURITable();
     mLoadingSrc = uri;
     mMediaSource = childSrc->GetSrcMediaSource();
     NS_ASSERTION(mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING,
                  "Network state should be loading");
 
     if (mPreloadAction == HTMLMediaElement::PRELOAD_NONE &&
         !IsMediaStreamURI(mLoadingSrc)) {
       // preload:none media, suspend the load here before we make any
@@ -1939,36 +1942,53 @@ public:
 typedef nsTHashtable<MediaElementSetForURI> MediaElementURITable;
 // Elements in this table must have non-null mDecoder and mLoadingSrc, and those
 // can't change while the element is in the table. The table is keyed by
 // the element's mLoadingSrc. Each entry has a list of all elements with the
 // same mLoadingSrc.
 static MediaElementURITable* gElementTable;
 
 #ifdef DEBUG
+static bool
+URISafeEquals(nsIURI* a1, nsIURI* a2)
+{
+  if (!a1 || !a2) {
+    // Consider two empty URIs *not* equal!
+    return false;
+  }
+  bool equal = false;
+  nsresult rv = a1->Equals(a2, &equal);
+  return NS_SUCCEEDED(rv) && equal;
+}
 // Returns the number of times aElement appears in the media element table
 // for aURI. If this returns other than 0 or 1, there's a bug somewhere!
 static unsigned
 MediaElementTableCount(HTMLMediaElement* aElement, nsIURI* aURI)
 {
-  if (!gElementTable || !aElement || !aURI) {
-    return 0;
-  }
-  MediaElementSetForURI* entry = gElementTable->GetEntry(aURI);
-  if (!entry) {
+  if (!gElementTable || !aElement) {
     return 0;
   }
-  uint32_t count = 0;
-  for (uint32_t i = 0; i < entry->mElements.Length(); ++i) {
-    HTMLMediaElement* elem = entry->mElements[i];
-    if (elem == aElement) {
-      count++;
+  uint32_t uriCount = 0;
+  uint32_t otherCount = 0;
+  for (auto it = gElementTable->ConstIter(); !it.Done(); it.Next()) {
+    MediaElementSetForURI* entry = it.Get();
+    uint32_t count = 0;
+    for (const auto& elem : entry->mElements) {
+      if (elem == aElement) {
+        count++;
+      }
     }
-  }
-  return count;
+    if (URISafeEquals(aURI, entry->GetKey())) {
+      uriCount = count;
+    } else {
+      otherCount += count;
+    }
+  }
+  NS_ASSERTION(otherCount == 0, "Should not have entries for unknown URIs");
+  return uriCount;
 }
 #endif
 
 void
 HTMLMediaElement::AddMediaElementToURITable()
 {
   NS_ASSERTION(mDecoder && mDecoder->GetResource(), "Call this only with decoder Load called");
   NS_ASSERTION(MediaElementTableCount(this, mLoadingSrc) == 0,
@@ -1980,45 +2000,45 @@ HTMLMediaElement::AddMediaElementToURITa
   entry->mElements.AppendElement(this);
   NS_ASSERTION(MediaElementTableCount(this, mLoadingSrc) == 1,
     "Should have a single entry for element in element table after addition");
 }
 
 void
 HTMLMediaElement::RemoveMediaElementFromURITable()
 {
-  NS_ASSERTION(MediaElementTableCount(this, mLoadingSrc) == 1,
-    "Before remove, should have a single entry for element in element table");
-  NS_ASSERTION(mDecoder, "Don't call this without decoder!");
-  NS_ASSERTION(mLoadingSrc, "Can't have decoder without source!");
-  if (!gElementTable)
+  if (!mDecoder || !mLoadingSrc || !gElementTable) {
     return;
+  }
   MediaElementSetForURI* entry = gElementTable->GetEntry(mLoadingSrc);
-  if (!entry)
+  if (!entry) {
     return;
+  }
   entry->mElements.RemoveElement(this);
   if (entry->mElements.IsEmpty()) {
     gElementTable->RemoveEntry(mLoadingSrc);
     if (gElementTable->Count() == 0) {
       delete gElementTable;
       gElementTable = nullptr;
     }
   }
   NS_ASSERTION(MediaElementTableCount(this, mLoadingSrc) == 0,
     "After remove, should no longer have an entry in element table");
 }
 
 HTMLMediaElement*
 HTMLMediaElement::LookupMediaElementURITable(nsIURI* aURI)
 {
-  if (!gElementTable)
+  if (!gElementTable) {
     return nullptr;
+  }
   MediaElementSetForURI* entry = gElementTable->GetEntry(aURI);
-  if (!entry)
+  if (!entry) {
     return nullptr;
+  }
   for (uint32_t i = 0; i < entry->mElements.Length(); ++i) {
     HTMLMediaElement* elem = entry->mElements[i];
     bool equal;
     // Look for elements that have the same principal and CORS mode.
     // Ditto for anything else that could cause us to send different headers.
     if (NS_SUCCEEDED(elem->NodePrincipal()->Equals(NodePrincipal(), &equal)) && equal &&
         elem->mCORSMode == mCORSMode) {
       NS_ASSERTION(elem->mDecoder && elem->mDecoder->GetResource(), "Decoder gone");
@@ -3306,16 +3326,17 @@ void HTMLMediaElement::DecodeError()
   nsAutoString src;
   GetCurrentSrc(src);
   const char16_t* params[] = { src.get() };
   ReportLoadError("MediaLoadDecodeError", params, ArrayLength(params));
 
   if (mDecoder) {
     ShutdownDecoder();
   }
+  RemoveMediaElementFromURITable();
   mLoadingSrc = nullptr;
   mMediaSource = nullptr;
   if (mIsLoadingFromSourceChildren) {
     mError = nullptr;
     if (mSourceLoadCandidate) {
       DispatchAsyncSourceError(mSourceLoadCandidate);
       QueueLoadFromSourceTask();
     } else {
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -787,17 +787,17 @@ protected:
                               nsIStreamListener **aListener,
                               MediaDecoder* aCloneDonor);
 
   /**
    * Call this after setting up mLoadingSrc and mDecoder.
    */
   void AddMediaElementToURITable();
   /**
-   * Call this before clearing mLoadingSrc.
+   * Call this before modifying mLoadingSrc.
    */
   void RemoveMediaElementFromURITable();
   /**
    * Call this to find a media element with the same NodePrincipal and mLoadingSrc
    * set to aURI, and with a decoder on which Load() has been called.
    */
   HTMLMediaElement* LookupMediaElementURITable(nsIURI* aURI);
 
--- a/dom/html/test/file_fullscreen-ancestor-stacking-context.html
+++ b/dom/html/test/file_fullscreen-ancestor-stacking-context.html
@@ -34,23 +34,17 @@ const gPropertyTestDecls = {
 //"domPropName": "prop-name: some-non-initial-value",
   "zIndex":      "z-index: 5",
   "opacity":     "opacity: 0.8",
   "mask":        "mask: url(#mymask)",
   "clip":        "clip: rect(0 0 0 0)",
   "clipPath":    "clip-path: url(#mypath)",
   "filter":      "filter: url(#myfilter)",
   "transform":   "transform: translate(0)",
-// XXXdholbert The "will-change" line in full-screen-override.css is only
-// parsed and honored if "layout.css.will-change.enabled" is turned on
-// *at startup time* (so, flipping it here with SpecialPowers wouldn't be
-// sufficient). So, we won't get the right behavior for 'will-change' here
-// until it's enabled by default (bug 961871). This line can be uncommented
-// when that happens:
-//  "willChange": "will-change: transform"
+  "willChange":  "will-change: transform"
 };
 
 // populated in populateInitialVals
 let gPropertyInitialVals = {};
 
 function begin() {
   populateInitialVals();
 
--- a/dom/inputmethod/Keyboard.jsm
+++ b/dom/inputmethod/Keyboard.jsm
@@ -109,34 +109,35 @@ this.Keyboard = {
       mm = frameLoader.messageManager;
     }
 
     if (topic == 'oop-frameloader-crashed' ||
 	topic == 'message-manager-close') {
       if (this.formMM == mm) {
         // The application has been closed unexpectingly. Let's tell the
         // keyboard app that the focus has been lost.
-        this.sendToKeyboard('Keyboard:FocusChange', { 'type': 'blur' });
+        this.sendToKeyboard('Keyboard:Blur', {});
         // Notify system app to hide keyboard.
         SystemAppProxy.dispatchEvent({
           type: 'inputmethod-contextchange',
           inputType: 'blur'
         });
       }
     } else {
       // Ignore notifications that aren't from a BrowserOrApp
       if (!frameLoader.ownerIsBrowserOrAppFrame) {
         return;
       }
       this.initFormsFrameScript(mm);
     }
   },
 
   initFormsFrameScript: function(mm) {
-    mm.addMessageListener('Forms:Input', this);
+    mm.addMessageListener('Forms:Focus', this);
+    mm.addMessageListener('Forms:Blur', this);
     mm.addMessageListener('Forms:SelectionChange', this);
     mm.addMessageListener('Forms:GetText:Result:OK', this);
     mm.addMessageListener('Forms:GetText:Result:Error', this);
     mm.addMessageListener('Forms:SetSelectionRange:Result:OK', this);
     mm.addMessageListener('Forms:SetSelectionRange:Result:Error', this);
     mm.addMessageListener('Forms:ReplaceSurroundingText:Result:OK', this);
     mm.addMessageListener('Forms:ReplaceSurroundingText:Result:Error', this);
     mm.addMessageListener('Forms:SendKey:Result:OK', this);
@@ -187,18 +188,21 @@ this.Keyboard = {
 
     if (0 === msg.name.indexOf('Keyboard:') &&
         ('Keyboard:Register' !== msg.name && this._keyboardID !== kbID)
        ) {
       return;
     }
 
     switch (msg.name) {
-      case 'Forms:Input':
-        this.handleFocusChange(msg);
+      case 'Forms:Focus':
+        this.handleFocus(msg);
+        break;
+      case 'Forms:Blur':
+        this.handleBlur(msg);
         break;
       case 'Forms:SelectionChange':
       case 'Forms:GetText:Result:OK':
       case 'Forms:GetText:Result:Error':
       case 'Forms:SetSelectionRange:Result:OK':
       case 'Forms:ReplaceSurroundingText:Result:OK':
       case 'Forms:SendKey:Result:OK':
       case 'Forms:SendKey:Result:Error':
@@ -269,60 +273,62 @@ this.Keyboard = {
         break;
       case 'Keyboard:Unregister':
         this._keyboardMM = null;
         this._keyboardID = -1;
         break;
     }
   },
 
-  forwardEvent: function keyboardForwardEvent(newEventName, msg) {
+  handleFocus: function keyboardHandleFocus(msg) {
+    // Set the formMM to the new message manager received.
     let mm = msg.target.QueryInterface(Ci.nsIFrameLoaderOwner)
                 .frameLoader.messageManager;
-    if (newEventName === 'Keyboard:FocusChange') {
-      if (msg.data.type !== 'blur') { // Focus on a new input field
-        // Set the formMM to the new message manager so that
-        // message gets to the right form now on.
-        this.formMM = mm;
-      } else { // input is blurred
-        // A blur message can't be sent to the keyboard if the focus has
-        // already been taken away at first place.
-        // This check is here to prevent problem caused by out-of-order
-        // ipc messages from two processes.
-        if (mm !== this.formMM) {
-          return false;
-        }
+    this.formMM = mm;
 
-        this.formMM = null;
-      }
-    }
-
-    this.sendToKeyboard(newEventName, msg.data);
-    return true;
-  },
-
-  handleFocusChange: function keyboardHandleFocusChange(msg) {
-    let isSent = this.forwardEvent('Keyboard:FocusChange', msg);
-
-    if (!isSent) {
-      return;
-    }
+    this.forwardEvent('Keyboard:Focus', msg);
 
     // Chrome event, used also to render value selectors; that's why we need
     // the info about choices / min / max here as well...
     SystemAppProxy.dispatchEvent({
       type: 'inputmethod-contextchange',
-      inputType: msg.data.type,
+      inputType: msg.data.inputType,
       value: msg.data.value,
       choices: JSON.stringify(msg.data.choices),
       min: msg.data.min,
       max: msg.data.max
     });
   },
 
+  handleBlur: function keyboardHandleBlur(msg) {
+    let mm = msg.target.QueryInterface(Ci.nsIFrameLoaderOwner)
+                .frameLoader.messageManager;
+    // A blur message can't be sent to the keyboard if the focus has
+    // already been taken away at first place.
+    // This check is here to prevent problem caused by out-of-order
+    // ipc messages from two processes.
+    if (mm !== this.formMM) {
+      return;
+    }
+
+    // unset formMM
+    this.formMM = null;
+
+    this.forwardEvent('Keyboard:Blur', msg);
+
+    SystemAppProxy.dispatchEvent({
+      type: 'inputmethod-contextchange',
+      inputType: 'blur'
+    });
+  },
+
+  forwardEvent: function keyboardForwardEvent(newEventName, msg) {
+    this.sendToKeyboard(newEventName, msg.data);
+  },
+
   setSelectedOption: function keyboardSetSelectedOption(msg) {
     this.sendToForm('Forms:Select:Choice', msg.data);
   },
 
   setSelectedOptions: function keyboardSetSelectedOptions(msg) {
     this.sendToForm('Forms:Select:Choice', msg.data);
   },
 
--- a/dom/inputmethod/MozKeyboard.js
+++ b/dom/inputmethod/MozKeyboard.js
@@ -181,18 +181,16 @@ function MozInputMethod() { }
 
 MozInputMethod.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
   _inputcontext: null,
   _wrappedInputContext: null,
   _layouts: {},
   _window: null,
-  _isSystem: false,
-  _isKeyboard: true,
 
   classID: Components.ID("{4607330d-e7d2-40a4-9eb8-43967eae0142}"),
 
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsIDOMGlobalPropertyInitializer,
     Ci.nsIObserver,
     Ci.nsISupportsWeakReference
   ]),
@@ -201,46 +199,31 @@ MozInputMethod.prototype = {
     this._window = win;
     this._mgmt = new MozInputMethodManager(win);
     this.innerWindowID = win.QueryInterface(Ci.nsIInterfaceRequestor)
                             .getInterface(Ci.nsIDOMWindowUtils)
                             .currentInnerWindowID;
 
     Services.obs.addObserver(this, "inner-window-destroyed", false);
 
-    let principal = win.document.nodePrincipal;
-    let perm = Services.perms.testExactPermissionFromPrincipal(principal,
-                                                               "input-manage");
-    if (perm === Ci.nsIPermissionManager.ALLOW_ACTION) {
-      this._isSystem = true;
-    }
-
-    perm = Services.perms.testExactPermissionFromPrincipal(principal, "input");
-    if (perm !== Ci.nsIPermissionManager.ALLOW_ACTION) {
-      this._isKeyboard = false;
-      return;
-    }
-
-    cpmm.addWeakMessageListener('Keyboard:FocusChange', this);
+    cpmm.addWeakMessageListener('Keyboard:Focus', this);
+    cpmm.addWeakMessageListener('Keyboard:Blur', this);
     cpmm.addWeakMessageListener('Keyboard:SelectionChange', this);
     cpmm.addWeakMessageListener('Keyboard:GetContext:Result:OK', this);
     cpmm.addWeakMessageListener('Keyboard:LayoutsChange', this);
     cpmm.addWeakMessageListener('InputRegistry:Result:OK', this);
     cpmm.addWeakMessageListener('InputRegistry:Result:Error', this);
   },
 
   uninit: function mozInputMethodUninit() {
     this._window = null;
     this._mgmt = null;
-    Services.obs.removeObserver(this, "inner-window-destroyed");
-    if (!this._isKeyboard) {
-      return;
-    }
 
-    cpmm.removeWeakMessageListener('Keyboard:FocusChange', this);
+    cpmm.removeWeakMessageListener('Keyboard:Focus', this);
+    cpmm.removeWeakMessageListener('Keyboard:Blur', this);
     cpmm.removeWeakMessageListener('Keyboard:SelectionChange', this);
     cpmm.removeWeakMessageListener('Keyboard:GetContext:Result:OK', this);
     cpmm.removeWeakMessageListener('Keyboard:LayoutsChange', this);
     cpmm.removeWeakMessageListener('InputRegistry:Result:OK', this);
     cpmm.removeWeakMessageListener('InputRegistry:Result:Error', this);
     this.setActive(false);
   },
 
@@ -250,24 +233,22 @@ MozInputMethod.prototype = {
       return;
     }
 
     let data = msg.data;
     let resolver = ('requestId' in data) ?
       this.takePromiseResolver(data.requestId) : null;
 
     switch(msg.name) {
-      case 'Keyboard:FocusChange':
-        if (data.type !== 'blur') {
-          // XXX Bug 904339 could receive 'text' event twice
-          this.setInputContext(data);
-        }
-        else {
-          this.setInputContext(null);
-        }
+      case 'Keyboard:Focus':
+        // XXX Bug 904339 could receive 'text' event twice
+        this.setInputContext(data);
+        break;
+      case 'Keyboard:Blur':
+        this.setInputContext(null);
         break;
       case 'Keyboard:SelectionChange':
         if (this.inputcontext) {
           this._inputcontext.updateSelectionContext(data, false);
         }
         break;
       case 'Keyboard:GetContext:Result:OK':
         this.setInputContext(data);
@@ -317,18 +298,18 @@ MozInputMethod.prototype = {
     if (this._inputcontext) {
       this._inputcontext.destroy();
       this._inputcontext = null;
       this._wrappedInputContext = null;
       this._mgmt._supportsSwitching = false;
     }
 
     if (data) {
-      this._mgmt._supportsSwitching = this._layouts[data.type] ?
-        this._layouts[data.type] > 1 :
+      this._mgmt._supportsSwitching = this._layouts[data.inputType] ?
+        this._layouts[data.inputType] > 1 :
         false;
 
       this._inputcontext = new MozInputContext(data);
       this._inputcontext.init(this._window);
       // inputcontext will be exposed as a WebIDL object. Create its
       // content-side object explicitly to avoid Bug 1001325.
       this._wrappedInputContext =
         this._window.MozInputContext._create(this._window, this._inputcontext);
@@ -395,45 +376,35 @@ MozInputMethod.prototype = {
         requestId: resolverId,
         inputId: inputId,
         appId: appId
       });
     }.bind(this));
   },
 
   setValue: function(value) {
-    this._ensureIsSystem();
     cpmm.sendAsyncMessage('System:SetValue', {
       'value': value
     });
   },
 
   setSelectedOption: function(index) {
-    this._ensureIsSystem();
     cpmm.sendAsyncMessage('System:SetSelectedOption', {
       'index': index
     });
   },
 
   setSelectedOptions: function(indexes) {
-    this._ensureIsSystem();
     cpmm.sendAsyncMessage('System:SetSelectedOptions', {
       'indexes': indexes
     });
   },
 
   removeFocus: function() {
-    this._ensureIsSystem();
     cpmm.sendAsyncMessage('System:RemoveFocus', {});
-  },
-
-  _ensureIsSystem: function() {
-    if (!this._isSystem) {
-      throw new this._window.Error("Should have 'input-manage' permssion.");
-    }
   }
 };
 
  /**
  * ==============================================
  * InputContextDOMRequestIpcHelper
  * ==============================================
  */
@@ -489,22 +460,20 @@ InputContextDOMRequestIpcHelper.prototyp
 
  /**
  * ==============================================
  * InputContext
  * ==============================================
  */
 function MozInputContext(ctx) {
   this._context = {
-    inputtype: ctx.type,
-    inputmode: ctx.inputmode,
+    type: ctx.type,
+    inputType: ctx.inputType,
+    inputMode: ctx.inputMode,
     lang: ctx.lang,
-    type: ["textarea", "contenteditable"].indexOf(ctx.type) > -1 ?
-              ctx.type :
-              "text",
     selectionStart: ctx.selectionStart,
     selectionEnd: ctx.selectionEnd,
     textBeforeCursor: ctx.textBeforeCursor,
     textAfterCursor: ctx.textAfterCursor
   };
 
   this._contextId = ctx.contextId;
 }
@@ -643,21 +612,21 @@ MozInputContext.prototype = {
 
   // tag name of the input field
   get type() {
     return this._context.type;
   },
 
   // type of the input field
   get inputType() {
-    return this._context.inputtype;
+    return this._context.inputType;
   },
 
   get inputMode() {
-    return this._context.inputmode;
+    return this._context.inputMode;
   },
 
   get lang() {
     return this._context.lang;
   },
 
   getText: function ic_getText(offset, length) {
     let self = this;
--- a/dom/inputmethod/forms.js
+++ b/dom/inputmethod/forms.js
@@ -992,17 +992,17 @@ let FormAssistant = {
     this.setFocusedElement(target);
     this.sendInputState(target);
     this.isHandlingFocus = true;
   },
 
   unhandleFocus: function fa_unhandleFocus() {
     this.setFocusedElement(null);
     this.isHandlingFocus = false;
-    sendAsyncMessage("Forms:Input", { "type": "blur" });
+    sendAsyncMessage("Forms:Blur", {});
   },
 
   isFocusableElement: function fa_isFocusableElement(element) {
     if (element instanceof HTMLSelectElement ||
         element instanceof HTMLTextAreaElement)
       return true;
 
     if (element instanceof HTMLOptionElement &&
@@ -1021,17 +1021,17 @@ let FormAssistant = {
 
       return element;
     }
 
     return retrieveTopLevelEditable(element) || element;
   },
 
   sendInputState: function(element) {
-    sendAsyncMessage("Forms:Input", getJSON(element, this._focusCounter));
+    sendAsyncMessage("Forms:Focus", getJSON(element, this._focusCounter));
   },
 
   getSelectionInfo: function fa_getSelectionInfo() {
     let element = this.focusedElement;
     let range =  getSelectionRange(element);
 
     let text = isContentEditable(element) ? getContentEditableText(element)
                                           : element.value;
@@ -1108,65 +1108,69 @@ function isPlainTextField(element) {
 
 function getJSON(element, focusCounter) {
   // <input type=number> has a nested anonymous <input type=text> element that
   // takes focus on behalf of the number control when someone tries to focus
   // the number control. If |element| is such an anonymous text control then we
   // need it's number control here in order to get the correct 'type' etc.:
   element = element.ownerNumberControl || element;
 
-  let type = element.type || "";
+  let type = element.tagName.toLowerCase();
+  let inputType = (element.type || "").toLowerCase();
   let value = element.value || "";
   let max = element.max || "";
   let min = element.min || "";
 
-  // Treat contenteditble element as a special text area field
+  // Treat contenteditable element as a special text area field
   if (isContentEditable(element)) {
-    type = "textarea";
+    type = "contenteditable";
+    inputType = "textarea";
     value = getContentEditableText(element);
   }
 
   // Until the input type=date/datetime/range have been implemented
   // let's return their real type even if the platform returns 'text'
-  let attributeType = element.getAttribute("type") || "";
+  let attributeInputType = element.getAttribute("type") || "";
 
-  if (attributeType) {
-    var typeLowerCase = attributeType.toLowerCase();
-    switch (typeLowerCase) {
+  if (attributeInputType) {
+    let inputTypeLowerCase = attributeInputType.toLowerCase();
+    switch (inputTypeLowerCase) {
       case "datetime":
       case "datetime-local":
       case "range":
-        type = typeLowerCase;
+        inputType = inputTypeLowerCase;
         break;
     }
   }
 
   // Gecko has some support for @inputmode but behind a preference and
   // it is disabled by default.
   // Gaia is then using @x-inputmode has its proprietary way to set
   // inputmode for fields. This shouldn't be used outside of pre-installed
   // apps because the attribute is going to disappear as soon as a definitive
   // solution will be find.
-  let inputmode = element.getAttribute('x-inputmode');
-  if (inputmode) {
-    inputmode = inputmode.toLowerCase();
+  let inputMode = element.getAttribute('x-inputmode');
+  if (inputMode) {
+    inputMode = inputMode.toLowerCase();
   } else {
-    inputmode = '';
+    inputMode = '';
   }
 
   let range = getSelectionRange(element);
   let textAround = getTextAroundCursor(value, range);
 
   return {
     "contextId": focusCounter,
 
-    "type": type.toLowerCase(),
+    "type": type,
+    "inputType": inputType,
+    "inputMode": inputMode,
+
     "choices": getListForElement(element),
     "value": value,
-    "inputmode": inputmode,
     "selectionStart": range[0],
     "selectionEnd": range[1],
     "max": max,
     "min": min,
     "lang": element.lang || "",
     "textBeforeCursor": textAround.before,
     "textAfterCursor": textAround.after
   };
--- a/dom/inputmethod/mochitest/test_basic.html
+++ b/dom/inputmethod/mochitest/test_basic.html
@@ -33,19 +33,19 @@ function runTest() {
 
     gContext = im.inputcontext;
     if (!gContext) {
       ok(false, 'Should have a non-null inputcontext.');
       inputmethod_cleanup();
       return;
     }
 
-    todo_is(gContext.type, 'input', 'The input context type should match.');
+    is(gContext.type, 'input', 'The input context type should match.');
     is(gContext.inputType, 'text', 'The inputType should match.');
-    is(gContext.inputMode, 'verbatim', 'The input mode should match.');
+    is(gContext.inputMode, 'verbatim', 'The inputMode should match.');
     is(gContext.lang, 'zh', 'The language should match.');
     is(gContext.textBeforeCursor + gContext.textAfterCursor, 'Yuan',
        'Should get the text around the cursor.');
 
     test_setSelectionRange();
   };
 
   // Set current page as an input method.
--- a/dom/inputmethod/mochitest/test_bug1059163.html
+++ b/dom/inputmethod/mochitest/test_bug1059163.html
@@ -49,16 +49,19 @@ function runTest() {
   app.src = 'data:text/html,<html><body><div id="text" contenteditable>Jan Jongboom</div></html>';
   app.setAttribute('mozbrowser', true);
   document.body.appendChild(app);
   app.addEventListener('mozbrowserloadend', function() {
     let mm = SpecialPowers.getBrowserFrameMessageManager(app);
     mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
 
     im.oninputcontextchange = function() {
+      is(im.inputcontext.type, 'contenteditable', 'type');
+      is(im.inputcontext.inputType, 'textarea', 'inputType');
+
       if (im.inputcontext) {
         im.oninputcontextchange = null;
         register();
       }
     };
 
     function register() {
       im.inputcontext.onselectionchange = function() {
--- a/dom/ipc/ContentBridgeParent.cpp
+++ b/dom/ipc/ContentBridgeParent.cpp
@@ -71,17 +71,17 @@ ContentBridgeParent::DeferredDestroy()
   // |this| was just destroyed, hands off
 }
 
 bool
 ContentBridgeParent::RecvSyncMessage(const nsString& aMsg,
                                      const ClonedMessageData& aData,
                                      InfallibleTArray<jsipc::CpowEntry>&& aCpows,
                                      const IPC::Principal& aPrincipal,
-                                     nsTArray<StructuredCloneIPCHelper>* aRetvals)
+                                     nsTArray<StructuredCloneData>* aRetvals)
 {
   return nsIContentParent::RecvSyncMessage(aMsg, aData, Move(aCpows),
                                            aPrincipal, aRetvals);
 }
 
 bool
 ContentBridgeParent::RecvAsyncMessage(const nsString& aMsg,
                                       const ClonedMessageData& aData,
--- a/dom/ipc/ContentBridgeParent.h
+++ b/dom/ipc/ContentBridgeParent.h
@@ -77,17 +77,17 @@ protected:
     mIsForBrowser = aIsForBrowser;
   }
 
 protected:
   virtual bool RecvSyncMessage(const nsString& aMsg,
                                const ClonedMessageData& aData,
                                InfallibleTArray<jsipc::CpowEntry>&& aCpows,
                                const IPC::Principal& aPrincipal,
-                               nsTArray<StructuredCloneIPCHelper>* aRetvals) override;
+                               nsTArray<StructuredCloneData>* aRetvals) override;
   virtual bool RecvAsyncMessage(const nsString& aMsg,
                                 const ClonedMessageData& aData,
                                 InfallibleTArray<jsipc::CpowEntry>&& aCpows,
                                 const IPC::Principal& aPrincipal) override;
 
   virtual jsipc::PJavaScriptParent* AllocPJavaScriptParent() override;
   virtual bool
   DeallocPJavaScriptParent(jsipc::PJavaScriptParent*) override;
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -173,23 +173,23 @@
 #include "mozilla/dom/PresentationIPCService.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 
 #ifdef MOZ_WEBSPEECH
 #include "mozilla/dom/PSpeechSynthesisChild.h"
 #endif
 
 #include "ProcessUtils.h"
-#include "StructuredCloneIPCHelper.h"
 #include "URIUtils.h"
 #include "nsContentUtils.h"
 #include "nsIPrincipal.h"
 #include "nsDeviceStorage.h"
 #include "DomainPolicy.h"
 #include "mozilla/dom/DataStoreService.h"
+#include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/dom/telephony/PTelephonyChild.h"
 #include "mozilla/dom/time/DateCacheCleaner.h"
 #include "mozilla/dom/voicemail/VoicemailIPCService.h"
 #include "mozilla/net/NeckoMessageUtils.h"
 #include "mozilla/widget/PuppetBidiKeyboard.h"
 #include "mozilla/RemoteSpellCheckEngineChild.h"
 #include "GMPServiceChild.h"
 #include "gfxPlatform.h"
@@ -794,17 +794,17 @@ ContentChild::InitXPCOM()
     mConsoleListener = new ConsoleListener(this);
     if (NS_FAILED(svc->RegisterListener(mConsoleListener)))
         NS_WARNING("Couldn't register console listener for child process");
 
     bool isOffline, isLangRTL;
     bool isConnected;
     ClipboardCapabilities clipboardCaps;
     DomainPolicyClone domainPolicy;
-    StructuredCloneIPCHelper initialData;
+    StructuredCloneData initialData;
 
     SendGetXPCOMProcessAttributes(&isOffline, &isConnected,
                                   &isLangRTL, &mAvailableDictionaries,
                                   &clipboardCaps, &domainPolicy, &initialData);
     RecvSetOffline(isOffline);
     RecvSetConnectivity(isConnected);
     RecvBidiKeyboardNotify(isLangRTL);