Merge m-c to s-c.
authorRichard Newman <rnewman@mozilla.com>
Sat, 22 Dec 2012 11:32:28 -0800
changeset 117365 ff1aad58f1ade238c373e91cd54c637bf36c2cce
parent 117364 8ca91ba7e69963fc33ba6936fe98f444bef3f894 (current diff)
parent 116860 84320dffec6e55f92fd01bde61ea367b325850ed (diff)
child 117366 2058a54f318015cb657a9b8389be0b59f3d7524e
push id24098
push userrnewman@mozilla.com
push dateThu, 03 Jan 2013 03:39:06 +0000
treeherdermozilla-central@6955309291ee [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone20.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 s-c.
browser/components/places/content/download.css
browser/components/places/content/download.xml
browser/components/places/content/downloadsView.js
content/base/public/nsIEventSource.idl
content/base/src/nsEventSource.cpp
content/base/src/nsEventSource.h
content/xslt/src/xpath/nsXPathNamespace.cpp
content/xslt/src/xpath/nsXPathNamespace.h
dom/imptests/failures/webapps/XMLHttpRequest/tests/submissions/Ms2ger/Makefile.in
dom/imptests/failures/webapps/XMLHttpRequest/tests/submissions/Ms2ger/test_interfaces.html.json
dom/indexedDB/CheckQuotaHelper.cpp
dom/indexedDB/CheckQuotaHelper.h
media/omx-plugin/include/froyo/stagefright/DataSource.h.orig
media/omx-plugin/include/froyo/stagefright/DataSource.h.rej
mobile/android/base/TabsPanelButton.java
mobile/android/base/resources/drawable-hdpi/abouthome_logo.png
mobile/android/base/resources/drawable-xhdpi/abouthome_logo.png
mobile/android/base/resources/drawable-xlarge-hdpi-v11/tabs_menu.png
mobile/android/base/resources/drawable-xlarge-mdpi-v11/tabs_menu.png
mobile/android/base/resources/drawable-xlarge-xhdpi-v11/tabs_menu.png
mobile/android/base/resources/drawable/abouthome_logo.png
mobile/android/base/resources/drawable/tab_new_button.xml
mobile/android/base/resources/layout-land-v14/tabs_panel_toolbar_menu.xml
mobile/android/base/resources/layout-large-v11/tabs_panel_toolbar_menu.xml
mobile/android/base/resources/layout/abouthome_promo_box.xml
mobile/android/base/resources/layout/remote_tabs.xml
mobile/android/base/resources/layout/tabs_panel.xml
mobile/android/base/resources/layout/tabs_tray.xml
profile/public/nsIProfile.idl
profile/public/nsIProfileChangeStatus.idl
security/coreconf/SunOS5.3.mk
security/coreconf/SunOS5.4.mk
security/coreconf/SunOS5.4_i86pc.mk
security/coreconf/SunOS5.5.1.mk
security/coreconf/SunOS5.5.1_i86pc.mk
security/coreconf/SunOS5.5.mk
security/coreconf/SunOS5.6.mk
security/coreconf/SunOS5.6_i86pc.mk
security/coreconf/SunOS5.7.mk
security/coreconf/SunOS5.7_i86pc.mk
--- a/accessible/src/atk/nsMaiInterfaceDocument.cpp
+++ b/accessible/src/atk/nsMaiInterfaceDocument.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "InterfaceInitFuncs.h"
 
+#include "Accessible-inl.h"
 #include "AccessibleWrap.h"
 #include "DocAccessible.h"
 #include "nsMai.h"
 #include "mozilla/Likely.h"
 
 using namespace mozilla::a11y;
 
 static const char* const kDocTypeName = "W3C-doctype";
--- a/accessible/src/atk/nsMaiInterfaceEditableText.cpp
+++ b/accessible/src/atk/nsMaiInterfaceEditableText.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "InterfaceInitFuncs.h"
 
+#include "Accessible-inl.h"
 #include "HyperTextAccessible.h"
 #include "nsMai.h"
 
 #include "nsString.h"
 #include "mozilla/Likely.h"
 
 using namespace mozilla::a11y;
 
--- a/accessible/src/atk/nsMaiInterfaceHypertext.cpp
+++ b/accessible/src/atk/nsMaiInterfaceHypertext.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "InterfaceInitFuncs.h"
 
+#include "Accessible-inl.h"
 #include "HyperTextAccessible.h"
 #include "nsMai.h"
 #include "nsMaiHyperlink.h"
 #include "mozilla/Likely.h"
 
 using namespace mozilla::a11y;
 
 extern "C" {
--- a/accessible/src/atk/nsMaiInterfaceSelection.cpp
+++ b/accessible/src/atk/nsMaiInterfaceSelection.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "InterfaceInitFuncs.h"
 
+#include "Accessible-inl.h"
 #include "AccessibleWrap.h"
 #include "nsMai.h"
 #include "mozilla/Likely.h"
 
 #include <atk/atk.h>
 
 using namespace mozilla::a11y;
 
--- a/accessible/src/atk/nsMaiInterfaceText.cpp
+++ b/accessible/src/atk/nsMaiInterfaceText.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "InterfaceInitFuncs.h"
 
+#include "Accessible-inl.h"
 #include "HyperTextAccessible.h"
 #include "nsMai.h"
 
 #include "nsIPersistentProperties2.h"
 
 #include "mozilla/Likely.h"
 
 using namespace mozilla::a11y;
--- a/accessible/src/base/AccEvent.h
+++ b/accessible/src/base/AccEvent.h
@@ -205,17 +205,16 @@ class AccMutationEvent: public AccEvent
 {
 public:
   AccMutationEvent(uint32_t aEventType, Accessible* aTarget,
                    nsINode* aTargetNode) :
     AccEvent(aEventType, aTarget, eAutoDetect, eCoalesceMutationTextChange)
   {
     // Don't coalesce these since they are coalesced by reorder event. Coalesce
     // contained text change events.
-    mNode = aTargetNode;
     mParent = mAccessible->Parent();
   }
   virtual ~AccMutationEvent() { }
 
   // Event
   static const EventGroup kEventGroup = eMutationEvent;
   virtual unsigned int GetEventGroups() const
   {
--- a/accessible/src/base/AccIterator.cpp
+++ b/accessible/src/base/AccIterator.cpp
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AccIterator.h"
 
 #include "nsAccessibilityService.h"
-#include "Accessible.h"
+#include "Accessible-inl.h"
 
 #include "mozilla/dom/Element.h"
 #include "nsBindingManager.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/src/base/NotificationController.cpp
+++ b/accessible/src/base/NotificationController.cpp
@@ -633,17 +633,17 @@ NotificationController::CoalesceTextChan
 
   aTailEvent->mTextChangeEvent.swap(aThisEvent->mTextChangeEvent);
 }
 
 void
 NotificationController::CreateTextChangeEventFor(AccMutationEvent* aEvent)
 {
   DocAccessible* document = aEvent->GetDocAccessible();
-  Accessible* container = document->GetContainerAccessible(aEvent->mNode);
+  Accessible* container = aEvent->mAccessible->Parent();
   if (!container)
     return;
 
   HyperTextAccessible* textAccessible = container->AsHyperText();
   if (!textAccessible)
     return;
 
   // Don't fire event for the first html:br in an editor.
--- a/accessible/src/base/nsARIAMap.h
+++ b/accessible/src/base/nsARIAMap.h
@@ -4,16 +4,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _nsARIAMap_H_
 #define _nsARIAMap_H_
 
 #include "ARIAStateMap.h"
+#include "mozilla/a11y/AccTypes.h"
 #include "mozilla/a11y/Role.h"
 
 #include "nsIAtom.h"
 #include "nsIContent.h"
 
 class nsINode;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -145,16 +146,22 @@ struct nsRoleMapEntry
 {
   /**
    * Return true if matches to the given ARIA role.
    */
   bool Is(nsIAtom* aARIARole) const
     { return *roleAtom == aARIARole; }
 
   /**
+   * Return true if ARIA role has the given accessible type.
+   */
+  bool IsOfType(mozilla::a11y::AccGenericType aType) const
+    { return accTypes & aType; }
+
+  /**
    * Return ARIA role.
    */
   const nsDependentAtomString ARIARoleString() const
     { return nsDependentAtomString(*roleAtom); }
 
   // ARIA role: string representation such as "button"
   nsIAtom** roleAtom;
 
--- a/accessible/src/generic/Accessible-inl.h
+++ b/accessible/src/generic/Accessible-inl.h
@@ -26,22 +26,21 @@ inline mozilla::a11y::role
 Accessible::ARIARole()
 {
   if (!mRoleMapEntry || mRoleMapEntry->roleRule != kUseMapRole)
     return mozilla::a11y::roles::NOTHING;
 
   return ARIATransformRole(mRoleMapEntry->role);
 }
 
-inline void
-Accessible::SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry)
+inline bool
+Accessible::HasGenericType(AccGenericType aType) const
 {
-  mRoleMapEntry = aRoleMapEntry;
-  if (mRoleMapEntry)
-    mGenericTypes |= mRoleMapEntry->accTypes;
+  return (mGenericTypes & aType) ||
+    (mRoleMapEntry && mRoleMapEntry->IsOfType(aType));
 }
 
 inline bool
 Accessible::HasNumericValue() const
 {
   if (mStateFlags & eHasNumericValue)
     return true;
 
--- a/accessible/src/generic/Accessible.h
+++ b/accessible/src/generic/Accessible.h
@@ -299,17 +299,18 @@ public:
   virtual mozilla::a11y::Relation RelationByType(uint32_t aType);
 
   //////////////////////////////////////////////////////////////////////////////
   // Initializing methods
 
   /**
    * Set the ARIA role map entry for a new accessible.
    */
-  void SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry);
+  void SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry)
+    { mRoleMapEntry = aRoleMapEntry; }
 
   /**
    * Update the children cache.
    */
   inline bool UpdateChildren()
   {
     InvalidateChildren();
     return EnsureChildren();
@@ -463,72 +464,77 @@ public:
   inline bool IsAbbreviation() const
   {
     return mContent->IsHTML() &&
       (mContent->Tag() == nsGkAtoms::abbr || mContent->Tag() == nsGkAtoms::acronym);
   }
 
   bool IsApplication() const { return mType == eApplicationType; }
 
-  bool IsAutoComplete() const { return mGenericTypes & eAutoComplete; }
+  bool IsAutoComplete() const { return HasGenericType(eAutoComplete); }
 
   bool IsAutoCompletePopup() const
-    { return mGenericTypes & eAutoCompletePopup; }
+    { return HasGenericType(eAutoCompletePopup); }
 
-  bool IsCombobox() const { return mGenericTypes & eCombobox; }
+  bool IsCombobox() const { return HasGenericType(eCombobox); }
 
-  bool IsDoc() const { return mGenericTypes & eDocument; }
+  bool IsDoc() const { return HasGenericType(eDocument); }
   DocAccessible* AsDoc();
 
-  bool IsHyperText() const { return mGenericTypes & eHyperText; }
+  bool IsHyperText() const { return HasGenericType(eHyperText); }
   HyperTextAccessible* AsHyperText();
 
   bool IsHTMLFileInput() const { return mType == eHTMLFileInputType; }
 
   bool IsHTMLListItem() const { return mType == eHTMLLiType; }
   HTMLLIAccessible* AsHTMLListItem();
 
   bool IsHTMLTableRow() const { return mType == eHTMLTableRowType; }
 
   bool IsImage() const { return mType == eImageType; }
   ImageAccessible* AsImage();
 
   bool IsImageMap() const { return mType == eImageMapType; }
   HTMLImageMapAccessible* AsImageMap();
 
-  bool IsList() const { return mGenericTypes & eList; }
+  bool IsList() const { return HasGenericType(eList); }
 
-  bool IsListControl() const { return mGenericTypes & eListControl; }
+  bool IsListControl() const { return HasGenericType(eListControl); }
 
-  bool IsMenuButton() const { return mGenericTypes & eMenuButton; }
+  bool IsMenuButton() const { return HasGenericType(eMenuButton); }
 
   bool IsMenuPopup() const { return mType == eMenuPopupType; }
 
   bool IsProgress() const { return mType == eProgressType; }
 
   bool IsRoot() const { return mType == eRootType; }
   a11y::RootAccessible* AsRoot();
 
-  bool IsSelect() const { return mGenericTypes & eSelect; }
+  bool IsSelect() const { return HasGenericType(eSelect); }
 
-  bool IsTable() const { return mGenericTypes & eTable; }
+  bool IsTable() const { return HasGenericType(eTable); }
   virtual TableAccessible* AsTable() { return nullptr; }
 
   virtual TableCellAccessible* AsTableCell() { return nullptr; }
 
-  bool IsTableRow() const { return mGenericTypes & eTableRow; }
+  bool IsTableRow() const { return HasGenericType(eTableRow); }
 
   bool IsTextLeaf() const { return mType == eTextLeafType; }
   TextLeafAccessible* AsTextLeaf();
 
   bool IsXULDeck() const { return mType == eXULDeckType; }
 
   bool IsXULTree() const { return mType == eXULTreeType; }
   XULTreeAccessible* AsXULTree();
 
+  /**
+   * Return true if the accessible belongs to the given accessible type.
+   */
+  bool HasGenericType(AccGenericType aType) const;
+
   //////////////////////////////////////////////////////////////////////////////
   // ActionAccessible
 
   /**
    * Return the number of actions that can be performed on this accessible.
    */
   virtual uint8_t ActionCount();
 
--- a/accessible/src/generic/OuterDocAccessible.cpp
+++ b/accessible/src/generic/OuterDocAccessible.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "OuterDocAccessible.h"
 
+#include "Accessible-inl.h"
 #include "nsAccUtils.h"
 #include "DocAccessible.h"
 #include "Role.h"
 #include "States.h"
 
 #ifdef A11Y_LOG
 #include "Logging.h"
 #endif
--- a/accessible/src/jsat/TouchAdapter.jsm
+++ b/accessible/src/jsat/TouchAdapter.jsm
@@ -64,19 +64,16 @@ this.TouchAdapter = {
       this.glass.id = 'accessfu-glass';
       this.chromeWin.document.documentElement.appendChild(this.glass);
       target = this.glass;
     }
 
     target.addEventListener('mousemove', this, true, true);
     target.addEventListener('mouseenter', this, true, true);
     target.addEventListener('mouseleave', this, true, true);
-    target.addEventListener('mousedown', this, true, true);
-    target.addEventListener('mouseup', this, true, true);
-    target.addEventListener('click', this, true, true);
 
     target.addEventListener('touchend', this, true, true);
     target.addEventListener('touchmove', this, true, true);
     target.addEventListener('touchstart', this, true, true);
 
     if (Utils.OS != 'Android')
       Mouse2Touch.attach(aWindow);
   },
@@ -92,19 +89,16 @@ this.TouchAdapter = {
     if (Utils.MozBuildApp == 'b2g') {
       target = this.glass;
       this.glass.parentNode.removeChild(this.glass);
     }
 
     target.removeEventListener('mousemove', this, true, true);
     target.removeEventListener('mouseenter', this, true, true);
     target.removeEventListener('mouseleave', this, true, true);
-    target.removeEventListener('mousedown', this, true, true);
-    target.removeEventListener('mouseup', this, true, true);
-    target.removeEventListener('click', this, true, true);
 
     target.removeEventListener('touchend', this, true, true);
     target.removeEventListener('touchmove', this, true, true);
     target.removeEventListener('touchstart', this, true, true);
 
     if (Utils.OS != 'Android')
       Mouse2Touch.detach(aWindow);
 
@@ -123,42 +117,48 @@ this.TouchAdapter = {
     // instead of milliseconds.
     let timeStamp = (Utils.OS == 'Android') ? aEvent.timeStamp : Date.now();
     switch (aEvent.type) {
       case 'mouseenter':
       case 'touchstart':
         for (var i = 0; i < changedTouches.length; i++) {
           let touch = changedTouches[i];
           let touchPoint = new TouchPoint(touch, timeStamp, this._dpi);
-          this._touchPoints[touch.identifier || this.HOVER_ID] = touchPoint;
+          let identifier = (touch.identifier == undefined) ?
+            this.HOVER_ID : touch.identifier;
+          this._touchPoints[identifier] = touchPoint;
           this._lastExploreTime = timeStamp + this.SWIPE_MAX_DURATION;
         }
         this._dwellTimeout = this.chromeWin.setTimeout(
           (function () {
              this.compileAndEmit(timeStamp + this.DWELL_THRESHOLD);
            }).bind(this), this.DWELL_THRESHOLD);
         break;
       case 'mousemove':
       case 'touchmove':
         for (var i = 0; i < changedTouches.length; i++) {
           let touch = changedTouches[i];
-          let touchPoint = this._touchPoints[touch.identifier || this.HOVER_ID];
+          let identifier = (touch.identifier == undefined) ?
+            this.HOVER_ID : touch.identifier;
+          let touchPoint = this._touchPoints[identifier];
           if (touchPoint)
             touchPoint.update(touch, timeStamp);
         }
         if (timeStamp - this._lastExploreTime >= EXPLORE_THROTTLE) {
           this.compileAndEmit(timeStamp);
           this._lastExploreTime = timeStamp;
         }
         break;
       case 'mouseleave':
       case 'touchend':
         for (var i = 0; i < changedTouches.length; i++) {
           let touch = changedTouches[i];
-          let touchPoint = this._touchPoints[touch.identifier || this.HOVER_ID];
+          let identifier = (touch.identifier == undefined) ?
+            this.HOVER_ID : touch.identifier;
+          let touchPoint = this._touchPoints[identifier];
           if (touchPoint) {
             touchPoint.update(touch, timeStamp);
             touchPoint.finish();
           }
         }
         this.compileAndEmit(timeStamp);
         break;
     }
--- a/accessible/src/mac/mozHTMLAccessible.mm
+++ b/accessible/src/mac/mozHTMLAccessible.mm
@@ -2,16 +2,17 @@
 /* vim:expandtab:shiftwidth=2:tabstop=2:
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #import "mozHTMLAccessible.h"
 
+#import "Accessible-inl.h"
 #import "HyperTextAccessible.h"
 
 #import "nsCocoaUtils.h"
 
 @implementation mozHeadingAccessible
 
 - (NSString*)title
 {
--- a/accessible/src/mac/mozTextAccessible.mm
+++ b/accessible/src/mac/mozTextAccessible.mm
@@ -1,14 +1,14 @@
 /* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-
+#include "Accessible-inl.h"
 #include "AccessibleWrap.h"
 #include "TextLeafAccessible.h"
 
 #include "nsCocoaUtils.h"
 #include "nsObjCExceptions.h"
 
 #import "mozTextAccessible.h"
 
--- a/accessible/src/xul/XULAlertAccessible.cpp
+++ b/accessible/src/xul/XULAlertAccessible.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "XULAlertAccessible.h"
 
+#include "Accessible-inl.h"
 #include "Role.h"
 #include "States.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULAlertAccessible
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/src/xul/XULTreeAccessible.cpp
+++ b/accessible/src/xul/XULTreeAccessible.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "XULTreeAccessible.h"
 
+#include "Accessible-inl.h"
 #include "DocAccessible-inl.h"
 #include "nsAccCache.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "nsEventShell.h"
 #include "DocAccessible.h"
 #include "Relation.h"
 #include "Role.h"
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -610,8 +610,11 @@ pref("font.size.inflation.disabledInMast
 
 // Enable freeing dirty pages when minimizing memory; this reduces memory
 // consumption when applications are sent to the background.
 pref("memory.free_dirty_pages", true);
 
 // UAProfile settings
 pref("wap.UAProf.url", "");
 pref("wap.UAProf.tagname", "x-wap-profile");
+
+// Wait up to this much milliseconds when orientation changed
+pref("layers.orientation.sync.timeout", 1000);
--- a/b2g/chrome/content/forms.js
+++ b/b2g/chrome/content/forms.js
@@ -34,17 +34,16 @@ let HTMLOptionElement = Ci.nsIDOMHTMLOpt
 let FormAssistant = {
   init: function fa_init() {
     addEventListener("focus", this, true, false);
     addEventListener("blur", this, true, false);
     addEventListener("resize", this, true, false);
     addMessageListener("Forms:Select:Choice", this);
     addMessageListener("Forms:Input:Value", this);
     addMessageListener("Forms:Select:Blur", this);
-    Services.obs.addObserver(this, "ime-enabled-state-changed", false);
     Services.obs.addObserver(this, "xpcom-shutdown", false);
   },
 
   ignoredInputTypes: new Set([
     'button', 'file', 'checkbox', 'radio', 'reset', 'submit', 'image'
   ]),
 
   isKeyboardOpened: false,
@@ -89,39 +88,39 @@ let FormAssistant = {
     let target = evt.target;
 
     switch (evt.type) {
       case "focus":
         if (this.isTextInputElement(target) && this.isIMEDisabled())
           return;
 
         if (target && this.isFocusableElement(target))
-          this.handleIMEStateEnabled(target);
+          this.showKeyboard(target);
         break;
 
       case "blur":
         if (this.focusedElement)
-          this.handleIMEStateDisabled();
+          this.hideKeyboard();
         break;
 
       case 'mousedown':
         // We only listen for this event on the currently focused element.
         // When the mouse goes down, note the cursor/selection position
         this.selectionStart = this.focusedElement.selectionStart;
         this.selectionEnd = this.focusedElement.selectionEnd;
         break;
 
       case 'mouseup':
         // We only listen for this event on the currently focused element.
         // When the mouse goes up, see if the cursor has moved (or the
         // selection changed) since the mouse went down. If it has, we
         // need to tell the keyboard about it
         if (this.focusedElement.selectionStart !== this.selectionStart ||
             this.focusedElement.selectionEnd !== this.selectionEnd) {
-          this.tryShowIme(this.focusedElement);
+          this.sendKeyboardState(this.focusedElement);
         }
         break;
 
       case "resize":
         if (!this.isKeyboardOpened)
           return;
 
         if (this.scrollIntoViewTimeout) {
@@ -190,63 +189,48 @@ let FormAssistant = {
         this.setFocusedElement(null);
         break;
       }
     }
   },
 
   observe: function fa_observe(subject, topic, data) {
     switch (topic) {
-      case "ime-enabled-state-changed":
-        let shouldOpen = parseInt(data);
-        let target = Services.fm.focusedElement;
-        if (!target || !this.isTextInputElement(target))
-          return;
-
-        if (shouldOpen) {
-          if (!this.focusedElement && this.isFocusableElement(target))
-            this.handleIMEStateEnabled(target);
-        } else if (this._focusedElement == target) {
-          this.handleIMEStateDisabled();
-        }
-        break;
-
       case "xpcom-shutdown":
-        Services.obs.removeObserver(this, "ime-enabled-state-changed", false);
         Services.obs.removeObserver(this, "xpcom-shutdown");
         removeMessageListener("Forms:Select:Choice", this);
         removeMessageListener("Forms:Input:Value", this);
         break;
     }
   },
 
   isIMEDisabled: function fa_isIMEDisabled() {
     let disabled = false;
     try {
       disabled = domWindowUtils.IMEStatus == domWindowUtils.IME_STATUS_DISABLED;
     } catch (e) {}
 
     return disabled;
   },
 
-  handleIMEStateEnabled: function fa_handleIMEStateEnabled(target) {
+  showKeyboard: function fa_showKeyboard(target) {
     if (this.isKeyboardOpened)
       return;
 
     if (target instanceof HTMLOptionElement)
       target = target.parentNode;
 
-    let kbOpened = this.tryShowIme(target);
+    let kbOpened = this.sendKeyboardState(target);
     if (this.isTextInputElement(target))
       this.isKeyboardOpened = kbOpened;
 
     this.setFocusedElement(target);
   },
 
-  handleIMEStateDisabled: function fa_handleIMEStateDisabled() {
+  hideKeyboard: function fa_hideKeyboard() {
     sendAsyncMessage("Forms:Input", { "type": "blur" });
     this.isKeyboardOpened = false;
     this.setFocusedElement(null);
   },
 
   isFocusableElement: function fa_isFocusableElement(element) {
     if (element.contentEditable && element.contentEditable == "true") {
       return true;
@@ -265,17 +249,17 @@ let FormAssistant = {
   },
 
   isTextInputElement: function fa_isTextInputElement(element) {
     return element instanceof HTMLInputElement ||
            element instanceof HTMLTextAreaElement ||
            (element.contentEditable && element.contentEditable == "true");
   },
 
-  tryShowIme: function(element) {
+  sendKeyboardState: function(element) {
     // FIXME/bug 729623: work around apparent bug in the IME manager
     // in gecko.
     let readonly = element.getAttribute("readonly");
     if (readonly) {
       return false;
     }
 
     sendAsyncMessage("Forms:Input", getJSON(element));
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -736,20 +736,26 @@ var AlertsHelper = {
                                                               cookie,
                                                               alertListener,
                                                               name) {
     let uid = this.registerListener(null, alertListener);
     this.showNotification(imageUrl, title, text, textClickable, cookie,
                           uid, name, null);
   },
 
-  receiveMessage: function alert_receiveMessage(message) {
-    let data = message.data;
+  receiveMessage: function alert_receiveMessage(aMessage) {
+    if (!aMessage.target.assertPermission("desktop-notification")) {
+      Cu.reportError("Desktop-notification message " + aMessage.name +
+                     " from a content process with no desktop-notification privileges.");
+      return null;
+    }
+
+    let data = aMessage.data;
     let listener = {
-      mm: message.target,
+      mm: aMessage.target,
       title: data.title,
       text: data.text,
       manifestURL: data.manifestURL,
       imageURL: data.imageURL
     }
     this.registerAppListener(data.uid, listener);
 
     this.showNotification(data.imageURL, data.title, data.text,
--- a/b2g/components/ContentPermissionPrompt.js
+++ b/b2g/components/ContentPermissionPrompt.js
@@ -115,24 +115,27 @@ ContentPermissionPrompt.prototype = {
                                         Ci.nsIPermissionManager.DENY_ACTION);
       }
 
       request.cancel();
     });
 
     let principal = request.principal;
     let isApp = principal.appStatus != Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED;
+    let remember = principal.appStatus == Ci.nsIPrincipal.APP_STATUS_PRIVILEGED
+                   ? true
+                   : request.remember;
 
     let details = {
       type: "permission-prompt",
       permission: request.type,
       id: requestId,
       origin: principal.origin,
       isApp: isApp,
-      remember: request.remember
+      remember: remember
     };
 
     this._permission = access;
     this._uri = request.principal.URI.spec;
     this._origin = request.principal.origin;
 
     if (!isApp) {
       browser.shell.sendChromeEvent(details);
--- a/b2g/config/panda/releng-pandaboard.tt
+++ b/b2g/config/panda/releng-pandaboard.tt
@@ -1,8 +1,8 @@
 [
 {
-"size": 676548372,
-"digest": "e94c1ef674d2144ef19bf6b5faa0bc050f2f6e61d5a859c20f0d61a4665cd4587836f2c45dbc3a2b264f94b4da9db7f31d566d6ad21e9e43b90bc3f617508184",
+"size": 676536592,
+"digest": "5aa3f1b523faa8996dbcde44a99d846740f80b5361d3109f36688c7bac86979861311c4e7d69b67d9ea1d7c56e20947a30576b3e3f08f7c1e42ec4c2192d92e1",
 "algorithm": "sha512",
 "filename": "gonk.tar.xz"
 }
 ]
--- a/b2g/config/panda/sources.xml
+++ b/b2g/config/panda/sources.xml
@@ -1,31 +1,31 @@
 <?xml version="1.0" ?><manifest>
   <!-- This is only a record of which revisions were pulled to generate the
        gonk.tar.xz snapshot referred to by releng-pandaboard.tt -->
 
   <remote fetch="https://android.googlesource.com/" name="aosp"/>
   <remote fetch="git://github.com/mozilla-b2g/" name="b2g"/>
   <remote fetch="git://android.git.linaro.org/" name="linaro"/>
   <remote fetch="git://github.com/mozilla/" name="mozilla"/>
-  <remote fetch="https://git.mozilla.org" name="mozillaorg"/>
+  <remote fetch="http://git.mozilla.org/" name="mozillaorg"/>
   <default remote="linaro" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
 
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="273ba23d5c6c9f6a34995a3cc429804d1449ca9f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="654358494ba601a46ef9838debc95417ae464cc6"/>
-  <project name="rilproxy" path="rilproxy" remote="b2g" revision="32106d4ea635ebe17a1610b643b398db639b8b97"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7c43e273991a8a66afc88c888befb2830b7640e1"/>
+  <project name="rilproxy" path="rilproxy" remote="b2g" revision="167b4c59a82b9130e385de786e8056d89a1cb8c3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="6ee1f8987ef36d688f97064c003ad57849dfadf2"/>
 
   <!-- Stock Android things -->
   <!-- Information: platform/abi/cpp is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.138 --><project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
-  <project name="platform/bionic" path="bionic" revision="c7bab8cb8483e7869eabdbd4add7c9e5beeecc80"/>
+  <!-- Information: platform/bionic is tagged with android-4.0.4_r2.1 --><project name="platform/bionic" path="bionic" revision="3d11bf0f3f3cf848f6f1e8449bf8736d8d1c78a3"/>
   <!-- Information: platform/bootable/recovery is tagged with android-4.0.4_r2.1 --><project name="platform/bootable/recovery" path="bootable/recovery" revision="fadc5ac81d6400ebdd041f7d4ea64021596d6b7d"/>
   <!-- Information: device/common is tagged with android-sdk-adt_r20 --><project name="device/common" path="device/common" revision="7d4526582f88808a3194e1a3b304abb369d2745c"/>
   <!-- Information: device/sample is tagged with android-4.0.4_r2.1 --><project name="device/sample" path="device/sample" revision="ef228b8b377a9663e94be4b1aeb6c2bf7a07d098"/>
   <!-- Information: platform/external/apache-http is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.138 --><project name="platform/external/apache-http" path="external/apache-http" revision="6c9d8c58d3ed710f87c26820d903bb8aad81754f"/>
   <!-- Information: platform/external/bluetooth/bluez is tagged with android-4.0.4_r2.1 --><project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="966afbd88f0bfc325bf80274ad2723c238883fa1"/>
   <!-- Information: platform/external/bluetooth/glib is tagged with android-4.1.1_r6.1 --><project name="platform/external/bluetooth/glib" path="external/bluetooth/glib" revision="1143b9918eab068401b604eb11c3f651f4e38b25"/>
   <!-- Information: platform/external/bluetooth/hcidump is tagged with android-4.1.1_r6.1 --><project name="platform/external/bluetooth/hcidump" path="external/bluetooth/hcidump" revision="7322661808c2006b7848e79e6bb72b37fbcf6710"/>
   <!-- Information: platform/external/bsdiff is tagged with AU_LINUX_ANDROID_JB_REL_2.0.3.04.01.02.21.041 --><project name="platform/external/bsdiff" path="external/bsdiff" revision="81872540236d9bb15cccf963d05b9de48baa5375"/>
@@ -34,42 +34,42 @@
   <!-- Information: platform/external/dbus is tagged with android-4.1.1_r6.1 --><project name="platform/external/dbus" path="external/dbus" revision="537eaff5de9aace3348436166d4cde7adc1e488e"/>
   <!-- Information: platform/external/dhcpcd is tagged with android-sdk-adt_r20 --><project name="platform/external/dhcpcd" path="external/dhcpcd" revision="ddaa48f57b54b2862b3e6dcf18a44c9647f3baaa"/>
   <!-- Information: platform/external/dnsmasq is tagged with AU_LINUX_ANDROID_JB_REL_2.0.3.04.01.02.21.041 --><project name="platform/external/dnsmasq" path="external/dnsmasq" revision="f621afad94df46204c25fc2593a19d704d2637f5"/>
   <!-- Information: platform/external/expat is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.138 --><project name="platform/external/expat" path="external/expat" revision="6df134250feab71edb5915ecaa6268210bca76c5"/>
   <!-- Information: platform/external/fdlibm is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.138 --><project name="platform/external/fdlibm" path="external/fdlibm" revision="988ffeb12a6e044ae3504838ef1fee3fe0716934"/>
   <!-- Information: platform/external/flac is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.138 --><project name="platform/external/flac" path="external/flac" revision="5893fbe890f5dab8e4146d2baa4bd2691c0739e0"/>
   <!-- Information: platform/external/freetype is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.138 --><project name="platform/external/freetype" path="external/freetype" revision="aeb407daf3711a10a27f3bc2223c5eb05158076e"/>
   <!-- Information: platform/external/giflib is tagged with AU_LINUX_ANDROID_JB_REL_2.0.3.04.01.02.21.041 --><project name="platform/external/giflib" path="external/giflib" revision="b2597268aef084202a8c349d1cc072c03c6e22eb"/>
-  <!-- Information: platform/external/gtest is tagged with android-4.2.1_r1 --><project name="platform/external/gtest" path="external/gtest" remote="linaro" revision="344e5f3db17615cc853073a02968a603efd39109"/>
+  <!-- Information: platform/external/gtest is tagged with android-sdk-support_r11 --><project name="platform/external/gtest" path="external/gtest" remote="linaro" revision="344e5f3db17615cc853073a02968a603efd39109"/>
   <!-- Information: platform/external/harfbuzz is tagged with android-sdk-adt_r20 --><project name="platform/external/harfbuzz" path="external/harfbuzz" revision="bae491c03a00757d83ede8d855b7d85d246bde3d"/>
   <!-- Information: platform/external/icu4c is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.138 --><project name="platform/external/icu4c" path="external/icu4c" revision="0fa67b93b831c6636ca18b152a1b1b14cc99b034"/>
   <!-- Information: platform/external/iptables is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.138 --><project name="platform/external/iptables" path="external/iptables" revision="3b2deb17f065c5664bb25e1a28489e5792eb63ff"/>
   <!-- Information: platform/external/jhead is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.138 --><project name="platform/external/jhead" path="external/jhead" revision="754078052c687f6721536009c816644c73e4f145"/>
   <!-- Information: platform/external/jpeg is tagged with android-4.1.1_r6.1 --><project name="platform/external/jpeg" path="external/jpeg" revision="d4fad7f50f79626455d88523207e05b868819cd8"/>
   <!-- Information: platform/external/libgsm is tagged with AU_LINUX_ANDROID_JB_REL_2.0.3.04.01.02.21.041 --><project name="platform/external/libgsm" path="external/libgsm" revision="5e4516958690b9a1b2c98f88eeecba3edd2dbda4"/>
-  <!-- Information: platform/external/liblzf is tagged with AU_LINUX_ANDROID_JB_REL_2.0.3.04.01.02.21.041 --><project name="platform/external/liblzf" path="external/liblzf" revision="6946aa575b0949d045722794850896099d937cbb"/>
+  <!-- Information: platform/external/liblzf is tagged with android-sdk-support_r11 --><project name="platform/external/liblzf" path="external/liblzf" revision="6946aa575b0949d045722794850896099d937cbb"/>
   <!-- Information: platform/external/libnfc-nxp is tagged with android-4.0.4_r2.1 --><project name="platform/external/libnfc-nxp" path="external/libnfc-nxp" revision="533c14450e6239cce8acb74f4e4dea2c89f8f219"/>
-  <!-- Information: platform/external/libnl-headers is tagged with AU_LINUX_ANDROID_JB_REL_2.0.3.04.01.02.21.041 --><project name="platform/external/libnl-headers" path="external/libnl-headers" revision="6ccf7349d61f73ac26a0675d735d903ab919c658"/>
+  <!-- Information: platform/external/libnl-headers is tagged with android-sdk-support_r11 --><project name="platform/external/libnl-headers" path="external/libnl-headers" revision="6ccf7349d61f73ac26a0675d735d903ab919c658"/>
   <!-- Information: platform/external/libphonenumber is tagged with android-4.0.4_r2.1 --><project name="platform/external/libphonenumber" path="external/libphonenumber" revision="d470984844c388d6766c3de6ac64e93e00480fc9"/>
   <!-- Information: platform/external/libpng is tagged with android-4.0.4_r2.1 --><project name="platform/external/libpng" path="external/libpng" revision="84d92c718ab9f48faec0f640747c4b6f7a995607"/>
   <!-- Information: platform/external/libvpx is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.138 --><project name="platform/external/libvpx" path="external/libvpx" revision="3a40da0d96da5c520e7707aa14f48a80956e20d7"/>
   <!-- Information: platform/external/mksh is tagged with M8960AAAAANLYA1099D --><project name="platform/external/mksh" path="external/mksh" revision="5155f1c7438ef540d7b25eb70aa1639579795b07"/>
   <project name="platform_external_opensans" path="external/opensans" remote="b2g" revision="b5b4c226ca1d71e936153cf679dda6d3d60e2354"/>
   <!-- Information: platform/external/openssl is tagged with android-4.0.4_r2.1 --><project name="platform/external/openssl" path="external/openssl" revision="ce96fb211b9a44bbd7fb5ef7ed0e6c1244045c2e"/>
   <!-- Information: platform/external/protobuf is tagged with AU_LINUX_ANDROID_JB_REL_2.0.3.04.01.02.21.041 --><project name="platform/external/protobuf" path="external/protobuf" revision="e217977611c52bccde7f7c78e1d3c790c6357431"/>
   <!-- Information: platform/external/safe-iop is tagged with AU_LINUX_ANDROID_JB_REL_2.0.3.04.01.02.21.041 --><project name="platform/external/safe-iop" path="external/safe-iop" revision="07073634e2e3aa4f518e36ed5dec3aabc549d5fb"/>
   <project name="screencap-gonk" path="external/screencap-gonk" remote="b2g" revision="e6403c71e9eca8cb943739d5a0a192deac60fc51"/>
   <!-- Information: platform/external/skia is tagged with android-4.0.4_r2.1 --><project name="platform/external/skia" path="external/skia" revision="5c67a309e16bffe7013defda8f1217b3ce2420b4"/>
   <!-- Information: platform/external/sonivox is tagged with android-sdk-adt_r20 --><project name="platform/external/sonivox" path="external/sonivox" revision="5f9600971859fe072f31b38a51c38157f5f9b381"/>
   <!-- Information: platform/external/speex is tagged with AU_LINUX_ANDROID_JB_REL_2.0.3.04.01.02.21.041 --><project name="platform/external/speex" path="external/speex" revision="ebe6230a7f7c69f5a4389f2b09b7b19ef9e94f32"/>
   <!-- Information: platform/external/sqlite is tagged with android-4.0.4_r2.1 --><project name="platform/external/sqlite" path="external/sqlite" revision="c999ff8c12a4cf81cb9ad628f47b2720effba5e5"/>
   <!-- Information: platform/external/stlport is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.138 --><project name="platform/external/stlport" path="external/stlport" revision="a6734e0645fce81c9610de0488b729207bfa576e"/>
   <!-- Information: platform/external/strace is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.138 --><project name="platform/external/strace" path="external/strace" revision="c9fd2e5ef7d002e12e7cf2512506c84a9414b0fd"/>
-  <!-- Information: platform/external/tagsoup is tagged with AU_LINUX_ANDROID_JB_REL_2.0.3.04.01.02.21.041 --><project name="platform/external/tagsoup" path="external/tagsoup" revision="68c2ec9e0acdb3214b7fb91dbab8c9fab8736817"/>
+  <!-- Information: platform/external/tagsoup is tagged with android-sdk-support_r11 --><project name="platform/external/tagsoup" path="external/tagsoup" revision="68c2ec9e0acdb3214b7fb91dbab8c9fab8736817"/>
   <!-- Information: platform/external/tinyalsa is tagged with android-4.0.4_r2.1 --><project name="platform/external/tinyalsa" path="external/tinyalsa" revision="495239e683a728957c890c124b239f9b7b8ef5a8"/>
   <!-- Information: platform/external/tremolo is tagged with AU_LINUX_ANDROID_JB_REL_2.0.3.04.01.02.21.041 --><project name="platform/external/tremolo" path="external/tremolo" revision="25bd78d2392dbdc879ae53382cde9d019f79cf6f"/>
   <!-- Information: platform/external/webp is tagged with AU_LINUX_ANDROID_JB_REL_2.0.3.04.01.02.21.041 --><project name="platform/external/webp" path="external/webp" revision="88fe2b83c4b9232cd08729556fd0485d6a6a92cd"/>
   <!-- Information: platform/external/webrtc is tagged with android-sdk-adt_r20 --><project name="platform/external/webrtc" path="external/webrtc" revision="4b6dc1ec58105d17dc8c2f550124cc0621dc93b7"/>
   <!-- Information: platform/external/wpa_supplicant is tagged with AU_LINUX_GECKO_ICS_STRAWBERRY.01.00.00.19.138 --><project name="platform/external/wpa_supplicant" path="external/wpa_supplicant" revision="a01d37870bbf9892d43e792e5de0683ca41c5497"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="6dd24fc3792d71edccef9b09140f9a44b063a553"/>
   <!-- Information: platform/external/zlib is tagged with android-4.0.4_r2.1 --><project name="platform/external/zlib" path="external/zlib" revision="69e5801bd16a495e1c1666669fe827b1ddb8d56b"/>
   <!-- Information: platform/external/yaffs2 is tagged with android-4.0.4-aah_r1 --><project name="platform/external/yaffs2" path="external/yaffs2" revision="6232e2d5ab34a40d710e4b05ab0ec6e3727804e7"/>
@@ -85,16 +85,14 @@
   <!-- Information: platform/system/bluetooth is tagged with android-4.0.4_r2.1 --><project name="platform/system/bluetooth" path="system/bluetooth" revision="2588cd802f322650ed737dfb7a10e9ad94064e99"/>
   <!-- Information: platform/system/core is tagged with android-4.0.4_r2.1 --><project name="platform/system/core" path="system/core" revision="c2db4ffb874783220abf967ca4ccd0e6cf1ba57f"/>
   <!-- Information: platform/system/extras is tagged with android-4.0.4_r2.1 --><project name="platform/system/extras" path="system/extras" revision="fa351ab265957fa8815df3c4ca1f3c105f253e8b"/>
   <!-- Information: platform/system/media is tagged with android-4.0.4_r2.1 --><project name="platform/system/media" path="system/media" revision="a8eea50f80327f15cb04bbdfee2d1cfcc4c3ce4a"/>
   <!-- Information: platform/system/netd is tagged with android-4.0.4_r2.1 --><project name="platform/system/netd" path="system/netd" revision="3c903b555975fa59d6688a0a6417ac7512c202e7"/>
   <!-- Information: platform/system/vold is tagged with android-4.0.4_r2.1 --><project name="platform/system/vold" path="system/vold" revision="3ad9072a5d6f6bda32123b367545649364e3c11d"/>
 
   <!-- Pandaboard specific things -->
-  <project name="android-device-panda" path="device/ti/panda" remote="b2g" revision="63196b48f479c30787863c8ca89456acd4b03910"/>
+  <project name="android-device-panda" path="device/ti/panda" remote="b2g" revision="0e9a89187970d6fa99930c8d9cb438b935c2337c"/>
   <!-- Information: platform/hardware/ti/omap4xxx is tagged with android-4.0.4_r2.1 --><project name="platform/hardware/ti/omap4xxx" path="hardware/ti/omap4xxx" revision="8be8e9a68c96b6cf43c08a58e7ecd7708737c599"/>
   <project name="platform/hardware/ti/wlan" path="hardware/ti/wlan" revision="60dfeb6e4448bfed707946ebca6612980f525e69"/>
   <project name="platform/hardware/ti/wpan" path="hardware/ti/wpan" revision="3ece7d9e08052989401e008bc397dbcd2557cfd0"/>
-  <project name="Negatus" path="external/negatus" remote="mozilla" revision="5d5288e7bec67d0a6a29320308cccb1321062b58"/>
-  <project name="orangutan" path="external/orangutan" remote="b2g" revision="601280aed7d7f29f1a78496f6fa41bd79c16305c"/>
 
 </manifest>
\ No newline at end of file
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -14,17 +14,16 @@ MOZ_B2G_VERSION=1.0.0-prerelease
 MOZ_B2G_OS_NAME=Boot2Gecko
 
 MOZ_BRANDING_DIRECTORY=b2g/branding/unofficial
 MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/branding/official
 # MOZ_APP_DISPLAYNAME is set by branding/configure.sh
 
 MOZ_SAFE_BROWSING=
 MOZ_SERVICES_COMMON=1
-MOZ_SERVICES_HEALTHREPORT=1
 MOZ_SERVICES_METRICS=1
 
 MOZ_WEBSMS_BACKEND=1
 MOZ_DISABLE_DOMCRYPTO=1
 MOZ_APP_STATIC_INI=1
 
 if test "$OS_TARGET" = "Android"; then
 MOZ_CAPTURE=1
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1354916891000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1356125617000">
   <emItems>
       <emItem  blockID="i58" id="webmaster@buzzzzvideos.info">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i41" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
@@ -41,17 +41,17 @@
                         <versionRange  minVersion="0" maxVersion="1.0.8" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i100" id="{394DCBA4-1F92-4f8e-8EC9-8D2CB90CB69B}">
                         <versionRange  minVersion="2.5.0" maxVersion="2.5.0" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i236" id="{EEE6C361-6118-11DC-9C72-001320C79847}">
-                        <versionRange  minVersion="0" maxVersion="*" severity="1">
+                        <versionRange  minVersion="0" maxVersion="1.7.999" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i64" id="royal@facebook.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i72" os="WINNT" id="{4ED1F68A-5463-4931-9384-8FFF5ED91D92}">
                         <versionRange  minVersion="3.4.1" maxVersion="3.4.1.194" severity="1">
@@ -550,42 +550,26 @@
       <pluginItem  blockID="p138">
                   <match name="filename" exp="JavaAppletPlugin\.plugin" />                                    <versionRange  minVersion="Java 7 Update 01" maxVersion="Java 7 Update 06" severity="1">
                                 <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="0.1" maxVersion="17.*" />
                           </targetApplication>
                   </versionRange>
                   </pluginItem>
       <pluginItem  blockID="p152">
-                  <match name="filename" exp="npctrl\.dll" />                                    <versionRange  minVersion="0" maxVersion="4.1.10328.0" severity="0" vulnerabilitystatus="1">
-                                <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
-                              <versionRange  minVersion="4.0" maxVersion="16.*" />
-                          </targetApplication>
-                  </versionRange>
+                  <match name="filename" exp="npctrl\.dll" />                      <versionRange  minVersion="0" maxVersion="4.1.10328.0" severity="0" vulnerabilitystatus="1"></versionRange>
                   </pluginItem>
       <pluginItem  blockID="p154">
-                  <match name="filename" exp="npctrl\.dll" />                                    <versionRange  minVersion="5.0" maxVersion="5.1.10410.0" severity="0" vulnerabilitystatus="1">
-                                <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
-                              <versionRange  minVersion="4.0" maxVersion="16.*" />
-                          </targetApplication>
-                  </versionRange>
+                  <match name="filename" exp="npctrl\.dll" />                      <versionRange  minVersion="5.0" maxVersion="5.1.10410.0" severity="0" vulnerabilitystatus="1"></versionRange>
                   </pluginItem>
       <pluginItem  blockID="p156">
-                  <match name="filename" exp="nppdf32\.dll" />                                    <versionRange  minVersion="0" maxVersion="9.5.1" severity="0" vulnerabilitystatus="1">
-                                <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
-                              <versionRange  minVersion="4.0" maxVersion="16.*" />
-                          </targetApplication>
-                  </versionRange>
+                  <match name="filename" exp="nppdf32\.dll" />                      <versionRange  minVersion="0" maxVersion="9.5.1" severity="0" vulnerabilitystatus="1"></versionRange>
                   </pluginItem>
       <pluginItem  blockID="p158">
-                  <match name="filename" exp="nppdf32\.dll" />                                    <versionRange  minVersion="10.0" maxVersion="10.1.3" severity="0" vulnerabilitystatus="1">
-                                <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
-                              <versionRange  minVersion="4.0" maxVersion="16.*" />
-                          </targetApplication>
-                  </versionRange>
+                  <match name="filename" exp="nppdf32\.dll" />                      <versionRange  minVersion="10.0" maxVersion="10.1.3" severity="0" vulnerabilitystatus="1"></versionRange>
                   </pluginItem>
       <pluginItem  blockID="p160">
                   <match name="filename" exp="NPSWF32\.dll" />                                    <versionRange  minVersion="0" maxVersion="10.2.9999" severity="0" vulnerabilitystatus="1">
                                 <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="4.0" maxVersion="16.*" />
                           </targetApplication>
                   </versionRange>
                   </pluginItem>
@@ -601,52 +585,52 @@
                                 <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="18.0a1" maxVersion="*" />
                           </targetApplication>
                   </versionRange>
                   </pluginItem>
       <pluginItem  blockID="p180">
                   <match name="filename" exp="JavaAppletPlugin\.plugin" />                                    <versionRange  minVersion="Java 7 Update 07" maxVersion="Java 7 Update 08" severity="0" vulnerabilitystatus="1">
                                 <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
-                              <versionRange  minVersion="18.0a1" maxVersion="*" />
+                              <versionRange  minVersion="17.0" maxVersion="*" />
                           </targetApplication>
                   </versionRange>
                   </pluginItem>
       <pluginItem  blockID="p182">
       <match name="name" exp="Java\(TM\) Platform SE 7 U[7-8](\s[^\d\._U]|$)" />            <match name="filename" exp="npjp2\.dll" />                                    <versionRange  severity="0" vulnerabilitystatus="1">
                                 <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
-                              <versionRange  minVersion="18.0a1" maxVersion="*" />
+                              <versionRange  minVersion="17.0" maxVersion="*" />
                           </targetApplication>
                   </versionRange>
                   </pluginItem>
       <pluginItem  blockID="p184">
       <match name="name" exp="Java\(TM\) Plug-in 1\.7\.0(_0?([7-8]))?([^\d\._]|$)" />            <match name="filename" exp="libnpjp2\.so" />                                    <versionRange  severity="0" vulnerabilitystatus="1">
                                 <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
-                              <versionRange  minVersion="18.0a1" maxVersion="*" />
+                              <versionRange  minVersion="17.0" maxVersion="*" />
                           </targetApplication>
                   </versionRange>
                   </pluginItem>
       <pluginItem  blockID="p186">
       <match name="name" exp="Java\(TM\) Platform SE 6 U3[3-6](\s[^\d\._U]|$)" />            <match name="filename" exp="npjp2\.dll" />                                    <versionRange  severity="0" vulnerabilitystatus="1">
                                 <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
-                              <versionRange  minVersion="18.0a1" maxVersion="*" />
+                              <versionRange  minVersion="17.0" maxVersion="*" />
                           </targetApplication>
                   </versionRange>
                   </pluginItem>
       <pluginItem  blockID="p188">
                   <match name="filename" exp="JavaAppletPlugin\.plugin" />                                    <versionRange  minVersion="Java 6 Update 0" maxVersion="Java 6 Update 36" severity="0" vulnerabilitystatus="1">
                                 <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
-                              <versionRange  minVersion="18.0a1" maxVersion="*" />
+                              <versionRange  minVersion="17.0" maxVersion="*" />
                           </targetApplication>
                   </versionRange>
                   </pluginItem>
       <pluginItem  blockID="p190">
       <match name="name" exp="Java\(TM\) Plug-in 1\.6\.0_3[3-6]([^\d\._]|$)" />            <match name="filename" exp="libnpjp2\.so" />                                    <versionRange  severity="0" vulnerabilitystatus="1">
                                 <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
-                              <versionRange  minVersion="18.0a1" maxVersion="*" />
+                              <versionRange  minVersion="17.0" maxVersion="*" />
                           </targetApplication>
                   </versionRange>
                   </pluginItem>
       <pluginItem  blockID="p210">
       <match name="name" exp="Java\(TM\) Plug-in 1\.7\.0(_0?7)?([^\d\._]|$)" />            <match name="filename" exp="libnpjp2\.so" />                                    <versionRange  severity="1">
                                 <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="0.1" maxVersion="17.*" />
                           </targetApplication>
@@ -661,16 +645,26 @@
                   </pluginItem>
       <pluginItem  blockID="p214">
       <match name="name" exp="Java\(TM\) Platform SE 7 U7(\s[^\d\._U]|$)" />            <match name="filename" exp="npjp2\.dll" />                                    <versionRange  severity="1">
                                 <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="0.1" maxVersion="17.*" />
                           </targetApplication>
                   </versionRange>
                   </pluginItem>
+      <pluginItem  blockID="p240">
+                  <match name="filename" exp="DivXBrowserPlugin\.plugin" />                      <versionRange  minVersion="0" maxVersion="1.4" severity="1"></versionRange>
+                  </pluginItem>
+      <pluginItem  os="Darwin" blockID="p242">
+            <match name="description" exp="Flip4Mac" />                                          <versionRange  minVersion="0" maxVersion="2.4.3.999" severity="1">
+                                <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="18.0a1" maxVersion="*" />
+                          </targetApplication>
+                  </versionRange>
+                  </pluginItem>
     </pluginItems>
 
   <gfxItems>
     <gfxBlacklistEntry  blockID="g35">      <os>WINNT 6.1</os>      <vendor>0x10de</vendor>              <devices>
                       <device>0x0a6c</device>
                   </devices>
             <feature>DIRECT2D</feature>      <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus>      <driverVersion>8.17.12.5896</driverVersion>      <driverVersionComparator>LESS_THAN_OR_EQUAL</driverVersionComparator>    </gfxBlacklistEntry>
     <gfxBlacklistEntry  blockID="g36">      <os>WINNT 6.1</os>      <vendor>0x10de</vendor>              <devices>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1030,17 +1030,16 @@ pref("devtools.responsiveUI.enabled", tr
 pref("devtools.debugger.enabled", true);
 pref("devtools.debugger.chrome-enabled", true);
 pref("devtools.debugger.remote-host", "localhost");
 pref("devtools.debugger.remote-autoconnect", false);
 pref("devtools.debugger.remote-connection-retries", 3);
 pref("devtools.debugger.remote-timeout", 20000);
 
 // The default Debugger UI settings
-pref("devtools.debugger.ui.height", 250);
 pref("devtools.debugger.ui.win-x", 0);
 pref("devtools.debugger.ui.win-y", 0);
 pref("devtools.debugger.ui.win-width", 900);
 pref("devtools.debugger.ui.win-height", 400);
 pref("devtools.debugger.ui.stackframes-width", 200);
 pref("devtools.debugger.ui.variables-width", 300);
 pref("devtools.debugger.ui.panes-visible-on-startup", false);
 pref("devtools.debugger.ui.variables-sorting-enabled", true);
--- a/browser/base/content/browser-appmenu.inc
+++ b/browser/base/content/browser-appmenu.inc
@@ -142,52 +142,52 @@
                       label="&printPreviewCmd.label;"
                       command="cmd_printPreview"/>
             <menuitem id="appmenu_printSetup"
                       label="&printSetupCmd.label;"
                       command="cmd_pageSetup"/>
           </menupopup>
       </splitmenu>
       <menuseparator class="appmenu-menuseparator"/>
-      <menu id="appmenu_webDeveloper"
-            label="&appMenuWebDeveloper.label;">
+      <splitmenu id="appmenu_webDeveloper"
+                 command="Tools:DevToolbox"
+                 label="&appMenuWebDeveloper.label;">
         <menupopup id="appmenu_webDeveloper_popup">
           <menuitem id="appmenu_devToolbox"
                     observes="devtoolsMenuBroadcaster_DevToolbox"/>
           <menuseparator id="appmenu_devtools_separator"/>
           <menuitem id="appmenu_devToolbar"
                     observes="devtoolsMenuBroadcaster_DevToolbar"/>
           <menuitem id="appmenu_chromeDebugger"
                     observes="devtoolsMenuBroadcaster_ChromeDebugger"/>
           <menuitem id="appmenu_responsiveUI"
                     observes="devtoolsMenuBroadcaster_ResponsiveUI"/>
           <menuitem id="appmenu_scratchpad"
                     observes="devtoolsMenuBroadcaster_Scratchpad"/>
           <menuitem id="appmenu_pageSource"
                     observes="devtoolsMenuBroadcaster_PageSource"/>
           <menuitem id="appmenu_errorConsole"
                     observes="devtoolsMenuBroadcaster_ErrorConsole"/>
-          <menuseparator id="appmenu_devToolsConnectSeparator"/>
           <menuitem id="appmenu_devtools_connect"
                     observes="devtoolsMenuBroadcaster_connect"/>
           <menuseparator id="appmenu_devToolsEndSeparator"/>
           <menuitem id="appmenu_getMoreDevtools"
                     observes="devtoolsMenuBroadcaster_GetMoreTools"/>
           <menuseparator/>
 #define ID_PREFIX appmenu_developer_
 #define OMIT_ACCESSKEYS
 #include browser-charsetmenu.inc
 #undef ID_PREFIX
 #undef OMIT_ACCESSKEYS
           <menuitem label="&goOfflineCmd.label;"
                     type="checkbox"
                     observes="workOfflineMenuitemState"
                     oncommand="BrowserOffline.toggleOfflineStatus();"/>
         </menupopup>
-      </menu>
+      </splitmenu>
       <menuseparator class="appmenu-menuseparator"/>
 #define ID_PREFIX appmenu_
 #define OMIT_ACCESSKEYS
 #include browser-charsetmenu.inc
 #undef ID_PREFIX
 #undef OMIT_ACCESSKEYS
       <menuitem id="appmenu_fullScreen"
                 class="menuitem-tooltip"
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -579,17 +579,16 @@
                             observes="devtoolsMenuBroadcaster_Scratchpad"
                             accesskey="&scratchpad.accesskey;"/>
                   <menuitem id="menu_pageSource"
                             observes="devtoolsMenuBroadcaster_PageSource"
                             accesskey="&pageSourceCmd.accesskey;"/>
                   <menuitem id="javascriptConsole"
                             observes="devtoolsMenuBroadcaster_ErrorConsole"
                             accesskey="&errorConsoleCmd.accesskey;"/>
-                  <menuseparator id="menu_devToolsConnectSeparator"/>
                   <menuitem id="menu_devtools_connect"
                             observes="devtoolsMenuBroadcaster_connect"/>
                   <menuseparator id="devToolsEndSeparator"/>
                   <menuitem id="getMoreDevtools"
                             observes="devtoolsMenuBroadcaster_GetMoreTools"
                             accesskey="&getMoreDevtoolsCmd.accesskey;"/>
                 </menupopup>
               </menu>
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -435,17 +435,17 @@ var PlacesCommandHook = {
                                      }, window);
   },
 
   /**
    * Opens the Places Organizer. 
    * @param   aLeftPaneRoot
    *          The query to select in the organizer window - options
    *          are: History, AllBookmarks, BookmarksMenu, BookmarksToolbar,
-   *          UnfiledBookmarks and Tags.
+   *          UnfiledBookmarks, Tags and Downloads.
    */
   showPlacesOrganizer: function PCH_showPlacesOrganizer(aLeftPaneRoot) {
     var organizer = Services.wm.getMostRecentWindow("Places:Organizer");
     if (!organizer) {
       // No currently open places window, so open one with the specified mode.
       openDialog("chrome://browser/content/places/places.xul", 
                  "", "chrome,toolbar=yes,dialog=no,resizable", aLeftPaneRoot);
     }
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -139,17 +139,16 @@ var gPluginHandler = {
         return "PluginPlayPreview";
       default:
         // Not all states map to a handler
         return null;
     }
   },
 
   handleEvent : function(event) {
-    let self = gPluginHandler;
     let plugin = event.target;
     let doc = plugin.ownerDocument;
 
     // We're expecting the target to be a plugin.
     if (!(plugin instanceof Ci.nsIObjectLoadingContent))
       return;
 
     let eventType = event.type;
@@ -159,98 +158,98 @@ var gPluginHandler = {
       // and make sure we don't handle it twice
       let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
       if (!overlay || overlay._bindingHandled) {
         return;
       }
       overlay._bindingHandled = true;
 
       // Lookup the handler for this binding
-      eventType = self._getBindingType(plugin);
+      eventType = this._getBindingType(plugin);
       if (!eventType) {
         // Not all bindings have handlers
         return;
       }
     }
 
     switch (eventType) {
       case "PluginCrashed":
-        self.pluginInstanceCrashed(plugin, event);
+        this.pluginInstanceCrashed(plugin, event);
         break;
 
       case "PluginNotFound":
         // For non-object plugin tags, register a click handler to install the
         // plugin. Object tags can, and often do, deal with that themselves,
         // so don't stomp on the page developers toes.
         if (!(plugin instanceof HTMLObjectElement)) {
           // We don't yet check to see if there's actually an installer available.
           let installStatus = doc.getAnonymousElementByAttribute(plugin, "class", "installStatus");
           installStatus.setAttribute("status", "ready");
           let iconStatus = doc.getAnonymousElementByAttribute(plugin, "class", "icon");
           iconStatus.setAttribute("status", "ready");
 
           let installLink = doc.getAnonymousElementByAttribute(plugin, "class", "installPluginLink");
-          self.addLinkClickCallback(installLink, "installSinglePlugin", plugin);
+          this.addLinkClickCallback(installLink, "installSinglePlugin", plugin);
         }
         /* FALLTHRU */
 
       case "PluginBlocklisted":
       case "PluginOutdated":
 #ifdef XP_MACOSX
       case "npapi-carbon-event-model-failure":
 #endif
-        self.pluginUnavailable(plugin, eventType);
+        this.pluginUnavailable(plugin, eventType);
         break;
 
       case "PluginVulnerableUpdatable":
         let updateLink = doc.getAnonymousElementByAttribute(plugin, "class", "checkForUpdatesLink");
-        self.addLinkClickCallback(updateLink, "openPluginUpdatePage");
+        this.addLinkClickCallback(updateLink, "openPluginUpdatePage");
         /* FALLTHRU */
 
       case "PluginVulnerableNoUpdate":
       case "PluginClickToPlay":
-        self._handleClickToPlayEvent(plugin);
+        this._handleClickToPlayEvent(plugin);
         let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
-        let pluginName = self._getPluginInfo(plugin).pluginName;
+        let pluginName = this._getPluginInfo(plugin).pluginName;
         let messageString = gNavigatorBundle.getFormattedString("PluginClickToPlay", [pluginName]);
         let overlayText = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgClickToPlay");
         overlayText.textContent = messageString;
         if (eventType == "PluginVulnerableUpdatable" ||
             eventType == "PluginVulnerableNoUpdate") {
           let vulnerabilityString = gNavigatorBundle.getString(eventType);
           let vulnerabilityText = doc.getAnonymousElementByAttribute(plugin, "anonid", "vulnerabilityStatus");
           vulnerabilityText.textContent = vulnerabilityString;
         }
         break;
 
       case "PluginPlayPreview":
-        self._handlePlayPreviewEvent(plugin);
+        this._handlePlayPreviewEvent(plugin);
         break;
 
       case "PluginDisabled":
         let manageLink = doc.getAnonymousElementByAttribute(plugin, "class", "managePluginsLink");
-        self.addLinkClickCallback(manageLink, "managePlugins");
+        this.addLinkClickCallback(manageLink, "managePlugins");
         break;
 
       case "PluginScripted":
         let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
         if (browser._pluginScriptedState == this.PLUGIN_SCRIPTED_STATE_NONE) {
           browser._pluginScriptedState = this.PLUGIN_SCRIPTED_STATE_FIRED;
           setTimeout(function() {
             gPluginHandler.handlePluginScripted(this);
           }.bind(browser), 500);
         }
         break;
     }
 
     // Hide the in-content UI if it's too big. The crashed plugin handler already did this.
     if (eventType != "PluginCrashed") {
       let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
-      if (overlay != null && self.isTooSmall(plugin, overlay))
-          overlay.style.visibility = "hidden";
+      if (overlay != null && this.isTooSmall(plugin, overlay))
+        overlay.style.visibility = "hidden";
     }
   },
 
   _notificationDisplayedOnce: false,
   handlePluginScripted: function PH_handlePluginScripted(aBrowser) {
     let contentWindow = aBrowser.contentWindow;
     if (!contentWindow)
       return;
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -92,17 +92,17 @@
     <command id="Tools:DevToolbox" oncommand="gDevToolsBrowser.toggleToolboxCommand(gBrowser);"/>
     <command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true" hidden="true"/>
     <command id="Tools:DevToolbarFocus" oncommand="DeveloperToolbar.focusToggle();" disabled="true"/>
     <command id="Tools:ChromeDebugger" oncommand="DebuggerUI.toggleChromeDebugger();" disabled="true" hidden="true"/>
     <command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true" hidden="true"/>
     <command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();" disabled="true" hidden="true"/>
     <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
     <command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" disabled="true" hidden="true"/>
-    <command id="Tools:DevToolsConnect" oncommand="gDevToolsBrowser.openConnectScreen(gBrowser)"/>
+    <command id="Tools:DevToolsConnect" oncommand="gDevToolsBrowser.openConnectScreen(gBrowser)" disabled="true" hidden="true"/>
     <command id="Tools:Sanitize"
      oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
     <command id="Tools:PrivateBrowsing"
 #ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
       oncommand="OpenBrowserWindow({private: true});"/>
 #else
       oncommand="gPrivateBrowsingUI.toggleMode();"/>
 #endif
@@ -346,22 +346,20 @@
 # Cmd+I is conventially mapped to Info on MacOS X, thus it should not be
 # overridden for other purposes there.
     <key id="viewBookmarksSidebarWinKb" key="&bookmarksWinCmd.commandkey;" command="viewBookmarksSidebar" modifiers="accel"/>
 #endif
     
     <key id="sharePage" key="&sharePageCmd.commandkey;" command="Social:SharePage" modifiers="accel,shift"/>
     <key id="focusChatBar" key="&social.chatBar.commandkey;" command="Social:FocusChat" modifiers="accel,shift"/>
 
-# don't use |command="Browser:Stop"|, ESC is being used to freeze animated gifs,
-# even if the stop button and menuitem are disabled (see Bug 284140)
-    <key id="key_stop" keycode="VK_ESCAPE" oncommand="BrowserStop();"/>
+    <key id="key_stop" keycode="VK_ESCAPE" command="Browser:Stop"/>
 
 #ifdef XP_MACOSX
-    <key id="key_stop_mac" modifiers="accel" key="&stopCmd.macCommandKey;" oncommand="BrowserStop();"/>
+    <key id="key_stop_mac" modifiers="accel" key="&stopCmd.macCommandKey;" command="Browser:Stop"/>
 #endif
 
     <key id="key_gotoHistory"
          key="&historySidebarCmd.commandKey;"
 #ifdef XP_MACOSX
          modifiers="accel,shift"
 #else
          modifiers="accel"
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -713,17 +713,17 @@ var SocialToolbar = {
     this.updateProvider();
     this._dynamicResizer = new DynamicResizeWatcher();
   },
 
   // Called when the Social.provider changes
   updateProvider: function () {
     if (!Social.provider)
       return;
-    this.button.setAttribute("image", Social.provider.iconURL);
+    this.button.style.listStyleImage = "url(" + Social.provider.iconURL + ")";
     this.updateButton();
     this.updateProfile();
     this.populateProviderMenus();
   },
 
   get button() {
     return document.getElementById("social-provider-button");
   },
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1439,16 +1439,24 @@ var gBrowserInit = {
     // Enable Scratchpad in the UI, if the preference allows this.
     let scratchpadEnabled = gPrefService.getBoolPref(Scratchpad.prefEnabledName);
     if (scratchpadEnabled) {
       let cmd = document.getElementById("Tools:Scratchpad");
       cmd.removeAttribute("disabled");
       cmd.removeAttribute("hidden");
     }
 
+    // Enable DevTools connection screen, if the preference allows this.
+    let devtoolsRemoteEnabled = gPrefService.getBoolPref("devtools.debugger.remote-enabled");
+    if (devtoolsRemoteEnabled) {
+      let cmd = document.getElementById("Tools:DevToolsConnect");
+      cmd.removeAttribute("disabled");
+      cmd.removeAttribute("hidden");
+    }
+
 #ifdef MENUBAR_CAN_AUTOHIDE
     // If the user (or the locale) hasn't enabled the top-level "Character
     // Encoding" menu via the "browser.menu.showCharacterEncoding" preference,
     // hide it.
     if ("true" != gPrefService.getComplexValue("browser.menu.showCharacterEncoding",
                                                Ci.nsIPrefLocalizedString).data)
       document.getElementById("appmenu_charsetMenu").hidden = true;
 #endif
@@ -1749,17 +1757,18 @@ function HandleAppCommandEvent(evt) {
     break;
   case "Forward":
     BrowserForward();
     break;
   case "Reload":
     BrowserReloadSkipCache();
     break;
   case "Stop":
-    BrowserStop();
+    if (XULBrowserWindow.stopCommand.getAttribute("disabled") != "true")
+      BrowserStop();
     break;
   case "Search":
     BrowserSearch.webSearch();
     break;
   case "Bookmarks":
     toggleSidebar('viewBookmarksSidebar');
     break;
   case "Home":
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -39,17 +39,16 @@
         titlemodifier_privatebrowsing="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@ &mainWindow.titlePrivateBrowsingSuffix;"
 #endif
         titlemenuseparator="&mainWindow.titlemodifiermenuseparator;"
         lightweightthemes="true"
         lightweightthemesfooter="browser-bottombox"
         windowtype="navigator:browser"
         macanimationtype="document"
         screenX="4" screenY="4"
-        browsingmode="normal"
         fullscreenbutton="true"
         persist="screenX screenY width height sizemode">
 
 # All JS files which are not content (only) dependent that browser.xul
 # wishes to include *must* go into the global-scripts.inc file
 # so that they can be shared by macBrowserOverlay.xul.
 #include global-scripts.inc
 <script type="application/javascript" src="chrome://browser/content/nsContextMenu.js"/>
@@ -439,16 +438,37 @@
     <tooltip id="forward-button-tooltip">
       <label class="tooltip-label" value="&forwardButton.tooltip;"/>
 #ifdef XP_MACOSX
       <label class="tooltip-label" value="&backForwardButtonMenuMac.tooltip;"/>
 #else
       <label class="tooltip-label" value="&backForwardButtonMenu.tooltip;"/>
 #endif
     </tooltip>
+
+    <popupnotification id="webRTC-shareDevices-notification" hidden="true">
+      <popupnotificationcontent id="webRTC-selectCamera" orient="vertical">
+        <separator class="thin"/>
+        <label value="&getUserMedia.selectCamera.label;"
+               accesskey="&getUserMedia.selectCamera.accesskey;"
+               control="webRTC-selectCamera-menulist"/>
+        <menulist id="webRTC-selectCamera-menulist">
+          <menupopup id="webRTC-selectCamera-menupopup"/>
+        </menulist>
+      </popupnotificationcontent>
+      <popupnotificationcontent id="webRTC-selectMicrophone" orient="vertical">
+        <separator class="thin"/>
+        <label value="&getUserMedia.selectMicrophone.label;"
+               accesskey="&getUserMedia.selectMicrophone.accesskey;"
+               control="webRTC-selectMicrophone-menulist"/>
+        <menulist id="webRTC-selectMicrophone-menulist">
+          <menupopup id="webRTC-selectMicrophone-menupopup"/>
+        </menulist>
+      </popupnotificationcontent>
+    </popupnotification>
   </popupset>
 
 #ifdef CAN_DRAW_IN_TITLEBAR
 <vbox id="titlebar">
   <hbox id="titlebar-content">
     <hbox id="appmenu-button-container">
       <button id="appmenu-button"
               type="menu"
--- a/browser/base/content/test/feed_discovery.html
+++ b/browser/base/content/test/feed_discovery.html
@@ -83,21 +83,21 @@ https://bugzilla.mozilla.org/show_bug.cg
         var browser = currentWindow.gBrowser.selectedBrowser;
 
         var discovered = browser.feeds;
         tests.push({ check: discovered.length > 0,
                      message: "some feeds should be discovered" });
 
         var feeds = [];
 
-        for each (var aFeed in discovered) {
+        for (var aFeed of discovered) {
           feeds[aFeed.href] = true;
         }
 
-        for each (var aLink in document.getElementsByTagName("link")) {
+        for (var aLink of document.getElementsByTagName("link")) {
           // ignore real stylesheets, and anything without an href property
           if (aLink.type != "text/css" && aLink.href) {
             if (/bogus/i.test(aLink.title)) {
               tests.push({ check: !feeds[aLink.href],
                            message: "don't discover " + aLink.href });
             } else {
               tests.push({ check: feeds[aLink.href],
                            message: "should discover " + aLink.href });
--- a/browser/base/content/test/social/Makefile.in
+++ b/browser/base/content/test/social/Makefile.in
@@ -7,17 +7,16 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 _BROWSER_FILES = \
                  head.js \
-                 browser_social.js \
                  browser_social_toolbar.js \
                  browser_social_shareButton.js \
                  browser_social_sidebar.js \
                  browser_social_flyout.js \
                  browser_social_mozSocial_API.js \
                  browser_social_isVisible.js \
                  browser_social_chatwindow.js \
                  browser_social_multiprovider.js \
@@ -25,12 +24,18 @@ include $(DEPTH)/config/autoconf.mk
                  social_share_image.png \
                  social_sidebar.html \
                  social_chat.html \
                  social_flyout.html \
                  social_window.html \
                  social_worker.js \
                  $(NULL)
 
+ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
+_BROWSER_FILES += \
+                browser_social.js \
+                $(NULL)
+endif
+
 include $(topsrcdir)/config/rules.mk
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/components/downloads/content/allDownloadsViewOverlay.css
@@ -0,0 +1,33 @@
+/* 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/. */
+ 
+richlistitem.download {
+  -moz-binding: url('chrome://browser/content/downloads/download.xml#download-full-ui');
+}
+
+.download-state:not(          [state="0"]  /* Downloading        */)
+                                           .downloadPauseMenuItem,
+.download-state:not(          [state="4"]  /* Paused             */)
+                                           .downloadResumeMenuItem,
+.download-state:not(:-moz-any([state="2"], /* Failed             */
+                              [state="4"]) /* Paused             */)
+                                           .downloadCancelMenuItem,
+.download-state:not(:-moz-any([state="1"], /* Finished           */
+                              [state="2"], /* Failed             */
+                              [state="3"], /* Canceled           */
+                              [state="6"], /* Blocked (parental) */
+                              [state="8"], /* Blocked (dirty)    */
+                              [state="9"]) /* Blocked (policy)   */)
+                                           .downloadRemoveFromHistoryMenuItem,
+.download-state:not(:-moz-any([state="-1"],/* Starting (initial) */
+                              [state="5"], /* Starting (queued)  */
+                              [state="0"], /* Downloading        */
+                              [state="4"]) /* Paused             */)
+                                           .downloadShowMenuItem,
+
+.download-state[state="7"]                 .downloadCommandsSeparator
+
+{
+  display: none;
+}
rename from browser/components/places/content/downloadsView.js
rename to browser/components/downloads/content/allDownloadsViewOverlay.js
--- a/browser/components/places/content/downloadsView.js
+++ b/browser/components/downloads/content/allDownloadsViewOverlay.js
@@ -11,29 +11,32 @@
 let Cu = Components.utils;
 let Ci = Components.interfaces;
 let Cc = Components.classes;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/DownloadUtils.jsm");
 Cu.import("resource:///modules/DownloadsCommon.jsm");
+Cu.import("resource://gre/modules/PlacesUtils.jsm");
 
 const nsIDM = Ci.nsIDownloadManager;
 
 const DESTINATION_FILE_URI_ANNO  = "downloads/destinationFileURI";
 const DESTINATION_FILE_NAME_ANNO = "downloads/destinationFileName";
 const DOWNLOAD_STATE_ANNO        = "downloads/state";
 
 const DOWNLOAD_VIEW_SUPPORTED_COMMANDS =
  ["cmd_delete", "cmd_copy", "cmd_paste", "cmd_selectAll",
   "downloadsCmd_pauseResume", "downloadsCmd_cancel",
   "downloadsCmd_open", "downloadsCmd_show", "downloadsCmd_retry",
   "downloadsCmd_openReferrer"];
 
+const NOT_AVAILABLE = Number.MAX_VALUE;
+
 function GetFileForFileURI(aFileURI)
   Cc["@mozilla.org/network/protocol;1?name=file"]
     .getService(Ci.nsIFileProtocolHandler)
     .getFileFromURLSpec(aFileURI);
 
 /**
  * A download element shell is responsible for handling the commands and the
  * displayed data for a single download view element. The download element
@@ -55,55 +58,65 @@ function GetFileForFileURI(aFileURI)
  *  - The DownloadsPlacesView object adds itself as a places result observer and
  *    calls this object's placesNodeIconChanged, placesNodeTitleChanged and
  *    placeNodeAnnotationChanged from its callbacks.
  *
  * @param [optional] aDataItem
  *        The data item of a the session download. Required if aPlacesNode is not set
  * @param [optional] aPlacesNode
  *        The places node for a past download. Required if aDataItem is not set.
+ * @param [optional] aAnnotations
+ *        Map containing annotations values, to speed up the initial loading.
  */
-function DownloadElementShell(aDataItem, aPlacesNode) {
+function DownloadElementShell(aDataItem, aPlacesNode, aAnnotations) {
   this._element = document.createElement("richlistitem");
   this._element._shell = this;
 
   this._element.classList.add("download");
   this._element.classList.add("download-state");
 
+ if (aAnnotations)
+    this._annotations = aAnnotations;
   if (aDataItem)
     this.dataItem = aDataItem;
   if (aPlacesNode)
     this.placesNode = aPlacesNode;
 }
 
 DownloadElementShell.prototype = {
   // The richlistitem for the download
   get element() this._element,
 
   // The data item for the download
+  _dataItem: null,
   get dataItem() this._dataItem,
 
   set dataItem(aValue) {
-    if (this._dataItem = aValue) {
+    if ((this._dataItem = aValue)) {
       this._wasDone = this._dataItem.done;
       this._wasInProgress = this._dataItem.inProgress;
     }
     else if (this._placesNode) {
       this._wasInProgress = false;
       this._wasDone = this._state == nsIDM.DOWNLOAD_FINISHED;
     }
 
     this._updateStatusUI();
     return aValue;
   },
 
+  _placesNode: null,
   get placesNode() this._placesNode,
   set placesNode(aNode) {
     if (this._placesNode != aNode) {
-      this._annotations = new Map();
+      // Preserve the annotations map if this is the first loading and we got
+      // cached values.
+      if (this._placesNode || !this._annotations) {
+        this._annotations = new Map();
+      }
       this._placesNode = aNode;
       if (!this._dataItem && this._placesNode) {
         this._wasInProgress = false;
         this._wasDone = this._state == nsIDM.DOWNLOAD_FINISHED;
         this._updateStatusUI();
       }
     }
     return aNode;
@@ -131,31 +144,40 @@ DownloadElementShell.prototype = {
       return this.placesNode.icon;
     if (this._dataItem)
       throw new Error("Session-download items should always have a target file uri");
     throw new Error("Unexpected download element state");
   },
 
   // Helper for getting a places annotation set for the download.
   _getAnnotation: function DES__getAnnotation(aAnnotation, aDefaultValue) {
+    let value;
     if (this._annotations.has(aAnnotation))
-      return this._annotations.get(aAnnotation);
+      value = this._annotations.get(aAnnotation);
 
-    let value;
-    try {
-      value = PlacesUtils.annotations.getPageAnnotation(
-        this._downloadURIObj, aAnnotation);
+    // If the value is cached, or we know it doesn't exist, avoid a database
+    // lookup.
+    if (value === undefined) {
+      try {
+        value = PlacesUtils.annotations.getPageAnnotation(
+          this._downloadURIObj, aAnnotation);
+      }
+      catch(ex) {
+        value = NOT_AVAILABLE;
+      }
     }
-    catch(ex) {
+
+    if (value === NOT_AVAILABLE) {
       if (aDefaultValue === undefined) {
         throw new Error("Could not get required annotation '" + aAnnotation +
                         "' for download with url '" + this.downloadURI + "'");
       }
       value = aDefaultValue;
     }
+
     this._annotations.set(aAnnotation, value);
     return value;
   },
 
   // The uri (as a string) of the target file, if any.
   get _targetFileURI() {
     if (this._dataItem)
       return this._dataItem.file;
@@ -422,16 +444,17 @@ DownloadElementShell.prototype = {
       case "cmd_delete":
         // The behavior in this case is somewhat unexpected, so we disallow that.
         if (this._placesNode && this._dataItem && this._dataItem.inProgress)
           return false;
         return true;
       case "downloadsCmd_cancel":
         return this._dataItem != null;
     }
+    return false;
   },
 
   _getTargetFileOrPartFileIfExists: function DES__getTargetFileOrPartFileIfExists() {
     if (this._file && this._file.exists())
       return this._file;
     if (this._dataItem &&
         this._dataItem.partFile && this._dataItem.partFile.exists())
       return this._dataItem.partFile;
@@ -517,16 +540,17 @@ DownloadElementShell.prototype = {
         case nsIDM.DOWNLOAD_DOWNLOADING:
         case nsIDM.DOWNLOAD_SCANNING:
           return "downloadsCmd_show";
         case nsIDM.DOWNLOAD_BLOCKED_PARENTAL:
         case nsIDM.DOWNLOAD_DIRTY:
         case nsIDM.DOWNLOAD_BLOCKED_POLICY:
           return "downloadsCmd_openReferrer";
       }
+      return "";
     }
     let command = getDefaultCommandForState(this._state);
     if (this.isCommandEnabled(command))
       this.doCommand(command);
   }
 };
 
 /**
@@ -578,16 +602,48 @@ DownloadsPlacesView.prototype = {
     if (this._downloadElementsShellsForURI.has(aURI)) {
       let downloadElementShells = this._downloadElementsShellsForURI.get(aURI);
       for (let des of downloadElementShells) {
         aCallback(des);
       }
     }
   },
 
+  _getAnnotationsFor: function DPV_getAnnotationsFor(aURI) {
+    if (!this._cachedAnnotations) {
+      this._cachedAnnotations = new Map();
+      for (let name of [ DESTINATION_FILE_URI_ANNO,
+                         DESTINATION_FILE_NAME_ANNO,
+                         DOWNLOAD_STATE_ANNO ]) {
+        let results = PlacesUtils.annotations.getAnnotationsWithName(name);
+        for (let result of results) {
+          let url = result.uri.spec;
+          if (!this._cachedAnnotations.has(url))
+            this._cachedAnnotations.set(url, new Map());
+          let m = this._cachedAnnotations.get(url);
+          m.set(result.annotationName, result.annotationValue);
+        }
+      }
+    }
+
+    let annotations = this._cachedAnnotations.get(aURI);
+    if (!annotations) {
+      // There are no annotations for this entry, that means it is quite old.
+      // Make up a fake annotations entry with default values.
+      annotations = new Map();
+      annotations.set(DESTINATION_FILE_URI_ANNO, NOT_AVAILABLE);
+      annotations.set(DESTINATION_FILE_NAME_ANNO, NOT_AVAILABLE);
+    }
+    // The state annotation has been added recently, so it's likely missing.
+    if (!annotations.has(DOWNLOAD_STATE_ANNO)) {
+      annotations.set(DOWNLOAD_STATE_ANNO, NOT_AVAILABLE);
+    }
+    return annotations;
+  },
+
   /**
    * Given a data item for a session download, or a places node for a past
    * download, updates the view as necessary.
    *  1. If the given data is a places node, we check whether there are any
    *     elements for the same download url. If there are, then we just reset
    *     their places node. Otherwise we add a new download element.
    *  2. If the given data is a data item, we first check if there's a history
    *     download in the list that is not associated with a data item. If we
@@ -606,17 +662,18 @@ DownloadsPlacesView.prototype = {
    * @param [optional] aDocumentFragment
    *        To speed up the appending of multiple elements to the end of the
    *        list which are coming in a single batch (i.e. invalidateContainer),
    *        a document fragment may be passed to which the new elements would
    *        be appended. It's the caller's job to ensure the fragment is merged
    *        to the richlistbox at the end.
    */
   _addDownloadData:
-  function DPV_addDownload(aDataItem, aPlacesNode, aNewest = false, aDocumentFragment = null) {
+  function DPV_addDownloadData(aDataItem, aPlacesNode, aNewest = false,
+                               aDocumentFragment = null) {
     let downloadURI = aPlacesNode ? aPlacesNode.uri : aDataItem.uri;
     let shellsForURI = this._downloadElementsShellsForURI.get(downloadURI, null);
     if (!shellsForURI) {
       shellsForURI = new Set();
       this._downloadElementsShellsForURI.set(downloadURI, shellsForURI);
     }
 
     let newOrUpdatedShell = null;
@@ -652,19 +709,19 @@ DownloadsPlacesView.prototype = {
           newOrUpdatedShell = shell;
           this._viewItemsForDataItems.set(aDataItem, shell);
           break;
         }
       }
     }
 
     if (shouldCreateShell) {
-      let shell = new DownloadElementShell(aDataItem, aPlacesNode);
+      let shell = new DownloadElementShell(aDataItem, aPlacesNode,
+                                           this._getAnnotationsFor(downloadURI));
       newOrUpdatedShell = shell;
-      element = shell.element;
       shellsForURI.add(shell);
       if (aDataItem)
         this._viewItemsForDataItems.set(aDataItem, shell);
     }
     else if (aPlacesNode) {
       for (let shell of shellsForURI) {
         if (shell.placesNode != aPlacesNode)
           shell.placesNode = aPlacesNode;
@@ -757,18 +814,18 @@ DownloadsPlacesView.prototype = {
       else {
         let before = this._lastSessionDownloadElement ?
           this._lastSessionDownloadElement.nextSibling : this._richlistbox.firstchild;
         this._richlistbox.insertBefore(shell.element, before);
       }
     }
   },
 
+  _place: "",
   get place() this._place,
-
   set place(val) {
     // Don't reload everything if we don't have to.
     if (this._place == val) {
       // XXXmano: places.js relies on this behavior (see Bug 822203).
       this.searchTerm = "";
       return val;
     }
 
@@ -781,16 +838,17 @@ DownloadsPlacesView.prototype = {
       queries.value = [history.getNewQuery()];
 
     let result = history.executeQueries(queries.value, queries.value.length,
                                         options.value);
     result.addObserver(this, false);
     return val;
   },
 
+  _result: null,
   get result() this._result,
   set result(val) {
     if (this._result == val)
       return val;
 
     if (this._result) {
       this._result.removeObserver(this);
       this._resultNode.containerOpen = false;
@@ -1017,16 +1075,17 @@ DownloadsPlacesView.prototype = {
   {
     let element = this._richlistbox.selectedItem;
     if (!element || !element._shell)
       return false;
 
     // Set the state attribute so that only the appropriate items are displayed.
     let contextMenu = document.getElementById("downloadsContextMenu");
     contextMenu.setAttribute("state", element._shell._state);
+    return true;
   },
 
   onKeyPress: function DPV_onKeyPress(aEvent) {
     let selectedElements = this._richlistbox.selectedItems;
     if (!selectedElements)
       return;
 
     if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN) {
new file mode 100644
--- /dev/null
+++ b/browser/components/downloads/content/allDownloadsViewOverlay.xul
@@ -0,0 +1,103 @@
+<?xml version="1.0"?>
+
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+<?xml-stylesheet href="chrome://browser/content/downloads/allDownloadsViewOverlay.css"?>
+<?xml-stylesheet href="chrome://browser/skin/downloads/allDownloadsViewOverlay.css"?>
+
+<!DOCTYPE overlay [
+<!ENTITY % downloadsDTD SYSTEM "chrome://browser/locale/downloads/downloads.dtd">
+%downloadsDTD;
+]>
+
+<!-- This overlay provides a downloads view that lists both session downloads,
+     using the DownloadsView API, and history downloads, using places queries.
+     The view also implements a command controller and a context menu for
+     managing the downloads list.  In order to use this view:
+     1. Apply this overlay to your window.
+     2. Insert in all the overlay entry-points, namely:
+        <richlistbox id="downloadsRichListBox"/>
+        <commandset id="downloadCommands"/>
+        <menupopup id="downloadsContextMenu"/>
+    3. Make sure your window has the editMenuOverlay overlay applied,
+       because the view implements cmd_copy and cmd_delete.
+    4. Make sure your window has the globalOverlay.js script loaded.
+    5. To initialize the view
+        let view = new DownloadsPlacesView(document.getElementById("downloadsRichListBox"));
+        // This is what the Places Library uses. It could be tweaked a bit as long as the
+        // transition-type is set correctly
+        view.place = "place:transition=7&sort=4";
+-->
+<overlay id="downloadsViewOverlay"
+         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script type="application/javascript"
+          src="chrome://browser/content/downloads/allDownloadsViewOverlay.js"/>
+  <script type="application/javascript"
+          src="chrome://global/content/contentAreaUtils.js"/>
+
+  <richlistbox flex="1"
+               seltype="multiple"
+               id="downloadsRichListBox" context="downloadsContextMenu"
+               onkeypress="return this._placesView.onKeyPress(event);"
+               oncontextmenu="return this._placesView.onContextMenu(event);"/>
+
+  <commandset id="downloadCommands"
+              commandupdater="true"
+              events="focus,select,contextmenu"
+              oncommandupdate="goUpdateDownloadCommands();">
+    <command id="downloadsCmd_pauseResume"
+             oncommand="goDoCommand('downloadsCmd_pauseResume')"/>
+    <command id="downloadsCmd_cancel"
+             oncommand="goDoCommand('downloadsCmd_cancel')"/>
+    <command id="downloadsCmd_open"
+             oncommand="goDoCommand('downloadsCmd_open')"/>
+    <command id="downloadsCmd_show"
+             oncommand="goDoCommand('downloadsCmd_show')"/>
+    <command id="downloadsCmd_retry"
+             oncommand="goDoCommand('downloadsCmd_retry')"/>
+    <command id="downloadsCmd_openReferrer"
+             oncommand="goDoCommand('downloadsCmd_openReferrer')"/>
+  </commandset>
+
+  <menupopup id="downloadsContextMenu" class="download-state">
+    <menuitem command="downloadsCmd_pauseResume"
+              class="downloadPauseMenuItem"
+              label="&cmd.pause.label;"
+              accesskey="&cmd.pause.accesskey;"/>
+    <menuitem command="downloadsCmd_pauseResume"
+              class="downloadResumeMenuItem"
+              label="&cmd.resume.label;"
+              accesskey="&cmd.resume.accesskey;"/>
+    <menuitem command="downloadsCmd_cancel"
+              class="downloadCancelMenuItem"
+              label="&cmd.cancel.label;"
+              accesskey="&cmd.cancel.accesskey;"/>
+    <menuitem command="cmd_delete"
+              class="downloadRemoveFromHistoryMenuItem"
+              label="&cmd.removeFromHistory.label;"
+              accesskey="&cmd.removeFromHistory.accesskey;"/>
+    <menuitem command="downloadsCmd_show"
+              class="downloadShowMenuItem"
+#ifdef XP_MACOSX
+              label="&cmd.showMac.label;"
+              accesskey="&cmd.showMac.accesskey;"
+#else
+              label="&cmd.show.label;"
+              accesskey="&cmd.show.accesskey;"
+#endif
+              />
+
+    <menuseparator class="downloadCommandsSeparator"/>
+
+    <menuitem command="downloadsCmd_openReferrer"
+              label="&cmd.goToDownloadPage.label;"
+              accesskey="&cmd.goToDownloadPage.accesskey;"/>
+    <menuitem command="cmd_copy"
+              label="&cmd.copyDownloadLink.label;"
+              accesskey="&cmd.copyDownloadLink.accesskey;"/>
+  </menupopup>
+</overlay>
new file mode 100644
--- /dev/null
+++ b/browser/components/downloads/content/contentAreaDownloadsView.js
@@ -0,0 +1,10 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+let ContentAreaDownloadsView = {
+  init: function CADV_init() {
+    let view = new DownloadsPlacesView(document.getElementById("downloadsRichListBox"));
+    view.place = "place:transition=7&sort=4";
+  }
+};
new file mode 100644
--- /dev/null
+++ b/browser/components/downloads/content/contentAreaDownloadsView.xul
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+<?xml-stylesheet href="chrome://global/skin/"?>
+<?xul-overlay href="chrome://browser/content/downloads/allDownloadsViewOverlay.xul"?>
+
+<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
+
+<window id="contentAreaDownloadsView"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="ContentAreaDownloadsView.init();">
+
+  <script type="application/javascript"
+          src="chrome://global/content/globalOverlay.js"/>
+  <script type="application/javascript"
+          src="chrome://browser/content/downloads/contentAreaDownloadsView.js"/>
+
+  <commandset id="editMenuCommands"/>
+
+  <keyset id="editMenuKeys">
+#ifdef XP_MACOSX
+    <key id="key_delete2" keycode="VK_BACK" command="cmd_delete"/>
+#endif
+  </keyset>
+
+  <richlistbox id="downloadsRichListBox"/>
+  <commandset id="downloadCommands"/>
+  <menupopup id="downloadsContextMenu"/>
+</window>
rename from browser/components/places/content/download.css
rename to browser/components/downloads/content/download.css
--- a/browser/components/places/content/download.css
+++ b/browser/components/downloads/content/download.css
@@ -36,10 +36,10 @@ richlistitem.download button {
 
 .download-state:not(:-moz-any([state="2"], /* Failed             */
                               [state="3"]) /* Canceled           */)
                                            .downloadRetry,
 
 .download-state:not(          [state="1"]  /* Finished           */)
                                            .downloadShow
 {
-  visibility: hidden;
+  display: none;
 }
--- a/browser/components/downloads/content/download.xml
+++ b/browser/components/downloads/content/download.xml
@@ -53,9 +53,48 @@
                     tooltiptext="&cmd.retry.label;"
                     oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_retry');"/>
         <xul:button class="downloadButton downloadShow"
                     tooltiptext="&cmd.show.label;"
                     oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_show');"/>
       </xul:stack>
     </content>
   </binding>
+
+  <binding id="download-full-ui"
+           extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
+    <resources>
+      <stylesheet src="chrome://browser/content/downloads/download.css"/>
+    </resources>
+
+    <content orient="horizontal" align="center">
+      <xul:image class="downloadTypeIcon"
+                 validate="always"
+                 xbl:inherits="src=image"/>
+      <xul:image class="downloadTypeIcon blockedIcon"/>
+      <xul:vbox pack="center" flex="1">
+        <xul:description class="downloadTarget"
+                         crop="center"
+                         xbl:inherits="value=displayName,tooltiptext=displayName"/>
+        <xul:progressmeter anonid="progressmeter"
+                           class="downloadProgress"
+                           min="0"
+                           max="100"
+                           xbl:inherits="mode=progressmode,value=progress"/>
+        <xul:description class="downloadDetails"
+                         style="width: &downloadDetails.width;"
+                         crop="end"
+                         xbl:inherits="value=status,tooltiptext=statusTip"/>
+      </xul:vbox>
+
+      <xul:button class="downloadButton downloadCancel"
+                  oncommand="goDoCommand('downloadsCmd_cancel')"
+                  tooltiptext="&cmd.cancel.label;"/>
+      <xul:button class="downloadButton downloadRetry"
+                  oncommand="goDoCommand('downloadsCmd_retry')"
+                  tooltiptext="&cmd.retry.label;"/>
+      <xul:button class="downloadButton downloadShow"
+                  oncommand="goDoCommand('downloadsCmd_show')"
+                  tooltiptext="&cmd.show.label;"/>
+
+    </content>
+  </binding>
 </bindings>
--- a/browser/components/downloads/jar.mn
+++ b/browser/components/downloads/jar.mn
@@ -1,11 +1,17 @@
 # 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/.
 
 browser.jar:
         content/browser/downloads/download.xml           (content/download.xml)
+        content/browser/downloads/download.css           (content/download.css)
         content/browser/downloads/downloads.css          (content/downloads.css)
 *       content/browser/downloads/downloads.js           (content/downloads.js)
 *       content/browser/downloads/downloadsOverlay.xul   (content/downloadsOverlay.xul)
         content/browser/downloads/indicator.js           (content/indicator.js)
         content/browser/downloads/indicatorOverlay.xul   (content/indicatorOverlay.xul)
+*       content/browser/downloads/allDownloadsViewOverlay.xul (content/allDownloadsViewOverlay.xul)
+        content/browser/downloads/allDownloadsViewOverlay.js  (content/allDownloadsViewOverlay.js)
+        content/browser/downloads/allDownloadsViewOverlay.css (content/allDownloadsViewOverlay.css)
+*       content/browser/downloads/contentAreaDownloadsView.xul (content/contentAreaDownloadsView.xul)
+        content/browser/downloads/contentAreaDownloadsView.js  (content/contentAreaDownloadsView.js)
--- a/browser/components/downloads/src/DownloadsUI.js
+++ b/browser/components/downloads/src/DownloadsUI.js
@@ -25,16 +25,18 @@ const Cr = Components.results;
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
                                   "resource:///modules/DownloadsCommon.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "gBrowserGlue",
                                    "@mozilla.org/browser/browserglue;1",
                                    "nsIBrowserGlue");
+XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
+                                  "resource:///modules/RecentWindow.jsm");
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadsUI
 
 function DownloadsUI()
 {
   XPCOMUtils.defineLazyGetter(this, "_toolkitUI", function () {
     // Create Toolkit's nsIDownloadManagerUI implementation.
@@ -67,41 +69,93 @@ DownloadsUI.prototype = {
       aReason = Ci.nsIDownloadManagerUI.REASON_USER_INTERACTED;
     }
 
     if (aReason == Ci.nsIDownloadManagerUI.REASON_NEW_DOWNLOAD) {
       const kMinimized = Ci.nsIDOMChromeWindow.STATE_MINIMIZED;
       let browserWin = gBrowserGlue.getMostRecentBrowserWindow();
 
       if (!browserWin || browserWin.windowState == kMinimized) {
-        this._toolkitUI.show(aWindowContext, aID, aReason);
+        this._showDownloadManagerUI(aWindowContext, aID, aReason);
       }
       else {
         // If the indicator is visible, then new download notifications are
         // already handled by the panel service.
         browserWin.DownloadsButton.checkIsVisible(function(isVisible) {
           if (!isVisible) {
-            this._toolkitUI.show(aWindowContext, aID, aReason);
+            this._showDownloadManagerUI(aWindowContext, aID, aReason);
           }
         }.bind(this));
       }
     } else {
-      this._toolkitUI.show(aWindowContext, aID, aReason);
+      this._showDownloadManagerUI(aWindowContext, aID, aReason);
     }
   },
 
   get visible()
   {
-    return this._toolkitUI.visible;
+    // If we're still using the toolkit downloads manager, delegate the call
+    // to it. Otherwise, return true for now, until we decide on how we want
+    // to indicate that a new download has started if a browser window is
+    // not available or minimized.
+    return DownloadsCommon.useToolkitUI ? this._toolkitUI.visible : true;
   },
 
   getAttention: function DUI_getAttention()
   {
     if (DownloadsCommon.useToolkitUI) {
       this._toolkitUI.getAttention();
     }
+  },
+
+  /**
+   * Helper function that opens the right download manager UI. Either the
+   * new Downloads View in Places, or the toolkit download window if the
+   * Places Downloads View is not enabled.
+   */
+  _showDownloadManagerUI:
+  function DUI_showDownloadManagerUI(aWindowContext, aID, aReason)
+  {
+    // First, determine if the Places Downloads view is preffed on.
+    let usePlacesView = false;
+    try {
+      usePlacesView =
+        Services.prefs.getBoolPref("browser.library.useNewDownloadsView");
+    } catch(e) {}
+
+    if (!usePlacesView) {
+      // If we got here, then the browser.library.useNewDownloadsView pref
+      // either didn't exist or was false, so just show the toolkit downloads
+      // manager.
+      this._toolkitUI.show(aWindowContext, aID, aReason);
+      return;
+    }
+
+    let organizer = Services.wm.getMostRecentWindow("Places:Organizer");
+    if (!organizer) {
+      let parentWindow = aWindowContext;
+      // If we weren't given a window context, try to find a browser window
+      // to use as our parent - and if that doesn't work, error out and give
+      // up.
+      if (!parentWindow) {
+        parentWindow = RecentWindow.getMostRecentBrowserWindow();
+        if (!parentWindow) {
+          Components.utils
+                    .reportError("Couldn't find a browser window to open " +
+                                 "the Places Downloads View from.");
+          return;
+        }
+      }
+      parentWindow.openDialog("chrome://browser/content/places/places.xul",
+                              "", "chrome,toolbar=yes,dialog=no,resizable",
+                              "Downloads");
+    }
+    else {
+      organizer.PlacesOrganizer.selectLeftPaneQuery("Downloads");
+      organizer.focus();
+    }
   }
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Module
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DownloadsUI]);
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -136,18 +136,21 @@ PlacesController.prototype = {
         if (nodes[i].itemId == -1)
           return false;
       }
       // Otherwise fallback to cmd_delete check.
     case "cmd_delete":
     case "placesCmd_delete":
       return this._hasRemovableSelection(false);
     case "placesCmd_deleteDataHost":
-      return this._hasRemovableSelection(false) &&
-        !PlacesUIUtils.privateBrowsing.privateBrowsingEnabled;
+      return this._hasRemovableSelection(false)
+#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
+        && !PlacesUIUtils.privateBrowsing.privateBrowsingEnabled
+#endif
+        ;
     case "placesCmd_moveBookmarks":
       return this._hasRemovableSelection(true);
     case "cmd_copy":
     case "placesCmd_copy":
       return this._view.hasSelection;
     case "cmd_paste":
     case "placesCmd_paste":
       return this._canInsert(true) && this._isClipboardDataPasteable();
@@ -596,18 +599,22 @@ PlacesController.prototype = {
     var visibleItemsBeforeSep = false;
     var anyVisible = false;
     for (var i = 0; i < aPopup.childNodes.length; ++i) {
       var item = aPopup.childNodes[i];
       if (item.localName != "menuseparator") {
         // We allow pasting into tag containers, so special case that.
         var hideIfNoIP = item.getAttribute("hideifnoinsertionpoint") == "true" &&
                          noIp && !(ip && ip.isTag && item.id == "placesContext_paste");
+#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+        var hideIfPB = false;
+#else
         var hideIfPB = item.getAttribute("hideifprivatebrowsing") == "true" &&
                        PlacesUIUtils.privateBrowsing.privateBrowsingEnabled;
+#endif
         item.hidden = hideIfNoIP || hideIfPB ||
                       !this._shouldShowMenuItem(item, metadata);
 
         if (!item.hidden) {
           visibleItemsBeforeSep = true;
           anyVisible = true;
 
           // Show the separator above the menu-item if any
deleted file mode 100644
--- a/browser/components/places/content/download.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0"?>
-<!-- -*- Mode: HTML; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- -->
-<!-- vim: set ts=2 et sw=2 tw=80: -->
-
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this file,
-   - You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<!DOCTYPE bindings SYSTEM "chrome://browser/locale/downloads/downloads.dtd">
-
-<bindings id="downloadBindings"
-          xmlns="http://www.mozilla.org/xbl"
-          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-          xmlns:xbl="http://www.mozilla.org/xbl">
-
-  <binding id="download"
-           extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
-   <resources>
-     <stylesheet src="chrome://browser/content/places/download.css"/>
-   </resources>
-
-    <content orient="horizontal" align="center">
-      <xul:image class="downloadTypeIcon"
-                 validate="always"
-                 xbl:inherits="src=image"/>
-      <xul:image class="downloadTypeIcon blockedIcon"/>
-      <xul:vbox pack="center" flex="1">
-        <xul:description class="downloadTarget"
-                         crop="center"
-                         xbl:inherits="value=displayName,tooltiptext=displayName"/>
-        <xul:progressmeter anonid="progressmeter"
-                           class="downloadProgress"
-                           min="0"
-                           max="100"
-                           xbl:inherits="mode=progressmode,value=progress"/>
-        <xul:description class="downloadDetails"
-                         style="width: &downloadDetails.width;"
-                         crop="end"
-                         xbl:inherits="value=status,tooltiptext=statusTip"/>
-      </xul:vbox>
-      <xul:stack>
-        <xul:button class="downloadButton downloadCancel"
-                    command="downloadsCmd_cancel"
-                    tooltiptext="&cmd.cancel.label;"/>
-        <xul:button class="downloadButton downloadRetry"
-                    command="downloadsCmd_retry"
-                    tooltiptext="&cmd.retry.label;"/>
-        <xul:button class="downloadButton downloadShow"
-                    command="downloadsCmd_show"
-                    tooltiptext="&cmd.show.label;"/>
-      </xul:stack>
-    </content>
-  </binding>
-</bindings>
--- a/browser/components/places/content/places.css
+++ b/browser/components/places/content/places.css
@@ -9,38 +9,8 @@ tree[type="places"] {
 .toolbar-drop-indicator {
   position: relative;
   z-index: 1;
 }
 
 menupopup[placespopup="true"] {
   -moz-binding: url("chrome://browser/content/places/menu.xml#places-popup-base");
 }
-
-richlistitem.download {
-	-moz-binding: url('chrome://browser/content/places/download.xml#download');
-}
-
-.download-state:not(          [state="0"]  /* Downloading        */)
-                                           .downloadPauseMenuItem,
-.download-state:not(          [state="4"]  /* Paused             */)
-                                           .downloadResumeMenuItem,
-.download-state:not(:-moz-any([state="2"], /* Failed             */
-                              [state="4"]) /* Paused             */)
-                                           .downloadCancelMenuItem,
-.download-state:not(:-moz-any([state="1"], /* Finished           */
-                              [state="2"], /* Failed             */
-                              [state="3"], /* Canceled           */
-                              [state="6"], /* Blocked (parental) */
-                              [state="8"], /* Blocked (dirty)    */
-                              [state="9"]) /* Blocked (policy)   */)
-                                           .downloadRemoveFromHistoryMenuItem,
-.download-state:not(:-moz-any([state="-1"],/* Starting (initial) */
-                              [state="5"], /* Starting (queued)  */
-                              [state="0"], /* Downloading        */
-                              [state="4"]) /* Paused             */)
-                                           .downloadShowMenuItem,
-
-.download-state[state="7"]                 .downloadCommandsSeparator
-
-{
-  display: none;
-}
--- a/browser/components/places/content/places.xul
+++ b/browser/components/places/content/places.xul
@@ -5,61 +5,55 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 <?xml-stylesheet href="chrome://browser/content/places/places.css"?>
 <?xml-stylesheet href="chrome://browser/content/places/organizer.css"?>
 
 <?xml-stylesheet href="chrome://global/skin/"?>
 <?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
 <?xml-stylesheet href="chrome://browser/skin/places/organizer.css"?>
-<?xml-stylesheet href="chrome://browser/skin/downloads/downloads.css"?>
 
 <?xul-overlay href="chrome://browser/content/places/editBookmarkOverlay.xul"?>
+<?xul-overlay href="chrome://browser/content/downloads/allDownloadsViewOverlay.xul"?>
 
 #ifdef XP_MACOSX
 <?xul-overlay href="chrome://browser/content/macBrowserOverlay.xul"?>
 #else
 <?xul-overlay href="chrome://browser/content/baseMenuOverlay.xul"?>
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
 <?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
 #endif
 
 <!DOCTYPE window [
 <!ENTITY % placesDTD SYSTEM "chrome://browser/locale/places/places.dtd">
 %placesDTD;
 <!ENTITY % editMenuOverlayDTD SYSTEM "chrome://global/locale/editMenuOverlay.dtd">
 %editMenuOverlayDTD;
 <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
 %browserDTD;
-<!ENTITY % downloadsDTD SYSTEM "chrome://browser/locale/downloads/downloads.dtd">
-%downloadsDTD;
 ]>
 
 <window id="places"
         title="&places.library.title;"
         windowtype="Places:Organizer"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml"
         onload="PlacesOrganizer.init();"
         onunload="PlacesOrganizer.destroy();"
         width="&places.library.width;" height="&places.library.height;"
         screenX="10" screenY="10"
         toggletoolbar="true"
         persist="width height screenX screenY sizemode">
 
   <script type="application/javascript"
-          src="chrome://browser/content/places/downloadsView.js"/>
-  <script type="application/javascript"
           src="chrome://browser/content/places/places.js"/>
   <script type="application/javascript"
           src="chrome://browser/content/utilityOverlay.js"/>
   <script type="application/javascript"
           src="chrome://browser/content/places/editBookmarkOverlay.js"/>
-  <script type="application/javascript"
-          src="chrome://global/content/contentAreaUtils.js"/>
 
   <stringbundleset id="placesStringSet">
     <stringbundle id="brandStrings" src="chrome://branding/locale/brand.properties"/>
   </stringbundleset>
 
 
 #ifdef XP_MACOSX
 #include ../../../base/content/browserMountPoints.inc
@@ -406,21 +400,17 @@
             <treecol label="&col.dateadded.label;" id="placesContentDateAdded" anonid="dateAdded" flex="1" hidden="true"
                       persist="width hidden ordinal sortActive sortDirection"/>
             <splitter class="tree-splitter"/>
             <treecol label="&col.lastmodified.label;" id="placesContentLastModified" anonid="lastModified" flex="1" hidden="true"
                       persist="width hidden ordinal sortActive sortDirection"/>
           </treecols>
           <treechildren flex="1"/>
         </tree>
-        <richlistbox flex="1"
-                     seltype="multiple"
-                     id="downloadsRichListBox" context="downloadsContextMenu"
-                     onkeypress="return this._placesView.onKeyPress(event);"
-                     oncontextmenu="return this._placesView.onContextMenu(event);"/>
+        <richlistbox id="downloadsRichListBox"/>
       </deck>
       <deck id="detailsDeck" style="height: 11em;">
         <vbox id="itemsCountBox" align="center">
           <spacer flex="3"/>
           <label id="itemsCountText"/>
           <spacer flex="1"/>
           <description id="selectItemDescription">
               &detailsPane.selectAnItemText.description;
@@ -446,65 +436,11 @@
                     control="infoBoxExpander"/>
 
           </hbox>
         </vbox>
       </deck>
     </vbox>
   </hbox>
 
-  <commandset id="downloadCommands"
-              commandupdater="true"
-              events="focus,select,contextmenu"
-              oncommandupdate="goUpdatePlacesCommands(); goUpdateDownloadCommands();">
-    <command id="downloadsCmd_pauseResume"
-             oncommand="goDoCommand('downloadsCmd_pauseResume')"/>
-    <command id="downloadsCmd_cancel"
-             oncommand="goDoCommand('downloadsCmd_cancel')"/>
-    <command id="downloadsCmd_open"
-             oncommand="goDoCommand('downloadsCmd_open')"/>
-    <command id="downloadsCmd_show"
-             oncommand="goDoCommand('downloadsCmd_show')"/>
-    <command id="downloadsCmd_retry"
-             oncommand="goDoCommand('downloadsCmd_retry')"/>
-    <command id="downloadsCmd_openReferrer"
-             oncommand="goDoCommand('downloadsCmd_openReferrer')"/>
-  </commandset>
-
-  <menupopup id="downloadsContextMenu"
-             class="download-state">
-    <menuitem command="downloadsCmd_pauseResume"
-              class="downloadPauseMenuItem"
-              label="&cmd.pause.label;"
-              accesskey="&cmd.pause.accesskey;"/>
-    <menuitem command="downloadsCmd_pauseResume"
-              class="downloadResumeMenuItem"
-              label="&cmd.resume.label;"
-              accesskey="&cmd.resume.accesskey;"/>
-    <menuitem command="downloadsCmd_cancel"
-              class="downloadCancelMenuItem"
-              label="&cmd.cancel.label;"
-              accesskey="&cmd.cancel.accesskey;"/>
-    <menuitem command="cmd_delete"
-              class="downloadRemoveFromHistoryMenuItem"
-              label="&cmd.removeFromHistory.label;"
-              accesskey="&cmd.removeFromHistory.accesskey;"/>
-    <menuitem command="downloadsCmd_show"
-              class="downloadShowMenuItem"
-#ifdef XP_MACOSX
-              label="&cmd.showMac.label;"
-              accesskey="&cmd.showMac.accesskey;"
-#else
-              label="&cmd.show.label;"
-              accesskey="&cmd.show.accesskey;"
-#endif
-              />
-
-    <menuseparator class="downloadCommandsSeparator"/>
-
-    <menuitem command="downloadsCmd_openReferrer"
-              label="&cmd.goToDownloadPage.label;"
-              accesskey="&cmd.goToDownloadPage.accesskey;"/>
-    <menuitem command="cmd_copy"
-              label="&cmd.copyDownloadLink.label;"
-              accesskey="&cmd.copyDownloadLink.accesskey;"/>
-  </menupopup>
+  <commandset id="downloadCommands"/>
+  <menupopup id="downloadsContextMenu"/>
 </window>
--- a/browser/components/places/jar.mn
+++ b/browser/components/places/jar.mn
@@ -3,27 +3,24 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 browser.jar:
 # Provide another URI for the bookmarkProperties dialog so we can persist the
 # attributes separately
     content/browser/places/bookmarkProperties2.xul       (content/bookmarkProperties.xul)
 *   content/browser/places/places.xul                    (content/places.xul) 
 *   content/browser/places/places.js                     (content/places.js)
-    content/browser/places/downloadsView.js              (content/downloadsView.js)
-    content/browser/places/download.xml                  (content/download.xml)
-    content/browser/places/download.css                  (content/download.css)
     content/browser/places/places.css                    (content/places.css)
     content/browser/places/organizer.css                 (content/organizer.css)
     content/browser/places/bookmarkProperties.xul        (content/bookmarkProperties.xul)
     content/browser/places/bookmarkProperties.js         (content/bookmarkProperties.js)
     content/browser/places/placesOverlay.xul             (content/placesOverlay.xul)
 *   content/browser/places/menu.xml                      (content/menu.xml)
     content/browser/places/tree.xml                      (content/tree.xml)
-    content/browser/places/controller.js                 (content/controller.js)
+*   content/browser/places/controller.js                 (content/controller.js)
     content/browser/places/treeView.js                   (content/treeView.js)
 *   content/browser/places/browserPlacesViews.js         (content/browserPlacesViews.js)
 # keep the Places version of the history sidebar at history/history-panel.xul 
 # to prevent having to worry about between versions of the browser
 *   content/browser/history/history-panel.xul            (content/history-panel.xul) 
     content/browser/places/history-panel.js              (content/history-panel.js)
 # ditto for the bookmarks sidebar
     content/browser/bookmarks/bookmarksPanel.xul         (content/bookmarksPanel.xul)
--- a/browser/components/places/src/Makefile.in
+++ b/browser/components/places/src/Makefile.in
@@ -10,15 +10,15 @@ VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 EXTRA_COMPONENTS = \
   BrowserPlaces.manifest \
   PlacesProtocolHandler.js \
   $(NULL)
 
-EXTRA_JS_MODULES = \
+EXTRA_PP_JS_MODULES = \
   PlacesUIUtils.jsm \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
 XPIDL_FLAGS += -I$(topsrcdir)/browser/components
--- a/browser/components/places/src/PlacesUIUtils.jsm
+++ b/browser/components/places/src/PlacesUIUtils.jsm
@@ -1004,19 +1004,21 @@ XPCOMUtils.defineLazyGetter(PlacesUIUtil
   return PlacesUIUtils.RDF.GetDataSource("rdf:local-store");
 });
 
 XPCOMUtils.defineLazyGetter(PlacesUIUtils, "ellipsis", function() {
   return Services.prefs.getComplexValue("intl.ellipsis",
                                         Ci.nsIPrefLocalizedString).data;
 });
 
+#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
 XPCOMUtils.defineLazyServiceGetter(PlacesUIUtils, "privateBrowsing",
                                    "@mozilla.org/privatebrowsing;1",
                                    "nsIPrivateBrowsingService");
+#endif
 
 XPCOMUtils.defineLazyServiceGetter(this, "URIFixup",
                                    "@mozilla.org/docshell/urifixup;1",
                                    "nsIURIFixup");
 
 XPCOMUtils.defineLazyGetter(this, "bundle", function() {
   const PLACES_STRING_BUNDLE_URI =
     "chrome://browser/locale/places/places.properties";
--- a/browser/components/privatebrowsing/test/browser/obsolete/browser_privatebrowsing_forgetthissite.js
+++ b/browser/components/privatebrowsing/test/browser/obsolete/browser_privatebrowsing_forgetthissite.js
@@ -49,17 +49,17 @@ function test() {
           // Select History in the left pane.
           let PO = organizer.PlacesOrganizer;
           PO.selectLeftPaneQuery('History');
           let histContainer = PO._places.selectedNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
           histContainer.containerOpen = true;
           PO._places.selectNode(histContainer.getChild(0));
           // Select the first history entry.
           let doc = organizer.document;
-          let tree = PO._content;
+          let tree = organizer.ContentTree.view;
           let selection = tree.view.selection;
           selection.clearSelection();
           selection.rangedSelect(0, 0, true);
           is(tree.selectedNode.uri, TEST_URI, "The correct history item has been selected");
           // Open the context menu
           let contextmenu = doc.getElementById("placesContext");
           contextmenu.addEventListener("popupshown", function() {
             contextmenu.removeEventListener("popupshown", arguments.callee, true);
--- a/browser/components/sessionstore/nsISessionStartup.idl
+++ b/browser/components/sessionstore/nsISessionStartup.idl
@@ -5,19 +5,25 @@
 #include "nsISupports.idl"
 
 /**
  * nsISessionStore keeps track of the current browsing state - i.e.
  * tab history, cookies, scroll state, form data, POSTDATA and window features
  * - and allows to restore everything into one window.
  */
 
-[scriptable, uuid(170c6857-7f71-46ce-bc9b-185723b1c3a8)]
+[scriptable, uuid(35235b39-7098-4b3b-8e28-cd004a88b06f)]
 interface nsISessionStartup: nsISupports
 {
+  /**
+   * Return a promise that is resolved once initialization
+   * is complete.
+   */
+  readonly attribute jsval onceInitialized;
+
   // Get session state
   readonly attribute jsval state;
 
   /**
    * Determine if session should be restored
    */
   boolean doRestore();
 
--- a/browser/components/sessionstore/src/Makefile.in
+++ b/browser/components/sessionstore/src/Makefile.in
@@ -7,25 +7,27 @@ topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/config.mk
 
 EXTRA_COMPONENTS = \
   nsSessionStore.manifest \
-	nsSessionStore.js \
-	nsSessionStartup.js \
+  nsSessionStore.js \
   $(NULL)
 
+EXTRA_PP_COMPONENTS := nsSessionStartup.js
+
 JS_MODULES_PATH := $(FINAL_TARGET)/modules/sessionstore
 
 EXTRA_JS_MODULES := \
   DocumentUtils.jsm \
   SessionStorage.jsm \
   XPathGenerator.jsm \
+  _SessionFile.jsm \
   $(NULL)
 
 EXTRA_PP_JS_MODULES := \
 	SessionStore.jsm \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -70,33 +70,39 @@ const TAB_EVENTS = [
   "TabOpen", "TabClose", "TabSelect", "TabShow", "TabHide", "TabPinned",
   "TabUnpinned"
 ];
 
 #ifndef XP_WIN
 #define BROKEN_WM_Z_ORDER
 #endif
 
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm", this);
+Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
 // debug.js adds NS_ASSERT. cf. bug 669196
-Cu.import("resource://gre/modules/debug.js");
-Cu.import("resource:///modules/TelemetryTimestamps.jsm");
-Cu.import("resource://gre/modules/TelemetryStopwatch.jsm");
-Cu.import("resource://gre/modules/osfile.jsm");
-Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
+Cu.import("resource://gre/modules/debug.js", this);
+Cu.import("resource:///modules/TelemetryTimestamps.jsm", this);
+Cu.import("resource://gre/modules/TelemetryStopwatch.jsm", this);
+Cu.import("resource://gre/modules/osfile.jsm", this);
+Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm", this);
+Cu.import("resource://gre/modules/commonjs/promise/core.js", this);
+
+XPCOMUtils.defineLazyServiceGetter(this, "gSessionStartup",
+  "@mozilla.org/browser/sessionstartup;1", "nsISessionStartup");
 
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
   "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ScratchpadManager",
   "resource:///modules/devtools/scratchpad-manager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DocumentUtils",
   "resource:///modules/sessionstore/DocumentUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "SessionStorage",
   "resource:///modules/sessionstore/SessionStorage.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "_SessionFile",
+  "resource:///modules/sessionstore/_SessionFile.jsm");
 
 #ifdef MOZ_CRASHREPORTER
 XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter",
   "@mozilla.org/xre/app-info;1", "nsICrashReporter");
 #endif
 
 function debug(aMsg) {
   aMsg = ("SessionStore: " + aMsg).replace(/\S{80}/g, "$&\n");
@@ -285,18 +291,21 @@ let SessionStoreInternal = {
   _restorePinnedTabsOnDemand: null,
 
   // The state from the previous session (after restoring pinned tabs). This
   // state is persisted and passed through to the next session during an app
   // restart to make the third party add-on warning not trash the deferred
   // session
   _lastSessionState: null,
 
-  // Whether we've been initialized
-  _initialized: false,
+  // A promise resolved once initialization is complete
+  _promiseInitialization: Promise.defer(),
+
+  // Whether session has been initialized
+  _sessionInitialized: false,
 
   // The original "sessionstore.resume_session_once" preference value before it
   // was modified by saveState.  saveState will set the
   // "sessionstore.resume_session_once" to true when the
   // the "sessionstore.resume_from_crash" preference is false (crash recovery
   // is disabled) so that pinned tabs will be restored in the case of a
   // crash.  This variable is used to restore the original value so the
   // previous session is not always restored when
@@ -321,16 +330,19 @@ let SessionStoreInternal = {
   },
 
   /* ........ Global Event Handlers .............. */
 
   /**
    * Initialize the component
    */
   initService: function ssi_initService() {
+    if (this._sessionInitialized) {
+      return;
+    }
     TelemetryTimestamps.add("sessionRestoreInitialized");
     OBSERVING.forEach(function(aTopic) {
       Services.obs.addObserver(this, aTopic, true);
     }, this);
 
 #ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
     var pbs = Cc["@mozilla.org/privatebrowsing;1"].
               getService(Ci.nsIPrivateBrowsingService);
@@ -353,25 +365,23 @@ let SessionStoreInternal = {
     this._restoreHiddenTabs =
       this._prefBranch.getBoolPref("sessionstore.restore_hidden_tabs");
     this._prefBranch.addObserver("sessionstore.restore_hidden_tabs", this, true);
 
     this._restorePinnedTabsOnDemand =
       this._prefBranch.getBoolPref("sessionstore.restore_pinned_tabs_on_demand");
     this._prefBranch.addObserver("sessionstore.restore_pinned_tabs_on_demand", this, true);
 
-    // get file references
-    this._sessionFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
-    this._sessionFileBackup = this._sessionFile.clone();
-    this._sessionFile.append("sessionstore.js");
-    this._sessionFileBackup.append("sessionstore.bak");
-
-    // get string containing session state
-    var ss = Cc["@mozilla.org/browser/sessionstartup;1"].
-             getService(Ci.nsISessionStartup);
+    gSessionStartup.onceInitialized.then(
+      this.initSession.bind(this)
+    );
+  },
+
+  initSession: function ssi_initSession() {
+    let ss = gSessionStartup;
     try {
       if (ss.doRestore() ||
           ss.sessionType == Ci.nsISessionStartup.DEFER_SESSION)
         this._initialState = ss.state;
     }
     catch(ex) { dump(ex + "\n"); } // no state to restore, which is ok
 
     if (this._initialState) {
@@ -432,35 +442,34 @@ let SessionStoreInternal = {
             delete aWindow.__lastSessionWindowID;
           });
         }
       }
       catch (ex) { debug("The session file is invalid: " + ex); }
     }
 
     if (this._resume_from_crash) {
-      // create a backup if the session data file exists
-      try {
-        if (this._sessionFileBackup.exists())
-          this._sessionFileBackup.remove(false);
-        if (this._sessionFile.exists())
-          this._sessionFile.copyTo(null, this._sessionFileBackup.leafName);
-      }
-      catch (ex) { Cu.reportError(ex); } // file was write-locked?
+      // Launch background copy of the session file. Note that we do
+      // not have race conditions here as _SessionFile guarantees
+      // that any I/O operation is completed before proceeding to
+      // the next I/O operation.
+      _SessionFile.createBackupCopy();
     }
 
     // at this point, we've as good as resumed the session, so we can
     // clear the resume_session_once flag, if it's set
     if (this._loadState != STATE_QUITTING &&
         this._prefBranch.getBoolPref("sessionstore.resume_session_once"))
       this._prefBranch.setBoolPref("sessionstore.resume_session_once", false);
 
     this._initEncoding();
 
-    this._initialized = true;
+    // Session is ready.
+    this._sessionInitialized = true;
+    this._promiseInitialization.resolve();
   },
 
   _initEncoding : function ssi_initEncoding() {
     // The (UTF-8) encoder used to write to files.
     XPCOMUtils.defineLazyGetter(this, "_writeFileEncoder", function () {
       return new TextEncoder();
     });
   },
@@ -490,26 +499,17 @@ let SessionStoreInternal = {
     });
 
     XPCOMUtils.defineLazyGetter(this, "_max_windows_undo", function () {
       this._prefBranch.addObserver("sessionstore.max_windows_undo", this, true);
       return this._prefBranch.getIntPref("sessionstore.max_windows_undo");
     });
   },
 
-  /**
-   * Start tracking a window.
-   * This function also initializes the component if it's not already
-   * initialized.
-   */
-  init: function ssi_init(aWindow) {
-    // Initialize the service if needed.
-    if (!this._initialized)
-      this.initService();
-
+  _initWindow: function ssi_initWindow(aWindow) {
     if (!aWindow || this._loadState == STATE_RUNNING) {
       // make sure that all browser windows which try to initialize
       // SessionStore are really tracked by it
       if (aWindow && (!aWindow.__SSi || !this._windows[aWindow.__SSi]))
         this.onLoad(aWindow);
       // If init is being called with a null window, it's possible that we
       // just want to tell sessionstore that a session is live (as is the case
       // with starting Firefox with -private, for example; see bug 568816),
@@ -520,22 +520,39 @@ let SessionStoreInternal = {
       return;
     }
 
     // As this is called at delayedStartup, restoration must be initiated here
     this.onLoad(aWindow);
   },
 
   /**
+   * Start tracking a window.
+   *
+   * This function also initializes the component if it is not
+   * initialized yet.
+   */
+  init: function ssi_init(aWindow) {
+    let self = this;
+    this.initService();
+    this._promiseInitialization.promise.then(
+      function onSuccess() {
+        self._initWindow(aWindow);
+      }
+    );
+  },
+
+  /**
    * Called on application shutdown, after notifications:
    * quit-application-granted, quit-application
    */
   _uninit: function ssi_uninit() {
     // save all data for session resuming
-    this.saveState(true);
+    if (this._sessionInitialized)
+      this.saveState(true);
 
     // clear out _tabsToRestore in case it's still holding refs
     this._tabsToRestore.priority = null;
     this._tabsToRestore.visible = null;
     this._tabsToRestore.hidden = null;
 
     // Make sure to break our cycle with the save timer
     if (this._saveTimer) {
@@ -993,17 +1010,17 @@ let SessionStoreInternal = {
     this._uninit();
   },
 
   /**
    * On purge of session history
    */
   onPurgeSessionHistory: function ssi_onPurgeSessionHistory() {
     var _this = this;
-    this._clearDisk();
+    _SessionFile.wipe();
     // If the browser is shutting down, simply return after clearing the
     // session data on disk as this notification fires after the
     // quit-application notification so the browser is about to exit.
     if (this._loadState == STATE_QUITTING)
       return;
     this._lastSessionState = null;
     let openWindows = {};
     this._forEachBrowserWindow(function(aWindow) {
@@ -1134,17 +1151,17 @@ let SessionStoreInternal = {
         if (this._resume_session_once_on_shutdown != null) {
           this._prefBranch.setBoolPref("sessionstore.resume_session_once",
                                        this._resume_session_once_on_shutdown);
           this._resume_session_once_on_shutdown = null;
         }
         // either create the file with crash recovery information or remove it
         // (when _loadState is not STATE_RUNNING, that file is used for session resuming instead)
         if (!this._resume_from_crash)
-          this._clearDisk();
+          _SessionFile.wipe();
         this.saveState(true);
         break;
       case "sessionstore.restore_on_demand":
         this._restoreOnDemand =
           this._prefBranch.getBoolPref("sessionstore.restore_on_demand");
         break;
       case "sessionstore.restore_hidden_tabs":
         this._restoreHiddenTabs =
@@ -3759,50 +3776,47 @@ let SessionStoreInternal = {
     this._saveStateObject(oState);
   },
 
   /**
    * write a state object to disk
    */
   _saveStateObject: function ssi_saveStateObject(aStateObj) {
     TelemetryStopwatch.start("FX_SESSION_RESTORE_SERIALIZE_DATA_MS");
-    var stateString = Cc["@mozilla.org/supports-string;1"].
-                        createInstance(Ci.nsISupportsString);
-    stateString.data = this._toJSONString(aStateObj);
+    let data = this._toJSONString(aStateObj);
     TelemetryStopwatch.finish("FX_SESSION_RESTORE_SERIALIZE_DATA_MS");
 
+    let stateString = this._createSupportsString(data);
     Services.obs.notifyObservers(stateString, "sessionstore-state-write", "");
-
-    // don't touch the file if an observer has deleted all state data
-    if (stateString.data)
-      this._writeFile(this._sessionFile, stateString.data);
-
-    this._lastSaveTime = Date.now();
-  },
-
-  /**
-   * delete session datafile and backup
-   */
-  _clearDisk: function ssi_clearDisk() {
-    if (this._sessionFile.exists()) {
-      try {
-        this._sessionFile.remove(false);
+    data = stateString.data;
+
+    // Don't touch the file if an observer has deleted all state data.
+    if (!data) {
+      return;
+    }
+
+    let self = this;
+    _SessionFile.write(data).then(
+      function onSuccess() {
+        self._lastSaveTime = Date.now();
+        Services.obs.notifyObservers(null, "sessionstore-state-write-complete", "");
       }
-      catch (ex) { dump(ex + '\n'); } // couldn't remove the file - what now?
-    }
-    if (this._sessionFileBackup.exists()) {
-      try {
-        this._sessionFileBackup.remove(false);
-      }
-      catch (ex) { dump(ex + '\n'); } // couldn't remove the file - what now?
-    }
+    );
   },
 
   /* ........ Auxiliary Functions .............. */
 
+  // Wrap a string as a nsISupports
+  _createSupportsString: function ssi_createSupportsString(aData) {
+    let string = Cc["@mozilla.org/supports-string;1"]
+                   .createInstance(Ci.nsISupportsString);
+    string.data = aData;
+    return string;
+  },
+
   /**
    * call a callback for all currently opened browser windows
    * (might miss the most recent one)
    * @param aFunc
    *        Callback each window is passed to
    */
   _forEachBrowserWindow: function ssi_forEachBrowserWindow(aFunc) {
     var windowsEnum = Services.wm.getEnumerator("navigator:browser");
@@ -4486,43 +4500,16 @@ let SessionStoreInternal = {
    */
   _removeSHistoryListener: function ssi_removeSHistoryListener(aTab) {
     let browser = aTab.linkedBrowser;
     if (browser.__SS_shistoryListener) {
       browser.webNavigation.sessionHistory.
                             removeSHistoryListener(browser.__SS_shistoryListener);
       delete browser.__SS_shistoryListener;
     }
-  },
-
-  /**
-   * write file to disk
-   * @param aFile
-   *        nsIFile
-   * @param aData
-   *        String data
-   */
-  _writeFile: function ssi_writeFile(aFile, aData) {
-    let refObj = {};
-    TelemetryStopwatch.start("FX_SESSION_RESTORE_WRITE_FILE_MS", refObj);
-    let path = aFile.path;
-    let encoded = this._writeFileEncoder.encode(aData);
-    let promise = OS.File.writeAtomic(path, encoded, {tmpPath: path + ".tmp"});
-
-    promise.then(
-      function onSuccess() {
-        TelemetryStopwatch.finish("FX_SESSION_RESTORE_WRITE_FILE_MS", refObj);
-        Services.obs.notifyObservers(null,
-                                      "sessionstore-state-write-complete",
-                                      "");
-      },
-      function onFailure(reason) {
-        TelemetryStopwatch.cancel("FX_SESSION_RESTORE_WRITE_FILE_MS", refObj);
-        Components.reportError("ssi_writeFile failure " + reason);
-      });
   }
 };
 
 // This is used to help meter the number of restoring tabs. This is the control
 // point for telling the next tab to restore. It gets attached to each gBrowser
 // via gBrowser.addTabsProgressListener
 let gRestoreTabsProgressListener = {
   onStateChange: function(aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/src/_SessionFile.jsm
@@ -0,0 +1,255 @@
+/* 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";
+
+this.EXPORTED_SYMBOLS = ["_SessionFile"];
+
+/**
+ * Implementation of all the disk I/O required by the session store.
+ * This is a private API, meant to be used only by the session store.
+ * It will change. Do not use it for any other purpose.
+ *
+ * Note that this module implicitly depends on one of two things:
+ * 1. either the asynchronous file I/O system enqueues its requests
+ *   and never attempts to simultaneously execute two I/O requests on
+ *   the files used by this module from two distinct threads; or
+ * 2. the clients of this API are well-behaved and do not place
+ *   concurrent requests to the files used by this module.
+ *
+ * Otherwise, we could encounter bugs, especially under Windows,
+ *   e.g. if a request attempts to write sessionstore.js while
+ *   another attempts to copy that file.
+ *
+ * This implementation uses OS.File, which guarantees property 1.
+ */
+
+const Cu = Components.utils;
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/osfile.jsm");
+Cu.import("resource://gre/modules/commonjs/promise/core.js");
+
+XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
+  "resource://gre/modules/TelemetryStopwatch.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
+  "resource://gre/modules/NetUtil.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
+  "resource://gre/modules/FileUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Task",
+  "resource://gre/modules/Task.jsm");
+
+// An encoder to UTF-8.
+XPCOMUtils.defineLazyGetter(this, "gEncoder", function () {
+  return new TextEncoder();
+});
+
+this._SessionFile = {
+  /**
+   * A promise fulfilled once initialization (either synchronous or
+   * asynchronous) is complete.
+   */
+  promiseInitialized: function SessionFile_initialized() {
+    return SessionFileInternal.promiseInitialized;
+  },
+  /**
+   * Read the contents of the session file, asynchronously.
+   */
+  read: function SessionFile_read() {
+    return SessionFileInternal.read();
+  },
+  /**
+   * Read the contents of the session file, synchronously.
+   */
+  syncRead: function SessionFile_syncRead() {
+    return SessionFileInternal.syncRead();
+  },
+  /**
+   * Write the contents of the session file, asynchronously.
+   */
+  write: function SessionFile_write(aData) {
+    return SessionFileInternal.write(aData);
+  },
+  /**
+   * Create a backup copy, asynchronously.
+   */
+  createBackupCopy: function SessionFile_createBackupCopy() {
+    return SessionFileInternal.createBackupCopy();
+  },
+  /**
+   * Wipe the contents of the session file, asynchronously.
+   */
+  wipe: function SessionFile_wipe() {
+    return SessionFileInternal.wipe();
+  }
+};
+
+Object.freeze(_SessionFile);
+
+/**
+ * Utilities for dealing with promises and Task.jsm
+ */
+const TaskUtils = {
+  /**
+   * Add logging to a promise.
+   *
+   * @param {Promise} promise
+   * @return {Promise} A promise behaving as |promise|, but with additional
+   * logging in case of uncaught error.
+   */
+  captureErrors: function captureErrors(promise) {
+    return promise.then(
+      null,
+      function onError(reason) {
+        Cu.reportError("Uncaught asynchronous error: " + reason + " at\n" + reason.stack);
+        throw reason;
+      }
+    );
+  },
+  /**
+   * Spawn a new Task from a generator.
+   *
+   * This function behaves as |Task.spawn|, with the exception that it
+   * adds logging in case of uncaught error. For more information, see
+   * the documentation of |Task.jsm|.
+   *
+   * @param {generator} gen Some generator.
+   * @return {Promise} A promise built from |gen|, with the same semantics
+   * as |Task.spawn(gen)|.
+   */
+  spawn: function spawn(gen) {
+    return this.captureErrors(Task.spawn(gen));
+  }
+};
+
+let SessionFileInternal = {
+  /**
+   * A promise fulfilled once initialization is complete
+   */
+  promiseInitialized: Promise.defer(),
+
+  /**
+   * The path to sessionstore.js
+   */
+  path: OS.Path.join(OS.Constants.Path.profileDir, "sessionstore.js"),
+
+  /**
+   * The path to sessionstore.bak
+   */
+  backupPath: OS.Path.join(OS.Constants.Path.profileDir, "sessionstore.bak"),
+
+  /**
+   * Read the sessionstore file synchronously.
+   *
+   * This function is meant to serve as a fallback in case of race
+   * between a synchronous usage of the API and asynchronous
+   * initialization.
+   */
+  syncRead: function ssfi_syncRead() {
+    let text;
+    let exn;
+    TelemetryStopwatch.start("FX_SESSION_RESTORE_SYNC_READ_FILE_MS");
+    try {
+      let file = new FileUtils.File(this.path);
+      if (!file.exists()) {
+        return null;
+      }
+      let chan = NetUtil.newChannel(file);
+      let stream = chan.open();
+      text = NetUtil.readInputStreamToString(stream, stream.available(), {charset: "utf-8"});
+    } catch(ex) {
+      exn = ex;
+    } finally {
+      TelemetryStopwatch.finish("FX_SESSION_RESTORE_SYNC_READ_FILE_MS");
+    }
+    if (exn) {
+      Cu.reportError(exn);
+      return "";
+    }
+    return text;
+  },
+
+  read: function ssfi_read() {
+    let refObj = {};
+    let self = this;
+    return TaskUtils.spawn(function task() {
+      TelemetryStopwatch.start("FX_SESSION_RESTORE_READ_FILE_MS", refObj);
+      let text;
+      try {
+        let bytes = yield OS.File.read(self.path);
+        text = new TextDecoder().decode(bytes);
+        TelemetryStopwatch.finish("FX_SESSION_RESTORE_READ_FILE_MS", refObj);
+      } catch (ex) {
+        if (self._isNoSuchFile(ex)) {
+          // The file does not exist, this is perfectly valid
+          TelemetryStopwatch.finish("FX_SESSION_RESTORE_READ_FILE_MS", refObj);
+        } else {
+          // Any other error: let's not measure with telemetry
+          TelemetryStopwatch.cancel("FX_SESSION_RESTORE_READ_FILE_MS", refObj);
+          Cu.reportError(ex);
+        }
+        text = "";
+      }
+      throw new Task.Result(text);
+    });
+  },
+
+  write: function ssfi_write(aData) {
+    let refObj = {};
+    let self = this;
+    return TaskUtils.spawn(function task() {
+      TelemetryStopwatch.start("FX_SESSION_RESTORE_WRITE_FILE_MS", refObj);
+
+      let bytes = gEncoder.encode(aData);
+
+      try {
+        yield OS.File.writeAtomic(self.path, bytes, {tmpPath: self.path + ".tmp"});
+        TelemetryStopwatch.finish("FX_SESSION_RESTORE_WRITE_FILE_MS", refObj);
+      } catch (ex) {
+        TelemetryStopwatch.cancel("FX_SESSION_RESTORE_WRITE_FILE_MS", refObj);
+        Cu.reportError("Could not write session state file " + self.path
+                       + ": " + aReason);
+      }
+    });
+  },
+
+  createBackupCopy: function ssfi_createBackupCopy() {
+    let self = this;
+    return TaskUtils.spawn(function task() {
+      try {
+        yield OS.File.copy(self.path, self.backupPath);
+      } catch (ex) {
+        if (!self._isNoSuchFile(ex)) {
+          Cu.reportError("Could not backup session state file: " + ex);
+          throw ex;
+        }
+      }
+    });
+  },
+
+  wipe: function ssfi_wipe() {
+    let self = this;
+    return TaskUtils.spawn(function task() {
+      try {
+        yield OS.File.remove(self.path);
+      } catch (ex) {
+        Cu.reportError("Could not remove session state file: " + ex);
+        throw ex;
+      }
+      try {
+        yield OS.File.remove(self.backupPath);
+      } catch (ex) {
+        Cu.reportError("Could not remove session state backup file: " + ex);
+        throw ex;
+      }
+    });
+  },
+
+  _isNoSuchFile: function ssfi_isNoSuchFile(aReason) {
+    return aReason instanceof OS.File.Error && aReason.becauseNoSuchFile;
+  }
+};
--- a/browser/components/sessionstore/src/nsSessionStartup.js
+++ b/browser/components/sessionstore/src/nsSessionStartup.js
@@ -34,131 +34,167 @@
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/TelemetryStopwatch.jsm");
 Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
+Cu.import("resource://gre/modules/commonjs/promise/core.js");
+
+XPCOMUtils.defineLazyModuleGetter(this, "_SessionFile",
+  "resource:///modules/sessionstore/_SessionFile.jsm");
 
 const STATE_RUNNING_STR = "running";
-const MAX_FILE_SIZE = 100 * 1024 * 1024; // 100 megabytes
 
 function debug(aMsg) {
   aMsg = ("SessionStartup: " + aMsg).replace(/\S{80}/g, "$&\n");
   Services.console.logStringMessage(aMsg);
 }
 
+let gOnceInitializedDeferred = Promise.defer();
+
 /* :::::::: The Service ::::::::::::::: */
 
 function SessionStartup() {
 }
 
 SessionStartup.prototype = {
 
   // the state to restore at startup
   _initialState: null,
   _sessionType: Ci.nsISessionStartup.NO_SESSION,
+  _initialized: false,
 
 /* ........ Global Event Handlers .............. */
 
   /**
    * Initialize the component
    */
   init: function sss_init() {
+    debug("init starting");
     // do not need to initialize anything in auto-started private browsing sessions
-    let pbs = Cc["@mozilla.org/privatebrowsing;1"].
-              getService(Ci.nsIPrivateBrowsingService);
-    if (PrivateBrowsingUtils.permanentPrivateBrowsing ||
-        pbs.lastChangedByCommandLine)
-      return;
-
-    let prefBranch = Cc["@mozilla.org/preferences-service;1"].
-                     getService(Ci.nsIPrefService).getBranch("browser.");
-
-    // get file references
-    var dirService = Cc["@mozilla.org/file/directory_service;1"].
-                     getService(Ci.nsIProperties);
-    let sessionFile = dirService.get("ProfD", Ci.nsILocalFile);
-    sessionFile.append("sessionstore.js");
-
-    let doResumeSessionOnce = prefBranch.getBoolPref("sessionstore.resume_session_once");
-    let doResumeSession = doResumeSessionOnce ||
-                          prefBranch.getIntPref("startup.page") == 3;
-
-    // only continue if the session file exists
-    if (!sessionFile.exists())
-      return;
-
-    // get string containing session state
-    let iniString = this._readStateFile(sessionFile);
-    if (!iniString)
+    if (PrivateBrowsingUtils.permanentPrivateBrowsing)
       return;
 
-    // parse the session state into a JS object
-    // remove unneeded braces (added for compatibility with Firefox 2.0 and 3.0)
-    if (iniString.charAt(0) == '(')
-      iniString = iniString.slice(1, -1);
-    let corruptFile = false;
-    try {
-      this._initialState = JSON.parse(iniString);
+#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
+    let pbs = Cc["@mozilla.org/privatebrowsing;1"].
+              getService(Ci.nsIPrivateBrowsingService);
+    if (pbs.lastChangedByCommandLine)
+      return;
+#endif
+    // Session state is unknown until we read the file.
+    this._sessionType = null;
+    _SessionFile.read().then(
+      this._onSessionFileRead.bind(this)
+    );
+    debug("init launched");
+  },
+
+  // Wrap a string as a nsISupports
+  _createSupportsString: function ssfi_createSupportsString(aData) {
+    let string = Cc["@mozilla.org/supports-string;1"]
+                   .createInstance(Ci.nsISupportsString);
+    string.data = aData;
+    return string;
+  },
+
+  _onSessionFileRead: function sss_onSessionFileRead(aStateString) {
+    debug("onSessionFileRead ");
+    if (this._initialized) {
+      debug("onSessionFileRead: Initialization is already complete");
+      // Initialization is complete, nothing else to do
+      return;
     }
-    catch (ex) {
-      debug("The session file contained un-parse-able JSON: " + ex);
-      // Try to eval.
-      // evalInSandbox will throw if iniString is not parse-able.
-      try {
-        var s = new Cu.Sandbox("about:blank", {sandboxName: 'nsSessionStartup'});
-        this._initialState = Cu.evalInSandbox("(" + iniString + ")", s);
-      } catch(ex) {
-        debug("The session file contained un-eval-able JSON: " + ex);
-        corruptFile = true;
+    try {
+      this._initialized = true;
+
+      // Let observers modify the state before it is used
+      let supportsStateString = this._createSupportsString(aStateString);
+      Services.obs.notifyObservers(supportsStateString, "sessionstore-state-read", "");
+      aStateString = supportsStateString.data;
+
+      // No valid session found.
+      if (!aStateString) {
+        this._sessionType = Ci.nsISessionStartup.NO_SESSION;
+        return;
       }
-    }
-    Services.telemetry.getHistogramById("FX_SESSION_RESTORE_CORRUPT_FILE").add(corruptFile);
-
-    // If this is a normal restore then throw away any previous session
-    if (!doResumeSessionOnce)
-      delete this._initialState.lastSessionState;
 
-    let resumeFromCrash = prefBranch.getBoolPref("sessionstore.resume_from_crash");
-    let lastSessionCrashed =
-      this._initialState && this._initialState.session &&
-      this._initialState.session.state &&
-      this._initialState.session.state == STATE_RUNNING_STR;
+      // parse the session state into a JS object
+      // remove unneeded braces (added for compatibility with Firefox 2.0 and 3.0)
+      if (aStateString.charAt(0) == '(')
+        aStateString = aStateString.slice(1, -1);
+      let corruptFile = false;
+      try {
+        this._initialState = JSON.parse(aStateString);
+      }
+      catch (ex) {
+        debug("The session file contained un-parse-able JSON: " + ex);
+        // This is not valid JSON, but this might still be valid JavaScript,
+        // as used in FF2/FF3, so we need to eval.
+        // evalInSandbox will throw if aStateString is not parse-able.
+        try {
+          var s = new Cu.Sandbox("about:blank", {sandboxName: 'nsSessionStartup'});
+          this._initialState = Cu.evalInSandbox("(" + aStateString + ")", s);
+        } catch(ex) {
+          debug("The session file contained un-eval-able JSON: " + ex);
+          corruptFile = true;
+        }
+      }
+      Services.telemetry.getHistogramById("FX_SESSION_RESTORE_CORRUPT_FILE").add(corruptFile);
 
-    // Report shutdown success via telemetry. Shortcoming here are
-    // being-killed-by-OS-shutdown-logic, shutdown freezing after
-    // session restore was written, etc.
-    Services.telemetry.getHistogramById("SHUTDOWN_OK").add(!lastSessionCrashed);
+      let doResumeSessionOnce = Services.prefs.getBoolPref("browser.sessionstore.resume_session_once");
+      let doResumeSession = doResumeSessionOnce ||
+            Services.prefs.getIntPref("browser.startup.page") == 3;
+
+      // If this is a normal restore then throw away any previous session
+      if (!doResumeSessionOnce)
+        delete this._initialState.lastSessionState;
 
-    // set the startup type
-    if (lastSessionCrashed && resumeFromCrash)
-      this._sessionType = Ci.nsISessionStartup.RECOVER_SESSION;
-    else if (!lastSessionCrashed && doResumeSession)
-      this._sessionType = Ci.nsISessionStartup.RESUME_SESSION;
-    else if (this._initialState)
-      this._sessionType = Ci.nsISessionStartup.DEFER_SESSION;
-    else
-      this._initialState = null; // reset the state
+      let resumeFromCrash = Services.prefs.getBoolPref("browser.sessionstore.resume_from_crash");
+      let lastSessionCrashed =
+        this._initialState && this._initialState.session &&
+        this._initialState.session.state &&
+        this._initialState.session.state == STATE_RUNNING_STR;
+
+      // Report shutdown success via telemetry. Shortcoming here are
+      // being-killed-by-OS-shutdown-logic, shutdown freezing after
+      // session restore was written, etc.
+      Services.telemetry.getHistogramById("SHUTDOWN_OK").add(!lastSessionCrashed);
 
-    // wait for the first browser window to open
-    // Don't reset the initial window's default args (i.e. the home page(s))
-    // if all stored tabs are pinned.
-    if (this.doRestore() &&
-        (!this._initialState.windows ||
-        !this._initialState.windows.every(function (win)
-           win.tabs.every(function (tab) tab.pinned))))
-      Services.obs.addObserver(this, "domwindowopened", true);
+      // set the startup type
+      if (lastSessionCrashed && resumeFromCrash)
+        this._sessionType = Ci.nsISessionStartup.RECOVER_SESSION;
+      else if (!lastSessionCrashed && doResumeSession)
+        this._sessionType = Ci.nsISessionStartup.RESUME_SESSION;
+      else if (this._initialState)
+        this._sessionType = Ci.nsISessionStartup.DEFER_SESSION;
+      else
+        this._initialState = null; // reset the state
 
-    Services.obs.addObserver(this, "sessionstore-windows-restored", true);
+      // wait for the first browser window to open
+      // Don't reset the initial window's default args (i.e. the home page(s))
+      // if all stored tabs are pinned.
+      if (this.doRestore() &&
+          (!this._initialState.windows ||
+           !this._initialState.windows.every(function (win)
+             win.tabs.every(function (tab) tab.pinned))))
+        Services.obs.addObserver(this, "domwindowopened", true);
 
-    if (this._sessionType != Ci.nsISessionStartup.NO_SESSION)
-      Services.obs.addObserver(this, "browser:purge-session-history", true);
+      Services.obs.addObserver(this, "sessionstore-windows-restored", true);
+
+      if (this._sessionType != Ci.nsISessionStartup.NO_SESSION)
+        Services.obs.addObserver(this, "browser:purge-session-history", true);
+
+    } finally {
+      // We're ready. Notify everyone else.
+      Services.obs.notifyObservers(null, "sessionstore-state-finalized", "");
+      gOnceInitializedDeferred.resolve();
+    }
   },
 
   /**
    * Handle notifications
    */
   observe: function sss_observe(aSubject, aTopic, aData) {
     switch (aTopic) {
     case "app-startup":
@@ -232,89 +268,62 @@ SessionStartup.prototype = {
     } catch (e) {
       // This might throw if we're removing the observer multiple times,
       // but this is safe to ignore.
     }
   },
 
 /* ........ Public API ................*/
 
+  get onceInitialized() {
+    return gOnceInitializedDeferred.promise;
+  },
+
   /**
    * Get the session state as a jsval
    */
   get state() {
+    this._ensureInitialized();
     return this._initialState;
   },
 
   /**
    * Determine whether there is a pending session restore.
    * @returns bool
    */
   doRestore: function sss_doRestore() {
+    this._ensureInitialized();
     return this._sessionType == Ci.nsISessionStartup.RECOVER_SESSION ||
            this._sessionType == Ci.nsISessionStartup.RESUME_SESSION;
   },
 
   /**
    * Get the type of pending session store, if any.
    */
   get sessionType() {
+    this._ensureInitialized();
     return this._sessionType;
   },
 
-/* ........ Storage API .............. */
-
-  /**
-   * Reads a session state file into a string and lets
-   * observers modify the state before it's being used
-   *
-   * @param aFile is any nsIFile
-   * @returns a session state string
-   */
-  _readStateFile: function sss_readStateFile(aFile) {
-    TelemetryStopwatch.start("FX_SESSION_RESTORE_READ_FILE_MS");
-    var stateString = Cc["@mozilla.org/supports-string;1"].
-                        createInstance(Ci.nsISupportsString);
-    stateString.data = this._readFile(aFile) || "";
-    TelemetryStopwatch.finish("FX_SESSION_RESTORE_READ_FILE_MS");
-
-    Services.obs.notifyObservers(stateString, "sessionstore-state-read", "");
-
-    return stateString.data;
-  },
-
-  /**
-   * reads a file into a string
-   * @param aFile
-   *        nsIFile
-   * @returns string
-   */
-  _readFile: function sss_readFile(aFile) {
+  // Ensure that initialization is complete.
+  // If initialization is not complete yet, fall back to a synchronous
+  // initialization and kill ongoing asynchronous initialization
+  _ensureInitialized: function sss__ensureInitialized() {
     try {
-      var stream = Cc["@mozilla.org/network/file-input-stream;1"].
-                   createInstance(Ci.nsIFileInputStream);
-      stream.init(aFile, 0x01, 0, 0);
-      var cvstream = Cc["@mozilla.org/intl/converter-input-stream;1"].
-                     createInstance(Ci.nsIConverterInputStream);
-
-      var fileSize = stream.available();
-      if (fileSize > MAX_FILE_SIZE)
-        throw "SessionStartup: sessionstore.js was not processed because it was too large.";
-
-      cvstream.init(stream, "UTF-8", fileSize, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
-      var data = {};
-      cvstream.readString(fileSize, data);
-      var content = data.value;
-      cvstream.close();
-
-      return content.replace(/\r\n?/g, "\n");
+      debug("_ensureInitialized: " + this._initialState);
+      if (this._initialized) {
+        // Initialization is complete, nothing else to do
+        return;
+      }
+      let contents = _SessionFile.syncRead();
+      this._onSessionFileRead(contents);
+    } catch(ex) {
+      debug("ensureInitialized: could not read session " + ex + ", " + ex.stack);
+      throw ex;
     }
-    catch (ex) { Cu.reportError(ex); }
-
-    return null;
   },
 
   /* ........ QueryInterface .............. */
   QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver,
                                           Ci.nsISupportsWeakReference,
                                           Ci.nsISessionStartup]),
   classID:          Components.ID("{ec7a6c20-e081-11da-8ad9-0800200c9a66}"),
 };
--- a/browser/components/sessionstore/test/Makefile.in
+++ b/browser/components/sessionstore/test/Makefile.in
@@ -11,16 +11,20 @@ relativesrcdir  = @relativesrcdir@
 include $(DEPTH)/config/autoconf.mk
 
 # browser_506482.js is disabled because of frequent failures (bug 538672)
 # browser_526613.js is disabled because of frequent failures (bug 534489)
 # browser_589246.js is disabled for leaking browser windows (bug 752467)
 # browser_580512.js is disabled for leaking browser windows (bug 752467)
 # browser_586068-reload.js is disabled due to generally being broken (bug 809123, 797263)
 
+XPCSHELL_TESTS = \
+	unit \
+	$(NULL)
+
 MOCHITEST_BROWSER_FILES = \
 	head.js \
 	browser_form_restore_events.js \
 	browser_form_restore_events_sample.html \
 	browser_formdata_format.js \
 	browser_formdata_format_sample.html \
 	browser_248970_b_sample.html \
 	browser_339445.js \
@@ -137,17 +141,17 @@ ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
 MOCHITEST_BROWSER_FILES += \
 	browser_354894_perwindowpb.js \
 	browser_394759_perwindowpb.js \
 	$(NULL)
 else
 MOCHITEST_BROWSER_FILES += \
 	browser_248970_a.js \
 	browser_248970_b.js \
-+	browser_248970_b_perwindowpb.js \
+	browser_248970_b_perwindowpb.js \
 	browser_354894.js \
 	browser_394759_privatebrowsing.js \
 	$(NULL)
 endif
 
 # Disabled on Windows for frequent intermittent failures
 ifneq ($(OS_ARCH), WINNT)
 MOCHITEST_FILES += \
--- a/browser/components/sessionstore/test/browser_597071.js
+++ b/browser/components/sessionstore/test/browser_597071.js
@@ -2,19 +2,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 function test() {
   /** Test for Bug 597071 **/
 
   waitForExplicitFinish();
 
-  let pb = Cc["@mozilla.org/privatebrowsing;1"].
-           getService(Ci.nsIPrivateBrowsingService);
-
   // set the pref to 1 greater than it currently is so we have room for an extra
   // closed window
   let closedWindowCount = ss.getClosedWindowCount();
   Services.prefs.setIntPref("browser.sessionstore.max_windows_undo",
                             closedWindowCount + 1);
 
   let currentState = ss.getBrowserState();
   let popupState = { windows:[
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/unit/data/sessionstore_valid.js
@@ -0,0 +1,3 @@
+{
+  "windows": []
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/unit/head.js
@@ -0,0 +1,26 @@
+let Cu = Components.utils;
+let Cc = Components.classes;
+let Ci = Components.interfaces;
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+// Call a function once initialization of SessionStartup is complete
+let afterSessionStartupInitialization =
+  function afterSessionStartupInitialization(cb) {
+    do_print("Waiting for session startup initialization");
+    let observer = function() {
+      try {
+        do_print("Session startup initialization observed");
+        Services.obs.removeObserver(observer, "sessionstore-state-finalized");
+        cb();
+      } catch (ex) {
+        do_throw(ex);
+      }
+    };
+    let startup = Cc["@mozilla.org/browser/sessionstartup;1"].
+      getService(Ci.nsIObserver);
+    Services.obs.addObserver(startup, "final-ui-startup", false);
+    Services.obs.addObserver(startup, "quit-application", false);
+    Services.obs.notifyObservers(null, "final-ui-startup", "");
+    Services.obs.addObserver(observer, "sessionstore-state-finalized", false);
+};
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/unit/test_startup_nosession_async.js
@@ -0,0 +1,22 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+
+// Test nsISessionStartup.sessionType in the following scenario:
+// - no sessionstore.js;
+// - the session store has been loaded, so no need to go
+//    through the synchronous fallback
+
+function run_test() {
+  do_get_profile();
+  // Initialize the profile (the session startup uses it)
+
+  do_test_pending();
+  let startup = Cc["@mozilla.org/browser/sessionstartup;1"].
+    getService(Ci.nsISessionStartup);
+
+  afterSessionStartupInitialization(function cb() {
+    do_check_eq(startup.sessionType, Ci.nsISessionStartup.NO_SESSION);
+    do_test_finished();
+  });
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/unit/test_startup_nosession_sync.js
@@ -0,0 +1,15 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+
+// Test nsISessionStartup.sessionType in the following scenario:
+// - no sessionstore.js;
+// - the session store has not been loaded yet, so we have to trigger
+//    synchronous fallback
+
+function run_test() {
+  do_get_profile();
+  let startup = Cc["@mozilla.org/browser/sessionstartup;1"].
+    getService(Ci.nsISessionStartup);
+  do_check_eq(startup.sessionType, Ci.nsISessionStartup.NO_SESSION);
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/unit/test_startup_session_async.js
@@ -0,0 +1,23 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+
+// Test nsISessionStartup.sessionType in the following scenario:
+// - valid sessionstore.js;
+// - the session store has been loaded, so no need to go
+//    through the synchronous fallback
+
+function run_test() {
+  let profd = do_get_profile();
+  let source = do_get_file("data/sessionstore_valid.js");
+  source.copyTo(profd, "sessionstore.js");
+
+  do_test_pending();
+  let startup = Cc["@mozilla.org/browser/sessionstartup;1"].
+    getService(Ci.nsISessionStartup);
+
+  afterSessionStartupInitialization(function cb() {
+    do_check_eq(startup.sessionType, Ci.nsISessionStartup.DEFER_SESSION);
+    do_test_finished();
+  });
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/unit/test_startup_session_sync.js
@@ -0,0 +1,17 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+
+// Test nsISessionStartup.sessionType in the following scenario:
+// - valid sessionstore.js;
+// - the session store has not been loaded yet, so we have to trigger
+//    synchronous fallback
+
+function run_test() {
+  let profd = do_get_profile();
+  let source = do_get_file("data/sessionstore_valid.js");
+  source.copyTo(profd, "sessionstore.js");
+  let startup = Cc["@mozilla.org/browser/sessionstartup;1"].
+    getService(Ci.nsISessionStartup);
+  do_check_eq(startup.sessionType, Ci.nsISessionStartup.DEFER_SESSION);
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/unit/xpcshell.ini
@@ -0,0 +1,8 @@
+[DEFAULT]
+head = head.js
+tail =
+
+[test_startup_nosession_sync.js]
+[test_startup_nosession_async.js]
+[test_startup_session_sync.js]
+[test_startup_session_async.js]
\ No newline at end of file
--- a/browser/devtools/debugger/DebuggerUI.jsm
+++ b/browser/devtools/debugger/DebuggerUI.jsm
@@ -169,22 +169,16 @@ DebuggerUI.prototype = {
    * @return ChromeDebuggerProcess | null
    *         The chrome debugger instance if it exists, null otherwise.
    */
   getChromeDebugger: function DUI_getChromeDebugger() {
     return '_chromeDebugger' in this ? this._chromeDebugger : null;
   },
 
   /**
-   * Get the preferences associated with the debugger frontend.
-   * @return object
-   */
-  get preferences() Prefs,
-
-  /**
    * Currently, there can only be one debugger per tab.
    * Show an asynchronous notification which asks the user to switch the
    * script debugger to the current tab if it's already open in another one.
    */
   showTabSwitchNotification: function DUI_showTabSwitchNotification() {
     let gBrowser = this.chromeWindow.gBrowser;
     let selectedBrowser = gBrowser.selectedBrowser;
 
@@ -274,17 +268,16 @@ DebuggerPane.prototype = {
 
     let gBrowser = this._win.gBrowser;
     let ownerDocument = gBrowser.parentNode.ownerDocument;
 
     this._splitter = ownerDocument.createElement("splitter");
     this._splitter.setAttribute("class", "devtools-horizontal-splitter");
 
     this._frame = ownerDocument.createElement("iframe");
-    this._frame.height = Prefs.height;
 
     this._nbox = gBrowser.getNotificationBox(this._tab.linkedBrowser);
     this._nbox.appendChild(this._splitter);
     this._nbox.appendChild(this._frame);
 
     let self = this;
 
     this._frame.addEventListener("Debugger:Loaded", function dbgLoaded() {
@@ -321,17 +314,16 @@ DebuggerPane.prototype = {
     if (typeof aCloseCallback == "function") {
       let frame = this._frame;
       frame.addEventListener("unload", function onUnload() {
         frame.removeEventListener("unload", onUnload, true);
         aCloseCallback();
       }, true)
     }
 
-    Prefs.height = this._frame.height;
     this._frame.removeEventListener("Debugger:Unloaded", this.close, true);
     this._nbox.removeChild(this._splitter);
     this._nbox.removeChild(this._frame);
 
     this._splitter = null;
     this._frame = null;
     this._nbox = null;
     this._win = null;
@@ -594,31 +586,17 @@ let L10N = {
 
 XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() {
   return Services.strings.createBundle(DBG_STRINGS_URI);
 });
 
 /**
  * Shortcuts for accessing various debugger preferences.
  */
-let Prefs = {
-  /**
-   * Gets the preferred height of the debugger pane.
-   * @return number
-   */
-  get height()
-    Services.prefs.getIntPref("devtools.debugger.ui.height"),
-
-  /**
-   * Sets the preferred height of the debugger pane.
-   * @param number aValue
-   */
-  set height(aValue)
-    Services.prefs.setIntPref("devtools.debugger.ui.height", aValue)
-};
+let Prefs = {};
 
 /**
  * Gets the preferred default remote debugging host.
  * @return string
  */
 XPCOMUtils.defineLazyGetter(Prefs, "remoteHost", function() {
   return Services.prefs.getCharPref("devtools.debugger.remote-host");
 });
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -6,16 +6,17 @@
 "use strict";
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties";
 const NEW_SCRIPT_DISPLAY_DELAY = 200; // ms
+const FETCH_SOURCE_RESPONSE_DELAY = 50; // ms
 const FRAME_STEP_CLEAR_DELAY = 100; // ms
 const CALL_STACK_PAGE_SIZE = 25; // frames
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
 Cu.import("resource:///modules/source-editor.jsm");
@@ -1161,39 +1162,51 @@ SourceScripts.prototype = {
    *        - forced: force the source to be immediately added
    */
   _addSource: function SS__addSource(aSource, aOptions = {}) {
     let url = aSource.url;
     let label = SourceUtils.getSourceLabel(url);
 
     DebuggerView.Sources.push(label, url, {
       forced: aOptions.forced,
+      tooltip: url,
       attachment: aSource
     });
   },
 
   /**
    * Gets a specified source's text.
    *
    * @param object aSource
    *        The source object coming from the active thread.
    * @param function aCallback
    *        Function called after the source text has been loaded.
+   * @param function aOnTimeout
+   *        Function called when the source text takes too long to fetch.
    */
-  getText: function SS_getText(aSource, aCallback) {
+  getText: function SS_getText(aSource, aCallback, aOnTimeout) {
     // If already loaded, return the source text immediately.
     if (aSource.loaded) {
       aCallback(aSource.url, aSource.text);
       return;
     }
 
+    // If the source text takes too long to fetch, invoke a timeout to
+    // avoid blocking any operations.
+    if (aOnTimeout) {
+      var fetchTimeout = window.setTimeout(aOnTimeout, FETCH_SOURCE_RESPONSE_DELAY);
+    }
+
     // Get the source text from the active thread.
     this.activeThread.source(aSource.source).source(function(aResponse) {
+      window.clearTimeout(fetchTimeout);
+
       if (aResponse.error) {
-        Cu.reportError("Error loading " + aUrl);
+        Cu.reportError("Error loading " + aSource.url + "\n" + aResponse.error);
+        aCallback(aSource.url, "");
         return;
       }
       aSource.loaded = true;
       aSource.text = aResponse.source;
       aCallback(aSource.url, aResponse.source);
     });
   }
 };
@@ -1604,17 +1617,16 @@ let Prefs = {
   map: function P_map(aType, aPropertyName, aPrefName) {
     Object.defineProperty(this, aPropertyName, {
       get: function() this._get(aType, aPrefName),
       set: function(aValue) this._set(aType, aPrefName, aValue)
     });
   }
 };
 
-Prefs.map("Int", "height", "devtools.debugger.ui.height");
 Prefs.map("Int", "windowX", "devtools.debugger.ui.win-x");
 Prefs.map("Int", "windowY", "devtools.debugger.ui.win-y");
 Prefs.map("Int", "windowWidth", "devtools.debugger.ui.win-width");
 Prefs.map("Int", "windowHeight", "devtools.debugger.ui.win-height");
 Prefs.map("Int", "stackframesWidth", "devtools.debugger.ui.stackframes-width");
 Prefs.map("Int", "variablesWidth", "devtools.debugger.ui.variables-width");
 Prefs.map("Bool", "panesVisibleOnStartup", "devtools.debugger.ui.panes-visible-on-startup");
 Prefs.map("Bool", "variablesSortingEnabled", "devtools.debugger.ui.variables-sorting-enabled");
--- a/browser/devtools/debugger/debugger-panes.js
+++ b/browser/devtools/debugger/debugger-panes.js
@@ -1255,16 +1255,17 @@ create({ constructor: WatchExpressionsVi
 /**
  * Functions handling the global search UI.
  */
 function GlobalSearchView() {
   dumpn("GlobalSearchView was instantiated");
   MenuContainer.call(this);
   this._startSearch = this._startSearch.bind(this);
   this._onFetchSourceFinished = this._onFetchSourceFinished.bind(this);
+  this._onFetchSourceTimeout = this._onFetchSourceTimeout.bind(this);
   this._onFetchSourcesFinished = this._onFetchSourcesFinished.bind(this);
   this._createItemView = this._createItemView.bind(this);
   this._onScroll = this._onScroll.bind(this);
   this._onHeaderClick = this._onHeaderClick.bind(this);
   this._onLineClick = this._onLineClick.bind(this);
   this._onMatchClick = this._onMatchClick.bind(this);
 }
 
@@ -1397,45 +1398,50 @@ create({ constructor: GlobalSearchView, 
    * @param string aQuery
    *        The string to search for.
    */
   _startSearch: function DVGS__startSearch(aQuery) {
     let locations = DebuggerView.Sources.values;
     this._sourcesCount = locations.length;
     this._searchedToken = aQuery;
 
-    this._fetchSources(
-      this._onFetchSourceFinished,
-      this._onFetchSourcesFinished, locations);
+    this._fetchSources(locations, {
+      onFetch: this._onFetchSourceFinished,
+      onTimeout: this._onFetchSourceTimeout,
+      onFinished: this._onFetchSourcesFinished
+    });
   },
 
   /**
    * Starts fetching all the sources, silently.
    *
-   * @param function aFetchCallback
-   *        Called after each source is fetched.
-   * @param function aFetchedCallback
-   *        Called if all the sources were already fetched.
    * @param array aLocations
    *        The locations for the sources to fetch.
+   * @param object aCallbacks
+   *        An object containing the callback functions to invoke:
+   *          - onFetch: called after each source is fetched
+   *          - onTimeout: called when a source's text takes too long to fetch
+   *          - onFinished: called if all the sources were already fetched
    */
-  _fetchSources: function DVGS__fetchSources(aFetchCallback, aFetchedCallback, aLocations) {
+  _fetchSources:
+  function DVGS__fetchSources(aLocations, { onFetch, onTimeout, onFinished }) {
     // If all the sources were already fetched, then don't do anything.
     if (this._cache.size == aLocations.length) {
-      aFetchedCallback();
+      onFinished();
       return;
     }
 
     // Fetch each new source.
     for (let location of aLocations) {
       if (this._cache.has(location)) {
         continue;
       }
       let sourceItem = DebuggerView.Sources.getItemByValue(location);
-      DebuggerController.SourceScripts.getText(sourceItem.attachment, aFetchCallback);
+      let sourceObject = sourceItem.attachment;
+      DebuggerController.SourceScripts.getText(sourceObject, onFetch, onTimeout);
     }
   },
 
   /**
    * Called when a source has been fetched.
    *
    * @param string aLocation
    *        The location of the source.
@@ -1448,19 +1454,33 @@ create({ constructor: GlobalSearchView, 
 
     // Check if all sources were fetched and stored in the cache.
     if (this._cache.size == this._sourcesCount) {
       this._onFetchSourcesFinished();
     }
   },
 
   /**
+   * Called when a source's text takes too long to fetch.
+   */
+  _onFetchSourceTimeout: function DVGS__onFetchSourceTimeout() {
+    // Remove the source from the load queue.
+    this._sourcesCount--;
+
+    // Check if the remaining sources were fetched and stored in the cache.
+    if (this._cache.size == this._sourcesCount) {
+      this._onFetchSourcesFinished();
+    }
+  },
+
+  /**
    * Called when all the sources have been fetched.
    */
   _onFetchSourcesFinished: function DVGS__onFetchSourcesFinished() {
+    // At least one source needs to be present to perform a global search.
     if (!this._sourcesCount) {
       return;
     }
     // All sources are fetched and stored in the cache, we can start searching.
     this._performGlobalSearch();
     this._sourcesCount = 0;
   },
 
--- a/browser/devtools/debugger/debugger-toolbar.js
+++ b/browser/devtools/debugger/debugger-toolbar.js
@@ -6,17 +6,16 @@
 "use strict";
 
 /**
  * Functions handling the toolbar view: close button, expand/collapse button,
  * pause/resume and stepping buttons etc.
  */
 function ToolbarView() {
   dumpn("ToolbarView was instantiated");
-  this._onCloseClick = this._onCloseClick.bind(this);
   this._onTogglePanesPressed = this._onTogglePanesPressed.bind(this);
   this._onResumePressed = this._onResumePressed.bind(this);
   this._onStepOverPressed = this._onStepOverPressed.bind(this);
   this._onStepInPressed = this._onStepInPressed.bind(this);
   this._onStepOutPressed = this._onStepOutPressed.bind(this);
 }
 
 ToolbarView.prototype = {
@@ -104,23 +103,16 @@ ToolbarView.prototype = {
    * @param boolean aVisibleFlag
    *        Specifies the intended visibility.
    */
   toggleSourcesContainer: function DVT_toggleSourcesContainer(aVisibleFlag) {
     this._sources.setAttribute("hidden", !aVisibleFlag);
   },
 
   /**
-   * Listener handling the close button click event.
-   */
-  _onCloseClick: function DVT__onCloseClick() {
-    DebuggerController._shutdownDebugger();
-  },
-
-  /**
    * Listener handling the toggle button click event.
    */
   _onTogglePanesPressed: function DVT__onTogglePanesPressed() {
     DebuggerView.togglePanes({
       visible: DebuggerView.panesHidden,
       animated: true
     });
   },
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -613,28 +613,29 @@ MenuContainer.prototype = {
    * @param string aValue
    *        The actual internal value of the item.
    * @param object aOptions [optional]
    *        Additional options or flags supported by this operation:
    *          - forced: true to force the item to be immediately appended
    *          - unsorted: true if the items should not always remain sorted
    *          - relaxed: true if this container should allow dupes & degenerates
    *          - description: an optional description of the item
+   *          - tooltip: an optional tooltip for the item
    *          - attachment: some attached primitive/object
    * @return MenuItem
    *         The item associated with the displayed element if a forced push,
    *         undefined if the item was staged for a later commit.
    */
   push: function DVMC_push(aLabel, aValue, aOptions = {}) {
     let item = new MenuItem(
       aLabel, aValue, aOptions.description, aOptions.attachment);
 
     // Batch the item to be added later.
     if (!aOptions.forced) {
-      this._stagedItems.push(item);
+      this._stagedItems.push({ item: item, options: aOptions });
     }
     // Immediately insert the item at the specified index.
     else if (aOptions.forced && aOptions.forced.atIndex !== undefined) {
       return this._insertItemAt(aOptions.forced.atIndex, item, aOptions);
     }
     // Find the target position in this container and insert the item there.
     else if (!aOptions.unsorted) {
       return this._insertItemAt(this._findExpectedIndex(aLabel), item, aOptions);
@@ -652,21 +653,22 @@ MenuContainer.prototype = {
    *        Additional options or flags supported by this operation:
    *          - unsorted: true if the items should not be sorted beforehand
    */
   commit: function DVMC_commit(aOptions = {}) {
     let stagedItems = this._stagedItems;
 
     // By default, sort the items before adding them to this container.
     if (!aOptions.unsorted) {
-      stagedItems.sort(function(a, b) a.label.toLowerCase() > b.label.toLowerCase());
+      stagedItems.sort(function(a, b) a.item.label.toLowerCase() >
+                                      b.item.label.toLowerCase());
     }
     // Append the prepared items to this container.
-    for (let item of stagedItems) {
-      this._appendItem(item, aOptions);
+    for (let { item, options } of stagedItems) {
+      this._appendItem(item, options);
     }
     // Recreate the temporary items list for ulterior pushes.
     this._stagedItems = [];
   },
 
   /**
    * Updates this container to reflect the information provided by the
    * currently selected item.
@@ -745,31 +747,31 @@ MenuContainer.prototype = {
    *
    * @param string aLabel
    *        The item's label.
    * @return boolean
    *         True if the label is known, false otherwise.
    */
   containsLabel: function DVMC_containsLabel(aLabel) {
     return this._itemsByLabel.has(aLabel) ||
-           this._stagedItems.some(function(o) o.label == aLabel);
+           this._stagedItems.some(function({item}) item.label == aLabel);
   },
 
   /**
    * Checks whether an item with the specified value is among the elements
    * shown in this container.
    *
    * @param string aValue
    *        The item's value.
    * @return boolean
    *         True if the value is known, false otherwise.
    */
   containsValue: function DVMC_containsValue(aValue) {
     return this._itemsByValue.has(aValue) ||
-           this._stagedItems.some(function(o) o.value == aValue);
+           this._stagedItems.some(function({item}) item.value == aValue);
   },
 
   /**
    * Checks whether an item with the specified trimmed value is among the
    * elements shown in this container.
    *
    * @param string aValue
    *        The item's value.
@@ -783,17 +785,17 @@ MenuContainer.prototype = {
                                      aTrim = SourceUtils.trimUrlQuery) {
     let trimmedValue = aTrim(aValue);
 
     for (let [value] of this._itemsByValue) {
       if (aTrim(value) == trimmedValue) {
         return true;
       }
     }
-    return this._stagedItems.some(function(o) aTrim(o.value) == trimmedValue);
+    return this._stagedItems.some(function({item}) aTrim(item.value) == trimmedValue);
   },
 
   /**
    * Gets the preferred selected value to be displayed in this container.
    * @return string
    */
   get preferredValue() this._preferredValue,
 
@@ -1041,18 +1043,25 @@ MenuContainer.prototype = {
    * @return MenuItem
    *         The item associated with the displayed element, null if rejected.
    */
   _appendItem: function DVMC__appendItem(aItem, aOptions = {}) {
     if (!aOptions.relaxed && !this.isEligible(aItem)) {
       return null;
     }
 
-    return this._entangleItem(aItem, this._container.appendItem(
+    this._entangleItem(aItem, this._container.appendItem(
       aItem.label, aItem.value, "", aOptions.attachment));
+
+    // Handle any additional options after entangling the item.
+    if (aOptions.tooltip) {
+      aItem._target.setAttribute("tooltiptext", aOptions.tooltip);
+    }
+
+    return aItem;
   },
 
   /**
    * Immediately inserts an item in this container at the specified index.
    *
    * @param number aIndex
    *        The position in the container intended for this item.
    * @param MenuItem aItem
@@ -1063,18 +1072,25 @@ MenuContainer.prototype = {
    * @return MenuItem
    *         The item associated with the displayed element, null if rejected.
    */
   _insertItemAt: function DVMC__insertItemAt(aIndex, aItem, aOptions) {
     if (!aOptions.relaxed && !this.isEligible(aItem)) {
       return null;
     }
 
-    return this._entangleItem(aItem, this._container.insertItemAt(
+    this._entangleItem(aItem, this._container.insertItemAt(
       aIndex, aItem.label, aItem.value, "", aOptions.attachment));
+
+    // Handle any additional options after entangling the item.
+    if (aOptions.tooltip) {
+      aItem._target.setAttribute("tooltiptext", aOptions.tooltip);
+    }
+
+    return aItem;
   },
 
   /**
    * Entangles an item (model) with a displayed node element (view).
    *
    * @param MenuItem aItem
    *        The item describing the element.
    * @param nsIDOMNode aElement
--- a/browser/devtools/framework/Sidebar.jsm
+++ b/browser/devtools/framework/Sidebar.jsm
@@ -110,16 +110,26 @@ ToolSidebar.prototype = {
         currentID = id;
         break;
       }
     }
     return currentID;
   },
 
   /**
+   * Returns the requested tab based on the id.
+   *
+   * @param String id
+   *        unique id of the requested tab.
+   */
+  getTab: function ToolSidebar_getTab(id) {
+    return this._tabbox.tabpanels.querySelector("#sidebar-panel-" + id);
+  },
+
+  /**
    * Event handler.
    */
   handleEvent: function ToolSidebar_eventHandler(event) {
     if (event.type == "select") {
       let previousTool = this._currentTool;
       this._currentTool = this.getCurrentTabID();
       if (previousTool) {
         this.emit(previousTool + "-unselected");
@@ -171,17 +181,17 @@ ToolSidebar.prototype = {
    * Clean-up.
    */
   destroy: function ToolSidebar_destroy() {
     if (this._destroyed) {
       return Promise.resolve(null);
     }
     this._destroyed = true;
 
-    this._tabbox.removeEventListener("select", this, true);
+    this._tabbox.tabpanels.removeEventListener("select", this, true);
 
     while (this._tabbox.tabpanels.hasChildNodes()) {
       this._tabbox.tabpanels.removeChild(this._tabbox.tabpanels.firstChild);
     }
 
     while (this._tabbox.tabs.hasChildNodes()) {
       this._tabbox.tabs.removeChild(this._tabbox.tabs.firstChild);
     }
--- a/browser/devtools/framework/Target.jsm
+++ b/browser/devtools/framework/Target.jsm
@@ -290,19 +290,20 @@ TabWebProgressListener.prototype = {
       this.target.emit("will-navigate", request);
     }
   },
 
   onProgressChange: function() {},
   onSecurityChange: function() {},
   onStatusChange: function() {},
 
-  onLocationChange: function TwPL_onLocationChange(webProgress) {
-    let window = webProgress.DOMWindow;
-    if (this.target) {
+  onLocationChange: function TwPL_onLocationChange(webProgress, request, URI, flags) {
+    if (this.target &&
+        !(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT)) {
+      let window = webProgress.DOMWindow;
       this.target.emit("navigate", window);
     }
   },
 };
 
 
 /**
  * A WindowTarget represents a page living in a xul window or panel. Generally
--- a/browser/devtools/framework/ToolDefinitions.jsm
+++ b/browser/devtools/framework/ToolDefinitions.jsm
@@ -64,16 +64,18 @@ let webConsoleDefinition = {
   id: "webconsole",
   key: l10n("cmd.commandkey", webConsoleStrings),
   accesskey: l10n("webConsoleCmd.accesskey", webConsoleStrings),
   modifiers: Services.appinfo.OS == "Darwin" ? "accel,alt" : "accel,shift",
   ordinal: 0,
   icon: "chrome://browser/skin/devtools/webconsole-tool-icon.png",
   url: "chrome://browser/content/devtools/webconsole.xul",
   label: l10n("ToolboxWebconsole.label", webConsoleStrings),
+  tooltip: l10n("ToolboxWebconsole.tooltip", webConsoleStrings),
+
   isTargetSupported: function(target) {
     return true;
   },
   build: function(iframeWindow, toolbox) {
     let panel = new WebConsolePanel(iframeWindow, toolbox);
     return panel.open();
   }
 };
@@ -83,16 +85,17 @@ let debuggerDefinition = {
   key: l10n("open.commandkey", debuggerStrings),
   accesskey: l10n("debuggerMenu.accesskey", debuggerStrings),
   modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
   ordinal: 1,
   killswitch: "devtools.debugger.enabled",
   icon: "chrome://browser/skin/devtools/tools-icons-small.png",
   url: "chrome://browser/content/debugger.xul",
   label: l10n("ToolboxDebugger.label", debuggerStrings),
+  tooltip: l10n("ToolboxDebugger.tooltip", debuggerStrings),
 
   isTargetSupported: function(target) {
     return true;
   },
 
   build: function(iframeWindow, toolbox) {
     let panel = new DebuggerPanel(iframeWindow, toolbox);
     return panel.open();
@@ -103,16 +106,17 @@ let inspectorDefinition = {
   id: "inspector",
   accesskey: l10n("inspector.accesskey", inspectorStrings),
   key: l10n("inspector.commandkey", inspectorStrings),
   ordinal: 2,
   modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
   icon: "chrome://browser/skin/devtools/tools-icons-small.png",
   url: "chrome://browser/content/devtools/inspector/inspector.xul",
   label: l10n("inspector.label", inspectorStrings),
+  tooltip: l10n("inspector.tooltip", inspectorStrings),
 
   isTargetSupported: function(target) {
     return !target.isRemote;
   },
 
   build: function(iframeWindow, toolbox) {
     let panel = new InspectorPanel(iframeWindow, toolbox);
     return panel.open();
@@ -122,16 +126,17 @@ let inspectorDefinition = {
 let styleEditorDefinition = {
   id: "styleeditor",
   key: l10n("open.commandkey", styleEditorStrings),
   ordinal: 3,
   accesskey: l10n("open.accesskey", styleEditorStrings),
   modifiers: "shift",
   label: l10n("ToolboxStyleEditor.label", styleEditorStrings),
   url: "chrome://browser/content/styleeditor.xul",
+  tooltip: l10n("ToolboxStyleEditor.tooltip", styleEditorStrings),
 
   isTargetSupported: function(target) {
     return !target.isRemote && !target.isChrome;
   },
 
   build: function(iframeWindow, toolbox) {
     let panel = new StyleEditorPanel(iframeWindow, toolbox);
     return panel.open();
@@ -139,16 +144,17 @@ let styleEditorDefinition = {
 };
 
 let profilerDefinition = {
   id: "jsprofiler",
   killswitch: "devtools.profiler.enabled",
   icon: "chrome://browser/skin/devtools/tools-icons-small.png",
   url: "chrome://browser/content/profiler.xul",
   label: l10n("profiler.label", profilerStrings),
+  tooltip: l10n("profiler.tooltip", profilerStrings),
 
   isTargetSupported: function (target) {
     if (target.isRemote || target.isChrome) {
       return false;
     }
 
     return true;
   },
--- a/browser/devtools/framework/Toolbox.jsm
+++ b/browser/devtools/framework/Toolbox.jsm
@@ -11,16 +11,27 @@ Cu.import("resource://gre/modules/Servic
 Cu.import("resource://gre/modules/commonjs/promise/core.js");
 Cu.import("resource:///modules/devtools/EventEmitter.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Hosts",
                                   "resource:///modules/devtools/ToolboxHosts.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "CommandUtils",
                                   "resource:///modules/devtools/DeveloperToolbar.jsm");
+XPCOMUtils.defineLazyGetter(this, "toolboxStrings", function() {
+  let bundle = Services.strings.createBundle("chrome://browser/locale/devtools/toolbox.properties");
+  let l10n = function(name) {
+    try {
+      return bundle.GetStringFromName(name);
+    } catch (ex) {
+      Services.console.logStringMessage("Error reading '" + name + "'");
+    }
+  };
+  return l10n;
+});
 
 // DO NOT put Require.jsm or gcli.jsm into lazy getters as this breaks the
 // requisition import a few lines down.
 Cu.import("resource:///modules/devtools/gcli.jsm");
 Cu.import("resource://gre/modules/devtools/Require.jsm");
 
 let Requisition = require('gcli/cli').Requisition;
 let CommandOutputManager = require('gcli/canon').CommandOutputManager;
@@ -280,16 +291,18 @@ Toolbox.prototype = {
       if (position == this.hostType ||
          (!sideEnabled && position == this.HostType.SIDE)) {
         continue;
       }
 
       let button = this.doc.createElement("toolbarbutton");
       button.id = "toolbox-dock-" + position;
       button.className = "toolbox-dock-button";
+      button.setAttribute("tooltiptext", toolboxStrings("toolboxDockButtons." +
+                                                        position + ".tooltip"));
       button.addEventListener("command", function(position) {
         this.switchHost(position);
       }.bind(this, position));
 
       dockBox.appendChild(button);
     }
   },
 
@@ -343,16 +356,17 @@ Toolbox.prototype = {
 
     let id = toolDefinition.id;
 
     let radio = this.doc.createElement("radio");
     radio.setAttribute("label", toolDefinition.label);
     radio.className = "toolbox-tab devtools-tab";
     radio.id = "toolbox-tab-" + id;
     radio.setAttribute("toolid", id);
+    radio.setAttribute("tooltiptext", toolDefinition.tooltip);
 
     let ordinal = (typeof toolDefinition.ordinal == "number") ?
                   toolDefinition.ordinal : MAX_ORDINAL;
     radio.setAttribute("ordinal", ordinal);
 
     radio.addEventListener("command", function(id) {
       this.selectTool(id);
     }.bind(this, id));
--- a/browser/devtools/framework/connect/connect.css
+++ b/browser/devtools/framework/connect/connect.css
@@ -1,19 +1,30 @@
 html {
-  background: url("chrome://browser/skin/newtab/noise.png");
+  background-color: #111;
+  background-image: url("chrome://browser/skin/newtab/noise.png");
 }
 
 body {
-  font-family: Arial;
+  font-family: Arial, sans-serif;
+  color: white;
+  max-width: 600px;
+  margin: 30px auto 0;
+  box-shadow: 0 2px 3px black;
+  background-color: #3C3E40;
+}
+
+h1 {
+  margin: 0;
   padding: 20px;
-  border-radius: 3px;
-  max-width: 600px;
-  min-height: 400px;
-  margin: 10px auto 0;
+  background-color: rgba(0,0,0,0.12);
+  background-image: radial-gradient(ellipse farthest-corner at center top , rgb(159, 223, 255), rgba(101, 203, 255, 0.3)), radial-gradient(ellipse farthest-side at center top , rgba(101, 203, 255, 0.4), rgba(101, 203, 255, 0));
+  background-size: 100% 2px, 100% 5px;
+  background-repeat: no-repeat;
+  border-bottom: 1px solid rgba(0,0,0,0.1);
 }
 
 label {
   display: block;
   margin: 10px;
   font-size: 0;
 }
 
@@ -24,28 +35,31 @@ label > span {
   text-align: right;
   margin-right: 10px;
 }
 
 #submit {
   margin-left: 160px;
 }
 
-
-#actors, #connection-form {
-  margin: 20px;
+input:invalid {
+  box-shadow: 0 0 2px 2px #F06;
 }
 
-input {
-  border: 1px solid grey;
+section {
+  min-height: 160px;
+  margin: 60px 20px;
+  display: none; /* By default, hidden */
 }
 
-#connection-form,
-#connecting,
-#actors-list {
+.error-message {
+  color: red;
+}
+
+.error-message:not(.active) {
   display: none;
 }
 
 body:not(.actors-mode):not(.connecting) > #connection-form {
   display: block;
 }
 
 body.actors-mode > #actors-list {
@@ -55,33 +69,40 @@ body.actors-mode > #actors-list {
 body.connecting > #connecting {
   display: block;
 }
 
 #connecting {
   text-align: center;
 }
 
-#throbber {
-  height: 7px; width: 7px;
-  border-radius: 50%;
-  background: black;
-  display: inline-block;
-  animation-duration: 0.6s;
-  animation-name: anim;
-  animation-direction: alternate;
-  animation-iteration-count: infinite;
-  animation-timing-function: linear;
+#connecting > p > img {
+  vertical-align: top;
 }
-@keyframes anim {to {
-    transform: scale(0.5) rotate(0.1deg);
-}}
 
 #actors {
   padding-left: 0;
   font-size: 0.9rem;
 }
 
 #actors > a {
   display: block;
   margin: 5px;
   padding: 5px;
+  color: white;
 }
+
+.remote-process {
+  font-style: italic;
+  opacity: 0.8;
+}
+
+footer {
+  padding: 10px;
+  background-color: rgba(0,0,0,0.12);
+  border-top: 1px solid rgba(0,0,0,0.1);
+  font-size: small;
+}
+
+footer > a,
+footer > a:visited {
+  color: white;
+}
--- a/browser/devtools/framework/connect/connect.js
+++ b/browser/devtools/framework/connect/connect.js
@@ -5,96 +5,163 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const Cu = Components.utils;
 Cu.import("resource:///modules/devtools/Target.jsm");
 Cu.import("resource:///modules/devtools/Toolbox.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
 
 let gClient;
+let gConnectionTimeout;
 
-function submit() {
-  document.body.classList.add("connecting");
+XPCOMUtils.defineLazyGetter(window, 'l10n', function () {
+  return Services.strings.createBundle('chrome://browser/locale/devtools/connection-screen.properties');
+});
 
-  let host = document.getElementById("host").value;
-  let port = document.getElementById("port").value;
-  if (!host) {
-    host = Services.prefs.getCharPref("devtools.debugger.remote-host");
-  } else {
-    Services.prefs.setCharPref("devtools.debugger.remote-host", host);
+/**
+ * Once DOM is ready, we prefil the host/port inputs with
+ * pref-stored values.
+ */
+window.addEventListener("DOMContentLoaded", function onDOMReady() {
+  window.removeEventListener("DOMContentLoaded", onDOMReady, true);
+  let host = Services.prefs.getCharPref("devtools.debugger.remote-host");
+  let port = Services.prefs.getIntPref("devtools.debugger.remote-port");
+
+  if (host) {
+    document.getElementById("host").value = host;
   }
-  if (!port) {
-    port = Services.prefs.getIntPref("devtools.debugger.remote-port");
-  } else {
-    Services.prefs.setIntPref("devtools.debugger.remote-port", port);
+
+  if (port) {
+    document.getElementById("port").value = port;
   }
 
-  let transport = debuggerSocketConnect(host, port);
-  let client = gClient = new DebuggerClient(transport);
+}, true);
 
-  client.connect(function(aType, aTraits) {
-    client.listTabs(function(aResponse) {
-      document.body.classList.remove("connecting");
-      document.body.classList.add("actors-mode");
+/**
+ * Called when the "connect" button is clicked.
+ */
+function submit() {
+  // Show the "connecting" screen
+  document.body.classList.add("connecting");
 
-      let parent = document.getElementById("actors");
-      let focusSet = false;
+  // Save the host/port values
+  let host = document.getElementById("host").value;
+  Services.prefs.setCharPref("devtools.debugger.remote-host", host);
+
+  let port = document.getElementById("port").value;
+  Services.prefs.setIntPref("devtools.debugger.remote-port", port);
 
-      // Add Global Process debugging...
-      let globals = JSON.parse(JSON.stringify(aResponse));
-      delete globals.tabs;
-      delete globals.selected;
-      // ...only if there are appropriate actors (a 'from' property will always
-      // be there).
-      if (Object.keys(globals).length > 1) {
-        let a = document.createElement("a");
-        a.onclick = function() {
-          connect(globals, true);
-        }
+  // Initiate the connection
+  let transport = debuggerSocketConnect(host, port);
+  gClient = new DebuggerClient(transport);
+  let delay = Services.prefs.getIntPref("devtools.debugger.remote-timeout");
+  gConnectionTimeout = setTimeout(handleConnectionTimeout, delay);
+  gClient.connect(onConnectionReady);
+}
 
-        a.title = a.textContent = "Remote process";
-        a.href = "#";
+/**
+ * Connection is ready. List actors and build buttons.
+ */
+function onConnectionReady(aType, aTraits) {
+  clearTimeout(gConnectionTimeout);
+  gClient.listTabs(function(aResponse) {
+    document.body.classList.remove("connecting");
+    document.body.classList.add("actors-mode");
 
-        parent.appendChild(a);
-      }
+    let parent = document.getElementById("actors");
 
-      // Add one entry for each open tab.
-      if (aResponse.tabs.length > 0) {
-        let header = document.createElement("div");
-        header.innerHTML = "Tabs:";
-        parent.appendChild(header);
-      }
-      for (let i = 0; i < aResponse.tabs.length; i++) {
-        let tab = aResponse.tabs[i];
+    // Add Global Process debugging...
+    let globals = JSON.parse(JSON.stringify(aResponse));
+    delete globals.tabs;
+    delete globals.selected;
+    // ...only if there are appropriate actors (a 'from' property will always
+    // be there).
 
-        let a = document.createElement("a");
-        a.onclick = function() {
-          connect(tab);
-        }
+    // Add one entry for each open tab.
+    for (let i = 0; i < aResponse.tabs.length; i++) {
+      buildLink(aResponse.tabs[i], parent, i == aResponse.selected);
+    }
+
+    // Build the Remote Process button
+    if (Object.keys(globals).length > 1) {
+      let a = document.createElement("a");
+      a.onclick = function() {
+        openToolbox(globals, true);
 
-        a.title = a.textContent = tab.title;
-        a.href = "#";
-
-        if (i == aResponse.selected) {
-          a.title += " [*]";
-          a.textContent = a.title;
-        }
+      }
+      a.title = a.textContent = window.l10n.GetStringFromName("remoteProcess");
+      a.className = "remote-process";
+      a.href = "#";
+      parent.appendChild(a);
+    }
+    // Move the selected tab on top
+    let selectedLink = parent.querySelector("a.selected");
+    if (selectedLink) {
+      parent.insertBefore(selectedLink, parent.firstChild);
+    }
 
-        parent.appendChild(a);
+    // Ensure the first link is focused
+    let firstLink = parent.querySelector("a:first-of-type");
+    if (firstLink) {
+      firstLink.focus();
+    }
 
-        if (!focusSet) {
-          a.focus();
-          focusSet = true;
-        }
-      }
-    });
   });
 }
 
-function connect(form, chrome=false) {
+/**
+ * Build one button for an actor.
+ */
+function buildLink(tab, parent, selected) {
+  let a = document.createElement("a");
+  a.onclick = function() {
+    openToolbox(tab);
+  }
+
+  a.textContent = tab.title;
+  a.title = tab.url;
+  if (!a.textContent) {
+    a.textContent = tab.url;
+  }
+  a.href = "#";
+
+  if (selected) {
+    a.classList.add("selected");
+  }
+
+  parent.appendChild(a);
+}
+
+/**
+ * An error occured. Let's show it and return to the first screen.
+ */
+function showError(type) {
+  document.body.className = "error";
+  let activeError = document.querySelector(".error-message.active");
+  if (activeError) {
+    activeError.classList.remove("active");
+  }
+  activeError = document.querySelector(".error-" + type);
+  if (activeError) {
+    activeError.classList.add("active");
+  }
+}
+
+/**
+ * Connection timeout.
+ */
+function handleConnectionTimeout() {
+  showError("timeout");
+}
+
+/**
+ * The user clicked on one of the buttons.
+ * Opens the toolbox.
+ */
+function openToolbox(form, chrome=false) {
   let target = TargetFactory.forRemote(form, gClient, chrome);
   gDevTools.showToolbox(target, "webconsole", Toolbox.HostType.WINDOW);
-  window.close();
 }
--- a/browser/devtools/framework/connect/connect.xhtml
+++ b/browser/devtools/framework/connect/connect.xhtml
@@ -7,39 +7,42 @@
 <!ENTITY % connectionDTD SYSTEM "chrome://browser/locale/devtools/connection-screen.dtd" >
  %connectionDTD;
 ]>
 
 <html xmlns="http://www.w3.org/1999/xhtml"
       xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <head>
     <title>&title;</title>
+    <link rel="stylesheet" href="chrome://browser/skin/devtools/common.css" type="text/css"/>
     <link rel="stylesheet" href="chrome://browser/content/devtools/connect.css" type="text/css"/>
     <script type="application/javascript;version=1.8" src="connect.js"></script>
   </head>
   <body>
-    <p>
-    </p>
+    <h1>&header;</h1>
     <section id="connection-form">
-      <form onsubmit="window.submit()" action="#">
+      <form validate="validate" onsubmit="window.submit()" action="#">
         <label>
           <span>&host;</span>
-          <input id="host" type="text" placeholder="localhost"></input>
+          <input required="required" class="devtools-textinput" id="host" type="text"></input>
         </label>
         <label>
           <span>&port;</span>
-          <input id="port" type="number" placeholder="6000"></input>
+          <input required="required" class="devtools-textinput" id="port" type="number" pattern="\d+"></input>
         </label>
         <label>
-          <input id="submit" type="submit" value="&connect;"></input>
+          <input class="devtools-toolbarbutton" id="submit" type="submit" value="&connect;"></input>
         </label>
       </form>
+      <p class="error-message error-timeout">&errorTimeout;</p>
+      <p class="error-message error-refused">&errorRefused;</p>
+      <p class="error-message error-unexpected">&errorUnexpected;</p>
     </section>
     <section id="actors-list">
       <p>&availability;</p>
       <ul id="actors"></ul>
     </section>
     <section id="connecting">
-      <p>&connecting;</p>
-      <div id="throbber"></div>
+      <p><img src="chrome://browser/skin/tabbrowser/loading.png"></img> &connecting;</p>
     </section>
+    <footer>&help;</footer>
   </body>
 </html>
--- a/browser/devtools/framework/toolbox.xul
+++ b/browser/devtools/framework/toolbox.xul
@@ -1,35 +1,43 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 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/. -->
+<!DOCTYPE window [
+<!ENTITY % toolboxDTD SYSTEM "chrome://browser/locale/devtools/toolbox.dtd" >
+ %toolboxDTD;
+]>
 <?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/devtools/shared/common.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/devtools/framework/toolbox.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/common.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/toolbox.css" type="text/css"?>
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
 <?xul-overlay href="chrome://browser/content/source-editor-overlay.xul"?>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <notificationbox id="toolbox-notificationbox" flex="1">
     <toolbar class="devtools-tabbar">
 #ifdef XP_MACOSX
       <hbox id="toolbox-controls">
-        <toolbarbutton id="toolbox-close" class="devtools-closebutton"></toolbarbutton>
+        <toolbarbutton id="toolbox-close"
+                       class="devtools-closebutton"
+                       tooltiptext="&toolboxCloseButton.tooltip;"/>
         <hbox id="toolbox-dock-buttons"/>
       </hbox>
 #endif
       <radiogroup id="toolbox-tabs" orient="horizontal">
       </radiogroup>
       <hbox id="toolbox-buttons" flex="1" pack="end"/>
 #ifndef XP_MACOSX
       <hbox id="toolbox-controls">
         <hbox id="toolbox-dock-buttons"/>
-        <toolbarbutton id="toolbox-close" class="devtools-closebutton"></toolbarbutton>
+        <toolbarbutton id="toolbox-close"
+                       class="devtools-closebutton"
+                       tooltiptext="&toolboxCloseButton.tooltip;"/>
       </hbox>
 #endif
     </toolbar>
     <deck id="toolbox-deck" flex="1">
     </deck>
   </notificationbox>
 </window>
--- a/browser/devtools/inspector/Breadcrumbs.jsm
+++ b/browser/devtools/inspector/Breadcrumbs.jsm
@@ -78,17 +78,16 @@ HTMLBreadcrumbs.prototype = {
     }.bind(this);
 
     this.container.addEventListener("underflow", this.onscrollboxreflow, false);
     this.container.addEventListener("overflow", this.onscrollboxreflow, false);
 
     this.update = this.update.bind(this);
     this.updateSelectors = this.updateSelectors.bind(this);
     this.selection.on("new-node", this.update);
-    this.selection.on("detached", this.update);
     this.selection.on("pseudoclass", this.updateSelectors);
     this.selection.on("attribute-changed", this.updateSelectors);
     this.update();
   },
 
   /**
    * Build a string that represents the node: tagName#id.class1.class2.
    *
@@ -291,17 +290,16 @@ HTMLBreadcrumbs.prototype = {
   {
     this.nodeHierarchy.forEach(function(crumb) {
       if (LayoutHelpers.isNodeConnected(crumb.node)) {
         DOMUtils.clearPseudoClassLocks(crumb.node);
       }
     });
 
     this.selection.off("new-node", this.update);
-    this.selection.off("detached", this.update);
     this.selection.off("pseudoclass", this.updateSelectors);
     this.selection.off("attribute-changed", this.updateSelectors);
 
     this.container.removeEventListener("underflow", this.onscrollboxreflow, false);
     this.container.removeEventListener("overflow", this.onscrollboxreflow, false);
     this.onscrollboxreflow = null;
 
     this.empty();
--- a/browser/devtools/inspector/Highlighter.jsm
+++ b/browser/devtools/inspector/Highlighter.jsm
@@ -128,17 +128,16 @@ Highlighter.prototype = {
 
     this.transitionDisabler = null;
     this.pageEventsMuter = null;
 
     this.unlock();
 
     this.selection.on("new-node", this.highlight);
     this.selection.on("new-node", this.updateInfobar);
-    this.selection.on("detached", this.highlight);
     this.selection.on("pseudoclass", this.updateInfobar);
     this.selection.on("attribute-changed", this.updateInfobar);
 
     this.onToolSelected = function(event, id) {
       if (id != "inspector") {
         this.chromeWin.clearTimeout(this.pageEventsMuter);
         this.detachMouseListeners();
         this.hide();
@@ -163,17 +162,16 @@ Highlighter.prototype = {
     this.inspectButton.removeEventListener("command", this.unlock);
     this.inspectButton = null;
 
     this.toolbox.off("select", this.onToolSelected);
     this.toolbox = null;
 
     this.selection.off("new-node", this.highlight);
     this.selection.off("new-node", this.updateInfobar);
-    this.selection.off("detached", this.highlight);
     this.selection.off("pseudoclass", this.updateInfobar);
     this.selection.off("attribute-changed", this.updateInfobar);
 
     this.detachMouseListeners();
     this.detachPageListeners();
 
     this.chromeWin.clearTimeout(this.transitionDisabler);
     this.chromeWin.clearTimeout(this.pageEventsMuter);
--- a/browser/devtools/inspector/InspectorPanel.jsm
+++ b/browser/devtools/inspector/InspectorPanel.jsm
@@ -63,16 +63,18 @@ InspectorPanel.prototype = {
     this._resetNodeMenu = this._resetNodeMenu.bind(this);
     this.nodemenu.addEventListener("popupshowing", this._setupNodeMenu, true);
     this.nodemenu.addEventListener("popuphiding", this._resetNodeMenu, true);
 
     // Create an empty selection
     this._selection = new Selection();
     this.onNewSelection = this.onNewSelection.bind(this);
     this.selection.on("new-node", this.onNewSelection);
+    this.onDetached = this.onDetached.bind(this);
+    this.selection.on("detached", this.onDetached);
 
     this.breadcrumbs = new HTMLBreadcrumbs(this);
 
     if (this.tabTarget) {
       this.browser = this.target.tab.linkedBrowser;
       this.scheduleLayoutChange = this.scheduleLayoutChange.bind(this);
       this.browser.addEventListener("resize", this.scheduleLayoutChange, true);
 
@@ -165,29 +167,34 @@ InspectorPanel.prototype = {
 
     let defaultTab = Services.prefs.getCharPref("devtools.inspector.activeSidebar");
 
     this._setDefaultSidebar = function(event, toolId) {
       Services.prefs.setCharPref("devtools.inspector.activeSidebar", toolId);
     }.bind(this);
 
     this.sidebar.on("select", this._setDefaultSidebar);
+    this.toggleHighlighter = this.toggleHighlighter.bind(this);
 
     this.sidebar.addTab("ruleview",
                         "chrome://browser/content/devtools/cssruleview.xul",
                         "ruleview" == defaultTab);
 
     this.sidebar.addTab("computedview",
                         "chrome://browser/content/devtools/csshtmltree.xul",
                         "computedview" == defaultTab);
 
     this.sidebar.addTab("layoutview",
                         "chrome://browser/content/devtools/layoutview/view.xhtml",
                         "layoutview" == defaultTab);
 
+    let ruleViewTab = this.sidebar.getTab("ruleview");
+    ruleViewTab.addEventListener("mouseover", this.toggleHighlighter, false);
+    ruleViewTab.addEventListener("mouseout", this.toggleHighlighter, false);
+
     this.sidebar.show();
   },
 
   /**
    * Reset the inspector on navigate away.
    */
   onNavigatedAway: function InspectorPanel_onNavigatedAway(event, newWindow) {
     this.selection.setNode(null);
@@ -271,16 +278,25 @@ InspectorPanel.prototype = {
   /**
    * When a new node is selected.
    */
   onNewSelection: function InspectorPanel_onNewSelection() {
     this.cancelLayoutChange();
   },
 
   /**
+   * When a node is deleted, select its parent node.
+   */
+  onDetached: function InspectorPanel_onDetached(event, parentNode) {
+    this.cancelLayoutChange();
+    this.breadcrumbs.cutAfter(this.breadcrumbs.indexOf(parentNode));
+    this.selection.setNode(parentNode, "detached");
+  },
+
+  /**
    * Destroy the inspector.
    */
   destroy: function InspectorPanel__destroy() {
     if (this._destroyed) {
       return Promise.resolve(null);
     }
     this._destroyed = true;
 
@@ -305,16 +321,17 @@ InspectorPanel.prototype = {
     this.sidebar.off("select", this._setDefaultSidebar);
     this.sidebar.destroy();
     this.sidebar = null;
 
     this.nodemenu.removeEventListener("popupshowing", this._setupNodeMenu, true);
     this.nodemenu.removeEventListener("popuphiding", this._resetNodeMenu, true);
     this.breadcrumbs.destroy();
     this.selection.off("new-node", this.onNewSelection);
+    this.selection.off("detached", this.onDetached);
     this._destroyMarkup();
     this._selection.destroy();
     this._selection = null;
     this.panelWin.inspector = null;
     this.target = null;
     this.panelDoc = null;
     this.panelWin = null;
     this.breadcrumbs = null;
@@ -443,16 +460,29 @@ InspectorPanel.prototype = {
           node = node.parentNode;
         } while (hierarchical && node.parentNode)
       }
     }
     this.selection.emit("pseudoclass");
   },
 
   /**
+   * Toggle the highlighter when ruleview is hovered.
+   */
+  toggleHighlighter: function InspectorPanel_toggleHighlighter(event)
+  {
+    if (event.type == "mouseover") {
+      this.highlighter.hide();
+    }
+    else if (event.type == "mouseout") {
+      this.highlighter.show();
+    }
+  },
+
+  /**
    * Copy the innerHTML of the selected Node to the clipboard.
    */
   copyInnerHTML: function InspectorPanel_copyInnerHTML()
   {
     if (!this.selection.isNode()) {
       return;
     }
     let toCopy = this.selection.node.innerHTML;
--- a/browser/devtools/inspector/Selection.jsm
+++ b/browser/devtools/inspector/Selection.jsm
@@ -65,31 +65,33 @@ this.Selection = function Selection(node
 }
 
 Selection.prototype = {
   _node: null,
 
   _onMutations: function(mutations) {
     let attributeChange = false;
     let detached = false;
+    let parentNode = null;
     for (let m of mutations) {
       if (!attributeChange && m.type == "attributes") {
         attributeChange = true;
       }
       if (m.type == "childList") {
         if (!detached && !this.isConnected()) {
+          parentNode = m.target;
           detached = true;
         }
       }
     }
 
     if (attributeChange)
       this.emit("attribute-changed");
     if (detached)
-      this.emit("detached");
+      this.emit("detached", parentNode);
   },
 
   _attachEvents: function SN__attachEvents() {
     if (!this.window || !this.isNode() || !this.track) {
       return;
     }
 
     if (this.track.attributes) {
--- a/browser/devtools/inspector/test/Makefile.in
+++ b/browser/devtools/inspector/test/Makefile.in
@@ -30,14 +30,15 @@ include $(topsrcdir)/config/rules.mk
 		browser_inspector_bug_566084_location_changed.js \
 		$(filter disabled-temporarily--bug-816990, browser_inspector_sidebarstate.js) \
 		browser_inspector_pseudoclass_lock.js \
 		browser_inspector_cmd_inspect.js \
 		browser_inspector_cmd_inspect.html \
 		browser_inspector_highlighter_autohide.js \
 		browser_inspector_changes.js \
 		browser_inspector_bug_674871.js \
+		browser_inspector_bug_817558_delete_node.js \
 		head.js \
 		helpers.js \
 		$(NULL)
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
--- a/browser/devtools/inspector/test/browser_inspector_bug_566084_location_changed.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_566084_location_changed.js
@@ -99,17 +99,17 @@ function test() {
     isnot(content.location.href.indexOf("test2"), -1,
           "page navigated to the correct location");
 
     let para = content.document.querySelector("p");
     ok(para, "found the paragraph element, third time");
     is(para.textContent, "test2", "paragraph content is correct");
 
     let root = content.document.documentElement;
-    ok(inspector.selection.node, root, "Selection is the root of the new page.");
+    is(inspector.selection.node, root, "Selection is the root of the new page.");
 
     ok(alertActive1_called, "first notification box has been showed");
     ok(alertActive2_called, "second notification box has been showed");
     testEnd();
   }
 
 
   function testEnd() {
new file mode 100644
--- /dev/null
+++ b/browser/devtools/inspector/test/browser_inspector_bug_817558_delete_node.js
@@ -0,0 +1,50 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test()
+{
+  waitForExplicitFinish();
+  //ignoreAllUncaughtExceptions();
+
+  let node, iframe, inspector;
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onload() {
+    gBrowser.selectedBrowser.removeEventListener("load", onload, true);
+    waitForFocus(setupTest, content);
+  }, true);
+
+  content.location = "http://mochi.test:8888/browser/browser/devtools/inspector/test/browser_inspector_destroyselection.html";
+
+  function setupTest()
+  {
+    iframe = content.document.querySelector("iframe");
+    node = iframe.contentDocument.querySelector("span");
+    openInspector(runTests);
+  }
+
+  function runTests(aInspector)
+  {
+    inspector = aInspector;
+    inspector.selection.setNode(node);
+
+    let parentNode = node.parentNode;
+    parentNode.removeChild(node);
+
+    let tmp = {};
+    Cu.import("resource:///modules/devtools/LayoutHelpers.jsm", tmp);
+    ok(!tmp.LayoutHelpers.isNodeConnected(node), "Node considered as disconnected.");
+    executeSoon(function() {
+      is(inspector.selection.node, parentNode, "parent of selection got selected");
+
+      finishUp();
+    });
+  }
+
+  function finishUp() {
+    node = null;
+    gBrowser.removeCurrentTab();
+    finish();
+  }
+}
+
--- a/browser/devtools/layoutview/view.js
+++ b/browser/devtools/layoutview/view.js
@@ -30,17 +30,16 @@ function LayoutView(aInspector, aWindow)
 
 LayoutView.prototype = {
   init: function LV_init() {
     this.cssLogic = new CssLogic();
 
     this.update = this.update.bind(this);
     this.onNewNode = this.onNewNode.bind(this);
     this.onHighlighterLocked = this.onHighlighterLocked.bind(this);
-    this.inspector.selection.on("detached", this.onNewNode);
     this.inspector.selection.on("new-node", this.onNewNode);
     this.inspector.sidebar.on("layoutview-selected", this.onNewNode);
     if (this.inspector.highlighter) {
       this.inspector.highlighter.on("locked", this.onHighlighterLocked);
     }
 
     // Store for the different dimensions of the node.
     // 'selector' refers to the element that holds the value in view.xhtml;
@@ -96,17 +95,16 @@ LayoutView.prototype = {
   },
 
   /**
    * Destroy the nodes. Remove listeners.
    */
   destroy: function LV_destroy() {
     this.inspector.sidebar.off("layoutview-selected", this.onNewNode);
     this.inspector.selection.off("new-node", this.onNewNode);
-    this.inspector.selection.off("detached", this.onNewNode);
     if (this.browser) {
       this.browser.removeEventListener("MozAfterPaint", this.update, true);
     }
     if (this.inspector.highlighter) {
       this.inspector.highlighter.on("locked", this.onHighlighterLocked);
     }
     this.sizeHeadingLabel = null;
     this.sizeLabel = null;
--- a/browser/devtools/markupview/MarkupView.jsm
+++ b/browser/devtools/markupview/MarkupView.jsm
@@ -7,24 +7,26 @@
 const Cc = Components.classes;
 const Cu = Components.utils;
 const Ci = Components.interfaces;
 
 // Page size for pageup/pagedown
 const PAGE_SIZE = 10;
 
 const PREVIEW_AREA = 700;
+const DEFAULT_MAX_CHILDREN = 100;
 
 this.EXPORTED_SYMBOLS = ["MarkupView"];
 
 Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
 Cu.import("resource:///modules/devtools/CssRuleView.jsm");
 Cu.import("resource:///modules/devtools/Templater.jsm");
 Cu.import("resource:///modules/devtools/Undo.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 /**
  * Vocabulary for the purposes of this file:
  *
  * MarkupContainer - the structure that holds an editor and its
  *  immediate children in the markup panel.
  * Node - A content node.
  * object.elt - A UI element in the markup panel.
@@ -41,16 +43,22 @@ Cu.import("resource://gre/modules/Servic
  */
 this.MarkupView = function MarkupView(aInspector, aFrame, aControllerWindow)
 {
   this._inspector = aInspector;
   this._frame = aFrame;
   this.doc = this._frame.contentDocument;
   this._elt = this.doc.querySelector("#root");
 
+  try {
+    this.maxChildren = Services.prefs.getIntPref("devtools.markup.pagesize");
+  } catch(ex) {
+    this.maxChildren = DEFAULT_MAX_CHILDREN;
+  }
+
   this.undo = new UndoStack();
   this.undo.installController(aControllerWindow);
 
   this._containers = new WeakMap();
 
   this._observer = new this.doc.defaultView.MutationObserver(this._mutationObserver.bind(this));
 
   this._boundOnNewSelection = this._onNewSelection.bind(this);
@@ -64,17 +72,17 @@ this.MarkupView = function MarkupView(aI
   this._frame.addEventListener("focus", this._boundFocus, false);
 
   this._initPreview();
 }
 
 MarkupView.prototype = {
   _selectedContainer: null,
 
-  template: function MT_template(aName, aDest, aOptions)
+  template: function MT_template(aName, aDest, aOptions={stack: "markup-view.xhtml"})
   {
     let node = this.doc.getElementById("template-" + aName).cloneNode(true);
     node.removeAttribute("id");
     template(node, aDest, aOptions);
     return node;
   },
 
   /**
@@ -283,32 +291,34 @@ MarkupView.prototype = {
       attributes: true,
       childList: true,
       characterData: true,
     });
 
     let walker = documentWalker(aNode);
     let parent = walker.parentNode();
     if (parent) {
-      // Make sure parents of this node are imported too.
       var container = new MarkupContainer(this, aNode);
     } else {
       var container = new RootContainer(this, aNode);
       this._elt.appendChild(container.elt);
       this._rootNode = aNode;
       aNode.addEventListener("load", function MP_watch_contentLoaded(aEvent) {
         // Fake a childList mutation here.
         this._mutationObserver([{target: aEvent.target, type: "childList"}]);
       }.bind(this), true);
-
     }
 
     this._containers.set(aNode, container);
+    // FIXME: set an expando to prevent the the wrapper from disappearing
+    // See bug 819131 for details.
+    aNode.__preserveHack = true;
     container.expanded = aExpand;
 
+    container.childrenDirty = true;
     this._updateChildren(container);
 
     if (parent) {
       this.importNode(parent, true);
     }
     return container;
   },
 
@@ -322,32 +332,35 @@ MarkupView.prototype = {
       if (!container) {
         // Container might not exist if this came from a load event for an iframe
         // we're not viewing.
         continue;
       }
       if (mutation.type === "attributes" || mutation.type === "characterData") {
         container.update();
       } else if (mutation.type === "childList") {
+        container.childrenDirty = true;
         this._updateChildren(container);
       }
     }
     this._inspector.emit("markupmutation");
   },
 
   /**
    * Make sure the given node's parents are expanded and the
    * node is scrolled on to screen.
    */
   showNode: function MT_showNode(aNode, centered)
   {
-    this.importNode(aNode);
+    let container = this.importNode(aNode);
+    this._updateChildren(container);
     let walker = documentWalker(aNode);
     let parent;
     while (parent = walker.parentNode()) {
+      this._updateChildren(this.getContainer(parent));
       this.expandNode(parent);
     }
     LayoutHelpers.scrollIntoViewIfNeeded(this._containers.get(aNode).editor.elt, centered);
   },
 
   /**
    * Expand the container's children.
    */
@@ -416,20 +429,43 @@ MarkupView.prototype = {
     if (this._selectedContainer) {
       this._selectedContainer.selected = false;
     }
     this._selectedContainer = container;
     if (aNode) {
       this._selectedContainer.selected = true;
     }
 
+    this._ensureSelectionVisible();
+
     return true;
   },
 
   /**
+   * Make sure that every ancestor of the selection are updated
+   * and included in the list of visible children.
+   */
+  _ensureSelectionVisible: function MT_ensureSelectionVisible()
+  {
+    let node = this._selectedContainer.node;
+    let walker = documentWalker(node);
+    while (node) {
+      let container = this._containers.get(node);
+      let parent = walker.parentNode();
+      if (!container.elt.parentNode) {
+        let parentContainer = this._containers.get(parent);
+        parentContainer.childrenDirty = true;
+        this._updateChildren(parentContainer, node);
+      }
+
+      node = parent;
+    }
+  },
+
+  /**
    * Unmark selected node (no node selected).
    */
   unmarkSelectedNode: function MT_unmarkSelectedNode()
   {
     if (this._selectedContainer) {
       this._selectedContainer.selected = false;
       this._selectedContainer = null;
     }
@@ -443,39 +479,149 @@ MarkupView.prototype = {
     if (aNode === this._inspector.selection) {
       this._inspector.change("markupview");
     }
   },
 
   /**
    * Make sure all children of the given container's node are
    * imported and attached to the container in the right order.
+   * @param aCentered If provided, this child will be included
+   *        in the visible subset, and will be roughly centered
+   *        in that list.
    */
-  _updateChildren: function MT__updateChildren(aContainer)
+  _updateChildren: function MT__updateChildren(aContainer, aCentered)
   {
+    if (!aContainer.childrenDirty) {
+      return false;
+    }
+
     // Get a tree walker pointing at the first child of the node.
     let treeWalker = documentWalker(aContainer.node);
     let child = treeWalker.firstChild();
     aContainer.hasChildren = !!child;
-    if (aContainer.expanded) {
-      let lastContainer = null;
-      while (child) {
-        let container = this.importNode(child, false);
+
+    if (!aContainer.expanded) {
+      return;
+    }
+
+    aContainer.childrenDirty = false;
+
+    let children = this._getVisibleChildren(aContainer, aCentered);
+    let fragment = this.doc.createDocumentFragment();
+
+    for (child of children.children) {
+      let container = this.importNode(child, false);
+      fragment.appendChild(container.elt);
+    }
+
+    while (aContainer.children.firstChild) {
+      aContainer.children.removeChild(aContainer.children.firstChild);
+    }
 
-        // Make sure children are in the right order.
-        let before = lastContainer ? lastContainer.nextSibling : aContainer.children.firstChild;
-        aContainer.children.insertBefore(container.elt, before);
-        lastContainer = container.elt;
-        child = treeWalker.nextSibling();
+    if (!(children.hasFirst && children.hasLast)) {
+      let data = {
+        showing: this.strings.GetStringFromName("markupView.more.showing"),
+        showAll: this.strings.formatStringFromName(
+                  "markupView.more.showAll",
+                  [aContainer.node.children.length.toString()], 1),
+        allButtonClick: function() {
+          aContainer.maxChildren = -1;
+          aContainer.childrenDirty = true;
+          this._updateChildren(aContainer);
+        }.bind(this)
+      };
+
+      if (!children.hasFirst) {
+        let span = this.template("more-nodes", data);
+        fragment.insertBefore(span, fragment.firstChild);
       }
-
-      while (aContainer.children.lastChild != lastContainer) {
-        aContainer.children.removeChild(aContainer.children.lastChild);
+      if (!children.hasLast) {
+        let span = this.template("more-nodes", data);
+        fragment.appendChild(span);
       }
     }
+
+    aContainer.children.appendChild(fragment);
+
+    return true;
+  },
+
+  /**
+   * Return a list of the children to display for this container.
+   */
+  _getVisibleChildren: function MV__getVisibleChildren(aContainer, aCentered)
+  {
+    let maxChildren = aContainer.maxChildren || this.maxChildren;
+    if (maxChildren == -1) {
+      maxChildren = Number.MAX_VALUE;
+    }
+    let firstChild = documentWalker(aContainer.node).firstChild();
+    let lastChild = documentWalker(aContainer.node).lastChild();
+
+    if (!firstChild) {
+      // No children, we're done.
+      return { hasFirst: true, hasLast: true, children: [] };
+    }
+
+    // By default try to put the selected child in the middle of the list.
+    let start = aCentered || firstChild;
+
+    // Start by reading backward from the starting point....
+    let nodes = [];
+    let backwardWalker = documentWalker(start);
+    if (backwardWalker.previousSibling()) {
+      let backwardCount = Math.floor(maxChildren / 2);
+      let backwardNodes = this._readBackward(backwardWalker, backwardCount);
+      nodes = backwardNodes;
+    }
+
+    // Then read forward by any slack left in the max children...
+    let forwardWalker = documentWalker(start);
+    let forwardCount = maxChildren - nodes.length;
+    nodes = nodes.concat(this._readForward(forwardWalker, forwardCount));
+
+    // If there's any room left, it means we've run all the way to the end.
+    // In that case, there might still be more items at the front.
+    let remaining = maxChildren - nodes.length;
+    if (remaining > 0 && nodes[0] != firstChild) {
+      let firstNodes = this._readBackward(backwardWalker, remaining);
+
+      // Then put it all back together.
+      nodes = firstNodes.concat(nodes);
+    }
+
+    return {
+      hasFirst: nodes[0] == firstChild,
+      hasLast: nodes[nodes.length - 1] == lastChild,
+      children: nodes
+    };
+  },
+
+  _readForward: function MV__readForward(aWalker, aCount)
+  {
+    let ret = [];
+    let node = aWalker.currentNode;
+    do {
+      ret.push(node);
+      node = aWalker.nextSibling();
+    } while (node && --aCount);
+    return ret;
+  },
+
+  _readBackward: function MV__readBackward(aWalker, aCount)
+  {
+    let ret = [];
+    let node = aWalker.currentNode;
+    do {
+      ret.push(node);
+      node = aWalker.previousSibling();
+    } while(node && --aCount);
+    ret.reverse();
+    return ret;
   },
 
   /**
    * Tear down the markup panel.
    */
   destroy: function MT_destroy()
   {
     this.undo.destroy();
@@ -613,19 +759,17 @@ function MarkupContainer(aMarkupView, aN
     this.editor = new GenericEditor(this.markup, aNode);
   }
 
   // The template will fill the following properties
   this.elt = null;
   this.expander = null;
   this.codeBox = null;
   this.children = null;
-  let options = { stack: "markup-view.xhtml" };
-  this.markup.template("container", this, options);
-
+  this.markup.template("container", this);
   this.elt.container = this;
 
   this.expander.addEventListener("click", function() {
     this.markup.navigate(this);
 
     if (this.expanded) {
       this.markup.collapseNode(this.node);
     } else {
@@ -729,17 +873,17 @@ MarkupContainer.prototype = {
    * Try to put keyboard focus on the current editor.
    */
   focus: function MC_focus()
   {
     let focusable = this.editor.elt.querySelector("[tabindex]");
     if (focusable) {
       focusable.focus();
     }
-  }
+  },
 }
 
 /**
  * Dummy container node used for the root document element.
  */
 function RootContainer(aMarkupView, aNode)
 {
   this.doc = aMarkupView.doc;
@@ -836,23 +980,22 @@ function ElementEditor(aContainer, aNode
   this.attrs = [];
 
   // The templates will fill the following properties
   this.elt = null;
   this.tag = null;
   this.attrList = null;
   this.newAttr = null;
   this.closeElt = null;
-  let options = { stack: "markup-view.xhtml" };
 
   // Create the main editor
-  this.template("element", this, options);
+  this.template("element", this);
 
   // Create the closing tag
-  this.template("elementClose", this, options);
+  this.template("elementClose", this);
 
   // Make the tag name editable (unless this is a document element)
   if (aNode != aNode.ownerDocument.documentElement) {
     this.tag.setAttribute("tabindex", "0");
     _editableField({
       element: this.tag,
       trigger: "dblclick",
       stopOnReturn: true,
@@ -922,18 +1065,17 @@ ElementEditor.prototype = {
       var attr = this.attrs[aAttr.name];
       var name = attr.querySelector(".attrname");
       var val = attr.querySelector(".attrvalue");
     } else {
       // Create the template editor, which will save some variables here.
       let data = {
         attrName: aAttr.name,
       };
-      let options = { stack: "markup-view.xhtml" };
-      this.template("attribute", data, options);
+      this.template("attribute", data);
       var {attr, inner, name, val} = data;
 
       // Figure out where we should place the attribute.
       let before = aBefore || null;
       if (aAttr.name == "id") {
         before = this.attrList.firstChild;
       } else if (aAttr.name == "class") {
         let idNode = this.attrs["id"];
@@ -1255,8 +1397,13 @@ function whitespaceTextFilter(aNode)
 {
     if (aNode.nodeType == Ci.nsIDOMNode.TEXT_NODE &&
         !/[^\s]/.exec(aNode.nodeValue)) {
       return Ci.nsIDOMNodeFilter.FILTER_SKIP;
     } else {
       return Ci.nsIDOMNodeFilter.FILTER_ACCEPT;
     }
 }
+
+XPCOMUtils.defineLazyGetter(MarkupView.prototype, "strings", function () {
+  return Services.strings.createBundle(
+          "chrome://browser/locale/devtools/inspector.properties");
+});
--- a/browser/devtools/markupview/markup-view.xhtml
+++ b/browser/devtools/markupview/markup-view.xhtml
@@ -11,16 +11,18 @@
   <link rel="stylesheet" href="chrome://browser/skin/devtools/markup-view.css" type="text/css"/>
   <link rel="stylesheet" href="chrome://browser/skin/devtools/common.css" type="text/css"/>
 </head>
 <body class="devtools-theme-background devtools-monospace" role="application">
   <div id="root"></div>
   <div id="templates" style="display:none">
     <ul>
       <li id="template-container" save="${elt}" class="container"><span save="${expander}" class="expander"></span><span save="${codeBox}" class="codebox"><ul save="${children}" class="children"></ul></span></li>
+
+      <li id="template-more-nodes" class="more-nodes devtools-class-comment" save="${elt}"><span>${showing}</span> <button href="#" onclick="${allButtonClick}">${showAll}</button></li>
     </ul>
 
     <span id="template-element" save="${elt}" class="editor"><span>&lt;</span><span save="${tag}" class="tagname devtools-theme-tagname"></span><span save="${attrList}"></span><span save="${newAttr}" class="newattr" tabindex="0"></span>&gt;</span>
 
     <span id="template-attribute" save="${attr}" data-attr="${attrName}" class="attreditor" style="display:none"> <span class="editable" save="${inner}" tabindex="0"><span save="${name}" class="attrname devtools-theme-attrname"></span>=&quot;<span save="${val}" class="attrvalue devtools-theme-attrvalue"></span>&quot;</span></span>
 
     <span id="template-text" save="${elt}" class="editor text">
       <pre save="${value}" style="display:inline-block;" tabindex="0"></pre>
--- a/browser/devtools/markupview/test/Makefile.in
+++ b/browser/devtools/markupview/test/Makefile.in
@@ -12,14 +12,16 @@ include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _BROWSER_FILES = \
 		browser_inspector_markup_navigation.html \
 		browser_inspector_markup_navigation.js \
 		browser_inspector_markup_mutation.html \
 		browser_inspector_markup_mutation.js \
 		browser_inspector_markup_edit.html \
-		browser_inspector_markup_edit.js \
+    browser_inspector_markup_edit.js \
+    browser_inspector_markup_subset.html \
+    browser_inspector_markup_subset.js \
 		head.js \
 		$(NULL)
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/markupview/test/browser_inspector_markup_subset.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+
+<html class="html">
+  <body class="body">
+    <div id="a"></div>
+    <div id="b"></div>
+    <div id="c"></div>
+    <div id="d"></div>
+    <div id="e"></div>
+    <div id="f"></div>
+    <div id="g"></div>
+    <div id="h"></div>
+    <div id="i"></div>
+    <div id="j"></div>
+    <div id="k"></div>
+    <div id="l"></div>
+    <div id="m"></div>
+    <div id="n"></div>
+    <div id="o"></div>
+    <div id="p"></div>
+    <div id="q"></div>
+    <div id="r"></div>
+    <div id="s"></div>
+    <div id="t"></div>
+    <div id="u"></div>
+    <div id="v"></div>
+    <div id="w"></div>
+    <div id="x"></div>
+    <div id="y"></div>
+    <div id="z"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/markupview/test/browser_inspector_markup_subset.js
@@ -0,0 +1,146 @@
+/* Any copyright", " is dedicated to the Public Domain.
+http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that the markup view loads only as many nodes as specified
+ * by the devtools.markup.pagesize preference.
+ */
+
+registerCleanupFunction(function() {
+  Services.prefs.clearUserPref("devtools.markup.pagesize");
+});
+Services.prefs.setIntPref("devtools.markup.pagesize", 5);
+
+
+function test() {
+  waitForExplicitFinish();
+
+  // Will hold the doc we're viewing
+  let doc;
+
+  let inspector;
+
+  // Holds the MarkupTool object we're testing.
+  let markup;
+
+  function assertChildren(expected)
+  {
+    let container = markup.getContainer(doc.querySelector("body"));
+    let found = [];
+    for (let child of container.children.children) {
+      if (child.classList.contains("more-nodes")) {
+        found += "*more*";
+      } else {
+        found += child.container.node.getAttribute("id");
+      }
+    }
+    is(expected, found, "Got the expected children.");
+  }
+
+  function forceReload()
+  {
+    let container = markup.getContainer(doc.querySelector("body"));
+    container.childrenDirty = true;
+  }
+
+  let selections = [
+    {
+      desc: "Select the first item",
+      selector: "#a",
+      before: function() {
+      },
+      after: function() {
+        assertChildren("abcde*more*");
+      }
+    },
+    {
+      desc: "Select the last item",
+      selector: "#z",
+      before: function() {},
+      after: function() {
+        assertChildren("*more*vwxyz");
+      }
+    },
+    {
+      desc: "Select an already-visible item",
+      selector: "#v",
+      before: function() {},
+      after: function() {
+        // Because "v" was already visible, we shouldn't have loaded
+        // a different page.
+        assertChildren("*more*vwxyz");
+      },
+    },
+    {
+      desc: "Verify childrenDirty reloads the page",
+      selector: "#w",
+      before: function() {
+        forceReload();
+      },
+      after: function() {
+        // But now that we don't already have a loaded page, selecting
+        // w should center around w.
+        assertChildren("*more*uvwxy*more*");
+      },
+    },
+  ];
+
+  // Create the helper tab for parsing...
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onload() {
+    gBrowser.selectedBrowser.removeEventListener("load", onload, true);
+    doc = content.document;
+    waitForFocus(setupTest, content);
+  }, true);
+  content.location = "http://mochi.test:8888/browser/browser/devtools/markupview/test/browser_inspector_markup_subset.html";
+
+  function setupTest() {
+    var target = TargetFactory.forTab(gBrowser.selectedTab);
+    let toolbox = gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
+      toolbox.once("inspector-selected", function SE_selected(id, aInspector) {
+        inspector = aInspector;
+        markup = inspector.markup;
+        runNextSelection();
+      });
+    });
+  }
+
+  function runTests() {
+    inspector.selection.once("new-node", startTests);
+    executeSoon(function() {
+      inspector.selection.setNode(doc.body);
+    });
+  }
+
+  function runNextSelection() {
+    let selection = selections.shift();
+    if (!selection) {
+      clickMore();
+      return;
+    }
+
+    info(selection.desc);
+    selection.before();
+    inspector.selection.once("new-node", function() {
+      selection.after();
+      runNextSelection();
+    });
+    inspector.selection.setNode(doc.querySelector(selection.selector));
+  }
+
+  function clickMore() {
+    info("Check that clicking more loads the whole thing.");
+    // Make sure that clicking the "more" button loads all the nodes.
+    let container = markup.getContainer(doc.querySelector("body"));
+    let button = container.elt.querySelector("button");
+    button.click();
+    assertChildren("abcdefghijklmnopqrstuvwxyz");
+    finishUp();
+  }
+
+  function finishUp() {
+    doc = inspector = null;
+    gBrowser.removeCurrentTab();
+    finish();
+  }
+}
--- a/browser/devtools/responsivedesign/responsivedesign.jsm
+++ b/browser/devtools/responsivedesign/responsivedesign.jsm
@@ -153,19 +153,16 @@ function ResponsiveUI(aWindow, aTab)
   // Events
   this.tab.addEventListener("TabClose", this);
   this.tabContainer.addEventListener("TabSelect", this);
   this.mainWindow.document.addEventListener("keypress", this.bound_onKeypress, false);
 
   this.buildUI();
   this.checkMenus();
 
-  let target = TargetFactory.forTab(this.tab);
-  this.toolboxWasOpen = !!gDevTools.getToolbox(target);
-
   try {
     if (Services.prefs.getBoolPref("devtools.responsiveUI.rotate")) {
       this.rotate();
     }
   } catch(e) {}
 
   if (this._floatingScrollbars)
     switchToFloatingScrollbars(this.tab);
@@ -234,27 +231,19 @@ ResponsiveUI.prototype = {
    * Handle keypressed.
    *
    * @param aEvent
    */
   onKeypress: function RUI_onKeypress(aEvent) {
     if (aEvent.keyCode == this.mainWindow.KeyEvent.DOM_VK_ESCAPE &&
         this.mainWindow.gBrowser.selectedBrowser == this.browser) {
 
-      // If the toolbox wasn't open at first but is open now,
-      // we don't want to close the Responsive Mode on Escape.
-      // We let the toolbox close first.
-
-      let target = TargetFactory.forTab(this.tab);
-      let isToolboxOpen =  !!gDevTools.getToolbox(target);
-      if (this.toolboxWasOpen || !isToolboxOpen) {
-        aEvent.preventDefault();
-        aEvent.stopPropagation();
-        this.close();
-      }
+      aEvent.preventDefault();
+      aEvent.stopPropagation();
+      this.close();
     }
   },
 
   /**
    * Handle events
    */
   handleEvent: function (aEvent) {
     switch (aEvent.type) {
--- a/browser/devtools/scratchpad/scratchpad-manager.jsm
+++ b/browser/devtools/scratchpad/scratchpad-manager.jsm
@@ -64,21 +64,39 @@ this.ScratchpadManager = {
   },
 
   /**
    * Iterate through open scratchpad windows and save their states.
    */
   saveOpenWindows: function SPM_saveOpenWindows() {
     this._scratchpads = [];
 
+    function clone(src) {
+      let dest = {};
+
+      for (let key in src) {
+        if (src.hasOwnProperty(key)) {
+          dest[key] = src[key];
+        }
+      }
+
+      return dest;
+    }
+
+    // We need to clone objects we get from Scratchpad instances
+    // because such (cross-window) objects have a property 'parent'
+    // that holds on to a ChromeWindow instance. This means that
+    // such objects are not primitive-values-only anymore so they
+    // can leak.
+
     let enumerator = Services.wm.getEnumerator("devtools:scratchpad");
     while (enumerator.hasMoreElements()) {
       let win = enumerator.getNext();
       if (!win.closed && win.Scratchpad.initialized) {
-        this._scratchpads.push(win.Scratchpad.getState());
+        this._scratchpads.push(clone(win.Scratchpad.getState()));
       }
     }
   },
 
   /**
    * Open a new scratchpad window with an optional initial state.
    *
    * @param object aState
@@ -101,16 +119,17 @@ this.ScratchpadManager = {
         return;
       }
 
       params.SetString(1, JSON.stringify(aState));
     }
 
     let win = Services.ww.openWindow(null, SCRATCHPAD_WINDOW_URL, "_blank",
                                      SCRATCHPAD_WINDOW_FEATURES, params);
+
     // Only add the shutdown observer if we've opened a scratchpad window.
     ShutdownObserver.init();
 
     return win;
   }
 };
 
 
@@ -123,24 +142,25 @@ var ShutdownObserver = {
 
   init: function SDO_init()
   {
     if (this._initialized) {
       return;
     }
 
     Services.obs.addObserver(this, "quit-application-granted", false);
+
     this._initialized = true;
   },
 
   observe: function SDO_observe(aMessage, aTopic, aData)
   {
     if (aTopic == "quit-application-granted") {
       ScratchpadManager.saveOpenWindows();
       this.uninit();
     }
   },
 
   uninit: function SDO_uninit()
   {
     Services.obs.removeObserver(this, "quit-application-granted");
   }
-};
+};
\ No newline at end of file
--- a/browser/devtools/styleinspector/CssHtmlTree.jsm
+++ b/browser/devtools/styleinspector/CssHtmlTree.jsm
@@ -128,23 +128,25 @@ this.CssHtmlTree = function CssHtmlTree(
   this.cssLogic = aStyleInspector.cssLogic;
   this.propertyViews = [];
 
   let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
     getService(Ci.nsIXULChromeRegistry);
   this.getRTLAttr = chromeReg.isLocaleRTL("global") ? "rtl" : "ltr";
 
   // Create bound methods.
+  this.siFocusWindow = this.focusWindow.bind(this);
   this.siBoundMenuUpdate = this.computedViewMenuUpdate.bind(this);
   this.siBoundCopy = this.computedViewCopy.bind(this);
   this.siBoundCopyDeclaration = this.computedViewCopyDeclaration.bind(this);
   this.siBoundCopyProperty = this.computedViewCopyProperty.bind(this);
   this.siBoundCopyPropertyValue = this.computedViewCopyPropertyValue.bind(this);
 
   this.styleDocument.addEventListener("copy", this.siBoundCopy);
+  this.styleDocument.addEventListener("mousedown", this.siFocusWindow);
 
   // Nodes used in templating
   this.root = this.styleDocument.getElementById("root");
   this.templateRoot = this.styleDocument.getElementById("templateRoot");
   this.propertyContainer = this.styleDocument.getElementById("propertyContainer");
   this.panel = aStyleInspector.panel;
 
   // No results text.
@@ -553,16 +555,27 @@ CssHtmlTree.prototype = {
     menuitem.disabled = disablePropertyItems;
     menuitem = outerDoc.querySelector("#computed-view-copy-property");
     menuitem.disabled = disablePropertyItems;
     menuitem = outerDoc.querySelector("#computed-view-copy-property-value");
     menuitem.disabled = disablePropertyItems;
   },
 
   /**
+   * Focus the window on mousedown.
+   *
+   * @param aEvent The event object
+   */
+  focusWindow: function si_focusWindow(aEvent)
+  {
+    let win = this.styleDocument.defaultView;
+    win.focus();
+  },
+
+  /**
    * Copy selected text.
    *
    * @param aEvent The event object
    */
   computedViewCopy: function si_computedViewCopy(aEvent)
   {
     let win = this.styleDocument.defaultView;
     let text = win.getSelection().toString();
@@ -699,16 +712,17 @@ CssHtmlTree.prototype = {
       menuitem.removeEventListener("command", this.siBoundCopyPropertyValue);
 
       menu.removeEventListener("popupshowing", this.siBoundMenuUpdate);
       menu.parentNode.removeChild(menu);
     }
 
     // Remove bound listeners
     this.styleDocument.removeEventListener("copy", this.siBoundCopy);
+    this.styleDocument.removeEventListener("mousedown", this.siFocusWindow);
 
     // Nodes used in templating
     delete this.root;
     delete this.propertyContainer;
     delete this.panel;
 
     // The document in which we display the results (csshtmltree.xul).
     delete this.styleDocument;
--- a/browser/devtools/styleinspector/CssRuleView.jsm
+++ b/browser/devtools/styleinspector/CssRuleView.jsm
@@ -1397,16 +1397,18 @@ RuleEditor.prototype = {
     code.addEventListener("click", function() {
       let selection = this.doc.defaultView.getSelection();
       if (selection.isCollapsed) {
         this.newProperty();
       }
     }.bind(this), false);
 
     this.element.addEventListener("mousedown", function() {
+      this.doc.defaultView.focus();
+
       let editorNodes =
         this.doc.querySelectorAll(".styleinspector-propertyeditor");
 
       if (editorNodes) {
         for (let node of editorNodes) {
           if (node.inplaceEditor) {
             node.inplaceEditor._clear();
           }
--- a/browser/devtools/tilt/TiltVisualizer.jsm
+++ b/browser/devtools/tilt/TiltVisualizer.jsm
@@ -176,32 +176,30 @@ TiltVisualizer.prototype = {
 
     let target = TargetFactory.forTab(aTab);
     let toolbox = gDevTools.getToolbox(target);
     if (toolbox) {
       let panel = toolbox.getPanel("inspector");
       if (panel) {
         this.inspector = panel;
         this.inspector.selection.on("new-node", this.onNewNodeFromInspector);
-        this.inspector.selection.on("detached", this.onNewNodeFromInspector);
         this.onNewNodeFromInspector();
       }
     }
   },
 
   /**
    * Unregister inspector event listeners.
    */
   unbindInspector: function TV_unbindInspector()
   {
     this._browserTab = null;
 
     if (this.inspector) {
       this.inspector.selection.off("new-node", this.onNewNodeFromInspector);
-      this.inspector.selection.off("detached", this.onNewNodeFromInspector);
       this.inspector = null;
     }
 
     gDevTools.off("inspector-ready", this.onInspectorReady);
     gDevTools.off("toolbox-destroyed", this.onToolboxDestroyed);
 
     Services.obs.removeObserver(this.onNewNodeFromTilt,
                                 this.presenter.NOTIFICATIONS.HIGHLIGHTING);
@@ -212,31 +210,29 @@ TiltVisualizer.prototype = {
   /**
    * When a new inspector is started.
    */
   onInspectorReady: function TV_onInspectorReady(event, toolbox, panel)
   {
     if (toolbox.target.tab === this._browserTab) {
       this.inspector = panel;
       this.inspector.selection.on("new-node", this.onNewNodeFromInspector);
-      this.inspector.selection.on("detached", this.onNewNodeFromInspector);
       this.onNewNodeFromTilt();
     }
   },
 
   /**
    * When the toolbox, therefor the inspector, is closed.
    */
   onToolboxDestroyed: function TV_onToolboxDestroyed(event, tab)
   {
     if (tab === this._browserTab &&
         this.inspector) {
       if (this.inspector.selection) {
         this.inspector.selection.off("new-node", this.onNewNodeFromInspector);
-        this.inspector.selection.off("detached", this.onNewNodeFromInspector);
       }
       this.inspector = null;
     }
   },
 
   /**
    * When a new node is selected in the inspector.
    */
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -618,8 +618,13 @@ just addresses the organization to follo
 <!ENTITY social.toggleNotifications.accesskey "n">
 
 <!ENTITY social.activated.undobutton.label "Undo">
 <!ENTITY social.activated.undobutton.accesskey "U">
 
 <!ENTITY social.chatBar.commandkey "c">
 <!ENTITY social.chatBar.label "Focus chats">
 <!ENTITY social.chatBar.accesskey "c">
+
+<!ENTITY getUserMedia.selectCamera.label "Camera to share:">
+<!ENTITY getUserMedia.selectCamera.accesskey "C">
+<!ENTITY getUserMedia.selectMicrophone.label "Microphone to share:">
+<!ENTITY getUserMedia.selectMicrophone.accesskey "M">
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -437,22 +437,20 @@ identity.next.label = Next
 identity.next.accessKey = n
 # LOCALIZATION NOTE: shown in the popup notification when a user successfully logs into a website
 # LOCALIZATION NOTE (identity.loggedIn.description): %S is the user's identity (e.g. user@example.com)
 identity.loggedIn.description = Signed in as: %S
 identity.loggedIn.signOut.label = Sign Out
 identity.loggedIn.signOut.accessKey = O
 
 # LOCALIZATION NOTE (getUserMedia.shareCamera.message, getUserMedia.shareMicrophone.message, getUserMedia.shareCameraAndMicrophone.message): %S is the website origin (e.g. www.mozilla.org)
-# LOCALIZATION NOTE (getUserMedia.shareMicrophone.message, getUserMedia.shareSpecificMicrophone.label): %S is the website origin (e.g. www.mozilla.org)
+# LOCALIZATION NOTE (getUserMedia.shareMicrophone.message): %S is the website origin (e.g. www.mozilla.org)
+# LOCALIZATION NOTE (getUserMedia.shareSelectedDevices.label):
+# Semi-colon list of plural forms. See:
+# http://developer.mozilla.org/en/docs/Localization_and_Plurals
+# The number of devices can be either one or two.
 getUserMedia.shareCamera.message = Would you like to share your camera with %S?
-getUserMedia.shareCamera.label = Share Camera
-getUserMedia.shareCamera.accesskey = S
-getUserMedia.shareSpecificCamera.label = Share Camera: %S
 getUserMedia.shareMicrophone.message = Would you like to share your microphone with %S?
-getUserMedia.shareMicrophone.label = Share Microphone
-getUserMedia.shareMicrophone.accesskey = S
-getUserMedia.shareSpecificMicrophone.label = Share Microphone: %S
 getUserMedia.shareCameraAndMicrophone.message = Would you like to share your camera and microphone with %S?
-getUserMedia.shareCameraAndMicrophone.label = Share Camera and Microphone
-getUserMedia.shareCameraAndMicrophone.accesskey = S
+getUserMedia.shareSelectedDevices.label = Share Selected Device;Share Selected Devices
+getUserMedia.shareSelectedDevices.accesskey = S
 getUserMedia.denyRequest.label = Don't Share
 getUserMedia.denyRequest.accesskey = D
--- a/browser/locales/en-US/chrome/browser/devtools/connection-screen.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/connection-screen.dtd
@@ -1,15 +1,22 @@
 <!-- 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/. -->
 
-<!-- LOCALIZATION NOTE : FILE This file contains the Remove Connection strings.
-  - The Remote Connection window can be start by running the command:
-  - `devtools connect`
+<!-- LOCALIZATION NOTE : FILE This file contains the Remote Connection strings.
+  - The Remote Connection window can reached from the "connect…" menuitem
+  - in the Web Developer menu.
   - -->
 
 <!ENTITY title      "Connect">
+<!ENTITY header     "Connect to remote device">
 <!ENTITY host       "Host:">
 <!ENTITY port       "Port:">
 <!ENTITY connect    "Connect">
 <!ENTITY connecting "Connecting…">
 <!ENTITY availability "Available remote objects:">
+<!ENTITY remoteProcess "remote process">
+<!ENTITY connectionError "Error:">
+<!ENTITY errorTimeout "Error: connection timeout.">
+<!ENTITY errorRefused "Error: connection refused.">
+<!ENTITY errorUnexpected "Unexpected error.">
+<!ENTITY help "Firefox Developer Tools can debug remote devices (Firefox for Android and Firefox OS for example). Make sure that you have turned on the 'Debugger Server' option on the remote device. See <a target='_' href='https://developer.mozilla.org/en-US/docs/Tools/Debugger#Remote_Debugging'>documentation</a>.">
new file mode 100644
--- /dev/null
+++ b/browser/locales/en-US/chrome/browser/devtools/connection-screen.properties
@@ -0,0 +1,9 @@
+# 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/.
+
+# LOCALIZATION NOTE : FILE This file contains the Remote Connection strings.
+# The Remote Connection window can reached from the "connect…" menuitem
+# in the Web Developer menu.
+
+remoteProcess=Remote Process
--- a/browser/locales/en-US/chrome/browser/devtools/debugger.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/debugger.properties
@@ -181,16 +181,21 @@ watchExpressionsScopeLabel=Watch express
 # the global scope.
 globalScopeLabel=Global
 
 # LOCALIZATION NOTE (ToolboxDebugger.label):
 # This string is displayed in the title of the tab when the debugger is
 # displayed inside the developer tools window and in the Developer Tools Menu.
 ToolboxDebugger.label=Debugger
 
+# LOCALIZATION NOTE (ToolboxDebugger.tooltip):
+# This string is displayed in the tooltip of the tab when the debugger is
+# displayed inside the developer tools window..
+ToolboxDebugger.tooltip=JavaScript Debugger
+
 # LOCALIZATION NOTE (variablesEditableNameTooltip): The text that is displayed
 # in the variables list on an item with an editable name.
 variablesEditableNameTooltip=Double click to edit
 
 # LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed
 # in the variables list on an item with an editable name.
 variablesEditableValueTooltip=Click to change value
 
--- a/browser/locales/en-US/chrome/browser/devtools/inspector.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/inspector.properties
@@ -28,8 +28,15 @@ breadcrumbs.siblings=Siblings
 nodeMenu.tooltiptext=Node operations
 
 
 # LOCALIZATION NOTE (inspector.*)
 # Used for the menuitem in the tool menu
 inspector.label=Inspector
 inspector.commandkey=I
 inspector.accesskey=I
+
+# LOCALIZATION NOTE (markupView.more.*)
+# When there are too many nodes to load at once, we will offer to
+# show all the nodes.
+markupView.more.showing=Some nodes were hidden.
+markupView.more.showAll=Show All %S Nodes
+inspector.tooltip=DOM and Style Inspector
--- a/browser/locales/en-US/chrome/browser/devtools/profiler.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/profiler.properties
@@ -8,9 +8,14 @@
 # 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.
 
 # LOCALIZATION NOTE (profiler.label):
 # This string is displayed in the title of the tab when the profiler is
 # displayed inside the developer tools window and in the Developer Tools Menu.
-profiler.label=Profiler
\ No newline at end of file
+profiler.label=Profiler
+
+# LOCALIZATION NOTE (profiler.tooltip):
+# This string is displayed in the tooltip of the tab when the profiler is
+# displayed inside the developer tools window.
+profiler.tooltip=Profiler
--- a/browser/locales/en-US/chrome/browser/devtools/styleeditor.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/styleeditor.properties
@@ -73,8 +73,13 @@ undo.commandkey=Z
 # conjunction with accel+shift (accel is Command on Mac or Ctrl on other
 # platforms) to Redo a change in the editor.
 redo.commandkey=Z
 
 # LOCALIZATION NOTE (ToolboxStyleEditor.label):
 # This string is displayed in the title of the tab when the debugger is
 # displayed inside the developer tools window and in the Developer Tools Menu.
 ToolboxStyleEditor.label=Style Editor
+
+# LOCALIZATION NOTE (ToolboxStyleEditor.tooltip):
+# This string is displayed in the tooltip of the tab when the debugger is
+# displayed inside the developer tools window.
+ToolboxStyleEditor.tooltip=CSS Stylesheets Editor
--- a/browser/locales/en-US/chrome/browser/devtools/toolbox.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/toolbox.dtd
@@ -1,7 +1,9 @@
 <!-- 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 window.title  "Developer Tools">
 
 <!ENTITY closeCmd.key  "W">
+
+<!ENTITY toolboxCloseButton.tooltip  "Close Developer Tools">
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/locales/en-US/chrome/browser/devtools/toolbox.properties
@@ -0,0 +1,3 @@
+toolboxDockButtons.bottom.tooltip=Dock to bottom of browser window
+toolboxDockButtons.side.tooltip=Dock to side of browser window
+toolboxDockButtons.window.tooltip=Show in separate window
--- a/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
@@ -169,16 +169,21 @@ remoteWebConsoleSelectTabMessage=Select 
 listTabs.globalConsoleActor=*Global Console*
 
 # LOCALIZATION NOTE (ToolboxWebconsole.label):
 # This string is displayed in the title of the tab when the web console is
 # displayed inside the developer tools window it is probably the same string
 # as webConsoleWindowTitleAndURL before the '-'
 ToolboxWebconsole.label=Web Console
 
+# LOCALIZATION NOTE (ToolboxWebconsole.tooltip):
+# This string is displayed in the tooltip of the tab when the web console is
+# displayed inside the developer tools window.
+ToolboxWebconsole.tooltip=Web Console
+
 # LOCALIZATION NOTE (longStringEllipsis): The string displayed after a long
 # string. This string is clickable such that the rest of the string is retrieved
 # from the server.
 longStringEllipsis=[…]
 
 # LOCALIZATION NOTE (executeEmptyInput): This is displayed when the user tries
 # to execute code, but the input is empty.
 executeEmptyInput=No value to execute.
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -36,16 +36,17 @@
     locale/browser/devtools/sourceeditor.properties   (%chrome/browser/devtools/sourceeditor.properties)
     locale/browser/devtools/sourceeditor.dtd          (%chrome/browser/devtools/sourceeditor.dtd)
     locale/browser/devtools/profiler.properties       (%chrome/browser/devtools/profiler.properties)
     locale/browser/devtools/layoutview.dtd            (%chrome/browser/devtools/layoutview.dtd)
     locale/browser/devtools/responsiveUI.properties   (%chrome/browser/devtools/responsiveUI.properties)
     locale/browser/devtools/toolbox.dtd            (%chrome/browser/devtools/toolbox.dtd)
     locale/browser/devtools/inspector.dtd          (%chrome/browser/devtools/inspector.dtd)
     locale/browser/devtools/connection-screen.dtd  (%chrome/browser/devtools/connection-screen.dtd)
+    locale/browser/devtools/connection-screen.properties (%chrome/browser/devtools/connection-screen.properties)
     locale/browser/newTab.dtd                      (%chrome/browser/newTab.dtd)
     locale/browser/newTab.properties               (%chrome/browser/newTab.properties)
     locale/browser/openLocation.dtd                (%chrome/browser/openLocation.dtd)
     locale/browser/openLocation.properties         (%chrome/browser/openLocation.properties)
     locale/browser/pageInfo.dtd                    (%chrome/browser/pageInfo.dtd)
     locale/browser/pageInfo.properties             (%chrome/browser/pageInfo.properties)
     locale/browser/quitDialog.properties           (%chrome/browser/quitDialog.properties)
     locale/browser/safeMode.dtd                    (%chrome/browser/safeMode.dtd)
--- a/browser/modules/test/browser_TelemetryTimestamps.js
+++ b/browser/modules/test/browser_TelemetryTimestamps.js
@@ -6,17 +6,17 @@ function getSimpleMeasurementsFromTeleme
   let ping = TelemetryPing.getPayload();
 
   return ping.simpleMeasurements;
 }
 
 function test() {
   waitForExplicitFinish()
   const Telemetry = Services.telemetry;
-  Telemetry.asyncReadShutdownTime(function () {
+  Telemetry.asyncFetchTelemetryData(function () {
     actualTest();
     finish();
   });
 }
 
 function actualTest() {
   // Test the module logic
   let tmp = {};
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -2,19 +2,21 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["webrtcUI"];
 
 const Cu = Components.utils;
+const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/PluralForm.jsm");
 
 this.webrtcUI = {
   init: function () {
     Services.obs.addObserver(handleRequest, "getUserMedia:request", false);
   },
   uninit: function () {
     Services.obs.removeObserver(handleRequest, "getUserMedia:request");
   }
@@ -67,57 +69,68 @@ function prompt(aBrowser, aCallID, aAudi
   else if (audioDevices.length)
     requestType = "shareMicrophone";
   else if (videoDevices.length)
     requestType = "shareCamera";
   else
     return;
 
   let host = aBrowser.contentDocument.documentURIObject.asciiHost;
-  let chromeWin = aBrowser.ownerDocument.defaultView;
+  let chromeDoc = aBrowser.ownerDocument;
+  let chromeWin = chromeDoc.defaultView;
   let stringBundle = chromeWin.gNavigatorBundle;
   let message = stringBundle.getFormattedString("getUserMedia." + requestType + ".message",
                                                 [ host ]);
 
+  function listDevices(menupopup, devices) {
+    while (menupopup.lastChild)
+      menupopup.removeChild(menupopup.lastChild);
+
+    let deviceIndex = 0;
+    for (let device of devices) {
+      let menuitem = chromeDoc.createElement("menuitem");
+      menuitem.setAttribute("value", deviceIndex);
+      menuitem.setAttribute("label", device.name);
+      menuitem.setAttribute("tooltiptext", device.name);
+      menupopup.appendChild(menuitem);
+      deviceIndex++;
+    }
+  }
+
+  chromeDoc.getElementById("webRTC-selectCamera").hidden = !videoDevices.length;
+  chromeDoc.getElementById("webRTC-selectMicrophone").hidden = !audioDevices.length;
+  listDevices(chromeDoc.getElementById("webRTC-selectCamera-menupopup"), videoDevices);
+  listDevices(chromeDoc.getElementById("webRTC-selectMicrophone-menupopup"), audioDevices);
+
   let mainAction = {
-    label: stringBundle.getString("getUserMedia." + requestType + ".label"),
-    accessKey: stringBundle.getString("getUserMedia." + requestType + ".accesskey"),
+    label: PluralForm.get(requestType == "shareCameraAndMicrophone" ? 2 : 1,
+                          stringBundle.getString("getUserMedia.shareSelectedDevices.label")),
+    accessKey: stringBundle.getString("getUserMedia.shareSelectedDevices.accesskey"),
     callback: function () {
-      Services.obs.notifyObservers(null, "getUserMedia:response:allow", aCallID);
+      let allowedDevices = Cc["@mozilla.org/supports-array;1"]
+                             .createInstance(Ci.nsISupportsArray);
+      if (videoDevices.length) {
+        let videoDeviceIndex = chromeDoc.getElementById("webRTC-selectCamera-menulist").value;
+        allowedDevices.AppendElement(videoDevices[videoDeviceIndex]);
+      }
+      if (audioDevices.length) {
+        let audioDeviceIndex = chromeDoc.getElementById("webRTC-selectMicrophone-menulist").value;
+        allowedDevices.AppendElement(audioDevices[audioDeviceIndex]);
+      }
+      Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow", aCallID);
     }
   };
 
-  let secondaryActions = [];
-  let selectableDevices = videoDevices.length ? videoDevices : audioDevices;
-  if (selectableDevices.length > 1) {
-    let selectableDeviceNumber = 0;
-    for (let device of selectableDevices) {
-      // See bug 449811 for why we do this
-      let actual_device = device;
-      selectableDeviceNumber++;
-      secondaryActions.push({
-        label: stringBundle.getFormattedString(
-                 device.type == "audio" ?
-                   "getUserMedia.shareSpecificMicrophone.label" :
-                   "getUserMedia.shareSpecificCamera.label",
-                 [ device.name ]),
-        accessKey: selectableDeviceNumber,
-        callback: function () {
-          Services.obs.notifyObservers(actual_device, "getUserMedia:response:allow", aCallID);
-        }
-      });
-    }
-  }
-  secondaryActions.push({
+  let secondaryActions = [{
     label: stringBundle.getString("getUserMedia.denyRequest.label"),
     accessKey: stringBundle.getString("getUserMedia.denyRequest.accesskey"),
     callback: function () {
       Services.obs.notifyObservers(null, "getUserMedia:response:deny", aCallID);
     }
-  });
+  }];
 
   let options = {
   };
 
   chromeWin.PopupNotifications.show(aBrowser, "webRTC-shareDevices", message,
                                     "webRTC-notification-icon", mainAction,
                                     secondaryActions, options);
 }
index 4f9061a09ac8759d90dc1e6c848d2f72537a2295..fecbd739f24cc2dc8a579c7b9e7916e4cefd52d9
GIT binary patch
literal 4183
zc$@)O5UB5oP)<h;3K|Lk000e1NJLTq003|R000mO1^@s6&J_C*000mkNkl<Zc-qC8
zc~I0>w#PeTUM6`-W+rATnU_~JFGfwGCYj1IZzfY&oQavZu(>4>K@?>XMNpAdSyVQ`
zC2ny;T;hV7pix9bK{i1|b{g56-n(hGruScWf8V*k4qf83Df8YR?^b>5ckaFC{GiU~
zch?qdOHKVh>EZI~?9@pU-P4n&E!a^p*<+iQY0A9q6|cFaC9}SV{r_uD^4}-9X9%ee
zzf^+9D3(5tiB_fOM>dt$4E98y*K2}bP&oD6H*IRqS)9_-o5`m3m<f&N<k5b)T+Z^4
zM8c!w=i~Er#M-sLVZINm)<^KidcR+NU+4RTg={>I>U;&3dcP;WXR(5`<P=vbBjF*H
zx$t`s+^+~$#2a22`p}Fk-0t&taiO#e#|!Tx=1>_H#9rVgd2G`Y+z9478uyx8y7<2X
zj-jNw1ubojXzLWBOVo~DX*XmF2~>Rw^bhu7SUUv0K?k$N44cjN6F@xisKi4x|7Dxf
zbDmY@o;1=qp?;)ma*I{van!2zOknMLvBwKP2M+zSp0O!CW?NOBNxJSS4Z|JNj0Vx$
zl~g~&zeDXc3z$BRL7?)=y72HrZLO^^n@kUi@|KMB)HH02jk9cujXSt8CiaB~0oE@a
zmn+-#sm)Rv59{r%4`>Ul6`R48CxI(V1Xr>NTyZS8n^7?5he4YDXB$Dx6{Kw4>PpaR
z`^Jd1x$twsn>ufM`9DLlbhn%3IGQiSifz~NkMMK6ytm|I!{I6<oV<tkeZSRB_RJ_B
zg~&ks$!9+<-na|7N&}t244u&oz0m@vOcoe;alDLXjt4kxTH;eKlP`DwJ*W2Yqhz1d
zb-!M39?G$shECbZZlJbvtey2UNRI+Ykmr!!K2Gt^OIne;-EKEQ+x?M^Q_TLs@eYqY
zHkIcWQmK^X;i<&<_=4*N1<>pD7#tdcN~MC)Xyo&jmzM{TNCaU^3$||FtcZ+=n9t&v
zYJH!ua+S&8a%aQVbQpF`6Kw4lV67sEdET&``YS9a{tU~p_h8O?2j;`m==mN@`D;+?
zE3gXag|395VKsWiVkX{ZZLWM-VI%MJm07yFE)4<*T+F^}D7aOEn<dwI6%?0X!=5~N
zZTt~Y$7}Jf&wd?^yogbNp9LSmNB##fJ@5!V4LpdMYqGH*>NLFL&%rn80+w$10V`53
zA}IYbR&T$G^}DbCEI>AL^rERH+Rh2RgRSEYHckZ_r^ev@7xg0@uXY(k@7yK`*%pPz
z%+FV3HcWI+8#6V3z9Jsqe?JFG;k)Q-odVPFB@jUv`;S7^@+RcXZ=<1dmd>j5NTmD-
zwj^ynQgpKjBO^M<WO7KPGN}7B1k(WO!|pwMP<Z18LF^^4YV6vv!x|G6HJ8P*DbZH9
z6V@MRfvfrku;}q%v5SjfxiHHCG5cKy#6weIDO?8@D@aOAbR`T7s?gOVV&ZMq=E|3?
zYi!yqtP#UMtpI28%1~KV2ANz8?TD5%45>_vsypR4b-4s?(U%aky8;twI%TmW%uT$C
zz_fh$Y`lO)v8PFAuqf^feByJkB=H;%&_6lX2{3YB;TVA1cV=u&&q(3Ywk2ctH%X{2
zc7tA>44Xy5M9H_3II??THTS@vN`SKEW2sf;wSK~!R2;n4jx%MwPL<T<VX)&bu-o*o
zSvB-DF@Pi!Y+N7JwNNxq1APQJi3tfG?%%hcK5{L3dc}~*74*?dP+C?7Edix|q@``c
z)%<H{7Pdm6R6(IoAv!8*U}Id|i#)))+rXXs6vou?(8rB~aTkrUb4y_DD0DzH^ut;d
z@e@4iJMac91z`?=@tfjZ37P>Vtw&u<yv^EN`A&38PYz7^k=v8oh`56VxK~#VgTVlf
zvyeE1g@?jyHbJM;p|<`mHtfBM#py+u5q6rJ;Mmx}YwHbc&bbfo&6n|yRY&keST@|(
zpTPQ%*AX4~JpAHzj{z9{?M)}Z#KgoWw`HbU*mT8;-71E4a0f<u=YmEaCEZL3AEtH<
z6Sc{xZywt3eQBdjNhZCAhqf-e&Z$#{+30SX0lg}bV){t^uyZncO6jSf_E^-G{{?I+
zjg5)TX=)Kds!*bfMp%7ABQ|Z^gs8|U;k~+g-k$#H^u*B6HJZkz7CxUUwFcJ;3Ykwb
zL1610n<7c?!*cj-nD@R0Q^w2C$Nw7Ui@|_-1gvlct6|zV38p<0V95)10E~@`b0w%X
zax~v>XX0(v=E`^K{OuLVCn~WtH6NAt>Y-9AVX;_XwOaYj#=@`WQ{4=c$q1!Nfr^@1
z%!#>(FE{7ob+62dM*;K>4a5G_KcVq<EY^j8G6rDW!J-ENK1~3v0QiqYH!Osye?JV0
z01USOrvreg26kg5*(waR{ShWrAlhpK>}I*wURMB56TsT~Scn=aq1ww7Uk97Hj(?A7
z;0UCx({cHVKMycECWZ!-2Ez6Zv~_eNIwlt0ix;!q-ITz<z(X;yu^{_}5C8VJ1<5HX
zmd0iwT06SX*)78Qh=>*jfh&rIY5!z!cXq<2tcA7Z3@rH}1nM;yw*D5z9dGau?K(C2
zy#-_DA7Ht-)B!LmI>wctR7+7$e~iT2tj(1#?JTv2ueRdvv{`ArFQg=nI05FIJIesF
zIuB5*9Y$-L5Ff8Ti=e#~pdG39VSp=wXCNx%4~SYe4$7`QuvvPrDdgV~8!{d-Vbc(r
zeiHGAi(LX79v;T<U<VAEEa(+$pqB;0ZV}QuI!PU{n;W2$`NN`#90iz?MB99;)rNs#
zol_%&B`|7IFw{8(c1}$2S_ot=Y^DZ!PdBt(@1m*70dPZ96l4Ujy1o(BwG9Ybxw3_T
z{hsp1?@s-eEj#>^{q%}}z|wnl4X7bW6)J3qj4~1gf)(a~Qko9CNsG~9>%K`N?kyOS
zf5VSNR;<DwVA%3J%sF2<0IuH<$<$54s7`!$5;CO(cN?0Rn9bT)--8m8c!0Zdn=m~r
z2i-kg{3tM+&HNO4Hiy=+CEmz7dITz!f)YH0Zc*1G0s1DKK&1aT+`s)1jLNk%YDx(}
zD@}>1=(|4~nK3USJa#n_vr1e792^`#f4>UazFg>)QP4>igVPsdsACH0O>nwmYWo`8
zKmreNL^O8+TQ^xT7!6Jtb!{*Y9)(u)35<Qo81DWnhI>Au`V1IV@i0i;(Q;=QtZJ{s
zHEY+JdZY@JSKmYB-C8X5_b;ZL37Epxu1jDLN9%#XE9<Lj>QPl&4~e3W<&cM9&RqdR
z(z7to`lpW(z_4ustc^JiU>ya}Cp^v8M(3Jn+&LAd<L(ZC;p^86eEogDrl+B(<R&EY
zUS9P=A#UHRXJWRqy|Abd%-7f7XD*9<WA65f(A`B?m~aKcjvfpR4YJY3);%6%pGJ-B
zV_Ard-T*b(P3_&79sTGjbUBT{w8$4JS+m#|&WqM6ocneXqCzKN^|l;r$u1oOkTx(@
zw#m?F`k+>;(66e-i0S~e;ziK*xIw3g#E5J?L6`$=?;`pj(ouCQ++J1?_&Zksc?}m6
zyi6L&t6@+@L$6Ar_iTVpz6!RXblfWqfJNy!IUsmtTU~P-L1`k0wTRu6VD|H0K9%yu
zatl&CvqQtfSA<c$uDKP}4bA8h%R%rpJiwgA4BW$VLNt9hm(}@=4HbI&!gOr51K{fL
zwSwng5&Zh=C5sl4ZMb%$03vA*O77H*5o^mYyaw{oEnNJi7mH!B?1sf{Lk_oUZ#fdO
zZlQlb1A{>iqtW0Ls}BwhP+uQ59lizcpWnpL=4B#kuYceKNZWlxE+2>B<P-cFm~y<#
z2{0og<JnPwY?Lb$GRWmpsO2>B6bC5j2^f)&DxMcNa*k$&Oe?{E&J{qNUWXxVABOu2
zF{1v~0Z*BT5oH1|yY4g&9@qo{m9M-P?>}+&Jeuj_Ev~wYqVg*EE?cgi<>u~B`9a~W
za?rDegrc(BxKrPRhSpA$Rn@>hFer~fFr8iG0F<{5_F)-&I!7Wa+?@lg&UUAcdc`*|
zWzTc~Tp7BCiHA6U(E=~Bbyu!kMYp&cH!JQi@%H8XJW!u@{-XIF<oncU96JiI8<y|`
zRs0d*Ms+(z^ds!%gg-(I4G$8$evIg}D7@2#S&<jV93xx-j1GAjlDg@rzWN?6X1$J~
zu9?`fZah{deZvDxKUo1Mz#VC|`w#4CwOTogTrTOAN_#~Tu}CED?Ged(Yb1S=3+e&s
zp@Bi!-obupR=-kGpfH*A=IrA~+S4;rTU-Iu>a-Z3|5>e3LZxhmN`3=s*?A}=mmm?B
z0(J{1jt4mPt+%H6EL*0nX}XW9`W9TeUW_9r&muG;n&k^!5+%Mn{{w+*rjgfzQW~Z0
zA{jQPq+#ZqIrDjd=Y610dIol_98}nouj><@;@3o*xRTYG_;aGI_clx?-5dY|SFLu6
zf${oko<~5)D(%I*AJN&{$t(BDC9pQnFTLED&x0|nutPaJoQE8!<^d&TmqVf&fZ1$;
z$!vy1*^k8RQofIT#vJ5b0gMQK1@Wt&L&U1d2wgJ+F+tDJapGx&Y~IHM%s6%136K)`
z9UUP$N!<kQbg!uEyMI;3DRFPdsnNP#ue)zF=sUOX+;;R~fO><TeSG|Ep;Rj%m5U*g
z(5|tk4eed6yr?(<QhD;z&pulhwjs(^-O!4n${OrCl#QTuk)Zsby;qLvMj?uB-=)60
z5O#@i><ryb`7OOjvCs0Gm@5G=?fegz^CQ>@WKX_s+WrzOh4HZ5NOaUQUt%^Xfe!Zz
z9RQcF3>hN^$bF&bZ2#bu!{;yMf{E-Qw*?+wu)c@=o%f)0J;uP$=weeOTj$tjg^AgG
z8|xz<=T+LH0M1#n2VaIIU|#fTe6=wLejC3<K;nMqF=EG=$_D`k=|;3Cr4mu7MBKCL
zu_O_#W-$bCxhsG}1W-c&6)G7dG7-9aJ9u!y_C}^L0P~8=+2eN~e*8(K@A3f6rRzmB
zYu&}p16iQ_;C_#crq+9?rV-lQ(ThXJPhs)WWhF0+A3ur35(KN|dI-$N-sJ)5H$BNe
z%}3tkW!Ul@9VMO{t&{yc49UNR<+2Z0tYB$S@WbLE&YCyp^Cba+A|_^2+rPQ+9dnt@
zMirYH+4@GC6t>gk#cbBb`k2qdm)ReOo+W^-SekN`Kfo`f+ZaE(LJLZ}gs`1?bn{X`
zM~9n8K2}PjuL8Srs+^bEl*nnrLxXPr8xg=M6mMroo?lYfn$F?`RDQf!%8SY~uTGpe
z)nmcJGxNO{TbBfefbxTuZs{21=HI~AeoNEI{|OdXzeJF$-uZ!@D+mU6V->i<5OCMY
z<`o34Ab_+2+_mKn<uBvmsWacPvseKEaw!Ik^b!-ZAK~Zn=Onf{VLMEAOkiU6g#U-1
zlOCt+{AT;U(QCNJ74zS*D`Ovv&n>*=6oW!~o<L4`=lu@?DL?ob#ZwIba}t60zRpMR
h_&+C+FN<NZ{{smln&x}(1c(3t002ovPDHLkV1iSm4B-F(
index b7365a9c6911301427ef88154a13b5ce92839301..20734e413503767eedb8e8d3c82ada6a50021dc8
GIT binary patch
literal 6578
zc$@*U8BOMiP)<h;3K|Lk000e1NJLTq005`}000;W1^@s6Zh^MJ000?zNkl<ZcwX&#
z36vGpwf1+a?ofB=;r2YybOS9Q4TuAvfDoLX8U__bkcPx0`Y>@N(P+?LF+PnFOnko>
z@_ZU(lz>y5fiTD*LpQcSH(&r6dY;ES*L40<XVqoZy6e(RzPJ9j*8A4l>zvxvwX09<
z@9w?Nt|Cc!_%BCq1I4A_fAPPt;XHWe7ccDsFdm8V)r)_AdIHV^LI@I}=#H050ZepB
z4#UQnsH_w??Dl#}X*ru4_uX;ki>D6b0#JD8%LAOE_(xSyrU-&=u8Z)2f`X5HuuLc{
z=gC<$2tm!pX9@m?gPIF!YHGrol`EeIun-r3IrHWbSdg2W`~NRNDW&5ddGui<!e3th
z&+)iuaALY$lKoXt6y{ttq@OUTf2OM-HyyrIFKQaQicZ$G7oDzaoqFm_i(WGAmDP%(
zKF)|5>T@B2@F!n-%G4t5fRLFa!s&Fv;c##f1mV0tAcw=w|F);skF`5H@O?mOyX#6p
z(~EUN)4(85(kTcyMY2Br_It74GHtj(Fo5bv<Es$#E}i0}J^PcY1f+Xz^@<h9FDO`e
z_dWMO6h$P$(m($hZ@uxxHvmpblC+*#-TcIY1wA+q4wR9J02Tunjmtv?fF}$4Id-JK
z6g@vdbxJ{*^!7$!MRKx}pSuKdj(0ij>&J~6kow513GVWvO*mfHg+qHzp{XN?>@+tr
zd|nJ4I>0q){8iYz<KW!WXPTz6>t-^NeuZ;D*XfiLk1ou=uMF84K6t&}vtqZ~aiLiF
z;_sol@+d9?wDVrKF3Uflx;7>pJ~3U@r6G19TIF<?oYE-$r`9~JT=2{PASD}=OR`^g
zuUB^{H&M_rA^$(8>BKi!ME7CIGx)dwoYGpS4ixm1F91YgLD`Rf^xVqj%QHXx@Wc7{
zFp`EN5ro2F#E_Ae22Iy-@64H_2qB|7+S_MTe*Jat;+J3k6M$EreCnwH&W&}2H_ymP
z9axIXLHEhSqieUkzYaj|1w~L@*Le!msSYc+PS-D<oRWRx!hii2PhNH!URb^dV@o`k
zbcF-n(j@4b1A^#;Ulwt+E`Y6jn{f50A?|+ta@;$29oWdO|Ce);lu|L>?L%EVMOHfh
zQJs~GL7=A-Ko%|soSX!AQeDo~kvlB8_zNLWGj$ZzBlSd(hEReGJ;|X1*l<bq9n3y(
z2i2olRO~k-sqix)SbNV1s)cJHx(0xfbQQhS27D9?G6q(?{q}H|+dX&U#7WR}il{7G
zeF&xkWyf9J-AGSQ$FR~;Tz$<o$%l^|d4B8W&9fK1^wP8iPd|MOiIJ0%mk;gO2N2v|
z!07@JYycsNd<CkjfU1Bh3L9lMMh&tdrTA8E3nnfwf`Tt7?jHQy#iVtKMb4)my3NxQ
z*6{v&`|$JIGU0I&<mTkU<4HnQ)gg?yvJ`<}fUUL(V;Fgte0~PL^fZhfJJM6J@8Ei7
zr{rAe{>q_+SibQne!r@VKLi~FfDVB0V^9JrP!MXU2tO7CegHy@Il;|^Dw|V!IcYr_
zI6g<wozo~)L|5i>032|pJ&a)6v$qonio@>s#x51K)7Gg6NY*FKVEDn07X7iMSNLTp
zqV?&MlDsfJ*<FtD!@3{}fII6MZr|?vSK@DZb}ERdIUV{wr?apfF@owkRxMwi!!pUn
z*>lP~PDw&%R~OgE*Q`3vmc5_=kEULa7lTSlP*_+vc-`8y`(J+X#c@wP^GtPOvM3;u
z8{$oW2Fbh%wC5zC20>d7fHv#^Ld`J2eLz6~5>p5ObZ#St3y+|bCRohHMNmf0SI3Sl
zO3h45!ABog;#YU3AvZe<1^I;_L|_8!*}Dhh$4x*|QWCPWveDSwfZtBnvFM`~Was4}
zFF!lAv7yySH}eq(0)haXY*RNKf-XarqX>n<kQD{G&L1`t!vVY;02gWqpr{&JI|KOJ
z=an#!h@FcUzckV2u>VC>)dA=OpKR?CCXG7d@D2J3ltw@V57*nhKNM{4Ne&`79KEM+
z7;TqGvj!NpxYruHgvTCx=uVQCm5RQQ<*G)Bv;nEb+X1Qpf{W`NNw>k_nE(h5(SK^}
zD5r!*OZj80|4-AWPR)yvGnQFgE*B)GlcP~iPF2(3c6%TY0g9p`7z%M+YDx+oD4UzK
zeA!<&{r-g)uKqvIKHH202%Y&3?(TNjvjmXT60Rc|R{>Z47_{RE=s#D0wpD?0Vp7Y)
zrkAuyGM&g5m`H!2(X-Up5Y4;m2KQ_0EAZ<nxya8+M}A&E5JI?gbabGty$zk69Y{+{
z=Np^6oO}=fk56;p-`=gm$g76Bo15Con7yU(yL&+-XzP`+_jnilJ>BSJ_S!o-p{feE
zWfMh+A{%Xd4x7LvHfMUi78;``p@@UsVP7?SR#{<2Mke|Kjc!M@>jXkAPs5e<G@u6n
z8a7SZ5NZ7b0wI^+P2#Eon20JG@pwHr-sneP5HdTFE#$z_{7Yv4MG!s8?Hi!5A=LO=
zh@yNP7A#-3Y;azF{_KK+ems3M!trO~W27^1=JaV47Z>w@BS&Ra?BCy7R8*8TeE4v<
zJs!xij2;$MeLf%VnsIOL+BK`62atH@ObB{cOaYANn>!Lhavtng+zRK2`#{o%fsA_v
z^wh`D4lV`w|E`;Y7%m}#>J*w57eV!lil7sRmE;MP$C@!=Xfjefc9zx)OmYf*tgWks
zftuPnq^D<qQgD5CRxSd;AZ{L+imGNmva&OT`nslx01n6R#03J5h^!(MRS}FR&{TyH
zQH0$_VW%Q!EZ#B^bOK$VuymIaV#$&v&WIe$&tg$M7!3B=))CbxY|d*D^>2a}`U;}6
z7zBhzQ#Eo5RH=kNI^32`JB%RJ3k$k~GTQx7^aa0HMYnf2(77GCN&DEnia;QO(q3l2
z0ViuJP&#Pvi8vq57<>H<2!|txL}mW0d@0H3>FLG#_3ID{1S$s(D!FFL)Tw+8PyFWb
z{`2O}8(($k&|7oL%8GnxY3T0hK^K$E%uEazIOwOpd+v9y{qFhS9fcLT2DcG(Y<B+K
zbuA37{TqZ%Y(!|&vv5s(0<Lk7f()1jF{wYa?N0)cc0g5_r~uWu4J!on4IVko2pSWs
z?n2Z1g#P)Nu2YTO7%?CjnHkx<-s40euo4t?^))fQ0UrHQQ&MsDpcI6H5k}rrm)&lg
zfH-h#0s+Cf;gu^fpzAmAhQ0(68sJtCkIv3cVj-bbc+}A~4Vo#s?grN@?XbD71K@xX
zJ_-;o?Cx>Uls3~2h_2~%us~KRqKe+9^oAv9I^ZN7u)D?pkRS(k0mKKJdo)s{?nFMk
zGc!9IfpCb;H8`9OgriZsz3i{>_xApH_S|{b9zTBU-#+>DlbBDVD_5=D)=*zRZq<qv
zjf$+m>2M+%l@SbvaP4)Y1-9-o#DQum-|SFThG4V7?(sq@C`8h*YvD*uLU{8+^t^d9
zXrPtXsNxS^1*HVK95t^~xQ&a9poSxK?f@&8j-R_gjLFIJVdueGq<hnN-NOOHHYX#t
zZry_R_I7OAv<cIuOos)$Kbe){KqwSqX+NFYLqbr1(sNccdCJFl{ONb_?=Q_jW75sA
z!bZ-L8v^>QT`b)JV}xZ+p&=avIS}l5h;%H465IwtT!=tr4!aRHM}bKia#Ru{-@(M>
zAr!y*VF^Ov2>JrilOd|intvd|?Z1Z>+zr8=1-a`jh@J_M^=#8WI06%*-BDz-*%6LJ
zdDfGhE_}6XClpm(&st9_4ARb?JD2xK85YJK-`mUIZhrE~-!5W%gC*l{yb=Cj00HKM
z^vq0y$hQD^3KnpJMMALMu?#}qXwc4Mpe+ZWpZplk3>h}J2cg;n=>E$MNSVJALPjaX
z>wW{}A5Q>OkJ-5R6wiz21U2Y|rg&LV3zCyPXz2{WZX<9q!ciLAJ@X#`C+CO}!%<aL
zjn6*+6nETyXYBqwin87*dIK^BCwZW%T0sJ80y+gnVhD)9>rjxHKOU(`J~V5+fX#;(
zVi6tY|8)-VXh}_Cf>Lu%%{idaY&Pu=o9A}uY8~wEn?VI9phcjmA-I!nM7ZWOIs?wN
z`Gfx+g^4S2D9<D|QRw@JL2}tR2sZDXfL0G%>U8c#N)?EL4pkotptFsNWHn59Jf2L$
zSBj#X%}R%>tH5-tRZHnMt8DIb@2p$_D^yL}d+6XnOq?{C&5i6S10Y6iIvnv(RfOAG
zAq0E*CX1vG<sw{h546f9pw%nk&dEclsR91g_aWusZ4gUmLHqhG=*@>>HWCx`XS1Im
z0L}m?gaxI;he1zJgEAdI$F7U##PPS*zA_jVu#{Y1-_l)_o+1H)gYT>*!Df;ZTuMr=
z;N*0>-Ppc!JFiV|yY)6`nhJ%9Mnxof9q{{uMon3dIK&9g2MUf9<!cnnZ-HoTkcf&q
z9(amVb^5GdW91u<0)icCqz78wkAbZFKm_Z%&v;NvU)VxQD_PCsC>;Ww0ye<|f)?W(
zCn=#$P_aM0`Bv8Jx8$BipNMb&=zOHQF%IR=PBiS(MkYFUr65XZ>vZGFqVC1E%)i%|
zdBA8JwP`xdWn$RiM5BZlQLxRL8P}~@{m}h$%AR8qTQFrhkE*JC-La02agE!<oDmOI
z;WZ@RB#92#3&+AS{BB6s{RHBeCqS~VgZ$AvNX*CK`uzxh^%}2BZ4;kEboHI!I9CK^
zq@rc_{9?<PF{2-xJb5ClXzvQ}+9X~#`KF0nOt3V)9px1j+Y<C;%WE1sihL;^bOkkJ
z^O{DAk&_d3?wq-NCvQ9qMU`=;riR%n$ME5${DE}%6?oXfy1RP8P@afCdR*+wz#)t*
z&BPBTUkO+0Sfpf(0F@7+<ceY}Sok!8UAs}f_ghpP*$-7<1f^zQE^%+!OwC$6G5MU2
z6y}^D!bnPx3lSX<&;^}3q0tn$-PfQe@EU*+&IfLpXE1X#Ny-I-p&$<e=>X6PK!V*f
zfURW(Cf&ZY1{MTE!83}g<Pt)Rw2nwLf&qg{*xL7uzGg(}*8phwfhx*;y!f3}D^q4Z
zQ1*(Yew{gV*l;5Y@^+kIL#Hr$)e7Q3H3beq2LwQ;QE0Wh5InsT(f!MjH18t_MU!9~
z`#9u{zlBWz!aHAuH0B`)#S=j?hVm#%wLVh(r(6DJgu?=z(pwFZwzl`O#VAMwe;~|7
za@vuVk&JEIb{ORR@V!r$EkGP(S=m+B*gm!7iXvC#iEb3<c;VLF0Qe4`*P*Pff&TrA
z&en3*kG%m=Il^DZiG<+m<6UrjB-EX53oDAcE3q?~SO{AuPD919WjOxb9{l1_9lHM@
zVjxik%irFIUabJ3te?XzSewS6eU&_%jERV8)$>CyRCw6fkLx*z{bHgfzn@7?E_{uA
zZj3G_`2g|&5G0G)&~=jNfBw9ovGMw(<Yc}%>hT9y%kFBhw?hl=_~DdyzxeFa_A#SI
z;Fpg*j@-Pw#cNlu#C@~pyz=haHFt@kIDhQ8alHOiHI4U7ql#<<lM@MU1elu~!4$)H
za??Q`Ra1Yy7q-zqhg$w7Y^_J3g*y>Fw2qPVVTe~whu%=hZJcu#-`&&Exn<`^^UBNj
z@7}TFD`ci8@m`^(>j{OO<A3wzmpj3(*|BZcCy&T-B+-WjJL>9Nb>m}@FZMU1C!`?|
zG8U|w5h0d7453^fiG~r4M!2pgsNyqrU4}0Stu5`kVJ}exjo-A%LIw^CkD*q*5t}!k
zgcarGXV9*fq9^YqP^llUK?ylqgZ4pC%_2INzIA*}FmbWu<f6rF@)}SB7tIiri)xO2
zbYkA$yJt7tE)OVxuAXkAj>q&F_vKSU_Dq^Qc>(~ZagV!a%tXJ!!o};>tonx_2p`^k
z?@TzI5^pgvJ8(%Z)Ya7)>q_7Q%0(!;5z_p9Tx>-X;D8FP`7k0C%fS1i*E|S9DMaW{
zj{gG&gnrk@uJ3!3)ZA9za^UcuGD_*+2_YlLjk_N8O`SZvTVc0}$j(T?u3dYuXK(p|
zeU)40G_}^XA_0u1`k<+=tl6{gaM`e7SGX6htj5wuM<W~#F_PPO(M~{O@Ao-DRYe5|
zVdouqW@RM?7U$#8!EZy1gsT&Mf@j^^(73$pBz~m%B&e#6QzzR|*gp-aJ{RnI8^V@1
zQC4FKpaN9X858(f>rS4}adzG}sEym|1C&Qfi%<*kDIa4bHnT?G_na~7fn)E!vwD3)
zW5Z0JFCC4|jc9CXh9tRh-~D9+D=PMVnVy|n#|TISLB!O%W}v$2&@F?94CU>m#^xqo
z8ZcjRvX<}LV~}+j;y`R7sLc+?{p%qlWpkZ#);iEv3SrZLX!U!LuAdKa@a-U*7eLej
zrQsX%1;h{#yPexO-!7gWJ^oFN-R`_!)9D6Ao}#g1N8?mo+u4UN5Q6+1pFvFQ*tz@I
zv6Ba9ovuCBU~(fNR8@Vfp}u)aenF1g;ql;+*UPc!r`IAqNrbG*=H|l?p7_CE$@PS>
zVA(!6-ChI(0W>zWbgQcNI1=DoZW3u2Dat+!8FD=q{b4)8nh%0{5D)(78c6yH1R|#Z
zZwW+!fF$VFFaFb_j~FTYx!s;`R7D-h$nj5WI**a{LZK+?U`cXSD~ht4+3tMu@ddZQ
z0yBM^5+fwFlJo4`T9?LwSbd=xk(cVfdhfk;H~!?O59g+*rQu9%E!w)<5ef!TJa7<U
zQh4h4(Oz~h{(5uRun|U`iI&zjeh)$j(o)k<Q(MD+<R?G>kJpz}A|4J2QB8o0YSsmT
zxID0FIwE!Zxr!v`bDc;jqQQ1>ohO6qn2if+GwFwp>^<(VOLx)j_`>dR<c=CO65rLd
zz(8^TZ0xT*fG@Z2YC3u5$o&To?>W&IIn5{<GCrBB*mr27@!>~Cb~ffO*@x*j6kuFw
zHuBPw;E@~%MPxLz2e7-k4j=EUHzFq|C%Z1l$T{;IABqUpy|#5mAu@5`jW^5DD$Pb9
z^;US*YS!cXztA-WRP@3??1h1OKrL;h#$P`A>!G0RGEHsJb*+jM;u4{0s`tn99!xWs
zxMb;TRi@f*N$)24t-?u|kf<?|#=!;f<Uq|7k9%f5(EQ%t*4(yy*;^H}=ggG~^70XD
zJ@xwi{B@>g*12t+9o7~iZy9A~Wbp3G2k)=%HOP(xAd(9Z2m&8I4DUUE1qh&h`6P(P
z3mc_Cu#Km5(dpniV(9#FI>~jxeNcV>!7r;F4r$hgjhjCZZMO8`rB}j0RrL|pP~Xzg
z*nH-`%0oM<0q8g{I7#;u-tz1e_Epk5#)lv5-MVY<Nk6t$eanBf{(#I|No=>yH$=mR
z^f%Ia*od6bKv!AawwEhRGU{>BLIQ!Vs;Us*7}ALoN8F3x6hffRe9nZ3bQPL&UxVE)
zLA0ly?G1vM<_M@I3LR!7&F$!D`^qGcj>|xMTgzcWh`>_q^#Ec7^)a0$%Tdwga^q6b
z)7uThj=5_(4ZxVk$i_%IyPA=7^qX%i{dm&kTZ&6dM<63T19kQF{2hH`?de#5o6Fgk
zBpI0qg+o~Xw>3&661nTIe_8q+5`Z`)NSRrPoZO1;#l>u%2^;ezaq%F)=0Swsoe5V?
z&N+3YuL$aIwCrO|*|udv#pIiAfAF)<HmtMRL{4uu4>vW}Jox3-jg@kMUn2sbrXVSg
zk5-6gl(5xqe&K*8cf=T7o$+FGQ|k=l-FkYuPcl9pNlNk<eNNs=syp2psod92)oAF0
z=E`*oL#^NX0k{FErpP8y1pq0U9Qda8WbHKr^Rq}SdJ;l-t?Y27!s*O}<g`Ju+u>xR
z)1CsS!x(M+Z=$lwGj(;VPgR3m&zp8N07o=ka|1XOv-v$hU<A-C1Qj|uI+rYY{ofza
zblrK$MhS_wwzj`vOs&l_>!*@;&wQZz{dH?bZQZhI;hx>Q=9dn?%9WXwh4kV9sH!YC
zzkH&6G~jl*A&NG9_Q^-gFI}tNe&av3Ar6EPY40p__#11}lZQ>kxfb9pKEJNF?lhtr
zIx=3CCHfK~@e!1mq!nYM9Dula!-mQmC*Snw`yYJ#2LMWa{i$bmZrfU^$(%5nDXL|R
zCn&Y*f=yN7Q%zMbqzs(6wY#qWcqt|GD!Y_AP$#xjfhs*psIw;A-F!6CajL>!S5cY3
zmKGO9ZC&4fv6|?L@145(Vh}=O?Vht)n+q{#mQvG_+BH=tC)zqU)$e+Jt;O~cMyBTE
zlvI45U^dSH=rR?Zix>TIF@RUU57PhwrY~TPpwn)iXait3&%JQ%*s=fF-rDkjqN<ak
zvYefrm6b;+P}HwK;xXgi*;xC|il5B;*+VB*zV+rG;(4~|3>FESKYz+DAPtuRMMtM$
z3xE$m6JgQL8bNuaixbfh!4Aphgbx%{mC>y$h*-#}ScTct;vzHRBC`NM0{CJw0A!hx
z3Ls)St_?uDId)r!uP3NKlK~V1C=#WlG{NR@;G#i{Eo_j61IH94^c{d6ey{&Fm{ITY
zL1V&jHo^fsusKYzn_@G>)Cpxj{n<7`h!^L9EXxbmtz7X6vmde8_nBY9C*ktoH@}hX
zGVI3_^lX1MZX_|WJ_HM4H0#K0>Tv}9uZ9hP#}vmUI+_Ad%;*#1^Z()C1pRLSVE`al
k$S&g2paGE0QKJn155{~|!e92rqW}N^07*qoM6N<$g81932LJ#7
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -2346,16 +2346,20 @@ html|*#gcli-output-frame {
 .social-notification-icon-hbox {
   pointer-events: none;
 }
 
 .social-status-button {
   list-style-image: none;
 }
 
+#social-provider-button {
+  -moz-image-region: rect(0, 16px, 16px, 0);
+}
+
 #social-provider-button > image {
   margin: 5px 3px;
 }
 
 #social-provider-button > .toolbarbutton-menu-dropmarker {
   display: none;
 }
 
--- a/browser/themes/gnomestripe/devtools/common.css
+++ b/browser/themes/gnomestripe/devtools/common.css
@@ -123,35 +123,41 @@
 .devtools-toolbarbutton[type=menu] > .toolbarbutton-menu-dropmarker,
 .devtools-toolbarbutton[type=menu-button] > .toolbarbutton-menubutton-dropmarker {
   -moz-appearance: none !important;
   list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
   -moz-box-align: center;
   margin: 0 3px;
 }
 
-/* Search input */
+/* Text input */
 
+.devtools-textinput,
 .devtools-searchinput {
   -moz-appearance: none;
   margin: 0 3px;
   border: 1px solid hsla(210,8%,5%,.6);
   border-radius: 2px;
   background-color: transparent;
-  background-image: url(magnifying-glass.png), -moz-linear-gradient(hsla(210,16%,76%,.15), hsla(210,16%,76%,.35));
-  background-repeat: no-repeat;
-  background-position: 4px center, top left, top left;
+  background-image: -moz-linear-gradient(hsla(210,16%,76%,.15), hsla(210,16%,76%,.35));
+  padding: 3px;
+  box-shadow: 0 1px 1px hsla(210,8%,5%,.3) inset,
+              0 0 0 1px hsla(210,16%,76%,.1) inset,
+              0 1px 0 hsla(210,16%,76%,.15);
+  color: inherit;
+}
+
+.devtools-searchinput {
   padding-top: 0;
   padding-bottom: 0;
   -moz-padding-start: 18px;
   -moz-padding-end: 12px;
-  box-shadow: 0 1px 1px hsla(210,8%,5%,.3) inset,
-              0 0 0 1px hsla(210,16%,76%,.1) inset,
-              0 1px 0 hsla(210,16%,76%,.15);
-  color: inherit;
+  background-image: url(magnifying-glass.png), -moz-linear-gradient(hsla(210,16%,76%,.15), hsla(210,16%,76%,.35));
+  background-position: 4px center, top left, top left;
+  background-repeat: no-repeat;
 }
 
 .devtools-searchinput:-moz-locale-dir(rtl) {
   background-position: calc(100% - 4px) center, top left, top left;
 }
 
 .devtools-searchinput > .textbox-input-box > .textbox-search-icons {
   display: none;
--- a/browser/themes/gnomestripe/devtools/markup-view.css
+++ b/browser/themes/gnomestripe/devtools/markup-view.css
@@ -44,11 +44,15 @@ li.container {
   -moz-appearance: treetwisty;
   padding: 11px 0;
 }
 
 .expander[expanded] {
   -moz-appearance: treetwistyopen;
 }
 
+.more-nodes {
+  padding-left: 16px;
+}
+
 .styleinspector-propertyeditor {
   border: 1px solid #CCC;
 }
copy from browser/themes/gnomestripe/downloads/downloads.css
copy to browser/themes/gnomestripe/downloads/allDownloadsViewOverlay.css
--- a/browser/themes/gnomestripe/downloads/downloads.css
+++ b/browser/themes/gnomestripe/downloads/allDownloadsViewOverlay.css
@@ -168,23 +168,23 @@ richlistitem[type="download"][state="1"]
 }
 .downloadButton.downloadRetry:hover {
   -moz-image-region: rect(32px, 32px, 48px, 16px);
 }
 .downloadButton.downloadRetry:active {
   -moz-image-region: rect(32px, 48px, 48px, 32px);
 }
 
-richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow {
+richlistitem[type="download"][state="1"]:hover > .downloadButton.downloadShow {
   -moz-image-region: rect(48px, 16px, 64px, 0px);
 }
-richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:hover {
+richlistitem[type="download"][state="1"]:hover > .downloadButton.downloadShow:hover {
   -moz-image-region: rect(48px, 32px, 64px, 16px);
 }
-richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:active {
+richlistitem[type="download"][state="1"]:hover > .downloadButton.downloadShow:active {
   -moz-image-region: rect(48px, 48px, 64px, 32px);
 }
 
 /*** Status and progress indicator ***/
 
 #downloads-indicator-anchor {
   /* Makes the outermost stack element positioned, so that its contents are
      rendered over the main browser window in the Z order.  This is required by
--- a/browser/themes/gnomestripe/jar.mn
+++ b/browser/themes/gnomestripe/jar.mn
@@ -46,16 +46,17 @@ browser.jar:
   skin/classic/browser/urlbar-arrow.png
   skin/classic/browser/webRTC-shareDevice-16.png
   skin/classic/browser/webRTC-shareDevice-64.png
   skin/classic/browser/downloads/buttons.png          (downloads/buttons.png)
   skin/classic/browser/downloads/download-glow.png    (downloads/download-glow.png)
   skin/classic/browser/downloads/download-glow-small.png (downloads/download-glow-small.png)
   skin/classic/browser/downloads/download-notification.png (downloads/download-notification.png)
   skin/classic/browser/downloads/downloads.css        (downloads/downloads.css)
+  skin/classic/browser/downloads/allDownloadsViewOverlay.css   (downloads/allDownloadsViewOverlay.css)
   skin/classic/browser/feeds/feedIcon.png             (feeds/feedIcon.png)
   skin/classic/browser/feeds/feedIcon16.png           (feeds/feedIcon16.png)
   skin/classic/browser/feeds/videoFeedIcon.png        (feeds/feedIcon.png)
   skin/classic/browser/feeds/videoFeedIcon16.png      (feeds/feedIcon16.png)
   skin/classic/browser/feeds/audioFeedIcon.png        (feeds/feedIcon.png)
   skin/classic/browser/feeds/audioFeedIcon16.png      (feeds/feedIcon16.png)
   skin/classic/browser/feeds/subscribe.css            (feeds/subscribe.css)
   skin/classic/browser/feeds/subscribe-ui.css         (feeds/subscribe-ui.css)
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -3812,16 +3812,20 @@ html|*#gcli-output-frame {
 .social-notification-icon-hbox {
   pointer-events: none;
 }
 
 .social-status-button {
   list-style-image: none;
 }
 
+#social-provider-button {
+  -moz-image-region: rect(0, 16px, 16px, 0);
+}
+
 #social-provider-button > .toolbarbutton-menu-dropmarker {
   display: none;
 }
 
 .social-notification-icon-stack {
   padding: 0;
 }
 
--- a/browser/themes/pinstripe/devtools/common.css
+++ b/browser/themes/pinstripe/devtools/common.css
@@ -129,35 +129,41 @@
 .devtools-toolbarbutton[type=menu] > .toolbarbutton-menu-dropmarker,
 .devtools-toolbarbutton[type=menu-button] > .toolbarbutton-menubutton-dropmarker {
   -moz-appearance: none !important;
   list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
   margin: 0 3px;
   border: 0;
 }
 
-/* Search input */
+/* Text input */
 
+.devtools-textinput,
 .devtools-searchinput {
   -moz-appearance: none;
   margin: 0 3px;
   background-color: transparent;
   border: 1px solid hsla(210,8%,5%,.6);
   border-radius: 20px;
+  background-image: -moz-linear-gradient(hsla(210,16%,76%,.15), hsla(210,16%,76%,.35));
+  padding: 3px;
+  box-shadow: 0 1px 1px hsla(210,8%,5%,.3) inset,
+              0 0 0 1px hsla(210,16%,76%,.1) inset,
+              0 1px 0 hsla(210,16%,76%,.15);
+  color: inherit;
+}
+
+.devtools-searchinput {
   background-image: url(magnifying-glass.png), -moz-linear-gradient(hsla(210,16%,76%,.15), hsla(210,16%,76%,.35));
   background-repeat: no-repeat;
   background-position: 4px center, top left, top left;
   padding-top: 0;
   padding-bottom: 0;
   -moz-padding-start: 18px;
   -moz-padding-end: 12px;
-  box-shadow: 0 1px 1px hsla(210,8%,5%,.3) inset,
-              0 0 0 1px hsla(210,16%,76%,.1) inset,
-              0 1px 0 hsla(210,16%,76%,.15);
-  color: inherit;
 }
 
 .devtools-searchinput:-moz-locale-dir(rtl) {
   background-position: calc(100% - 4px) center, top left, top left;
 }
 
 .devtools-searchinput > .textbox-input-box > .textbox-search-icons {
   display: none;
--- a/browser/themes/pinstripe/devtools/markup-view.css
+++ b/browser/themes/pinstripe/devtools/markup-view.css
@@ -47,11 +47,15 @@ li.container {
   width: 14px;
   height: 14px;
 }
 
 .expander[expanded] {
   -moz-appearance: treetwistyopen;
 }
 
+.more-nodes {
+  padding-left: 16px;
+}
+
 .styleinspector-propertyeditor {
   border: 1px solid #CCC;
 }
new file mode 100644
--- /dev/null
+++ b/browser/themes/pinstripe/downloads/allDownloadsViewOverlay.css
@@ -0,0 +1,64 @@
+richlistitem.download {
+  height: 7em;
+  margin: 0;
+  padding: 8px;
+  -moz-padding-end: 0;
+}
+
+richlistitem.download:first-child {
+  border-top: 1px solid transparent;
+}
+
+richlistitem.download:last-child {
+  border-bottom: 1px solid transparent;
+}
+
+.downloadTypeIcon {
+  -moz-margin-end: 8px;
+  /* Prevent flickering when changing states. */
+  min-height: 32px;
+  min-width: 32px;
+}
+
+.blockedIcon {
+  list-style-image: url("chrome://global/skin/icons/Error.png");
+}
+
+.downloadTarget {
+  margin-bottom: 6px;
+  cursor: inherit;
+}
+
+.downloadDetails {
+  opacity: 0.7;
+  font-size: 95%;
+  cursor: inherit;
+}
+
+.downloadButton {
+  -moz-appearance: none;
+  min-width: 0;
+  min-height: 0;
+  margin: 3px;
+  border: none;
+  padding: 5px;
+  list-style-image: url("chrome://browser/skin/downloads/buttons.png");
+}
+
+.downloadButton > .button-box {
+  padding: 0;
+}
+
+/*** Button icons ***/
+
+.downloadButton.downloadCancel {
+  -moz-image-region: rect(0px, 16px, 16px, 0px);
+}
+
+.downloadButton.downloadShow {
+  -moz-image-region: rect(16px, 16px, 32px, 0px);
+}
+
+.downloadButton.downloadRetry {
+  -moz-image-region: rect(32px, 16px, 48px, 0px);
+}
--- a/browser/themes/pinstripe/jar.mn
+++ b/browser/themes/pinstripe/jar.mn
@@ -70,16 +70,17 @@ browser.jar:
   skin/classic/browser/webRTC-shareDevice-16.png
   skin/classic/browser/webRTC-shareDevice-16@2x.png
   skin/classic/browser/webRTC-shareDevice-64.png
   skin/classic/browser/downloads/buttons.png                (downloads/buttons.png)
   skin/classic/browser/downloads/download-glow.png          (downloads/download-glow.png)
   skin/classic/browser/downloads/download-glow@2x.png       (downloads/download-glow@2x.png)
   skin/classic/browser/downloads/download-notification.png  (downloads/download-notification.png)
   skin/classic/browser/downloads/downloads.css              (downloads/downloads.css)
+  skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css)
   skin/classic/browser/feeds/subscribe.css                  (feeds/subscribe.css)
   skin/classic/browser/feeds/subscribe-ui.css               (feeds/subscribe-ui.css)
   skin/classic/browser/feeds/feedIcon.png                   (feeds/feedIcon.png)
   skin/classic/browser/feeds/feedIcon16.png                 (feeds/feedIcon16.png)
   skin/classic/browser/feeds/videoFeedIcon.png              (feeds/feedIcon.png)
   skin/classic/browser/feeds/videoFeedIcon16.png            (feeds/feedIcon16.png)
   skin/classic/browser/feeds/audioFeedIcon.png              (feeds/feedIcon.png)
   skin/classic/browser/feeds/audioFeedIcon16.png            (feeds/feedIcon16.png)
--- a/browser/themes/pinstripe/places/places.css
+++ b/browser/themes/pinstripe/places/places.css
@@ -197,76 +197,8 @@ treechildren::-moz-tree-twisty(title, se
 
 treechildren::-moz-tree-image(cutting) {
   opacity: 0.5;
 }
 
 treechildren::-moz-tree-cell-text(cutting) {
   opacity: 0.7;
 }
-
-
-/** Downloads View **/
-
-richlistitem.download {
-  height: 7em;
-  margin: 0;
-  padding: 8px;
-  -moz-padding-end: 0;
-}
-
-richlistitem.download:first-child {
-  border-top: 1px solid transparent;
-}
-
-richlistitem.download:last-child {
-  border-bottom: 1px solid transparent;
-}
-
-.downloadTypeIcon {
-  -moz-margin-end: 8px;
-  /* Prevent flickering when changing states. */
-  min-height: 32px;
-  min-width: 32px;
-}
-
-.blockedIcon {
-  list-style-image: url("chrome://global/skin/icons/Error.png");
-}
-
-.downloadTarget {
-  margin-bottom: 6px;
-  cursor: inherit;
-}
-
-.downloadDetails {
-  opacity: 0.7;
-  font-size: 95%;
-  cursor: inherit;
-}
-
-.downloadButton {
-  -moz-appearance: none;
-  min-width: 0;
-  min-height: 0;
-  margin: 3px;
-  border: none;
-  padding: 5px;
-  list-style-image: url("chrome://browser/skin/downloads/buttons.png");
-}
-
-.downloadButton > .button-box {
-  padding: 0;
-}
-
-/*** Button icons ***/
-
-.downloadButton.downloadCancel {
-  -moz-image-region: rect(0px, 16px, 16px, 0px);
-}
-
-.downloadButton.downloadShow {
-  -moz-image-region: rect(16px, 16px, 32px, 0px);
-}
-
-.downloadButton.downloadRetry {
-  -moz-image-region: rect(32px, 16px, 48px, 0px);
-}
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -3013,16 +3013,19 @@ html|*#gcli-output-frame {
   min-width: 16px;
   text-shadow: none;
   background-image: -moz-linear-gradient(top, #B4211B, #8A1915);
   border-radius: 1px;
   -moz-margin-end: 5px;
 }
 
 /* Social toolbar item */
+#social-provider-button {
+  -moz-image-region: rect(0, 16px, 16px, 0);
+}
 
 #social-provider-button > .toolbarbutton-menu-dropmarker {
   display: none;
 }
 
 #social-toolbar-item > .toolbarbutton-1 {
   padding: 5px;
   -moz-appearance: toolbarbutton;
--- a/browser/themes/winstripe/devtools/common.css
+++ b/browser/themes/winstripe/devtools/common.css
@@ -127,36 +127,42 @@
 
 .devtools-toolbarbutton[type=menu] > .toolbarbutton-menu-dropmarker,
 .devtools-toolbarbutton[type=menu-button] > .toolbarbutton-menubutton-dropmarker {
   -moz-appearance: none !important;
   list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
   -moz-box-align: center;
 }
 
-/* Search input */
+/* Text input */
 
+.devtools-textinput,
 .devtools-searchinput {
   -moz-appearance: none;
   margin: 0 3px;
   border: 1px solid hsla(211,68%,6%,.6);
   box-shadow: inset 0 1px 0 hsla(211,68%,6%,.05), 0 0 0 1px hsla(210,40%,83%,.1);
   border-radius: 2px;
   background-color: transparent;
+  background-image: -moz-linear-gradient(hsla(210,16%,76%,.15), hsla(210,16%,76%,.35));
+  padding: 3px;
+  transition-property: background-color, border-color, box-shadow;
+  transition-duration: 150ms;
+  transition-timing-function: ease;
+  color: inherit;
+}
+
+.devtools-searchinput {
   background-image: url(magnifying-glass.png), -moz-linear-gradient(hsla(210,16%,76%,.15), hsla(210,16%,76%,.35));
   background-repeat: no-repeat;
   background-position: 4px center, top left, top left;
   padding-top: 0;
   padding-bottom: 0;
   -moz-padding-start: 18px;
   -moz-padding-end: 12px;
-  transition-property: background-color, border-color, box-shadow;
-  transition-duration: 150ms;
-  transition-timing-function: ease;
-  color: inherit;
 }
 
 .devtools-searchinput[focused] {
   border-color: hsl(200,70%,40%) hsl(200,75%,37%) hsl(200,80%,35%);
   background-origin: padding-box;
   background-clip: padding-box;
   box-shadow: inset 0 0 0 1px hsla(211,68%,6%,.1);
 }
--- a/browser/themes/winstripe/devtools/markup-view.css
+++ b/browser/themes/winstripe/devtools/markup-view.css
@@ -49,11 +49,15 @@ li.container {
   background-position: center;
   background-image: url("chrome://global/skin/tree/twisty-clsd.png");
 }
 
 .expander[expanded] {
   background-image: url("chrome://global/skin/tree/twisty-open.png");
 }
 
+.more-nodes {
+  padding-left: 16px;
+}
+
 .styleinspector-propertyeditor {
   border: 1px solid #CCC;
 }
new file mode 100644
--- /dev/null
+++ b/browser/themes/winstripe/downloads/allDownloadsViewOverlay-aero.css
@@ -0,0 +1,35 @@
+/* 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/. */
+
+%define WINSTRIPE_AERO
+%include allDownloadsViewOverlay.css
+%undef WINSTRIPE_AERO
+
+@media (-moz-windows-default-theme) {
+  /*
+  -moz-appearance: menuitem is almost right, but the hover effect is not
+  transparent and is lighter than desired.
+
+  Copied from the autocomplete richlistbox styling in
+  toolkit/themes/winstripe/global/autocomplete.css
+
+  This styling should be kept in sync with the style from the above file.
+  */
+  #downloadsRichListBox > richlistitem.download[selected] {
+    color: inherit;
+    background-color: transparent;
+    /* four gradients for the bevel highlights on each edge, one for blue background */
+    background-image:
+      -moz-linear-gradient(to bottom, rgba(255,255,255,0.9) 3px, rgba(255,255,255,0) 3px),
+      -moz-linear-gradient(to right, rgba(255,255,255,0.5) 3px, rgba(255,255,255,0) 3px),
+      -moz-linear-gradient(to left, rgba(255,255,255,0.5) 3px, rgba(255,255,255,0) 3px),
+      -moz-linear-gradient(to top, rgba(255,255,255,0.4) 3px, rgba(255,255,255,0) 3px),
+      -moz-linear-gradient(to bottom, rgba(163,196,247,0.3), rgba(122,180,246,0.3));
+    background-clip: content-box;
+    border-radius: 6px;
+    outline: 1px solid rgb(124,163,206);
+    -moz-outline-radius: 3px;
+    outline-offset: -2px;
+  }
+}
copy from browser/themes/winstripe/downloads/downloads.css
copy to browser/themes/winstripe/downloads/allDownloadsViewOverlay.css
--- a/browser/themes/winstripe/downloads/downloads.css
+++ b/browser/themes/winstripe/downloads/allDownloadsViewOverlay.css
@@ -1,319 +1,65 @@
 /* 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/. */
 
-/*** Panel and outer controls ***/
-
-#downloadsPanel > .panel-arrowcontainer > .panel-arrowcontent {
-  padding: 0;
-}
-
-#downloadsListBox {
-  background-color: transparent;
-  padding: 4px;
-  color: inherit;
-}
-
-#downloadsPanel:not([hasdownloads]) > #downloadsListBox {
-  display: none;
-}
-
-#downloadsHistory {
-  background: transparent;
-  color: -moz-nativehyperlinktext;
-  cursor: pointer;
-}
-
-#downloadsHistory > .button-box {
-  margin: 1em;
-}
-
-@media (-moz-windows-default-theme) {
-  #downloadsPanel[hasdownloads] > #downloadsFooter {
-%ifdef WINSTRIPE_AERO
-    background-color: #f1f5fb;
-%else
-    background-color: hsla(216,45%,88%,.98);
-%endif
-    box-shadow: 0px 1px 2px rgb(204,214,234) inset;
-    border-bottom-left-radius: 3px;
-    border-bottom-right-radius: 3px;
-  }
+#downloadsRichListBox {
+  -moz-appearance: none;
+  margin: 0;
 }
 
-/*** Downloads Summary and List items ***/
-
-#downloadsSummary,
-richlistitem[type="download"] {
-  height: 7em;
-  -moz-padding-end: 0;
-  color: inherit;
-}
-
-#downloadsSummary {
-  padding: 8px 38px 8px 12px;
-  cursor: pointer;
-  -moz-user-focus: normal;
-}
-
-#downloadsSummary:-moz-focusring {
-  outline: 1px -moz-dialogtext dotted;
-  outline-offset: -5px;
-}
-
-#downloadsSummary > .downloadTypeIcon {
-  height: 24px;
-  width: 24px;
-  list-style-image: url("chrome://mozapps/skin/downloads/downloadIcon.png");
-}
-
-#downloadsSummaryDescription {
-  color: -moz-nativehyperlinktext;
-}
-
-richlistitem[type="download"] {
-  margin: 0;
-  border-top: 1px solid hsla(0,0%,100%,.3);
-  border-bottom: 1px solid hsla(220,18%,51%,.25);
-  background: transparent;
-  padding: 8px;
-}
-
-richlistitem[type="download"]:first-child {
-  border-top: 1px solid transparent;
-}
-
-@media (-moz-windows-default-theme) {
-  richlistitem[type="download"]:last-child {
-    border-bottom: 1px solid transparent;
-  }
-}
-
-#downloadsListBox:-moz-focusring > richlistitem[type="download"][selected] {
-  outline: 1px -moz-dialogtext dotted;
-  outline-offset: -1px;
+#downloadsRichListBox > richlistitem.download {
+  height: 6em;
+%ifndef WINSTRIPE_AERO
+  padding: 5px 8px;
+%endif
 }
 
 .downloadTypeIcon {
   -moz-margin-end: 8px;
+%ifdef WINSTRIPE_AERO
+  -moz-margin-start: 8px;
+%endif
   /* Prevent flickering when changing states. */
   min-height: 32px;
   min-width: 32px;
 }
 
 .blockedIcon {
   list-style-image: url("chrome://global/skin/icons/Error.png");
 }
 
 .downloadTarget {
-  margin-bottom: 6px;
+  margin-bottom: 3px;
   cursor: inherit;
 }
 
 .downloadDetails {
-  opacity: 0.6;
-  font-size: 90%;
+  opacity: 0.7;
+  font-size: 95%;
   cursor: inherit;
 }
 
 .downloadButton {
   -moz-appearance: none;
+  background: transparent;
   min-width: 0;
   min-height: 0;
   margin: 3px;
   border: none;
-  background: transparent;
   padding: 5px;
   list-style-image: url("chrome://browser/skin/downloads/buttons.png");
 }
 
-.downloadButton > .button-box {
-  padding: 0;
-}
-
-/*** Highlighted list items ***/
-
-richlistitem[type="download"][state="1"]:hover {
-  border-radius: 3px;
-  border-top: 1px solid hsla(0,0%,100%,.2);
-  border-bottom: 1px solid hsla(0,0%,0%,.2);
-  background-color: Highlight;
-  color: HighlightText;
-  cursor: pointer;
-}
-
-/*** Button icons ***/
+ /*** Button icons ***/
 
 .downloadButton.downloadCancel {
   -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
-.downloadButton.downloadCancel:hover {
-  -moz-image-region: rect(0px, 32px, 16px, 16px);
-}
-.downloadButton.downloadCancel:active {
-  -moz-image-region: rect(0px, 48px, 16px, 32px);
-}
 
 .downloadButton.downloadShow {
   -moz-image-region: rect(16px, 16px, 32px, 0px);
 }
-.downloadButton.downloadShow:hover {
-  -moz-image-region: rect(16px, 32px, 32px, 16px);
-}
-.downloadButton.downloadShow:active {
-  -moz-image-region: rect(16px, 48px, 32px, 32px);
-}
 
 .downloadButton.downloadRetry {
   -moz-image-region: rect(32px, 16px, 48px, 0px);
 }
-.downloadButton.downloadRetry:hover {
-  -moz-image-region: rect(32px, 32px, 48px, 16px);
-}
-.downloadButton.downloadRetry:active {
-  -moz-image-region: rect(32px, 48px, 48px, 32px);
-}
-
-%ifdef WINSTRIPE_AERO
-@media not all and (-moz-windows-default-theme) {
-%endif
-
-richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow {
-  -moz-image-region: rect(48px, 16px, 64px, 0px);
-}
-richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:hover {
-  -moz-image-region: rect(48px, 32px, 64px, 16px);
-}
-richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:active {
-  -moz-image-region: rect(48px, 48px, 64px, 32px);
-}
-
-%ifdef WINSTRIPE_AERO
-}
-%endif
-
-/*** Status and progress indicator ***/
-
-#downloads-indicator-anchor {
-  /* Makes the outermost stack element positioned, so that its contents are
-     rendered over the main browser window in the Z order.  This is required by
-     the animated event notification. */
-  position: relative;
-}
-
-/*** Main indicator icon ***/
-
-#downloads-indicator-icon {
-  background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"),
-                              0, 108, 18, 90) center no-repeat;
-  min-width: 18px;
-  min-height: 18px;
-}
-
-#downloads-indicator-icon:-moz-lwtheme-brighttext {
-  background: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"),
-                              0, 108, 18, 90) center no-repeat;
-}
-
-#downloads-indicator[attention] > #downloads-indicator-anchor > #downloads-indicator-icon {
-  background-image: url("chrome://browser/skin/downloads/download-glow.png");
-}
-
-#downloads-indicator:not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
-  background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"),
-                              0, 108, 18, 90) center no-repeat;
-  background-size: 12px;
-}
-
-#downloads-indicator:not([counter])[attention] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
-  background-image: url("chrome://browser/skin/downloads/download-glow.png");
-}
-
-/*** Event notification ***/
-
-#downloads-indicator-notification {
-  opacity: 0;
-  background: url("chrome://browser/skin/downloads/download-notification.png")
-              center no-repeat;
-  background-size: 16px;
-}
-
-@keyframes downloadsIndicatorNotificationRight {
-  from { opacity: 0; transform: translate(-128px, 128px) scale(8); }
-  20%  { opacity: .85; animation-timing-function: ease-out; }
-  to   { opacity: 0; transform: translate(0) scale(1); }
-}
-
-@keyframes downloadsIndicatorNotificationLeft {
-  from { opacity: 0; transform: translate(128px, 128px) scale(8); }
-  20%  { opacity: .85; animation-timing-function: ease-out; }
-  to   { opacity: 0; transform: translate(0) scale(1); }
-}
-
-#downloads-indicator[notification] > #downloads-indicator-anchor > #downloads-indicator-notification {
-  animation-name: downloadsIndicatorNotificationRight;
-  animation-duration: 1s;
-}
-
-#downloads-indicator[notification]:-moz-locale-dir(rtl) > #downloads-indicator-anchor > #downloads-indicator-notification {
-  animation-name: downloadsIndicatorNotificationLeft;
-}
-
-/*** Progress bar and text ***/
-
-#downloads-indicator-counter {
-  height: 9px;
-  margin: -3px 0px 0px 0px;
-  color: hsl(0,0%,30%);
-  text-shadow: hsla(0,0%,100%,.5) 0 1px;
-  font-size: 9px;
-  line-height: 9px;
-  text-align: center;
-}
-
-#downloads-indicator-counter:-moz-lwtheme-brighttext {
-  color: white;
-  text-shadow: 0 0 1px rgba(0,0,0,.7),
-               0 1px 1.5px rgba(0,0,0,.5);
-}
-
-#downloads-indicator-progress {
-  width: 16px;
-  height: 5px;
-  min-width: 0;
-  min-height: 0;
-  margin-top: 1px;
-  margin-bottom: 2px;
-  border-radius: 2px;
-  box-shadow: 0 1px 0 hsla(0,0%,100%,.4);
-}
-
-#downloads-indicator-progress > .progress-bar {
-  -moz-appearance: none;
-  min-width: 0;
-  min-height: 0;
-  background-color: rgb(90, 201, 66);
-  background-image: linear-gradient(transparent 1px, rgba(255, 255, 255, 0.4) 1px, rgba(255, 255, 255, 0.4) 2px, transparent 2px);
-  border: 1px solid;
-  border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4);
-  border-radius: 2px 0 0 2px;
-}
-
-#downloads-indicator-progress > .progress-remainder {
-  -moz-appearance: none;
-  min-width: 0;
-  min-height: 0;
-  background-image: linear-gradient(#505050, #575757);
-  border: 1px solid;
-  border-color: hsla(0,0%,0%,.6) hsla(0,0%,0%,.4) hsla(0,0%,0%,.4);
-  -moz-border-start: none;
-  border-radius: 0 2px 2px 0;
-}
-
-#downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-bar {
-  background-color: rgb(220, 230, 81);
-}
-
-#downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder {
-  background-image: linear-gradient(#4b5000, #515700);
-}
--- a/browser/themes/winstripe/jar.mn
+++ b/browser/themes/winstripe/jar.mn
@@ -60,16 +60,17 @@ browser.jar:
         skin/classic/browser/webapps-16.png
         skin/classic/browser/webapps-64.png
         skin/classic/browser/webRTC-shareDevice-16.png
         skin/classic/browser/webRTC-shareDevice-64.png
         skin/classic/browser/downloads/buttons.png                   (downloads/buttons.png)
         skin/classic/browser/downloads/download-glow.png             (downloads/download-glow.png)
         skin/classic/browser/downloads/download-notification.png     (downloads/download-notification.png)
 *       skin/classic/browser/downloads/downloads.css                 (downloads/downloads.css)
+*       skin/classic/browser/downloads/allDownloadsViewOverlay.css   (downloads/allDownloadsViewOverlay.css)
         skin/classic/browser/feeds/feedIcon.png                      (feeds/feedIcon.png)
         skin/classic/browser/feeds/feedIcon16.png                    (feeds/feedIcon16.png)
         skin/classic/browser/feeds/audioFeedIcon.png                 (feeds/feedIcon.png)
         skin/classic/browser/feeds/audioFeedIcon16.png               (feeds/feedIcon16.png)
         skin/classic/browser/feeds/videoFeedIcon.png                 (feeds/feedIcon.png)
         skin/classic/browser/feeds/videoFeedIcon16.png               (feeds/feedIcon16.png)
         skin/classic/browser/feeds/subscribe.css                     (feeds/subscribe.css)
         skin/classic/browser/feeds/subscribe-ui.css                  (feeds/subscribe-ui.css)
@@ -272,16 +273,17 @@ browser.jar:
         skin/classic/aero/browser/webapps-16.png
         skin/classic/aero/browser/webapps-64.png
         skin/classic/aero/browser/webRTC-shareDevice-16.png
         skin/classic/aero/browser/webRTC-shareDevice-64.png
         skin/classic/aero/browser/downloads/buttons.png              (downloads/buttons-aero.png)
         skin/classic/aero/browser/downloads/download-glow.png        (downloads/download-glow.png)
         skin/classic/aero/browser/downloads/download-notification.png (downloads/download-notification.png)
 *       skin/classic/aero/browser/downloads/downloads.css            (downloads/downloads-aero.css)
+*       skin/classic/aero/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay-aero.css)
         skin/classic/aero/browser/feeds/feedIcon.png                 (feeds/feedIcon-aero.png)
         skin/classic/aero/browser/feeds/feedIcon16.png               (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/audioFeedIcon.png            (feeds/feedIcon-aero.png)
         skin/classic/aero/browser/feeds/audioFeedIcon16.png          (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/videoFeedIcon.png            (feeds/feedIcon-aero.png)
         skin/classic/aero/browser/feeds/videoFeedIcon16.png          (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/subscribe.css                (feeds/subscribe.css)
         skin/classic/aero/browser/feeds/subscribe-ui.css             (feeds/subscribe-ui.css)
--- a/build/Makefile.in
+++ b/build/Makefile.in
@@ -52,22 +52,16 @@ GRE_MILESTONE = $(shell tail -n 1 $(tops
 APP_INI_DEPS = $(topsrcdir)/config/milestone.txt
 endif
 
 APP_BUILDID := $(shell cat $(DEPTH)/config/buildid)
 APP_INI_DEPS += $(DEPTH)/config/buildid
 
 DEFINES += -DGRE_MILESTONE=$(GRE_MILESTONE) -DAPP_BUILDID=$(APP_BUILDID)
 
-# Set a flag that can be used in pref files to disable features if
-# we are not building for Aurora or Nightly.
-ifeq (,$(findstring a,$(GRE_MILESTONE)))
-PREF_PPFLAGS += -DRELEASE_BUILD
-endif
-
 DEFINES += -DMOZ_APP_VERSION="$(MOZ_APP_VERSION)"
 APP_INI_DEPS += $(DEPTH)/config/autoconf.mk
 
 MOZ_SOURCE_STAMP := $(firstword $(shell cd $(topsrcdir)/$(MOZ_BUILD_APP)/.. && hg parent --template="{node|short}\n" 2>/dev/null))
 ifdef MOZ_SOURCE_STAMP
 DEFINES += -DMOZ_SOURCE_STAMP="$(MOZ_SOURCE_STAMP)"
 endif
 
@@ -148,16 +142,18 @@ leaktest.py: leaktest.py.in
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $^ > $@
 	chmod +x $@
 GARBAGE += leaktest.py
 
 ifdef MOZ_APP_BASENAME
 $(FINAL_TARGET)/application.ini: $(APP_INI_DEPS)
 
 ifdef MOZ_APP_STATIC_INI
+DEFINES += -DMOZ_APP_STATIC_INI
+
 application.ini.h: appini_header.py $(FINAL_TARGET)/application.ini
 	$(PYTHON) $^ > $@
 export:: application.ini.h
 GARBAGE += application.ini.h
 endif
 endif
 
 libs:: $(_LEAKTEST_FILES)
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -445,16 +445,18 @@ user_pref("extensions.update.enabled", f
 // Make sure opening about:addons won't hit the network
 user_pref("extensions.webservice.discoverURL", "http://%(server)s/extensions-dummy/discoveryURL");
 // Make sure AddonRepository won't hit the network
 user_pref("extensions.getAddons.maxResults", 0);
 user_pref("extensions.getAddons.get.url", "http://%(server)s/extensions-dummy/repositoryGetURL");
 user_pref("extensions.getAddons.getWithPerformance.url", "http://%(server)s/extensions-dummy/repositoryGetWithPerformanceURL");
 user_pref("extensions.getAddons.search.browseURL", "http://%(server)s/extensions-dummy/repositoryBrowseURL");
 user_pref("extensions.getAddons.search.url", "http://%(server)s/extensions-dummy/repositorySearchURL");
+// Make sure that opening the plugins check page won't hit the network
+user_pref("plugins.update.url", "http://%(server)s/plugins-dummy/updateCheckURL");
 
 // Make enablePrivilege continue to work for test code. :-(
 user_pref("security.turn_off_all_security_so_that_viruses_can_take_over_this_computer", true);
 
 // Get network events.
 user_pref("network.activity.blipIntervalMilliseconds", 250);
 """ % { "server" : self.webServer + ":" + str(self.httpPort) }
     prefs.append(part)
--- a/build/valgrind/cross-architecture.sup
+++ b/build/valgrind/cross-architecture.sup
@@ -249,8 +249,31 @@
 {
    Bug 812423
    Memcheck:Leak
    fun:malloc
    fun:_ZN2js15ArgumentsObject6createI18CopyStackFrameArgsEEPS0_P9JSContextN2JS6HandleIP8JSScriptEENS7_IP10JSFunctionEEjRT_
    fun:_ZN2js15ArgumentsObject14createExpectedEP9JSContextPNS_10StackFrameE
    ...
 }
+{
+   Bug 823782
+   Memcheck:Leak
+   fun:malloc
+   ...
+   fun:_ZN2js6ctypes7LibraryL7DeclareEP9JSContextjPN2JS5ValueE
+   ...
+}
+{
+   Bug 823782
+   Memcheck:Leak
+   fun:malloc
+   fun:_ZN2js6ctypes5CData6CreateEP9JSContextN2JS6HandleIP8JSObjectEES8_Pvb
+   ...
+}
+{
+   Bug 823782
+   Memcheck:Leak
+   fun:malloc
+   ...
+   fun:_ZN2js6ctypes10StructTypeL6CreateEP9JSContextjPN2JS5ValueE
+   ...
+}
--- a/chrome/src/nsChromeRegistryChrome.h
+++ b/chrome/src/nsChromeRegistryChrome.h
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsChromeRegistryChrome_h
 #define nsChromeRegistryChrome_h
 
 #include "nsChromeRegistry.h"
+#include "nsVoidArray.h"
 
 namespace mozilla {
 namespace dom {
 class PContentParent;
 }
 }
 
 class nsIPrefBranch;
--- a/config/makefiles/xpcshell.mk
+++ b/config/makefiles/xpcshell.mk
@@ -51,21 +51,17 @@ xpcshell-tests:
 	  --xunit-suite-name=xpcshell \
 	  --test-plugin-path=$(DIST)/plugins \
 	  $(EXTRA_TEST_ARGS) \
 	  $(LIBXUL_DIST)/bin/xpcshell \
 	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
 
 xpcshell-tests-remote: DM_TRANS?=adb
 xpcshell-tests-remote:
-	$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
-	  -I$(topsrcdir)/build \
-	  -I$(topsrcdir)/build/mobile \
-	  -I$(topsrcdir)/testing/mozbase/mozdevice/mozdevice \
-	  $(topsrcdir)/testing/xpcshell/remotexpcshelltests.py \
+	$(PYTHON) -u $(topsrcdir)/testing/xpcshell/remotexpcshelltests.py \
 	  --symbols-path=$(DIST)/crashreporter-symbols \
 	  --build-info-json=$(DEPTH)/mozinfo.json \
 	  --testing-modules-dir=$(DEPTH)/_tests/modules \
 	  $(EXTRA_TEST_ARGS) \
 	  --dm_trans=$(DM_TRANS) \
 	  --deviceIP=${TEST_DEVICE} \
 	  --objdir=$(DEPTH) \
 	  $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
--- a/configure.in
+++ b/configure.in
@@ -3990,17 +3990,17 @@ dnl = If NSS was not detected in the sys
 dnl = use the one in the source tree (mozilla/security/nss)
 dnl ========================================================
 
 MOZ_ARG_WITH_BOOL(system-nss,
 [  --with-system-nss       Use system installed NSS],
     _USE_SYSTEM_NSS=1 )
 
 if test -n "$_USE_SYSTEM_NSS"; then
-    AM_PATH_NSS(3.14.1, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
+    AM_PATH_NSS(3.14.2, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
 fi
 
 if test -n "$MOZ_NATIVE_NSS"; then
    NSS_LIBS="$NSS_LIBS -lcrmf"
 else
    NSS_CFLAGS='-I$(LIBXUL_DIST)/include/nss'
    NSS_DEP_LIBS="\
         \$(LIBXUL_DIST)/lib/\$(LIB_PREFIX)crmf.\$(LIB_SUFFIX) \
@@ -8708,24 +8708,22 @@ AC_SUBST(MOZ_PKG_SPECIAL)
 
 AC_SUBST(MOZILLA_OFFICIAL)
 
 AC_DEFINE_UNQUOTED(MOZ_TELEMETRY_DISPLAY_REV, 2)
 AC_SUBST(MOZ_TELEMETRY_DISPLAY_REV)
 
 if test "$MOZ_TELEMETRY_REPORTING"; then
     AC_DEFINE(MOZ_TELEMETRY_REPORTING)
-    # Those lines will remain commented until we are ready to enable
-    # telemetry by default on Nightly & Aurora channels.
-    #
+
     # Enable Telemetry by default for nightly and aurora channels
-    # if test "$MOZ_UPDATE_CHANNEL" = "nightly" -o \
-    #     "$MOZ_UPDATE_CHANNEL" = "aurora"; then
-    #     AC_DEFINE(MOZ_TELEMETRY_ON_BY_DEFAULT)
-    # fi
+    if test "$MOZ_UPDATE_CHANNEL" = "nightly" -o \
+        "$MOZ_UPDATE_CHANNEL" = "aurora"; then
+        AC_DEFINE(MOZ_TELEMETRY_ON_BY_DEFAULT)
+    fi
 fi
 
 dnl win32 options
 AC_SUBST(MOZ_MAPINFO)
 AC_SUBST(MOZ_BROWSE_INFO)
 AC_SUBST(MOZ_TOOLS_DIR)
 AC_SUBST(WIN32_REDIST_DIR)
 AC_SUBST(MAKENSISU)
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -453,19 +453,18 @@ public:
       nsNodeUtils::AttributeSetToCurrentValue(this, aNamespaceID, aName);
       return true;
     }
     return false;
   }
 
   virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
                            const nsAString& aValue, bool aNotify);
-  virtual nsresult SetParsedAttr(int32_t aNameSpaceID, nsIAtom* aName,
-                                 nsIAtom* aPrefix, nsAttrValue& aParsedValue,
-                                 bool aNotify);
+  nsresult SetParsedAttr(int32_t aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
+                         nsAttrValue& aParsedValue, bool aNotify);
   virtual bool GetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                          nsAString& aResult) const;
   virtual bool HasAttr(int32_t aNameSpaceID, nsIAtom* aName) const;
   // aCaseSensitive == eIgnoreCaase means ASCII case-insensitive matching.
   virtual bool AttrValueIs(int32_t aNameSpaceID, nsIAtom* aName,
                              const nsAString& aValue,
                              nsCaseTreatment aCaseSensitive) const;
   virtual bool AttrValueIs(int32_t aNameSpaceID, nsIAtom* aName,
--- a/content/base/public/Makefile.in
+++ b/content/base/public/Makefile.in
@@ -79,13 +79,12 @@ XPIDLSRCS	= \
 		nsIScriptLoaderObserver.idl  \
 		nsIDroppedLinkHandler.idl \
 		nsIImageLoadingContent.idl \
 		nsIObjectLoadingContent.idl \
 		nsIFrameLoader.idl \
 		nsIXMLHttpRequest.idl \
 		nsIContentSecurityPolicy.idl \
 		nsIMessageManager.idl \
-		nsIEventSource.idl \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -60,16 +60,17 @@ class nsIStyleSheet;
 class nsIURI;
 class nsIVariant;
 class nsIViewManager;
 class nsPresContext;
 class nsScriptLoader;
 class nsSMILAnimationController;
 class nsStyleSet;
 class nsWindowSizes;
+class nsSmallVoidArray;
 
 namespace mozilla {
 namespace css {
 class Loader;
 class ImageLoader;
 } // namespace css
 
 namespace dom {
@@ -459,18 +460,32 @@ public:
                                nsIPresShell** aInstancePtrResult) = 0;
   virtual void DeleteShell() = 0;
 
   nsIPresShell* GetShell() const
   {
     return GetBFCacheEntry() ? nullptr : mPresShell;
   }
 
+  void DisallowBFCaching()
+  {
+    NS_ASSERTION(!mBFCacheEntry, "We're already in the bfcache!");
+    mBFCacheDisallowed = true;
+  }
+
+  bool IsBFCachingAllowed() const
+  {
+    return !mBFCacheDisallowed;
+  }
+
   void SetBFCacheEntry(nsIBFCacheEntry* aEntry)
   {
+    NS_ASSERTION(IsBFCachingAllowed() || !aEntry,
+                 "You should have checked!");
+
     mBFCacheEntry = aEntry;
   }
 
   nsIBFCacheEntry* GetBFCacheEntry() const
   {
     return mBFCacheEntry;
   }
 
@@ -1911,16 +1926,19 @@ protected:
   bool mNeedStyleFlush;
 
   // True if a DOMMutationObserver is perhaps attached to a node in the document.
   bool mMayHaveDOMMutationObservers;
 
   // True if a document has loaded Mixed Active Script (see nsMixedContentBlocker.cpp)
   bool mHasMixedActiveContentLoaded;
 
+  // True if DisallowBFCaching has been called on this document.
+  bool mBFCacheDisallowed;
+
   // The document's script global object, the object from which the
   // document can get its script context and scope. This is the
   // *inner* window object.
   nsCOMPtr<nsIScriptGlobalObject> mScriptGlobalObject;
 
   // If mIsStaticDocument is true, mOriginalDocument points to the original
   // document.
   nsCOMPtr<nsIDocument> mOriginalDocument;
deleted file mode 100644
--- a/content/base/public/nsIEventSource.idl
+++ /dev/null
@@ -1,67 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * The nsIEventSource interface is the interface for server-sent
- * DOM events as described in
- * http://dev.w3.org/html5/eventsource/#eventsource
- *
- */
-
-#include "nsISupports.idl"
-
-interface nsIDOMEventListener;
-interface nsIPrincipal;
-interface nsIScriptContext;
-interface nsPIDOMWindow;
-
-[scriptable, uuid(778e5ae3-c72c-4d4b-9dc7-4a6477651957)]
-interface nsIEventSource : nsISupports
-{
-  readonly attribute DOMString url;
-
-  // ready state
-  const unsigned short CONNECTING = 0;
-  const unsigned short OPEN = 1;
-  const unsigned short CLOSED = 2;
-  readonly attribute long readyState;
-
-  // if true then cross-site Access-Control requests are made using credentials
-  // such as cookies and authorization headers. Never affects same-site
-  // requests.
-  readonly attribute boolean withCredentials;
-
-  // event handler attributes
-  [implicit_jscontext] attribute jsval onopen;
-  [implicit_jscontext] attribute jsval onmessage;
-  [implicit_jscontext] attribute jsval onerror;
-
-  /**
-   * Close the connection, if any, and set the readyState attribute to CLOSED.
-   * If the connection is already closed, the method does nothing.
-   */
-  void close();
-
-  /**
-   * Initialize the object for use from C++ code with the principal, script
-   * context, and owner window that should be used.
-   *
-   * @param principal The principal to use for the request. This must not be
-   *                  null.
-   * @param scriptContext The script context to use for the request. May be
-   *                      null.
-   * @param ownerWindow The associated window for the request. May be null.
-   * @param url The EventSource's url. This must not be empty.
-   * @param withCredentials When set to true attempts to make cross-site
-   *                        Access-Control requests with credentials such as
-   *                        cookies and authorization headers. Never affects
-   *                        same-site requests.
-   */
-  [noscript] void init(in nsIPrincipal principal,
-                       in nsIScriptContext scriptContext,
-                       in nsPIDOMWindow ownerWindow,
-                       in DOMString url,
-                       in boolean withCredentials);
-};
--- a/content/base/public/nsISelectionController.idl
+++ b/content/base/public/nsISelectionController.idl
@@ -219,17 +219,17 @@ interface nsISelectionController : nsISe
     void completeMove(in boolean forward, in boolean extend);
 
 
   /** ScrollPage will scroll the page without affecting the selection.
    *  @param aForward scroll forward or backwards in selection
    */
     void scrollPage(in boolean forward);
 
-  /** ScrolLine will scroll line up or down dependent on the boolean
+  /** ScrollLine will scroll line up or down dependent on the boolean
    *  @param aForward scroll forward or backwards in selection
    */
 	  void scrollLine(in boolean forward);
 
   /** ScrollCharacter will scroll right or left dependent on the boolean
    *  @param aRight if true will scroll right. if not will scroll left.
    */
     void scrollCharacter(in boolean right);
rename from content/base/src/nsEventSource.cpp
rename to content/base/src/EventSource.cpp
--- a/content/base/src/nsEventSource.cpp
+++ b/content/base/src/EventSource.cpp
@@ -1,17 +1,19 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "mozilla/dom/EventSource.h"
+
 #include "mozilla/DebugOnly.h"
+#include "mozilla/dom/EventSourceBinding.h"
 #include "mozilla/Util.h"
 
-#include "nsEventSource.h"
 #include "nsNetUtil.h"
 #include "nsMimeTypes.h"
 #include "nsDOMMessageEvent.h"
 #include "nsIJSContextStack.h"
 #include "nsIPromptFactory.h"
 #include "nsIWindowWatcher.h"
 #include "nsPresContext.h"
 #include "nsContentPolicyUtils.h"
@@ -28,161 +30,126 @@
 #include "nsIContentSecurityPolicy.h"
 #include "nsContentUtils.h"
 #include "mozilla/Preferences.h"
 #include "xpcpublic.h"
 #include "nsCrossSiteListenerProxy.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsDOMEventTargetHelper.h"
 #include "mozilla/Attributes.h"
-#include "nsDOMClassInfoID.h"
 #include "nsError.h"
 
-using namespace mozilla;
+namespace mozilla {
+namespace dom {
 
 #define REPLACEMENT_CHAR     (PRUnichar)0xFFFD
 #define BOM_CHAR             (PRUnichar)0xFEFF
 #define SPACE_CHAR           (PRUnichar)0x0020
 #define CR_CHAR              (PRUnichar)0x000D
 #define LF_CHAR              (PRUnichar)0x000A
 #define COLON_CHAR           (PRUnichar)0x003A
 
 #define DEFAULT_BUFFER_SIZE 4096
 
 // Reconnection time related values in milliseconds. The default one is equal
 // to the default value of the pref dom.server-events.default-reconnection-time
 #define MIN_RECONNECTION_TIME_VALUE       500
 #define DEFAULT_RECONNECTION_TIME_VALUE   5000
 #define MAX_RECONNECTION_TIME_VALUE       PR_IntervalToMilliseconds(DELAY_INTERVAL_LIMIT)
 
-nsEventSource::nsEventSource() :
+EventSource::EventSource() :
   mStatus(PARSE_STATE_OFF),
   mFrozen(false),
   mErrorLoadOnRedirect(false),
   mGoingToDispatchAllMessages(false),
   mWithCredentials(false),
   mWaitingForOnStopRequest(false),
   mLastConvertionResult(NS_OK),
-  mReadyState(nsIEventSource::CONNECTING),
+  mReadyState(CONNECTING),
   mScriptLine(0),
   mInnerWindowID(0)
 {
+  SetIsDOMBinding();
 }
 
-nsEventSource::~nsEventSource()
+EventSource::~EventSource()
 {
   Close();
 }
 
 //-----------------------------------------------------------------------------
-// nsEventSource::nsISupports
+// EventSource::nsISupports
 //-----------------------------------------------------------------------------
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsEventSource)
+NS_IMPL_CYCLE_COLLECTION_CLASS(EventSource)
 
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsEventSource)
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(EventSource)
   bool isBlack = tmp->IsBlack();
   if (isBlack || tmp->mWaitingForOnStopRequest) {
     if (tmp->mListenerManager) {
       tmp->mListenerManager->MarkForCC();
     }
     if (!isBlack && tmp->PreservingWrapper()) {
       xpc_UnmarkGrayObject(tmp->GetWrapperPreserveColor());
     }
     return true;
   }
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsEventSource)
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(EventSource)
   return tmp->IsBlack();
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
 
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsEventSource)
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(EventSource)
   return tmp->IsBlack();
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
 
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsEventSource,
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(EventSource,
                                                nsDOMEventTargetHelper)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsEventSource,
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(EventSource,
                                                   nsDOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSrc)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotificationCallbacks)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoadGroup)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannelEventSink)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHttpChannel)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimer)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnicodeDecoder)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsEventSource, nsDOMEventTargetHelper)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(EventSource, nsDOMEventTargetHelper)
   tmp->Close();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
-DOMCI_DATA(EventSource, nsEventSource)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsEventSource)
-  NS_INTERFACE_MAP_ENTRY(nsIEventSource)
-  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(EventSource)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
   NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(EventSource)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
-NS_IMPL_ADDREF_INHERITED(nsEventSource, nsDOMEventTargetHelper)
-NS_IMPL_RELEASE_INHERITED(nsEventSource, nsDOMEventTargetHelper)
-
-NS_IMPL_EVENT_HANDLER(nsEventSource, open)
-NS_IMPL_EVENT_HANDLER(nsEventSource, message)
-NS_IMPL_EVENT_HANDLER(nsEventSource, error)
+NS_IMPL_ADDREF_INHERITED(EventSource, nsDOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(EventSource, nsDOMEventTargetHelper)
 
 void
-nsEventSource::DisconnectFromOwner()
+EventSource::DisconnectFromOwner()
 {
   nsDOMEventTargetHelper::DisconnectFromOwner();
   Close();
 }
 
-//-----------------------------------------------------------------------------
-// nsEventSource::nsIEventSource
-//-----------------------------------------------------------------------------
-
-NS_IMETHODIMP
-nsEventSource::GetUrl(nsAString& aURL)
-{
-  aURL = mOriginalURL;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsEventSource::GetReadyState(int32_t *aReadyState)
+void
+EventSource::Close()
 {
-  NS_ENSURE_ARG_POINTER(aReadyState);
-  *aReadyState = mReadyState;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsEventSource::GetWithCredentials(bool *aWithCredentials)
-{
-  NS_ENSURE_ARG_POINTER(aWithCredentials);
-  *aWithCredentials = mWithCredentials;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsEventSource::Close()
-{
-  if (mReadyState == nsIEventSource::CLOSED) {
-    return NS_OK;
+  if (mReadyState == CLOSED) {
+    return;
   }
 
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   if (os) {
     os->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
     os->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC);
     os->RemoveObserver(this, DOM_WINDOW_THAWED_TOPIC);
   }
@@ -200,45 +167,46 @@ nsEventSource::Close()
     delete static_cast<Message*>(mMessagesToDispatch.PopFront());
   }
 
   mSrc = nullptr;
   mFrozen = false;
 
   mUnicodeDecoder = nullptr;
 
-  mReadyState = nsIEventSource::CLOSED;
-
-  return NS_OK;
+  mReadyState = CLOSED;
 }
 
-/**
- * This Init method should only be called by C++ consumers.
- */
-NS_IMETHODIMP
-nsEventSource::Init(nsIPrincipal* aPrincipal,
-                    nsIScriptContext* aScriptContext,
-                    nsPIDOMWindow* aOwnerWindow,
-                    const nsAString& aURL,
-                    bool aWithCredentials)
+nsresult
+EventSource::Init(nsISupports* aOwner,
+                  const nsAString& aURL,
+                  bool aWithCredentials)
 {
-  NS_ENSURE_ARG(aPrincipal);
-
-  if (mReadyState != nsIEventSource::CONNECTING || !PrefEnabled()) {
+  if (mReadyState != CONNECTING || !PrefEnabled()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
-  mPrincipal = aPrincipal;
+  nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aOwner);
+  NS_ENSURE_STATE(ownerWindow);
+  MOZ_ASSERT(ownerWindow->IsInnerWindow());
+
+  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
+  NS_ENSURE_STATE(sgo);
+  nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
+  NS_ENSURE_STATE(scriptContext);
+
+  nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
+    do_QueryInterface(aOwner);
+  NS_ENSURE_STATE(scriptPrincipal);
+  nsCOMPtr<nsIPrincipal> principal = scriptPrincipal->GetPrincipal();
+  NS_ENSURE_STATE(principal);
+
+  mPrincipal = principal;
   mWithCredentials = aWithCredentials;
-  if (aOwnerWindow) {
-    BindToOwner(aOwnerWindow->IsOuterWindow() ?
-      aOwnerWindow->GetCurrentInnerWindow() : aOwnerWindow);
-  } else {
-    BindToOwner(aOwnerWindow);
-  }
+  BindToOwner(ownerWindow);
 
   nsCOMPtr<nsIJSContextStack> stack =
     do_GetService("@mozilla.org/js/xpc/ContextStack;1");
   JSContext* cx = nullptr;
   if (stack && NS_SUCCEEDED(stack->Peek(&cx)) && cx) {
     const char *filename;
     if (nsJSUtils::GetCallingLocation(cx, &filename, &mScriptLine)) {
       mScriptFile.AssignASCII(filename);
@@ -306,107 +274,42 @@ nsEventSource::Init(nsIPrincipal* aPrinc
   // the constructor should throw a SYNTAX_ERROR only if it fails resolving the
   // url parameter, so we don't care about the InitChannelAndRequestEventSource
   // result.
   InitChannelAndRequestEventSource();
 
   return NS_OK;
 }
 
-//-----------------------------------------------------------------------------
-// nsEventSource::nsIJSNativeInitializer methods:
-//-----------------------------------------------------------------------------
-
-/**
- * This Initialize method is called from XPConnect via nsIJSNativeInitializer.
- * It is used for constructing our nsEventSource from javascript. It expects a
- * URL string parameter. Also, initializes the principal, the script context
- * and the window owner.
- */
-NS_IMETHODIMP
-nsEventSource::Initialize(nsISupports* aOwner,
-                          JSContext* aContext,
-                          JSObject* aObject,
-                          uint32_t aArgc,
-                          jsval* aArgv)
+/* virtual */ JSObject*
+EventSource::WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap)
 {
-  if (mReadyState != nsIEventSource::CONNECTING || !PrefEnabled() ||
-      aArgc < 1) {
-    return NS_ERROR_FAILURE;
-  }
-
-  JSAutoRequest ar(aContext);
-
-  JSString* jsstr = JS_ValueToString(aContext, aArgv[0]);
-  if (!jsstr) {
-    return NS_ERROR_DOM_SYNTAX_ERR;
-  }
-
-  JS::Anchor<JSString *> deleteProtector(jsstr);
-  size_t length;
-  const jschar *chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
-  if (!chars) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  nsAutoString urlParam;
-
-  urlParam.Assign(chars, length);
+  return EventSourceBinding::Wrap(aCx, aScope, this, aTriedToWrap);
+}
 
-  nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aOwner);
-  NS_ENSURE_STATE(ownerWindow);
-
-  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
-  NS_ENSURE_STATE(sgo);
-  nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
-  NS_ENSURE_STATE(scriptContext);
-
-  nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
-    do_QueryInterface(aOwner);
-  NS_ENSURE_STATE(scriptPrincipal);
-  nsCOMPtr<nsIPrincipal> principal = scriptPrincipal->GetPrincipal();
-  NS_ENSURE_STATE(principal);
-
-  bool withCredentialsParam = false;
-  if (aArgc >= 2) {
-    NS_ENSURE_TRUE(!JSVAL_IS_PRIMITIVE(aArgv[1]), NS_ERROR_INVALID_ARG);
-
-    JSObject *obj = JSVAL_TO_OBJECT(aArgv[1]);
-    NS_ASSERTION(obj, "obj shouldn't be null!!");
-
-    JSBool hasProperty = JS_FALSE;
-    NS_ENSURE_TRUE(JS_HasProperty(aContext, obj, "withCredentials",
-                                  &hasProperty), NS_ERROR_FAILURE);
-
-    if (hasProperty) {
-      jsval withCredentialsVal;
-      NS_ENSURE_TRUE(JS_GetProperty(aContext, obj, "withCredentials",
-                                    &withCredentialsVal), NS_ERROR_FAILURE);
-
-      JSBool withCredentials = JS_FALSE;
-      NS_ENSURE_TRUE(JS_ValueToBoolean(aContext, withCredentialsVal,
-                                       &withCredentials), NS_ERROR_FAILURE);
-      withCredentialsParam = !!withCredentials;
-    }
-  }
-
-  return Init(principal, scriptContext, ownerWindow,
-              urlParam, withCredentialsParam);
+/* static */ already_AddRefed<EventSource>
+EventSource::Constructor(nsISupports* aOwner, const nsAString& aURL,
+                         const EventSourceInit& aEventSourceInitDict,
+                         ErrorResult& aRv)
+{
+  nsRefPtr<EventSource> eventSource = new EventSource();
+  aRv = eventSource->Init(aOwner, aURL, aEventSourceInitDict.mWithCredentials);
+  return eventSource.forget();
 }
 
 //-----------------------------------------------------------------------------
-// nsEventSource::nsIObserver
+// EventSource::nsIObserver
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
-nsEventSource::Observe(nsISupports* aSubject,
-                       const char* aTopic,
-                       const PRUnichar* aData)
+EventSource::Observe(nsISupports* aSubject,
+                     const char* aTopic,
+                     const PRUnichar* aData)
 {
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return NS_OK;
   }
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aSubject);
   if (!GetOwner() || window != GetOwner()) {
     return NS_OK;
   }
 
@@ -420,22 +323,22 @@ nsEventSource::Observe(nsISupports* aSub
   } else if (strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC) == 0) {
     Close();
   }
 
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
-// nsEventSource::nsIStreamListener
+// EventSource::nsIStreamListener
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
-nsEventSource::OnStartRequest(nsIRequest *aRequest,
-                              nsISupports *ctxt)
+EventSource::OnStartRequest(nsIRequest *aRequest,
+                            nsISupports *ctxt)
 {
   nsresult rv = CheckHealthOfRequestCallback(aRequest);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool requestSucceeded;
@@ -456,40 +359,40 @@ nsEventSource::OnStartRequest(nsIRequest
     // Don't give this channel the system principal.
     principal = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   rv = httpChannel->SetOwner(principal);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIRunnable> event =
-    NS_NewRunnableMethod(this, &nsEventSource::AnnounceConnection);
+    NS_NewRunnableMethod(this, &EventSource::AnnounceConnection);
   NS_ENSURE_STATE(event);
 
   rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mStatus = PARSE_STATE_BEGIN_OF_STREAM;
 
   return NS_OK;
 }
 
 // this method parses the characters as they become available instead of
 // buffering them.
 NS_METHOD
-nsEventSource::StreamReaderFunc(nsIInputStream *aInputStream,
-                                void *aClosure,
-                                const char *aFromRawSegment,
-                                uint32_t aToOffset,
-                                uint32_t aCount,
-                                uint32_t *aWriteCount)
+EventSource::StreamReaderFunc(nsIInputStream *aInputStream,
+                              void *aClosure,
+                              const char *aFromRawSegment,
+                              uint32_t aToOffset,
+                              uint32_t aCount,
+                              uint32_t *aWriteCount)
 {
-  nsEventSource* thisObject = static_cast<nsEventSource*>(aClosure);
+  EventSource* thisObject = static_cast<EventSource*>(aClosure);
   if (!thisObject || !aWriteCount) {
-    NS_WARNING("nsEventSource cannot read from stream: no aClosure or aWriteCount");
+    NS_WARNING("EventSource cannot read from stream: no aClosure or aWriteCount");
     return NS_ERROR_FAILURE;
   }
 
   *aWriteCount = 0;
 
   int32_t srcCount, outCount;
   PRUnichar out[2];
   nsresult rv;
@@ -514,40 +417,40 @@ nsEventSource::StreamReaderFunc(nsIInput
            thisObject->mLastConvertionResult != NS_PARTIAL_MORE_INPUT &&
            thisObject->mLastConvertionResult != NS_OK);
 
   *aWriteCount = aCount;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsEventSource::OnDataAvailable(nsIRequest *aRequest,
-                               nsISupports *aContext,
-                               nsIInputStream *aInputStream,
-                               uint64_t aOffset,
-                               uint32_t aCount)
+EventSource::OnDataAvailable(nsIRequest *aRequest,
+                             nsISupports *aContext,
+                             nsIInputStream *aInputStream,
+                             uint64_t aOffset,
+                             uint32_t aCount)
 {
   NS_ENSURE_ARG_POINTER(aInputStream);
 
   nsresult rv = CheckHealthOfRequestCallback(aRequest);
   NS_ENSURE_SUCCESS(rv, rv);
 
   uint32_t totalRead;
-  return aInputStream->ReadSegments(nsEventSource::StreamReaderFunc, this,
+  return aInputStream->ReadSegments(EventSource::StreamReaderFunc, this,
                                     aCount, &totalRead);
 }
 
 NS_IMETHODIMP
-nsEventSource::OnStopRequest(nsIRequest *aRequest,
-                             nsISupports *aContext,
-                             nsresult aStatusCode)
+EventSource::OnStopRequest(nsIRequest *aRequest,
+                           nsISupports *aContext,
+                           nsresult aStatusCode)
 {
   mWaitingForOnStopRequest = false;
 
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return NS_ERROR_ABORT;
   }
 
   if (NS_FAILED(aStatusCode)) {
     DispatchFailConnection();
     return aStatusCode;
   }
 
@@ -582,33 +485,33 @@ nsEventSource::OnStopRequest(nsIRequest 
       case PARSE_STATE_OFF:
       case PARSE_STATE_BEGIN_OF_STREAM:
       case PARSE_STATE_BOM_WAS_READ:
         break;
     }
   }
 
   nsCOMPtr<nsIRunnable> event =
-    NS_NewRunnableMethod(this, &nsEventSource::ReestablishConnection);
+    NS_NewRunnableMethod(this, &EventSource::ReestablishConnection);
   NS_ENSURE_STATE(event);
 
   rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return healthOfRequestResult;
 }
 
 /**
  * Simple helper class that just forwards the redirect callback back
- * to the nsEventSource.
+ * to the EventSource.
  */
 class AsyncVerifyRedirectCallbackFwr MOZ_FINAL : public nsIAsyncVerifyRedirectCallback
 {
 public:
-  AsyncVerifyRedirectCallbackFwr(nsEventSource* aEventsource)
+  AsyncVerifyRedirectCallbackFwr(EventSource* aEventsource)
     : mEventSource(aEventsource)
   {
   }
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(AsyncVerifyRedirectCallbackFwr)
 
   // nsIAsyncVerifyRedirectCallback implementation
@@ -619,17 +522,17 @@ public:
       mEventSource->mErrorLoadOnRedirect = true;
       mEventSource->DispatchFailConnection();
     }
 
     return NS_OK;
   }
 
 private:
-  nsRefPtr<nsEventSource> mEventSource;
+  nsRefPtr<EventSource> mEventSource;
 };
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(AsyncVerifyRedirectCallbackFwr)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AsyncVerifyRedirectCallbackFwr)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventSource)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
@@ -641,24 +544,24 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(AsyncVerifyRedirectCallbackFwr)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(AsyncVerifyRedirectCallbackFwr)
 
 //-----------------------------------------------------------------------------
-// nsEventSource::nsIChannelEventSink
+// EventSource::nsIChannelEventSink
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
-nsEventSource::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
-                                      nsIChannel *aNewChannel,
-                                      uint32_t    aFlags,
-                                      nsIAsyncVerifyRedirectCallback *aCallback)
+EventSource::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
+                                    nsIChannel *aNewChannel,
+                                    uint32_t    aFlags,
+                                    nsIAsyncVerifyRedirectCallback *aCallback)
 {
   nsCOMPtr<nsIRequest> aOldRequest = do_QueryInterface(aOldChannel);
   NS_PRECONDITION(aOldRequest, "Redirect from a null request?");
 
   nsresult rv = CheckHealthOfRequestCallback(aOldRequest);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_PRECONDITION(aNewChannel, "Redirect without a channel?");
@@ -692,17 +595,17 @@ nsEventSource::AsyncOnChannelRedirect(ns
     }
     return rv;
   }
   OnRedirectVerifyCallback(NS_OK);
   return NS_OK;
 }
 
 nsresult
-nsEventSource::OnRedirectVerifyCallback(nsresult aResult)
+EventSource::OnRedirectVerifyCallback(nsresult aResult)
 {
   NS_ABORT_IF_FALSE(mRedirectCallback, "mRedirectCallback not set in callback");
   NS_ABORT_IF_FALSE(mNewRedirectChannel,
                     "mNewRedirectChannel not set in callback");
 
   NS_ENSURE_SUCCESS(aResult, aResult);
 
   // update our channel
@@ -722,22 +625,22 @@ nsEventSource::OnRedirectVerifyCallback(
 
   mRedirectCallback->OnRedirectVerifyCallback(aResult);
   mRedirectCallback = nullptr;
 
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
-// nsEventSource::nsIInterfaceRequestor
+// EventSource::nsIInterfaceRequestor
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
-nsEventSource::GetInterface(const nsIID & aIID,
-                            void **aResult)
+EventSource::GetInterface(const nsIID & aIID,
+                          void **aResult)
 {
   // Make sure to return ourselves for the channel event sink interface,
   // no matter what.  We can forward these to mNotificationCallbacks
   // if it wants to get notifications for them.  But we
   // need to see these notifications for proper functioning.
   if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
     mChannelEventSink = do_GetInterface(mNotificationCallbacks);
     *aResult = static_cast<nsIChannelEventSink*>(this);
@@ -775,23 +678,23 @@ nsEventSource::GetInterface(const nsIID 
     return wwatch->GetPrompt(window, aIID, aResult);
   }
 
   return QueryInterface(aIID, aResult);
 }
 
 // static
 bool
-nsEventSource::PrefEnabled()
+EventSource::PrefEnabled()
 {
   return Preferences::GetBool("dom.server-events.enabled", false);
 }
 
 nsresult
-nsEventSource::GetBaseURI(nsIURI **aBaseURI)
+EventSource::GetBaseURI(nsIURI **aBaseURI)
 {
   NS_ENSURE_ARG_POINTER(aBaseURI);
 
   *aBaseURI = nullptr;
 
   nsCOMPtr<nsIURI> baseURI;
 
   // first we try from document->GetBaseURI()
@@ -811,17 +714,17 @@ nsEventSource::GetBaseURI(nsIURI **aBase
 
   NS_ENSURE_STATE(baseURI);
 
   baseURI.forget(aBaseURI);
   return NS_OK;
 }
 
 nsresult
-nsEventSource::SetupHttpChannel()
+EventSource::SetupHttpChannel()
 {
   mHttpChannel->SetRequestMethod(NS_LITERAL_CSTRING("GET"));
 
   /* set the http request headers */
 
   mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
     NS_LITERAL_CSTRING(TEXT_EVENT_STREAM), false);
 
@@ -838,19 +741,19 @@ nsEventSource::SetupHttpChannel()
     rv = mHttpChannel->SetReferrer(codebase);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 nsresult
-nsEventSource::InitChannelAndRequestEventSource()
+EventSource::InitChannelAndRequestEventSource()
 {
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return NS_ERROR_ABORT;
   }
 
   // eventsource validation
 
   if (!CheckCanRequestSrc()) {
     DispatchFailConnection();
     return NS_ERROR_DOM_SECURITY_ERR;
@@ -897,32 +800,32 @@ nsEventSource::InitChannelAndRequestEven
   rv = mHttpChannel->AsyncOpen(listener, nullptr);
   if (NS_SUCCEEDED(rv)) {
     mWaitingForOnStopRequest = true;
   }
   return rv;
 }
 
 void
-nsEventSource::AnnounceConnection()
+EventSource::AnnounceConnection()
 {
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return;
   }
 
-  if (mReadyState != nsIEventSource::CONNECTING) {
+  if (mReadyState != CONNECTING) {
     NS_WARNING("Unexpected mReadyState!!!");
     return;
   }
 
   // When a user agent is to announce the connection, the user agent must set
   // the readyState attribute to OPEN and queue a task to fire a simple event
   // named open at the EventSource object.
 
-  mReadyState = nsIEventSource::OPEN;
+  mReadyState = OPEN;
 
   nsresult rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return;
   }
 
   nsCOMPtr<nsIDOMEvent> event;
   rv = NS_NewDOMEvent(getter_AddRefs(event), nullptr, nullptr);
@@ -943,17 +846,17 @@ nsEventSource::AnnounceConnection()
   rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to dispatch the open event!!!");
     return;
   }
 }
 
 nsresult
-nsEventSource::ResetConnection()
+EventSource::ResetConnection()
 {
   if (mHttpChannel) {
     mHttpChannel->Cancel(NS_ERROR_ABORT);
   }
 
   if (mUnicodeDecoder) {
     mUnicodeDecoder->Reset();
   }
@@ -961,29 +864,29 @@ nsEventSource::ResetConnection()
 
   mHttpChannel = nullptr;
   mNotificationCallbacks = nullptr;
   mChannelEventSink = nullptr;
   mStatus = PARSE_STATE_OFF;
   mRedirectCallback = nullptr;
   mNewRedirectChannel = nullptr;
 
-  mReadyState = nsIEventSource::CONNECTING;
+  mReadyState = CONNECTING;
 
   return NS_OK;
 }
 
 void
-nsEventSource::ReestablishConnection()
+EventSource::ReestablishConnection()
 {
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return;
   }
 
-  if (mReadyState != nsIEventSource::OPEN) {
+  if (mReadyState != OPEN) {
     NS_WARNING("Unexpected mReadyState!!!");
     return;
   }
 
   nsresult rv = ResetConnection();
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to reset the connection!!!");
     return;
@@ -1019,19 +922,19 @@ nsEventSource::ReestablishConnection()
   rv = SetReconnectionTimeout();
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to set the timeout for reestablishing the connection!!!");
     return;
   }
 }
 
 nsresult
-nsEventSource::SetReconnectionTimeout()
+EventSource::SetReconnectionTimeout()
 {
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return NS_ERROR_ABORT;
   }
 
   // the timer will be used whenever the requests are going finished.
   if (!mTimer) {
     mTimer = do_CreateInstance("@mozilla.org/timer;1");
     NS_ENSURE_STATE(mTimer);
   }
@@ -1040,20 +943,20 @@ nsEventSource::SetReconnectionTimeout()
                                              mReconnectionTime,
                                              nsITimer::TYPE_ONE_SHOT);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
-nsEventSource::PrintErrorOnConsole(const char *aBundleURI,
-                                   const PRUnichar *aError,
-                                   const PRUnichar **aFormatStrings,
-                                   uint32_t aFormatStringsLen)
+EventSource::PrintErrorOnConsole(const char *aBundleURI,
+                                 const PRUnichar *aError,
+                                 const PRUnichar **aFormatStrings,
+                                 uint32_t aFormatStringsLen)
 {
   nsCOMPtr<nsIStringBundleService> bundleService =
     mozilla::services::GetStringBundleService();
   NS_ENSURE_STATE(bundleService);
 
   nsCOMPtr<nsIStringBundle> strBundle;
   nsresult rv =
     bundleService->CreateBundle(aBundleURI, getter_AddRefs(strBundle));
@@ -1089,53 +992,53 @@ nsEventSource::PrintErrorOnConsole(const
   // print the error message directly to the JS console
   rv = console->LogMessage(errObj);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
-nsEventSource::ConsoleError()
+EventSource::ConsoleError()
 {
   nsAutoCString targetSpec;
   nsresult rv = mSrc->GetSpec(targetSpec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ConvertUTF8toUTF16 specUTF16(targetSpec);
   const PRUnichar *formatStrings[] = { specUTF16.get() };
 
-  if (mReadyState == nsIEventSource::CONNECTING) {
+  if (mReadyState == CONNECTING) {
     rv = PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
                              NS_LITERAL_STRING("connectionFailure").get(),
                              formatStrings, ArrayLength(formatStrings));
   } else {
     rv = PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
                              NS_LITERAL_STRING("netInterrupt").get(),
                              formatStrings, ArrayLength(formatStrings));
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
-nsEventSource::DispatchFailConnection()
+EventSource::DispatchFailConnection()
 {
   nsCOMPtr<nsIRunnable> event =
-    NS_NewRunnableMethod(this, &nsEventSource::FailConnection);
+    NS_NewRunnableMethod(this, &EventSource::FailConnection);
   NS_ENSURE_STATE(event);
 
   return NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
 }
 
 void
-nsEventSource::FailConnection()
+EventSource::FailConnection()
 {
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return;
   }
 
   nsresult rv = ConsoleError();
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to print to the console error");
   }
 
@@ -1169,19 +1072,19 @@ nsEventSource::FailConnection()
   rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to dispatch the error event!!!");
     return;
   }
 }
 
 bool
-nsEventSource::CheckCanRequestSrc(nsIURI* aSrc)
+EventSource::CheckCanRequestSrc(nsIURI* aSrc)
 {
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return false;
   }
 
   bool isValidURI = false;
   bool isValidContentLoadPolicy = false;
   bool isValidProtocol = false;
 
   nsCOMPtr<nsIURI> srcToTest = aSrc ? aSrc : mSrc.get();
@@ -1227,78 +1130,78 @@ nsEventSource::CheckCanRequestSrc(nsIURI
                       targetURIScheme.EqualsLiteral("https");
   }
 
   return isValidURI && isValidContentLoadPolicy && isValidProtocol;
 }
 
 // static
 void
-nsEventSource::TimerCallback(nsITimer* aTimer, void* aClosure)
+EventSource::TimerCallback(nsITimer* aTimer, void* aClosure)
 {
-  nsRefPtr<nsEventSource> thisObject = static_cast<nsEventSource*>(aClosure);
+  nsRefPtr<EventSource> thisObject = static_cast<EventSource*>(aClosure);
 
-  if (thisObject->mReadyState == nsIEventSource::CLOSED) {
+  if (thisObject->mReadyState == CLOSED) {
     return;
   }
 
   NS_PRECONDITION(!thisObject->mHttpChannel,
                   "the channel hasn't been cancelled!!");
 
   if (!thisObject->mFrozen) {
     nsresult rv = thisObject->InitChannelAndRequestEventSource();
     if (NS_FAILED(rv)) {
       NS_WARNING("thisObject->InitChannelAndRequestEventSource() failed");
       return;
     }
   }
 }
 
 nsresult
-nsEventSource::Thaw()
+EventSource::Thaw()
 {
-  if (mReadyState == nsIEventSource::CLOSED || !mFrozen) {
+  if (mReadyState == CLOSED || !mFrozen) {
     return NS_OK;
   }
 
   NS_ASSERTION(!mHttpChannel, "the connection hasn't been closed!!!");
 
   mFrozen = false;
   nsresult rv;
   if (!mGoingToDispatchAllMessages && mMessagesToDispatch.GetSize() > 0) {
     nsCOMPtr<nsIRunnable> event =
-      NS_NewRunnableMethod(this, &nsEventSource::DispatchAllMessageEvents);
+      NS_NewRunnableMethod(this, &EventSource::DispatchAllMessageEvents);
     NS_ENSURE_STATE(event);
 
     mGoingToDispatchAllMessages = true;
 
     rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   rv = InitChannelAndRequestEventSource();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
-nsEventSource::Freeze()
+EventSource::Freeze()
 {
-  if (mReadyState == nsIEventSource::CLOSED || mFrozen) {
+  if (mReadyState == CLOSED || mFrozen) {
     return NS_OK;
   }
 
   NS_ASSERTION(!mHttpChannel, "the connection hasn't been closed!!!");
   mFrozen = true;
   return NS_OK;
 }
 
 nsresult
-nsEventSource::DispatchCurrentMessageEvent()
+EventSource::DispatchCurrentMessageEvent()
 {
   nsAutoPtr<Message> message(new Message());
   *message = mCurrentMessage;
 
   ClearFields();
 
   if (message->mData.IsEmpty()) {
     return NS_OK;
@@ -1320,31 +1223,31 @@ nsEventSource::DispatchCurrentMessageEve
   int32_t sizeBefore = mMessagesToDispatch.GetSize();
   mMessagesToDispatch.Push(message.forget());
   NS_ENSURE_TRUE(mMessagesToDispatch.GetSize() == sizeBefore + 1,
                  NS_ERROR_OUT_OF_MEMORY);
 
 
   if (!mGoingToDispatchAllMessages) {
     nsCOMPtr<nsIRunnable> event =
-      NS_NewRunnableMethod(this, &nsEventSource::DispatchAllMessageEvents);
+      NS_NewRunnableMethod(this, &EventSource::DispatchAllMessageEvents);
     NS_ENSURE_STATE(event);
 
     mGoingToDispatchAllMessages = true;
 
     return NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
   }
 
   return NS_OK;
 }
 
 void
-nsEventSource::DispatchAllMessageEvents()
+EventSource::DispatchAllMessageEvents()
 {
-  if (mReadyState == nsIEventSource::CLOSED || mFrozen) {
+  if (mReadyState == CLOSED || mFrozen) {
     return;
   }
 
   mGoingToDispatchAllMessages = false;
 
   nsresult rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return;
@@ -1404,32 +1307,32 @@ nsEventSource::DispatchAllMessageEvents(
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to dispatch the message event!!!");
       return;
     }
   }
 }
 
 nsresult
-nsEventSource::ClearFields()
+EventSource::ClearFields()
 {
   // mLastEventID and mReconnectionTime must be cached
 
   mCurrentMessage.mEventName.Truncate();
   mCurrentMessage.mLastEventID.Truncate();
   mCurrentMessage.mData.Truncate();
 
   mLastFieldName.Truncate();
   mLastFieldValue.Truncate();
 
   return NS_OK;
 }
 
 nsresult
-nsEventSource::SetFieldAndClear()
+EventSource::SetFieldAndClear()
 {
   if (mLastFieldName.IsEmpty()) {
     mLastFieldValue.Truncate();
     return NS_OK;
   }
 
   PRUnichar first_char;
   first_char = mLastFieldName.CharAt(0);
@@ -1491,42 +1394,42 @@ nsEventSource::SetFieldAndClear()
 
   mLastFieldName.Truncate();
   mLastFieldValue.Truncate();
 
   return NS_OK;
 }
 
 nsresult
-nsEventSource::CheckHealthOfRequestCallback(nsIRequest *aRequestCallback)
+EventSource::CheckHealthOfRequestCallback(nsIRequest *aRequestCallback)
 {
   // check if we have been closed or if the request has been canceled
   // or if we have been frozen
-  if (mReadyState == nsIEventSource::CLOSED || !mHttpChannel ||
+  if (mReadyState == CLOSED || !mHttpChannel ||
       mFrozen || mErrorLoadOnRedirect) {
     return NS_ERROR_ABORT;
   }
 
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequestCallback);
   NS_ENSURE_STATE(httpChannel);
 
   if (httpChannel != mHttpChannel) {
     NS_WARNING("wrong channel from request callback");
     return NS_ERROR_ABORT;
   }
 
   return NS_OK;
 }
 
 nsresult
-nsEventSource::ParseCharacter(PRUnichar aChr)
+EventSource::ParseCharacter(PRUnichar aChr)
 {
   nsresult rv;
 
-  if (mReadyState == nsIEventSource::CLOSED) {
+  if (mReadyState == CLOSED) {
     return NS_ERROR_ABORT;
   }
 
   switch (mStatus)
   {
     case PARSE_STATE_OFF:
       NS_ERROR("Invalid state");
       return NS_ERROR_FAILURE;
@@ -1659,8 +1562,11 @@ nsEventSource::ParseCharacter(PRUnichar 
         mStatus = PARSE_STATE_FIELD_NAME;
       }
 
       break;
   }
 
   return NS_OK;
 }
+
+} // namespace dom
+} // namespace mozilla
rename from content/base/src/nsEventSource.h
rename to content/base/src/EventSource.h
--- a/content/base/src/nsEventSource.h
+++ b/content/base/src/EventSource.h
@@ -5,21 +5,19 @@
 
 /*
  * This implementation has support only for http requests. It is because the
  * spec has defined event streams only for http. HTTP is required because
  * this implementation uses some http headers: "Last-Event-ID", "Cache-Control"
  * and "Accept".
  */
 
-#ifndef nsEventSource_h__
-#define nsEventSource_h__
+#ifndef mozilla_dom_EventSource_h
+#define mozilla_dom_EventSource_h
 
-#include "nsIEventSource.h"
-#include "nsIJSNativeInitializer.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsIObserver.h"
 #include "nsIStreamListener.h"
 #include "nsIChannelEventSink.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsITimer.h"
 #include "nsIHttpChannel.h"
 #include "nsWeakReference.h"
@@ -28,54 +26,98 @@
 
 #define NS_EVENTSOURCE_CID                          \
  { /* 755e2d2d-a836-4539-83f4-16b51156341f */       \
   0x755e2d2d, 0xa836, 0x4539,                       \
  {0x83, 0xf4, 0x16, 0xb5, 0x11, 0x56, 0x34, 0x1f} }
 
 #define NS_EVENTSOURCE_CONTRACTID "@mozilla.org/eventsource;1"
 
-class AsyncVerifyRedirectCallbackFwr;
-class nsAutoClearFields;
+class nsPIDOMWindow;
+
+namespace mozilla {
+
+class ErrorResult;
+
+namespace dom {
 
-class nsEventSource: public nsDOMEventTargetHelper,
-                     public nsIEventSource,
-                     public nsIJSNativeInitializer,
-                     public nsIObserver,
-                     public nsIStreamListener,
-                     public nsIChannelEventSink,
-                     public nsIInterfaceRequestor,
-                     public nsSupportsWeakReference
+class AsyncVerifyRedirectCallbackFwr;
+struct EventSourceInit;
+
+class EventSource : public nsDOMEventTargetHelper
+                  , public nsIObserver
+                  , public nsIStreamListener
+                  , public nsIChannelEventSink
+                  , public nsIInterfaceRequestor
+                  , public nsSupportsWeakReference
 {
 friend class AsyncVerifyRedirectCallbackFwr;
 
 public:
-  nsEventSource();
-  virtual ~nsEventSource();
+  EventSource();
+  virtual ~EventSource();
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED(nsEventSource,
+  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED(EventSource,
                                                                    nsDOMEventTargetHelper)
 
-  NS_DECL_NSIEVENTSOURCE
-
-  // nsIJSNativeInitializer
-  NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
-                        uint32_t argc, jsval* argv);
-
   NS_DECL_NSIOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSICHANNELEVENTSINK
   NS_DECL_NSIINTERFACEREQUESTOR
 
+  // nsWrapperCache
+  virtual JSObject*
+  WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap) MOZ_OVERRIDE;
+
+  // WebIDL
+  nsPIDOMWindow*
+  GetParentObject() const
+  {
+    return GetOwner();
+  }
+  static already_AddRefed<EventSource>
+  Constructor(nsISupports* aOwner, const nsAString& aURL,
+              const EventSourceInit& aEventSourceInitDict,
+              ErrorResult& aRv);
+
+  void GetUrl(nsAString& aURL) const
+  {
+    aURL = mOriginalURL;
+  }
+  bool WithCredentials() const
+  {
+    return mWithCredentials;
+  }
+
+  enum {
+    CONNECTING = 0U,
+    OPEN = 1U,
+    CLOSED = 2U
+  };
+  uint16_t ReadyState() const
+  {
+    return mReadyState;
+  }
+
+  IMPL_EVENT_HANDLER(open)
+  IMPL_EVENT_HANDLER(message)
+  IMPL_EVENT_HANDLER(error)
+  void Close();
+
   // Determine if preferences allow EventSource
   static bool PrefEnabled();
 
   virtual void DisconnectFromOwner();
+
 protected:
+  nsresult Init(nsISupports* aOwner,
+                const nsAString& aURL,
+                bool aWithCredentials);
+
   nsresult GetBaseURI(nsIURI **aBaseURI);
 
   nsresult SetupHttpChannel();
   nsresult InitChannelAndRequestEventSource();
   nsresult ResetConnection();
   nsresult DispatchFailConnection();
   nsresult SetReconnectionTimeout();
 
@@ -200,17 +242,17 @@ protected:
    */
   nsCOMPtr<nsIInterfaceRequestor> mNotificationCallbacks;
   nsCOMPtr<nsIChannelEventSink>   mChannelEventSink;
 
   nsCOMPtr<nsIHttpChannel> mHttpChannel;
 
   nsCOMPtr<nsITimer> mTimer;
 
-  int32_t mReadyState;
+  uint16_t mReadyState;
   nsString mOriginalURL;
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsString mOrigin;
 
   uint32_t mRedirectFlags;
   nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
   nsCOMPtr<nsIChannel> mNewRedirectChannel;
@@ -221,13 +263,16 @@ protected:
   // - the ID of the inner window where the script lives. Note that this may not
   //   be the same as the Event Source owner window.
   // These attributes are used for error reporting.
   nsString mScriptFile;
   uint32_t mScriptLine;
   uint64_t mInnerWindowID;
 
 private:
-  nsEventSource(const nsEventSource& x);   // prevent bad usage
-  nsEventSource& operator=(const nsEventSource& x);
+  EventSource(const EventSource& x);   // prevent bad usage
+  EventSource& operator=(const EventSource& x);
 };
 
-#endif // nsEventSource_h__
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_EventSource_h
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -43,23 +43,26 @@ EXPORTS		= \
 		$(NULL)
 
 EXPORTS_NAMESPACES = mozilla/dom
 
 EXPORTS_mozilla/dom = \
   Comment.h \
   DocumentFragment.h \
   DOMImplementation.h \
+  EventSource.h \
   Link.h \
   $(NULL)
 
 CPPSRCS		= \
 		Comment.cpp \
 		DirectionalityUtils.cpp \
 		DOMImplementation.cpp \
+		EventSource.cpp \
+		FileIOObject.cpp \
 		nsAtomListUtils.cpp \
 		nsAttrAndChildArray.cpp \
 		nsAttrValue.cpp \
 		nsAttrValueOrString.cpp \
 		nsCCUncollectableMarker.cpp \
 		nsChannelPolicy.cpp \
 		nsContentAreaDragDrop.cpp \
 		nsContentIterator.cpp \
@@ -128,18 +131,16 @@ CPPSRCS		= \
 		nsXMLNameSpaceMap.cpp \
 		FragmentOrElement.cpp \
 		Link.cpp \
 		nsHostObjectProtocolHandler.cpp \
 		nsHostObjectURI.cpp \
 		nsFrameMessageManager.cpp \
 		nsInProcessTabChildGlobal.cpp \
 		ThirdPartyUtil.cpp \
-		nsEventSource.cpp \
-		FileIOObject.cpp \
 		nsDOMMutationObserver.cpp \
 		nsMixedContentBlocker.cpp \
 		$(NULL)
 
 ifdef MOZ_WEBRTC
 EXPORTS += nsDOMDataChannel.h
 CPPSRCS += nsDOMDataChannel.cpp
 LOCAL_INCLUDES += \
@@ -195,16 +196,17 @@ LOCAL_INCLUDES += \
   -I$(topsrcdir)/image/src \
   -I$(topsrcdir)/js/xpconnect/src \
   -I$(topsrcdir)/layout/base \
   -I$(topsrcdir)/layout/generic \
   -I$(topsrcdir)/layout/style \
   -I$(topsrcdir)/layout/svg \
   -I$(topsrcdir)/layout/xul/base/src \
   -I$(topsrcdir)/netwerk/base/src \
+  -I$(topsrcdir)/js/xpconnect/wrappers \
   $(NULL)
 
 DEFINES += -D_IMPL_NS_LAYOUT
 DEFINES += -DHB_DONT_DEFINE_STDINT
 
 # gcc requires -msse2 for this file since it uses SSE2 intrinsics.  (See bug
 # 585538 comment 12.)
 ifneq (,$(INTEL_ARCHITECTURE))
--- a/content/base/src/WebSocket.cpp
+++ b/content/base/src/WebSocket.cpp
@@ -186,27 +186,25 @@ WebSocket::ConsoleError()
                           formatStrings, ArrayLength(formatStrings));
     }
   }
   /// todo some specific errors - like for message too large
   return rv;
 }
 
 
-nsresult
+void
 WebSocket::FailConnection(uint16_t aReasonCode,
                           const nsACString& aReasonString)
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
   ConsoleError();
   mFailed = true;
   CloseConnection(aReasonCode, aReasonString);
-
-  return NS_OK;
 }
 
 nsresult
 WebSocket::Disconnect()
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
   if (mDisconnected)
@@ -857,18 +855,17 @@ WebSocket::CreateAndDispatchSimpleEvent(
   nsCOMPtr<nsIDOMEvent> event;
   rv = NS_NewDOMEvent(getter_AddRefs(event), nullptr, nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // it doesn't bubble, and it isn't cancelable
   rv = event->InitEvent(aName, false, false);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = event->SetTrusted(true);
-  NS_ENSURE_SUCCESS(rv, rv);
+  event->SetTrusted(true);
 
   return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 }
 
 nsresult
 WebSocket::CreateAndDispatchMessageEvent(const nsACString& aData,
                                          bool isBinary)
 {
@@ -926,18 +923,17 @@ WebSocket::CreateAndDispatchMessageEvent
   nsCOMPtr<nsIDOMMessageEvent> messageEvent = do_QueryInterface(event);
   rv = messageEvent->InitMessageEvent(NS_LITERAL_STRING("message"),
                                       false, false,
                                       jsData,
                                       mUTF16Origin,
                                       EmptyString(), nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = event->SetTrusted(true);
-  NS_ENSURE_SUCCESS(rv, rv);
+  event->SetTrusted(true);
 
   return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 }
 
 nsresult
 WebSocket::CreateAndDispatchCloseEvent(bool aWasClean,
                                        uint16_t aCode,
                                        const nsString &aReason)
@@ -957,18 +953,17 @@ WebSocket::CreateAndDispatchCloseEvent(b
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIDOMCloseEvent> closeEvent = do_QueryInterface(event);
   rv = closeEvent->InitCloseEvent(NS_LITERAL_STRING("close"),
                                   false, false,
                                   aWasClean, aCode, aReason);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = event->SetTrusted(true);
-  NS_ENSURE_SUCCESS(rv, rv);
+  event->SetTrusted(true);
 
   return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 }
 
 bool
 WebSocket::PrefEnabled()
 {
   return Preferences::GetBool("network.websocket.enabled", true);
--- a/content/base/src/WebSocket.h
+++ b/content/base/src/WebSocket.h
@@ -177,18 +177,18 @@ protected:
             uint32_t aMsgLength,
             bool aIsBinary,
             ErrorResult& aRv);
 
   nsresult ParseURL(const nsString& aURL);
   nsresult EstablishConnection();
 
   // These methods when called can release the WebSocket object
-  nsresult FailConnection(uint16_t reasonCode,
-                          const nsACString& aReasonString = EmptyCString());
+  void FailConnection(uint16_t reasonCode,
+                      const nsACString& aReasonString = EmptyCString());
   nsresult CloseConnection(uint16_t reasonCode,
                            const nsACString& aReasonString = EmptyCString());
   nsresult Disconnect();
 
   nsresult ConsoleError();
   nsresult PrintErrorOnConsole(const char* aBundleURI,
                                const PRUnichar* aError,
                                const PRUnichar** aFormatStrings,
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -3435,18 +3435,17 @@ nsresult GetEventAndTarget(nsIDocument* 
   nsCOMPtr<nsIDOMEvent> event;
   nsresult rv =
     domDoc->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = event->InitEvent(aEventName, aCanBubble, aCancelable);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = event->SetTrusted(aTrusted);
-  NS_ENSURE_SUCCESS(rv, rv);
+  event->SetTrusted(aTrusted);
 
   rv = event->SetTarget(target);
   NS_ENSURE_SUCCESS(rv, rv);
 
   event.forget(aEvent);
   target.forget(aTargetOut);
   return NS_OK;
 }
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1291,16 +1291,17 @@ GK_ATOM(marker, "marker")
 GK_ATOM(marker_end, "marker-end")
 GK_ATOM(marker_mid, "marker-mid")
 GK_ATOM(marker_start, "marker-start")
 GK_ATOM(markerHeight, "markerHeight")
 GK_ATOM(markerUnits, "markerUnits")
 GK_ATOM(markerWidth, "markerWidth")
 GK_ATOM(mask, "mask")
 GK_ATOM(maskContentUnits, "maskContentUnits")
+GK_ATOM(mask_type, "mask-type")
 GK_ATOM(maskUnits, "maskUnits")
 GK_ATOM(matrix, "matrix")
 GK_ATOM(metadata, "metadata")
 GK_ATOM(missingGlyph, "missing-glyph")
 GK_ATOM(mm, "mm")
 GK_ATOM(mpath, "mpath")
 GK_ATOM(noStitch, "noStitch")
 GK_ATOM(numOctaves, "numOctaves")
--- a/content/base/src/nsINode.cpp
+++ b/content/base/src/nsINode.cpp
@@ -97,16 +97,17 @@
 #include "nsXBLInsertionPoint.h"
 #include "nsXBLPrototypeBinding.h"
 #include "prprf.h"
 #include "xpcpublic.h"
 #include "nsCSSRuleProcessor.h"
 #include "nsCSSParser.h"
 #include "nsHTMLLegendElement.h"
 #include "nsWrapperCacheInlines.h"
+#include "WrapperFactory.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsINode::nsSlots::~nsSlots()
 {
   if (mChildNodes) {
     mChildNodes->DropReference();
@@ -2174,17 +2175,22 @@ ParseSelectorList(nsINode* aNode,
   nsIDocument* doc = aNode->OwnerDoc();
   nsCSSParser parser(doc->CSSLoader());
 
   nsCSSSelectorList* selectorList;
   nsresult rv = parser.ParseSelectorString(aSelectorString,
                                            doc->GetDocumentURI(),
                                            0, // XXXbz get the line number!
                                            &selectorList);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    // We hit this for syntax errors, which are quite common, so don't
+    // use NS_ENSURE_SUCCESS.  (For example, jQuery has an extended set
+    // of selectors, but it sees if we can parse them first.)
+    return rv;
+  }
 
   // Filter out pseudo-element selectors from selectorList
   nsCSSSelectorList** slot = &selectorList;
   do {
     nsCSSSelectorList* cur = *slot;
     if (cur->mSelectors->IsPseudoElement()) {
       *slot = cur->mNext;
       cur->mNext = nullptr;
@@ -2213,17 +2219,22 @@ AddScopeElements(TreeMatchContext& aMatc
 // onlyFirstMatch, then stop once the first one is found.
 template<bool onlyFirstMatch, class T>
 inline static nsresult
 FindMatchingElements(nsINode* aRoot, const nsAString& aSelector, T &aList)
 {
   nsAutoPtr<nsCSSSelectorList> selectorList;
   nsresult rv = ParseSelectorList(aRoot, aSelector,
                                   getter_Transfers(selectorList));
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    // We hit this for syntax errors, which are quite common, so don't
+    // use NS_ENSURE_SUCCESS.  (For example, jQuery has an extended set
+    // of selectors, but it sees if we can parse them first.)
+    return rv;
+  }
   NS_ENSURE_TRUE(selectorList, NS_OK);
 
   NS_ASSERTION(selectorList->mSelectors,
                "How can we not have any selectors?");
 
   nsIDocument* doc = aRoot->OwnerDoc();
   TreeMatchContext matchingContext(false, nsRuleWalker::eRelevantLinkUnvisited,
                                    doc, TreeMatchContext::eNeverMatchVisited);
@@ -2337,17 +2348,28 @@ nsINode::WrapObject(JSContext *aCx, JSOb
   if (!OwnerDoc()->GetScriptHandlingObject(hasHadScriptHandlingObject) &&
       !hasHadScriptHandlingObject &&
       !nsContentUtils::IsCallerChrome()) {
     Throw<true>(aCx, NS_ERROR_UNEXPECTED);
     *aTriedToWrap = true;
     return nullptr;
   }
 
-  return WrapNode(aCx, aScope, aTriedToWrap);
+  JSObject* obj = WrapNode(aCx, aScope, aTriedToWrap);
+  if (obj && ChromeOnlyAccess()) {
+    // Create a new wrapper and cache it.
+    JSAutoCompartment ac(aCx, obj);
+    JSObject* wrapper = xpc::WrapperFactory::WrapSOWObject(aCx, obj);
+    if (!wrapper) {
+      ClearWrapper();
+      return nullptr;
+    }
+    dom::SetSystemOnlyWrapper(obj, this, *wrapper);
+  }
+  return obj;
 }
 
 bool
 nsINode::IsSupported(const nsAString& aFeature, const nsAString& aVersion)
 {
   return nsContentUtils::InternalIsSupported(this, aFeature, aVersion);
 }
 
--- a/content/base/src/nsNodeUtils.cpp
+++ b/content/base/src/nsNodeUtils.cpp
@@ -25,16 +25,17 @@
 #include "nsBindingManager.h"
 #include "nsGenericHTMLElement.h"
 #ifdef MOZ_MEDIA
 #include "nsHTMLMediaElement.h"
 #endif // MOZ_MEDIA
 #include "nsWrapperCacheInlines.h"
 #include "nsObjectLoadingContent.h"
 #include "nsDOMMutationObserver.h"
+#include "mozilla/dom/BindingUtils.h"
 
 using namespace mozilla::dom;
 
 // This macro expects the ownerDocument of content_ to be in scope as
 // |nsIDocument* doc|
 #define IMPL_MUTATION_NOTIFICATION(func_, content_, params_)      \
   PR_BEGIN_MACRO                                                  \
   bool needsEnterLeave = doc->MayHaveDOMMutationObservers();      \
@@ -395,17 +396,19 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
   *aResult = nullptr;
 
   // First deal with aNode and walk its attributes (and their children). Then,
   // if aDeep is true, deal with aNode's children (and recurse into their
   // attributes and children).
 
   nsresult rv;
   JSObject *wrapper;
-  if (aCx && (wrapper = aNode->GetWrapper())) {
+  bool isDOMBinding;
+  if (aCx && (wrapper = aNode->GetWrapper()) &&
+      !(isDOMBinding = IsDOMObject(wrapper))) {
       rv = xpc_MorphSlimWrapper(aCx, aNode);
       NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsNodeInfoManager *nodeInfoManager = aNewNodeInfoManager;
 
   // aNode.
   nsINodeInfo *nodeInfo = aNode->mNodeInfo;
@@ -520,24 +523,28 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
       newDoc->SetMayHaveDOMMutationObservers();
     }
 
     if (elem) {
       elem->RecompileScriptEventListeners();
     }
 
     if (aCx && wrapper) {
-      nsIXPConnect *xpc = nsContentUtils::XPConnect();
-      if (xpc) {
-        rv = xpc->ReparentWrappedNativeIfFound(aCx, wrapper, aNewScope, aNode);
-        if (NS_FAILED(rv)) {
-          aNode->mNodeInfo.swap(nodeInfo);
+      if (isDOMBinding) {
+        rv = ReparentWrapper(aCx, wrapper);
+      } else {
+        nsIXPConnect *xpc = nsContentUtils::XPConnect();
+        if (xpc) {
+          rv = xpc->ReparentWrappedNativeIfFound(aCx, wrapper, aNewScope, aNode);
+        }
+      }
+      if (NS_FAILED(rv)) {
+        aNode->mNodeInfo.swap(nodeInfo);
 
-          return rv;
-        }
+        return rv;
       }
     }
   }
 
   // XXX If there are any attribute nodes on this element with UserDataHandlers
   // we should technically adopt/clone/import such attribute nodes and notify
   // those handlers. However we currently don't have code to do so without
   // also notifying when it's not safe so we're not doing that at this time.
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -2515,29 +2515,30 @@ GetRequestBody(nsIInputStream* aStream, 
 
 static nsresult
 GetRequestBody(nsIXHRSendable* aSendable, nsIInputStream** aResult, uint64_t* aContentLength,
                nsACString& aContentType, nsACString& aCharset)
 {
   return aSendable->GetSendInfo(aResult, aContentLength, aContentType, aCharset);
 }
 
+// Used for array buffers and array buffer views
 static nsresult
-GetRequestBody(ArrayBuffer* aArrayBuffer, nsIInputStream** aResult, uint64_t* aContentLength,
+GetRequestBody(const uint8_t* aData, uint32_t aDataLength,
+               nsIInputStream** aResult, uint64_t* aContentLength,
                nsACString& aContentType, nsACString& aCharset)
 {
   aContentType.SetIsVoid(true);
   aCharset.Truncate();
 
-  int32_t length = aArrayBuffer->Length();
-  *aContentLength = length;
-  char* data = reinterpret_cast<char*>(aArrayBuffer->Data());
+  *aContentLength = aDataLength;
+  const char* data = reinterpret_cast<const char*>(aData);
 
   nsCOMPtr<nsIInputStream> stream;
-  nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), data, length,
+  nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), data, aDataLength,
                                       NS_ASSIGNMENT_COPY);
   NS_ENSURE_SUCCESS(rv, rv);
 
   stream.forget(aResult);
 
   return NS_OK;
 }
 
@@ -2590,17 +2591,18 @@ GetRequestBody(nsIVariant* aBody, nsIInp
     // ArrayBuffer?
     jsval realVal;
 
     nsresult rv = aBody->GetAsJSVal(&realVal);
     if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(realVal)) {
       JSObject *obj = JSVAL_TO_OBJECT(realVal);
       if (JS_IsArrayBufferObject(obj)) {
           ArrayBuffer buf(obj);
-          return GetRequestBody(&buf, aResult, aContentLength, aContentType, aCharset);
+          return GetRequestBody(buf.Data(), buf.Length(), aResult,
+                                aContentLength, aContentType, aCharset);
       }
     }
   }
   else if (dataType == nsIDataType::VTYPE_VOID ||
            dataType == nsIDataType::VTYPE_EMPTY) {
     // Makes us act as if !aBody, don't upload anything
     aContentType.AssignLiteral("text/plain");
     aCharset.AssignLiteral("UTF-8");
@@ -2632,18 +2634,25 @@ nsXMLHttpRequest::GetRequestBody(nsIVari
     return ::GetRequestBody(aVariant, aResult, aContentLength, aContentType, aCharset);
   }
 
   const RequestBody& body = aBody.Value();
   RequestBody::Value value = body.GetValue();
   switch (body.GetType()) {
     case nsXMLHttpRequest::RequestBody::ArrayBuffer:
     {
-      return ::GetRequestBody(value.mArrayBuffer, aResult, aCo