Merge mozilla-inbound and mozilla-central.
authorL. David Baron <dbaron@dbaron.org>
Sat, 22 Dec 2012 00:05:00 -0500
changeset 125959 77d65b2c81c809d3f0342181ea3baf2693b0a576
parent 125770 ae6237161b6c49c91cb0e439cdffeeb7f8c87123 (current diff)
parent 125958 81f530168b395aa43b087fafcf65a801f8135430 (diff)
child 125960 756335a3066f7066ca7738d531368a7e992631f4
child 125972 be3375d887c61a36826efcd642a1f72597864368
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [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-inbound and mozilla-central.
browser/themes/gnomestripe/downloads/downloads.css
browser/themes/winstripe/downloads/downloads.css
dom/encoding/TextDecoder.h
dom/encoding/TextEncoder.h
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
toolkit/components/places/tests/mochitest/test_bug_461710.html
--- 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/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/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
@@ -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
@@ -1757,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/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/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/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/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
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
 
--- 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/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/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);
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -195,16 +195,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/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_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/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)
 {
-  *aResult = new DOMAnimPAspectRatio(this, aSVGElement);
-  if (!*aResult)
-    return NS_ERROR_OUT_OF_MEMORY;
+  nsRefPtr<DOMAnimPAspectRatio> domAnimatedPAspectRatio =
+    sSVGAnimatedPAspectRatioTearoffTable.GetTearoff(this);
+  if (!domAnimatedPAspectRatio) {
+    domAnimatedPAspectRatio = new DOMAnimPAspectRatio(this, aSVGElement);
+    sSVGAnimatedPAspectRatioTearoffTable.AddTearoff(this, domAnimatedPAspectRatio);
+  }
+  domAnimatedPAspectRatio.forget(aResult);
+  return NS_OK;
+}
 
-  NS_ADDREF(*aResult);
-  return NS_OK;
+SVGAnimatedPreserveAspectRatio::DOMAnimPAspectRatio::~DOMAnimPAspectRatio()
+{
+  sSVGAnimatedPAspectRatioTearoffTable.RemoveTearoff(mVal);
 }
 
 nsISMILAttr*
 SVGAnimatedPreserveAspectRatio::ToSMILAttr(nsSVGElement *aSVGElement)
 {
   return new SMILPreserveAspectRatio(this, aSVGElement);
 }
 
