Merge mozilla-central into build-system
authorGregory Szorc <gps@mozilla.com>
Sat, 22 Dec 2012 15:29:20 -0800
changeset 117937 dbde4d3de84d022543925b7984972ed03ca4bd96
parent 117936 d4f37aa65d0959eaca8860afbcb5f4d85106a7d0 (current diff)
parent 116860 84320dffec6e55f92fd01bde61ea367b325850ed (diff)
child 117938 30830a4b9bfdf568fa5484f173135400a27b7603
push id24140
push usergszorc@mozilla.com
push dateMon, 07 Jan 2013 22:33:06 +0000
treeherdermozilla-central@795632f0e4fe [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 mozilla-central into build-system
configure.in
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
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-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/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/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/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
@@ -59,60 +59,51 @@ let FormAssistant = {
     return this._focusedElement;
   },
 
   set focusedElement(val) {
     this._focusedElement = val;
   },
 
   setFocusedElement: function fa_setFocusedElement(element) {
-    if (element instanceof HTMLOptionElement)
-      element = element.parentNode;
-
     if (element === this.focusedElement)
       return;
 
     if (this.focusedElement) {
-      this.focusedElement.removeEventListener('click', this);
       this.focusedElement.removeEventListener('mousedown', this);
       this.focusedElement.removeEventListener('mouseup', this);
       if (!element) {
         this.focusedElement.blur();
       }
     }
 
     if (element) {
-      element.addEventListener('click', this);
       element.addEventListener('mousedown', this);
       element.addEventListener('mouseup', this);
     }
 
     this.focusedElement = element;
   },
 
   handleEvent: function fa_handleEvent(evt) {
     let focusedElement = this.focusedElement;
     let target = evt.target;
 
     switch (evt.type) {
       case "focus":
         if (this.isTextInputElement(target) && this.isIMEDisabled())
           return;
 
-        // We got input focus, but don't open the virtual keyboard unless we
-        // get a 'click' event, i.e. the user is tapping the input element.
-        if (target && this.isFocusableElement(target)) {
-          this.setFocusedElement(target);
-        }
+        if (target && this.isFocusableElement(target))
+          this.showKeyboard(target);
         break;
 
       case "blur":
         if (this.focusedElement)
           this.hideKeyboard();
-        this.setFocusedElement(null);
         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;
@@ -123,24 +114,16 @@ let FormAssistant = {
         // 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.sendKeyboardState(this.focusedElement);
         }
         break;
 
-      case 'click':
-        // We only listen for click events on the currently focused element.
-        // Gecko fires a click event if the user "taps" an input element
-        // without dragging. This is how we differentiate tap gestures to set
-        // input focus (and open the keyboard) from simply panning the page.
-        this.showKeyboard();
-        break;
-
       case "resize":
         if (!this.isKeyboardOpened)
           return;
 
         if (this.scrollIntoViewTimeout) {
           content.clearTimeout(this.scrollIntoViewTimeout);
           this.scrollIntoViewTimeout = null;
         }
@@ -223,29 +206,34 @@ let FormAssistant = {
     let disabled = false;
     try {
       disabled = domWindowUtils.IMEStatus == domWindowUtils.IME_STATUS_DISABLED;
     } catch (e) {}
 
     return disabled;
   },
 
-  showKeyboard: function fa_showKeyboard() {
+  showKeyboard: function fa_showKeyboard(target) {
     if (this.isKeyboardOpened)
       return;
 
-    let target = this.focusedElement;
+    if (target instanceof HTMLOptionElement)
+      target = target.parentNode;
+
     let kbOpened = this.sendKeyboardState(target);
     if (this.isTextInputElement(target))
       this.isKeyboardOpened = kbOpened;
+
+    this.setFocusedElement(target);
   },
 
   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;
     }
 
     if (element instanceof HTMLSelectElement ||
--- 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/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-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.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)
--- a/browser/components/downloads/content/allDownloadsViewOverlay.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) {
--- a/browser/components/downloads/content/allDownloadsViewOverlay.xul
+++ b/browser/components/downloads/content/allDownloadsViewOverlay.xul
@@ -16,23 +16,24 @@
      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 also has the editMenuOverlay overlay applied,
+    3. Make sure your window has the editMenuOverlay overlay applied,
        because the view implements cmd_copy and cmd_delete.
-    4. To initialize the view
+    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.places = "place:transition=7&sort=4";
+        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"
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>
--- a/browser/components/downloads/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
@@ -79,22 +79,22 @@
                            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>
+
+      <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
@@ -8,8 +8,10 @@ browser.jar:
         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
--- a/browser/components/places/jar.mn
+++ b/browser/components/places/jar.mn
@@ -10,17 +10,17 @@ browser.jar:
 *   content/browser/places/places.js                     (content/places.js)
     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/src/Makefile.in
+++ b/browser/components/sessionstore/src/Makefile.in
@@ -8,19 +8,20 @@ srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/config.mk
 
 EXTRA_COMPONENTS = \
   nsSessionStore.manifest \
   nsSessionStore.js \
-  nsSessionStartup.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)
--- a/browser/components/sessionstore/src/nsSessionStartup.js
+++ b/browser/components/sessionstore/src/nsSessionStartup.js
@@ -68,21 +68,25 @@ SessionStartup.prototype = {
 /* ........ 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
+    if (PrivateBrowsingUtils.permanentPrivateBrowsing)
+      return;
+
+#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
     let pbs = Cc["@mozilla.org/privatebrowsing;1"].
               getService(Ci.nsIPrivateBrowsingService);
-    if (PrivateBrowsingUtils.permanentPrivateBrowsing ||
-        pbs.lastChangedByCommandLine)
+    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");
   },
 
--- 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:[
--- 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/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/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;
 }
--- a/browser/themes/gnomestripe/downloads/allDownloadsViewOverlay.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/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;
 }
--- 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;
+  }
+}
--- a/browser/themes/winstripe/downloads/allDownloadsViewOverlay.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
@@ -273,17 +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.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 {
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();
@@ -2347,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/test/file_CrossSiteXHR_inner.html
+++ b/content/base/test/file_CrossSiteXHR_inner.html
@@ -20,17 +20,17 @@ window.addEventListener("message", funct
     status: 0,
     responseText: "",
     statusText: "",
     responseXML: null,
     sendThrew: false
   };
   
   var xhr = new XMLHttpRequest();
-  for each(type in ["load", "abort", "error", "loadstart", "loadend"]) {
+  for (type of ["load", "abort", "error", "loadstart", "loadend"]) {
     xhr.addEventListener(type, function(e) {
       res.events.push(e.type);
     }, false);
   }
   xhr.addEventListener("readystatechange", function(e) {
     res.events.push("rs" + xhr.readyState);
   }, false);
   xhr.addEventListener("progress", function(e) {
index 9fc85c29c082b1d4c8825c73154fbb1cf91dd7f5..bdb0eb44087ff46452871adf27f9b5b1705f36fa
GIT binary patch
literal 1105
zc$^FHW@Zs#U|`^2SUR)c@lp0M^~uZ(46U3D3^G8`w9K5;c;}-0;^N@UlGF%~p!m$Z
zywoDSjFQ}(sbSIimkmVf&abz4qA3`AO8M0`C6l(cEeE%JV>I!doaraM_zK^)&Fd8Y
zSs$N%M~X{Hzwi9tPd{&@>))&06;ZcyZ_DbZXTRE5RTmZsG1mOqvZsdeG*hB#t7D?W
zx`QGyhi6Ua*z&A2^pmLZ3}*4ZUlj|NT;tCB@cHUpWpSp^Z@rqEj=9wNJTgpgOZ_!l
zZR2gBnQkkz7b#Xw-m)=E>W9>~P46t8#B-flG<kBR$XwC1=yREl(=IOx?+Q<od%NSr
zQ@!NMx}PqbF~zwPWYj*2ZB3KzQQxrc=&1rtA)kloE`k{%Kdreq&N*I5t<1{g+J9MW
ze#Fd#w8g&uoxhHV6q*#)xjDq2`~1CUx^cwjpvOlpUifv@ct`z*-(DwqU%oi)Q2+Gg
zEra0l=t(P<T-b3W-MHD}9k=P0g-@Q(em%4M`lMQ+(@qcdSe%c<n>`WuTD&l)Y6tVB
z-A2oH9e!_`HF?LLYe9}l-$ZY<-9NrG#Zpu&Eq<xdH}<KMy6R-wo0PI{Ot}6-@$1tK
zer{9C(|)^tKcqPMOt|*ytk{5sYu9jhG|k^(^XFT5$&rdREB;nTtHp@={8_lazQ85Q
zs%`qYMVI3z>?^-gY5Qv9%jbdqhuikoRAyX%WTjY>TAHd|A$_FUm1oYz&l|5<bR;MK
zS-K`@2ixJF6MLA>bmoWj`hDIK%B%50)A>=?-R%z=eT<d}o9W3J?T~l5t7ykj-ZFvV
z!jDMN3;yQEg?QDR|FXH~^6YJXoXf9~-?Ua`&O}zNb6)?NSIt{CGq22hr$JY@Z_$GJ
zht5cUP)>QW<@5^GpL5(Mg?oGr$vd_~tNpTN%I%ll2^Jwz3J)e!+TXE1P&wi2+&c?)
zN^{8U$a(#8`K%>38--u1JFH}XBWr%N^^i?2!`&bbu@LvWN-Hn_)cU-4s(jDmw#3sW
zc1JfkIj-%9Ww@-lN7s92b64hB^Fw$2pJefyn)(~e`X7Aymgm&$3qoZc9zqEj9GC7k
z-PUN>*n4wU`NG_Zc}r^^Em|3BxpCv~#QU|LcXo6-=Lc0hHj%QrA!v6g%gO3W){C%i
z!}&?<f1mH4b1wNUr-c^VkB_?#zPXrj=<b8xawclEKdblKZP|AG?8ewHXC+0iZJM;~
z^#9p2mu@e=yT9n2@9q_I{pQA;kT%xM-g@XvQQjTvgZ#qE;(ZgBl-w3A$vn60^4b_t
zo6Rd`?p=2NnS0;4We*vh>L0o$6<YV(-FVIyk}}bv&t-M}u0L!6-i%E447jqh3IhZv
zKxurLn+vLnkwJoCmhyw+Yi^xo4El2)OusnkYw<SfEMtH-D;q=&BSRjLKFbW^0RXqQ
B1>FDu
--- a/content/base/test/file_CrossSiteXHR_inner_data.sjs
+++ b/content/base/test/file_CrossSiteXHR_inner_data.sjs
@@ -9,17 +9,17 @@ window.addEventListener("message", funct
   req = eval(e.data);\n\
   var res = {\n\
     didFail: false,\n\
     events: [],\n\
     progressEvents: 0\n\
   };\n\
   \n\
   var xhr = new XMLHttpRequest();\n\
-  for each(type in ["load", "abort", "error", "loadstart", "loadend"]) {\n\
+  for (type of ["load", "abort", "error", "loadstart", "loadend"]) {\n\
     xhr.addEventListener(type, function(e) {\n\
       res.events.push(e.type);\n\
     }, false);\n\
   }\n\
   xhr.addEventListener("readystatechange", function(e) {\n\
     res.events.push("rs" + xhr.readyState);\n\
   }, false);\n\
   xhr.addEventListener("progress", function(e) {\n\
--- a/content/base/test/test_CrossSiteXHR.html
+++ b/content/base/test/test_CrossSiteXHR.html
@@ -567,17 +567,17 @@ function runTest() {
                  preflightBody: "I'm a preflight response body",
                },
                ];
 
   if (!runPreflightTests) {
     tests = [];
   }
 
-  for each(test in tests) {
+  for (test of tests) {
     var req = {
       url: baseURL + "allowOrigin=" + escape(test.origin || origin),
       method: test.method,
       headers: test.headers,
       uploadProgress: test.uploadProgress,
       body: test.body,
       responseHeaders: test.responseHeaders,
     };
@@ -782,17 +782,17 @@ function runTest() {
              allowCred: 1,
            },
            ];
 
   if (!runCookieTests) {
     tests = [];
   }
 
-  for each(test in tests) {
+  for (test of tests) {
     req = {
       url: baseURL + "allowOrigin=" + escape(test.origin || origin),
       method: test.method,
       headers: test.headers,
       withCred: test.withCred,
     };
 
     if (test.allowCred)
@@ -1107,17 +1107,17 @@ function runTest() {
                     ],
            },
            ];
 
   if (!runRedirectTests) {
     tests = [];
   }
 
-  for each(test in tests) {
+  for (test of tests) {
     req = {
       url: test.hops[0].server + basePath + "hop=1&hops=" +
            escape(test.hops.toSource()),
       method: test.method,
       headers: test.headers,
       body: test.body,
     };
 
--- a/content/base/test/test_CrossSiteXHR_cache.html
+++ b/content/base/test/test_CrossSiteXHR_cache.html
@@ -427,17 +427,17 @@ function runTest() {
                });
   }
 
   baseURL = "http://mochi.test:8888/tests/content/base/test/" +
              "file_CrossSiteXHR_cache_server.sjs?";
   setStateURL = baseURL + "setState=";
 
   var unique = Date.now();
-  for each (test in tests) {
+  for (test of tests) {
     if (test.newTest) {
       unique++;
       continue;
     }
     if (test.pause) {
       setTimeout(function() { gen.next() }, test.pause * 1000);
       yield;
       continue;
--- a/content/base/test/test_CrossSiteXHR_origin.html
+++ b/content/base/test/test_CrossSiteXHR_origin.html
@@ -59,17 +59,17 @@ function runTest() {
   var loader = document.getElementById('loader');
   var loaderWindow = loader.contentWindow;
   loader.onload = function () { gen.next() };
 
   // Test preflight-less requests
   basePath = "/tests/content/base/test/file_CrossSiteXHR_server.sjs?"
   baseURL = "http://mochi.test:8888" + basePath;
 
-  for each(originEntry in origins) {
+  for (originEntry of origins) {
     origin = originEntry.origin || originEntry.server;
 
     loader.src = originEntry.file ||
                  (originEntry.server + "/tests/content/base/test/file_CrossSiteXHR_inner.html");
     yield;
 
     var isNullOrigin = origin == "null";
 
@@ -108,17 +108,17 @@ function runTest() {
       origin.replace(/\/[^.]+\./, "/"),
     ];
 
     if (isNullOrigin) {
       passTests = ["*", "\t \t* \t ", "null"];
       failTests = failTests.filter(function(v) { return v != origin });
     }
     
-    for each(allowOrigin in passTests) {
+    for (allowOrigin of passTests) {
       req = {
         url: baseURL +
              "allowOrigin=" + escape(allowOrigin) +
              "&origin=" + escape(origin),
         method: "GET",
       };
       loaderWindow.postMessage(req.toSource(), isNullOrigin ? "*" : origin);
 
@@ -131,17 +131,17 @@ function runTest() {
          "wrong responseXML in test for " + allowOrigin);
       is(res.responseText, "<res>hello pass</res>\n",
          "wrong responseText in test for " + allowOrigin);
       is(res.events.join(","),
          "opening,rs1,sending,loadstart,rs2,rs3,rs4,load,loadend",
          "wrong responseText in test for " + allowOrigin);
     }
 
-    for each(allowOrigin in failTests) {
+    for (allowOrigin of failTests) {
       req = {
         url: baseURL + "allowOrigin=" + escape(allowOrigin),
         method: "GET",
       };
       loaderWindow.postMessage(req.toSource(), isNullOrigin ? "*" : origin);
 
       res = eval(yield);
       is(res.didFail, true, "should have failed for " + allowOrigin);
--- a/content/base/test/test_XHRSendData.html
+++ b/content/base/test/test_XHRSendData.html
@@ -208,17 +208,17 @@ for (var i = 0; i < testDOMFiles.length;
   tests.push({ body: testDOMFiles[i],
                resBody: testData,
                resContentType: fileTypes[i],
                resContentLength: testData.length,
               });
 }
 
 try {
-  for each(test in tests) {
+  for (test of tests) {
     xhr = new XMLHttpRequest;
     xhr.open("POST", "file_XHRSendData.sjs", !!test.resType);
     if (test.contentType)
       xhr.setRequestHeader("Content-Type", test.contentType);
     if (test.resType) {
       xhr.responseType = test.resType;
       xhr.onloadend = continueTest;
     }
--- a/content/base/test/test_bug338583.html
+++ b/content/base/test/test_bug338583.html
@@ -115,17 +115,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     return true;
   }
 
 // in order to test (1):
 //   a) if the EventSource constructor parameter is equal to its url attribute
 //   b) let its fn_onmessage, fn_event_listener_message, and fn_other_event_name functions listeners be hit four times each
 //   c) the close method (we expect readyState == CLOSED)
 //   d) the close method (we expect no message events anymore)
-//   e) if the ctor throws an exception when the second parameter is null
+//   e) use the default for withCredentials when passing dictionary arguments that don't explicitly set it
 
   function doTest1(test_id) {
     gEventSourceObj1 = new EventSource("eventsource.resource");
     ok(gEventSourceObj1.url == "http://mochi.test:8888/tests/content/base/test/eventsource.resource", "Test 1.a failed.");
     ok(gEventSourceObj1.readyState == 0 || gEventSourceObj1.readyState == 1, "Test 1.a failed.");
 
     doTest1_b(test_id);
   }
@@ -165,21 +165,23 @@ https://bugzilla.mozilla.org/show_bug.cg
       ok(!bhits, "Test 1.d failed.");
       gEventSourceObj1.close();
       setTestHasFinished(test_id);
     }, parseInt(2000*stress_factor));
   }
 
   function doTest1_e(test_id) {
     try {
-      gEventSourceObj1_e = new EventSource("eventsource.resource", null);
+      for (var options of [null, undefined, {}]) {
+        gEventSourceObj1_e = new EventSource("eventsource.resource", options);
+        is(gEventSourceObj1_e.withCredentials, false, "withCredentials should default to false");
+        gEventSourceObj1_e.close();
+      }
+    } catch (e) {
       ok(false, "Test 1.e failed");
-      gEventSourceObj1_e.close();
-    } catch (e) {
-      ok(true, "Test 1.e failed");
     }
     setTestHasFinished(test_id);
   }
 
 // in order to test (2)
 //   a) set a eventsource that give the dom events messages
 //   b) expect trusted events
 
--- a/content/base/test/test_bug353334.html
+++ b/content/base/test/test_bug353334.html
@@ -47,21 +47,21 @@ function checkPrincipal() {
   is(SpecialPowers.getNodePrincipal(document) instanceof SpecialPowers.Ci.nsIPrincipal,
      true,
      "Should be a principal");
 }
 
 addLoadEvent(function() {
   checkPrincipal();
 
-  for each (var i in [ "one", "two", "three", "four" ]) {
+  for (var i of [ "one", "two", "three", "four" ]) {
     doPrincipalTest(i);
   }
 
-  for each (i in [ "five", "six" ]) {
+  for (i of [ "five", "six" ]) {
     doContentTest(i);
   }
 
   SimpleTest.finish();
 });
 </script>
 </pre>
 </body>
--- a/content/base/test/test_bug422537.html
+++ b/content/base/test/test_bug422537.html
@@ -25,17 +25,17 @@ isupports_string.data = "foo";
 
 const url = "http://mochi.test:8888";
 var body = [
   document,
   "foo",
   isupports_string
 ];
 
-for each (var i in body) {
+for (var i of body) {
   var xhr = new XMLHttpRequest();
   xhr.open("POST", url, true);
   if (i == isupports_string)
     SpecialPowers.wrap(xhr).send(i);
   else
     xhr.send(i);
   var chan = SpecialPowers.wrap(xhr).channel;
   if (!SpecialPowers.call_Instanceof(chan, SpecialPowers.Ci.nsIUploadChannel))
--- a/content/base/test/test_bug453736.html
+++ b/content/base/test/test_bug453736.html
@@ -20,17 +20,17 @@ SimpleTest.waitForExplicitFinish();
 addLoadEvent(function() {
   const scriptCreationFuncs = [
     function() { return document.createElement("script"); },
     function() { return document.createElementNS("http://www.w3.org/2000/svg", "script"); }
   ];
 
   const scriptContainers = ["div", "iframe", "noframes", "noembed"];
   for (var i = 0; i < scriptContainers.length; ++i) {
-    for each (var func in scriptCreationFuncs) {
+    for (var func of scriptCreationFuncs) {
       var cont = scriptContainers[i];
       var node = document.createElement(cont);
       document.body.appendChild(node);
       var s = func();
       s.setAttribute("type", "application/javascript");
       s.appendChild(document.createTextNode('window["'+cont+'ScriptRan"] = true'));
 
       window[cont+"ScriptRan"] = false;
--- a/content/canvas/crashtests/421715-1.html
+++ b/content/canvas/crashtests/421715-1.html
@@ -7,17 +7,17 @@
           return a.toSource();
         return ''+a;
       }
       var args = [undefined, null, [], {}, 0, "0"];
       var stringArgs = args.map(stringify);
 
       function test_method(context, method, arity) {
         function testParams(existingParams, depth) {
-          for each (var arg in stringArgs) {
+          for (var arg of stringArgs) {
             var code = "context[method](" + existingParams + arg + ")";
             try {
               eval(code);
             } catch (ex) {
               // Exceptions are expected
             }
 
             if (depth < arity)
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -259,21 +259,20 @@ nsDOMEvent::GetOriginalTarget(nsIDOMEven
 {
   if (mEvent->originalTarget) {
     return GetDOMEventTarget(mEvent->originalTarget, aOriginalTarget);
   }
 
   return GetTarget(aOriginalTarget);
 }
 
-NS_IMETHODIMP
+NS_IMETHODIMP_(void)
 nsDOMEvent::SetTrusted(bool aTrusted)
 {
   mEvent->mFlags.mIsTrusted = aTrusted;
-  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMEvent::Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
                        uint32_t aArgc, jsval* aArgv)
 {
   NS_ENSURE_TRUE(aArgc >= 1, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
 
--- a/content/events/src/nsDOMEvent.h
+++ b/content/events/src/nsDOMEvent.h
@@ -97,14 +97,14 @@ protected:
   NS_IMETHOD GetExplicitOriginalTarget(nsIDOMEventTarget** aExplicitOriginalTarget) { return _to GetExplicitOriginalTarget(aExplicitOriginalTarget); } \
   NS_IMETHOD PreventBubble() { return _to PreventBubble(); } \
   NS_IMETHOD PreventCapture() { return _to PreventCapture(); } \
   NS_IMETHOD GetPreventDefault(bool* aRetval) { return _to GetPreventDefault(aRetval); } \
   NS_IMETHOD GetIsTrusted(bool* aIsTrusted) { return _to GetIsTrusted(aIsTrusted); } \
   NS_IMETHOD SetTarget(nsIDOMEventTarget *aTarget) { return _to SetTarget(aTarget); } \
   NS_IMETHOD_(bool) IsDispatchStopped(void) { return _to IsDispatchStopped(); } \
   NS_IMETHOD_(nsEvent *) GetInternalNSEvent(void) { return _to GetInternalNSEvent(); } \
-  NS_IMETHOD SetTrusted(bool aTrusted) { return _to SetTrusted(aTrusted); }
+  NS_IMETHOD_(void) SetTrusted(bool aTrusted) { _to SetTrusted(aTrusted); }
 
 #define NS_FORWARD_TO_NSDOMEVENT_NO_SERIALIZATION_NO_DUPLICATION \
   NS_FORWARD_NSIDOMEVENT_NO_SERIALIZATION_NO_DUPLICATION(nsDOMEvent::)
 
 #endif // nsDOMEvent_h__
--- a/content/events/src/nsDOMEventTargetHelper.cpp
+++ b/content/events/src/nsDOMEventTargetHelper.cpp
@@ -216,18 +216,17 @@ nsDOMEventTargetHelper::DispatchTrustedE
   NS_ENSURE_SUCCESS(rv, rv);
 
   return DispatchTrustedEvent(event);
 }
 
 nsresult
 nsDOMEventTargetHelper::DispatchTrustedEvent(nsIDOMEvent* event)
 {
-  nsresult rv = event->SetTrusted(true);
-  NS_ENSURE_SUCCESS(rv, rv);
+  event->SetTrusted(true);
 
   bool dummy;
   return DispatchEvent(event, &dummy);
 }
 
 nsresult
 nsDOMEventTargetHelper::SetEventHandler(nsIAtom* aType,
                                         JSContext* aCx,
--- a/content/events/src/nsDOMNotifyPaintEvent.cpp
+++ b/content/events/src/nsDOMNotifyPaintEvent.cpp
@@ -87,34 +87,36 @@ nsDOMNotifyPaintEvent::GetClientRects(ns
 
   rectList.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMNotifyPaintEvent::GetPaintRequests(nsIDOMPaintRequestList** aResult)
 {
-  nsRefPtr<nsPaintRequestList> requests =
-    new nsPaintRequestList(static_cast<nsDOMEvent*>(this));
-  if (!requests)
-    return NS_ERROR_OUT_OF_MEMORY;
+  nsRefPtr<nsPaintRequestList> requests = PaintRequests();
+  requests.forget(aResult);
+  return NS_OK;
+}
+
+already_AddRefed<nsPaintRequestList>
+nsDOMNotifyPaintEvent::PaintRequests()
+{
+  nsDOMEvent* parent = this;
+  nsRefPtr<nsPaintRequestList> requests = new nsPaintRequestList(parent);
 
   if (nsContentUtils::IsCallerChrome()) {
     for (uint32_t i = 0; i < mInvalidateRequests.Length(); ++i) {
-      nsRefPtr<nsPaintRequest> r = new nsPaintRequest();
-      if (!r)
-        return NS_ERROR_OUT_OF_MEMORY;
- 
+      nsRefPtr<nsPaintRequest> r = new nsPaintRequest(parent);
       r->SetRequest(mInvalidateRequests[i]);
       requests->Append(r);
     }
   }
 
-  requests.forget(aResult);
-  return NS_OK;
+  return requests.forget();
 }
 
 NS_IMETHODIMP_(void)
 nsDOMNotifyPaintEvent::Serialize(IPC::Message* aMsg,
                                  bool aSerializeInterfaceType)
 {
   if (aSerializeInterfaceType) {
     IPC::WriteParam(aMsg, NS_LITERAL_STRING("notifypaintevent"));
--- a/content/events/src/nsDOMNotifyPaintEvent.h
+++ b/content/events/src/nsDOMNotifyPaintEvent.h
@@ -28,15 +28,18 @@ public:
   // Forward to base class
   NS_FORWARD_TO_NSDOMEVENT_NO_SERIALIZATION_NO_DUPLICATION
   NS_IMETHOD DuplicatePrivateData()
   {
     return nsDOMEvent::DuplicatePrivateData();
   }
   NS_IMETHOD_(void) Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType);
   NS_IMETHOD_(bool) Deserialize(const IPC::Message* aMsg, void** aIter);
+
+  already_AddRefed<nsPaintRequestList> PaintRequests();
+
 private:
   nsRegion GetRegion();
 
   nsTArray<nsInvalidateRequestList::Request> mInvalidateRequests;
 };
 
 #endif // nsDOMNotifyPaintEvent_h_
--- a/content/events/src/nsPaintRequest.cpp
+++ b/content/events/src/nsPaintRequest.cpp
@@ -1,47 +1,64 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- 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 "nsPaintRequest.h"
 
 #include "nsDOMClassInfoID.h"
-#include "nsClientRect.h"
 #include "nsIFrame.h"
 #include "nsContentUtils.h"
+#include "mozilla/dom/PaintRequestBinding.h"
 #include "mozilla/dom/PaintRequestListBinding.h"
 
+using namespace mozilla;
+using namespace mozilla::dom;
+
 DOMCI_DATA(PaintRequest, nsPaintRequest)
 
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsPaintRequest, mParent)
+
 NS_INTERFACE_TABLE_HEAD(nsPaintRequest)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_TABLE1(nsPaintRequest, nsIDOMPaintRequest)
-  NS_INTERFACE_TABLE_TO_MAP_SEGUE
+  NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsPaintRequest)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(PaintRequest)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_ADDREF(nsPaintRequest)
-NS_IMPL_RELEASE(nsPaintRequest)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPaintRequest)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPaintRequest)
+
+/* virtual */ JSObject*
+nsPaintRequest::WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap)
+{
+  return PaintRequestBinding::Wrap(aCx, aScope, this, aTriedToWrap);
+}
+
+already_AddRefed<nsClientRect>
+nsPaintRequest::ClientRect()
+{
+  nsRefPtr<nsClientRect> clientRect = new nsClientRect();
+  clientRect->SetLayoutRect(mRequest.mRect);
+  return clientRect.forget();
+}
 
 NS_IMETHODIMP
 nsPaintRequest::GetClientRect(nsIDOMClientRect** aResult)
 {
-  nsRefPtr<nsClientRect> clientRect = new nsClientRect();
-  if (!clientRect)
-    return NS_ERROR_OUT_OF_MEMORY;
-  clientRect->SetLayoutRect(mRequest.mRect);
+  nsRefPtr<nsClientRect> clientRect = ClientRect();
   clientRect.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPaintRequest::GetReason(nsAString& aResult)
+nsPaintRequest::GetXPCOMReason(nsAString& aResult)
 {
-  aResult.AssignLiteral("repaint");
+  GetReason(aResult);
   return NS_OK;
 }
 
 DOMCI_DATA(PaintRequestList, nsPaintRequestList)
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsPaintRequestList, mParent)
 
 NS_INTERFACE_TABLE_HEAD(nsPaintRequestList)
--- a/content/events/src/nsPaintRequest.h
+++ b/content/events/src/nsPaintRequest.h
@@ -1,37 +1,60 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef NSPAINTREQUEST_H_
 #define NSPAINTREQUEST_H_
 
 #include "nsIDOMPaintRequest.h"
 #include "nsIDOMPaintRequestList.h"
 #include "nsPresContext.h"
 #include "nsIDOMEvent.h"
 #include "mozilla/Attributes.h"
+#include "nsClientRect.h"
 #include "nsWrapperCache.h"
 
 class nsPaintRequest MOZ_FINAL : public nsIDOMPaintRequest
+                               , public nsWrapperCache
 {
 public:
-  NS_DECL_ISUPPORTS
+  nsPaintRequest(nsIDOMEvent* aParent)
+    : mParent(aParent)
+  {
+    mRequest.mFlags = 0;
+    SetIsDOMBinding();
+  }
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsPaintRequest)
   NS_DECL_NSIDOMPAINTREQUEST
 
-  nsPaintRequest() { mRequest.mFlags = 0; }
+  virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
+                               bool* aTriedToWrap) MOZ_OVERRIDE;
+
+  nsIDOMEvent* GetParentObject() const
+  {
+    return mParent;
+  }
+
+  already_AddRefed<nsClientRect> ClientRect();
+  void GetReason(nsAString& aResult) const
+  {
+    aResult.AssignLiteral("repaint");
+  }
 
   void SetRequest(const nsInvalidateRequestList::Request& aRequest)
   { mRequest = aRequest; }
 
 private:
   ~nsPaintRequest() {}
 
+  nsCOMPtr<nsIDOMEvent> mParent;
   nsInvalidateRequestList::Request mRequest;
 };
 
 class nsPaintRequestList MOZ_FINAL : public nsIDOMPaintRequestList,
                                      public nsWrapperCache
 {
 public:
   nsPaintRequestList(nsIDOMEvent *aParent) : mParent(aParent)
@@ -45,17 +68,20 @@ public:
   
   virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
                                bool *triedToWrap);
   nsISupports* GetParentObject()
   {
     return mParent;
   }
 