--- a/content/svg/content/src/SVGAnimatedPreserveAspectRatio.h
+++ b/content/svg/content/src/SVGAnimatedPreserveAspectRatio.h
@@ -150,16 +150,17 @@ private:
 public:
   struct DOMBaseVal MOZ_FINAL : public nsIDOMSVGPreserveAspectRatio
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMBaseVal)
 
     DOMBaseVal(SVGAnimatedPreserveAspectRatio* aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
+    virtual ~DOMBaseVal();
     
     SVGAnimatedPreserveAspectRatio* mVal; // kept alive because it belongs to mSVGElement
     nsRefPtr<nsSVGElement> mSVGElement;
     
     NS_IMETHOD GetAlign(uint16_t* aAlign)
       { *aAlign = mVal->GetBaseValue().GetAlign(); return NS_OK; }
     NS_IMETHOD SetAlign(uint16_t aAlign)
       { return mVal->SetBaseAlign(aAlign, mSVGElement); }
@@ -172,16 +173,17 @@ public:
 
   struct DOMAnimVal MOZ_FINAL : public nsIDOMSVGPreserveAspectRatio
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimVal)
 
     DOMAnimVal(SVGAnimatedPreserveAspectRatio* aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
+    virtual ~DOMAnimVal();
     
     SVGAnimatedPreserveAspectRatio* mVal; // kept alive because it belongs to mSVGElement
     nsRefPtr<nsSVGElement> mSVGElement;
     
     // Script may have modified animation parameters or timeline -- DOM getters
     // need to flush any resample requests to reflect these modifications.
     NS_IMETHOD GetAlign(uint16_t* aAlign)
     {
@@ -205,16 +207,17 @@ public:
   struct DOMAnimPAspectRatio MOZ_FINAL : public nsIDOMSVGAnimatedPreserveAspectRatio
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimPAspectRatio)
 
     DOMAnimPAspectRatio(SVGAnimatedPreserveAspectRatio* aVal,
                         nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
+    virtual ~DOMAnimPAspectRatio();
 
     // kept alive because it belongs to content:
     SVGAnimatedPreserveAspectRatio* mVal;
 
     nsRefPtr<nsSVGElement> mSVGElement;
 
     NS_IMETHOD GetBaseVal(nsIDOMSVGPreserveAspectRatio **aBaseVal)
       { return mVal->ToDOMBaseVal(aBaseVal, mSVGElement); }
--- a/content/svg/content/src/nsSVGAngle.cpp
+++ b/content/svg/content/src/nsSVGAngle.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 "nsSVGAngle.h"
 #include "prdtoa.h"
 #include "nsTextFormatter.h"
+#include "nsSVGAttrTearoffTable.h"
 #include "nsSVGMarkerElement.h"
 #include "nsMathUtils.h"
 #include "nsContentUtils.h" // NS_ENSURE_FINITE
 #include "nsSMILValue.h"
 #include "SVGOrientSMILType.h"
 #include "nsAttrValueInlines.h"
 #include "mozilla/Attributes.h"
 
@@ -122,16 +123,23 @@ static nsIAtom** const unitMap[] =
 {
   nullptr, /* SVG_ANGLETYPE_UNKNOWN */
   nullptr, /* SVG_ANGLETYPE_UNSPECIFIED */
   &nsGkAtoms::deg,
   &nsGkAtoms::rad,
   &nsGkAtoms::grad
 };
 
+static nsSVGAttrTearoffTable<nsSVGAngle, nsSVGAngle::DOMAnimatedAngle>
+  sSVGAnimatedAngleTearoffTable;
+static nsSVGAttrTearoffTable<nsSVGAngle, nsSVGAngle::DOMBaseVal>
+  sBaseSVGAngleTearoffTable;
+static nsSVGAttrTearoffTable<nsSVGAngle, nsSVGAngle::DOMAnimVal>
+  sAnimSVGAngleTearoffTable;
+
 /* Helper functions */
 
 static bool
 IsValidUnitType(uint16_t unit)
 {
   if (unit > nsIDOMSVGAngle::SVG_ANGLETYPE_UNKNOWN &&
       unit <= nsIDOMSVGAngle::SVG_ANGLETYPE_GRAD)
     return true;
@@ -304,35 +312,51 @@ nsSVGAngle::NewValueSpecifiedUnits(uint1
     aSVGElement->DidChangeAngle(mAttrEnum, emptyOrOldValue);
   }
   return NS_OK;
 }
 
 nsresult
 nsSVGAngle::ToDOMBaseVal(nsIDOMSVGAngle **aResult, nsSVGElement *aSVGElement)
 {
-  *aResult = new DOMBaseVal(this, aSVGElement);
-  if (!*aResult)
-    return NS_ERROR_OUT_OF_MEMORY;
+  nsRefPtr<DOMBaseVal> domBaseVal =
+    sBaseSVGAngleTearoffTable.GetTearoff(this);
+  if (!domBaseVal) {
+    domBaseVal = new DOMBaseVal(this, aSVGElement);
+    sBaseSVGAngleTearoffTable.AddTearoff(this, domBaseVal);
+  }
 
-  NS_ADDREF(*aResult);
+  domBaseVal.forget(aResult);
   return NS_OK;
 }
 
+nsSVGAngle::DOMBaseVal::~DOMBaseVal()
+{
+  sBaseSVGAngleTearoffTable.RemoveTearoff(mVal);
+}
+
 nsresult
 nsSVGAngle::ToDOMAnimVal(nsIDOMSVGAngle **aResult, nsSVGElement *aSVGElement)
 {
-  *aResult = new DOMAnimVal(this, aSVGElement);
-  if (!*aResult)
-    return NS_ERROR_OUT_OF_MEMORY;
+  nsRefPtr<DOMAnimVal> domAnimVal =
+    sAnimSVGAngleTearoffTable.GetTearoff(this);
+  if (!domAnimVal) {
+    domAnimVal = new DOMAnimVal(this, aSVGElement);
+    sAnimSVGAngleTearoffTable.AddTearoff(this, domAnimVal);
+  }
 
-  NS_ADDREF(*aResult);
+  domAnimVal.forget(aResult);
   return NS_OK;
 }
 
+nsSVGAngle::DOMAnimVal::~DOMAnimVal()
+{
+  sAnimSVGAngleTearoffTable.RemoveTearoff(mVal);
+}
+
 /* Implementation */
 
 nsresult
 nsSVGAngle::SetBaseValueString(const nsAString &aValueAsString,
                                nsSVGElement *aSVGElement,
                                bool aDoSetAttr)
 {
   float value = 0;
@@ -413,24 +437,32 @@ nsSVGAngle::SetAnimValue(float aValue, u
   mIsAnimated = true;
   aSVGElement->DidAnimateAngle(mAttrEnum);
 }
 
 nsresult
 nsSVGAngle::ToDOMAnimatedAngle(nsIDOMSVGAnimatedAngle **aResult,
                                nsSVGElement *aSVGElement)
 {
-  *aResult = new DOMAnimatedAngle(this, aSVGElement);
-  if (!*aResult)
-    return NS_ERROR_OUT_OF_MEMORY;
+  nsRefPtr<DOMAnimatedAngle> domAnimatedAngle =
+    sSVGAnimatedAngleTearoffTable.GetTearoff(this);
+  if (!domAnimatedAngle) {
+    domAnimatedAngle = new DOMAnimatedAngle(this, aSVGElement);
+    sSVGAnimatedAngleTearoffTable.AddTearoff(this, domAnimatedAngle);
+  }
 
-  NS_ADDREF(*aResult);
+  domAnimatedAngle.forget(aResult);
   return NS_OK;
 }
 
+nsSVGAngle::DOMAnimatedAngle::~DOMAnimatedAngle()
+{
+  sSVGAnimatedAngleTearoffTable.RemoveTearoff(mVal);
+}
+
 nsresult
 NS_NewDOMSVGAngle(nsIDOMSVGAngle** aResult)
 {
   *aResult = new DOMSVGAngle;
   if (!*aResult)
     return NS_ERROR_OUT_OF_MEMORY;
 
   NS_ADDREF(*aResult);
--- a/content/svg/content/src/nsSVGAngle.h
+++ b/content/svg/content/src/nsSVGAngle.h
@@ -79,16 +79,17 @@ private:
 public:
   struct DOMBaseVal MOZ_FINAL : public nsIDOMSVGAngle
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMBaseVal)
 
     DOMBaseVal(nsSVGAngle* aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
+    virtual ~DOMBaseVal();
     
     nsSVGAngle* mVal; // kept alive because it belongs to mSVGElement
     nsRefPtr<nsSVGElement> mSVGElement;
     
     NS_IMETHOD GetUnitType(uint16_t* aResult)
       { *aResult = mVal->mBaseValUnit; return NS_OK; }
 
     NS_IMETHOD GetValue(float* aResult)
@@ -118,16 +119,17 @@ public:
 
   struct DOMAnimVal MOZ_FINAL : public nsIDOMSVGAngle
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimVal)
 
     DOMAnimVal(nsSVGAngle* aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
+    virtual ~DOMAnimVal();
     
     nsSVGAngle* mVal; // kept alive because it belongs to mSVGElement
     nsRefPtr<nsSVGElement> mSVGElement;
     
     NS_IMETHOD GetUnitType(uint16_t* aResult)
       { *aResult = mVal->mAnimValUnit; return NS_OK; }
 
     NS_IMETHOD GetValue(float* aResult)
@@ -155,16 +157,17 @@ public:
 
   struct DOMAnimatedAngle MOZ_FINAL : public nsIDOMSVGAnimatedAngle
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimatedAngle)
 
     DOMAnimatedAngle(nsSVGAngle* aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
+    virtual ~DOMAnimatedAngle();
     
     nsSVGAngle* mVal; // kept alive because it belongs to content
     nsRefPtr<nsSVGElement> mSVGElement;
 
     NS_IMETHOD GetBaseVal(nsIDOMSVGAngle **aBaseVal)
       { return mVal->ToDOMBaseVal(aBaseVal, mSVGElement); }
 
     NS_IMETHOD GetAnimVal(nsIDOMSVGAngle **aAnimVal)
--- a/content/svg/content/src/nsSVGBoolean.cpp
+++ b/content/svg/content/src/nsSVGBoolean.cpp
@@ -1,14 +1,15 @@
 /* -*- 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 "nsError.h"
+#include "nsSVGAttrTearoffTable.h"
 #include "nsSVGBoolean.h"
 #include "nsSMILValue.h"
 #include "SMILBoolType.h"
 
 using namespace mozilla;
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGBoolean::DOMAnimatedBoolean, mSVGElement)
 
@@ -20,16 +21,19 @@ DOMCI_DATA(SVGAnimatedBoolean, nsSVGBool
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGBoolean::DOMAnimatedBoolean)
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedBoolean)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGAnimatedBoolean)
 NS_INTERFACE_MAP_END
 
 /* Implementation */
 
+static nsSVGAttrTearoffTable<nsSVGBoolean, nsSVGBoolean::DOMAnimatedBoolean>
+  sSVGAnimatedBooleanTearoffTable;
+
 static nsresult
 GetValueFromString(const nsAString &aValueAsString,
                    bool *aValue)
 {
   if (aValueAsString.EqualsLiteral("true")) {
     *aValue = true;
     return NS_OK;
   }
@@ -112,24 +116,32 @@ nsSVGBoolean::SetAnimValue(bool aValue, 
   mIsAnimated = true;
   aSVGElement->DidAnimateBoolean(mAttrEnum);
 }
 
 nsresult
 nsSVGBoolean::ToDOMAnimatedBoolean(nsIDOMSVGAnimatedBoolean **aResult,
                                    nsSVGElement *aSVGElement)
 {
-  *aResult = new DOMAnimatedBoolean(this, aSVGElement);
-  if (!*aResult)
-    return NS_ERROR_OUT_OF_MEMORY;
+  nsRefPtr<DOMAnimatedBoolean> domAnimatedBoolean =
+    sSVGAnimatedBooleanTearoffTable.GetTearoff(this);
+  if (!domAnimatedBoolean) {
+    domAnimatedBoolean = new DOMAnimatedBoolean(this, aSVGElement);
+    sSVGAnimatedBooleanTearoffTable.AddTearoff(this, domAnimatedBoolean);
+  }
 
-  NS_ADDREF(*aResult);
+  domAnimatedBoolean.forget(aResult);
   return NS_OK;
 }
 
+nsSVGBoolean::DOMAnimatedBoolean::~DOMAnimatedBoolean()
+{
+  sSVGAnimatedBooleanTearoffTable.RemoveTearoff(mVal);
+}
+
 nsISMILAttr*
 nsSVGBoolean::ToSMILAttr(nsSVGElement *aSVGElement)
 {
   return new SMILBool(this, aSVGElement);
 }
 
 nsresult
 nsSVGBoolean::SMILBool::ValueFromString(const nsAString& aStr,
--- a/content/svg/content/src/nsSVGBoolean.h
+++ b/content/svg/content/src/nsSVGBoolean.h
@@ -54,16 +54,17 @@ private:
 public:
   struct DOMAnimatedBoolean MOZ_FINAL : public nsIDOMSVGAnimatedBoolean
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimatedBoolean)
 
     DOMAnimatedBoolean(nsSVGBoolean* aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
+    virtual ~DOMAnimatedBoolean();
 
     nsSVGBoolean* mVal; // kept alive because it belongs to content
     nsRefPtr<nsSVGElement> mSVGElement;
 
     NS_IMETHOD GetBaseVal(bool* aResult)
       { *aResult = mVal->GetBaseValue(); return NS_OK; }
     NS_IMETHOD SetBaseVal(bool aValue)
       { mVal->SetBaseValue(aValue, mSVGElement); return NS_OK; }
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -1006,16 +1006,23 @@ nsSVGElement::sFEFloodMap[] = {
 
 // PresentationAttributes-LightingEffects
 /* static */ const Element::MappedAttributeEntry
 nsSVGElement::sLightingEffectsMap[] = {
   { &nsGkAtoms::lighting_color },
   { nullptr }
 };
 
+// PresentationAttributes-mask
+/* static */ const Element::MappedAttributeEntry
+nsSVGElement::sMaskMap[] = {
+  { &nsGkAtoms::mask_type },
+  { nullptr }
+};
+
 //----------------------------------------------------------------------
 // nsIDOMNode methods
 
 NS_IMETHODIMP
 nsSVGElement::IsSupported(const nsAString& aFeature, const nsAString& aVersion, bool* aReturn)
 {
   *aReturn = Element::IsSupported(aFeature, aVersion);
   return NS_OK;
--- a/content/svg/content/src/nsSVGElement.h
+++ b/content/svg/content/src/nsSVGElement.h
@@ -98,16 +98,17 @@ public:
   static const MappedAttributeEntry sFontSpecificationMap[];
   static const MappedAttributeEntry sGradientStopMap[];
   static const MappedAttributeEntry sViewportsMap[];
   static const MappedAttributeEntry sMarkersMap[];
   static const MappedAttributeEntry sColorMap[];
   static const MappedAttributeEntry sFiltersMap[];
   static const MappedAttributeEntry sFEFloodMap[];
   static const MappedAttributeEntry sLightingEffectsMap[];
+  static const MappedAttributeEntry sMaskMap[];
 
   // nsIDOMNode
   NS_IMETHOD IsSupported(const nsAString& aFeature, const nsAString& aVersion,
                          bool* aReturn);
   
   // nsIDOMSVGElement
   NS_IMETHOD GetId(nsAString & aId);
   NS_IMETHOD SetId(const nsAString & aId);
--- a/content/svg/content/src/nsSVGEnum.cpp
+++ b/content/svg/content/src/nsSVGEnum.cpp
@@ -1,14 +1,15 @@
 /* -*- 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 "nsError.h"
+#include "nsSVGAttrTearoffTable.h"
 #include "nsSVGEnum.h"
 #include "nsIAtom.h"
 #include "nsSVGElement.h"
 #include "nsSMILValue.h"
 #include "SMILEnumType.h"
 
 using namespace mozilla;
 
@@ -20,16 +21,19 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGEn
 DOMCI_DATA(SVGAnimatedEnumeration, nsSVGEnum::DOMAnimatedEnum)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGEnum::DOMAnimatedEnum)
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedEnumeration)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGAnimatedEnumeration)
 NS_INTERFACE_MAP_END
 
+static nsSVGAttrTearoffTable<nsSVGEnum, nsSVGEnum::DOMAnimatedEnum>
+  sSVGAnimatedEnumTearoffTable;
+
 nsSVGEnumMapping *
 nsSVGEnum::GetMapping(nsSVGElement *aSVGElement)
 {
   nsSVGElement::EnumAttributesInfo info = aSVGElement->GetEnumInfo();
 
   NS_ASSERTION(info.mEnumCount > 0 && mAttrEnum < info.mEnumCount,
                "mapping request for a non-attrib enum");
 
@@ -117,24 +121,32 @@ nsSVGEnum::SetAnimValue(uint16_t aValue,
   mIsAnimated = true;
   aSVGElement->DidAnimateEnum(mAttrEnum);
 }
 
 nsresult
 nsSVGEnum::ToDOMAnimatedEnum(nsIDOMSVGAnimatedEnumeration **aResult,
                              nsSVGElement *aSVGElement)
 {
-  *aResult = new DOMAnimatedEnum(this, aSVGElement);
-  if (!*aResult)
-    return NS_ERROR_OUT_OF_MEMORY;
+  nsRefPtr<DOMAnimatedEnum> domAnimatedEnum =
+    sSVGAnimatedEnumTearoffTable.GetTearoff(this);
+  if (!domAnimatedEnum) {
+    domAnimatedEnum = new DOMAnimatedEnum(this, aSVGElement);
+    sSVGAnimatedEnumTearoffTable.AddTearoff(this, domAnimatedEnum);
+  }
 
-  NS_ADDREF(*aResult);
+  domAnimatedEnum.forget(aResult);
   return NS_OK;
 }
 
+nsSVGEnum::DOMAnimatedEnum::~DOMAnimatedEnum()
+{
+  sSVGAnimatedEnumTearoffTable.RemoveTearoff(mVal);
+}
+
 nsISMILAttr*
 nsSVGEnum::ToSMILAttr(nsSVGElement *aSVGElement)
 {
   return new SMILEnum(this, aSVGElement);
 }
 
 nsresult
 nsSVGEnum::SMILEnum::ValueFromString(const nsAString& aStr,
--- a/content/svg/content/src/nsSVGEnum.h
+++ b/content/svg/content/src/nsSVGEnum.h
@@ -65,16 +65,17 @@ private:
 public:
   struct DOMAnimatedEnum MOZ_FINAL : public nsIDOMSVGAnimatedEnumeration
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimatedEnum)
 
     DOMAnimatedEnum(nsSVGEnum* aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
+    virtual ~DOMAnimatedEnum();
 
     nsSVGEnum *mVal; // kept alive because it belongs to content
     nsRefPtr<nsSVGElement> mSVGElement;
 
     NS_IMETHOD GetBaseVal(uint16_t* aResult)
       { *aResult = mVal->GetBaseValue(); return NS_OK; }
     NS_IMETHOD SetBaseVal(uint16_t aValue)
       { return mVal->SetBaseValue(aValue, mSVGElement); }
--- a/content/svg/content/src/nsSVGInteger.cpp
+++ b/content/svg/content/src/nsSVGInteger.cpp
@@ -1,14 +1,15 @@
 /* -*- 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 "nsError.h"
+#include "nsSVGAttrTearoffTable.h"
 #include "nsSVGInteger.h"
 #include "nsSMILValue.h"
 #include "SMILIntegerType.h"
 
 using namespace mozilla;
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGInteger::DOMAnimatedInteger, mSVGElement)
 
@@ -20,16 +21,19 @@ DOMCI_DATA(SVGAnimatedInteger, nsSVGInte
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGInteger::DOMAnimatedInteger)
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedInteger)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGAnimatedInteger)
 NS_INTERFACE_MAP_END
 
 /* Implementation */
 
+static nsSVGAttrTearoffTable<nsSVGInteger, nsSVGInteger::DOMAnimatedInteger>
+  sSVGAnimatedIntegerTearoffTable;
+
 static nsresult
 GetValueFromString(const nsAString &aValueAsString,
                    int32_t *aValue)
 {
   NS_ConvertUTF16toUTF8 value(aValueAsString);
   const char *str = value.get();
 
   if (NS_IsAsciiWhitespace(*str))
@@ -107,24 +111,32 @@ nsSVGInteger::SetAnimValue(int aValue, n
   mIsAnimated = true;
   aSVGElement->DidAnimateInteger(mAttrEnum);
 }
 
 nsresult
 nsSVGInteger::ToDOMAnimatedInteger(nsIDOMSVGAnimatedInteger **aResult,
                                    nsSVGElement *aSVGElement)
 {
-  *aResult = new DOMAnimatedInteger(this, aSVGElement);
-  if (!*aResult)
-    return NS_ERROR_OUT_OF_MEMORY;
+  nsRefPtr<DOMAnimatedInteger> domAnimatedInteger =
+    sSVGAnimatedIntegerTearoffTable.GetTearoff(this);
+  if (!domAnimatedInteger) {
+    domAnimatedInteger = new DOMAnimatedInteger(this, aSVGElement);
+    sSVGAnimatedIntegerTearoffTable.AddTearoff(this, domAnimatedInteger);
+  }
 
-  NS_ADDREF(*aResult);
+  domAnimatedInteger.forget(aResult);
   return NS_OK;
 }
 
+nsSVGInteger::DOMAnimatedInteger::~DOMAnimatedInteger()
+{
+  sSVGAnimatedIntegerTearoffTable.RemoveTearoff(mVal);
+}
+
 nsISMILAttr*
 nsSVGInteger::ToSMILAttr(nsSVGElement *aSVGElement)
 {
   return new SMILInteger(this, aSVGElement);
 }
 
 nsresult
 nsSVGInteger::SMILInteger::ValueFromString(const nsAString& aStr,
--- a/content/svg/content/src/nsSVGInteger.h
+++ b/content/svg/content/src/nsSVGInteger.h
@@ -64,16 +64,17 @@ private:
 public:
   struct DOMAnimatedInteger MOZ_FINAL : public nsIDOMSVGAnimatedInteger
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimatedInteger)
 
     DOMAnimatedInteger(nsSVGInteger* aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
+    virtual ~DOMAnimatedInteger();
 
     nsSVGInteger* mVal; // kept alive because it belongs to content
     nsRefPtr<nsSVGElement> mSVGElement;
 
     NS_IMETHOD GetBaseVal(int32_t* aResult)
       { *aResult = mVal->GetBaseValue(); return NS_OK; }
     NS_IMETHOD SetBaseVal(int32_t aValue)
       { mVal->SetBaseValue(aValue, mSVGElement); return NS_OK; }
--- a/content/svg/content/src/nsSVGIntegerPair.cpp
+++ b/content/svg/content/src/nsSVGIntegerPair.cpp
@@ -1,14 +1,15 @@
 /* -*- 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 "nsSVGIntegerPair.h"
+#include "nsSVGAttrTearoffTable.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsError.h"
 #include "nsMathUtils.h"
 #include "nsSMILValue.h"
 #include "SVGContentUtils.h"
 #include "SVGIntegerPairSMILType.h"
 
 using namespace mozilla;
@@ -21,16 +22,21 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGIn
 DOMCI_DATA(SVGAnimatedIntegerPair, nsSVGIntegerPair::DOMAnimatedInteger)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGIntegerPair::DOMAnimatedInteger)
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedInteger)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGAnimatedInteger)
 NS_INTERFACE_MAP_END
 
+static nsSVGAttrTearoffTable<nsSVGIntegerPair, nsSVGIntegerPair::DOMAnimatedInteger>
+  sSVGFirstAnimatedIntegerTearoffTable;
+static nsSVGAttrTearoffTable<nsSVGIntegerPair, nsSVGIntegerPair::DOMAnimatedInteger>
+  sSVGSecondAnimatedIntegerTearoffTable;
+
 /* Implementation */
 
 static nsresult
 ParseIntegerOptionalInteger(const nsAString& aValue,
                             int32_t aValues[2])
 {
   nsCharSeparatedTokenizerTemplate<IsSVGWhitespace>
     tokenizer(aValue, ',',
@@ -162,21 +168,41 @@ nsSVGIntegerPair::SetAnimValue(const int
   aSVGElement->DidAnimateIntegerPair(mAttrEnum);
 }
 
 nsresult
 nsSVGIntegerPair::ToDOMAnimatedInteger(nsIDOMSVGAnimatedInteger **aResult,
                                        PairIndex aIndex,
                                        nsSVGElement *aSVGElement)
 {
-  *aResult = new DOMAnimatedInteger(this, aIndex, aSVGElement);
-  NS_ADDREF(*aResult);
+  nsRefPtr<DOMAnimatedInteger> domAnimatedInteger =
+    aIndex == eFirst ? sSVGFirstAnimatedIntegerTearoffTable.GetTearoff(this) :
+                       sSVGSecondAnimatedIntegerTearoffTable.GetTearoff(this);
+  if (!domAnimatedInteger) {
+    domAnimatedInteger = new DOMAnimatedInteger(this, aIndex, aSVGElement);
+    if (aIndex == eFirst) {
+      sSVGFirstAnimatedIntegerTearoffTable.AddTearoff(this, domAnimatedInteger);
+    } else {
+      sSVGSecondAnimatedIntegerTearoffTable.AddTearoff(this, domAnimatedInteger);
+    }
+  }
+
+  domAnimatedInteger.forget(aResult);
   return NS_OK;
 }
 
+nsSVGIntegerPair::DOMAnimatedInteger::~DOMAnimatedInteger()
+{
+  if (mIndex == eFirst) {
+    sSVGFirstAnimatedIntegerTearoffTable.RemoveTearoff(mVal);
+  } else {
+    sSVGSecondAnimatedIntegerTearoffTable.RemoveTearoff(mVal);
+  }
+}
+
 nsISMILAttr*
 nsSVGIntegerPair::ToSMILAttr(nsSVGElement *aSVGElement)
 {
   return new SMILIntegerPair(this, aSVGElement);
 }
 
 nsresult
 nsSVGIntegerPair::SMILIntegerPair::ValueFromString(const nsAString& aStr,
--- a/content/svg/content/src/nsSVGIntegerPair.h
+++ b/content/svg/content/src/nsSVGIntegerPair.h
@@ -71,16 +71,17 @@ private:
 public:
   struct DOMAnimatedInteger MOZ_FINAL : public nsIDOMSVGAnimatedInteger
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimatedInteger)
 
     DOMAnimatedInteger(nsSVGIntegerPair* aVal, PairIndex aIndex, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement), mIndex(aIndex) {}
+    virtual ~DOMAnimatedInteger();
 
     nsSVGIntegerPair* mVal; // kept alive because it belongs to content
     nsRefPtr<nsSVGElement> mSVGElement;
     PairIndex mIndex; // are we the first or second integer
 
     NS_IMETHOD GetBaseVal(int32_t* aResult)
       { *aResult = mVal->GetBaseValue(mIndex); return NS_OK; }
     NS_IMETHOD SetBaseVal(int32_t aValue)
--- a/content/svg/content/src/nsSVGMaskElement.cpp
+++ b/content/svg/content/src/nsSVGMaskElement.cpp
@@ -136,15 +136,16 @@ nsSVGMaskElement::IsAttributeMapped(cons
 {
   static const MappedAttributeEntry* const map[] = {
     sFEFloodMap,
     sFiltersMap,
     sFontSpecificationMap,
     sGradientStopMap,
     sGraphicsMap,
     sMarkersMap,
+    sMaskMap,
     sTextContentElementsMap,
     sViewportsMap
   };
 
   return FindAttributeDependence(name, map) ||
     nsSVGMaskElementBase::IsAttributeMapped(name);
 }
--- a/content/svg/content/src/nsSVGNumber2.cpp
+++ b/content/svg/content/src/nsSVGNumber2.cpp
@@ -1,14 +1,15 @@
 /* -*- 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 "nsError.h"
+#include "nsSVGAttrTearoffTable.h"
 #include "nsSVGNumber2.h"
 #include "nsTextFormatter.h"
 #include "prdtoa.h"
 #include "nsMathUtils.h"
 #include "nsContentUtils.h" // NS_ENSURE_FINITE
 #include "nsSMILValue.h"
 #include "nsSMILFloatType.h"
 #include "nsIDOMSVGNumber.h"
@@ -52,16 +53,19 @@ NS_INTERFACE_MAP_END
 NS_INTERFACE_MAP_BEGIN(DOMSVGNumber)
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGNumber)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGNumber)
 NS_INTERFACE_MAP_END
 
 /* Implementation */
 
+static nsSVGAttrTearoffTable<nsSVGNumber2, nsSVGNumber2::DOMAnimatedNumber>
+  sSVGAnimatedNumberTearoffTable;
+
 static nsresult
 GetValueFromString(const nsAString &aValueAsString,
                    bool aPercentagesAllowed,
                    float *aValue)
 {
   NS_ConvertUTF16toUTF8 value(aValueAsString);
   const char *str = value.get();
 
@@ -146,24 +150,32 @@ nsSVGNumber2::SetAnimValue(float aValue,
   mIsAnimated = true;
   aSVGElement->DidAnimateNumber(mAttrEnum);
 }
 
 nsresult
 nsSVGNumber2::ToDOMAnimatedNumber(nsIDOMSVGAnimatedNumber **aResult,
                                   nsSVGElement *aSVGElement)
 {
-  *aResult = new DOMAnimatedNumber(this, aSVGElement);
-  if (!*aResult)
-    return NS_ERROR_OUT_OF_MEMORY;
+  nsRefPtr<DOMAnimatedNumber> domAnimatedNumber =
+    sSVGAnimatedNumberTearoffTable.GetTearoff(this);
+  if (!domAnimatedNumber) {
+    domAnimatedNumber = new DOMAnimatedNumber(this, aSVGElement);
+    sSVGAnimatedNumberTearoffTable.AddTearoff(this, domAnimatedNumber);
+  }
 
-  NS_ADDREF(*aResult);
+  domAnimatedNumber.forget(aResult);
   return NS_OK;
 }
 
+nsSVGNumber2::DOMAnimatedNumber::~DOMAnimatedNumber()
+{
+  sSVGAnimatedNumberTearoffTable.RemoveTearoff(mVal);
+}
+
 nsISMILAttr*
 nsSVGNumber2::ToSMILAttr(nsSVGElement *aSVGElement)
 {
   return new SMILNumber(this, aSVGElement);
 }
 
 nsresult
 nsSVGNumber2::SMILNumber::ValueFromString(const nsAString& aStr,
--- a/content/svg/content/src/nsSVGNumber2.h
+++ b/content/svg/content/src/nsSVGNumber2.h
@@ -64,16 +64,17 @@ private:
 public:
   struct DOMAnimatedNumber MOZ_FINAL : public nsIDOMSVGAnimatedNumber
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimatedNumber)
 
     DOMAnimatedNumber(nsSVGNumber2* aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
+    virtual ~DOMAnimatedNumber();
 
     nsSVGNumber2* mVal; // kept alive because it belongs to content
     nsRefPtr<nsSVGElement> mSVGElement;
 
     NS_IMETHOD GetBaseVal(float* aResult)
       { *aResult = mVal->GetBaseValue(); return NS_OK; }
     NS_IMETHOD SetBaseVal(float aValue)
       {
--- a/content/svg/content/src/nsSVGNumberPair.cpp
+++ b/content/svg/content/src/nsSVGNumberPair.cpp
@@ -1,14 +1,15 @@
 /* -*- 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 "nsSVGNumberPair.h"
+#include "nsSVGAttrTearoffTable.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "prdtoa.h"
 #include "nsError.h"
 #include "nsMathUtils.h"
 #include "nsSMILValue.h"
 #include "SVGContentUtils.h"
 #include "SVGNumberPairSMILType.h"
 
@@ -24,16 +25,21 @@ DOMCI_DATA(SVGAnimatedNumberPair, nsSVGN
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGNumberPair::DOMAnimatedNumber)
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedNumber)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGAnimatedNumber)
 NS_INTERFACE_MAP_END
 
 /* Implementation */
 
+static nsSVGAttrTearoffTable<nsSVGNumberPair, nsSVGNumberPair::DOMAnimatedNumber>
+  sSVGFirstAnimatedNumberTearoffTable;
+static nsSVGAttrTearoffTable<nsSVGNumberPair, nsSVGNumberPair::DOMAnimatedNumber>
+  sSVGSecondAnimatedNumberTearoffTable;
+
 static nsresult
 ParseNumberOptionalNumber(const nsAString& aValue,
                           float aValues[2])
 {
   nsCharSeparatedTokenizerTemplate<IsSVGWhitespace>
     tokenizer(aValue, ',',
               nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
   if (tokenizer.firstTokenBeganWithWhitespace()) {
@@ -160,21 +166,41 @@ nsSVGNumberPair::SetAnimValue(const floa
   aSVGElement->DidAnimateNumberPair(mAttrEnum);
 }
 
 nsresult
 nsSVGNumberPair::ToDOMAnimatedNumber(nsIDOMSVGAnimatedNumber **aResult,
                                      PairIndex aIndex,
                                      nsSVGElement *aSVGElement)
 {
-  *aResult = new DOMAnimatedNumber(this, aIndex, aSVGElement);
-  NS_ADDREF(*aResult);
+  nsRefPtr<DOMAnimatedNumber> domAnimatedNumber =
+    aIndex == eFirst ? sSVGFirstAnimatedNumberTearoffTable.GetTearoff(this) :
+                       sSVGSecondAnimatedNumberTearoffTable.GetTearoff(this);
+  if (!domAnimatedNumber) {
+    domAnimatedNumber = new DOMAnimatedNumber(this, aIndex, aSVGElement);
+    if (aIndex == eFirst) {
+      sSVGFirstAnimatedNumberTearoffTable.AddTearoff(this, domAnimatedNumber);
+    } else {
+      sSVGSecondAnimatedNumberTearoffTable.AddTearoff(this, domAnimatedNumber);
+    }
+  }
+
+  domAnimatedNumber.forget(aResult);
   return NS_OK;
 }
 
+nsSVGNumberPair::DOMAnimatedNumber::~DOMAnimatedNumber()
+{
+  if (mIndex == eFirst) {
+    sSVGFirstAnimatedNumberTearoffTable.RemoveTearoff(mVal);
+  } else {
+    sSVGSecondAnimatedNumberTearoffTable.RemoveTearoff(mVal);
+  }
+}
+
 nsISMILAttr*
 nsSVGNumberPair::ToSMILAttr(nsSVGElement *aSVGElement)
 {
   return new SMILNumberPair(this, aSVGElement);
 }
 
 nsresult
 nsSVGNumberPair::SMILNumberPair::ValueFromString(const nsAString& aStr,
--- a/content/svg/content/src/nsSVGNumberPair.h
+++ b/content/svg/content/src/nsSVGNumberPair.h
@@ -72,16 +72,17 @@ private:
 public:
   struct DOMAnimatedNumber MOZ_FINAL : public nsIDOMSVGAnimatedNumber
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimatedNumber)
 
     DOMAnimatedNumber(nsSVGNumberPair* aVal, PairIndex aIndex, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement), mIndex(aIndex) {}
+    virtual ~DOMAnimatedNumber();
 
     nsSVGNumberPair* mVal; // kept alive because it belongs to content
     nsRefPtr<nsSVGElement> mSVGElement;
     PairIndex mIndex; // are we the first or second number
 
     NS_IMETHOD GetBaseVal(float* aResult)
       { *aResult = mVal->GetBaseValue(mIndex); return NS_OK; }
     NS_IMETHOD SetBaseVal(float aValue)
--- a/content/svg/content/src/nsSVGString.cpp
+++ b/content/svg/content/src/nsSVGString.cpp
@@ -1,14 +1,15 @@
 /* -*- 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 "nsSVGString.h"
+#include "nsSVGAttrTearoffTable.h"
 #include "nsSMILValue.h"
 #include "SMILStringType.h"
 
 using namespace mozilla;
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGString::DOMAnimatedString, mSVGElement)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGString::DOMAnimatedString)
@@ -17,16 +18,19 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGSt
 DOMCI_DATA(SVGAnimatedString, nsSVGString::DOMAnimatedString)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGString::DOMAnimatedString)
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedString)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGAnimatedString)
 NS_INTERFACE_MAP_END
 
+static nsSVGAttrTearoffTable<nsSVGString, nsSVGString::DOMAnimatedString>
+  sSVGAnimatedStringTearoffTable;
+
 /* Implementation */
 
 void
 nsSVGString::SetBaseValue(const nsAString& aValue,
                           nsSVGElement *aSVGElement,
                           bool aDoSetAttr)
 {
   NS_ASSERTION(aSVGElement, "Null element passed to SetBaseValue");
@@ -67,24 +71,32 @@ nsSVGString::SetAnimValue(const nsAStrin
     aSVGElement->DidAnimateString(mAttrEnum);
   }
 }
 
 nsresult
 nsSVGString::ToDOMAnimatedString(nsIDOMSVGAnimatedString **aResult,
                                  nsSVGElement *aSVGElement)
 {
-  *aResult = new DOMAnimatedString(this, aSVGElement);
-  if (!*aResult)
-    return NS_ERROR_OUT_OF_MEMORY;
+  nsRefPtr<DOMAnimatedString> domAnimatedString =
+    sSVGAnimatedStringTearoffTable.GetTearoff(this);
+  if (!domAnimatedString) {
+    domAnimatedString = new DOMAnimatedString(this, aSVGElement);
+    sSVGAnimatedStringTearoffTable.AddTearoff(this, domAnimatedString);
+  }
 
-  NS_ADDREF(*aResult);
+  domAnimatedString.forget(aResult);
   return NS_OK;
 }
 
+nsSVGString::DOMAnimatedString::~DOMAnimatedString()
+{
+  sSVGAnimatedStringTearoffTable.RemoveTearoff(mVal);
+}
+
 nsISMILAttr*
 nsSVGString::ToSMILAttr(nsSVGElement *aSVGElement)
 {
   return new SMILString(this, aSVGElement);
 }
 
 nsresult
 nsSVGString::SMILString::ValueFromString(const nsAString& aStr,
--- a/content/svg/content/src/nsSVGString.h
+++ b/content/svg/content/src/nsSVGString.h
@@ -52,16 +52,17 @@ private:
 public:
   struct DOMAnimatedString MOZ_FINAL : public nsIDOMSVGAnimatedString
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimatedString)
 
     DOMAnimatedString(nsSVGString *aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
+    virtual ~DOMAnimatedString();
 
     nsSVGString* mVal; // kept alive because it belongs to content
     nsRefPtr<nsSVGElement> mSVGElement;
 
     NS_IMETHOD GetBaseVal(nsAString & aResult)
       { mVal->GetBaseValue(aResult, mSVGElement); return NS_OK; }
     NS_IMETHOD SetBaseVal(const nsAString & aValue)
       { mVal->SetBaseValue(aValue, mSVGElement, true); return NS_OK; }
--- a/content/svg/content/src/nsSVGViewBox.cpp
+++ b/content/svg/content/src/nsSVGViewBox.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsSVGViewBox.h"
 #include "prdtoa.h"
 #include "nsTextFormatter.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsMathUtils.h"
 #include "nsSMILValue.h"
+#include "nsSVGAttrTearoffTable.h"
 #include "SVGContentUtils.h"
 #include "SVGViewBoxSMILType.h"
 #include "nsAttrValueInlines.h"
 
 #define NUM_VIEWBOX_COMPONENTS 4
 using namespace mozilla;
 
 /* Implementation of nsSVGViewBoxRect methods */
@@ -60,16 +61,24 @@ NS_INTERFACE_MAP_END
 DOMCI_DATA(SVGAnimatedRect, nsSVGViewBox::DOMAnimatedRect)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGViewBox::DOMAnimatedRect)
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedRect)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGAnimatedRect)
 NS_INTERFACE_MAP_END
 
+static nsSVGAttrTearoffTable<nsSVGViewBox, nsSVGViewBox::DOMAnimatedRect>
+  sSVGAnimatedRectTearoffTable;
+static nsSVGAttrTearoffTable<nsSVGViewBox, nsSVGViewBox::DOMBaseVal>
+  sBaseSVGViewBoxTearoffTable;
+static nsSVGAttrTearoffTable<nsSVGViewBox, nsSVGViewBox::DOMAnimVal>
+  sAnimSVGViewBoxTearoffTable;
+
+
 /* Implementation of nsSVGViewBox methods */
 
 void
 nsSVGViewBox::Init()
 {
   mBaseVal = nsSVGViewBoxRect();
   mAnimVal = nullptr;
   mHasBaseVal = false;
@@ -182,43 +191,70 @@ nsSVGViewBox::GetBaseValueString(nsAStri
                             (double)mBaseVal.width, (double)mBaseVal.height);
   aValue.Assign(buf);
 }
 
 nsresult
 nsSVGViewBox::ToDOMAnimatedRect(nsIDOMSVGAnimatedRect **aResult,
                                 nsSVGElement* aSVGElement)
 {
-  *aResult = new DOMAnimatedRect(this, aSVGElement);
-  NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
+  nsRefPtr<DOMAnimatedRect> domAnimatedRect =
+    sSVGAnimatedRectTearoffTable.GetTearoff(this);
+  if (!domAnimatedRect) {
+    domAnimatedRect = new DOMAnimatedRect(this, aSVGElement);
+    sSVGAnimatedRectTearoffTable.AddTearoff(this, domAnimatedRect);
+  }
 
-  NS_ADDREF(*aResult);
+  domAnimatedRect.forget(aResult);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsSVGViewBox::DOMAnimatedRect::GetBaseVal(nsIDOMSVGRect **aResult)
+nsSVGViewBox::DOMAnimatedRect::~DOMAnimatedRect()
+{
+  sSVGAnimatedRectTearoffTable.RemoveTearoff(mVal);
+}
+
+nsresult
+nsSVGViewBox::ToDOMBaseVal(nsIDOMSVGRect **aResult, nsSVGElement *aSVGElement)
 {
-  *aResult = new nsSVGViewBox::DOMBaseVal(mVal, mSVGElement);
-  NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
+  nsRefPtr<DOMBaseVal> domBaseVal =
+    sBaseSVGViewBoxTearoffTable.GetTearoff(this);
+  if (!domBaseVal) {
+    domBaseVal = new DOMBaseVal(this, aSVGElement);
+    sBaseSVGViewBoxTearoffTable.AddTearoff(this, domBaseVal);
+  }
 
-  NS_ADDREF(*aResult);
+  domBaseVal.forget(aResult);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsSVGViewBox::DOMAnimatedRect::GetAnimVal(nsIDOMSVGRect **aResult)
+nsSVGViewBox::DOMBaseVal::~DOMBaseVal()
+{
+  sBaseSVGViewBoxTearoffTable.RemoveTearoff(mVal);
+}
+
+nsresult
+nsSVGViewBox::ToDOMAnimVal(nsIDOMSVGRect **aResult, nsSVGElement *aSVGElement)
 {
-  *aResult = new nsSVGViewBox::DOMAnimVal(mVal, mSVGElement);
-  NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
+  nsRefPtr<DOMAnimVal> domAnimVal =
+    sAnimSVGViewBoxTearoffTable.GetTearoff(this);
+  if (!domAnimVal) {
+    domAnimVal = new DOMAnimVal(this, aSVGElement);
+    sAnimSVGViewBoxTearoffTable.AddTearoff(this, domAnimVal);
+  }
 
-  NS_ADDREF(*aResult);
+  domAnimVal.forget(aResult);
   return NS_OK;
 }
 
+nsSVGViewBox::DOMAnimVal::~DOMAnimVal()
+{
+  sAnimSVGViewBoxTearoffTable.RemoveTearoff(mVal);
+}
+
 NS_IMETHODIMP
 nsSVGViewBox::DOMBaseVal::SetX(float aX)
 {
   nsSVGViewBoxRect rect = mVal->GetBaseValue();
   rect.x = aX;
   mVal->SetBaseValue(rect.x, rect.y, rect.width, rect.height,
                      mSVGElement);
   return NS_OK;
--- a/content/svg/content/src/nsSVGViewBox.h
+++ b/content/svg/content/src/nsSVGViewBox.h
@@ -65,32 +65,36 @@ public:
 
   nsresult SetBaseValueString(const nsAString& aValue,
                               nsSVGElement *aSVGElement,
                               bool aDoSetAttr);
   void GetBaseValueString(nsAString& aValue) const;
 
   nsresult ToDOMAnimatedRect(nsIDOMSVGAnimatedRect **aResult,
                              nsSVGElement *aSVGElement);
+  nsresult ToDOMBaseVal(nsIDOMSVGRect **aResult, nsSVGElement* aSVGElement);
+  nsresult ToDOMAnimVal(nsIDOMSVGRect **aResult, nsSVGElement* aSVGElement);
   // Returns a new nsISMILAttr object that the caller must delete
   nsISMILAttr* ToSMILAttr(nsSVGElement* aSVGElement);
 
 private:
 
   nsSVGViewBoxRect mBaseVal;
   nsAutoPtr<nsSVGViewBoxRect> mAnimVal;
   bool mHasBaseVal;
 
+public:
   struct DOMBaseVal MOZ_FINAL : public nsIDOMSVGRect
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMBaseVal)
 
     DOMBaseVal(nsSVGViewBox *aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
+    virtual ~DOMBaseVal();
 
     nsSVGViewBox* mVal; // kept alive because it belongs to content
     nsRefPtr<nsSVGElement> mSVGElement;
 
     NS_IMETHOD GetX(float *aX)
       { *aX = mVal->GetBaseValue().x; return NS_OK; }
     NS_IMETHOD GetY(float *aY)
       { *aY = mVal->GetBaseValue().y; return NS_OK; }
@@ -107,16 +111,17 @@ private:
 
   struct DOMAnimVal MOZ_FINAL : public nsIDOMSVGRect
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimVal)
 
     DOMAnimVal(nsSVGViewBox *aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
+    virtual ~DOMAnimVal();
 
     nsSVGViewBox* mVal; // kept alive because it belongs to content
     nsRefPtr<nsSVGElement> mSVGElement;
 
     // Script may have modified animation parameters or timeline -- DOM getters
     // need to flush any resample requests to reflect these modifications.
     NS_IMETHOD GetX(float *aX)
     {
@@ -148,30 +153,33 @@ private:
     NS_IMETHOD SetY(float aY)
       { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
     NS_IMETHOD SetWidth(float aWidth)
       { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
     NS_IMETHOD SetHeight(float aHeight)
       { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
   };
 
-public:
   struct DOMAnimatedRect MOZ_FINAL : public nsIDOMSVGAnimatedRect
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimatedRect)
 
     DOMAnimatedRect(nsSVGViewBox *aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
+    virtual ~DOMAnimatedRect();
 
     nsSVGViewBox* mVal; // kept alive because it belongs to content
     nsRefPtr<nsSVGElement> mSVGElement;
 
-    NS_IMETHOD GetBaseVal(nsIDOMSVGRect **aResult);
-    NS_IMETHOD GetAnimVal(nsIDOMSVGRect **aResult);
+    NS_IMETHOD GetBaseVal(nsIDOMSVGRect **aBaseVal)
+      { return mVal->ToDOMBaseVal(aBaseVal, mSVGElement); }
+
+    NS_IMETHOD GetAnimVal(nsIDOMSVGRect **aAnimVal)
+      { return mVal->ToDOMAnimVal(aAnimVal, mSVGElement); }
   };
 
   struct SMILViewBox : public nsISMILAttr
   {
   public:
     SMILViewBox(nsSVGViewBox* aVal, nsSVGElement* aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
 
--- a/content/svg/content/test/test_SVGxxxList.xhtml
+++ b/content/svg/content/test/test_SVGxxxList.xhtml
@@ -450,17 +450,17 @@ function get_array_of_list_items(list)
  *
  * @param t A test from the 'tests' array.
  */
 function run_baseVal_API_tests()
 {
   var res, threw, items;
   var eventChecker = new MutationEventChecker;
 
-  for each (var t in tests) {
+  for (var t of tests) {
 
     // Test .clear():
 
     t.element.setAttribute(t.attr_name, t.attr_val_4);
 
     is(t.baseVal.numberOfItems, 4,
        'The '+t.list_type+' object should contain four list items.');
 
@@ -845,17 +845,17 @@ function run_baseVal_API_tests()
 /**
  * This function tests the SVGXxxList API for the anim val list (see also the
  * comment for test_baseVal_API).
  */
 function run_animVal_API_tests()
 {
   var threw, item;
 
-  for each (var t in tests) {
+  for (var t of tests) {
     if (!t.animVal)
       continue; // SVGStringList isn't animatable
 
     item = t.item_constructor();
 
     t.element.setAttribute(t.attr_name, t.attr_val_4);
 
     is(t.animVal.numberOfItems, 4,
@@ -944,17 +944,17 @@ function run_animVal_API_tests()
 
 
 /**
  * This function runs some basic tests to check the effect of setAttribute()
  * calls on object identity, without taking SMIL animation into consideration.
  */
 function run_basic_setAttribute_tests()
 {
-  for each (var t in tests) {
+  for (var t of tests) {
 
     // Since the t.prop, t.baseVal and t.animVal objects should never ever
     // change, we leave testing of them to our caller so that it can check
     // them after all the other mutations such as SMIL changes.
 
     t.element.setAttribute(t.attr_name, t.attr_val_4);
 
     ok(t.baseVal.numberOfItems == 4 && t.baseVal.getItem(3) != null,
@@ -1041,17 +1041,17 @@ function run_basic_setAttribute_tests()
 }
 
 /**
  * This function verifies that a list's animVal is kept in sync with its
  * baseVal, when we add & remove items from the baseVal.
  */
 function run_list_mutation_tests()
 {
-  for each (var t in tests) {
+  for (var t of tests) {
     if (t.animVal) {
       // Test removeItem()
       // =================
       // Save second item in baseVal list; then make it the first item, and
       // check that animVal is updated accordingly.
       t.element.setAttribute(t.attr_name, t.attr_val_4);
 
       var secondVal = t.baseVal.getItem(1);
@@ -1137,17 +1137,17 @@ function run_list_mutation_tests()
  *
  * See the comment for create_animate_elements() for details of the animations
  * and their timings.
  */
 function run_animation_timeline_tests()
 {
   var svg = document.getElementById('svg');
 
-  for each (var t in tests) {
+  for (var t of tests) {
     // Skip if there is no animVal for this test or if it is a transform list
     // since these are handled specially
     if (!t.animVal || is_transform_attr(t.attr_name))
       continue;
 
     svg.setCurrentTime(0); // reset timeline
 
     // Reset attributes before moving along the timeline and triggering SMIL:
@@ -1363,17 +1363,17 @@ function run_animation_timeline_tests()
    }
 }
 
 
 function run_tests()
 {
   // Initialize each test object with some useful properties, and create their
   // 'animate' elements. Note that 'prop' and 'animVal' may be null.
-  for each (var t in tests) {
+  for (var t of tests) {
     t.element = document.getElementById(t.target_element_id);
     t.prop = t.prop_name ? t.element[t.prop_name] : null;
     t.baseVal = ( t.prop || t.element )[t.bv_name];
     t.animVal = t.av_name ? ( t.prop || t.element )[t.av_name] : null;
     t.bv_path = t.el_type + '.' +
                 (t.prop ? t.prop_name + '.' : '') +
                 t.bv_name;  // e.g. 'SVGTextElement.x.baseVal'
     if (t.animVal) {
@@ -1404,17 +1404,17 @@ function run_tests()
   run_animVal_API_tests();
   run_basic_setAttribute_tests();
   run_list_mutation_tests();
   run_animation_timeline_tests();
 
   // After all the other test manipulations, we check that the following
   // objects have still not changed, since they never should:
 
-  for each (var t in tests) {
+  for (var t of tests) {
     if (t.prop) {
       ok(t.prop === t.element[t.prop_name],
          'The same '+t.prop_type+' object should ALWAYS be returned for '+
          t.el_type+'.'+t.prop_name+' each time it is accessed.');
     }
 
     ok(t.baseVal === ( t.prop || t.element )[t.bv_name],
        'The same '+t.list_type+' object should ALWAYS be returned for '+
--- a/content/svg/content/test/test_isSupported.xhtml
+++ b/content/svg/content/test/test_isSupported.xhtml
@@ -131,17 +131,17 @@ var features = [
   ["org.w3c.dom.svg", "1.0", false],
   ["org.w3c.dom.svg.all", "1.0", false],
   ["org.w3c.dom.svg.static", "1.0", false],
   ["org.w3c.dom.svg.animation", "1.0", true],
   ["org.w3c.dom.svg.dynamic", "1.0", false]
 ];
 
 function testIsSupported(elem) {
-  for each (var [feature, version, accepted_result] in features) {
+  for (var [feature, version, accepted_result] of features) {
     if (accepted_result) {
       ok(elem.isSupported(feature, version), "isSupported(" + feature + ", " + version + ") returned wrong value, Was it changed to unsupported feature?");
     } else {
       todo(elem.isSupported(feature, version), "isSupported(" + feature + ", " + version + ") is unsupported feature string");
     }
   }
 }
 
--- a/content/xbl/src/nsBindingManager.cpp
+++ b/content/xbl/src/nsBindingManager.cpp
@@ -1214,27 +1214,17 @@ nsBindingManager::GetBindingImplementati
         return NS_NOINTERFACE;
 
       JSContext* jscontext = context->GetNativeContext();
       if (!jscontext)
         return NS_NOINTERFACE;
 
       nsIXPConnect *xpConnect = nsContentUtils::XPConnect();
 
-      nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
-      xpConnect->GetWrappedNativeOfNativeObject(jscontext,
-                                                global->GetGlobalJSObject(),
-                                                aContent,
-                                                NS_GET_IID(nsISupports),
-                                                getter_AddRefs(wrapper));
-      NS_ENSURE_TRUE(wrapper, NS_NOINTERFACE);
-
-      JSObject* jsobj = nullptr;
-
-      wrapper->GetJSObject(&jsobj);
+      JSObject* jsobj = aContent->GetWrapper();
       NS_ENSURE_TRUE(jsobj, NS_NOINTERFACE);
 
       nsresult rv = xpConnect->WrapJSAggregatedToNative(aContent, jscontext,
                                                         jsobj, aIID, aResult);
       if (NS_FAILED(rv))
         return rv;
 
       // We successfully created a wrapper.  We will own this wrapper for as long as the binding remains
--- a/content/xbl/src/nsXBLBinding.cpp
+++ b/content/xbl/src/nsXBLBinding.cpp
@@ -54,19 +54,21 @@
 #include "prprf.h"
 #include "nsNodeUtils.h"
 
 // Nasty hack.  Maybe we could move some of the classinfo utility methods
 // (e.g. WrapNative) over to nsContentUtils?
 #include "nsDOMClassInfo.h"
 #include "nsJSUtils.h"
 
+#include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 // Helper classes
 
 /***********************************************************************/
 //
 // The JS class for XBLBinding
 //
 static void
@@ -107,16 +109,21 @@ static const uint32_t FIELD_SLOT = 1;
 
 bool
 ValueHasISupportsPrivate(const JS::Value &v)
 {
   if (!v.isObject()) {
     return false;
   }
 
+  const DOMClass* domClass = GetDOMClass(&v.toObject());
+  if (domClass) {
+    return domClass->mDOMObjectIsISupports;
+  }
+
   JSClass* clasp = ::JS_GetClass(&v.toObject());
   const uint32_t HAS_PRIVATE_NSISUPPORTS =
     JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS;
   return (clasp->flags & HAS_PRIVATE_NSISUPPORTS) == HAS_PRIVATE_NSISUPPORTS;
 }
 
 // Define a shadowing property on |this| for the XBL field defined by the
 // contents of the callee's reserved slots.  If the property was defined,
@@ -133,29 +140,29 @@ InstallXBLField(JSContext* cx,
   //
   // FieldAccessorGuard already determined whether |thisObj| was acceptable as
   // |this| in terms of not throwing a TypeError.  Assert this for good measure.
   MOZ_ASSERT(ValueHasISupportsPrivate(JS::ObjectValue(*thisObj)));
 
   // But there are some cases where we must accept |thisObj| but not install a
   // property on it, or otherwise touch it.  Hence this split of |this|-vetting
   // duties.
-  nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
-    do_QueryInterface(static_cast<nsISupports*>(::JS_GetPrivate(thisObj)));
-  if (!xpcWrapper) {
+  nsISupports* native =
+    nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, thisObj);
+  if (!native) {
     // Looks like whatever |thisObj| is it's not our nsIContent.  It might well
     // be the proto our binding installed, however, where the private is the
     // nsXBLDocumentInfo, so just baul out quietly.  Do NOT throw an exception
     // here.
     //
     // We could make this stricter by checking the class maybe, but whatever.
     return true;
   }
 
-  nsCOMPtr<nsIContent> xblNode = do_QueryWrappedNative(xpcWrapper);
+  nsCOMPtr<nsIContent> xblNode = do_QueryInterface(native);
   if (!xblNode) {
     xpc::Throw(cx, NS_ERROR_UNEXPECTED);
     return false;
   }
 
   // Now that |this| is okay, actually install the field.  Some of this
   // installation work could have been done in XBLResolve, but this splitting
   // of work seems simplest to implement and friendliest regarding lifetimes
@@ -1203,31 +1210,17 @@ nsXBLBinding::ChangeDocument(nsIDocument
 
           nsCOMPtr<nsIScriptContext> context = global->GetContext();
           if (context && scope) {
             JSContext *cx = context->GetNativeContext();
  
             nsCxPusher pusher;
             pusher.Push(cx);
 
-            nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
-            nsIXPConnect *xpc = nsContentUtils::XPConnect();
-            nsresult rv =
-              xpc->GetWrappedNativeOfNativeObject(cx, scope, mBoundElement,
-                                                  NS_GET_IID(nsISupports),
-                                                  getter_AddRefs(wrapper));
-            if (NS_FAILED(rv))
-              return;
-
-            JSObject* scriptObject;
-            if (wrapper)
-                wrapper->GetJSObject(&scriptObject);
-            else
-                scriptObject = nullptr;
-
+            JSObject* scriptObject = mBoundElement->GetWrapper();
             if (scriptObject) {
               // XXX Stay in sync! What if a layered binding has an
               // <interface>?!
               // XXXbz what does that comment mean, really?  It seems to date
               // back to when there was such a thing as an <interface>, whever
               // that was...
 
               // Find the right prototype.
--- a/content/xml/content/src/nsXMLElement.cpp
+++ b/content/xml/content/src/nsXMLElement.cpp
@@ -1,14 +1,15 @@
 /* -*- 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 "nsXMLElement.h"
+#include "mozilla/dom/ElementBinding.h"
 #include "nsContentUtils.h" // nsAutoScriptBlocker
 
 using namespace mozilla::dom;
 
 nsresult
 NS_NewXMLElement(nsIContent** aInstancePtrResult, already_AddRefed<nsINodeInfo> aNodeInfo)
 {
   nsXMLElement* it = new nsXMLElement(aNodeInfo);
@@ -26,16 +27,22 @@ NS_INTERFACE_TABLE_HEAD(nsXMLElement)
   NS_OFFSET_AND_INTERFACE_TABLE_END
   NS_ELEMENT_INTERFACE_TABLE_TO_MAP_SEGUE
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Element)
 NS_ELEMENT_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF_INHERITED(nsXMLElement, Element)
 NS_IMPL_RELEASE_INHERITED(nsXMLElement, Element)
 
+JSObject*
+nsXMLElement::WrapNode(JSContext *aCx, JSObject *aScope, bool *aTriedToWrap)
+{
+  return ElementBinding::Wrap(aCx, aScope, this, aTriedToWrap);
+}
+
 NS_IMPL_ELEMENT_CLONE(nsXMLElement)
 
 nsresult
 nsXMLElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                         bool aNotify)
 {
   nsAutoScriptBlocker scriptBlocker;
   bool isId = false;
--- a/content/xml/content/src/nsXMLElement.h
+++ b/content/xml/content/src/nsXMLElement.h
@@ -11,16 +11,17 @@
 
 class nsXMLElement : public mozilla::dom::Element,
                      public nsIDOMElement
 {
 public:
   nsXMLElement(already_AddRefed<nsINodeInfo> aNodeInfo)
     : mozilla::dom::Element(aNodeInfo)
   {
+    SetIsDOMBinding();
   }
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMNode
   NS_FORWARD_NSIDOMNODE_TO_NSINODE
 
@@ -46,12 +47,14 @@ public:
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult);
 
   // Element overrides
   virtual void NodeInfoChanged(nsINodeInfo* aOldNodeInfo);
 
-
+protected:
+  virtual JSObject* WrapNode(JSContext *aCx, JSObject *aScope,
+                             bool *aTriedToWrap) MOZ_OVERRIDE;
 };
 
 #endif // nsXMLElement_h___
--- a/content/xslt/tests/mochitest/test_bug427060.html
+++ b/content/xslt/tests/mochitest/test_bug427060.html
@@ -15,17 +15,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 427060 **/
 
 var xmldoc, xsltdoc;
-[ xmldoc, xsltdoc ] = [ new DOMParser().parseFromString(xml, "text/xml") for each (xml in [ 
+[ xmldoc, xsltdoc ] = [ new DOMParser().parseFromString(xml, "text/xml") for (xml of [ 
 
     '<opml version="1.0"><body></body></opml>' ,
 
     '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">\n\
     	<xsl:template match="/opml">\n\
     		<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n\
     			<head>\n\
     				<base target="_blank"></base>\n\
--- a/content/xslt/tests/mochitest/test_bug440974.html
+++ b/content/xslt/tests/mochitest/test_bug440974.html
@@ -21,17 +21,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 function isTxResult(node)
 {
   return node.namespaceURI == "http://www.mozilla.org/TransforMiix" &&
          node.localName == "result";
 }
 
 var xmldoc, xsltdoc;
-[ xmldoc, xsltdoc ] = [ new DOMParser().parseFromString(xml, "text/xml") for each (xml in [ 
+[ xmldoc, xsltdoc ] = [ new DOMParser().parseFromString(xml, "text/xml") for (xml of [ 
 
     '<items><item><id>1</id></item><item><id>2</id></item><item><id>3</id></item></items>' ,
 
     '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">\n\
         <xsl:output method="xml" />\n\
         <xsl:template match="item"><foo id="{id}"/></xsl:template>\n\
     </xsl:stylesheet>'
 
--- a/content/xslt/tests/mochitest/test_exslt_regex.html
+++ b/content/xslt/tests/mochitest/test_exslt_regex.html
@@ -23,17 +23,17 @@ http://www.exslt.org/regexp/index.html
       expr: "regexp:match('XSLT is great', 'XSL.', '')[1]",
       expResult: "XSLT" },
 
     { descr: "Testing regexp:replace",
       expr: "regexp:replace('Food is great', 'Fo.d', '', 'XSLT')",
       expResult: "XSLT is great" }
   ];
 
-  for each(test in tests) {
+  for (test of tests) {
     var style =
       '<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" ' +
                       'xmlns:regexp="http://exslt.org/regular-expressions" '+
                       'version="1.0">' +
         '<xsl:output method="html"/>' +
         '<xsl:template match="/">' +
           '<xsl:value-of select="'+test.expr+'" /> ' +
         '</xsl:template>' +
new file mode 100644
--- /dev/null
+++ b/dom/apps/src/AppDownloadManager.jsm
@@ -0,0 +1,98 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/FreeSpaceWatcher.jsm");
+
+this.EXPORTED_SYMBOLS = ["AppDownloadManager"];
+
+function debug(aMsg) {
+  //dump("-*-*- AppDownloadManager.jsm : " + aMsg + "\n");
+}
+
+this.AppDownloadManager = {
+  // Minimum disk free space we want to keep, in bytes.
+  // Keep synchronized with Webapps.jsm
+  MIN_REMAINING_FREESPACE: 5 * 1024 * 1024,
+
+  downloads: {},
+  count: 0,
+  cancelFunc: null,
+  timer: null,
+
+  /**
+   * Registers the function called when we need to cancel a download.
+   * The function will be called with a single parameter being the
+   * manifest URL.
+   */
+  registerCancelFunction: function app_dlMgr_registerCancel(aFunction) {
+    this.cancelFunc = aFunction;
+  },
+
+  /**
+   * Adds a download to the list of current downloads.
+   * @param aManifestURL The manifest URL for the application being downloaded.
+   * @param aDownload    An opaque object representing the download.
+   */
+  add: function app_dlMgr_add(aManifestURL, aDownload) {
+    debug("Adding " + aManifestURL);
+    if (!(aManifestURL in this.downloads)) {
+      this.count++;
+      if (this.count == 1) {
+        this.timer = FreeSpaceWatcher.create(this.MIN_REMAINING_FREESPACE,
+                                             this._spaceWatcher.bind(this));
+      }
+    }
+    this.downloads[aManifestURL] = aDownload;
+  },
+
+  /**
+   * Retrieves a download from the list of current downloads.
+   * @param  aManifestURL The manifest URL for the application being retrieved.
+   * @return              The opaque object representing the download.
+   */
+  get: function app_dlMgr_get(aManifestURL) {
+    debug("Getting " + aManifestURL);
+    return this.downloads[aManifestURL];
+  },
+
+  /**
+   * Removes a download of the list of current downloads.
+   * @param aManifestURL The manifest URL for the application being removed.
+   */
+  remove: function app_dlMgr_remove(aManifestURL) {
+    debug("Removing " + aManifestURL);
+    if (aManifestURL in this.downloads) {
+      this.count--;
+      delete this.downloads[aManifestURL];
+      if (this.count == 0) {
+        FreeSpaceWatcher.stop(this.timer);
+      }
+    }
+  },
+
+  /**
+   * Callback for the free space watcher. This will call cancel on downloads
+   * if needed.
+   */
+  _spaceWatcher: function app_dlMgr_watcher(aStatus) {
+    debug("Disk space is now " + aStatus);
+    if (aStatus == "free") {
+      // Nothing to do.
+      return;
+    }
+
+    // We cancel all downloads, because we don't know which ones we could
+    // keep running. We can improve that later if we have better heuristics,
+    // or when we'll support pause & resume we should just pause downloads.
+    for (let url in this.downloads) {
+      this.cancelFunc(url, "INSUFFICIENT_STORAGE");
+    }
+  }
+}
--- a/dom/apps/src/AppsUtils.jsm
+++ b/dom/apps/src/AppsUtils.jsm
@@ -43,16 +43,17 @@ this.AppsUtils = {
       installState: aApp.installState || "installed",
       downloadAvailable: aApp.downloadAvailable,
       downloading: aApp.downloading,
       readyToApplyDownload: aApp.readyToApplyDownload,
       downloadSize: aApp.downloadSize || 0,
       lastUpdateCheck: aApp.lastUpdateCheck,
       updateTime: aApp.updateTime,
       etag: aApp.etag,
+      packageEtag: aApp.packageEtag,
       installerAppId: aApp.installerAppId || Ci.nsIScriptSecurityManager.NO_APP_ID,
       installerIsBrowser: !!aApp.installerIsBrowser
     };
   },
 
   cloneAsMozIApplication: function cloneAsMozIApplication(aApp) {
     let res = this.cloneAppObject(aApp);
     res.hasPermission = function(aPermission) {
new file mode 100644
--- /dev/null
+++ b/dom/apps/src/FreeSpaceWatcher.jsm
@@ -0,0 +1,83 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+this.EXPORTED_SYMBOLS = ["FreeSpaceWatcher"];
+
+function debug(aMsg) {
+  //dump("-*-*- FreeSpaceWatcher.jsm : " + aMsg + "\n");
+}
+
+// Polling delay for free space, in ms.
+const DEFAULT_WATCHER_DELAY = 1000;
+
+this.FreeSpaceWatcher = {
+  timers: {},
+  id: 0,
+
+  /**
+   * This function  will call aOnStatusChange
+   * each time the free space for apps crosses aThreshold, checking
+   * every aDelay milliseconds, or every second by default.
+   * aOnStatusChange is called with either "free" or "full" and will
+   * always be called at least one to get the initial status.
+   * @param aThreshold      The amount of space in bytes to watch for.
+   * @param aOnStatusChange The function called when the state changes.
+   * @param aDelay          How often (in ms) we check free space. Defaults
+   *                        to DEFAULT_WATCHER_DELAY.
+   * @return                An opaque value to use with stop().
+   */
+  create: function spaceWatcher_create(aThreshold, aOnStatusChange, aDelay) {
+    let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+    debug("Creating new FreeSpaceWatcher");
+    let callback = {
+      currentStatus: null,
+      notify: function(aTimer) {
+        try {
+          let deviceStorage = Services.wm.getMostRecentWindow("navigator:browser")
+                                         .navigator.getDeviceStorage("apps");
+          let req = deviceStorage.stat();
+          req.onsuccess = req.onerror = function statResult(e) {
+            if (!e.target.result) {
+              return;
+            }
+
+            let freeBytes = e.target.result.freeBytes;
+            debug("Free bytes: " + freeBytes);
+            let newStatus = freeBytes > aThreshold;
+            if (newStatus != callback.currentStatus) {
+              debug("New status: " + (newStatus ? "free" : "full"));
+              aOnStatusChange(newStatus ? "free" : "full");
+              callback.currentStatus = newStatus;
+            }
+          }
+        } catch(e) { debug(e); }
+      }
+    }
+
+    timer.initWithCallback(callback, aDelay || DEFAULT_WATCHER_DELAY,
+                           Ci.nsITimer.TYPE_REPEATING_SLACK);
+    let id = "timer-" + this.id++;
+    this.timers[id] = timer;
+    return id;
+  },
+
+  /**
+   * This function stops a running watcher.
+   * @param aId The opaque timer id returned by create().
+   */
+  stop: function spaceWatcher_stop(aId) {
+    if (this.timers[aId]) {
+      this.timers[aId].cancel();
+      delete this.timers[aId];
+    }
+  }
+}
--- a/dom/apps/src/Makefile.in
+++ b/dom/apps/src/Makefile.in
@@ -24,11 +24,13 @@ EXTRA_PP_JS_MODULES += \
   $(NULL)
 
 EXTRA_JS_MODULES += \
   AppsServiceChild.jsm \
   AppsUtils.jsm \
   OfflineCacheInstaller.jsm \
   PermissionsInstaller.jsm \
   PermissionsTable.jsm \
+  FreeSpaceWatcher.jsm \
+  AppDownloadManager.jsm \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -14,16 +14,17 @@ this.EXPORTED_SYMBOLS = ["DOMApplication
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import('resource://gre/modules/ActivitiesService.jsm');
 Cu.import("resource://gre/modules/AppsUtils.jsm");
 Cu.import("resource://gre/modules/PermissionsInstaller.jsm");
 Cu.import("resource://gre/modules/OfflineCacheInstaller.jsm");
 Cu.import("resource://gre/modules/SystemMessagePermissionsChecker.jsm");
+Cu.import("resource://gre/modules/AppDownloadManager.jsm");
 
 function debug(aMsg) {
   //dump("-*-*- Webapps.jsm : " + aMsg + "\n");
 }
 
 // Minimum delay between two progress events while downloading, in ms.
 const MIN_PROGRESS_EVENT_DELAY = 1000;
 
@@ -63,17 +64,16 @@ XPCOMUtils.defineLazyGetter(this, "updat
   const DIRECTORY_NAME = WEBAPP_RUNTIME ? "WebappRegD" : "ProfD";
 #endif
 
 this.DOMApplicationRegistry = {
   appsFile: null,
   webapps: { },
   children: [ ],
   allAppsLaunchable: false,
-  downloads: { },
 
   init: function() {
     this.messages = ["Webapps:Install", "Webapps:Uninstall",
                      "Webapps:GetSelf", "Webapps:CheckInstalled",
                      "Webapps:GetInstalled", "Webapps:GetNotInstalled",
                      "Webapps:Launch", "Webapps:GetAll",
                      "Webapps:InstallPackage", "Webapps:GetBasePath",
                      "Webapps:GetList", "Webapps:RegisterForMessages",
@@ -87,16 +87,18 @@ this.DOMApplicationRegistry = {
     this.messages.forEach((function(msgName) {
       ppmm.addMessageListener(msgName, this);
     }).bind(this));
 
     cpmm.addMessageListener("Activities:Register:OK", this);
 
     Services.obs.addObserver(this, "xpcom-shutdown", false);
 
+    AppDownloadManager.registerCancelFunction(this.cancelDownload.bind(this));
+
     this.appsFile = FileUtils.getFile(DIRECTORY_NAME,
                                       ["webapps", "webapps.json"], true);
 
     this.loadAndUpdateApps();
   },
 
   // loads the current registry, that could be empty on first run.
   // aNext() is called after we load the current webapps list.
@@ -862,19 +864,20 @@ this.DOMApplicationRegistry = {
     if (app.installState == "pending") {
       aMm.sendAsyncMessage("Webapps:Launch:Return:KO", aData);
       return;
     }
 
     Services.obs.notifyObservers(aMm, "webapps-launch", JSON.stringify(aData));
   },
 
-  cancelDownload: function cancelDownload(aManifestURL) {
+  cancelDownload: function cancelDownload(aManifestURL, aError) {
     debug("cancelDownload " + aManifestURL);
-    let download = this.downloads[aManifestURL];
+    let error = aError || "DOWNLOAD_CANCELED";
+    let download = AppDownloadManager.get(aManifestURL);
     if (!download) {
       debug("Could not find a download for " + aManifestURL);
       return;
     }
 
     if (download.cacheUpdate) {
       // Cancel hosted app download.
       try {
@@ -893,18 +896,19 @@ this.DOMApplicationRegistry = {
     app.downloading = false;
     app.downloadAvailable = false;
     app.downloadSize = 0;
     this._saveApps((function() {
       this.broadcastMessage("Webapps:PackageEvent",
                              { type: "canceled",
                                manifestURL:  app.manifestURL,
                                app: app,
-                               error: "DOWNLOAD_CANCELED" });
+                               error: error });
     }).bind(this));
+    AppDownloadManager.remove(aManifestURL);
   },
 
   startDownload: function startDownload(aManifestURL) {
     debug("startDownload for " + aManifestURL);
     let id = this._appIdForManifestURL(aManifestURL);
     let app = this.webapps[id];
     if (!app) {
       debug("startDownload: No app found for " + aManifestURL);
@@ -1075,17 +1079,17 @@ this.DOMApplicationRegistry = {
 
     // We save the download details for potential further usage like cancelling
     // it.
     let download = {
       cacheUpdate: cacheUpdate,
       appId: this._appIdForManifestURL(aApp.manifestURL),
       previousState: aIsUpdate ? "installed" : "pending"
     };
-    this.downloads[aApp.manifestURL] = download;
+    AppDownloadManager.add(aApp.manifestURL, download);
 
     cacheUpdate.addObserver(new AppcacheObserver(aApp), false);
     if (aOfflineCacheObserver) {
       cacheUpdate.addObserver(aOfflineCacheObserver, false);
     }
   },
 
   checkForUpdate: function(aData, aMm) {
@@ -1117,20 +1121,22 @@ this.DOMApplicationRegistry = {
       let manifest = new ManifestHelper(aManifest, app.manifestURL);
       // A package is available: set downloadAvailable to fire the matching
       // event.
       app.downloadAvailable = true;
       app.downloadSize = manifest.size;
       aData.event = "downloadavailable";
       aData.app = {
         downloadAvailable: true,
-        downloadSize: manifest.size
+        downloadSize: manifest.size,
+        updateManifest: aManifest
       }
       DOMApplicationRegistry._saveApps(function() {
         aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
+        delete aData.app.updateManifest;
       });
     }
 
     function updateHostedApp(aManifest) {
       debug("updateHostedApp " + aData.manifestURL);
       let id = this._appId(app.origin);
 
       // Clean up the deprecated manifest cache if needed.
@@ -1156,29 +1162,30 @@ this.DOMApplicationRegistry = {
       let manFile = dir.clone();
       manFile.append("manifest.webapp");
       this._writeFile(manFile, JSON.stringify(aManifest), function() { });
 
       let manifest = new ManifestHelper(aManifest, app.origin);
 
       app.installState = "installed";
       app.downloading = false;
-      app.downloadsize = 0;
+      app.downloadSize = 0;
       app.readyToApplyDownload = false;
       app.downloadAvailable = !!manifest.appcache_path;
 
       app.name = aManifest.name;
       app.csp = aManifest.csp || "";
       app.updateTime = Date.now();
 
       // Update the registry.
       this.webapps[id] = app;
 
       this._saveApps(function() {
         aData.app = app;
+        app.manifest = aManifest;
         if (!manifest.appcache_path) {
           aData.event = "downloadapplied";
           aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
         } else {
           // Check if the appcache is updatable, and send "downloadavailable" or
           // "downloadapplied".
           let updateObserver = {
             observe: function(aSubject, aTopic, aObsData) {
@@ -1186,16 +1193,17 @@ this.DOMApplicationRegistry = {
                 aTopic == "offline-cache-update-available" ? "downloadavailable"
                                                            : "downloadapplied";
               aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
             }
           }
           updateSvc.checkForUpdate(Services.io.newURI(aData.manifestURL, null, null),
                                    app.localId, false, updateObserver);
         }
+        delete app.manifest;
       });
 
       // Update the permissions for this app.
       PermissionsInstaller.installPermissions({ manifest: aManifest,
                                                 origin: app.origin,
                                                 manifestURL: aData.manifestURL },
                                               true);
     }
@@ -1718,39 +1726,47 @@ this.DOMApplicationRegistry = {
 
       // We avoid notifying the error to the DOM side if the app download
       // was cancelled via cancelDownload, which already sends its own
       // notification.
       if (!app.downloading && !app.downloadAvailable && !app.downloadSize) {
         return;
       }
 
-      let download = self.downloads[aApp.manifestURL];
+      let download = AppDownloadManager.get(aApp.manifestURL);
       app.downloading = false;
       // If there were not enough storage to download the packaged app we
       // won't have a record of the download details, so we just set the
       // installState to 'pending'.
       app.installState = download ? download.previousState : "pending";
       self.broadcastMessage("Webapps:PackageEvent",
                             { type: "error",
                               manifestURL:  aApp.manifestURL,
                               error: aError,
                               app: app });
+      self._saveApps();
+      AppDownloadManager.remove(aApp.manifestURL);
     }
 
     function download() {
       debug("About to download " + aManifest.fullPackagePath());
 
       let requestChannel = NetUtil.newChannel(aManifest.fullPackagePath())
                                   .QueryInterface(Ci.nsIHttpChannel);
-      self.downloads[aApp.manifestURL] = {
-        channel: requestChannel,
-        appId: id,
-        previousState: aIsUpdate ? "installed" : "pending"
-      };
+      if (app.packageEtag) {
+        requestChannel.setRequestHeader("If-None-Match", app.packageEtag);
+      }
+
+      AppDownloadManager.add(aApp.manifestURL,
+        {
+          channel: requestChannel,
+          appId: id,
+          previousState: aIsUpdate ? "installed" : "pending"
+        }
+      );
 
       let lastProgressTime = 0;
       requestChannel.notificationCallbacks = {
         QueryInterface: function notifQI(aIID) {
           if (aIID.equals(Ci.nsISupports)          ||
               aIID.equals(Ci.nsIProgressEventSink) ||
               aIID.equals(Ci.nsILoadContext))
             return this;
@@ -1812,16 +1828,46 @@ this.DOMApplicationRegistry = {
                        .createInstance(Ci.nsISimpleStreamListener);
       listener.init(bufferedOutputStream, {
         onStartRequest: function(aRequest, aContext) { },
         onStopRequest: function(aRequest, aContext, aStatusCode) {
           debug("onStopRequest " + aStatusCode);
           bufferedOutputStream.close();
           outputStream.close();
 
+          if (requestChannel.responseStatus == 304) {
+            // The package's Etag has not changed.
+            // We send a "applied" event right away.
+            app.downloading = false;
+            app.downloadAvailable = false;
+            app.downloadSize = 0;
+            app.installState = "installed";
+            app.readyToApplyDownload = false;
+            self.broadcastMessage("Webapps:PackageEvent", {
+                                    type: "applied",
+                                    manifestURL: aApp.manifestURL,
+                                    app: app });
+            // Save the updated registry, and cleanup the tmp directory.
+            self._saveApps();
+            let file = FileUtils.getFile("TmpD", ["webapps", id], false);
+            if (file && file.exists()) {
+              file.remove(true);
+            }
+            return;
+          }
+
+          // Save the new Etag for the package.
+          app.packageEtag = requestChannel.getResponseHeader("Etag");
+          debug("Package etag=" + app.packageEtag);
+
+          if (!Components.isSuccessCode(aStatusCode)) {
+            cleanup("NETWORK_ERROR");
+            return;
+          }
+
           let certdb;
           try {
             certdb = Cc["@mozilla.org/security/x509certdb;1"]
                        .getService(Ci.nsIX509CertDB);
           } catch (e) {
             cleanup("CERTDB_ERROR");
             return;
           }
@@ -1869,34 +1915,36 @@ this.DOMApplicationRegistry = {
                 throw "INSTALL_FROM_DENIED";
               }
 
               let isDevMode = Services.prefs.getBoolPref("dom.mozApps.dev_mode");
               let maxStatus = isDevMode ? Ci.nsIPrincipal.APP_STATUS_CERTIFIED
                             : isSigned  ? Ci.nsIPrincipal.APP_STATUS_PRIVILEGED
                                         : Ci.nsIPrincipal.APP_STATUS_INSTALLED;
 
-              if (AppsUtils.getAppManifestStatus(aManifest) > maxStatus) {
+              if (AppsUtils.getAppManifestStatus(manifest) > maxStatus) {
                 throw "INVALID_SECURITY_LEVEL";
               }
+              aApp.appStatus = AppsUtils.getAppManifestStatus(manifest);
 
               if (aOnSuccess) {
                 aOnSuccess(id, manifest);
               }
-              delete self.downloads[aApp.manifestURL];
             } catch (e) {
               // Something bad happened when reading the package.
               if (typeof e == 'object') {
                 debug(e);
                 cleanup("INVALID_PACKAGE");
               } else {
                 cleanup(e);
               }
             } finally {
-              zipReader.close();
+              AppDownloadManager.remove(aApp.manifestURL);
+              if (zipReader)
+                zipReader.close();
             }
           });
         }
       });
 
       requestChannel.asyncOpen(listener, null);
     };
 
@@ -1910,17 +1958,18 @@ this.DOMApplicationRegistry = {
         download();
         return;
       }
 
       let freeBytes = e.target.result.freeBytes;
       if (freeBytes) {
         debug("Free storage: " + freeBytes + ". Download size: " +
               aApp.downloadSize);
-        if (freeBytes <= aApp.downloadSize) {
+        if (freeBytes <=
+            aApp.downloadSize + AppDownloadManager.MIN_REMAINING_FREESPACE) {
           cleanup("INSUFFICIENT_STORAGE");
           return;
         }
       }
       download();
     }
   },
 
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -54,17 +54,16 @@ AudioChannelService::GetAudioChannelServ
 void
 AudioChannelService::Shutdown()
 {
   if (XRE_GetProcessType() != GeckoProcessType_Default) {
     return AudioChannelServiceChild::Shutdown();
   }
 
   if (gAudioChannelService) {
-    delete gAudioChannelService;
     gAudioChannelService = nullptr;
   }
 }
 
 NS_IMPL_ISUPPORTS0(AudioChannelService)
 
 AudioChannelService::AudioChannelService()
 : mCurrentHigherChannel(AUDIO_CHANNEL_NORMAL)
--- a/dom/audiochannel/AudioChannelServiceChild.cpp
+++ b/dom/audiochannel/AudioChannelServiceChild.cpp
@@ -42,17 +42,16 @@ AudioChannelServiceChild::GetAudioChanne
   gAudioChannelServiceChild = service;
   return gAudioChannelServiceChild;
 }
 
 void
 AudioChannelServiceChild::Shutdown()
 {
   if (gAudioChannelServiceChild) {
-    delete gAudioChannelServiceChild;
     gAudioChannelServiceChild = nullptr;
   }
 }
 
 AudioChannelServiceChild::AudioChannelServiceChild()
 {
 }
 
--- a/dom/base/ScreenOrientation.h
+++ b/dom/base/ScreenOrientation.h
@@ -1,17 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_ScreenOrientation_h
 #define mozilla_dom_ScreenOrientation_h
 
-#include "ipc/IPCMessageUtils.h"
-
 namespace mozilla {
 namespace dom {
 
 // Make sure that any change here is also made in
 // * mobile/android/base/GeckoScreenOrientationListener.java
 // * embedding/android/GeckoScreenOrientationListener.java
 typedef uint32_t ScreenOrientation;
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1767,37 +1767,28 @@ jsid nsDOMClassInfo::sContent_id        
 jsid nsDOMClassInfo::sMenubar_id         = JSID_VOID;
 jsid nsDOMClassInfo::sToolbar_id         = JSID_VOID;
 jsid nsDOMClassInfo::sLocationbar_id     = JSID_VOID;
 jsid nsDOMClassInfo::sPersonalbar_id     = JSID_VOID;
 jsid nsDOMClassInfo::sStatusbar_id       = JSID_VOID;
 jsid nsDOMClassInfo::sDialogArguments_id = JSID_VOID;
 jsid nsDOMClassInfo::sControllers_id     = JSID_VOID;
 jsid nsDOMClassInfo::sLength_id          = JSID_VOID;
-jsid nsDOMClassInfo::sInnerHeight_id     = JSID_VOID;
-jsid nsDOMClassInfo::sInnerWidth_id      = JSID_VOID;
-jsid nsDOMClassInfo::sOuterHeight_id     = JSID_VOID;
-jsid nsDOMClassInfo::sOuterWidth_id      = JSID_VOID;
-jsid nsDOMClassInfo::sScreenX_id         = JSID_VOID;
-jsid nsDOMClassInfo::sScreenY_id         = JSID_VOID;
-jsid nsDOMClassInfo::sStatus_id          = JSID_VOID;
-jsid nsDOMClassInfo::sName_id            = JSID_VOID;
 jsid nsDOMClassInfo::sScrollX_id         = JSID_VOID;
 jsid nsDOMClassInfo::sScrollY_id         = JSID_VOID;
 jsid nsDOMClassInfo::sScrollMaxX_id      = JSID_VOID;
 jsid nsDOMClassInfo::sScrollMaxY_id      = JSID_VOID;
 jsid nsDOMClassInfo::sItem_id            = JSID_VOID;
 jsid nsDOMClassInfo::sNamedItem_id       = JSID_VOID;
 jsid nsDOMClassInfo::sEnumerate_id       = JSID_VOID;
 jsid nsDOMClassInfo::sNavigator_id       = JSID_VOID;
 jsid nsDOMClassInfo::sTop_id             = JSID_VOID;
 jsid nsDOMClassInfo::sDocument_id        = JSID_VOID;
 jsid nsDOMClassInfo::sFrames_id          = JSID_VOID;
 jsid nsDOMClassInfo::sSelf_id            = JSID_VOID;
-jsid nsDOMClassInfo::sOpener_id          = JSID_VOID;
 jsid nsDOMClassInfo::sAll_id             = JSID_VOID;
 jsid nsDOMClassInfo::sTags_id            = JSID_VOID;
 jsid nsDOMClassInfo::sDocumentURIObject_id=JSID_VOID;
 jsid nsDOMClassInfo::sWrappedJSObject_id = JSID_VOID;
 jsid nsDOMClassInfo::sURL_id             = JSID_VOID;
 jsid nsDOMClassInfo::sOnload_id          = JSID_VOID;
 jsid nsDOMClassInfo::sOnerror_id         = JSID_VOID;
 
@@ -2037,37 +2028,28 @@ nsDOMClassInfo::DefineStaticJSVals(JSCon
   SET_JSID_TO_STRING(sMenubar_id,         cx, "menubar");
   SET_JSID_TO_STRING(sToolbar_id,         cx, "toolbar");
   SET_JSID_TO_STRING(sLocationbar_id,     cx, "locationbar");
   SET_JSID_TO_STRING(sPersonalbar_id,     cx, "personalbar");
   SET_JSID_TO_STRING(sStatusbar_id,       cx, "statusbar");
   SET_JSID_TO_STRING(sDialogArguments_id, cx, "dialogArguments");
   SET_JSID_TO_STRING(sControllers_id,     cx, "controllers");
   SET_JSID_TO_STRING(sLength_id,          cx, "length");
-  SET_JSID_TO_STRING(sInnerHeight_id,     cx, "innerHeight");
-  SET_JSID_TO_STRING(sInnerWidth_id,      cx, "innerWidth");
-  SET_JSID_TO_STRING(sOuterHeight_id,     cx, "outerHeight");
-  SET_JSID_TO_STRING(sOuterWidth_id,      cx, "outerWidth");
-  SET_JSID_TO_STRING(sScreenX_id,         cx, "screenX");
-  SET_JSID_TO_STRING(sScreenY_id,         cx, "screenY");
-  SET_JSID_TO_STRING(sStatus_id,          cx, "status");
-  SET_JSID_TO_STRING(sName_id,            cx, "name");
   SET_JSID_TO_STRING(sScrollX_id,         cx, "scrollX");
   SET_JSID_TO_STRING(sScrollY_id,         cx, "scrollY");
   SET_JSID_TO_STRING(sScrollMaxX_id,      cx, "scrollMaxX");
   SET_JSID_TO_STRING(sScrollMaxY_id,      cx, "scrollMaxY");
   SET_JSID_TO_STRING(sItem_id,            cx, "item");
   SET_JSID_TO_STRING(sNamedItem_id,       cx, "namedItem");
   SET_JSID_TO_STRING(sEnumerate_id,       cx, "enumerateProperties");
   SET_JSID_TO_STRING(sNavigator_id,       cx, "navigator");
   SET_JSID_TO_STRING(sTop_id,             cx, "top");
   SET_JSID_TO_STRING(sDocument_id,        cx, "document");
   SET_JSID_TO_STRING(sFrames_id,          cx, "frames");
   SET_JSID_TO_STRING(sSelf_id,            cx, "self");
-  SET_JSID_TO_STRING(sOpener_id,          cx, "opener");
   SET_JSID_TO_STRING(sAll_id,             cx, "all");
   SET_JSID_TO_STRING(sTags_id,            cx, "tags");
   SET_JSID_TO_STRING(sDocumentURIObject_id,cx,"documentURIObject");
   SET_JSID_TO_STRING(sWrappedJSObject_id, cx, "wrappedJSObject");
   SET_JSID_TO_STRING(sURL_id,             cx, "URL");
   SET_JSID_TO_STRING(sOnload_id,          cx, "onload");
   SET_JSID_TO_STRING(sOnerror_id,         cx, "onerror");
 
@@ -5069,36 +5051,27 @@ nsDOMClassInfo::ShutDown()
   sMenubar_id         = JSID_VOID;
   sToolbar_id         = JSID_VOID;
   sLocationbar_id     = JSID_VOID;
   sPersonalbar_id     = JSID_VOID;
   sStatusbar_id       = JSID_VOID;
   sDialogArguments_id = JSID_VOID;
   sControllers_id     = JSID_VOID;
   sLength_id          = JSID_VOID;
-  sInnerHeight_id     = JSID_VOID;
-  sInnerWidth_id      = JSID_VOID;
-  sOuterHeight_id     = JSID_VOID;
-  sOuterWidth_id      = JSID_VOID;
-  sScreenX_id         = JSID_VOID;
-  sScreenY_id         = JSID_VOID;
-  sStatus_id          = JSID_VOID;
-  sName_id            = JSID_VOID;
   sScrollX_id         = JSID_VOID;
   sScrollY_id         = JSID_VOID;
   sScrollMaxX_id      = JSID_VOID;
   sScrollMaxY_id      = JSID_VOID;
   sItem_id            = JSID_VOID;
   sEnumerate_id       = JSID_VOID;
   sNavigator_id       = JSID_VOID;
   sTop_id             = JSID_VOID;
   sDocument_id        = JSID_VOID;
   sFrames_id          = JSID_VOID;
   sSelf_id            = JSID_VOID;
-  sOpener_id          = JSID_VOID;
   sAll_id             = JSID_VOID;
   sTags_id            = JSID_VOID;
   sDocumentURIObject_id=JSID_VOID;
   sWrappedJSObject_id = JSID_VOID;
   sOnload_id          = JSID_VOID;
   sOnerror_id         = JSID_VOID;
 
   NS_IF_RELEASE(sXPConnect);
@@ -5215,19 +5188,17 @@ GetDocument(JSObject *obj)
 
 // static
 JSBool
 nsWindowSH::GlobalScopePolluterNewResolve(JSContext *cx, JSHandleObject obj,
                                           JSHandleId id, unsigned flags,
                                           JSMutableHandleObject objp)
 {
   if ((flags & JSRESOLVE_ASSIGNING) || !JSID_IS_STRING(id)) {
-    // Nothing to do here if we're assigning or resolving a non-string
-    // property.
-
+    // Nothing to do if we're assigning or resolving a non-string property.
     return JS_TRUE;
   }
 
   nsHTMLDocument *document = GetDocument(obj);
 
   if (!document) {
     // If we don't have a document, return early.
 
@@ -7236,23 +7207,21 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
     }
 
     *objp = obj;
 
     return NS_OK;
   }
 
   if (flags & JSRESOLVE_ASSIGNING) {
-    if (IsReadonlyReplaceable(id) ||
-        (!(flags & JSRESOLVE_QUALIFIED) && IsWritableReplaceable(id))) {
-      // A readonly "replaceable" property is being set, or a
-      // readwrite "replaceable" property is being set w/o being
-      // fully qualified. Define the property on obj with the value
-      // undefined to override the predefined property. This is done
-      // for compatibility with other browsers.
+    if (IsReadonlyReplaceable(id)) {
+      // A readonly "replaceable" property is being set.  Define the property
+      // on obj with the value undefined to override the predefined property.
+      // This isn't quite what WebIDL requires for [Replaceable] properties,
+      // but it'll do until we move Window over to the new DOM bindings.
       JSAutoRequest ar(cx);
 
       if (!::JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, JS_PropertyStub,
                                    JS_StrictPropertyStub, JSPROP_ENUMERATE)) {
         return NS_ERROR_FAILURE;
       }
       *objp = obj;
 
@@ -7365,30 +7334,28 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
 
         if (pobj) {
           // A property was found on the prototype chain.
           *objp = pobj;
           return NS_OK;
         }
       }
 
-      // Define a fast expando, the key here is to use JS_PropertyStub
-      // as the getter/setter, which makes us stay out of XPConnect
-      // when using this property.
+      // Define a fast expando.  The key here is to use JS_PropertyStub as the
+      // getter/setter, which makes us stay out of XPConnect when using this
+      // property.
       //
-      // We don't need to worry about property attributes here as we
-      // know here we're dealing with an undefined property set, so
-      // we're not declaring readonly or permanent properties.
+      // We're adding a new property here, so we don't need to worry about
+      // conflicting with any existing ones.
       //
-      // Since we always create the undeclared property here without given a
-      // chance for the interpreter to report applicable strict mode warnings,
-      // we must take care to check those warnings here.
-      JSString *str = JSID_TO_STRING(id);
-      if ((!(flags & JSRESOLVE_QUALIFIED) &&
-           !js::CheckUndeclaredVarAssignment(cx, str)) ||
+      // Since we always create the undeclared property here, shortcutting the
+      // normal process, we go out of our way to tell the JS engine to report
+      // strict warnings/errors using js::ReportIfUndeclaredVarAssignment.
+      js::Rooted<JSString*> str(cx, JSID_TO_STRING(id));
+      if (!js::ReportIfUndeclaredVarAssignment(cx, str) ||
           !::JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, JS_PropertyStub,
                                    JS_StrictPropertyStub, JSPROP_ENUMERATE)) {
         *_retval = JS_FALSE;
 
         return NS_OK;
       }
 
       *objp = obj;
@@ -9022,20 +8989,19 @@ nsHTMLDocumentSH::NewResolve(nsIXPConnec
             if (!::JS_GetPrototype(cx, tmp, &tmpProto)) {
               return NS_ERROR_UNEXPECTED;
             }
           } while (tmpProto != helper);
 
           ::JS_SetPrototype(cx, tmp, proto);
         }
 
-        // If we don't already have a helper, and we're resolving
-        // document.all qualified, and "all" isn't already defined
-        // on our prototype, create a helper.
-        if (!helper && (flags & JSRESOLVE_QUALIFIED) && !hasAll) {
+        // If we don't already have a helper and "all" isn't already defined on
+        // our prototype, create a helper.
+        if (!helper && !hasAll) {
           // Print a warning so developers can stop using document.all
           PrintWarningOnConsole(cx, "DocumentAllUsed");
 
           if (!::JS_GetPrototype(cx, obj, &proto)) {
             return NS_ERROR_UNEXPECTED;
           }
           helper = ::JS_NewObject(cx, &sHTMLDocumentAllHelperClass,
                                   proto,
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -191,29 +191,16 @@ protected:
             id == sScrollMaxX_id   ||
             id == sScrollMaxY_id   ||
             id == sLength_id       ||
             id == sFrames_id       ||
             id == sSelf_id         ||
             id == sURL_id);
   }
 
-  static inline bool IsWritableReplaceable(jsid id)
-  {
-    return (id == sInnerHeight_id  ||
-            id == sInnerWidth_id   ||
-            id == sOpener_id       ||
-            id == sOuterHeight_id  ||
-            id == sOuterWidth_id   ||
-            id == sScreenX_id      ||
-            id == sScreenY_id      ||
-            id == sStatus_id       ||
-            id == sName_id);
-  }
-
   static nsIXPConnect *sXPConnect;
   static nsIScriptSecurityManager *sSecMan;
 
   // nsIXPCScriptable code
   static nsresult DefineStaticJSVals(JSContext *cx);
 
   static bool sIsInitialized;
   static bool sDisableDocumentAllSupport;
@@ -229,37 +216,28 @@ public:
   static jsid sMenubar_id;
   static jsid sToolbar_id;
   static jsid sLocationbar_id;
   static jsid sPersonalbar_id;
   static jsid sStatusbar_id;
   static jsid sDialogArguments_id;
   static jsid sControllers_id;
   static jsid sLength_id;
-  static jsid sInnerHeight_id;
-  static jsid sInnerWidth_id;
-  static jsid sOuterHeight_id;
-  static jsid sOuterWidth_id;
-  static jsid sScreenX_id;
-  static jsid sScreenY_id;
-  static jsid sStatus_id;
-  static jsid sName_id;
   static jsid sScrollX_id;
   static jsid sScrollY_id;
   static jsid sScrollMaxX_id;
   static jsid sScrollMaxY_id;
   static jsid sItem_id;
   static jsid sNamedItem_id;
   static jsid sEnumerate_id;
   static jsid sNavigator_id;
   static jsid sTop_id;
   static jsid sDocument_id;
   static jsid sFrames_id;
   static jsid sSelf_id;
-  static jsid sOpener_id;
   static jsid sAll_id;
   static jsid sTags_id;
   static jsid sDocumentURIObject_id;
   static jsid sJava_id;
   static jsid sPackages_id;
   static jsid sWrappedJSObject_id;
   static jsid sURL_id;
   static jsid sOnload_id;
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -131,16 +131,29 @@ public:
     mWrapperPtrBits = 0;
   }
 
   bool IsDOMBinding() const
   {
     return (mWrapperPtrBits & WRAPPER_IS_DOM_BINDING) != 0;
   }
 
+  void SetHasSystemOnlyWrapper()
+  {
+    MOZ_ASSERT(GetWrapperPreserveColor(),
+               "This flag should be set after wrapper creation.");
+    MOZ_ASSERT(IsDOMBinding(),
+               "This flag should only be set for DOM bindings.");
+    mWrapperPtrBits |= WRAPPER_HAS_SOW;
+  }
+
+  bool HasSystemOnlyWrapper() const
+  {
+    return (mWrapperPtrBits & WRAPPER_HAS_SOW) != 0;
+  }
 
   /**
    * Wrap the object corresponding to this wrapper cache. If non-null is
    * returned, the object has already been stored in the wrapper cache and the
    * value set in triedToWrap is meaningless. If null is returned then
    * triedToWrap indicates whether an error occurred, if it's false then the
    * object doesn't actually support creating a wrapper through its WrapObject
    * hook.
@@ -199,17 +212,25 @@ private:
   enum { WRAPPER_BIT_PRESERVED = 1 << 0 };
 
   /**
    * If this bit is set then the wrapper for the native object is a DOM binding
    * (regular JS object or proxy).
    */
   enum { WRAPPER_IS_DOM_BINDING = 1 << 1 };
 
-  enum { kWrapperBitMask = (WRAPPER_BIT_PRESERVED | WRAPPER_IS_DOM_BINDING) };
+  /**
+   * If this bit is set then the wrapper for the native object is a DOM binding
+   * (regular JS object or proxy) that has a system only wrapper for same-origin
+   * access.
+   */
+  enum { WRAPPER_HAS_SOW = 1 << 2 };
+
+  enum { kWrapperBitMask = (WRAPPER_BIT_PRESERVED | WRAPPER_IS_DOM_BINDING |
+                            WRAPPER_HAS_SOW) };
 
   uintptr_t mWrapperPtrBits;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsWrapperCache, NS_WRAPPERCACHE_IID)
 
 #define NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY                                   \
   if ( aIID.Equals(NS_GET_IID(nsWrapperCache)) ) {                            \
--- a/dom/base/nsWrapperCacheInlines.h
+++ b/dom/base/nsWrapperCacheInlines.h
@@ -4,16 +4,26 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsWrapperCacheInline_h___
 #define nsWrapperCacheInline_h___
 
 #include "nsWrapperCache.h"
 #include "xpcpublic.h"
 
+// We want to encode 3 bits into mWrapperPtrBits, so anything we store in it
+// needs to be aligned on 8 byte boundaries.
+// JS arenas are aligned on 4k boundaries and padded so that the array of
+// JSObjects ends on the end of the arena. If the size of a JSObject is a
+// multiple of 8 then the start of every JSObject in an arena should be aligned
+// on 8 byte boundaries.
+MOZ_STATIC_ASSERT(sizeof(js::shadow::Object) % 8 == 0 && sizeof(JS::Value) == 8,
+                  "We want to rely on JSObject being aligned on 8 byte "
+                  "boundaries.");
+
 inline JSObject*
 nsWrapperCache::GetWrapper() const
 {
     JSObject* obj = GetWrapperPreserveColor();
     xpc_UnmarkGrayObject(obj);
     return obj;
 }
 
--- a/dom/base/test/Makefile.in
+++ b/dom/base/test/Makefile.in
@@ -6,23 +6,25 @@ DEPTH = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 relativesrcdir = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_FILES = \
+  test_document.all_unqualified.html \
   test_domrequest.html \
   test_gsp-standards.html \
   test_gsp-quirks.html \
   test_gsp-qualified.html \
   test_nondomexception.html \
   test_screen_orientation.html \
   test_window_enumeration.html \
+  test_writable-replaceable.html \
   $(NULL)
 
 MOCHITEST_CHROME_FILES = \
    test_bug715041.xul \
    test_bug715041_removal.xul \
    $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_document.all_unqualified.html
@@ -0,0 +1,35 @@
+<html>
+<head>
+  <meta charset="UTF-8">
+  <title>Test for Bug 823283</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=823283">Mozilla Bug 823283</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<form id="f" onreset="window.valueOfAll = all; SimpleTest.executeSoon(finishTest); return false;">
+</form>
+</div>
+<pre id="test">
+<script>
+SimpleTest.waitForExplicitFinish();
+
+var all = 17;
+var valueOfAll = "initial value";
+
+function finishTest()
+{
+  is(valueOfAll, document.all,
+     "wrong value for |all| in event handler attribute; note that the wrong " +
+     "value may be |document.forms.f.all| in browsers with an 'all' property " +
+     "on elements");
+  SimpleTest.finish();
+}
+
+window.addEventListener("load", function() { document.getElementById("f").reset(); }, false);
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_writable-replaceable.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="UTF-8">
+  <title>Test for Bug 823283</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=823283">Mozilla Bug 823283</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+<script type="application/javascript">
+/** Test for Bug 823283 **/
+
+function createTest(prop, typeStr, valCode)
+{
+  var code =
+    'is(typeof ' + prop + ', "' + typeStr + '", "' + prop + ': bad unqualified before-state");\n' +
+    'is(typeof window.' + prop + ', "' + typeStr + '", "' + prop + ': bad qualified before-state");\n' +
+    '\n' +
+    prop + ' = ' + valCode + ';\n' +
+    '\n' +
+    'is(typeof ' + prop + ', "' + typeStr + '", "' + prop + ': bad unqualified after-state");\n' +
+    'is(typeof window.' + prop + ', "' + typeStr + '", "' + prop + ': bad qualified after-state");';
+
+  return Function(code);
+}
+
+[
+  ["innerHeight", "number", '"123"'],
+  ["innerWidth", "number", '"456"'],
+  ["outerHeight", "number", '"654"'],
+  ["outerWidth", "number", '"321"'],
+  ["screenX", "number", '"17"'],
+  ["screenY", "number", '"42"'],
+  ["status", "string", '{}'],
+  ["name", "string", '{}'],
+].forEach(function(args)
+{
+  createTest.apply(null, args)();
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -7,21 +7,22 @@
 #include <algorithm>
 #include <stdarg.h>
 
 #include "mozilla/DebugOnly.h"
 
 #include "BindingUtils.h"
 
 #include "AccessCheck.h"
+#include "nsContentUtils.h"
+#include "nsIXPConnect.h"
 #include "WrapperFactory.h"
 #include "xpcprivate.h"
-#include "nsContentUtils.h"
 #include "XPCQuickStubs.h"
-#include "nsIXPConnect.h"
+#include "XrayWrapper.h"
 
 namespace mozilla {
 namespace dom {
 
 JSErrorFormatString ErrorFormatString[] = {
 #define MSG_DEF(_name, _argc, _str) \
   { _str, _argc, JSEXN_TYPEERR },
 #include "mozilla/dom/Errors.msg"
@@ -1249,10 +1250,169 @@ NativeToString(JSContext* cx, JSObject* 
   if (!str) {
     return false;
   }
 
   v->setString(str);
   return JS_WrapValue(cx, v);
 }
 
+// Dynamically ensure that two objects don't end up with the same reserved slot.
+class AutoCloneDOMObjectSlotGuard NS_STACK_CLASS
+{
+public:
+  AutoCloneDOMObjectSlotGuard(JSObject* aOld, JSObject* aNew)
+    : mOldReflector(aOld), mNewReflector(aNew)
+  {
+    MOZ_ASSERT(js::GetReservedSlot(aOld, DOM_OBJECT_SLOT) ==
+                 js::GetReservedSlot(aNew, DOM_OBJECT_SLOT));
+  }
+
+  ~AutoCloneDOMObjectSlotGuard()
+  {
+    if (js::GetReservedSlot(mOldReflector, DOM_OBJECT_SLOT).toPrivate()) {
+      js::SetReservedSlot(mNewReflector, DOM_OBJECT_SLOT,
+                          JS::PrivateValue(nullptr));
+    }
+  }
+
+private:
+  JSObject* mOldReflector;
+  JSObject* mNewReflector;
+  size_t mSlot;
+};
+
+nsresult
+ReparentWrapper(JSContext* aCx, JSObject* aObj)
+{
+  const DOMClass* domClass = GetDOMClass(aObj);
+
+  JSObject* oldParent = JS_GetParent(aObj);
+  JSObject* newParent = domClass->mGetParent(aCx, aObj);
+
+  JSAutoCompartment oldAc(aCx, oldParent);
+
+  if (js::GetObjectCompartment(oldParent) ==
+      js::GetObjectCompartment(newParent)) {
+    if (!JS_SetParent(aCx, aObj, newParent)) {
+      MOZ_CRASH();
+    }
+    return NS_OK;
+  }
+
+  nsISupports* native;
+  if (!UnwrapDOMObjectToISupports(aObj, native)) {
+    return NS_OK;
+  }
+
+  // Before proceeding, eagerly create any same-compartment security wrappers
+  // that the object might have. This forces us to take the 'WithWrapper' path
+  // while transplanting that handles this stuff correctly.
+  JSObject* ww = xpc::WrapperFactory::WrapForSameCompartment(aCx, aObj);
+  if (!ww) {
+    return NS_ERROR_FAILURE;
+  }
+
+  JSAutoCompartment newAc(aCx, newParent);
+
+  // First we clone the reflector. We get a copy of its properties and clone its
+  // expando chain. The only part that is dangerous here is that if we have to
+  // return early we must avoid ending up with two reflectors pointing to the
+  // same native. Other than that, the objects we create will just go away.
+
+  JSObject *proto =
+    (domClass->mGetProto)(aCx,
+                          js::GetGlobalForObjectCrossCompartment(newParent));
+  if (!proto) {
+    return NS_ERROR_FAILURE;
+  }
+
+  JSObject *newobj = JS_CloneObject(aCx, aObj, proto, newParent);
+  if (!newobj) {
+    return NS_ERROR_FAILURE;
+  }
+
+  js::SetReservedSlot(newobj, DOM_OBJECT_SLOT,
+                      js::GetReservedSlot(aObj, DOM_OBJECT_SLOT));
+
+  // At this point, both |aObj| and |newobj| point to the same native
+  // which is bad, because one of them will end up being finalized with a
+  // native it does not own. |cloneGuard| ensures that if we exit before
+  // clearing |aObj|'s reserved slot the reserved slot of |newobj| will be
+  // set to null. |aObj| will go away soon, because we swap it with
+  // another object during the transplant and let that object die.
+  JSObject *propertyHolder;
+  {
+    AutoCloneDOMObjectSlotGuard cloneGuard(aObj, newobj);
+
+    propertyHolder = JS_NewObjectWithGivenProto(aCx, nullptr, nullptr,
+                                                newParent);
+    if (!propertyHolder) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    if (!JS_CopyPropertiesFrom(aCx, propertyHolder, aObj)) {
+      return NS_ERROR_FAILURE;
+    }
+
+    // Expandos from other compartments are attached to the target JS object.
+    // Copy them over, and let the old ones die a natural death.
+    SetXrayExpandoChain(newobj, nullptr);
+    if (!xpc::XrayUtils::CloneExpandoChain(aCx, newobj, aObj)) {
+      return NS_ERROR_FAILURE;
+    }
+
+    // We've set up |newobj|, so we make it own the native by nulling
+    // out the reserved slot of |obj|.
+    //
+    // NB: It's important to do this _after_ copying the properties to
+    // propertyHolder. Otherwise, an object with |foo.x === foo| will
+    // crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x.
+    js::SetReservedSlot(aObj, DOM_OBJECT_SLOT, JS::PrivateValue(nullptr));
+  }
+
+  nsWrapperCache* cache = nullptr;
+  CallQueryInterface(native, &cache);
+  if (ww != aObj) {
+    MOZ_ASSERT(cache->HasSystemOnlyWrapper());
+
+    JSObject *newwrapper =
+      xpc::WrapperFactory::WrapSOWObject(aCx, newobj);
+    if (!newwrapper) {
+      MOZ_CRASH();
+    }
+
+    // Ok, now we do the special object-plus-wrapper transplant.
+    ww = xpc::TransplantObjectWithWrapper(aCx, aObj, ww, newobj, newwrapper);
+    if (!ww) {
+      MOZ_CRASH();
+    }
+
+    aObj = newobj;
+    SetSystemOnlyWrapperSlot(aObj, JS::ObjectValue(*ww));
+  } else {
+    aObj = xpc::TransplantObject(aCx, aObj, newobj);
+    if (!aObj) {
+      MOZ_CRASH();
+    }
+  }
+
+  bool preserving = cache->PreservingWrapper();
+  cache->SetPreservingWrapper(false);
+  cache->SetWrapper(aObj);
+  cache->SetPreservingWrapper(preserving);
+  if (!JS_CopyPropertiesFrom(aCx, aObj, propertyHolder)) {
+    MOZ_CRASH();
+  }
+
+  // We might need to call a hook here similar to PostTransplant.
+
+  // Now we can just fix up the parent and return the wrapper
+
+  if (newParent && !JS_SetParent(aCx, aObj, newParent)) {
+    MOZ_CRASH();
+  }
+
+  return NS_OK;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -470,35 +470,93 @@ CouldBeDOMBinding(void*)
 }
 
 MOZ_ALWAYS_INLINE bool
 CouldBeDOMBinding(nsWrapperCache* aCache)
 {
   return aCache->IsDOMBinding();
 }
 
+// The DOM_OBJECT_SLOT_SOW slot contains a JS::ObjectValue which points to the
+// cached system object wrapper (SOW) or JS::UndefinedValue if this class
+// doesn't need SOWs.
+
+inline const JS::Value&
+GetSystemOnlyWrapperSlot(JSObject* obj)
+{
+  MOZ_ASSERT(IsDOMClass(js::GetObjectJSClass(obj)) &&
+             !(js::GetObjectJSClass(obj)->flags & JSCLASS_DOM_GLOBAL));
+  return js::GetReservedSlot(obj, DOM_OBJECT_SLOT_SOW);
+}
+inline void
+SetSystemOnlyWrapperSlot(JSObject* obj, const JS::Value& v)
+{
+  MOZ_ASSERT(IsDOMClass(js::GetObjectJSClass(obj)) &&
+             !(js::GetObjectJSClass(obj)->flags & JSCLASS_DOM_GLOBAL));
+  js::SetReservedSlot(obj, DOM_OBJECT_SLOT_SOW, v);
+}
+
+inline bool
+GetSameCompartmentWrapperForDOMBinding(JSObject*& obj)
+{
+  js::Class* clasp = js::GetObjectClass(obj);
+  if (dom::IsDOMClass(clasp)) {
+    if (!(clasp->flags & JSCLASS_DOM_GLOBAL)) {
+      JS::Value v = GetSystemOnlyWrapperSlot(obj);
+      if (v.isObject()) {
+        obj = &v.toObject();
+      }
+    }
+    return true;
+  }
+  return IsDOMProxy(obj, clasp);
+}
+
+inline void
+SetSystemOnlyWrapper(JSObject* obj, nsWrapperCache* cache, JSObject& wrapper)
+{
+  SetSystemOnlyWrapperSlot(obj, JS::ObjectValue(wrapper));
+  cache->SetHasSystemOnlyWrapper();
+}
+
+static inline void
+WrapNewBindingForSameCompartment(JSContext* cx, JSObject* obj, void* value,
+                                 JS::Value* vp)
+{
+  *vp = JS::ObjectValue(*obj);
+}
+
+static inline void
+WrapNewBindingForSameCompartment(JSContext* cx, JSObject* obj,
+                                 nsWrapperCache* value, JS::Value* vp)
+{
+  if (value->HasSystemOnlyWrapper()) {
+    *vp = GetSystemOnlyWrapperSlot(obj);
+    MOZ_ASSERT(vp->isObject());
+  } else {
+    *vp = JS::ObjectValue(*obj);
+  }
+}
+
 // Create a JSObject wrapping "value", if there isn't one already, and store it
 // in *vp.  "value" must be a concrete class that implements a
 // GetWrapperPreserveColor() which can return its existing wrapper, if any, and
 // a WrapObject() which will try to create a wrapper. Typically, this is done by
 // having "value" inherit from nsWrapperCache.
 template <class T>
 MOZ_ALWAYS_INLINE bool
 WrapNewBindingObject(JSContext* cx, JSObject* scope, T* value, JS::Value* vp)
 {
   JSObject* obj = value->GetWrapperPreserveColor();
+  bool couldBeDOMBinding = CouldBeDOMBinding(value);
   if (obj) {
     xpc_UnmarkNonNullGrayObject(obj);
-    if (js::GetObjectCompartment(obj) == js::GetContextCompartment(cx)) {
-      *vp = JS::ObjectValue(*obj);
-      return true;
-    }
   } else {
     // Inline this here while we have non-dom objects in wrapper caches.
-    if (!CouldBeDOMBinding(value)) {
+    if (!couldBeDOMBinding) {
       return false;
     }
 
     bool triedToWrap;
     obj = value->WrapObject(cx, scope, &triedToWrap);
     if (!obj) {
       // At this point, obj is null, so just return false.  We could
       // try to communicate triedToWrap to the caller, but in practice
@@ -518,26 +576,34 @@ WrapNewBindingObject(JSContext* cx, JSOb
     //     XXXbz ideally, we could assert that reinterpret_cast to nsISupports
     //     does the right thing, but I don't see a way to do it.  :(
     // 2)  If our class doesn't claim we're nsISupports we better be
     //     reinterpret_castable to nsWrapperCache.
     MOZ_ASSERT(clasp, "What happened here?");
     MOZ_ASSERT_IF(clasp->mDOMObjectIsISupports, IsISupports<T>::Value);
     MOZ_ASSERT(CheckWrapperCacheCast<T>::Check());
   }
-#endif
 
   // When called via XrayWrapper, we end up here while running in the
   // chrome compartment.  But the obj we have would be created in
   // whatever the content compartment is.  So at this point we need to
   // make sure it's correctly wrapped for the compartment of |scope|.
   // cx should already be in the compartment of |scope| here.
   MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
+#endif
+
+  bool sameCompartment =
+    js::GetObjectCompartment(obj) == js::GetContextCompartment(cx);
+  if (sameCompartment && couldBeDOMBinding) {
+    WrapNewBindingForSameCompartment(cx, obj, value, vp);
+    return true;
+  }
+
   *vp = JS::ObjectValue(*obj);
-  return JS_WrapValue(cx, vp);
+  return (sameCompartment && IS_SLIM_WRAPPER(obj)) || JS_WrapValue(cx, vp);
 }
 
 // Create a JSObject wrapping "value", for cases when "value" is a
 // non-wrapper-cached object using WebIDL bindings.  "value" must implement a
 // WrapObject() method taking a JSContext and a scope.
 template <class T>
 inline bool
 WrapNewBindingNonWrapperCachedObject(JSContext* cx, JSObject* scope, T* value,
@@ -979,16 +1045,38 @@ WrapNativeParent(JSContext* cx, JSObject
 // things like the nsWrapperCache for it.
 template<typename T>
 static inline JSObject*
 WrapNativeParent(JSContext* cx, JSObject* scope, const T& p)
 {
   return WrapNativeParent(cx, scope, GetParentPointer(p), GetWrapperCache(p));
 }
 
+HAS_MEMBER(GetParentObject)
+
+template<typename T, bool WrapperCached=HasGetParentObjectMember<T>::Value>
+struct GetParentObject
+{
+  static JSObject* Get(JSContext* cx, JSObject* obj)
+  {
+    T* native = UnwrapDOMObject<T>(obj);
+    return WrapNativeParent(cx, obj, native->GetParentObject());
+  }
+};
+
+template<typename T>
+struct GetParentObject<T, false>
+{
+  static JSObject* Get(JSContext* cx, JSObject* obj)
+  {
+    MOZ_CRASH();
+    return nullptr;
+  }
+};
+
 template<typename T>
 static inline JSObject*
 WrapCallThisObject(JSContext* cx, JSObject* scope, const T& p)
 {
   // WrapNativeParent is a bit of a Swiss army knife that will
   // wrap anything for us.
   JSObject* obj = WrapNativeParent(cx, scope, p);
   if (!obj) {
@@ -1586,12 +1674,15 @@ protected:
  * pre is a string that should be prefixed to the value.
  * post is a string that should be prefixed to the value.
  * v contains the JSString for the value if the function returns true.
  */
 bool
 NativeToString(JSContext* cx, JSObject* wrapper, JSObject* obj, const char* pre,
                const char* post, JS::Value* v);
 
+nsresult
+ReparentWrapper(JSContext* aCx, JSObject* aObj);
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_BindingUtils_h__ */
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -208,17 +208,16 @@ DOMInterfaces = {
                            'reduction', 'attack', 'release' ],
     'binaryNames': {
         'release': 'getRelease'
     }
 }],
 
 'Element': {
     'hasXPConnectImpls': True,
-    'register': False,
     'hasInstanceInterface': 'nsIDOMElement',
     'resultNotAddRefed': [
         'classList', 'attributes', 'children', 'firstElementChild',
         'lastElementChild', 'previousElementSibling', 'nextElementSibling',
         'getAttributeNode', 'getAttributeNodeNS'
     ]
 },
 
@@ -272,19 +271,22 @@ DOMInterfaces = {
     'resultNotAddRefed': [ 'gain' ],
 }],
 
 'HTMLCollection': {
     'nativeType': 'nsIHTMLCollection',
     'resultNotAddRefed': [ 'item' ]
 },
 
+'HTMLDivElement': {
+    'nativeType': 'nsHTMLDivElement'
+},
+
 'HTMLElement': {
     'nativeType': 'nsGenericHTMLElement',
-    'register': False,
     'hasXPConnectImpls': True,
     'hasInstanceInterface': 'nsIDOMHTMLElement',
     'resultNotAddRefed': [
         'itemType', 'itemRef', 'itemProp', 'properties', 'contextMenu', 'style',
         'offsetParent'
     ]
 },
 
@@ -298,19 +300,17 @@ DOMInterfaces = {
 },
 
 'HTMLPropertiesCollection': {
     'headerFile': 'HTMLPropertiesCollection.h',
     'resultNotAddRefed': [ 'item', 'namedItem', 'names' ]
 },
 
 'HTMLUnknownElement': {
-    'nativeType': 'nsHTMLUnknownElement',
-    'register': False,
-    'hasXPConnectImpls': True
+    'nativeType': 'nsHTMLUnknownElement'
 },
 
 'IID': [
 {
     'nativeType': 'nsIJSID',
     'headerFile': 'xpcjsid.h',
 },
 {
@@ -441,19 +441,29 @@ DOMInterfaces = {
 },
 
 'SVGTransformList': {
     'nativeType': 'mozilla::DOMSVGTransformList',
     'headerFile': 'DOMSVGTransformList.h',
     'resultNotAddRefed': [ 'getItem' ]
 },
 
-'TextEncoder': {
+'TextDecoder': [
+{
+    'workers': True,
+}],
+
+'TextEncoder': [
+{
     'implicitJSContext': [ 'encode' ],
 },
+{
+    'workers': True,
+    'implicitJSContext': [ 'encode' ],
+}],
 
 'URL' : {
     'concrete': False,
 },
 
 'WebGLActiveInfo': {
    'nativeType': 'mozilla::WebGLActiveInfo',
    'headerFile': 'WebGLContext.h',
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -126,23 +126,27 @@ def DOMClass(descriptor):
         # is never the ID of any prototype, so it's safe to use as
         # padding.
         protoList.extend(['prototypes::id::_ID_Count'] * (descriptor.config.maxProtoChainLength - len(protoList)))
         prototypeChainString = ', '.join(protoList)
         if descriptor.workers or descriptor.nativeOwnership != 'refcounted':
             participant = "nullptr"
         else:
             participant = "NS_CYCLE_COLLECTION_PARTICIPANT(%s)" % descriptor.nativeType
+        getParentObject = "GetParentObject<%s>::Get" % descriptor.nativeType
         return """{
   { %s },
   %s,
   %s,
+  %s,
+  GetProtoObject,
   %s
 }""" % (prototypeChainString, toStringBool(descriptor.nativeOwnership == 'nsisupports'),
         NativePropertyHooks(descriptor),
+        getParentObject,
         participant)
 
 class CGDOMJSClass(CGThing):
     """
     Generate a DOMJSClass for a given descriptor
     """
     def __init__(self, descriptor):
         CGThing.__init__(self)
@@ -151,17 +155,17 @@ class CGDOMJSClass(CGThing):
         assert "Window" not in descriptor.interface.identifier.name
     def declare(self):
         return "extern DOMJSClass Class;\n"
     def define(self):
         traceHook = TRACE_HOOK_NAME if self.descriptor.customTrace else 'NULL'
         return """
 DOMJSClass Class = {
   { "%s",
-    JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2),
+    JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(3),
     %s, /* addProperty */
     JS_PropertyStub,       /* delProperty */
     JS_PropertyStub,       /* getProperty */
     JS_StrictPropertyStub, /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
     %s, /* finalize */
@@ -827,32 +831,31 @@ class CGDeferredFinalize(CGAbstractStati
   if (newLen == 0) {
     delete pointers;
     return true;
   }
   return false;""" % { 'smartPtr': smartPtr }
 
 def finalizeHook(descriptor, hookName, context):
     if descriptor.customFinalize:
-        return """if (self) {
-  self->%s(%s);
-}""" % (hookName, context)
-    clearWrapper = "ClearWrapper(self, self);\n" if descriptor.wrapperCache else ""
-    if descriptor.workers:
-        release = "self->Release();"
-    elif descriptor.nativeOwnership == 'nsisupports':
-        release = """XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
+        finalize = "self->%s(%s);" % (hookName, context)
+    else:
+        finalize = "ClearWrapper(self, self);\n" if descriptor.wrapperCache else ""
+        if descriptor.workers:
+            finalize += "self->Release();"
+        elif descriptor.nativeOwnership == 'nsisupports':
+            finalize += """XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
 if (rt) {
   rt->DeferredRelease(reinterpret_cast<nsISupports*>(self));
 } else {
   NS_RELEASE(self);
 }"""
-    else:
-        smartPtr = DeferredFinalizeSmartPtr(descriptor)
-        release = """static bool registered = false;
+        else:
+            smartPtr = DeferredFinalizeSmartPtr(descriptor)
+            finalize += """static bool registered = false;
 if (!registered) {
   XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
   if (!rt) {
     %(smartPtr)s dying;
     Take(dying, self);
     return;
   }
   rt->RegisterDeferredFinalize(GetDeferredFinalizePointers, DeferredFinalize);
@@ -863,29 +866,29 @@ if (!sDeferredFinalizePointers) {
 }
 %(smartPtr)s* defer = sDeferredFinalizePointers->AppendElement();
 if (!defer) {
   %(smartPtr)s dying;
   Take(dying, self);
   return;
 }
 Take(*defer, self);""" % { 'smartPtr': smartPtr }
-    return clearWrapper + release
+    return CGIfWrapper(CGGeneric(finalize), "self")
 
 class CGClassFinalizeHook(CGAbstractClassHook):
     """
     A hook for finalize, used to release our native object.
     """
     def __init__(self, descriptor):
         args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'obj')]
         CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
                                      'void', args)
 
     def generate_code(self):
-        return CGIndenter(CGGeneric(finalizeHook(self.descriptor, self.name, self.args[0].name))).define()
+        return CGIndenter(finalizeHook(self.descriptor, self.name, self.args[0].name)).define()
 
 class CGClassTraceHook(CGAbstractClassHook):
     """
     A hook to trace through our native object; used for GC and CC
     """
     def __init__(self, descriptor):
         args = [Argument('JSTracer*', 'trc'), Argument('JSObject*', 'obj')]
         CGAbstractClassHook.__init__(self, descriptor, TRACE_HOOK_NAME, 'void',
@@ -6107,17 +6110,17 @@ class CGDOMJSProxyHandler_obj_toString(C
 
 class CGDOMJSProxyHandler_finalize(ClassMethod):
     def __init__(self, descriptor):
         args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'proxy')]
         ClassMethod.__init__(self, "finalize", "void", args)
         self.descriptor = descriptor
     def getBody(self):
         return ("%s self = UnwrapProxy(proxy);\n\n" % (self.descriptor.nativeType + "*") +
-                finalizeHook(self.descriptor, FINALIZE_HOOK_NAME, self.args[0].name))
+                finalizeHook(self.descriptor, FINALIZE_HOOK_NAME, self.args[0].name).define())
 
 class CGDOMJSProxyHandler_getElementIfPresent(ClassMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
                 Argument('JSObject*', 'receiver'),
                 Argument('uint32_t', 'index'),
                 Argument('JS::Value*', 'vp'), Argument('bool*', 'present')]
         ClassMethod.__init__(self, "getElementIfPresent", "bool", args)
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -18,16 +18,22 @@ class nsCycleCollectionParticipant;
 // globals and non-globals.
 #define DOM_OBJECT_SLOT 0
 
 // We use slot 1 for holding the expando object. This is not safe for globals
 // until bug 760095 is fixed, so that bug blocks converting Window to new
 // bindings.
 #define DOM_XRAY_EXPANDO_SLOT 1
 
+// We use slot 2 for holding either a JS::ObjectValue which points to the cached
+// SOW or JS::UndefinedValue if this class doesn't need SOWs. This is not safe
+// for globals until bug 760095 is fixed, so that bug blocks converting Window
+// to new bindings.
+#define DOM_OBJECT_SLOT_SOW 2
+
 // All DOM globals must have a slot at DOM_PROTOTYPE_SLOT.
 #define DOM_PROTOTYPE_SLOT JSCLASS_GLOBAL_SLOT_COUNT
 
 // We use these flag bits for the new bindings.
 #define JSCLASS_DOM_GLOBAL JSCLASS_USERBIT1
 #define JSCLASS_IS_DOMIFACEANDPROTOJSCLASS JSCLASS_USERBIT2
 
 // NOTE: This is baked into the Ion JIT as 0 in codegen for LGetDOMProperty and
@@ -124,30 +130,36 @@ struct NativePropertyHooks
 };
 
 enum DOMObjectType {
   eInstance,
   eInterface,
   eInterfacePrototype
 };
 
+typedef JSObject* (*ParentGetter)(JSContext* aCx, JSObject* aObj);
+typedef JSObject* (*ProtoGetter)(JSContext* aCx, JSObject* aGlobal);
+
 struct DOMClass
 {
   // A list of interfaces that this object implements, in order of decreasing
   // derivedness.
   const prototypes::ID mInterfaceChain[MAX_PROTOTYPE_CHAIN_LENGTH];
 
   // We store the DOM object in reserved slot with index DOM_OBJECT_SLOT or in
   // the proxy private if we use a proxy object.
   // Sometimes it's an nsISupports and sometimes it's not; this class tells
   // us which it is.
   const bool mDOMObjectIsISupports;
 
   const NativePropertyHooks* mNativeHooks;
 
+  ParentGetter mGetParent;
+  ProtoGetter mGetProto;
+
   // This stores the CC participant for the native, null if this class is for a
   // worker or for a native inheriting from nsISupports (we can get the CC
   // participant by QI'ing in that case).
   nsCycleCollectionParticipant* mParticipant;
 };
 
 // Special JSClass for reflected DOM objects.
 struct DOMJSClass
--- a/dom/bluetooth/BluetoothService.cpp
+++ b/dom/bluetooth/BluetoothService.cpp
@@ -425,25 +425,18 @@ BluetoothService::SetEnabled(bool aEnabl
     mBluetoothSignalObserverTable.Clear();
   }
 
   /**
    * mEnabled: real status of bluetooth
    * aEnabled: expected status of bluetooth
    */
   if (mEnabled == aEnabled) {
-    /**
-     * The process of toggling should be over here, so we set gToggleInProgress
-     * back to false here. Note that, we don't fire onenabled/ondisabled in
-     * this case.
-     */
-    NS_WARNING("Bluetooth has already been enabled/disabled before.\
-                Skip fire onenabled/ondisabled events here.");
-    gToggleInProgress = false;
-    return;
+    NS_WARNING("Bluetooth has already been enabled/disabled before\
+                or the toggling is failed.");
   }
 
   mEnabled = aEnabled;
 
   // Fire onenabled/ondisabled event for each BluetoothManager
   BluetoothManagerList::ForwardIterator iter(mLiveManagers);
   while (iter.HasMore()) {
     if (NS_FAILED(iter.GetNext()->FireEnabledDisabledEvent(aEnabled))) {
--- a/dom/bluetooth/ObexBase.cpp
+++ b/dom/bluetooth/ObexBase.cpp
@@ -110,18 +110,15 @@ ParseHeaders(const uint8_t* aHeaderStart
         break;
 
       case 0x03:
         // 4 byte quantity
         contentLength = 4;
         break;
     }
 
-    uint8_t* content = new uint8_t[contentLength];
-    memcpy(content, ptr, contentLength);
-    aRetHandlerSet->AddHeader(new ObexHeader(headerId, contentLength, content));
-    delete [] content;
+    aRetHandlerSet->AddHeader(new ObexHeader(headerId, contentLength, ptr));
 
     ptr += contentLength;
   }
 }
 
 END_BLUETOOTH_NAMESPACE
--- a/dom/bluetooth/ObexBase.h
+++ b/dom/bluetooth/ObexBase.h
@@ -99,17 +99,17 @@ enum ObexResponseCode {
   HttpVersionNotSupported = 0xD5,
 
   DatabaseFull = 0xE0,
   DatabaseLocked = 0xE1,
 };
 
 class ObexHeader {
 public:
-  ObexHeader(ObexHeaderId aId, int aDataLength, uint8_t* aData)
+  ObexHeader(ObexHeaderId aId, int aDataLength, const uint8_t* aData)
     : mId(aId)
     , mDataLength(aDataLength)
     , mData(nullptr)
   {
     mData = new uint8_t[mDataLength];
     memcpy(mData, aData, aDataLength);
   }
 
--- a/dom/browser-element/mochitest/browserElement_Auth.js
+++ b/dom/browser-element/mochitest/browserElement_Auth.js
@@ -35,56 +35,126 @@ function runTest() {
 function testHttpAuthCancel(e) {
   iframe.removeEventListener("mozbrowserusernameandpasswordrequired", testHttpAuthCancel);
   // Will cancel authentication, but prompt should not be shown again. Instead,
   // we will be led to fail message
   iframe.addEventListener("mozbrowserusernameandpasswordrequired", testFail);
   iframe.addEventListener("mozbrowsertitlechange", function onTitleChange(e) {
     iframe.removeEventListener("mozbrowsertitlechange", onTitleChange);
     iframe.removeEventListener("mozbrowserusernameandpasswordrequired", testFail);
-    is(e.detail, 'http auth failed');
+    is(e.detail, 'http auth failed', 'expected authentication to fail');
     iframe.addEventListener('mozbrowserusernameandpasswordrequired', testHttpAuth);
     SimpleTest.executeSoon(function() {
       // Use absolute path because we need to specify host.
       iframe.src = 'http://test/tests/dom/browser-element/mochitest/file_http_401_response.sjs';
     });
   });
 
-  is(e.detail.realm, 'http_realm');
-  is(e.detail.host, 'http://test');
+  is(e.detail.realm, 'http_realm', 'expected realm matches');
+  is(e.detail.host, 'http://test', 'expected host matches');
   e.preventDefault();
 
   SimpleTest.executeSoon(function() {
     e.detail.cancel();
   });
 }
 
 function testHttpAuth(e) {
   iframe.removeEventListener("mozbrowserusernameandpasswordrequired", testHttpAuth);
 
   // Will authenticate with correct password, prompt should not be
   // called again.
   iframe.addEventListener("mozbrowserusernameandpasswordrequired", testFail);
   iframe.addEventListener("mozbrowsertitlechange", function onTitleChange(e) {
     iframe.removeEventListener("mozbrowsertitlechange", onTitleChange);
     iframe.removeEventListener("mozbrowserusernameandpasswordrequired", testFail);
-    is(e.detail, 'http auth success');
-    SimpleTest.executeSoon(testFinish);
+    is(e.detail, 'http auth success', 'expect authentication to succeed');
+    SimpleTest.executeSoon(testAuthJarNoInterfere);
   });
 
-  is(e.detail.realm, 'http_realm');
-  is(e.detail.host, 'http://test');
+  is(e.detail.realm, 'http_realm', 'expected realm matches');
+  is(e.detail.host, 'http://test', 'expected host matches');
   e.preventDefault();
 
   SimpleTest.executeSoon(function() {
     e.detail.authenticate("httpuser", "httppass");
   });
 }
 
+function testAuthJarNoInterfere(e) {
+  var authMgr = SpecialPowers.Cc['@mozilla.org/network/http-auth-manager;1']
+    .getService(SpecialPowers.Ci.nsIHttpAuthManager);
+  var secMan = SpecialPowers.Cc["@mozilla.org/scriptsecuritymanager;1"]
+               .getService(SpecialPowers.Ci.nsIScriptSecurityManager);
+  var ioService = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
+                  .getService(SpecialPowers.Ci.nsIIOService);
+  var uri = ioService.newURI("http://test/tests/dom/browser-element/mochitest/file_http_401_response.sjs", null, null);
+
+  // Set a bunch of auth data that should not conflict with the correct auth data already
+  // stored in the cache.
+  var principal = secMan.getAppCodebasePrincipal(uri, 1, false);
+  authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm',
+                          'tests/dom/browser-element/mochitest/file_http_401_response.sjs',
+                          '', 'httpuser', 'wrongpass', false, principal);
+  principal = secMan.getAppCodebasePrincipal(uri, 1, true);
+  authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm',
+                          'tests/dom/browser-element/mochitest/file_http_401_response.sjs',
+                          '', 'httpuser', 'wrongpass', false, principal);
+  principal = secMan.getAppCodebasePrincipal(uri, secMan.NO_APP_ID, false);
+  authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm',
+                          'tests/dom/browser-element/mochitest/file_http_401_response.sjs',
+                          '', 'httpuser', 'wrongpass', false, principal);
+
+  // Will authenticate with correct password, prompt should not be
+  // called again.
+  iframe.addEventListener("mozbrowserusernameandpasswordrequired", testFail);
+  iframe.addEventListener("mozbrowsertitlechange", function onTitleChange(e) {
+    iframe.removeEventListener("mozbrowsertitlechange", onTitleChange);
+    iframe.removeEventListener("mozbrowserusernameandpasswordrequired", testFail);
+    is(e.detail, 'http auth success', 'expected authentication success');
+    SimpleTest.executeSoon(testAuthJarInterfere);
+  });
+
+  // Once more with feeling. Ensure that our new auth data doesn't interfere with this mozbrowser's
+  // auth data.
+  iframe.src = 'http://test/tests/dom/browser-element/mochitest/file_http_401_response.sjs';
+}
+
+function testAuthJarInterfere(e) {
+  var authMgr = SpecialPowers.Cc['@mozilla.org/network/http-auth-manager;1']
+    .getService(SpecialPowers.Ci.nsIHttpAuthManager);
+  var secMan = SpecialPowers.Cc["@mozilla.org/scriptsecuritymanager;1"]
+               .getService(SpecialPowers.Ci.nsIScriptSecurityManager);
+  var ioService = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
+                  .getService(SpecialPowers.Ci.nsIIOService);
+  var uri = ioService.newURI("http://test/tests/dom/browser-element/mochitest/file_http_401_response.sjs", null, null);
+
+  // Set some auth data that should overwrite the successful stored details.
+  var principal = secMan.getAppCodebasePrincipal(uri, secMan.NO_APP_ID, true);
+  authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm',
+                          'tests/dom/browser-element/mochitest/file_http_401_response.sjs',
+                          '', 'httpuser', 'wrongpass', false, principal);
+
+  // Will authenticate with correct password, prompt should not be
+  // called again.
+  iframe.addEventListener("mozbrowserusernameandpasswordrequired", testFinish);
+  iframe.addEventListener("mozbrowsertitlechange", function onTitleChange(e) {
+    iframe.removeEventListener("mozbrowsertitlechange", onTitleChange);
+    iframe.removeEventListener("mozbrowserusernameandpasswordrequired", testFinish);
+    SimpleTest.execute(testFail);
+  });
+
+  // Once more with feeling. Ensure that our new auth data interferes with this mozbrowser's
+  // auth data.
+  iframe.src = 'http://test/tests/dom/browser-element/mochitest/file_http_401_response.sjs';
+}
+
 function testFinish() {
+  iframe.removeEventListener("mozbrowserusernameandpasswordrequired", testFinish);
+
   // Clear login information stored in password manager.
   var authMgr = SpecialPowers.Cc['@mozilla.org/network/http-auth-manager;1']
     .getService(SpecialPowers.Ci.nsIHttpAuthManager);
   authMgr.clearAll();
 
   var pwmgr = SpecialPowers.Cc["@mozilla.org/login-manager;1"]
     .getService(SpecialPowers.Ci.nsILoginManager);
   pwmgr.removeAllLogins();
--- a/dom/encoding/Makefile.in
+++ b/dom/encoding/Makefile.in
@@ -19,17 +19,19 @@ FORCE_STATIC_LIB = 1
 DIRS = \
   test \
   $(NULL)
 
 EXPORTS_NAMESPACES = mozilla/dom
 EXPORTS_mozilla/dom = \
   EncodingUtils.h \
   TextDecoder.h \
+  TextDecoderBase.h \
   TextEncoder.h \
+  TextEncoderBase.h \
   $(NULL)
 
 CPPSRCS = \
 	EncodingUtils.cpp \
 	TextDecoder.cpp \
 	TextEncoder.cpp \
 	$(NULL)
 
--- a/dom/encoding/TextDecoder.cpp
+++ b/dom/encoding/TextDecoder.cpp
@@ -9,34 +9,33 @@
 #include "nsServiceManagerUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 static const PRUnichar kReplacementChar = static_cast<PRUnichar>(0xFFFD);
 
 void
-TextDecoder::Init(const nsAString& aEncoding,
-                  const TextDecoderOptions& aFatal,
-                  ErrorResult& aRv)
+TextDecoderBase::Init(const nsAString& aEncoding, const bool aFatal,
+                      ErrorResult& aRv)
 {
   nsAutoString label(aEncoding);
   EncodingUtils::TrimSpaceCharacters(label);
 
   // Let encoding be the result of getting an encoding from label.
   // If encoding is failure, throw a TypeError.
   if (!EncodingUtils::FindEncodingForLabel(label, mEncoding)) {
     aRv.ThrowTypeError(MSG_ENCODING_NOT_SUPPORTED, &label);
     return;
   }
 
   // If the constructor is called with an options argument,
   // and the fatal property of the dictionary is set,
   // set the internal fatal flag of the decoder object.
-  mFatal = aFatal.mFatal;
+  mFatal = aFatal;
 
   // Create a decoder object for mEncoding.
   nsCOMPtr<nsICharsetConverterManager> ccm =
     do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID);
   if (!ccm) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
@@ -48,20 +47,20 @@ TextDecoder::Init(const nsAString& aEnco
   }
 
   if (mFatal) {
     mDecoder->SetInputErrorBehavior(nsIUnicodeDecoder::kOnError_Signal);
   }
 }
 
 void
-TextDecoder::Decode(const ArrayBufferView* aView,
-                    const TextDecodeOptions& aOptions,
-                    nsAString& aOutDecodedString,
-                    ErrorResult& aRv)
+TextDecoderBase::Decode(const ArrayBufferView* aView,
+                        const bool aStream,
+                        nsAString& aOutDecodedString,
+                        ErrorResult& aRv)
 {
   const char* data;
   int32_t length;
   // If view is not specified, let view be a Uint8Array of length 0.
   if (!aView) {
     data = EmptyCString().BeginReading();
     length = EmptyCString().Length();
   } else {
@@ -89,17 +88,17 @@ TextDecoder::Decode(const ArrayBufferVie
 
   rv = mDecoder->Convert(data, &length, buf, &outLen);
   MOZ_ASSERT(mFatal || rv != NS_ERROR_ILLEGAL_INPUT);
   buf[outLen] = 0;
   aOutDecodedString.Append(buf, outLen);
 
   // If the internal streaming flag of the decoder object is not set,
   // then reset the encoding algorithm state to the default values
-  if (!aOptions.mStream) {
+  if (!aStream) {
     mDecoder->Reset();
     if (rv == NS_OK_UDEC_MOREINPUT) {
       if (mFatal) {
         aRv.Throw(NS_ERROR_DOM_ENCODING_DECODE_ERR);
       } else {
         // Need to emit a decode error manually
         // to simulate the EOF handling of the Encoding spec.
         aOutDecodedString.Append(kReplacementChar);
@@ -108,17 +107,17 @@ TextDecoder::Decode(const ArrayBufferVie
   }
 
   if (NS_FAILED(rv)) {
     aRv.Throw(NS_ERROR_DOM_ENCODING_DECODE_ERR);
   }
 }
 
 void
-TextDecoder::GetEncoding(nsAString& aEncoding)
+TextDecoderBase::GetEncoding(nsAString& aEncoding)
 {
   CopyASCIItoUTF16(mEncoding, aEncoding);
   nsContentUtils::ASCIIToLower(aEncoding);
 }
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(TextDecoder)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(TextDecoder)
 
--- a/dom/encoding/TextDecoder.h
+++ b/dom/encoding/TextDecoder.h
@@ -1,118 +1,74 @@
 /* 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 mozilla_dom_textdecoder_h_
 #define mozilla_dom_textdecoder_h_
 
-#include "jsapi.h"
-#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/TextDecoderBase.h"
 #include "mozilla/dom/TextDecoderBinding.h"
-#include "mozilla/dom/TypedArray.h"
-#include "mozilla/ErrorResult.h"
-#include "nsIUnicodeDecoder.h"
-#include "nsString.h"
-
-#include "nsCOMPtr.h"
-#include "nsCycleCollectionParticipant.h"
 
 namespace mozilla {
 namespace dom {
 
-class TextDecoder : public nsISupports, public nsWrapperCache
+class TextDecoder MOZ_FINAL
+  : public nsISupports, public nsWrapperCache, public TextDecoderBase
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TextDecoder)
 
   // The WebIDL constructor.
   static already_AddRefed<TextDecoder>
   Constructor(nsISupports* aGlobal,
               const nsAString& aEncoding,
-              const TextDecoderOptions& aFatal,
+              const TextDecoderOptions& aOptions,
               ErrorResult& aRv)
   {
     nsRefPtr<TextDecoder> txtDecoder = new TextDecoder(aGlobal);
-    txtDecoder->Init(aEncoding, aFatal, aRv);
+    txtDecoder->Init(aEncoding, aOptions.mFatal, aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
     return txtDecoder.forget();
   }
 
   TextDecoder(nsISupports* aGlobal)
-    : mGlobal(aGlobal), mFatal(false)
+    : mGlobal(aGlobal)
   {
     MOZ_ASSERT(aGlobal);
     SetIsDOMBinding();
   }
 
   virtual
   ~TextDecoder()
   {}
 
   virtual JSObject*
-  WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap)
+  WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap) MOZ_OVERRIDE
   {
     return TextDecoderBinding::Wrap(aCx, aScope, this, aTriedToWrap);
   }
 
   nsISupports*
   GetParentObject()
   {
     return mGlobal;
   }
 
-  /**
-   * Return the encoding name.
-   *
-   * @param aEncoding, current encoding.
-   */
-  void GetEncoding(nsAString& aEncoding);
-
-  /**
-   * Decodes incoming byte stream of characters in charset indicated by
-   * encoding.
-   *
-   * The encoding algorithm state is reset if aOptions.stream is not set.
-   *
-   * If the fatal flag is set then a decoding error will throw EncodingError.
-   * Else the decoder will return a decoded string with replacement
-   * character(s) for unidentified character(s).
-   *
-   * @param      aView, incoming byte stream of characters to be decoded to
-   *                    to UTF-16 code points.
-   * @param      aOptions, indicates if streaming or not.
-   * @param      aOutDecodedString, decoded string of UTF-16 code points.
-   * @param      aRv, error result.
-   */
   void Decode(const ArrayBufferView* aView,
               const TextDecodeOptions& aOptions,
               nsAString& aOutDecodedString,
-              ErrorResult& aRv);
+              ErrorResult& aRv) {
+    return TextDecoderBase::Decode(aView, aOptions.mStream,
+                                   aOutDecodedString, aRv);
+  }
 
 private:
-  nsCString mEncoding;
-  nsCOMPtr<nsIUnicodeDecoder> mDecoder;
   nsCOMPtr<nsISupports> mGlobal;
-  bool mFatal;
-
-  /**
-   * Validates provided encoding and throws an exception if invalid encoding.
-   * If no encoding is provided then mEncoding is default initialised to "utf-8".
-   *
-   * @param aEncoding    Optional encoding (case insensitive) provided.
-   *                     Default value is "utf-8" if no encoding is provided.
-   * @param aFatal       aFatal, indicates whether to throw an 'EncodingError'
-   *                     exception or not.
-   * @return aRv         EncodingError exception else null.
-   */
-  void Init(const nsAString& aEncoding,
-            const TextDecoderOptions& aFatal,
-            ErrorResult& aRv);
 };
 
 } // dom
 } // mozilla
 
 #endif // mozilla_dom_textdecoder_h_
copy from dom/encoding/TextDecoder.h
copy to dom/encoding/TextDecoderBase.h
--- a/dom/encoding/TextDecoder.h
+++ b/dom/encoding/TextDecoderBase.h
@@ -1,118 +1,76 @@
 /* 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 mozilla_dom_textdecoder_h_
-#define mozilla_dom_textdecoder_h_
+#ifndef mozilla_dom_textdecoderbase_h_
+#define mozilla_dom_textdecoderbase_h_
 
-#include "jsapi.h"
 #include "mozilla/dom/BindingUtils.h"
-#include "mozilla/dom/TextDecoderBinding.h"
 #include "mozilla/dom/TypedArray.h"
-#include "mozilla/ErrorResult.h"
 #include "nsIUnicodeDecoder.h"
-#include "nsString.h"
-
-#include "nsCOMPtr.h"
-#include "nsCycleCollectionParticipant.h"
 
 namespace mozilla {
+class ErrorResult;
+
 namespace dom {
 
-class TextDecoder : public nsISupports, public nsWrapperCache
+class TextDecoderBase
 {
-public:
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TextDecoder)
-
-  // The WebIDL constructor.
-  static already_AddRefed<TextDecoder>
-  Constructor(nsISupports* aGlobal,
-              const nsAString& aEncoding,
-              const TextDecoderOptions& aFatal,
-              ErrorResult& aRv)
-  {
-    nsRefPtr<TextDecoder> txtDecoder = new TextDecoder(aGlobal);
-    txtDecoder->Init(aEncoding, aFatal, aRv);
-    if (aRv.Failed()) {
-      return nullptr;
-    }
-    return txtDecoder.forget();
-  }
-
-  TextDecoder(nsISupports* aGlobal)
-    : mGlobal(aGlobal), mFatal(false)
-  {
-    MOZ_ASSERT(aGlobal);
-    SetIsDOMBinding();
-  }
+protected:
+  TextDecoderBase()
+    : mFatal(false)
+  {}
 
   virtual
-  ~TextDecoder()
+  ~TextDecoderBase()
   {}
 
-  virtual JSObject*
-  WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap)
-  {
-    return TextDecoderBinding::Wrap(aCx, aScope, this, aTriedToWrap);
-  }
+  /**
+   * Validates provided encoding and throws an exception if invalid encoding.
+   * If no encoding is provided then mEncoding is default initialised to "utf-8".
+   *
+   * @param aEncoding    Optional encoding (case insensitive) provided.
+   *                     Default value is "utf-8" if no encoding is provided.
+   * @param aFatal       aFatal, indicates whether to throw an 'EncodingError'
+   *                     exception or not.
+   * @return aRv         EncodingError exception else null.
+   */
+  void Init(const nsAString& aEncoding, const bool aFatal, ErrorResult& aRv);
 
-  nsISupports*
-  GetParentObject()
-  {
-    return mGlobal;
-  }
-
+public:
   /**
    * Return the encoding name.
    *
    * @param aEncoding, current encoding.
    */
   void GetEncoding(nsAString& aEncoding);
 
   /**
    * Decodes incoming byte stream of characters in charset indicated by
    * encoding.
    *
-   * The encoding algorithm state is reset if aOptions.stream is not set.
+   * The encoding algorithm state is reset if aOptions.mStream is not set.
    *
    * If the fatal flag is set then a decoding error will throw EncodingError.
    * Else the decoder will return a decoded string with replacement
    * character(s) for unidentified character(s).
    *
    * @param      aView, incoming byte stream of characters to be decoded to
    *                    to UTF-16 code points.
    * @param      aOptions, indicates if streaming or not.
    * @param      aOutDecodedString, decoded string of UTF-16 code points.
    * @param      aRv, error result.
    */
-  void Decode(const ArrayBufferView* aView,
-              const TextDecodeOptions& aOptions,
-              nsAString& aOutDecodedString,
-              ErrorResult& aRv);
+  void Decode(const ArrayBufferView* aView, const bool aStream,
+              nsAString& aOutDecodedString, ErrorResult& aRv);
 
 private:
   nsCString mEncoding;
   nsCOMPtr<nsIUnicodeDecoder> mDecoder;
-  nsCOMPtr<nsISupports> mGlobal;
   bool mFatal;
-
-  /**
-   * Validates provided encoding and throws an exception if invalid encoding.
-   * If no encoding is provided then mEncoding is default initialised to "utf-8".
-   *
-   * @param aEncoding    Optional encoding (case insensitive) provided.
-   *                     Default value is "utf-8" if no encoding is provided.
-   * @param aFatal       aFatal, indicates whether to throw an 'EncodingError'
-   *                     exception or not.
-   * @return aRv         EncodingError exception else null.
-   */
-  void Init(const nsAString& aEncoding,
-            const TextDecoderOptions& aFatal,
-            ErrorResult& aRv);
 };
 
 } // dom
 } // mozilla
 
-#endif // mozilla_dom_textdecoder_h_
+#endif // mozilla_dom_textdecoderbase_h_
--- a/dom/encoding/TextEncoder.cpp
+++ b/dom/encoding/TextEncoder.cpp
@@ -7,18 +7,17 @@
 #include "nsContentUtils.h"
 #include "nsICharsetConverterManager.h"
 #include "nsServiceManagerUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 void
-TextEncoder::Init(const nsAString& aEncoding,
-                  ErrorResult& aRv)
+TextEncoderBase::Init(const nsAString& aEncoding, ErrorResult& aRv)
 {
   nsAutoString label(aEncoding);
   EncodingUtils::TrimSpaceCharacters(label);
 
   // Let encoding be the result of getting an encoding from label.
   // If encoding is failure, or is none of utf-8, utf-16, and utf-16be,
   // throw a TypeError.
   if (!EncodingUtils::FindEncodingForLabel(label, mEncoding)) {
@@ -44,20 +43,20 @@ TextEncoder::Init(const nsAString& aEnco
   ccm->GetUnicodeEncoderRaw(mEncoding.get(), getter_AddRefs(mEncoder));
   if (!mEncoder) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
 }
 
 JSObject*
-TextEncoder::Encode(JSContext* aCx,
-                    const nsAString& aString,
-                    const TextEncodeOptions& aOptions,
-                    ErrorResult& aRv)
+TextEncoderBase::Encode(JSContext* aCx,
+                        const nsAString& aString,
+                        const bool aStream,
+                        ErrorResult& aRv)
 {
   // Run the steps of the encoding algorithm.
   int32_t srcLen = aString.Length();
   int32_t maxLen;
   const PRUnichar* data = PromiseFlatString(aString).get();
   nsresult rv = mEncoder->GetMaxLength(data, srcLen, &maxLen);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
@@ -72,43 +71,42 @@ TextEncoder::Encode(JSContext* aCx,
     return nullptr;
   }
 
   int32_t dstLen = maxLen;
   rv = mEncoder->Convert(data, &srcLen, buf, &dstLen);
 
   // If the internal streaming flag is not set, then reset
   // the encoding algorithm state to the default values for encoding.
-  if (!aOptions.mStream) {
+  if (!aStream) {
     int32_t finishLen = maxLen - dstLen;
     rv = mEncoder->Finish(buf + dstLen, &finishLen);
     if (NS_SUCCEEDED(rv)) {
       dstLen += finishLen;
     }
   }
 
   JSObject* outView = nullptr;
   if (NS_SUCCEEDED(rv)) {
     buf[dstLen] = '\0';
-    outView = Uint8Array::Create(aCx, this, dstLen,
-                                 reinterpret_cast<uint8_t*>(buf.get()));
+    outView = CreateUint8Array(aCx, buf, dstLen);
     if (!outView) {
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
       return nullptr;
     }
   }
 
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
   }
   return outView;
 }
 
 void
-TextEncoder::GetEncoding(nsAString& aEncoding)
+TextEncoderBase::GetEncoding(nsAString& aEncoding)
 {
   CopyASCIItoUTF16(mEncoding, aEncoding);
   nsContentUtils::ASCIIToLower(aEncoding);
 }
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(TextEncoder)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(TextEncoder)
 
--- a/dom/encoding/TextEncoder.h
+++ b/dom/encoding/TextEncoder.h
@@ -1,30 +1,23 @@
 /* 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 mozilla_dom_textencoder_h_
 #define mozilla_dom_textencoder_h_
 
-#include "jsapi.h"
-#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/TextEncoderBase.h"
 #include "mozilla/dom/TextEncoderBinding.h"
-#include "mozilla/dom/TypedArray.h"
-#include "mozilla/ErrorResult.h"
-#include "nsIUnicodeEncoder.h"
-#include "nsString.h"
-
-#include "nsCOMPtr.h"
-#include "nsCycleCollectionParticipant.h"
 
 namespace mozilla {
 namespace dom {
 
-class TextEncoder : public nsISupports, public nsWrapperCache
+class TextEncoder MOZ_FINAL
+  : public nsISupports, public nsWrapperCache, public TextEncoderBase
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TextEncoder)
 
   // The WebIDL constructor.
   static already_AddRefed<TextEncoder>
   Constructor(nsISupports* aGlobal,
@@ -46,63 +39,42 @@ public:
     SetIsDOMBinding();
   }
 
   virtual
   ~TextEncoder()
   {}
 
   virtual JSObject*
-  WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap)
+  WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap) MOZ_OVERRIDE
   {
     return TextEncoderBinding::Wrap(aCx, aScope, this, aTriedToWrap);
   }
 
   nsISupports*
   GetParentObject()
   {
     return mGlobal;
   }
 
-  /**
-   * Return the encoding name.
-   *
-   * @param aEncoding, current encoding.
-   */
-  void GetEncoding(nsAString& aEncoding);
-
-  /**
-   * Encodes incoming utf-16 code units/ DOM string to the requested encoding.
-   *
-   * @param aCx        Javascript context.
-   * @param aString    utf-16 code units to be encoded.
-   * @param aOptions   Streaming option. Initialised by default to false.
-   *                   If the streaming option is false, then the encoding
-   *                   algorithm state will get reset. If set to true then
-   *                   the previous encoding is reused/continued.
-   * @return JSObject* The Uint8Array wrapped in a JS object.
-   */
   JSObject* Encode(JSContext* aCx,
                    const nsAString& aString,
                    const TextEncodeOptions& aOptions,
-                   ErrorResult& aRv);
-private:
-  nsCString mEncoding;
-  nsCOMPtr<nsIUnicodeEncoder> mEncoder;
-  nsCOMPtr<nsISupports> mGlobal;
+                   ErrorResult& aRv) {
+    return TextEncoderBase::Encode(aCx, aString, aOptions.mStream, aRv);
+  }
 
-  /**
-   * Validates provided encoding and throws an exception if invalid encoding.
-   * If no encoding is provided then mEncoding is default initialised to "utf-8".
-   *
-   * @param aEncoding    Optional encoding (case insensitive) provided.
-   *                     (valid values are "utf-8", "utf-16", "utf-16be")
-   *                     Default value is "utf-8" if no encoding is provided.
-   * @return aRv         EncodingError exception else null.
-   */
-  void Init(const nsAString& aEncoding,
-            ErrorResult& aRv);
+protected:
+  virtual JSObject*
+  CreateUint8Array(JSContext* aCx, char* aBuf, uint32_t aLen) MOZ_OVERRIDE
+  {
+    return Uint8Array::Create(aCx, this, aLen,
+                              reinterpret_cast<uint8_t*>(aBuf));
+  }
+
+private:
+  nsCOMPtr<nsISupports> mGlobal;
 };
 
 } // dom
 } // mozilla
 
 #endif // mozilla_dom_textencoder_h_
copy from dom/encoding/TextEncoder.h
copy to dom/encoding/TextEncoderBase.h
--- a/dom/encoding/TextEncoder.h
+++ b/dom/encoding/TextEncoderBase.h
@@ -1,72 +1,46 @@
 /* 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 mozilla_dom_textencoder_h_
-#define mozilla_dom_textencoder_h_
+#ifndef mozilla_dom_textencoderbase_h_
+#define mozilla_dom_textencoderbase_h_
 
-#include "jsapi.h"
 #include "mozilla/dom/BindingUtils.h"
-#include "mozilla/dom/TextEncoderBinding.h"
 #include "mozilla/dom/TypedArray.h"
-#include "mozilla/ErrorResult.h"
 #include "nsIUnicodeEncoder.h"
-#include "nsString.h"
-
-#include "nsCOMPtr.h"
-#include "nsCycleCollectionParticipant.h"
 
 namespace mozilla {
+class ErrorResult;
+
 namespace dom {
 
-class TextEncoder : public nsISupports, public nsWrapperCache
+class TextEncoderBase
 {
-public:
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TextEncoder)
-
-  // The WebIDL constructor.
-  static already_AddRefed<TextEncoder>
-  Constructor(nsISupports* aGlobal,
-              const nsAString& aEncoding,
-              ErrorResult& aRv)
-  {
-    nsRefPtr<TextEncoder> txtEncoder = new TextEncoder(aGlobal);
-    txtEncoder->Init(aEncoding, aRv);
-    if (aRv.Failed()) {
-      return nullptr;
-    }
-    return txtEncoder.forget();
-  }
-
-  TextEncoder(nsISupports* aGlobal)
-    : mGlobal(aGlobal)
-  {
-    MOZ_ASSERT(aGlobal);
-    SetIsDOMBinding();
-  }
+protected:
+  TextEncoderBase()
+  {}
 
   virtual
-  ~TextEncoder()
+  ~TextEncoderBase()
   {}
 
-  virtual JSObject*
-  WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap)
-  {
-    return TextEncoderBinding::Wrap(aCx, aScope, this, aTriedToWrap);
-  }
+  /**
+   * Validates provided encoding and throws an exception if invalid encoding.
+   * If no encoding is provided then mEncoding is default initialised to "utf-8".
+   *
+   * @param aEncoding    Optional encoding (case insensitive) provided.
+   *                     (valid values are "utf-8", "utf-16", "utf-16be")
+   *                     Default value is "utf-8" if no encoding is provided.
+   * @return aRv         EncodingError exception else null.
+   */
+  void Init(const nsAString& aEncoding, ErrorResult& aRv);
 
-  nsISupports*
-  GetParentObject()
-  {
-    return mGlobal;
-  }
-
+public:
   /**
    * Return the encoding name.
    *
    * @param aEncoding, current encoding.
    */
   void GetEncoding(nsAString& aEncoding);
 
   /**
@@ -75,34 +49,24 @@ public:
    * @param aCx        Javascript context.
    * @param aString    utf-16 code units to be encoded.
    * @param aOptions   Streaming option. Initialised by default to false.
    *                   If the streaming option is false, then the encoding
    *                   algorithm state will get reset. If set to true then
    *                   the previous encoding is reused/continued.
    * @return JSObject* The Uint8Array wrapped in a JS object.
    */
-  JSObject* Encode(JSContext* aCx,
-                   const nsAString& aString,
-                   const TextEncodeOptions& aOptions,
-                   ErrorResult& aRv);
+  JSObject* Encode(JSContext* aCx, const nsAString& aString,
+                   const bool aStream, ErrorResult& aRv);
+
+protected:
+  virtual JSObject*
+  CreateUint8Array(JSContext* aCx, char* aBuf, uint32_t aLen) = 0;
+
 private:
   nsCString mEncoding;
   nsCOMPtr<nsIUnicodeEncoder> mEncoder;
-  nsCOMPtr<nsISupports> mGlobal;
-
-  /**
-   * Validates provided encoding and throws an exception if invalid encoding.
-   * If no encoding is provided then mEncoding is default initialised to "utf-8".
-   *
-   * @param aEncoding    Optional encoding (case insensitive) provided.
-   *                     (valid values are "utf-8", "utf-16", "utf-16be")
-   *                     Default value is "utf-8" if no encoding is provided.
-   * @return aRv         EncodingError exception else null.
-   */
-  void Init(const nsAString& aEncoding,
-            ErrorResult& aRv);
 };
 
 } // dom
 } // mozilla
 
-#endif // mozilla_dom_textencoder_h_
+#endif // mozilla_dom_textencoderbase_h_
--- a/dom/encoding/test/Makefile.in
+++ b/dom/encoding/test/Makefile.in
@@ -25,16 +25,17 @@ MOCHITEST_FILES = \
   test_BOMEncoding.js \
   test_TextDecoder.html \
   test_TextDecoder.js \
   test_TextEncoder.html \
   test_TextEncoder.js \
   test_stringencoding.html \
   test_submit_euckr.html \
   test_utf16_files.html \
+  worker_helper.js \
   $(NULL)
 
 MOCHITEST_CHROME_FILES = \
   file_stringencoding.jsm \
   test_stringencoding.xul \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/dom/encoding/test/test_TextDecoder.html
+++ b/dom/encoding/test/test_TextDecoder.html
@@ -1,25 +1,29 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset=utf-8>
-  <title>Test for Bug 764234</title>
+  <title>Test for TextDecoder</title>
   <script type="text/javascript" src="/resources/testharness.js"></script>
   <script type="text/javascript" src="/resources/testharnessreport.js"></script>
   <script type="text/javascript" src="test_TextDecoder.js"></script>
   <script type="text/javascript" src="test_BOMEncoding.js"></script>
+  <script type="text/javascript" src="worker_helper.js"></script>
 </head>
 <body>
 <div id="log"></div>
 <script>
 
+setup({explicit_done: true});
 runTest();
 
 function runTest()
 {
   runTextDecoderOptions();
   runTextDecoderBOMEnoding();
 }
 
+runTestInWorker(["test_TextDecoder.js", "test_BOMEncoding.js"]);
+
 </script>
 </body>
 </html>
--- a/dom/encoding/test/test_TextEncoder.html
+++ b/dom/encoding/test/test_TextEncoder.html
@@ -1,23 +1,27 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset=utf-8>
-  <title>Test for Bug 764234</title>
+  <title>Test for TextEncoder</title>
   <script type="text/javascript" src="/resources/testharness.js"></script>
   <script type="text/javascript" src="/resources/testharnessreport.js"></script>
   <script type="text/javascript" src="test_TextEncoder.js"></script>
+  <script type="text/javascript" src="worker_helper.js"></script>
 </head>
 <body>
 <div id="log"></div>
 <script>
 
+setup({explicit_done: true});
 runTest();
 
 function runTest()
 {
   runTextEncoderTests();
 }
 
+runTestInWorker(["test_TextEncoder.js"]);
+
 </script>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/dom/encoding/test/worker_helper.js
@@ -0,0 +1,48 @@
+/*
+ * worker_helper.js
+ * bug 764234 tests
+*/
+function runTestInWorker(files) {
+  function workerRun() {
+    var tests = [];
+    var asserts;
+    test = function(func, msg) {
+      asserts = [];
+      tests.push({asserts: asserts, msg: msg});
+    }
+    assert_equals = function(result, expected, msg) {
+      asserts.push(["assert_equals", result, expected, msg]);
+    };
+    assert_true = function(condition, msg) {
+      asserts.push(["assert_true", condition, msg]);
+    };
+    assert_unreached = function(condition, msg) {
+      asserts.push(["assert_unreached", condition, msg]);
+    };
+    onmessage = function(event) {
+      importScripts.apply(self, event.data);
+      runTest();
+      postMessage(tests);
+    };
+  }
+
+  var url = URL.createObjectURL(new Blob([
+    runTest.toString(), "\n\n",
+    "(", workerRun.toString(), ")();"
+  ]));
+  var worker = new Worker(url);
+  var base = location.toString().replace(/\/[^\/]*$/,"/");
+  worker.postMessage(files.map(function(f) { return base + f; }));
+  worker.onmessage = function(event) {
+    URL.revokeObjectURL(url);
+    event.data.forEach(function(t) {
+      test(function() {
+        t.asserts.forEach(function(a) {
+          func = a.shift();
+          self[func].apply(self, a);
+        });
+      }, "worker " + t.msg);
+    });
+    done();
+  };
+}
--- a/dom/imptests/failures/webapps/DOMCore/tests/approved/test_interfaces.html.json
+++ b/dom/imptests/failures/webapps/DOMCore/tests/approved/test_interfaces.html.json
@@ -134,27 +134,24 @@
   "DocumentType interface: attribute publicId": true,
   "DocumentType interface: attribute systemId": true,
   "DocumentType interface: operation remove()": true,
   "Stringification of document.doctype": "debug",
   "DocumentType interface: document.doctype must inherit property \"remove\" with the proper type (3)": true,
   "EventTarget interface: calling addEventListener(DOMString,EventListener,boolean) on document.doctype with too few arguments must throw TypeError": true,
   "EventTarget interface: calling removeEventListener(DOMString,EventListener,boolean) on document.doctype with too few arguments must throw TypeError": true,
   "EventTarget interface: calling dispatchEvent(Event) on document.doctype with too few arguments must throw TypeError": true,
-  "Element interface: existence and properties of interface object": true,
-  "Element interface: existence and properties of interface prototype object": true,
-  "Element interface: existence and properties of interface prototype object's \"constructor\" property": true,
+  "Element interface: attribute namespaceURI": true,
+  "Element interface: attribute prefix": true,
+  "Element interface: attribute localName": true,
+  "Element interface: attribute attributes": true,
   "Element interface: attribute className": true,
   "Element interface: operation remove()": true,
-  "Stringification of element": "debug",
   "Element interface: element must inherit property \"className\" with the proper type (5)": true,
   "Element interface: element must inherit property \"remove\" with the proper type (25)": true,
-  "EventTarget interface: calling addEventListener(DOMString,EventListener,boolean) on element with too few arguments must throw TypeError": true,
-  "EventTarget interface: calling removeEventListener(DOMString,EventListener,boolean) on element with too few arguments must throw TypeError": true,
-  "EventTarget interface: calling dispatchEvent(Event) on element with too few arguments must throw TypeError": true,
   "Attr interface: existence and properties of interface object": true,
   "Attr interface: existence and properties of interface prototype object": true,
   "Attr interface: existence and properties of interface prototype object's \"constructor\" property": true,
   "Attr interface: attribute name": true,
   "Attr interface: attribute value": true,
   "Stringification of document.querySelector(\"[id]\").attributes[0]": "debug",
   "CharacterData interface: existence and properties of interface object": true,
   "CharacterData interface: existence and properties of interface prototype object": true,
--- a/dom/interfaces/base/Makefile.in
+++ b/dom/interfaces/base/Makefile.in
@@ -22,16 +22,17 @@ SDK_XPIDLSRCS =                         
 	nsIDOMWindowUtils.idl			\
 	$(NULL)
 
 XPIDLSRCS =					\
 	nsIFrameRequestCallback.idl             \
 	nsIBrowserDOMWindow.idl			\
 	nsIContentPermissionPrompt.idl  \
 	nsIContentPrefService.idl		\
+	nsIContentPrefService2.idl		\
 	nsIContentURIGrouper.idl		\
 	nsIDOMClientInformation.idl		\
 	nsIDOMConstructor.idl			\
 	nsIDOMCRMFObject.idl			\
 	nsIDOMCrypto.idl			\
 	nsIDOMHistory.idl			\
 	nsIDOMLocation.idl			\
 	nsIDOMMediaQueryList.idl		\
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/base/nsIContentPrefService2.idl
@@ -0,0 +1,365 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+interface nsIVariant;
+interface nsIContentPrefObserver;
+interface nsIContentPrefCallback2;
+interface nsILoadContext;
+interface nsIContentPref;
+
+/**
+ * Content Preferences
+ *
+ * Content preferences allow the application to associate arbitrary data, or
+ * "preferences", with specific domains, or web "content".  Specifically, a
+ * content preference is a structure with three values: a domain with which the
+ * preference is associated, a name that identifies the preference within its
+ * domain, and a value.  (See nsIContentPref below.)
+ *
+ * For example, if you want to remember the user's preference for a certain zoom
+ * level on www.mozilla.org pages, you might store a preference whose domain is
+ * "www.mozilla.org", whose name is "zoomLevel", and whose value is the numeric
+ * zoom level.
+ *
+ * A preference need not have a domain, and in that case the preference is
+ * called a "global" preference.  This interface doesn't impart any special
+ * significance to global preferences; they're simply name-value pairs that
+ * aren't associated with any particular domain.  As a consumer of this
+ * interface, you might choose to let a global preference override all non-
+ * global preferences of the same name, for example, for whatever definition of
+ * "override" is appropriate for your use case.
+ *
+ *
+ * Domain Parameters
+ *
+ * Many methods of this interface accept a "domain" parameter.  Domains may be
+ * specified either exactly, like "example.com", or as full URLs, like
+ * "http://example.com/foo/bar".  In the latter case the API extracts the full
+ * domain from the URL, so if you specify "http://foo.bar.example.com/baz", the
+ * domain is taken to be "foo.bar.example.com", not "example.com".
+ *
+ *
+ * Private-Browsing Context Parameters
+ *
+ * Many methods also accept a "context" parameter.  This parameter relates to
+ * private browsing and determines the kind of storage that a method uses,
+ * either the usual permanent storage or temporary storage set aside for private
+ * browsing sessions.
+ *
+ * Pass null to unconditionally use permanent storage.  Pass an nsILoadContext
+ * to use storage appropriate to the context's usePrivateBrowsing attribute: if
+ * usePrivateBrowsing is true, temporary private-browsing storage is used, and
+ * otherwise permanent storage is used.  A context can be obtained from the
+ * window or channel whose content pertains to the preferences being modified or
+ * retrieved.
+ *
+ *
+ * Callbacks
+ *
+ * The methods of callback objects are always called asynchronously.  See
+ * nsIContentPrefCallback2 below for more information about callbacks.
+ */
+
+[scriptable, uuid(51e1d34a-5e9d-4b77-b14c-0f8346e264ca)]
+interface nsIContentPrefService2 : nsISupports
+{
+  /**
+   * Gets the preference with the given domain and name.
+   *
+   * @param domain    The preference's domain.
+   * @param name      The preference's name.
+   * @param context   The private-browsing context, if any.
+   * @param callback  handleResult is called once unless no such preference
+   *                  exists, in which case handleResult is not called at all.
+   */
+  void getByDomainAndName(in AString domain,
+                          in AString name,
+                          in nsILoadContext context,
+                          in nsIContentPrefCallback2 callback);
+
+  /**
+   * Gets all preferences with the given name whose domains are either the same
+   * as or subdomains of the given domain.
+   *
+   * @param domain    The preferences' domain.
+   * @param name      The preferences' name.
+   * @param context   The private-browsing context, if any.
+   * @param callback  handleResult is called once for each preference.  If no
+   *                  such preferences exist, handleResult is not called at all.
+   */
+  void getBySubdomainAndName(in AString domain,
+                             in AString name,
+                             in nsILoadContext context,
+                             in nsIContentPrefCallback2 callback);
+
+  /**
+   * Gets the preference with no domain and the given name.
+   *
+   * @param name      The preference's name.
+   * @param context   The private-browsing context, if any.
+   * @param callback  handleResult is called once unless no such preference
+   *                  exists, in which case handleResult is not called at all.
+   */
+  void getGlobal(in AString name,
+                 in nsILoadContext context,
+                 in nsIContentPrefCallback2 callback);
+
+  /**
+   * Synchronously retrieves from the in-memory cache the preference with the
+   * given domain and name.
+   *
+   * In addition to caching preference values, the cache also keeps track of
+   * preferences that are known not to exist.  If the preference is known not to
+   * exist, the value attribute of the returned object will be undefined
+   * (nsIDataType::VTYPE_VOID).
+   *
+   * If the preference is neither cached nor known not to exist, then null is
+   * returned, and get() must be called to determine whether the preference
+   * exists.
+   *
+   * @param domain   The preference's domain.
+   * @param name     The preference's name.
+   * @param context  The private-browsing context, if any.
+   * @return         The preference, or null if no such preference is known to
+   *                 exist.
+   */
+  nsIContentPref getCachedByDomainAndName(in AString domain,
+                                          in AString name,
+                                          in nsILoadContext context);
+
+  /**
+   * Synchronously retrieves from the in-memory cache all preferences with the
+   * given name whose domains are either the same as or subdomains of the given
+   * domain.
+   *
+   * The preferences are returned in an array through the out-parameter.  If a
+   * preference for a particular subdomain is known not to exist, then an object
+   * corresponding to that preference will be present in the array, and, as with
+   * getCachedByDomainAndName, its value attribute will be undefined.
+   *
+   * @param domain   The preferences' domain.
+   * @param name     The preferences' name.
+   * @param context  The private-browsing context, if any.
+   * @param len      The length of the returned array.
+   * @param prefs    The array of preferences.
+   */
+  void getCachedBySubdomainAndName(in AString domain,
+                                   in AString name,
+                                   in nsILoadContext context,
+                                   out unsigned long len,
+                                   [retval,array,size_is(len)] out nsIContentPref prefs);
+
+  /**
+   * Synchronously retrieves from the in-memory cache the preference with no
+   * domain and the given name.
+   *
+   * As with getCachedByDomainAndName, if the preference is cached then it is
+   * returned; if the preference is known not to exist, then the value attribute
+   * of the returned object will be undefined; if the preference is neither
+   * cached nor known not to exist, then null is returned.
+   *
+   * @param name     The preference's name.
+   * @param context  The private-browsing context, if any.
+   * @return         The preference, or null if no such preference is known to
+   *                 exist.
+   */
+  nsIContentPref getCachedGlobal(in AString name,
+                                 in nsILoadContext context);
+
+  /**
+   * Sets a preference.
+   *
+   * @param domain    The preference's domain.
+   * @param name      The preference's name.
+   * @param value     The preference's value.
+   * @param context   The private-browsing context, if any.
+   * @param callback  handleCompletion is called when the preference has been
+   *                  stored.
+   */
+  void set(in AString domain,
+           in AString name,
+           in nsIVariant value,
+           in nsILoadContext context,
+           [optional] in nsIContentPrefCallback2 callback);
+
+  /**
+   * Sets a preference with no domain.
+   *
+   * @param name      The preference's name.
+   * @param value     The preference's value.
+   * @param context   The private-browsing context, if any.
+   * @param callback  handleCompletion is called when the preference has been
+   *                  stored.
+   */
+  void setGlobal(in AString name,
+                 in nsIVariant value,
+                 in nsILoadContext context,
+                 [optional] in nsIContentPrefCallback2 callback);
+
+  /**
+   * Removes the preference with the given domain and name.
+   *
+   * @param domain    The preference's domain.
+   * @param name      The preference's name.
+   * @param context   The private-browsing context, if any.
+   * @param callback  handleCompletion is called when the operation completes.
+   */
+  void removeByDomainAndName(in AString domain,
+                             in AString name,
+                             in nsILoadContext context,
+                             [optional] in nsIContentPrefCallback2 callback);
+
+  /**
+   * Removes all the preferences with the given name whose domains are either
+   * the same as or subdomains of the given domain.
+   *
+   * @param domain    The preferences' domain.
+   * @param name      The preferences' name.
+   * @param context   The private-browsing context, if any.
+   * @param callback  handleCompletion is called when the operation completes.
+   */
+  void removeBySubdomainAndName(in AString domain,
+                                in AString name,
+                                in nsILoadContext context,
+                                [optional] in nsIContentPrefCallback2 callback);
+
+  /**
+   * Removes the preference with no domain and the given name.
+   *
+   * @param name      The preference's name.
+   * @param context   The private-browsing context, if any.
+   * @param callback  handleCompletion is called when the operation completes.
+   */
+  void removeGlobal(in AString name,
+                    in nsILoadContext context,
+                    [optional] in nsIContentPrefCallback2 callback);
+
+  /**
+   * Removes all preferences with the given domain.
+   *
+   * @param domain    The preferences' domain.
+   * @param context   The private-browsing context, if any.
+   * @param callback  handleCompletion is called when the operation completes.
+   */
+  void removeByDomain(in AString domain,
+                      in nsILoadContext context,
+                      [optional] in nsIContentPrefCallback2 callback);
+
+  /**
+   * Removes all preferences whose domains are either the same as or subdomains
+   * of the given domain.
+   *
+   * @param domain    The preferences' domain.
+   * @param context   The private-browsing context, if any.
+   * @param callback  handleCompletion is called when the operation completes.
+   */
+  void removeBySubdomain(in AString domain,
+                         in nsILoadContext context,
+                         [optional] in nsIContentPrefCallback2 callback);
+
+  /**
+   * Removes all preferences with the given name regardless of domain, including
+   * global preferences with the given name.
+   *
+   * @param name      The preferences' name.
+   * @param context   The private-browsing context, if any.
+   * @param callback  handleCompletion is called when the operation completes.
+   */
+  void removeByName(in AString name,
+                    in nsILoadContext context,
+                    [optional] in nsIContentPrefCallback2 callback);
+
+  /**
+   * Removes all non-global preferences -- in other words, all preferences that
+   * have a domain.
+   *
+   * @param context   The private-browsing context, if any.
+   * @param callback  handleCompletion is called when the operation completes.
+   */
+  void removeAllDomains(in nsILoadContext context,
+                        [optional] in nsIContentPrefCallback2 callback);
+
+  /**
+   * Removes all global preferences -- in other words, all preferences that have
+   * no domain.
+   *
+   * @param context   The private-browsing context, if any.
+   * @param callback  handleCompletion is called when the operation completes.
+   */
+  void removeAllGlobals(in nsILoadContext context,
+                        [optional] in nsIContentPrefCallback2 callback);
+
+  /**
+   * Registers an observer that will be notified whenever a preference with the
+   * given name is set or removed.
+   *
+   * When a set or remove method is called, observers are notified after the set
+   * or removal completes but before method's callback is called.
+   *
+   * The service holds a strong reference to the observer, so the observer must
+   * be removed later to avoid leaking it.
+   *
+   * @param name      The name of the preferences to observe.  Pass null to
+   *                  observe all preference changes regardless of name.
+   * @param observer  The observer.
+   */
+  void addObserverForName(in AString name,
+                          in nsIContentPrefObserver observer);
+
+  /**
+   * Unregisters an observer for the given name.
+   *
+   * @param name      The name for which the observer was registered.  Pass null
+   *                  if the observer was added with a null name.
+   * @param observer  The observer.
+   */
+  void removeObserverForName(in AString name,
+                             in nsIContentPrefObserver observer);
+};
+
+/**
+ * The callback used by the above methods.
+ */
+[scriptable, uuid(1a12cf41-79e8-4d0f-9899-2f7b27c5d9a1)]
+interface nsIContentPrefCallback2 : nsISupports
+{
+  /**
+   * For the retrieval methods, this is called once for each retrieved
+   * preference.  It is not called for other methods.
+   *
+   * @param pref  The retrieved preference.
+   */
+  void handleResult(in nsIContentPref pref);
+
+  /**
+   * Called when an error occurs.  This may be called multiple times before
+   * onComplete is called.
+   *
+   * @param error  A number in Components.results describing the error.
+   */
+  void handleError(in nsresult error);
+
+  /**
+   * Called when the method finishes.  This will be called exactly once for
+   * each method invocation, and afterward no other callback methods will be
+   * called.
+   *
+   * @param reason  One of the COMPLETE_* values indicating the manner in which
+   *                the method completed.
+   */
+  void handleCompletion(in unsigned short reason);
+
+  const unsigned short COMPLETE_OK = 0;
+  const unsigned short COMPLETE_ERROR = 1;
+};
+
+[scriptable, function, uuid(9f24948d-24b5-4b1b-b554-7dbd58c1d792)]
+interface nsIContentPref : nsISupports
+{
+  readonly attribute AString domain;
+  readonly attribute AString name;
+  readonly attribute nsIVariant value;
+};
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1805,16 +1805,19 @@ ContentParent::AfterProcessNextEvent(nsI
     return NS_OK;
 }
 
 bool
 ContentParent::RecvShowAlertNotification(const nsString& aImageUrl, const nsString& aTitle,
                                          const nsString& aText, const bool& aTextClickable,
                                          const nsString& aCookie, const nsString& aName)
 {
+    if (!AssertAppProcessPermission(this, "desktop-notification")) {
+        return false;
+    }
     nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_ALERTSERVICE_CONTRACTID));
     if (sysAlerts) {
         sysAlerts->ShowAlertNotification(aImageUrl, aTitle, aText, aTextClickable,
                                          aCookie, this, aName);
     }
 
     return true;
 }
--- a/dom/ipc/Makefile.in
+++ b/dom/ipc/Makefile.in
@@ -89,16 +89,17 @@ LOCAL_INCLUDES += \
 	-I$(topsrcdir)/dom/base \
 	-I$(topsrcdir)/toolkit/xre \
 	-I$(topsrcdir)/hal/sandbox \
 	-I$(topsrcdir)/dom/sms/src/ipc \
 	-I$(topsrcdir)/dom/devicestorage \
 	-I$(topsrcdir)/widget/xpwidgets \
 	-I$(topsrcdir)/dom/bluetooth \
 	-I$(topsrcdir)/dom/bluetooth/ipc \
+        -I$(topsrcdir)/hal \
 	$(NULL)
 
 DEFINES += -DBIN_SUFFIX='"$(BIN_SUFFIX)"'
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),$(findstring $(MOZ_WIDGET_TOOLKIT),android gtk2 gonk qt))
 DEFINES += -DMOZ_ENABLE_FREETYPE
 endif
 
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -15,16 +15,17 @@ include protocol POfflineCacheUpdate;
 include protocol PIndexedDB;
 include DOMTypes;
 include URIParams;
 
 include "gfxMatrix.h";
 include "FrameMetrics.h";
 include "IPC/nsGUIEventIPC.h";
 include "mozilla/dom/TabMessageUtils.h";
+include "mozilla/dom/ScreenOrientation.h";
 include "mozilla/dom/PermissionMessageUtils.h";
 include "mozilla/layout/RenderFrameUtils.h";
 
 using IPC::Principal;
 using gfxMatrix;
 using gfxRect;
 using gfxSize;
 using mozilla::layers::LayersBackend;
@@ -42,16 +43,17 @@ using nsMouseEvent;
 using nsMouseScrollEvent;
 using mozilla::widget::WheelEvent;
 using nsQueryContentEvent;
 using nsRect;
 using nsSelectionEvent;
 using nsTextEvent;
 using nsTouchEvent;
 using RemoteDOMEvent;
+using mozilla::dom::ScreenOrientation;
 
 namespace mozilla {
 namespace dom {
 
 rpc protocol PBrowser
 {
     manager PContent;
 
@@ -286,17 +288,17 @@ child:
      * |Show()| and |Move()| take IntSizes rather than Rects because
      * content processes always render to a virtual <0, 0> top-left
      * point.
      */
     Show(nsIntSize size);
 
     LoadURL(nsCString uri);
 
-    UpdateDimensions(nsRect rect, nsIntSize size) compress;
+    UpdateDimensions(nsRect rect, nsIntSize size, ScreenOrientation orientation) compress;
 
     UpdateFrame(FrameMetrics frame) compress;
 
     /**
      * Requests handling of a double tap. |point| is in CSS pixels, relative to
      * the scroll offset. This message is expected to round-trip back to
      * ZoomToRect() with a rect indicating where we should zoom to.
      */
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -163,16 +163,17 @@ TabChild::TabChild(const TabContext& aCo
   , mOuterRect(0, 0, 0, 0)
   , mInnerSize(0, 0)
   , mOldViewportWidth(0.0f)
   , mLastBackgroundColor(NS_RGB(255, 255, 255))
   , mDidFakeShow(false)
   , mNotified(false)
   , mContentDocumentIsDisplayed(false)
   , mTriedBrowserInit(false)
+  , mOrientation(eScreenOrientation_PortraitPrimary)
 {
     printf("creating %d!\n", NS_IsMainThread());
 }
 
 NS_IMETHODIMP
 TabChild::HandleEvent(nsIDOMEvent* aEvent)
 {
   nsAutoString eventType;
@@ -1114,27 +1115,28 @@ TabChild::RecvShow(const nsIntSize& size
     }
 
     baseWindow->SetVisibility(true);
 
     return InitTabChildGlobal();
 }
 
 bool
-TabChild::RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size)
+TabChild::RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size, const ScreenOrientation& orientation)
 {
     if (!mRemoteFrame) {
         return true;
     }
 
     mOuterRect.x = rect.x;
     mOuterRect.y = rect.y;
     mOuterRect.width = rect.width;
     mOuterRect.height = rect.height;
 
+    mOrientation = orientation;
     mInnerSize = size;
     mWidget->Resize(0, 0, size.width, size.height,
                     true);
 
     nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mWebNav);
     baseWin->SetPositionAndSize(0, 0, size.width, size.height,
                                 true);
 
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -192,17 +192,17 @@ public:
     virtual bool DoSendSyncMessage(const nsAString& aMessage,
                                    const mozilla::dom::StructuredCloneData& aData,
                                    InfallibleTArray<nsString>* aJSONRetVal);
     virtual bool DoSendAsyncMessage(const nsAString& aMessage,
                                     const mozilla::dom::StructuredCloneData& aData);
 
     virtual bool RecvLoadURL(const nsCString& uri);
     virtual bool RecvShow(const nsIntSize& size);
-    virtual bool RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size);
+    virtual bool RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size, const ScreenOrientation& orientation);
     virtual bool RecvUpdateFrame(const mozilla::layers::FrameMetrics& aFrameMetrics);
     virtual bool RecvHandleDoubleTap(const nsIntPoint& aPoint);
     virtual bool RecvHandleSingleTap(const nsIntPoint& aPoint);
     virtual bool RecvHandleLongTap(const nsIntPoint& aPoint);
     virtual bool RecvActivate();
     virtual bool RecvDeactivate();
     virtual bool RecvMouseEvent(const nsString& aType,
                                 const float&    aX,
@@ -288,16 +288,18 @@ public:
 
     nsIPrincipal* GetPrincipal() { return mPrincipal; }
 
     /** Return the DPI of the widget this TabChild draws to. */
     void GetDPI(float* aDPI);
 
     gfxSize GetZoom() { return mLastMetrics.mZoom; }
 
+    ScreenOrientation GetOrientation() { return mOrientation; }
+
     void SetBackgroundColor(const nscolor& aColor);
 
     void NotifyPainted();
 
     bool IsAsyncPanZoomEnabled();
 
     /**
      * Signal to this TabChild that it should be made visible:
@@ -414,16 +416,17 @@ private:
     float mOldViewportWidth;
     nscolor mLastBackgroundColor;
     ScrollingBehavior mScrolling;
     bool mDidFakeShow;
     bool mNotified;
     bool mContentDocumentIsDisplayed;
     bool mTriedBrowserInit;
     nsString mAppType;
+    ScreenOrientation mOrientation;
 
     DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 inline TabChild*
 GetTabChildFrom(nsIDocShell* aDocShell)
 {
     nsCOMPtr<nsITabChild> tc = do_GetInterface(aDocShell);
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -46,16 +46,17 @@
 #include "nsNetUtil.h"
 #include "nsPIDOMWindow.h"
 #include "nsPrintfCString.h"
 #include "nsSerializationHelper.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "StructuredCloneUtils.h"
 #include "TabChild.h"
+#include "Hal.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::layout;
 using namespace mozilla::services;
 using namespace mozilla::widget;
 using namespace mozilla::dom::indexedDB;
@@ -251,17 +252,20 @@ TabParent::Show(const nsIntSize& size)
 }
 
 void
 TabParent::UpdateDimensions(const nsRect& rect, const nsIntSize& size)
 {
   if (mIsDestroyed) {
     return;
   }
-  unused << SendUpdateDimensions(rect, size);
+  hal::ScreenConfiguration config;
+  hal::GetCurrentScreenConfiguration(&config);
+
+  unused << SendUpdateDimensions(rect, size, config.orientation());
   if (RenderFrameParent* rfp = GetRenderFrame()) {
     rfp->NotifyDimensionsChanged(size.width, size.height);
   }
   mDimensions = size;
 }
 
 void
 TabParent::UpdateFrame(const FrameMetrics& aFrameMetrics)
@@ -426,24 +430,24 @@ bool TabParent::SendRealTouchEvent(nsTou
                (sEventCapturer == this && mEventCaptureDepth > 0));
     // We want to capture all remaining touch events in this series
     // for fast-path dispatch.
     sEventCapturer = this;
     ++mEventCaptureDepth;
   }
 
   nsTouchEvent e(event);
-  // PresShell::HandleEventInternal adds touches on touch end/cancel,
-  // when we're not capturing raw events from the widget backend.
-  // This hack filters those out. Bug 785554
-  if (sEventCapturer != this &&
-      (event.message == NS_TOUCH_END || event.message == NS_TOUCH_CANCEL)) {
+  // PresShell::HandleEventInternal adds touches on touch end/cancel.
+  // This confuses remote content into thinking that the added touches
+  // are part of the touchend/cancel, when actually they're not.
+  if (event.message == NS_TOUCH_END || event.message == NS_TOUCH_CANCEL) {
     for (int i = e.touches.Length() - 1; i >= 0; i--) {
-      if (!e.touches[i]->mChanged)
+      if (!e.touches[i]->mChanged) {
         e.touches.RemoveElementAt(i);
+      }
     }
   }
 
   MaybeForwardEventToRenderFrame(event, &e);
   return (e.message == NS_TOUCH_MOVE) ?
     PBrowserParent::SendRealTouchMoveEvent(e) :
     PBrowserParent::SendRealTouchEvent(e);
 }
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -257,50 +257,41 @@ public:
     StreamListeners* listeners = MediaManager::Get()->GetWindowListeners(mWindowID);
     if (!listeners) {
       // This window is no longer live.
       return NS_OK;
     }
 
     // Create a media stream.
     nsRefPtr<nsDOMLocalMediaStream> stream;
-    nsRefPtr<nsDOMLocalMediaStream> trackunion;
     uint32_t hints = (mAudioSource ? nsDOMMediaStream::HINT_CONTENTS_AUDIO : 0);
     hints |= (mVideoSource ? nsDOMMediaStream::HINT_CONTENTS_VIDEO : 0);
 
-    stream     = nsDOMLocalMediaStream::CreateSourceStream(hints);
-    trackunion = nsDOMLocalMediaStream::CreateTrackUnionStream(hints);
-    if (!stream || !trackunion) {
+    stream = nsDOMLocalMediaStream::CreateSourceStream(hints);
+    if (!stream) {
       nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
       LOG(("Returning error for getUserMedia() - no stream"));
       error->OnError(NS_LITERAL_STRING("NO_STREAM"));
       return NS_OK;
     }
-    // connect the source stream to the track union stream to avoid us blocking
-    trackunion->GetStream()->AsProcessedStream()->SetAutofinish(true);
-    nsRefPtr<MediaInputPort> port = trackunion->GetStream()->AsProcessedStream()->
-      AllocateInputPort(stream->GetStream()->AsSourceStream(),
-                        MediaInputPort::FLAG_BLOCK_OUTPUT);
 
     nsPIDOMWindow *window = static_cast<nsPIDOMWindow*>
       (nsGlobalWindow::GetInnerWindowWithId(mWindowID));
     if (window && window->GetExtantDoc()) {
       stream->CombineWithPrincipal(window->GetExtantDoc()->NodePrincipal());
-      trackunion->CombineWithPrincipal(window->GetExtantDoc()->NodePrincipal());
     }
 
     // Ensure there's a thread for gum to proxy to off main thread
     nsIThread *mediaThread = MediaManager::GetThread();
 
     // Add our listener. We'll call Start() on the source when get a callback
     // that the MediaStream has started consuming. The listener is freed
     // when the page is invalidated (on navigation or close).
     GetUserMediaCallbackMediaStreamListener* listener =
       new GetUserMediaCallbackMediaStreamListener(mediaThread, stream,
-                                                  port.forget(),
                                                   mAudioSource,
                                                   mVideoSource);
     stream->GetStream()->AddListener(listener);
 
     // No need for locking because we always do this in the main thread.
     listeners->AppendElement(listener);
 
     // Dispatch to the media thread to ask it to start the sources,
@@ -315,17 +306,17 @@ public:
     nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
 
     if (!(MediaManager::Get()->IsWindowStillActive(mWindowID))) {
       return NS_OK;
     }
     // This is safe since we're on main-thread, and the windowlist can only
     // be invalidated from the main-thread (see OnNavigation)
     LOG(("Returning success for getUserMedia()"));
-    success->OnSuccess(static_cast<nsIDOMLocalMediaStream*>(trackunion));
+    success->OnSuccess(static_cast<nsIDOMLocalMediaStream*>(stream));
 
     return NS_OK;
   }
 
 private:
   already_AddRefed<nsIDOMGetUserMediaSuccessCallback> mSuccess;
   already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
   nsRefPtr<MediaEngineSource> mAudioSource;
@@ -999,30 +990,45 @@ MediaManager::Observe(nsISupports* aSubj
     nsString key(aData);
     nsRefPtr<nsRunnable> runnable;
     if (!mActiveCallbacks.Get(key, getter_AddRefs(runnable))) {
       return NS_OK;
     }
     mActiveCallbacks.Remove(key);
 
     if (aSubject) {
-      // A particular device was chosen by the user.
+      // A particular device or devices were chosen by the user.
       // NOTE: does not allow setting a device to null; assumes nullptr
-      nsCOMPtr<nsIMediaDevice> device = do_QueryInterface(aSubject);
-      if (device) {
-        GetUserMediaRunnable* gUMRunnable =
-          static_cast<GetUserMediaRunnable*>(runnable.get());
-        nsString type;
-        device->GetType(type);
-        if (type.EqualsLiteral("video")) {
-          gUMRunnable->SetVideoDevice(static_cast<MediaDevice*>(device.get()));
-        } else if (type.EqualsLiteral("audio")) {
-          gUMRunnable->SetAudioDevice(static_cast<MediaDevice*>(device.get()));
-        } else {
-          NS_WARNING("Unknown device type in getUserMedia");
+      GetUserMediaRunnable* gUMRunnable =
+        static_cast<GetUserMediaRunnable*>(runnable.get());
+
+      nsCOMPtr<nsISupportsArray> array(do_QueryInterface(aSubject));
+      MOZ_ASSERT(array);
+      uint32_t len = 0;
+      array->Count(&len);
+      MOZ_ASSERT(len);
+      if (!len) {
+        gUMRunnable->Denied(); // neither audio nor video were selected
+        return NS_OK;
+      }
+      for (uint32_t i = 0; i < len; i++) {
+        nsCOMPtr<nsISupports> supports;
+        array->GetElementAt(i,getter_AddRefs(supports));
+        nsCOMPtr<nsIMediaDevice> device(do_QueryInterface(supports));
+        MOZ_ASSERT(device); // shouldn't be returning anything else...
+        if (device) {
+          nsString type;
+          device->GetType(type);
+          if (type.EqualsLiteral("video")) {
+            gUMRunnable->SetVideoDevice(static_cast<MediaDevice*>(device.get()));
+          } else if (type.EqualsLiteral("audio")) {
+            gUMRunnable->SetAudioDevice(static_cast<MediaDevice*>(device.get()));
+          } else {
+            NS_WARNING("Unknown device type in getUserMedia");
+          }
         }
       }
     }
 
     // Reuse the same thread to save memory.
     mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
     return NS_OK;
   }
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -84,17 +84,16 @@ public:
     MediaEngineSource* aAudioSource,
     MediaEngineSource* aVideoSource)
     : mType(aType)
     , mAudioSource(aAudioSource)
     , mVideoSource(aVideoSource)
     , mStream(aStream)
     {}
 
-  // so we can send Stop without AddRef()ing from the MSG thread
   MediaOperationRunnable(MediaOperation aType,
     SourceMediaStream* aStream,
     MediaEngineSource* aAudioSource,
     MediaEngineSource* aVideoSource)
     : mType(aType)
     , mAudioSource(aAudioSource)
     , mVideoSource(aVideoSource)
     , mStream(nullptr)
@@ -157,17 +156,16 @@ public:
             mAudioSource->Deallocate();
           }
           if (mVideoSource) {
             mVideoSource->Stop();
             mVideoSource->Deallocate();
           }
           // Do this after stopping all tracks with EndTrack()
           mSourceStream->Finish();
-          // the TrackUnion destination of the port will autofinish
 
           nsRefPtr<GetUserMediaNotificationEvent> event =
             new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STOPPING);
 
           NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
         }
         break;
     }
@@ -187,35 +185,33 @@ private:
  * to Start() and Stop() the underlying MediaEngineSource when MediaStreams
  * are assigned and deassigned in content.
  */
 class GetUserMediaCallbackMediaStreamListener : public MediaStreamListener
 {
 public:
   GetUserMediaCallbackMediaStreamListener(nsIThread *aThread,
     nsDOMMediaStream* aStream,
-    already_AddRefed<MediaInputPort> aPort,
     MediaEngineSource* aAudioSource,
     MediaEngineSource* aVideoSource)
     : mMediaThread(aThread)
     , mAudioSource(aAudioSource)
     , mVideoSource(aVideoSource)
-    , mStream(aStream)
-    , mPort(aPort) {}
+    , mStream(aStream) {}
 
   void
   Invalidate()
   {
     nsRefPtr<MediaOperationRunnable> runnable;