-  void Append(nsIDOMPaintRequest* aElement) { mArray.AppendObject(aElement); }
+  void Append(nsPaintRequest* aElement)
+  {
+    mArray.AppendElement(aElement);
+  }
 
   static nsPaintRequestList* FromSupports(nsISupports* aSupports)
   {
 #ifdef DEBUG
     {
       nsCOMPtr<nsIDOMPaintRequestList> list_qi = do_QueryInterface(aSupports);
 
       // If this assertion fires the QI implementation for the object in
@@ -66,29 +92,29 @@ public:
     }
 #endif
 
     return static_cast<nsPaintRequestList*>(aSupports);
   }
 
   uint32_t Length()
   {
-    return mArray.Count();
+    return mArray.Length();
   }
 
-  nsIDOMPaintRequest* Item(uint32_t aIndex)
+  nsPaintRequest* Item(uint32_t aIndex)
   {
-    return mArray.SafeObjectAt(aIndex);
+    return mArray.SafeElementAt(aIndex);
   }
-  nsIDOMPaintRequest* IndexedGetter(uint32_t aIndex, bool& aFound)
+  nsPaintRequest* IndexedGetter(uint32_t aIndex, bool& aFound)
   {
-    aFound = aIndex < static_cast<uint32_t>(mArray.Count());
-    return aFound ? mArray.ObjectAt(aIndex) : nullptr;
+    aFound = aIndex < mArray.Length();
+    return aFound ? mArray.ElementAt(aIndex) : nullptr;
   }
 
 private:
   ~nsPaintRequestList() {}
 
-  nsCOMArray<nsIDOMPaintRequest> mArray;
+  nsTArray< nsRefPtr<nsPaintRequest> > mArray;
   nsCOMPtr<nsIDOMEvent> mParent;
 };
 
 #endif /*NSPAINTREQUEST_H_*/
--- a/content/events/test/test_bug336682_1.html
+++ b/content/events/test/test_bug336682_1.html
@@ -31,17 +31,17 @@ function makeBodyHandler(eventName) {
     var handler = makeHandler("<body on%1='...'>", eventName, [3,4]);
     handler(aEvent);
   }
 }
 addLoadEvent(function() {
   /** @see test_bug336682.js */
   MAX_STATE = 4;
 
-  for each(var event in ["online", "offline"]) {
+  for (var event of ["online", "offline"]) {
     document.body.addEventListener(
       event,
       makeHandler("document.body.addEventListener('%1', ..., false)",
                   event, [1]),
       false);
 
     document.addEventListener(
       event,
--- a/content/events/test/test_bug603008.html
+++ b/content/events/test/test_bug603008.html
@@ -72,17 +72,17 @@ function checkTouch(aFakeTouch, aTouch) 
   is(aFakeTouch.rotationAngle, aTouch.rotationAngle, "Touch has correct rotationAngle");
   is(aFakeTouch.force, aTouch.force, "Touch has correct force");
 }
 
 function sendTouchEvent(windowUtils, aType, aEvent, aModifiers) {
   var ids = [], xs=[], ys=[], rxs = [], rys = [],
       rotations = [], forces = [];
 
-  for each (var touchType in ["touches", "changedTouches", "targetTouches"]) {
+  for (var touchType of ["touches", "changedTouches", "targetTouches"]) {
     for (var i = 0; i < aEvent[touchType].length; i++) {
       if (ids.indexOf(aEvent[touchType][i].identifier) == -1) {
         ids.push(aEvent[touchType][i].identifier);
         xs.push(aEvent[touchType][i].page.x);
         ys.push(aEvent[touchType][i].page.y);
         rxs.push(aEvent[touchType][i].radius.x);
         rys.push(aEvent[touchType][i].radius.y);
         rotations.push(aEvent[touchType][i].rotationAngle);
--- a/content/events/test/test_bug741666.html
+++ b/content/events/test/test_bug741666.html
@@ -67,17 +67,17 @@ function checkTouch(aFakeTouch, aTouch) 
   is(aFakeTouch.rotationAngle, aTouch.rotationAngle, "Touch has correct rotationAngle");
   is(aFakeTouch.force, aTouch.force, "Touch has correct force");
 }
 
 function sendTouchEvent(windowUtils, aType, aEvent, aModifiers) {
   var ids = [], xs=[], ys=[], rxs = [], rys = [],
       rotations = [], forces = [];
 
-  for each (var touchType in ["touches", "changedTouches", "targetTouches"]) {
+  for (var touchType of ["touches", "changedTouches", "targetTouches"]) {
     for (var i = 0; i < aEvent[touchType].length; i++) {
       if (ids.indexOf(aEvent[touchType][i].identifier) == -1) {
         ids.push(aEvent[touchType][i].identifier);
         xs.push(aEvent[touchType][i].page.x);
         ys.push(aEvent[touchType][i].page.y);
         rxs.push(aEvent[touchType][i].radius.x);
         rys.push(aEvent[touchType][i].radius.y);
         rotations.push(aEvent[touchType][i].rotationAngle);
--- a/content/html/content/reftests/autofocus/autofocus-after-load.html
+++ b/content/html/content/reftests/autofocus/autofocus-after-load.html
@@ -2,17 +2,17 @@
 <html class="reftest-wait">
   <link rel='stylesheet' type='text/css' href='style.css'>
   <script>
     function loadHandler()
     {
       var body = document.body;
 
       var elements = ["input", "textarea", "select", "button"];
-      for each (var e in elements) {
+      for (var e of elements) {
         var el = document.createElement(e);
         el.autofocus = true;
         body.appendChild(el);
       }
 
       setTimeout(document.documentElement.removeAttribute('class'), 0);
     }
   </script>
--- a/content/html/content/src/nsHTMLDivElement.cpp
+++ b/content/html/content/src/nsHTMLDivElement.cpp
@@ -4,26 +4,28 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Util.h"
 
 #include "nsHTMLDivElement.h"
 #include "nsGenericHTMLElement.h"
 #include "nsStyleConsts.h"
 #include "nsMappedAttributes.h"
+#include "mozilla/dom/HTMLDivElementBinding.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Div)
 
 
 nsHTMLDivElement::nsHTMLDivElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
 {
+  SetIsDOMBinding();
 }
 
 nsHTMLDivElement::~nsHTMLDivElement()
 {
 }
 
 
 NS_IMPL_ADDREF_INHERITED(nsHTMLDivElement, Element)
@@ -35,16 +37,21 @@ DOMCI_NODE_DATA(HTMLDivElement, nsHTMLDi
 NS_INTERFACE_TABLE_HEAD(nsHTMLDivElement)
   NS_HTML_CONTENT_INTERFACE_TABLE1(nsHTMLDivElement, nsIDOMHTMLDivElement)
   NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLDivElement,
                                                nsGenericHTMLElement)
 NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLDivElement)
 
 NS_IMPL_ELEMENT_CLONE(nsHTMLDivElement)
 
+JSObject*
+nsHTMLDivElement::WrapNode(JSContext *aCx, JSObject *aScope, bool *aTriedToWrap)
+{
+  return dom::HTMLDivElementBinding::Wrap(aCx, aScope, this, aTriedToWrap);
+}
 
 bool
 nsHTMLDivElement::ParseAttribute(int32_t aNamespaceID,
                                  nsIAtom* aAttribute,
                                  const nsAString& aValue,
                                  nsAttrValue& aResult)
 {
   if (aNamespaceID == kNameSpaceID_None) {
--- a/content/html/content/src/nsHTMLDivElement.h
+++ b/content/html/content/src/nsHTMLDivElement.h
@@ -3,18 +3,18 @@
  * 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 nsHTMLDivElement_h___
 #define nsHTMLDivElement_h___
 
 #include "nsGenericHTMLElement.h"
 #include "nsIDOMHTMLDivElement.h"
 
-class nsHTMLDivElement : public nsGenericHTMLElement,
-                         public nsIDOMHTMLDivElement
+class nsHTMLDivElement MOZ_FINAL : public nsGenericHTMLElement,
+                                   public nsIDOMHTMLDivElement
 {
 public:
   nsHTMLDivElement(already_AddRefed<nsINodeInfo> aNodeInfo);
   virtual ~nsHTMLDivElement();
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
@@ -56,11 +56,15 @@ public:
                                 const nsAString& aValue,
                                 nsAttrValue& aResult);
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   virtual nsXPCClassInfo* GetClassInfo();
   virtual nsIDOMNode* AsDOMNode() { return this; }
+
+protected:
+  virtual JSObject* WrapNode(JSContext *aCx, JSObject *aScope,
+                             bool *aTriedToWrap) MOZ_OVERRIDE;
 };
 
 #endif /* nsHTMLDivElement_h___ */
--- a/content/html/content/src/nsHTMLElement.cpp
+++ b/content/html/content/src/nsHTMLElement.cpp
@@ -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/. */
 
 #include "nsGenericHTMLElement.h"
 #include "nsIDOMHTMLElement.h"
 
 #include "nsContentUtils.h"
+#include "mozilla/dom/HTMLElementBinding.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 class nsHTMLElement : public nsGenericHTMLElement,
                       public nsIDOMHTMLElement
 {
 public:
@@ -33,30 +34,35 @@ public:
   virtual void GetInnerHTML(nsAString& aInnerHTML,
                             mozilla::ErrorResult& aError) MOZ_OVERRIDE;
 
   nsresult Clone(nsINodeInfo* aNodeInfo, nsINode** aResult) const;
 
   virtual nsXPCClassInfo* GetClassInfo();
 
   virtual nsIDOMNode* AsDOMNode() { return this; }
+
+protected:
+  virtual JSObject* WrapNode(JSContext *aCx, JSObject *aScope,
+                             bool *aTriedToWrap) MOZ_OVERRIDE;
 };
 
 // Here, we expand 'NS_IMPL_NS_NEW_HTML_ELEMENT()' by hand.
 // (Calling the macro directly (with no args) produces compiler warnings.)
 nsGenericHTMLElement*
 NS_NewHTMLElement(already_AddRefed<nsINodeInfo> aNodeInfo,
                   FromParser aFromParser)
 {
   return new nsHTMLElement(aNodeInfo);
 }
 
 nsHTMLElement::nsHTMLElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
 {
+  SetIsDOMBinding();
 }
 
 nsHTMLElement::~nsHTMLElement()
 {
 }
 
 NS_IMPL_ADDREF_INHERITED(nsHTMLElement, Element)
 NS_IMPL_RELEASE_INHERITED(nsHTMLElement, Element)
@@ -85,8 +91,13 @@ nsHTMLElement::GetInnerHTML(nsAString& a
       mNodeInfo->Equals(nsGkAtoms::plaintext)) {
     nsContentUtils::GetNodeTextContent(this, false, aInnerHTML);
     return;
   }
 
   nsGenericHTMLElement::GetInnerHTML(aInnerHTML, aError);
 }
 
+JSObject*
+nsHTMLElement::WrapNode(JSContext *aCx, JSObject *aScope, bool *aTriedToWrap)
+{
+  return dom::HTMLElementBinding::Wrap(aCx, aScope, this, aTriedToWrap);
+}
old mode 100644
new mode 100755
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -3559,18 +3559,19 @@ nsresult nsHTMLMediaElement::UpdateChann
   return NS_OK;
 }
 
 void nsHTMLMediaElement::UpdateAudioChannelPlayingState()
 {
   // The nsHTMLMediaElement is registered to the AudioChannelService only on B2G.
 #ifdef MOZ_B2G
   bool playingThroughTheAudioChannel =
-     (mReadyState >= nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
-      IsPotentiallyPlaying());
+     (mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
+      !mPaused &&
+      !IsPlaybackEnded());
   if (playingThroughTheAudioChannel != mPlayingThroughTheAudioChannel) {
     mPlayingThroughTheAudioChannel = playingThroughTheAudioChannel;
 
     if (!mAudioChannelAgent) {
       nsresult rv;
       mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1", &rv);
       if (!mAudioChannelAgent) {
         return;
--- a/content/html/content/src/nsHTMLUnknownElement.cpp
+++ b/content/html/content/src/nsHTMLUnknownElement.cpp
@@ -1,20 +1,28 @@
 /* -*- 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 "nsHTMLUnknownElement.h"
+#include "mozilla/dom/HTMLElementBinding.h"
 
 using namespace mozilla::dom;
 
 NS_IMPL_ADDREF_INHERITED(nsHTMLUnknownElement, Element)
 NS_IMPL_RELEASE_INHERITED(nsHTMLUnknownElement, Element)
 
+JSObject*
+nsHTMLUnknownElement::WrapNode(JSContext *aCx, JSObject *aScope,
+                               bool *aTriedToWrap)
+{
+  return HTMLUnknownElementBinding::Wrap(aCx, aScope, this, aTriedToWrap);
+}
+
 NS_IMPL_NS_NEW_HTML_ELEMENT(Unknown)
 
 DOMCI_NODE_DATA(HTMLUnknownElement, nsHTMLUnknownElement)
 
 // QueryInterface implementation for nsHTMLUnknownElement
 NS_INTERFACE_TABLE_HEAD(nsHTMLUnknownElement)
   NS_HTML_CONTENT_INTERFACE_TABLE1(nsHTMLUnknownElement,
                                    nsIDOMHTMLUnknownElement)
--- a/content/html/content/src/nsHTMLUnknownElement.h
+++ b/content/html/content/src/nsHTMLUnknownElement.h
@@ -3,23 +3,24 @@
  * 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 nsHTMLUnknownElement_h___
 #define nsHTMLUnknownElement_h___
 
 #include "nsGenericHTMLElement.h"
 #include "nsIDOMHTMLUnknownElement.h"
 
-class nsHTMLUnknownElement : public nsGenericHTMLElement
-                           , public nsIDOMHTMLUnknownElement
+class nsHTMLUnknownElement MOZ_FINAL : public nsGenericHTMLElement
+                                     , public nsIDOMHTMLUnknownElement
 {
 public:
   nsHTMLUnknownElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : nsGenericHTMLElement(aNodeInfo)
   {
+    SetIsDOMBinding();
     if (NodeInfo()->Equals(nsGkAtoms::bdi)) {
       SetHasDirAuto();
     }
   }
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
@@ -32,11 +33,15 @@ public:
   // nsIDOMHTMLElement
   NS_FORWARD_NSIDOMHTMLELEMENT_TO_GENERIC
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   virtual nsXPCClassInfo* GetClassInfo();
 
   virtual nsIDOMNode* AsDOMNode() { return this; }
+
+protected:
+  virtual JSObject* WrapNode(JSContext *aCx, JSObject *aScope,
+                             bool *aTriedToWrap) MOZ_OVERRIDE;
 };
 
 #endif /* nsHTMLUnknownElement_h___ */
--- a/content/html/content/test/forms/test_form_attribute-1.html
+++ b/content/html/content/test/forms/test_form_attribute-1.html
@@ -402,40 +402,40 @@ var elementNames = [
   'button', 'fieldset', 'input', 'label', 'object', 'output', 'select',
   'textarea'
 ];
 
 var todoElements = [
   ['keygen', 'Keygen'],
 ];
 
-for each(var e in todoElements) {
+for (var e of todoElements) {
   var node = document.createElement(e[0]);
   var nodeString = HTMLElement.prototype.toString.apply(node);
   nodeString = nodeString.replace(/Element[\] ].*/, "Element");
   todo_is(nodeString, "[object HTML" + e[1] + "Element",
           e[0] + " should not be implemented");
 }
 
-for each(var name in elementNames) {
+for (var name of elementNames) {
   var elements = [
     document.createElement(name),
     document.createElement(name),
   ];
 
-  for each(var func in functions) {
+  for (var func of functions) {
     // Clean-up.
     while (content.firstChild) {
       content.removeChild(content.firstChild);
     }
-    for each(form in forms) {
+    for (form of forms) {
       content.appendChild(form);
       form.removeAttribute('id');
     }
-    for each(e in elements) {
+    for (e of elements) {
       content.appendChild(e);
       e.removeAttribute('form');
       is(e.form, null, "The element should not have a form owner");
     }
 
     // Calling the test.
     var results = func(forms, elements);
 
@@ -454,17 +454,17 @@ for each(var name in elementNames) {
         }
         is(elementsList[j].form, formsList[i],
            "The form owner should be the form associated to the list");
       }
     }
   }
 
   // Cleaning-up.
-  for each(e in elements) {
+  for (e of elements) {
     e.parentNode.removeChild(e);
     e = null;
   }
 }
 
 </script>
 </pre>
 </body>
--- a/content/html/content/test/forms/test_input_email.html
+++ b/content/html/content/test/forms/test_input_email.html
@@ -139,45 +139,45 @@ var multipleValues = [
 /* Additional username checks. */
 
 var legalCharacters = "abcdefghijklmnopqrstuvwxyz";
 legalCharacters += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 legalCharacters += "0123456789";
 legalCharacters += "!#$%&'*+-/=?^_`{|}~.";
 
 // Add all username legal characters individually to the list.
-for each (c in legalCharacters) {
+for (c of legalCharacters) {
   values.push([c + "@bar.com", true]);
 }
 // Add the concatenation of all legal characters too.
 values.push([legalCharacters + "@bar.com", true]);
 
 // Add username illegal characters, the same way.
 var illegalCharacters = "()<>[]:;@\\, \t";
-for each (c in illegalCharacters) {
+for (c of illegalCharacters) {
   values.push([illegalCharacters + "@bar.com", false]);
 }
 
 /* Additional domain checks. */
 
 legalCharacters = "abcdefghijklmnopqrstuvwxyz";
 legalCharacters += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 legalCharacters += "0123456789";
 legalCharacters += "-";
 
 // Add domain legal characters (except '.' because it's special).
-for each (c in legalCharacters) {
+for (c of legalCharacters) {
   values.push(["foo@foo.bar" + c, true]);
 }
 // Add the concatenation of all legal characters too.
 values.push(["foo@bar.com" + legalCharacters, true]);
 
 // Add domain illegal characters.
 illegalCharacters = "()<>[]:;@\\,!#$%&'*+/=?^_`{|}~ \t";
-for each (c in illegalCharacters) {
+for (c of illegalCharacters) {
   values.push(['foo@foo.ba' + c + 'r', false]);
 }
 
 values.forEach(function([value, valid, todo]) {
   if (todo === true) {
     email.value = value;
     todo_is(email.validity.valid, true, "value should be valid");
   } else {
--- a/content/html/content/test/forms/test_input_list_attribute.html
+++ b/content/html/content/test/forms/test_input_list_attribute.html
@@ -230,17 +230,17 @@ function test17(aContent, aInput) {
   return null;
 }
 
 var tests = [ test1, test2, test3, test4, test5, test6, test7, test8, test9,
               test10, test11, test12, test13, test14, test15, test16, test17 ];
 
 test0();
 
-for each (var test in tests) {
+for (var test of tests) {
   var content = document.getElementById('content');
 
   // Clean-up.
   content.textContent = '';
 
   var input = document.createElement("input");
   var res = test(content, input);
 
--- a/content/html/content/test/forms/test_input_number_value.html
+++ b/content/html/content/test/forms/test_input_number_value.html
@@ -102,25 +102,25 @@ function submitNextValue() {
 var valueIndex = 0;
 var submitMethod = submitForm;
 
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(function () {
   SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function() {
     input.type = "number";
 
-    for each (data in validData) {
+    for (data of validData) {
       input.value = "";
       SpecialPowers.focus(input);
       sendString(data);
       input.blur();
       is(input.value, data, "valid user input should not be sanitized");
     }
 
-    for each (data in invalidData) {
+    for (data of invalidData) {
       input.value = "";
       SpecialPowers.focus(input);
       sendString(data);
       input.blur();
       is(input.value, "", "invalid user input should be sanitized");
     }
 
     testData = validData;
--- a/content/html/content/test/forms/test_max_attribute.html
+++ b/content/html/content/test/forms/test_max_attribute.html
@@ -74,17 +74,17 @@ function checkValidity(aElement, aValidi
        ":in-range matches status should be " + aValidity);
     is(aElement.mozMatchesSelector(":out-of-range"), !aValidity,
        ":out-of-range matches status should be " + !aValidity);
   }
 }
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function() {
-for each (var data in types) {
+for (var data of types) {
   input.type = data[0];
   var apply = data[1];
 
   if (data[2]) {
     todo_is(input.type, data[0], data[0] + " isn't implemented yet");
     continue;
   }
 
--- a/content/html/content/test/forms/test_meter_element.html
+++ b/content/html/content/test/forms/test_meter_element.html
@@ -81,17 +81,17 @@ function checkValueAttribute()
     [  0.5 ],
     [  1.0 ],
     // Check double-precision value.
     [  0.234567898765432 ],
   ];
 
   var element = document.createElement('meter');
 
-  for each(var test in tests) {
+  for (var test of tests) {
     if (test[2]) {
       element.setAttribute('max', test[2]);
     }
 
     if (test[3]) {
       element.setAttribute('min', test[3]);
     }
 
@@ -113,17 +113,17 @@ function checkMinAttribute()
     [  1.0 ],
     [  2.0 ],
     // Check double-precision value.
     [  0.234567898765432 ],
   ];
 
   var element = document.createElement('meter');
 
-  for each(var test in tests) {
+  for (var test of tests) {
     checkAttribute(element, 'min', test[0], test[1]);
   }
 }
 
 function checkMaxAttribute()
 {
   var tests = [
     // max default value is 1.0.
@@ -139,17 +139,17 @@ function checkMaxAttribute()
     [  1.0 ],
     [  2.0 ],
     // Check double-precision value.
     [  0.234567898765432 ],
   ];
 
   var element = document.createElement('meter');
 
-  for each(var test in tests) {
+  for (var test of tests) {
     if (test[2]) {
       element.setAttribute('min', test[2]);
     }
 
     checkAttribute(element, 'max', test[0], test[1]);
 
     element.removeAttribute('min');
   }
@@ -176,17 +176,17 @@ function checkLowAttribute()
     [  0.5 ],
     [  1.0 ],
     // Check double-precision value.
     [  0.234567898765432 ],
   ];
 
   var element = document.createElement('meter');
 
-  for each(var test in tests) {
+  for (var test of tests) {
     if (test[2]) {
       element.setAttribute('min', test[2]);
     }
     if (test[3]) {
       element.setAttribute('max', test[3]);
     }
 
     checkAttribute(element, 'low', test[0], test[1]);
@@ -217,17 +217,17 @@ function checkHighAttribute()
     [  0.5 ],
     [  1.0 ],
     // Check double-precision value.
     [  0.234567898765432 ],
   ];
 
   var element = document.createElement('meter');
 
-  for each(var test in tests) {
+  for (var test of tests) {
     if (test[2]) {
       element.setAttribute('min', test[2]);
     }
     if (test[3]) {
       element.setAttribute('max', test[3]);
     }
 
     checkAttribute(element, 'high', test[0], test[1]);
@@ -258,17 +258,17 @@ function checkOptimumAttribute()
     [  0.5 ],
     [  1.0 ],
     // Check double-precision value.
     [  0.234567898765432 ],
   ];
 
   var element = document.createElement('meter');
 
-  for each(var test in tests) {
+  for (var test of tests) {
     if (test[2]) {
       element.setAttribute('min', test[2]);
     }
     if (test[3]) {
       element.setAttribute('max', test[3]);
     }
 
     checkAttribute(element, 'optimum', test[0], test[1]);
--- a/content/html/content/test/forms/test_min_attribute.html
+++ b/content/html/content/test/forms/test_min_attribute.html
@@ -74,17 +74,17 @@ function checkValidity(aElement, aValidi
        ":in-range matches status should be " + aValidity);
     is(aElement.mozMatchesSelector(":out-of-range"), !aValidity,
        ":out-of-range matches status should be " + !aValidity);
   }
 }
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function() {
-for each (var data in types) {
+for (var data of types) {
   input.type = data[0];
   var apply = data[1];
 
   if (data[2]) {
     todo_is(input.type, data[0], data[0] + " isn't implemented yet");
     continue;
   }
 
--- a/content/html/content/test/forms/test_mozistextfield.html
+++ b/content/html/content/test/forms/test_mozistextfield.html
@@ -100,29 +100,29 @@ function checkMozIsTextFieldValueTodo(aI
           "mozIsTextField(false) should return " + aResult);
   todo_is(aInput.mozIsTextField(true), aResult,
           "mozIsTextField(true) should return " + aResult);
 }
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function() {
 // Check if the method is defined for the correct elements.
-for each (data in gElementTestData) {
+for (data of gElementTestData) {
   checkMozIsTextFieldDefined(data[0], data[1]);
 }
 
 // Check if the method returns the correct value.
 var input = document.createElement('input');
-for each (data in gInputTestData) {
+for (data of gInputTestData) {
   input.type = data[0];
   checkMozIsTextFieldValue(input, data[1]);
 }
 
 // Check for the todo's.
-for each (data in gInputTodoData) {
+for (data of gInputTodoData) {
   input.type = data[0];
   checkMozIsTextFieldValueTodo(input, data[1]);
 }
 
 SimpleTest.finish();
 });
 
 </script>
--- a/content/html/content/test/forms/test_pattern_attribute.html
+++ b/content/html/content/test/forms/test_pattern_attribute.html
@@ -263,28 +263,28 @@ var validTypes = Array('text', 'password
 var barredTypes = Array('hidden', 'reset', 'button', 'submit', 'image');
 var invalidTypes = Array('checkbox', 'radio', 'file', 'number');
 // TODO: 'datetime', 'date', 'month', 'week', 'time', 'datetime-local',
 //       'range', and 'color' do not accept the @pattern too but are not
 //       implemented yet.
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function() {
-for each (type in validTypes) {
+for (type of validTypes) {
   input.type = type;
   completeValidityCheck(input, false);
   checkPatternValidity(input);
 }
 
-for each (type in barredTypes) {
+for (type of barredTypes) {
   input.type = type;
   completeValidityCheck(input, true, true);
 }
 
-for each (type in invalidTypes) {
+for (type of invalidTypes) {
   input.type = type;
   completeValidityCheck(input, true);
 }
 
 SimpleTest.finish();
 });
 
 </script>
--- a/content/html/content/test/forms/test_progress_element.html
+++ b/content/html/content/test/forms/test_progress_element.html
@@ -80,17 +80,17 @@ function checkValueAttribute()
     [  0.5 ],
     [  1.0 ],
     // Check double-precision value.
     [  0.234567898765432 ],
   ];
 
   var element = document.createElement('progress');
 
-  for each(var test in tests) {
+  for (var test of tests) {
     if (test[2]) {
       element.setAttribute('max', test[2]);
     }
 
     checkAttribute(element, 'value', test[0], test[1]);
 
     element.removeAttribute('max');
   }
@@ -109,17 +109,17 @@ function checkMaxAttribute()
     [  1.0 ],
     [  2.0 ],
     // Check double-precision value.
     [  0.234567898765432 ],
   ];
 
   var element = document.createElement('progress');
 
-  for each(var test in tests) {
+  for (var test of tests) {
     checkAttribute(element, 'max', test[0], test[1]);
   }
 }
 
 function checkPositionAttribute()
 {
   function checkPositionValue(aElement, aValue, aMax, aExpected) {
     if (aValue != null) {
@@ -160,17 +160,17 @@ function checkPositionAttribute()
     [  10,    50,  10/50 ],
     // Values implying .position is a double.
     [ 1.0,   3.0,  1.0/3.0 ],
     [ 0.1,   0.7,  0.1/0.7  ],
   ];
 
   var element = document.createElement('progress');
 
-  for each(var test in tests) {
+  for (var test of tests) {
     checkPositionValue(element, test[0], test[1], test[2], test[3]);
   }
 }
 
 function checkIndeterminatePseudoClass()
 {
   function checkIndeterminate(aElement, aValue, aMax, aIndeterminate) {
     if (aValue != null) {
@@ -201,17 +201,17 @@ function checkIndeterminatePseudoClass()
     [ 1.0,  null, false ],
     [ 1.0, 'foo', false ],
     [ 1.0,  -1.0, false ],
     [ 0.0,   1.0, false ],
   ];
 
   var element = document.createElement('progress');
 
-  for each(var test in tests) {
+  for (var test of tests) {
     checkIndeterminate(element, test[0], test[1], test[2]);
   }
 }
 
 function checkFormListedElement(aElement)
 {
   is(document.forms[0].elements.length, 0, "the form should have no element");
 }
--- a/content/html/content/test/forms/test_required_attribute.html
+++ b/content/html/content/test/forms/test_required_attribute.html
@@ -353,34 +353,34 @@ function checkInputRequiredValidityForFi
 }
 
 checkTextareaRequiredValidity();
 
 // The require attribute behavior depend of the input type.
 // First of all, checks for types that make the element barred from
 // constraint validation.
 var typeBarredFromConstraintValidation = ["hidden", "button", "reset", "submit", "image"];
-for each (type in typeRequireNotApply) {
+for (type of typeBarredFromConstraintValidation) {
   checkInputRequiredNotApply(type, true);
 }
 
 // Then, checks for the types which do not use the required attribute.
 // TODO: check 'color' and 'range' when they will be implemented.
 var typeRequireNotApply = [];
-for each (type in typeRequireNotApply) {
+for (type of typeRequireNotApply) {
   checkInputRequiredNotApply(type, false);
 }
 
 // Now, checking for all types which accept the required attribute.
 // TODO: check 'datetime', 'date', 'month', 'week', 'time' and 'datetime-local'
 //       when they will be implemented.
 var typeRequireApply = ["text", "password", "search", "tel", "email", "url",
                         "number"];
 
-for each (type in typeRequireApply) {
+for (type of typeRequireApply) {
   checkInputRequiredValidity(type);
 }
 
 checkInputRequiredValidityForCheckbox();
 checkInputRequiredValidityForRadio();
 checkInputRequiredValidityForFile();
 
 </script>
--- a/content/html/content/test/forms/test_step_attribute.html
+++ b/content/html/content/test/forms/test_step_attribute.html
@@ -71,17 +71,17 @@ function checkValidity(aElement, aValidi
   is(aElement.mozMatchesSelector(":valid"), aElement.willValidate && aValidity,
      (aElement.willValidate && aValidity) ? ":valid should apply" : "valid shouldn't apply");
   is(aElement.mozMatchesSelector(":invalid"), aElement.willValidate && !aValidity,
      (aElement.wil && aValidity) ? ":invalid shouldn't apply" : "valid should apply");
 }
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function() {
-for each (var data in types) {
+for (var data of types) {
   var input = getFreshElement(data[0]);
   var apply = data[1];
 
   if (data[2]) {
     todo_is(input.type, data[0], data[0] + " isn't implemented yet");
     continue;
   }
 
--- a/content/html/content/test/forms/test_stepup_stepdown.html
+++ b/content/html/content/test/forms/test_stepup_stepdown.html
@@ -61,17 +61,17 @@ function checkAvailability()
     ["time", true],
     ["datetime-local", true],
     ["range", true],
   ];
 
   var element = document.createElement("input");
   element.setAttribute('value', '0');
 
-  for each (data in testData) {
+  for (data of testData) {
     var exceptionCaught = false;
     element.type = data[0];
     try {
       element.stepDown();
     } catch (e) {
       exceptionCaught = true;
     }
     is(exceptionCaught, !data[1], "stepDown() availability is not correct");
@@ -80,17 +80,17 @@ function checkAvailability()
     try {
       element.stepUp();
     } catch (e) {
       exceptionCaught = true;
     }
     is(exceptionCaught, !data[1], "stepUp() availability is not correct");
   }
 
-  for each (data in todoList) {
+  for (data of todoList) {
     var exceptionCaught = false;
     element.type = data[0];
     try {
       element.stepDown();
     } catch (e) {
       exceptionCaught = true;
     }
     todo_is(exceptionCaught, !data[1],
@@ -175,17 +175,17 @@ function checkStepDownForNumber()
     [ '0',  'any',  null,  null,  1,    null,   true ],
     [ '0',  'ANY',  null,  null,  1,    null,   true ],
     [ '0',  'AnY',  null,  null,  1,    null,   true ],
     [ '0',  'aNy',  null,  null,  1,    null,   true ],
     // With @value = step base.
     [ '1',  '2',    null,  null,  null, '-1',   false ],
   ];
 
-  for each (var data in testData) {
+  for (var data of testData) {
     var element = document.createElement("input");
     element.type = 'number';
 
     if (data[0] != null) {
       element.setAttribute('value', data[0]);
     }
 
     if (data[1] != null) {
@@ -285,17 +285,17 @@ function checkStepUpForNumber()
     [ '0',  'any',  null,  null,  1,    null,  true ],
     [ '0',  'ANY',  null,  null,  1,    null,  true ],
     [ '0',  'AnY',  null,  null,  1,    null,  true ],
     [ '0',  'aNy',  null,  null,  1,    null,  true ],
     // With @value = step base.
     [ '1',  '2',    null,  null,  null, '3',   false ],
   ];
 
-  for each (var data in testData) {
+  for (var data of testData) {
     var element = document.createElement("input");
     element.type = 'number';
 
     if (data[0] != null) {
       element.setAttribute('value', data[0]);
     }
 
     if (data[1] != null) {
--- a/content/html/content/test/forms/test_valueasnumber_attribute.html
+++ b/content/html/content/test/forms/test_valueasnumber_attribute.html
@@ -55,17 +55,17 @@ function checkAvailability()
     ["month", true],
     ["week", true],
     ["time", true],
     ["datetime-local", true],
     ["range", true],
   ];
 
 
-  for each (data in testData) {
+  for (data of testData) {
     var exceptionCatched = false;
     element.type = data[0];
     try {
       element.valueAsNumber;
     } catch (e) {
       exceptionCatched = true;
     }
     is(exceptionCatched, false,
@@ -76,17 +76,17 @@ function checkAvailability()
       element.valueAsNumber = 42;
     } catch (e) {
       exceptionCatched = true;
     }
     is(exceptionCatched, !data[1], "valueAsNumber for " + data[0] +
                                    " availability is not correct");
   }
 
-  for each (data in todoList) {
+  for (data of todoList) {
     var exceptionCatched = false;
     element.type = data[0];
     try {
       element.valueAsNumber;
     } catch (e) {
       exceptionCatched = true;
     }
     is(exceptionCatched, false,
@@ -119,17 +119,17 @@ function checkGet()
     ["e2", null],
     ["1e0.1", null],
     ["", null], // the empty string is not a number
     ["foo", null],
     ["42,13", null], // comma can't be used as a decimal separator
   ];
 
   element.type = "number";
-  for each (data in testData) {
+  for (data of testData) {
     element.value = data[0];
     if (data[1] != null) {
       is(element.valueAsNumber, data[1], "valueAsNumber should return the " +
          "floating point representation of the value");
     } else {
       ok(isNaN(element.valueAsNumber), "valueAsNumber should return NaN "  +
          "when the element value is not a number");
     }
@@ -148,17 +148,17 @@ function checkSet()
     [2e1, "20"],
     [1e-1, "0.1"], // value after e can be negative
     [1E2, "100"], // E can be used instead of e
     ["", null], // the empty string is not a number
     ["foo", null],
   ];
 
   element.type = "number";
-  for each (data in testData) {
+  for (data of testData) {
     element.valueAsNumber = data[0];
     if (data[1] != null) {
       is(element.value, data[1],
          "valueAsNumber should be able to set the value");
     } else {
       element.valueAsNumber = testData[0];
       isnot(element.value, data[1],
             "valueAsNumber should not set the value if it's not a number");
--- a/content/html/content/test/reflect.js
+++ b/content/html/content/test/reflect.js
@@ -151,17 +151,17 @@ function reflectUnsignedInt(aParameters)
   is(typeof element[attr], "number", attr + " IDL attribute should be a number");
 
   // Check default value.
   is(element[attr], defaultValue, "default value should be " + defaultValue);
   ok(!element.hasAttribute(attr), attr + " shouldn't be present");
 
   var values = [ 1, 3, 42, 2147483647 ];
 
-  for each (var value in values) {
+  for (var value of values) {
     element[attr] = value;
     is(element[attr], value, "." + attr + " should be equals " + value);
     is(element.getAttribute(attr), value,
        "@" + attr + " should be equals " + value);
 
     element.setAttribute(attr, value);
     is(element[attr], value, "." + attr + " should be equals " + value);
     is(element.getAttribute(attr), value,
@@ -183,25 +183,25 @@ function reflectUnsignedInt(aParameters)
 
   var nonValidValues = [
     /* invalid value, value in the unsigned int range */
     [ -2147483648, 2147483648 ],
     [ -1,          4294967295 ],
     [ 3147483647,  3147483647 ],
   ];
 
-  for each (var values in nonValidValues) {
+  for (var values of nonValidValues) {
     element[attr] = values[0];
     is(element.getAttribute(attr), values[1],
        "@" + attr + " should be equals to " + values[1]);
     is(element[attr], defaultValue,
        "." + attr + " should be equals to " + defaultValue);
   }
 
-  for each (var values in nonValidValues) {
+  for (var values of nonValidValues) {
     element.setAttribute(attr, values[0]);
     is(element.getAttribute(attr), values[0],
        "@" + attr + " should be equals to " + values[0]);
     is(element[attr], defaultValue,
        "." + attr + " should be equals to " + defaultValue);
   }
 
   // Setting to 0 should throw an error if nonZero is true.
--- a/content/html/content/test/test_bug274626.html
+++ b/content/html/content/test/test_bug274626.html
@@ -70,17 +70,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   }
 
   var controls=["textbox_enabled","textbox_disabled",
     "input_button_enabled", "input_button_disabled", "checkbox_enabled", 
     "checkbox_disabled", "button_enabled", "button_disabled",
     "textarea_enabled", "textarea_disabled", "select_enabled", 
     "select_disabled", "fieldset_enabled", "fieldset_disabled"];
 
-  for each(id in controls) {
+  for (id of controls) {
     var ctrl = document.getElementById(id);
     ctrl.addEventListener('mousemove', HandlesMouseMove, false);
     ctrl.handlesMouseMove = false;
     var evt = document.createEvent("MouseEvents");
     evt.initMouseEvent("mousemove", true, true, window,
       0, 0, 0, 0, 0, false, false, false, false, 0, null);
     ctrl.dispatchEvent(evt);
 
--- a/content/html/content/test/test_bug389797.html
+++ b/content/html/content/test/test_bug389797.html
@@ -36,18 +36,17 @@ function HTML_TAG(aTagName, aImplClass) 
       "nsIDOMNodeSelector",
       "nsITouchEventReceiver",
       "nsIInlineEventHandlers" ];
 
   // Some interfaces don't appear in classinfo because other interfaces that
   // inherit from them do.
   interfacesNonClassinfo[aTagName] =
     [ "nsIDOMNode",
-      "nsIDOMElement",
-      "nsISupportsWeakReference" ];
+      "nsIDOMElement" ];
 
   var interfaceName = "nsIDOM" + getClassName(aTagName);
   if (interfaceName in SpecialPowers.Ci) {  // no nsIDOMHTMLSpanElement
     interfaces[aTagName].push(interfaceName);
     interfacesNonClassinfo[aTagName].push("nsIDOMHTMLElement");
   } else {
     // Inherits directly from nsIDOMHTMLElement.
     interfaces[aTagName].push("nsIDOMHTMLElement");
@@ -73,17 +72,17 @@ function HTML_TAG(aTagName, aImplClass) 
 
 const objectIfaces = [
     "imgINotificationObserver", "nsIRequestObserver", "nsIStreamListener",
     "nsIFrameLoaderOwner", "nsIObjectLoadingContent", "nsIInterfaceRequestor",
     "nsIChannelEventSink"
   ];
 
 var objectIfaces2 = [];
-for each (var iface in objectIfaces) {
+for (var iface of objectIfaces) {
   objectIfaces2.push(iface);
 }
 objectIfaces2.push("nsIImageLoadingContent");
 
 /* List copy/pasted from nsHTMLTagList.h, with the second field modified to the
    correct classinfo (instead of the impl class) in the following cases:
 
    applet
@@ -222,17 +221,17 @@ HTML_TAG("ul", "UList");
 HTML_TAG("var", "");
 HTML_TAG("wbr", "");
 HTML_TAG("xmp", "");
 
 function tagName(aTag) {
   return "<" + aTag + ">";
 }
 
-for each (var tag in allTags) {
+for (var tag of allTags) {
   var node = document.createElement(tag);
 
   // Have to use the proto's toString(), since HTMLAnchorElement and company
   // override toString().
   var nodeString = HTMLElement.prototype.toString.apply(node);
 
   // Debug builds have extra info, so chop off after "Element" if it's followed
   // by ' ' or ']'
@@ -244,40 +243,40 @@ for each (var tag in allTags) {
   is(node instanceof window[classInfoString], true,
      tagName(tag) + " not an instance of " + classInfos[tag]);
   is(node instanceof HTMLUnknownElement, false,
      tagName(tag) + " is an instance of HTMLUnknownElement");
   is(node instanceof SpecialPowers.Ci.nsIDOMHTMLUnknownElement, false,
      tagName(tag) + " is an instance of nsIDOMHTMLUnknownElement");
 
   // Check that each node QIs to all the things we expect it to QI to
-  for each (var iface in interfaces[tag].concat(interfacesNonClassinfo[tag])) {
+  for (var iface of interfaces[tag].concat(interfacesNonClassinfo[tag])) {
     is(iface in SpecialPowers.Ci, true,
        iface + " not in Components.interfaces");
     is(node instanceof SpecialPowers.Ci[iface], true,
        tagName(tag) + " does not QI to " + iface);
   }
 
   // Now see what classinfo reports
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   var nodeClassInfo = SpecialPowers.wrap(node).QueryInterface(SpecialPowers.Ci.nsIClassInfo);
   var count = {};
   var classInfoInterfaces =
     nodeClassInfo.getInterfaces(count).
     map(function(id) { return SpecialPowers.Components.interfacesByID[id].toString(); });
 
   // Make sure that we know about all the things classinfo claims
-  for each (var classInfoInterface in classInfoInterfaces) {
+  for (var classInfoInterface of classInfoInterfaces) {
     isnot(interfaces[tag].indexOf(classInfoInterface), -1,
           "Should know about " + tagName(tag) + " implementing " +
           classInfoInterface);
   }
 
   // And make sure classinfo claims all the things we know about
-  for each (iface in interfaces[tag]) {
+  for (iface of interfaces[tag]) {
     isnot(classInfoInterfaces.indexOf(iface), -1,
           "Classinfo for " + tagName(tag) + " should claim to implement " +
           iface);
   }
 }
 </script>
 </pre>
 </body>
--- a/content/html/content/test/test_bug430351.html
+++ b/content/html/content/test/test_bug430351.html
@@ -428,17 +428,17 @@ function testElements(parent, tags, shou
     if (parent.ownerDocument.designMode == "on") {
         focusable = focusableInDesignMode;
         errorSuffix = " in a document with designMode=on";
     }
     else if (parent.contentEditable == "true") {
         focusable = focusableInContentEditable;
     }
 
-    for each (var tag in tags) {
+    for (var tag of tags) {
         parent.ownerDocument.body.focus();
 
         if (focusableElementsTODO.indexOf(tag) > -1) {
             todo_is(parent.ownerDocument.activeElement, parent.firstChild,
                     tag + " should be focusable" + errorSuffix);
             continue;
         }
 
--- a/content/html/content/test/test_bug523771.html
+++ b/content/html/content/test/test_bug523771.html
@@ -31,17 +31,17 @@ var input2Files =
 
 SimpleTest.waitForExplicitFinish();
 
 function setFileInputs () {
   f = createFileWithData(input1File.name, input1File.body);
   SpecialPowers.wrap(singleFileInput).mozSetFileNameArray([f.path], 1);
 
   var input2FileNames = [];
-  for each (file in input2Files) {
+  for (file of input2Files) {
     f = createFileWithData(file.name, file.body);
     input2FileNames.push(f.path);
   }
   SpecialPowers.wrap(multiFileInput).mozSetFileNameArray(input2FileNames, input2FileNames.length);
 }
 
 function createFileWithData(fileName, fileData) {
   var dirSvc = SpecialPowers.Cc["@mozilla.org/file/directory_service;1"]
--- a/content/html/content/test/test_bug549475.html
+++ b/content/html/content/test/test_bug549475.html
@@ -84,17 +84,17 @@ function checkSanitizing(element)
     // For url:
     "\r\n foobar    \n\r",
     // For number:
     "42",
     "13.37",
     "1.234567898765432",
   ];
 
-  for each (value in testData) {
+  for (value of testData) {
     element.setAttribute('value', value);
     is(element.value, sanitizeValue(type, value),
        "The value has not been correctly sanitized for type=" + type);
     is(element.getAttribute('value'), value,
        "The content value should not have been sanitized");
 
     if (type in valueModeValue) {
       element.setAttribute('value', 'tulip');
@@ -128,17 +128,17 @@ function checkSanitizing(element)
     // Cleaning-up.
     element.setAttribute('value', '');
     form.reset();
   }
 }
 
 var pref = SpecialPowers.getBoolPref("dom.experimental_forms");
 SpecialPowers.setBoolPref("dom.experimental_forms", true);
-for each (type in inputTypes) {
+for (type of inputTypes) {
   var form = document.forms[0];
   var element = document.createElement("input");
   element.style.display = "none";
   element.type = type;
   form.appendChild(element);
 
   checkSanitizing(element); // no frame, no editor
 
@@ -150,17 +150,17 @@ for each (type in inputTypes) {
   checkSanitizing(element); // frame, editor
 
   element.style.display = "none";
   checkSanitizing(element); // no frame, editor
 
   form.removeChild(element);
 }
 
-for each (type in todoTypes) {
+for (type of todoTypes) {
   // The only meaning of this is to have a failure when new types are introduced
   // so we will know we have to write the tests here.
   var form = document.forms[0];
   var element = document.createElement("input");
   element.type = type;
   form.appendChild(element);
 
   todo_is(element.type, type, "");
--- a/content/html/content/test/test_bug557087-2.html
+++ b/content/html/content/test/test_bug557087-2.html
@@ -157,118 +157,118 @@ function clean()
   }
 }
 
 function test1()
 {
   gHandled = 0;
 
   // Initialize children without click expected.
-  for each(var name in elementsPreventingClick) {
+  for (var name of elementsPreventingClick) {
     var element = document.createElement(name);
     fieldset2.appendChild(element);
     element.addEventListener("click", clickShouldNotHappenHandler, false);
     sendMouseEvent({type:'click'}, element);
   }
 
   // Initialize children with click expected.
-  for each(var name in elementsWithClick) {
+  for (var name of elementsWithClick) {
     var element = document.createElement(name);
     fieldset2.appendChild(element);
     element.addEventListener("click", clickShouldHappenHandler, false);
     sendMouseEvent({type:'click'}, element);
   }
 }
 
 function test2()
 {
   gHandled = 0;
   fieldset1.disabled = false;
   fieldset2.disabled = true;
 
   // Initialize children without click expected.
-  for each(var name in elementsPreventingClick) {
+  for (var name of elementsPreventingClick) {
     var element = document.createElement(name);
     fieldset2.appendChild(element);
     element.addEventListener("click", clickShouldNotHappenHandler2, false);
     sendMouseEvent({type:'click'}, element);
   }
 
   // Initialize children with click expected.
-  for each(var name in elementsWithClick) {
+  for (var name of elementsWithClick) {
     var element = document.createElement(name);
     fieldset2.appendChild(element);
     element.addEventListener("click", clickShouldHappenHandler2, false);
     sendMouseEvent({type:'click'}, element);
   }
 }
 
 function test3()
 {
   gHandled = 0;
   fieldset1.disabled = false;
   fieldset2.disabled = false;
 
   // All elements should accept the click.
-  for each(var name in elementsPreventingClick) {
+  for (var name of elementsPreventingClick) {
     var element = document.createElement(name);
     fieldset2.appendChild(element);
     element.addEventListener("click", clickShouldHappenHandler3, false);
     sendMouseEvent({type:'click'}, element);
   }
 
   // Initialize children with click expected.
-  for each(var name in elementsWithClick) {
+  for (var name of elementsWithClick) {
     var element = document.createElement(name);
     fieldset2.appendChild(element);
     element.addEventListener("click", clickShouldHappenHandler3, false);
     sendMouseEvent({type:'click'}, element);
   }
 }
 
 function test4()
 {
   gHandled = 0;
   fieldset1.disabled = false;
   fieldset2.disabled = true;
 
   fieldset2.appendChild(legendA);
 
   // All elements should accept the click.
-  for each(var name in elementsPreventingClick) {
+  for (var name of elementsPreventingClick) {
     var element = document.createElement(name);
     legendA.appendChild(element);
     element.addEventListener("click", clickShouldHappenHandler4, false);
     sendMouseEvent({type:'click'}, element);
   }
 
   // Initialize children with click expected.
-  for each(var name in elementsWithClick) {
+  for (var name of elementsWithClick) {
     var element = document.createElement(name);
     legendA.appendChild(element);
     element.addEventListener("click", clickShouldHappenHandler4, false);
     sendMouseEvent({type:'click'}, element);
   }
 }
 
 function test5()
 {
   gHandled = 0;
   fieldset2.insertBefore(legendB, legendA);
 
   // Initialize children without click expected.
-  for each(var name in elementsPreventingClick) {
+  for (var name of elementsPreventingClick) {
     var element = document.createElement(name);
     legendA.appendChild(element);
     element.addEventListener("click", clickShouldNotHappenHandler5, false);
     sendMouseEvent({type:'click'}, element);
   }
 
   // Initialize children with click expected.
-  for each(var name in elementsWithClick) {
+  for (var name of elementsWithClick) {
     var element = document.createElement(name);
     legendA.appendChild(element);
     element.addEventListener("click", clickShouldHappenHandler5, false);
     sendMouseEvent({type:'click'}, element);
   }
 }
 
 function test6()
@@ -277,25 +277,25 @@ function test6()
   fieldset2.removeChild(legendB);
   fieldset1.disabled = true;
   fieldset2.disabled = false;
 
   fieldset1.appendChild(legendA);
   legendA.appendChild(fieldset2);
 
   // All elements should accept the click.
-  for each(var name in elementsPreventingClick) {
+  for (var name of elementsPreventingClick) {
     var element = document.createElement(name);
     fieldset2.appendChild(element);
     element.addEventListener("click", clickShouldHappenHandler6, false);
     sendMouseEvent({type:'click'}, element);
   }
 
   // Initialize children with click expected.
-  for each(var name in elementsWithClick) {
+  for (var name of elementsWithClick) {
     var element = document.createElement(name);
     fieldset2.appendChild(element);
     element.addEventListener("click", clickShouldHappenHandler6, false);
     sendMouseEvent({type:'click'}, element);
   }
 }
 
 function test7()
@@ -303,25 +303,25 @@ function test7()
   gHandled = 0;
   fieldset1.disabled = true;
   fieldset2.disabled = false;
 
   fieldset1.appendChild(fieldset2);
   fieldset2.appendChild(legendA);
 
   // All elements should accept the click.
-  for each(var name in elementsPreventingClick) {
+  for (var name of elementsPreventingClick) {
     var element = document.createElement(name);
     legendA.appendChild(element);
     element.addEventListener("click", clickShouldNotHappenHandler7, false);
     sendMouseEvent({type:'click'}, element);
   }
 
   // Initialize children with click expected.
-  for each(var name in elementsWithClick) {
+  for (var name of elementsWithClick) {
     var element = document.createElement(name);
     legendA.appendChild(element);
     element.addEventListener("click", clickShouldHappenHandler7, false);
     sendMouseEvent({type:'click'}, element);
   }
 }
 
 function test8()
@@ -330,25 +330,25 @@ function test8()
   fieldset1.disabled = true;
   fieldset2.disabled = true;
 
   fieldset1.appendChild(legendA);
   legendA.appendChild(fieldset2);
   fieldset2.appendChild(legendB);
 
   // All elements should accept the click.
-  for each(var name in elementsPreventingClick) {
+  for (var name of elementsPreventingClick) {
     var element = document.createElement(name);
     legendB.appendChild(element);
     element.addEventListener("click", clickShouldHappenHandler8, false);
     sendMouseEvent({type:'click'}, element);
   }
 
   // Initialize children with click expected.
-  for each(var name in elementsWithClick) {
+  for (var name of elementsWithClick) {
     var element = document.createElement(name);
     legendB.appendChild(element);
     element.addEventListener("click", clickShouldHappenHandler8, false);
     sendMouseEvent({type:'click'}, element);
   }
 }
 
 test1();
--- a/content/html/content/test/test_bug557087-3.html
+++ b/content/html/content/test/test_bug557087-3.html
@@ -33,34 +33,34 @@ function checkCandidateForConstraintVali
   is(aElement.willValidate, aExpected, msg);
 }
 
 function checkDisabledPseudoClass(aElement, aDisabled)
 {
   var disabledElements = document.querySelectorAll(":disabled");
   var found = false;
 
-  for each(var e in disabledElements) {
+  for (var e of disabledElements) {
     if (aElement == e) {
       found = true;
       break;
     }
   }
 
   var msg = aDisabled ? aElement.tagName + " should have :disabled applying"
                       : aElement.tagName + " should not have :disabled applying";
   ok(aDisabled ? found : !found, msg);
 }
 
 function checkEnabledPseudoClass(aElement, aEnabled)
 {
   var enabledElements = document.querySelectorAll(":enabled");
   var found = false;
 
-  for each(var e in enabledElements) {
+  for (var e of enabledElements) {
     if (aElement == e) {
       found = true;
       break;
     }
   }
 
   var msg = aEnabled ? aElement.tagName + " should have :enabled applying"
                      : aElement.tagName + " should not have :enabled applying";
@@ -136,17 +136,17 @@ var fieldset1 = document.createElement("
 var fieldset2 = document.createElement("fieldset");
 var legendA = document.createElement("legend");
 var legendB = document.createElement("legend");
 var content  = document.getElementById('content');
 content.appendChild(fieldset1);
 fieldset1.appendChild(fieldset2);
 fieldset2.disabled = true;
 
-for each(var data in elements) {
+for (var data of elements) {
   var element = document.createElement(data);
 
   if (data[4]) {
     element.required = true;
   }
 
   fieldset1.disabled = false;
   fieldset2.appendChild(element);
--- a/content/html/content/test/test_bug557087-4.html
+++ b/content/html/content/test/test_bug557087-4.html
@@ -50,17 +50,17 @@ form.addEventListener("submit", function
 var inputs = [
   document.getElementById('a'),
   document.getElementById('b'),
   document.getElementById('c'),
 ];
 
 function doSubmit()
 {
-  for each(e in inputs) {
+  for (e of inputs) {
     e.focus();
     synthesizeKey("VK_RETURN", {});
   }
 }
 
 SimpleTest.waitForFocus(function() {
   doSubmit();
 
--- a/content/html/content/test/test_bug561640.html
+++ b/content/html/content/test/test_bug561640.html
@@ -35,17 +35,17 @@ function checkValid(elmt)
 
 function checkInvalid(elmt)
 {
   todo(elmt.validity.tooLong, "element should be too long");
   todo_is(window.getComputedStyle(elmt, null).getPropertyValue('background-color'),
           "rgb(255, 0, 0)", ":invalid pseudo-class should apply");
 }
 
-for each (var elmtName in elements) {
+for (var elmtName of elements) {
   var elmt = document.createElement(elmtName);
   content.appendChild(elmt);
 
   if (elmtName == 'textarea') {
     elmt.textContent = 'foo';
   } else {
     elmt.setAttribute('value', 'foo');
   }
--- a/content/html/content/test/test_bug573969.html
+++ b/content/html/content/test/test_bug573969.html
@@ -21,17 +21,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 var testData = [
   '<div>foo</div>',
   '&lt;div&gt;&lt;/div&gt;',
 ];
 
 var x = document.getElementById('x');
 
-for each (v in testData) {
+for (v of testData) {
   x.innerHTML = v;
   is(x.innerHTML, v, "innerHTML value should not be escaped");
 }
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/html/content/test/test_bug590353-1.html
+++ b/content/html/content/test/test_bug590353-1.html
@@ -13,17 +13,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 590353 **/
 
 var testData = ['checkbox', 'radio'];
 
-for each(var data in testData) {
+for (var data of testData) {
   var e = document.createElement('input');
   e.type = data;
   e.checked = true;
   e.value = "foo";
 
   is(e.value, "foo", "foo should be the new " + data + "value");
   is(e.getAttribute('value'), "foo", "foo should be the new " + data +
                                      " value attribute value");
--- a/content/html/content/test/test_bug590353-2.html
+++ b/content/html/content/test/test_bug590353-2.html
@@ -48,17 +48,17 @@ function createFileWithData(fileName, fi
 
   return testFile;
 }
 
 var content = document.getElementById('content');
 var form = document.createElement('form');
 content.appendChild(form);
 
-for each (var data in testData) {
+for (var data of testData) {
   var e = document.createElement('input');
   e.type = data[0];
 
   if (data[0] == 'checkbox' || data[0] == 'radio') {
     e.checked = data[1];
   } else if (data[0] == 'file') {
     // Need privileges to set a filename with .value and create a file.
     netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
--- a/content/html/content/test/test_bug590363.html
+++ b/content/html/content/test/test_bug590363.html
@@ -59,34 +59,34 @@ for (var i=0; i<length; ++i) {
     e.type = testData[j][0];
     is(e.value, expectedValue, ".value should still return the same value after " +
        "changing type from " + testData[i][0] + " to " + testData[j][0]);
   }
 }
 
 // For type='file' .value doesn't behave the same way.
 // We are just going to check that we do not loose the value.
-for each (var data in testData) {
+for (var data of testData) {
   var e = document.createElement('input');
   e.type = data[0];
   e.value = 'foo';
   e.type = 'file';
   e.type = data[0];
 
   if (data[1]) {
     is(e.value, '', ".value should have been reset to the empty string after " +
        "changing type from " + data[0] + " to 'file' then reverting to " + data[0]);
   } else {
     is(e.value, 'foo', ".value should still return the same value after " +
        "changing type from " + data[0] + " to 'file' then reverting to " + data[0]);
   }
 }
 
 // TODO checks
-for each (var type in todoTypes) {
+for (var type of todoTypes) {
   var e = document.createElement('input');
   e.type = type;
   todo_is(e.type, type, type + " type isn't supported yet");
 }
 
 </script>
 </pre>
 </body>
--- a/content/html/content/test/test_bug595429.html
+++ b/content/html/content/test/test_bug595429.html
@@ -27,17 +27,17 @@ var testData = [
   "foo bar",
 ];
 
 is(fieldset.getAttribute("name"), null,
    "By default, name content attribute should be null");
 is(fieldset.name, "",
    "By default, name IDL attribute should be the empty string");
 
-for each(var data in testData) {
+for (var data of testData) {
   fieldset.setAttribute("name", data);
   is(fieldset.getAttribute("name"), data,
      "name content attribute should be " + data);
   is(fieldset.name, data, "name IDL attribute should be " + data);
 
   fieldset.setAttribute("name", "");
   fieldset.name = data;
   is(fieldset.getAttribute("name"), data,
--- a/content/html/content/test/test_bug595449.html
+++ b/content/html/content/test/test_bug595449.html
@@ -78,17 +78,17 @@ var testData = [
   [ "<legend><input></legend><legend><input></legend>", 2, [ HTMLInputElement, HTMLInputElement ] ],
   [ "<legend><input></legend><input>", 2, [ HTMLInputElement, HTMLInputElement ] ],
   [ "<fieldset></fieldset>", 1, [ HTMLFieldSetElement ] ],
   [ "<fieldset><input></fieldset>", 2, [ HTMLFieldSetElement, HTMLInputElement ] ],
   [ "<fieldset><fieldset><input></fieldset></fieldset>", 3, [ HTMLFieldSetElement, HTMLFieldSetElement, HTMLInputElement ] ],
   [ "<button></button><fieldset></fieldset><input><keygen><object><output></output><select></select><textarea></textarea>", 8, [ HTMLButtonElement, HTMLFieldSetElement, HTMLInputElement, HTMLSelectElement, HTMLObjectElement, HTMLOutputElement, HTMLSelectElement, HTMLTextAreaElement ] ],
 ];
 
-for each(var data in testData) {
+for (var data of testData) {
   fieldset.innerHTML = data[0];
   is(fieldset.elements.length, data[1],
      "fieldset.elements should contain " + data[1] + " elements");
 
   for (var i=0; i<data[1]; ++i) {
     ok(fieldset.elements[i] instanceof data[2][i],
        "fieldset.elements[" + i + "] should be instance of " + data[2][i])
   }
--- a/content/html/content/test/test_bug596350.html
+++ b/content/html/content/test/test_bug596350.html
@@ -39,17 +39,17 @@ var testData = [
   [ 2, "1", "1" ],
   [ 2, "-1", "-1" ],
 ];
 
 var objects = document.getElementsByTagName("object");
 
 function runTests()
 {
-  for each(var data in testData) {
+  for (var data of testData) {
     var obj = objects[data[0]];
 
     if (data[1]) {
       obj.setAttribute("tabindex", data[1]);
     }
 
     is(obj.tabIndex, data[2], "tabIndex value should be " + data[2]);
 
--- a/content/html/content/test/test_bug598643.html
+++ b/content/html/content/test/test_bug598643.html
@@ -55,17 +55,17 @@ var types = [
     "datetime-local" ],
 ];
 
 var input = document.createElement("input");
 input.maxLength = 1;
 input.value = "foo";
 
 // Too long types.
-for each (type in types[0]) {
+for (type of types[0]) {
   input.type = type
   if (type == 'email') {
     input.value = "foo@bar.com";
   } else if (type == 'url') {
     input.value = 'http://foo.org';
   }
 
   todo(!input.validity.valid, "the element should be invalid [type=" + type + "]");
@@ -73,25 +73,25 @@ for each (type in types[0]) {
        "the element should suffer from being too long [type=" + type + "]");
 
   if (type == 'email' || type == 'url') {
     input.value = 'foo';
   }
 }
 
 // Not too long types.
-for each (type in types[1]) {
+for (type of types[1]) {
   input.type = type
   ok(input.validity.valid, "the element should be valid [type=" + type + "]");
   ok(!input.validity.tooLong,
      "the element shouldn't suffer from being too long [type=" + type + "]");
 }
 
 // Not too long types but TODO.
-for each (type in types[2]) {
+for (type of types[2]) {
   input.type = type
   ok(input.validity.valid, "the element should be valid [type=" + type + "]");
   ok(!input.validity.tooLong,
      "the element shouldn't suffer from being too long [type=" + type + "]");
 }
 
 testFileControl(input);
 
--- a/content/html/content/test/test_bug600155.html
+++ b/content/html/content/test/test_bug600155.html
@@ -16,17 +16,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 600155 **/
 
 var subjectForConstraintValidation = [ "input", "select", "textarea" ];
 var content = document.getElementById('content');
 
-for each (var eName in subjectForConstraintValidation) {
+for (var eName of subjectForConstraintValidation) {
   var e = document.createElement(eName);
   content.appendChild(e);
   e.setAttribute("x-moz-errormessage", "foo");
   if ("required" in e) {
     e.required = true;
   } else {
     e.setCustomValidity("bar");
   }
--- a/content/html/content/test/test_bug607145.html
+++ b/content/html/content/test/test_bug607145.html
@@ -47,24 +47,24 @@ function reflectURL(aElement, aAttr)
     [ "", "" ], // TODO: doesn't follow the specs, should be location.href.
     [ " ", location.href ],
     [ "../", previousDir ],
     [ "...", dir + "..." ],
     // invalid URL
     [ "http://a b/", "http://a b/" ], // TODO: doesn't follow the specs, should be "".
   ];
 
-  for each (var value in values) {
+  for (var value of values) {
     aElement[idl] = value[0];
     is(aElement[idl], value[1], "." + idl + " value should be " + value[1]);
     is(aElement.getAttribute(attr), value[0],
        "@" + attr + " value should be " + value[0]);
   }
 
-  for each (var value in values) {
+  for (var value of values) {
     aElement.setAttribute(attr, value[0]);
     is(aElement[idl], value[1], "." + idl + " value should be " + value[1]);
     is(aElement.getAttribute(attr), value[0],
        "@" + attr + " value should be " + value[0]);
   }
 }
 
 reflectURL(document.createElement("form"), "action");
--- a/content/html/content/test/test_bug618948.html
+++ b/content/html/content/test/test_bug618948.html
@@ -30,26 +30,26 @@ var handled = ({});
 function eventHandler(event)
 {
  dump("\n" + event.type + "\n");
   handled[event.type] = true;
 }
 
 function beginTest()
 {
-  for each (var e in events) {
+  for (var e of events) {
     handled[e] = false;
   }
 
   i.focus();
 }
 
 function endTest()
 {
-  for each (var e in events) {
+  for (var e of events) {
     ok(handled[e], "on" + e + " should have been called");
   }
 
   SimpleTest.finish();
 }
 
 var i = document.getElementsByTagName('input')[0];
 var b = document.getElementsByTagName('button')[0];
--- a/content/html/content/test/test_bug659596.html
+++ b/content/html/content/test/test_bug659596.html
@@ -18,49 +18,49 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 function checkReflection(option, attribute) {
   /**
    * Getting.
    */
 
   // When attribute isn't present.
   var tests = [ "", "foo" ];
-  for each (var test in tests) {
+  for (var test of tests) {
     option.removeAttribute(attribute);
     option.textContent = test;
     is(option.getAttribute(attribute), null,
        "option " + attribute + "'s value should be null");
     is(option[attribute], option.textContent,
        "option." + attribute + " should reflect the text content when the attribute isn't set");
   }
 
   // When attribute is present.
   tests = [
     [ "", "" ],
     [ "", "foo" ],
     [ "foo", "bar" ],
     [ "foo", "" ],
   ];
-  for each (var test in tests) {
+  for (var test of tests) {
     option.setAttribute(attribute, test[0]);
     option.textContent = test[1];
     is(option[attribute], option.getAttribute(attribute),
        "option." + attribute + " should reflect the content attribute when it is set");
   }
 
   /**
    * Setting.
    */
 
   // When attribute isn't present.
   tests = [
     [ "", "new" ],
     [ "foo", "new" ],
   ];
-  for each (var test in tests) {
+  for (var test of tests) {
     option.removeAttribute(attribute);
     option.textContent = test[0];
     option[attribute] = test[1]
 
     is(option.getAttribute(attribute), test[1],
        "when setting, the content attribute should change");
     is(option.textContent, test[0],
        "when setting, the text content should not change");
@@ -68,17 +68,17 @@ function checkReflection(option, attribu
 
   // When attribute is present.
   tests = [
     [ "", "", "new" ],
     [ "", "foo", "new" ],
     [ "foo", "bar", "new" ],
     [ "foo", "", "new" ],
   ];
-  for each (var test in tests) {
+  for (var test of tests) {
     option.setAttribute(attribute, test[0]);
     option.textContent = test[1];
     option[attribute] = test[2];
 
     is(option.getAttribute(attribute), test[2],
        "when setting, the content attribute should change");
     is(option.textContent, test[1],
        "when setting, the text content should not change");
--- a/content/html/content/test/test_restore_from_parser_fragment.html
+++ b/content/html/content/test/test_restore_from_parser_fragment.html
@@ -34,17 +34,17 @@ var tests = [
   [  "button", "<button></button>" ],
   [  "input", "<input>" ],
   [  "textarea", "<textarea></textarea>" ],
   [  "select", "<select></select>" ],
 ];
 
 var element = null;
 
-for each (var test in tests) {
+for (var test of tests) {
   appendHTML(content, test[1]);
   element = content.getElementsByTagName(test[0])[0];
   is(element.disabled, false, "element shouldn't be disabled");
   element.disabled = true;
   is(element.disabled, true, "element should be disabled");
 
   clearHTML(content);
 
--- a/content/media/nsDOMMediaStream.cpp
+++ b/content/media/nsDOMMediaStream.cpp
@@ -90,30 +90,28 @@ nsDOMLocalMediaStream::CreateSourceStrea
   nsRefPtr<nsDOMLocalMediaStream> stream = new nsDOMLocalMediaStream();
   stream->SetHintContents(aHintContents);
   MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
   stream->mStream = gm->CreateSourceStream(stream);
   return stream.forget();
 }
 
 already_AddRefed<nsDOMMediaStream>
-nsDOMMediaStream::CreateTrackUnionStream(uint32_t aHintContents)
+nsDOMMediaStream::CreateTrackUnionStream()
 {
   nsRefPtr<nsDOMMediaStream> stream = new nsDOMMediaStream();
-  stream->SetHintContents(aHintContents);
   MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
   stream->mStream = gm->CreateTrackUnionStream(stream);
   return stream.forget();
 }
 
 already_AddRefed<nsDOMLocalMediaStream>
-nsDOMLocalMediaStream::CreateTrackUnionStream(uint32_t aHintContents)
+nsDOMLocalMediaStream::CreateTrackUnionStream()
 {
   nsRefPtr<nsDOMLocalMediaStream> stream = new nsDOMLocalMediaStream();
-  stream->SetHintContents(aHintContents);
   MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
   stream->mStream = gm->CreateTrackUnionStream(stream);
   return stream.forget();
 }
 
 bool
 nsDOMMediaStream::CombineWithPrincipal(nsIPrincipal* aPrincipal)
 {
--- a/content/media/nsDOMMediaStream.h
+++ b/content/media/nsDOMMediaStream.h
@@ -65,17 +65,17 @@ public:
     HINT_CONTENTS_VIDEO = 0x00000002U
   };
   uint32_t GetHintContents() const { return mHintContents; }
   void SetHintContents(uint32_t aHintContents) { mHintContents = aHintContents; }
 
   /**
    * Create an nsDOMMediaStream whose underlying stream is a TrackUnionStream.
    */
-  static already_AddRefed<nsDOMMediaStream> CreateTrackUnionStream(uint32_t aHintContents = 0);
+  static already_AddRefed<nsDOMMediaStream> CreateTrackUnionStream();
 
 protected:
   // MediaStream is owned by the graph, but we tell it when to die, and it won't
   // die until we let it.
   MediaStream* mStream;
   // Principal identifying who may access the contents of this stream.
   // If null, this stream can be used by anyone because it has no content yet.
   nsCOMPtr<nsIPrincipal> mPrincipal;
@@ -101,12 +101,12 @@ public:
   /**
    * Create an nsDOMLocalMediaStream whose underlying stream is a SourceMediaStream.
    */
   static already_AddRefed<nsDOMLocalMediaStream> CreateSourceStream(uint32_t aHintContents);
 
   /**
    * Create an nsDOMLocalMediaStream whose underlying stream is a TrackUnionStream.
    */
-  static already_AddRefed<nsDOMLocalMediaStream> CreateTrackUnionStream(uint32_t aHintContents = 0);
+  static already_AddRefed<nsDOMLocalMediaStream> CreateTrackUnionStream();
 };
 
 #endif /* NSDOMMEDIASTREAM_H_ */
--- a/content/media/plugins/MediaPluginHost.cpp
+++ b/content/media/plugins/MediaPluginHost.cpp
@@ -9,16 +9,17 @@
 #include "MediaResource.h"
 #include "nsHTMLMediaElement.h"
 #include "MediaPluginHost.h"
 #include "nsXPCOMStrings.h"
 #include "nsISeekableStream.h"
 #include "pratom.h"
 #include "MediaPluginReader.h"
 #include "nsIGfxInfo.h"
+#include "gfxCrashReporterUtils.h"
 
 #include "MPAPI.h"
 
 #if defined(ANDROID) || defined(MOZ_WIDGET_GONK)
 #include "android/log.h"
 #define ALOG(args...)  __android_log_print(ANDROID_LOG_INFO, "MediaPluginHost" , ## args)
 #else
 #define ALOG(args...) /* do nothing */
@@ -108,28 +109,32 @@ static bool IsOmxSupported()
   bool disabled =
       Preferences::GetBool("stagefright.disabled", false);
 
   if (disabled) {
     NS_WARNING("XXX stagefright disabled\n");
     return false;
   }
 
+  ScopedGfxFeatureReporter reporter("Stagefright", forceEnabled);
+
   if (!forceEnabled) {
     nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
     if (gfxInfo) {
       int32_t status;
       if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_STAGEFRIGHT, &status))) {
         if (status != nsIGfxInfo::FEATURE_NO_INFO) {
           NS_WARNING("XXX stagefright blacklisted\n");
           return false;
         }
       }
     }
   }
+
+  reporter.SetSuccessful();
   return true;
 }
 
 // Return the name of the shared library that implements Omx based decoding. This varies
 // depending on libstagefright version installed on the device and whether it is B2G vs Android.
 // nullptr is returned if Omx decoding is not supported on the device,
 static const char* GetOmxLibraryName()
 {
--- a/content/smil/nsSMILCSSProperty.cpp
+++ b/content/smil/nsSMILCSSProperty.cpp
@@ -223,16 +223,17 @@ nsSMILCSSProperty::IsPropertyAnimatable(
     case eCSSProperty_image_rendering:
     case eCSSProperty_letter_spacing:
     case eCSSProperty_lighting_color:
     case eCSSProperty_marker:
     case eCSSProperty_marker_end:
     case eCSSProperty_marker_mid:
     case eCSSProperty_marker_start:
     case eCSSProperty_mask:
+    case eCSSProperty_mask_type:
     case eCSSProperty_opacity:
     case eCSSProperty_overflow:
     case eCSSProperty_pointer_events:
     case eCSSProperty_shape_rendering:
     case eCSSProperty_stop_color:
     case eCSSProperty_stop_opacity:
     case eCSSProperty_stroke:
     case eCSSProperty_stroke_dasharray:
--- a/content/svg/content/src/SVGAnimatedPreserveAspectRatio.cpp
+++ b/content/svg/content/src/SVGAnimatedPreserveAspectRatio.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Util.h"
 
 #include "SVGAnimatedPreserveAspectRatio.h"
 #include "nsWhitespaceTokenizer.h"
 #include "nsSMILValue.h"
+#include "nsSVGAttrTearoffTable.h"
 #include "SMILEnumType.h"
 #include "nsAttrValueInlines.h"
 
 using namespace mozilla;
 
 ////////////////////////////////////////////////////////////////////////
 // SVGAnimatedPreserveAspectRatio class
 
@@ -62,16 +63,23 @@ NS_INTERFACE_MAP_END
 /* Implementation */
 
 static const char *sAlignStrings[] =
   { "none", "xMinYMin", "xMidYMin", "xMaxYMin", "xMinYMid", "xMidYMid",
     "xMaxYMid", "xMinYMax", "xMidYMax", "xMaxYMax" };
 
 static const char *sMeetOrSliceStrings[] = { "meet", "slice" };
 
+static nsSVGAttrTearoffTable<SVGAnimatedPreserveAspectRatio, SVGAnimatedPreserveAspectRatio::DOMAnimPAspectRatio>
+  sSVGAnimatedPAspectRatioTearoffTable;
+static nsSVGAttrTearoffTable<SVGAnimatedPreserveAspectRatio, SVGAnimatedPreserveAspectRatio::DOMBaseVal>
+  sBaseSVGPAspectRatioTearoffTable;
+static nsSVGAttrTearoffTable<SVGAnimatedPreserveAspectRatio, SVGAnimatedPreserveAspectRatio::DOMAnimVal>
+  sAnimSVGPAspectRatioTearoffTable;
+
 static uint16_t
 GetAlignForString(const nsAString &aAlignString)
 {
   for (uint32_t i = 0 ; i < ArrayLength(sAlignStrings) ; i++) {
     if (aAlignString.EqualsASCII(sAlignStrings[i])) {
       return (i + nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE);
     }
   }
@@ -125,37 +133,53 @@ SVGPreserveAspectRatio::operator==(const
     mDefer == aOther.mDefer;
 }
 
 nsresult
 SVGAnimatedPreserveAspectRatio::ToDOMBaseVal(
   nsIDOMSVGPreserveAspectRatio **aResult,
   nsSVGElement *aSVGElement)
 {
-  *aResult = new DOMBaseVal(this, aSVGElement);
-  if (!*aResult)
-    return NS_ERROR_OUT_OF_MEMORY;
+  nsRefPtr<DOMBaseVal> domBaseVal =
+    sBaseSVGPAspectRatioTearoffTable.GetTearoff(this);
+  if (!domBaseVal) {
+    domBaseVal = new DOMBaseVal(this, aSVGElement);
+    sBaseSVGPAspectRatioTearoffTable.AddTearoff(this, domBaseVal);
+  }
 
-  NS_ADDREF(*aResult);
+  domBaseVal.forget(aResult);
   return NS_OK;
 }
 
+SVGAnimatedPreserveAspectRatio::DOMBaseVal::~DOMBaseVal()
+{
+  sBaseSVGPAspectRatioTearoffTable.RemoveTearoff(mVal);
+}
+
 nsresult
 SVGAnimatedPreserveAspectRatio::ToDOMAnimVal(
   nsIDOMSVGPreserveAspectRatio **aResult,
   nsSVGElement *aSVGElement)
 {
-  *aResult = new DOMAnimVal(this, aSVGElement);
-  if (!*aResult)
-    return NS_ERROR_OUT_OF_MEMORY;
+  nsRefPtr<DOMAnimVal> domAnimVal =
+    sAnimSVGPAspectRatioTearoffTable.GetTearoff(this);
+  if (!domAnimVal) {
+    domAnimVal = new DOMAnimVal(this, aSVGElement);
+    sAnimSVGPAspectRatioTearoffTable.AddTearoff(this, domAnimVal);
+  }
 
-  NS_ADDREF(*aResult);
+  domAnimVal.forget(aResult);
   return NS_OK;
 }
 
+SVGAnimatedPreserveAspectRatio::DOMAnimVal::~DOMAnimVal()
+{
+  sAnimSVGPAspectRatioTearoffTable.RemoveTearoff(mVal);
+}
+
 static nsresult
 ToPreserveAspectRatio(const nsAString &aString,
                       SVGPreserveAspectRatio *aValue)
 {
   if (aString.IsEmpty() || NS_IsAsciiWhitespace(aString[0])) {
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
@@ -301,22 +325,29 @@ SVGAnimatedPreserveAspectRatio::SetAnimV
   aSVGElement->DidAnimatePreserveAspectRatio();
 }
 
 nsresult
 SVGAnimatedPreserveAspectRatio::ToDOMAnimatedPreserveAspectRatio(
   nsIDOMSVGAnimatedPreserveAspectRatio **aResult,
   nsSVGElement *aSVGElement)