Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 15 Feb 2013 09:39:34 -0500
changeset 131903 326c5e4868fe5ec714983f4138251c66cb3be044
parent 131809 31e89328fe12042f5affd2905d280ef412086c8f (current diff)
parent 131902 13882bd746800f8509fb59d64c943a58fab29475 (diff)
child 131915 26c3dd6332881233a07a6a85fc020b9cb666118c
child 138255 6cd92ea91269ba45ea00a07cf6f1d42b4422036a
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone21.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 inbound to m-c.
content/media/nsDOMMediaStream.cpp
content/media/nsDOMMediaStream.h
docshell/base/nsIEditorDocShell.idl
mfbt/ASan.h
mobile/android/base/resources/drawable-nodpi/abouthome_bg.png
mobile/android/base/resources/drawable/abouthome_icon.png
mobile/android/base/resources/drawable/abouthome_logo_dark.png
mobile/android/base/resources/drawable/abouthome_logo_light.png
mobile/android/base/resources/drawable/abouthome_promo_box_bg.9.png
mobile/android/base/resources/drawable/abouthome_promo_box_pressed_bg.9.png
mobile/android/base/resources/drawable/abouthome_promo_logo_apps.png
mobile/android/base/resources/drawable/abouthome_promo_logo_sync.png
mobile/android/base/resources/drawable/abouthome_thumbnail.png
mobile/android/base/resources/drawable/abouthome_thumbnail_add.png
mobile/android/base/resources/drawable/abouthome_thumbnail_bg.png
mobile/android/base/resources/drawable/address_bar_bg_shadow.png
mobile/android/base/resources/drawable/address_bar_url_default.9.png
mobile/android/base/resources/drawable/address_bar_url_default_pb.9.png
mobile/android/base/resources/drawable/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable/address_bar_url_pressed_pb.9.png
mobile/android/base/resources/drawable/alert_addon.png
mobile/android/base/resources/drawable/alert_app.png
mobile/android/base/resources/drawable/alert_download.png
mobile/android/base/resources/drawable/appwidget_bg.9.png
mobile/android/base/resources/drawable/autocomplete_list_bg.9.png
mobile/android/base/resources/drawable/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable/bookmarkdefaults_favicon_addons.png
mobile/android/base/resources/drawable/bookmarkdefaults_favicon_support.png
mobile/android/base/resources/drawable/crash_reporter.png
mobile/android/base/resources/drawable/desktop_notification.png
mobile/android/base/resources/drawable/doorhanger_arrow.png
mobile/android/base/resources/drawable/doorhanger_bg.9.png
mobile/android/base/resources/drawable/doorhanger_popup_bg.9.png
mobile/android/base/resources/drawable/doorhanger_shadow_bg.9.png
mobile/android/base/resources/drawable/favicon.png
mobile/android/base/resources/drawable/find_close.png
mobile/android/base/resources/drawable/find_next.png
mobile/android/base/resources/drawable/find_prev.png
mobile/android/base/resources/drawable/folder.png
mobile/android/base/resources/drawable/handle_end.png
mobile/android/base/resources/drawable/handle_middle.png
mobile/android/base/resources/drawable/handle_start.png
mobile/android/base/resources/drawable/ic_addons_empty.png
mobile/android/base/resources/drawable/ic_awesomebar_go.png
mobile/android/base/resources/drawable/ic_awesomebar_reader.png
mobile/android/base/resources/drawable/ic_awesomebar_search.png
mobile/android/base/resources/drawable/ic_awesomebar_star.png
mobile/android/base/resources/drawable/ic_menu_bookmark_add.png
mobile/android/base/resources/drawable/ic_menu_bookmark_remove.png
mobile/android/base/resources/drawable/ic_menu_close_all_tabs.png
mobile/android/base/resources/drawable/ic_menu_forward.png
mobile/android/base/resources/drawable/ic_menu_new_private_tab.png
mobile/android/base/resources/drawable/ic_menu_new_private_tab_small.png
mobile/android/base/resources/drawable/ic_menu_new_tab.png
mobile/android/base/resources/drawable/ic_menu_new_tab_small.png
mobile/android/base/resources/drawable/ic_menu_reload.png
mobile/android/base/resources/drawable/ic_status_logo.png
mobile/android/base/resources/drawable/larry_blue.png
mobile/android/base/resources/drawable/larry_green.png
mobile/android/base/resources/drawable/marketplace.png
mobile/android/base/resources/drawable/menu.png
mobile/android/base/resources/drawable/menu_item_check.png
mobile/android/base/resources/drawable/menu_item_more.png
mobile/android/base/resources/drawable/menu_item_uncheck.png
mobile/android/base/resources/drawable/menu_panel_bg.9.png
mobile/android/base/resources/drawable/menu_pb.png
mobile/android/base/resources/drawable/menu_popup_arrow_bottom.png
mobile/android/base/resources/drawable/menu_popup_arrow_top.png
mobile/android/base/resources/drawable/menu_popup_bg.9.png
mobile/android/base/resources/drawable/progress_spinner_1.png
mobile/android/base/resources/drawable/progress_spinner_10.png
mobile/android/base/resources/drawable/progress_spinner_11.png
mobile/android/base/resources/drawable/progress_spinner_12.png
mobile/android/base/resources/drawable/progress_spinner_2.png
mobile/android/base/resources/drawable/progress_spinner_3.png
mobile/android/base/resources/drawable/progress_spinner_4.png
mobile/android/base/resources/drawable/progress_spinner_5.png
mobile/android/base/resources/drawable/progress_spinner_6.png
mobile/android/base/resources/drawable/progress_spinner_7.png
mobile/android/base/resources/drawable/progress_spinner_8.png
mobile/android/base/resources/drawable/progress_spinner_9.png
mobile/android/base/resources/drawable/reader.png
mobile/android/base/resources/drawable/reading_list.png
mobile/android/base/resources/drawable/scrollbar.png
mobile/android/base/resources/drawable/shadow.png
mobile/android/base/resources/drawable/site_security_identified.png
mobile/android/base/resources/drawable/site_security_verified.png
mobile/android/base/resources/drawable/spinner_default.9.png
mobile/android/base/resources/drawable/spinner_focused.9.png
mobile/android/base/resources/drawable/spinner_pressed.9.png
mobile/android/base/resources/drawable/start.png
mobile/android/base/resources/drawable/tab_close.png
mobile/android/base/resources/drawable/tab_indicator_divider.9.png
mobile/android/base/resources/drawable/tab_indicator_selected.9.png
mobile/android/base/resources/drawable/tab_indicator_selected_focused.9.png
mobile/android/base/resources/drawable/tab_new.png
mobile/android/base/resources/drawable/tab_new_pb.png
mobile/android/base/resources/drawable/tab_thumbnail_default.png
mobile/android/base/resources/drawable/tab_thumbnail_shadow.png
mobile/android/base/resources/drawable/tabs_carat.png
mobile/android/base/resources/drawable/tabs_normal.png
mobile/android/base/resources/drawable/tabs_private.png
mobile/android/base/resources/drawable/tabs_synced.png
mobile/android/base/resources/drawable/urlbar_stop.png
mobile/android/base/resources/drawable/validation_arrow.png
mobile/android/base/resources/drawable/validation_arrow_inverted.png
mobile/android/base/resources/drawable/validation_bg.9.png
--- a/CLOBBER
+++ b/CLOBBER
@@ -10,9 +10,9 @@
 #                  O   <-- Users coming from both parents need to Clobber
 #               /     \
 #          O               O
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
-Bug 755724 - Move browser application in a subdirectory
+Bug 836654 - IndexedDB test failures without clobber
--- a/accessible/src/base/nsAccUtils.h
+++ b/accessible/src/base/nsAccUtils.h
@@ -10,17 +10,16 @@
 #include "nsIAccessibleRole.h"
 #include "nsIAccessibleText.h"
 
 #include "nsAccessibilityService.h"
 #include "nsCoreUtils.h"
 
 #include "mozilla/dom/Element.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsIPersistentProperties2.h"
 #include "nsIPresShell.h"
 #include "nsPoint.h"
 
 struct nsRoleMapEntry;
 
 namespace mozilla {
 namespace a11y {
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -6,17 +6,16 @@
 #include "nsAccessNode.h"
 
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "RootAccessible.h"
 
 #include "nsIDocShell.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsIDOMWindow.h"
 #include "nsIFrame.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIPresShell.h"
 #include "nsIServiceManager.h"
 #include "nsFocusManager.h"
 #include "nsPresContext.h"
 #include "mozilla/Services.h"
@@ -77,24 +76,23 @@ nsAccessNode::Shutdown()
 {
   mContent = nullptr;
   mDoc = nullptr;
 }
 
 RootAccessible*
 nsAccessNode::RootAccessible() const
 {
-  nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
-    nsCoreUtils::GetDocShellTreeItemFor(GetNode());
-  NS_ASSERTION(docShellTreeItem, "No docshell tree item for mContent");
-  if (!docShellTreeItem) {
+  nsCOMPtr<nsIDocShell> docShell = nsCoreUtils::GetDocShellFor(GetNode());
+  NS_ASSERTION(docShell, "No docshell for mContent");
+  if (!docShell) {
     return nullptr;
   }
   nsCOMPtr<nsIDocShellTreeItem> root;
-  docShellTreeItem->GetRootTreeItem(getter_AddRefs(root));
+  docShell->GetRootTreeItem(getter_AddRefs(root));
   NS_ASSERTION(root, "No root content tree item");
   if (!root) {
     return nullptr;
   }
 
   DocAccessible* docAcc = nsAccUtils::GetDocAccessibleFor(root);
   return docAcc ? docAcc->AsRoot() : nullptr;
 }
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -33,17 +33,16 @@
 #include "nsLayoutUtils.h"
 #include "nsGkAtoms.h"
 
 #include "nsComponentManagerUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "mozilla/dom/Element.h"
 
 #include "nsITreeBoxObject.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsITreeColumns.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsCoreUtils
 ////////////////////////////////////////////////////////////////////////////////
 
 bool
 nsCoreUtils::HasClickListener(nsIContent *aContent)
@@ -375,44 +374,41 @@ nsCoreUtils::ConvertScrollTypeToPercents
   *aVertical = nsIPresShell::ScrollAxis(whereY, whenY);
   *aHorizontal = nsIPresShell::ScrollAxis(whereX, whenX);
 }
 
 nsIntPoint
 nsCoreUtils::GetScreenCoordsForWindow(nsINode *aNode)
 {
   nsIntPoint coords(0, 0);
-  nsCOMPtr<nsIDocShellTreeItem> treeItem(GetDocShellTreeItemFor(aNode));
+  nsCOMPtr<nsIDocShellTreeItem> treeItem(GetDocShellFor(aNode));
   if (!treeItem)
     return coords;
 
   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
   treeItem->GetTreeOwner(getter_AddRefs(treeOwner));
   if (!treeOwner)
     return coords;
 
   nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(treeOwner);
   if (baseWindow)
     baseWindow->GetPosition(&coords.x, &coords.y); // in device pixels
 
   return coords;
 }
 
-already_AddRefed<nsIDocShellTreeItem>
-nsCoreUtils::GetDocShellTreeItemFor(nsINode *aNode)
+already_AddRefed<nsIDocShell>
+nsCoreUtils::GetDocShellFor(nsINode *aNode)
 {
   if (!aNode)
     return nullptr;
 
   nsCOMPtr<nsISupports> container = aNode->OwnerDoc()->GetContainer();
-  nsIDocShellTreeItem *docShellTreeItem = nullptr;
-  if (container)
-    CallQueryInterface(container, &docShellTreeItem);
-
-  return docShellTreeItem;
+  nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
+  return docShell.forget();
 }
 
 bool
 nsCoreUtils::IsRootDocument(nsIDocument *aDocument)
 {
   nsCOMPtr<nsISupports> container = aDocument->GetContainer();
   nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
     do_QueryInterface(container);
--- a/accessible/src/base/nsCoreUtils.h
+++ b/accessible/src/base/nsCoreUtils.h
@@ -12,17 +12,17 @@
 #include "nsIPresShell.h"
 
 #include "nsIDOMDOMStringList.h"
 #include "nsPoint.h"
 #include "nsTArray.h"
 
 class nsRange;
 class nsIFrame;
-class nsIDocShellTreeItem;
+class nsIDocShell;
 class nsITreeColumn;
 class nsITreeBoxObject;
 class nsIWidget;
 
 /**
  * Core utils.
  */
 class nsCoreUtils
@@ -171,20 +171,19 @@ public:
    * Returns coordinates in device pixels relative screen for the top level
    * window.
    *
    * @param aNode  the DOM node hosted in the window.
    */
   static nsIntPoint GetScreenCoordsForWindow(nsINode *aNode);
 
   /**
-   * Return document shell tree item for the given DOM node.
+   * Return document shell for the given DOM node.
    */
-  static already_AddRefed<nsIDocShellTreeItem>
-    GetDocShellTreeItemFor(nsINode *aNode);
+  static already_AddRefed<nsIDocShell> GetDocShellFor(nsINode *aNode);
 
   /**
    * Return true if the given document is root document.
    */
   static bool IsRootDocument(nsIDocument *aDocument);
 
   /**
    * Return true if the given document is content document (not chrome).
--- a/accessible/src/base/nsTextEquivUtils.cpp
+++ b/accessible/src/base/nsTextEquivUtils.cpp
@@ -43,16 +43,29 @@ nsTextEquivUtils::GetNameFromSubtree(Acc
     }
   }
 
   gInitiatorAcc = nullptr;
 
   return NS_OK;
 }
 
+void
+nsTextEquivUtils::GetTextEquivFromSubtree(Accessible* aAccessible,
+                                          nsString& aTextEquiv)
+{
+  aTextEquiv.Truncate();
+
+  uint32_t nameRule = GetRoleRule(aAccessible->Role());
+  if (nameRule & eNameFromSubtreeIfReqRule) {
+    AppendFromAccessibleChildren(aAccessible, &aTextEquiv);
+    aTextEquiv.CompressWhitespace();
+  }
+}
+
 nsresult
 nsTextEquivUtils::GetTextEquivFromIDRefs(Accessible* aAccessible,
                                          nsIAtom *aIDRefsAttr,
                                          nsAString& aTextEquiv)
 {
   aTextEquiv.Truncate();
 
   nsIContent* content = aAccessible->GetContent();
--- a/accessible/src/base/nsTextEquivUtils.h
+++ b/accessible/src/base/nsTextEquivUtils.h
@@ -49,16 +49,24 @@ public:
    *
    * @param aAccessible [in] the given accessible
    * @param aName       [out] accessible name
    */
   static nsresult GetNameFromSubtree(Accessible* aAccessible,
                                      nsAString& aName);
 
   /**
+   * Calculates text equivalent from the subtree. Similar to GetNameFromSubtree.
+   * The difference it returns not empty result for things like HTML p, i.e.
+   * if the role has eNameFromSubtreeIfReq rule.
+   */
+  static void GetTextEquivFromSubtree(Accessible* aAccessible,
+                                      nsString& aTextEquiv);
+
+  /**
    * Calculates text equivalent for the given accessible from its IDRefs
    * attribute (like aria-labelledby or aria-describedby).
    *
    * @param aAccessible  [in] the accessible text equivalent is computed for
    * @param aIDRefsAttr  [in] IDRefs attribute on DOM node of the accessible
    * @param aTextEquiv   [out] result text equivalent
    */
   static nsresult GetTextEquivFromIDRefs(Accessible* aAccessible,
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -1665,17 +1665,17 @@ Accessible::Value(nsString& aValue)
         }
       }
 
       if (listbox)
         option = listbox->GetSelectedItem(0);
     }
 
     if (option)
-      nsTextEquivUtils::GetNameFromSubtree(option, aValue);
+      nsTextEquivUtils::GetTextEquivFromSubtree(option, aValue);
   }
 }
 
 // nsIAccessibleValue
 NS_IMETHODIMP
 Accessible::GetMaximumValue(double *aMaximumValue)
 {
   return GetAttrValue(nsGkAtoms::aria_valuemax, aMaximumValue);
--- a/accessible/src/generic/DocAccessible.cpp
+++ b/accessible/src/generic/DocAccessible.cpp
@@ -13,17 +13,16 @@
 #include "nsTextEquivUtils.h"
 #include "Role.h"
 #include "RootAccessible.h"
 #include "TreeWalker.h"
 
 #include "nsIMutableArray.h"
 #include "nsICommandManager.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsIDocument.h"
 #include "nsIDOMAttr.h"
 #include "nsIDOMCharacterData.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentType.h"
 #include "nsIDOMXULDocument.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsPIDOMWindow.h"
@@ -180,24 +179,23 @@ DocAccessible::Name(nsString& aName)
  
   return eNameOK;
 }
 
 // Accessible public method
 role
 DocAccessible::NativeRole()
 {
-  nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
-    nsCoreUtils::GetDocShellTreeItemFor(mDocumentNode);
-  if (docShellTreeItem) {
+  nsCOMPtr<nsIDocShell> docShell = nsCoreUtils::GetDocShellFor(mDocumentNode);
+  if (docShell) {
     nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
-    docShellTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
+    docShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
     int32_t itemType;
-    docShellTreeItem->GetItemType(&itemType);
-    if (sameTypeRoot == docShellTreeItem) {
+    docShell->GetItemType(&itemType);
+    if (sameTypeRoot == docShell) {
       // Root of content or chrome tree
       if (itemType == nsIDocShellTreeItem::typeChrome)
         return roles::CHROME_WINDOW;
 
       if (itemType == nsIDocShellTreeItem::typeContent) {
 #ifdef MOZ_XUL
         nsCOMPtr<nsIXULDocument> xulDoc(do_QueryInterface(mDocumentNode));
         if (xulDoc)
--- a/accessible/src/generic/HyperTextAccessible.cpp
+++ b/accessible/src/generic/HyperTextAccessible.cpp
@@ -1477,19 +1477,18 @@ HyperTextAccessible::GetEditor() const
       }
 
       ancestor = ancestor->Parent();
     }
 
     return nullptr;
   }
 
-  nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
-    nsCoreUtils::GetDocShellTreeItemFor(mContent);
-  nsCOMPtr<nsIEditingSession> editingSession(do_GetInterface(docShellTreeItem));
+  nsCOMPtr<nsIDocShell> docShell = nsCoreUtils::GetDocShellFor(mContent);
+  nsCOMPtr<nsIEditingSession> editingSession(do_GetInterface(docShell));
   if (!editingSession)
     return nullptr; // No editing session interface
 
   nsCOMPtr<nsIEditor> editor;
   nsIDocument* docNode = mDoc->DocumentNode();
   editingSession->GetEditorForWindow(docNode->GetWindow(),
                                      getter_AddRefs(editor));
   return editor.forget();
--- a/accessible/src/generic/RootAccessible.cpp
+++ b/accessible/src/generic/RootAccessible.cpp
@@ -103,21 +103,20 @@ RootAccessible::NativeRole()
 // RootAccessible protected member
 #ifdef MOZ_XUL
 uint32_t
 RootAccessible::GetChromeFlags()
 {
   // Return the flag set for the top level window as defined 
   // by nsIWebBrowserChrome::CHROME_WINDOW_[FLAGNAME]
   // Not simple: nsIXULWindow is not just a QI from nsIDOMWindow
-  nsCOMPtr<nsIDocShellTreeItem> treeItem =
-    nsCoreUtils::GetDocShellTreeItemFor(mDocumentNode);
-  NS_ENSURE_TRUE(treeItem, 0);
+  nsCOMPtr<nsIDocShell> docShell = nsCoreUtils::GetDocShellFor(mDocumentNode);
+  NS_ENSURE_TRUE(docShell, 0);
   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
-  treeItem->GetTreeOwner(getter_AddRefs(treeOwner));
+  docShell->GetTreeOwner(getter_AddRefs(treeOwner));
   NS_ENSURE_TRUE(treeOwner, 0);
   nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(treeOwner));
   if (!xulWin) {
     return 0;
   }
   uint32_t chromeFlags;
   xulWin->GetChromeFlags(&chromeFlags);
   return chromeFlags;
--- a/accessible/src/msaa/nsAccessNodeWrap.cpp
+++ b/accessible/src/msaa/nsAccessNodeWrap.cpp
@@ -72,25 +72,24 @@ nsAccessNodeWrap::QueryService(REFGUID g
   // A use case for this is for screen readers that need to switch context or
   // 'virtual buffer' when focus moves from one browser tab area to another.
   static const GUID SID_IAccessibleContentDocument =
     { 0xa5d8e1f3,0x3571,0x4d8f,{0x95,0x21,0x07,0xed,0x28,0xfb,0x07,0x2e} };
   if (guidService == SID_IAccessibleContentDocument) {
     if (iid != IID_IAccessible)
       return E_NOINTERFACE;
 
-    nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = 
-      nsCoreUtils::GetDocShellTreeItemFor(mContent);
-    if (!docShellTreeItem)
+    nsCOMPtr<nsIDocShell> docShell = nsCoreUtils::GetDocShellFor(mContent);
+    if (!docShell)
       return E_UNEXPECTED;
 
     // Walk up the parent chain without crossing the boundary at which item
     // types change, preventing us from walking up out of tab content.
     nsCOMPtr<nsIDocShellTreeItem> root;
-    docShellTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
+    docShell->GetSameTypeRootTreeItem(getter_AddRefs(root));
     if (!root)
       return E_UNEXPECTED;
 
 
     // If the item type is typeContent, we assume we are in browser tab content.
     // Note this includes content such as about:addons, for consistency.
     int32_t itemType;
     root->GetItemType(&itemType);
--- a/accessible/tests/mochitest/name/test_general.html
+++ b/accessible/tests/mochitest/name/test_general.html
@@ -166,16 +166,17 @@
 
       //////////////////////////////////////////////////////////////////////////
       // controls having a value used as a part of computed name
 
       testName("ctrlvalue_progressbar:input", "foo 5 baz");
       testName("ctrlvalue_scrollbar:input", "foo 5 baz");
       testName("ctrlvalue_slider:input", "foo 5 baz");
       testName("ctrlvalue_spinbutton:input", "foo 5 baz");
+      testName("ctrlvalue_combobox:input", "foo 5 baz");
 
 
       /////////////////////////////////////////////////////////////////////////
       // label with nested combobox (test for 'f' item of name computation guide)
 
       testName("comboinstart", "One day(s).");
       testName("combo3", "day(s).");
 
@@ -265,16 +266,21 @@
      title="ARIA slider and spinbutton don't provide a value for name computation">
     Bug 812041
   </a>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=823927"
      title="Text is jammed with control's text in name computation">
     Bug 823927
   </a>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=835666"
+     title="ARIA combobox selected value is not a part of name computation">
+    Bug 835666
+  </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <!-- aria-label, simple label -->
   <span id="btn_simple_aria_label" role="button" aria-label="I am a button"/>
   <br/>
@@ -500,16 +506,30 @@
   <label for="ctrlvalue_spinbutton:input">
     foo <input role="spinbutton" type="number"
                value="5" min="1" max="10"
                aria-valuenow="5" aria-valuemin="1"
                aria-valuemax="10">
     baz
   </label>
 
+  <input type="checkbox" id="ctrlvalue_combobox:input">
+  <label for="ctrlvalue_combobox:input">
+    foo
+    <div role="combobox">
+      <div role="textbox"></div>
+      <ul role="listbox" style="list-style-type: none;">
+        <li role="option">1</li>
+        <li role="option" aria-selected="true">5</li>
+        <li role="option">3</li>
+      </ul>
+    </div>
+    baz
+  </label>
+
   <!-- a label with a nested control in the start, middle and end -->
   <form>
     <!-- at the start (without and with whitespaces) -->
     <label id="comboinstart"><select id="combo3">
         <option>One</option>
         <option>Two</option>
       </select>
       day(s).
--- a/addon-sdk/Makefile.in
+++ b/addon-sdk/Makefile.in
@@ -6,23 +6,19 @@ DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(topsrcdir)/config/config.mk
 
 TEST_DIRS += test
 
-COMMONJS_FILES = \
-  source/lib/toolkit \
-  source/lib/sdk \
-  $(NULL)
-
-COMMONJS_DEST = $(FINAL_TARGET)/modules/commonjs
-INSTALL_TARGETS += COMMONJS
+libs::
+	$(PYTHON) $(srcdir)/copy_source.py $(topsrcdir) $(srcdir)/source/lib $(FINAL_TARGET)/modules/commonjs >copy_source.mk
+	$(MAKE) -f copy_source.mk libs
 
 include $(topsrcdir)/config/rules.mk
 
 TEST_FILES = \
   source/app-extension \
   source/bin \
   source/data \
   source/python-lib \
new file mode 100644
--- /dev/null
+++ b/addon-sdk/copy_source.py
@@ -0,0 +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/.
+
+import os
+import sys
+
+if len(sys.argv) != 4:
+    print >> sys.stderr, "Usage: copy_source.py " \
+                         "<topsrcdir> <source directory> <target directory>"
+    sys.exit(1)
+
+topsrcdir = sys.argv[1]
+source_dir = sys.argv[2]
+target_dir = sys.argv[3]
+
+print """
+DEPTH     = ..
+topsrcdir = %(topsrcdir)s
+srcdir    = %(topsrcdir)s/addon-sdk
+VPATH     = %(topsrcdir)s/addon-sdk
+
+include $(topsrcdir)/config/config.mk
+""" % {'topsrcdir': topsrcdir}
+
+real_source = source_dir.replace('/', os.sep)
+if not os.path.exists(real_source):
+    print >> sys.stderr, "Error: Missing source file %s" % real_source
+    sys.exit(1)
+elif not os.path.isdir(real_source):
+    print >> sys.stderr, "Error: Source %s is not a directory" % real_source
+    sys.exit(1)
+for dirpath, dirnames, filenames in os.walk(real_source):
+    if not filenames:
+        continue
+    dirpath = dirpath.replace(os.sep, '/')
+    relative = dirpath[len(source_dir):]
+    varname = "COMMONJS%s" % relative.replace('/', '_')
+    print "%s_FILES = \\" % varname
+    for name in filenames:
+        print "  %s/%s \\" % (dirpath, name)
+    print "  $(NULL)"
+    print "%s_DEST = %s%s" % (varname, target_dir, relative)
+    print "INSTALL_TARGETS += %s\n" % varname
+
+print "include $(topsrcdir)/config/rules.mk"
--- a/addon-sdk/source/README
+++ b/addon-sdk/source/README
@@ -33,13 +33,13 @@ If you get an error when running cfx or 
 started, see the "Troubleshooting" guide at:
 https://addons.mozilla.org/en-US/developers/docs/sdk/latest/dev-guide/tutorials/troubleshooting.html
 
 Bugs
 -------
 
 * file a bug: https://bugzilla.mozilla.org/enter_bug.cgi?product=Add-on%20SDK
 
-
 Style Guidelines
 --------------------
 
-* https://github.com/mozilla/addon-sdk/wiki/Coding-style-guide
+* https://github.com/mozilla/addon-sdk/wiki/Coding-style-guide
+
--- a/addon-sdk/source/app-extension/install.rdf
+++ b/addon-sdk/source/app-extension/install.rdf
@@ -13,17 +13,17 @@
     <em:bootstrap>true</em:bootstrap>
     <em:unpack>false</em:unpack>
 
     <!-- Firefox -->
     <em:targetApplication>
       <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>18.0</em:minVersion>
-        <em:maxVersion>21.0a1</em:maxVersion>
+        <em:maxVersion>20.*</em:maxVersion>
       </Description>
     </em:targetApplication>
 
     <!-- Front End MetaData -->
     <em:name>Test App</em:name>
     <em:description>Harness for tests.</em:description>
     <em:creator>Mozilla Corporation</em:creator>
     <em:homepageURL></em:homepageURL>
--- a/addon-sdk/source/lib/sdk/context-menu.js
+++ b/addon-sdk/source/lib/sdk/context-menu.js
@@ -1,25 +1,24 @@
 /* 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";
 
 module.metadata = {
   "stability": "stable"
 };
 
 const { Class, mix } = require("./core/heritage");
 const { addCollectionProperty } = require("./util/collection");
 const { ns } = require("./core/namespace");
 const { validateOptions, getTypeOf } = require("./deprecated/api-utils");
 const { URL } = require("./url");
 const { WindowTracker, browserWindowIterator } = require("./deprecated/window-utils");
-const { isBrowser } = require("./window/utils");
+const { isBrowser, getInnerId } = require("./window/utils");
 const { Ci } = require("chrome");
 const { MatchPattern } = require("./page-mod/match-pattern");
 const { Worker } = require("./content/worker");
 const { EventTarget } = require("./event/target");
 const { emit } = require('./event/core');
 const { when } = require('./system/unload');
 
 // All user items we add have this class.
@@ -320,76 +319,69 @@ function hasMatchingContext(contexts, po
     if (!context.isCurrent(popupNode))
       return false;
   }
 
   return true;
 }
 
 // Gets the matched context from any worker for this item. If there is no worker
-// or no matched context then returns null.
+// or no matched context then returns false.
 function getCurrentWorkerContext(item, popupNode) {
   let worker = getItemWorkerForWindow(item, popupNode.ownerDocument.defaultView);
-  if (!worker)
-    return null;
+  if (!worker || !worker.anyContextListeners())
+    return true;
   return worker.getMatchedContext(popupNode);
 }
 
 // Tests whether an item should be visible or not based on its contexts and
 // content scripts
 function isItemVisible(item, popupNode, defaultVisibility) {
   if (!item.context.length) {
     let worker = getItemWorkerForWindow(item, popupNode.ownerDocument.defaultView);
     if (!worker || !worker.anyContextListeners())
       return defaultVisibility;
   }
 
   if (!hasMatchingContext(item.context, popupNode))
     return false;
 
   let context = getCurrentWorkerContext(item, popupNode);
-  if (typeof(context) === "string")
+  if (typeof(context) === "string" && context != "")
     item.label = context;
 
-  return context !== false;
-}
-
-// Destroys any item's content scripts workers associated with the given window
-function destroyItemWorkerForWindow(item, window) {
-  let worker = internal(item).workerMap.get(window);
-  if (worker)
-    worker.destroy();
-  internal(item).workerMap.delete(window);
+  return !!context;
 }
 
 // Gets the item's content script worker for a window, creating one if necessary
 // Once created it will be automatically destroyed when the window unloads.
 // If there is not content scripts for the item then null will be returned.
 function getItemWorkerForWindow(item, window) {
   if (!item.contentScript && !item.contentScriptFile)
     return null;
 
-  let worker = internal(item).workerMap.get(window);
+  let id = getInnerId(window);
+  let worker = internal(item).workerMap.get(id);
 
   if (worker)
     return worker;
 
   worker = ContextWorker({
     window: window,
     contentScript: item.contentScript,
     contentScriptFile: item.contentScriptFile,
     onMessage: function(msg) {
       emit(item, "message", msg);
     },
     onDetach: function() {
-      destroyItemWorkerForWindow(item, window);
+      internal(item).workerMap.delete(id);
     }
   });
 
-  internal(item).workerMap.set(window, worker);
+  internal(item).workerMap.set(id, worker);
 
   return worker;
 }
 
 // Called when an item is clicked to send out click events to the content
 // scripts
 function itemClicked(item, clickedItem, popupNode) {
   let worker = getItemWorkerForWindow(item, popupNode.ownerDocument.defaultView);
@@ -458,18 +450,18 @@ let LabelledItem = Class({
   implements: [ EventTarget ],
 
   initialize: function initialize(options) {
     BaseItem.prototype.initialize.call(this);
     EventTarget.prototype.initialize.call(this, options);
   },
 
   destroy: function destroy() {
-    for (let [window] of internal(this).workerMap)
-      destroyItemWorkerForWindow(this, window);
+    for (let [,worker] of internal(this).workerMap)
+      worker.destroy();
 
     BaseItem.prototype.destroy.call(this);
   },
 
   get label() {
     return internal(this).options.label;
   },
 
@@ -640,30 +632,42 @@ exports.contentContextMenu = contentCont
 
 when(function() {
   contentContextMenu.destroy();
 });
 
 // App specific UI code lives here, it should handle populating the context
 // menu and passing clicks etc. through to the items.
 
+function countVisibleItems(nodes) {
+  return Array.reduce(nodes, function(sum, node) {
+    return node.hidden ? sum : sum + 1;
+  }, 0);
+}
+
 let MenuWrapper = Class({
   initialize: function initialize(winWrapper, items, contextMenu) {
     this.winWrapper = winWrapper;
     this.window = winWrapper.window;
     this.items = items;
     this.contextMenu = contextMenu;
     this.populated = false;
     this.menuMap = new Map();
 
-    this.contextMenu.addEventListener("popupshowing", this, false);
+    // updateItemVisibilities will run first, updateOverflowState will run after
+    // all other instances of this module have run updateItemVisibilities
+    this._updateItemVisibilities = this.updateItemVisibilities.bind(this);
+    this.contextMenu.addEventListener("popupshowing", this._updateItemVisibilities, true);
+    this._updateOverflowState = this.updateOverflowState.bind(this);
+    this.contextMenu.addEventListener("popupshowing", this._updateOverflowState, false);
   },
 
   destroy: function destroy() {
-    this.contextMenu.removeEventListener("popupshowing", this, false);
+    this.contextMenu.removeEventListener("popupshowing", this._updateOverflowState, false);
+    this.contextMenu.removeEventListener("popupshowing", this._updateItemVisibilities, true);
 
     if (!this.populated)
       return;
 
     // If we're getting unloaded at runtime then we must remove all the
     // generated XUL nodes
     let oldParent = null;
     for (let item of internal(this.items).children) {
@@ -688,17 +692,17 @@ let MenuWrapper = Class({
     return this.contextMenu.querySelector("." + OVERFLOW_POPUP_CLASS);
   },
 
   get topLevelItems() {
     return this.contextMenu.querySelectorAll("." + TOPLEVEL_ITEM_CLASS);
   },
 
   get overflowItems() {
-    return this.contextMenu.querySelectorAll("." + OVERFLOW_ITEM_CLASS + " > ." + ITEM_CLASS);
+    return this.contextMenu.querySelectorAll("." + OVERFLOW_ITEM_CLASS);
   },
 
   getXULNodeForItem: function getXULNodeForItem(item) {
     return this.menuMap.get(item);
   },
 
   // Recurses through the item hierarchy creating XUL nodes for everything
   populate: function populate(menu) {
@@ -736,41 +740,21 @@ let MenuWrapper = Class({
 
   // Works out where to insert a XUL node for an item in a browser window
   insertIntoXUL: function insertIntoXUL(item, node, after) {
     let menupopup = null;
     let before = null;
 
     let menu = item.parentMenu;
     if (menu === this.items) {
+      // Insert into the overflow popup if it exists, otherwise the normal
+      // context menu
       menupopup = this.overflowPopup;
-
-      // If there isn't already an overflow menu then check if we need to
-      // create one, otherwise use the main context menu
-      if (!menupopup) {
+      if (!menupopup)
         menupopup = this.contextMenu;
-        let toplevel = this.topLevelItems;
-
-        if (toplevel.length >= MenuManager.overflowThreshold) {
-          // Create the overflow menu and move everything there
-          let overflowMenu = this.window.document.createElement("menu");
-          overflowMenu.setAttribute("class", OVERFLOW_MENU_CLASS);
-          overflowMenu.setAttribute("label", OVERFLOW_MENU_LABEL);
-          this.contextMenu.insertBefore(overflowMenu, this.separator.nextSibling);
-
-          menupopup = this.window.document.createElement("menupopup");
-          menupopup.setAttribute("class", OVERFLOW_POPUP_CLASS);
-          overflowMenu.appendChild(menupopup);
-
-          for (let xulNode of toplevel) {
-            menupopup.appendChild(xulNode);
-            this.updateXULClass(xulNode);
-          }
-        }
-      }
     }
     else {
       let xulNode = this.getXULNodeForItem(menu);
       menupopup = xulNode.firstChild;
     }
 
     if (after) {
       let afterNode = this.getXULNodeForItem(after);
@@ -834,17 +818,17 @@ let MenuWrapper = Class({
           xulNode.classList.add("menu-iconic");
         else
           xulNode.classList.add("menuitem-iconic");
       }
       if (item.data)
         xulNode.setAttribute("value", item.data);
 
       let self = this;
-      xulNode.addEventListener("click", function(event) {
+      xulNode.addEventListener("command", function(event) {
         // Only care about clicks directly on this item
         if (event.target !== xulNode)
           return;
 
         itemClicked(item, item, self.contextMenu.triggerNode);
       }, false);
     }
 
@@ -927,76 +911,113 @@ let MenuWrapper = Class({
       // If there are no more items then remove the separator
       if (toplevel.length == 0) {
         let separator = this.separator;
         if (separator)
           separator.parentNode.removeChild(separator);
       }
     }
     else if (parent == this.overflowPopup) {
+      // If there are no more items then remove the overflow menu and separator
       if (parent.childNodes.length == 0) {
-        // It's possible that this add-on had all the items in the overflow
-        // menu and they're now all gone, so remove the separator and overflow
-        // menu directly
-
         let separator = this.separator;
         separator.parentNode.removeChild(separator);
         this.contextMenu.removeChild(parent.parentNode);
       }
-      else if (parent.childNodes.length <= MenuManager.overflowThreshold) {
-        // Otherwise if the overflow menu is empty enough move everything in
-        // the overflow menu back to top level and remove the overflow menu
-
-        while (parent.firstChild) {
-          let node = parent.firstChild;
-          this.contextMenu.insertBefore(node, parent.parentNode);
-          this.updateXULClass(node);
-        }
-        this.contextMenu.removeChild(parent.parentNode);
-      }
     }
   },
 
-  handleEvent: function handleEvent(event) {
+  // Recurses through all the items owned by this module and sets their hidden
+  // state
+  updateItemVisibilities: function updateItemVisibilities(event) {
     try {
       if (event.type != "popupshowing")
         return;
       if (event.target != this.contextMenu)
         return;
 
       if (internal(this.items).children.length == 0)
         return;
 
       if (!this.populated) {
         this.populated = true;
         this.populate(this.items);
       }
 
-      let separator = this.separator;
-      let popup = this.overflowMenu;
-  
       let popupNode = event.target.triggerNode;
-      if (this.setVisibility(this.items, popupNode, PageContext().isCurrent(popupNode))) {
-        // Some of this instance's items are visible so make sure the separator
-        // and if necessary the overflow popup are visible
-        separator.hidden = false;
-        if (popup)
-          popup.hidden = false;
+      this.setVisibility(this.items, popupNode, PageContext().isCurrent(popupNode));
+    }
+    catch (e) {
+      console.exception(e);
+    }
+  },
+
+  // Counts the number of visible items across all modules and makes sure they
+  // are in the right place between the top level context menu and the overflow
+  // menu
+  updateOverflowState: function updateOverflowState(event) {
+    try {
+      if (event.type != "popupshowing")
+        return;
+      if (event.target != this.contextMenu)
+        return;
+
+      // The main items will be in either the top level context menu or the
+      // overflow menu at this point. Count the visible ones and if they are in
+      // the wrong place move them
+      let toplevel = this.topLevelItems;
+      let overflow = this.overflowItems;
+      let visibleCount = countVisibleItems(toplevel) +
+                         countVisibleItems(overflow);
+
+      if (visibleCount == 0) {
+        let separator = this.separator;
+        if (separator)
+          separator.hidden = true;
+        let overflowMenu = this.overflowMenu;
+        if (overflowMenu)
+          overflowMenu.hidden = true;
+      }
+      else if (visibleCount > MenuManager.overflowThreshold) {
+        this.separator.hidden = false;
+        let overflowPopup = this.overflowPopup;
+        if (overflowPopup)
+          overflowPopup.parentNode.hidden = false;
+
+        if (toplevel.length > 0) {
+          // The overflow menu shouldn't exist here but let's play it safe
+          if (!overflowPopup) {
+            let overflowMenu = this.window.document.createElement("menu");
+            overflowMenu.setAttribute("class", OVERFLOW_MENU_CLASS);
+            overflowMenu.setAttribute("label", OVERFLOW_MENU_LABEL);
+            this.contextMenu.insertBefore(overflowMenu, this.separator.nextSibling);
+
+            overflowPopup = this.window.document.createElement("menupopup");
+            overflowPopup.setAttribute("class", OVERFLOW_POPUP_CLASS);
+            overflowMenu.appendChild(overflowPopup);
+          }
+
+          for (let xulNode of toplevel) {
+            overflowPopup.appendChild(xulNode);
+            this.updateXULClass(xulNode);
+          }
+        }
       }
       else {
-        // We need to test whether any other instance has visible items.
-        // Get all the highest level items and see if any are visible.
-        let anyVisible = (Array.some(this.topLevelItems, function(item) !item.hidden)) ||
-                         (Array.some(this.overflowItems, function(item) !item.hidden));
-  
-        // If any were visible make sure the separator and if necessary the
-        // overflow popup are visible, otherwise hide them
-        separator.hidden = !anyVisible;
-        if (popup)
-          popup.hidden = !anyVisible;
+        this.separator.hidden = false;
+
+        if (overflow.length > 0) {
+          // Move all the overflow nodes out of the overflow menu and position
+          // them immediately before it
+          for (let xulNode of overflow) {
+            this.contextMenu.insertBefore(xulNode, xulNode.parentNode.parentNode);
+            this.updateXULClass(xulNode);
+          }
+          this.contextMenu.removeChild(this.overflowMenu);
+        }
       }
     }
     catch (e) {
       console.exception(e);
     }
   }
 });
 
--- a/addon-sdk/source/lib/sdk/tabs/tab-firefox.js
+++ b/addon-sdk/source/lib/sdk/tabs/tab-firefox.js
@@ -52,17 +52,21 @@ const TabTrait = Trait.compose(EventEmit
 
     // Since we will have to identify tabs by a DOM elements facade function
     // is used as constructor that collects all the instances and makes sure
     // that they more then one wrapper is not created per tab.
     return this;
   },
   destroy: function destroy() {
     this._removeAllListeners();
-    this._browser.removeEventListener(EVENTS.ready.dom, this._onReady, true);
+    if (this._tab) {
+      this._browser.removeEventListener(EVENTS.ready.dom, this._onReady, true);
+      this._tab = null;
+      TABS.splice(TABS.indexOf(this), 1);
+    }
   },
 
   /**
    * Internal listener that emits public event 'ready' when the page of this
    * tab is loaded.
    */
   _onReady: function _onReady(event) {
     // IFrames events will bubble so we need to ignore those.
@@ -93,107 +97,122 @@ const TabTrait = Trait.compose(EventEmit
   /**
    * Window object of the page that is currently loaded in this tab.
    */
   get _contentWindow() this._browser.contentWindow,
 
   /**
    * Unique id for the tab, actually maps to tab.linkedPanel but with some munging.
    */
-  get id() getTabId(this._tab),
+  get id() this._tab ? getTabId(this._tab) : undefined,
 
   /**
    * The title of the page currently loaded in the tab.
    * Changing this property changes an actual title.
    * @type {String}
    */
-  get title() getTabTitle(this._tab),
-  set title(title) setTabTitle(this._tab, title),
+  get title() this._tab ? getTabTitle(this._tab) : undefined,
+  set title(title) this._tab && setTabTitle(this._tab, title),
 
   /**
    * Returns the MIME type that the document loaded in the tab is being
    * rendered as.
    * @type {String}
    */
-  get contentType() getTabContentType(this._tab),
+  get contentType() this._tab ? getTabContentType(this._tab) : undefined,
 
   /**
    * Location of the page currently loaded in this tab.
    * Changing this property will loads page under under the specified location.
    * @type {String}
    */
-  get url() getTabURL(this._tab),
-  set url(url) setTabURL(this._tab, url),
+  get url() this._tab ? getTabURL(this._tab) : undefined,
+  set url(url) this._tab && setTabURL(this._tab, url),
   /**
    * URI of the favicon for the page currently loaded in this tab.
    * @type {String}
    */
-  get favicon() getFaviconURIForLocation(this.url),
+  get favicon() this._tab ? getFaviconURIForLocation(this.url) : undefined,
   /**
    * The CSS style for the tab
    */
   get style() null, // TODO
   /**
    * The index of the tab relative to other tabs in the application window.
    * Changing this property will change order of the actual position of the tab.
    * @type {Number}
    */
   get index()
-    this._window.gBrowser.getBrowserIndexForDocument(this._contentDocument),
-  set index(value) this._window.gBrowser.moveTabTo(this._tab, value),
+    this._tab ?
+    this._window.gBrowser.getBrowserIndexForDocument(this._contentDocument) :
+    undefined,
+  set index(value)
+    this._tab && this._window.gBrowser.moveTabTo(this._tab, value),
   /**
    * Thumbnail data URI of the page currently loaded in this tab.
    * @type {String}
    */
   getThumbnail: function getThumbnail()
-    getThumbnailURIForWindow(this._contentWindow),
+    this._tab ? getThumbnailURIForWindow(this._contentWindow) : undefined,
   /**
    * Whether or not tab is pinned (Is an app-tab).
    * @type {Boolean}
    */
-  get isPinned() this._tab.pinned,
+  get isPinned() this._tab ? this._tab.pinned : undefined,
   pin: function pin() {
+    if (!this._tab)
+      return;
     this._window.gBrowser.pinTab(this._tab);
   },
   unpin: function unpin() {
+    if (!this._tab)
+      return;
     this._window.gBrowser.unpinTab(this._tab);
   },
 
   /**
    * Create a worker for this tab, first argument is options given to Worker.
    * @type {Worker}
    */
   attach: function attach(options) {
+    if (!this._tab)
+      return;
     // BUG 792946 https://bugzilla.mozilla.org/show_bug.cgi?id=792946
     // TODO: fix this circular dependency
     let { Worker } = require('./worker');
     return Worker(options, this._contentWindow);
   },
 
   /**
    * Make this tab active.
    * Please note: That this function is called asynchronous since in E10S that
    * will be the case. Besides this function is called from a constructor where
    * we would like to return instance before firing a 'TabActivated' event.
    */
   activate: defer(function activate() {
+    if (!this._tab)
+      return;
     activateTab(this._tab);
   }),
   /**
    * Close the tab
    */
   close: function close(callback) {
+    if (!this._tab)
+      return;
     if (callback)
       this.once(EVENTS.close.name, callback);
     this._window.gBrowser.removeTab(this._tab);
   },
   /**
    * Reload the tab
    */
   reload: function reload() {
+    if (!this._tab)
+      return;
     this._window.gBrowser.reloadTab(this._tab);
   }
 });
 
 function Tab(options) {
   let chromeTab = options.tab;
   for each (let tab in TABS) {
     if (chromeTab == tab._tab)
--- a/addon-sdk/source/lib/sdk/windows/loader.js
+++ b/addon-sdk/source/lib/sdk/windows/loader.js
@@ -81,16 +81,19 @@ const WindowLoader = Trait.compose({
             ,
             false
           );
         }
         else { // If window is loaded calling listener next turn of event loop.
           this._onLoad(window)
         }
       }
+      else {
+        this.__window = null;
+      }
     }
   },
   __window: null,
   /**
    * Internal method used for listening 'load' event on the `_window`.
    * Method takes care of removing itself from 'load' event listeners once
    * event is being handled.
    */
--- a/addon-sdk/source/python-lib/cuddlefish/docs/generate.py
+++ b/addon-sdk/source/python-lib/cuddlefish/docs/generate.py
@@ -191,8 +191,9 @@ def write_file(env_root, doc_html, dest_
 def replace_file(env_root, dest_path, file_contents, must_rewrite_links):
     if os.path.exists(dest_path):
         os.remove(dest_path)
     # before we copy the final version, we'll rewrite the links
     # I'll do this last, just because we know definitely what the dest_path is at this point
     if must_rewrite_links and dest_path.endswith(".html"):
         file_contents = rewrite_links(env_root, get_sdk_docs_path(env_root), file_contents, dest_path)
     open(dest_path, "w").write(file_contents)
+
--- a/addon-sdk/source/python-lib/cuddlefish/rdf.py
+++ b/addon-sdk/source/python-lib/cuddlefish/rdf.py
@@ -164,17 +164,17 @@ def gen_manifest(template_root_dir, targ
         elem.appendChild(dom.createTextNode("{aa3c5121-dab2-40e2-81ca-7ea25febc110}"))
         ta_desc.appendChild(elem)
 
         elem = dom.createElement("em:minVersion")
         elem.appendChild(dom.createTextNode("18.0"))
         ta_desc.appendChild(elem)
 
         elem = dom.createElement("em:maxVersion")
-        elem.appendChild(dom.createTextNode("21.0a1"))
+        elem.appendChild(dom.createTextNode("20.*"))
         ta_desc.appendChild(elem)
 
     if target_cfg.get("homepage"):
         manifest.set("em:homepageURL", target_cfg.get("homepage"))
     else:
         manifest.remove("em:homepageURL")
 
     return manifest
--- a/addon-sdk/source/test/test-context-menu.js
+++ b/addon-sdk/source/test/test-context-menu.js
@@ -1,15 +1,17 @@
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-let {Cc,Ci} = require("chrome");
+ 'use strict';
+
+let { Cc, Ci } = require("chrome");
+
 const { Loader } = require('sdk/test/loader');
 const timer = require("sdk/timers");
 
 // These should match the same constants in the module.
 const ITEM_CLASS = "addon-context-menu-item";
 const SEPARATOR_CLASS = "addon-context-menu-separator";
 const OVERFLOW_THRESH_DEFAULT = 10;
 const OVERFLOW_THRESH_PREF =
@@ -475,16 +477,62 @@ exports.testURLContextRemove = function 
             });
           });
         });
       });
     });
   });
 };
 
+// Loading a new page in the same tab should correctly start a new worker for
+// any content scripts
+exports.testPageReload = function (test) {
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+
+  let item = loader.cm.Item({
+    label: "Item",
+    contentScript: "var doc = document; self.on('context', function(node) doc.body.getAttribute('showItem') == 'true');"
+  });
+
+  test.withTestDoc(function (window, doc) {
+    // Set a flag on the document that the item uses
+    doc.body.setAttribute("showItem", "true");
+
+    test.showMenu(null, function (popup) {
+      // With the attribute true the item should be visible in the menu
+      test.checkMenu([item], [], []);
+      test.hideMenu(function() {
+        let browser = this.tabBrowser.getBrowserForTab(this.tab)
+        test.delayedEventListener(browser, "load", function() {
+          test.delayedEventListener(browser, "load", function() {
+            window = browser.contentWindow;
+            doc = window.document;
+
+            // Set a flag on the document that the item uses
+            doc.body.setAttribute("showItem", "false");
+
+            test.showMenu(null, function (popup) {
+              // In the new document with the attribute false the item should be
+              // hidden, but if the contentScript hasn't been reloaded it will
+              // still see the old value
+              test.checkMenu([item], [item], []);
+
+              test.done();
+            });
+          }, true);
+          browser.loadURI(TEST_DOC_URL, null, null);
+        }, true);
+        // Required to make sure we load a new page in history rather than
+        // just reloading the current page which would unload it
+        browser.loadURI("about:blank", null, null);
+      });
+    });
+  });
+};
 
 // Closing a page after it's been used with a worker should cause the worker
 // to be destroyed
 /*exports.testWorkerDestroy = function (test) {
   test = new TestHelper(test);
   let loader = test.newLoader();
 
   let loadExpected = false;
@@ -550,16 +598,153 @@ exports.testContentContextNoMatch = func
 
   test.showMenu(null, function (popup) {
     test.checkMenu([item], [item], []);
     test.done();
   });
 };
 
 
+// Content contexts that return undefined should cause their items to be absent
+// from the menu.
+exports.testContentContextUndefined = function (test) {
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+
+  let item = new loader.cm.Item({
+    label: "item",
+    contentScript: 'self.on("context", function () {});'
+  });
+
+  test.showMenu(null, function (popup) {
+    test.checkMenu([item], [item], []);
+    test.done();
+  });
+};
+
+
+// Content contexts that return an empty string should cause their items to be
+// absent from the menu and shouldn't wipe the label
+exports.testContentContextEmptyString = function (test) {
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+
+  let item = new loader.cm.Item({
+    label: "item",
+    contentScript: 'self.on("context", function () "");'
+  });
+
+  test.showMenu(null, function (popup) {
+    test.checkMenu([item], [item], []);
+    test.assertEqual(item.label, "item", "Label should still be correct");
+    test.done();
+  });
+};
+
+
+// If any content contexts returns true then their items should be present in
+// the menu.
+exports.testMultipleContentContextMatch1 = function (test) {
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+
+  let item = new loader.cm.Item({
+    label: "item",
+    contentScript: 'self.on("context", function () true); ' +
+                   'self.on("context", function () false);',
+    onMessage: function() {
+      test.fail("Should not have called the second context listener");
+    }
+  });
+
+  test.showMenu(null, function (popup) {
+    test.checkMenu([item], [], []);
+    test.done();
+  });
+};
+
+
+// If any content contexts returns true then their items should be present in
+// the menu.
+exports.testMultipleContentContextMatch2 = function (test) {
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+
+  let item = new loader.cm.Item({
+    label: "item",
+    contentScript: 'self.on("context", function () false); ' +
+                   'self.on("context", function () true);'
+  });
+
+  test.showMenu(null, function (popup) {
+    test.checkMenu([item], [], []);
+    test.done();
+  });
+};
+
+
+// If any content contexts returns a string then their items should be present
+// in the menu.
+exports.testMultipleContentContextString1 = function (test) {
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+
+  let item = new loader.cm.Item({
+    label: "item",
+    contentScript: 'self.on("context", function () "new label"); ' +
+                   'self.on("context", function () false);'
+  });
+
+  test.showMenu(null, function (popup) {
+    test.checkMenu([item], [], []);
+    test.assertEqual(item.label, "new label", "Label should have changed");
+    test.done();
+  });
+};
+
+
+// If any content contexts returns a string then their items should be present
+// in the menu.
+exports.testMultipleContentContextString2 = function (test) {
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+
+  let item = new loader.cm.Item({
+    label: "item",
+    contentScript: 'self.on("context", function () false); ' +
+                   'self.on("context", function () "new label");'
+  });
+
+  test.showMenu(null, function (popup) {
+    test.checkMenu([item], [], []);
+    test.assertEqual(item.label, "new label", "Label should have changed");
+    test.done();
+  });
+};
+
+
+// If many content contexts returns a string then the first should take effect
+exports.testMultipleContentContextString3 = function (test) {
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+
+  let item = new loader.cm.Item({
+    label: "item",
+    contentScript: 'self.on("context", function () "new label 1"); ' +
+                   'self.on("context", function () "new label 2");'
+  });
+
+  test.showMenu(null, function (popup) {
+    test.checkMenu([item], [], []);
+    test.assertEqual(item.label, "new label 1", "Label should have changed");
+    test.done();
+  });
+};
+
+
 // Content contexts that return true should cause their items to be present
 // in the menu when context clicking an active element.
 exports.testContentContextMatchActiveElement = function (test) {
   test = new TestHelper(test);
   let loader = test.newLoader();
 
   let items = [
     new loader.cm.Item({
@@ -626,16 +811,54 @@ exports.testContentContextNoMatchActiveE
     test.showMenu(doc.getElementById("image"), function (popup) {
       test.checkMenu(items, items, []);
       test.done();
     });
   });
 };
 
 
+// Content contexts that return undefined should cause their items to be absent
+// from the menu when context clicking an active element.
+exports.testContentContextNoMatchActiveElement = function (test) {
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+
+  let items = [
+    new loader.cm.Item({
+      label: "item 1",
+      contentScript: 'self.on("context", function () {});'
+    }),
+    new loader.cm.Item({
+      label: "item 2",
+      context: undefined,
+      contentScript: 'self.on("context", function () {});'
+    }),
+    // These items will always be hidden by the declarative usage of PageContext
+    new loader.cm.Item({
+      label: "item 3",
+      context: loader.cm.PageContext(),
+      contentScript: 'self.on("context", function () {});'
+    }),
+    new loader.cm.Item({
+      label: "item 4",
+      context: [loader.cm.PageContext()],
+      contentScript: 'self.on("context", function () {});'
+    })
+  ];
+
+  test.withTestDoc(function (window, doc) {
+    test.showMenu(doc.getElementById("image"), function (popup) {
+      test.checkMenu(items, items, []);
+      test.done();
+    });
+  });
+};
+
+
 // Content contexts that return a string should cause their items to be present
 // in the menu and the items' labels to be updated.
 exports.testContentContextMatchString = function (test) {
   test = new TestHelper(test);
   let loader = test.newLoader();
 
   let item = new loader.cm.Item({
     label: "first label",
@@ -794,17 +1017,17 @@ exports.testUnload = function (test) {
       test.checkMenu([item], [], [item]);
       test.done();
     });
   });
 };
 
 
 // Using multiple module instances to add items without causing overflow should
-// work OK.  Assumes OVERFLOW_THRESH_DEFAULT <= 2.
+// work OK.  Assumes OVERFLOW_THRESH_DEFAULT >= 2.
 exports.testMultipleModulesAdd = function (test) {
   test = new TestHelper(test);
   let loader0 = test.newLoader();
   let loader1 = test.newLoader();
 
   // Use each module to add an item, then unload each module in turn.
   let item0 = new loader0.cm.Item({ label: "item 0" });
   let item1 = new loader1.cm.Item({ label: "item 1" });
@@ -1159,24 +1382,418 @@ exports.testMultipleModulesOrderOverflow
       popup.hidePopup();
 
       let item3 = new loader1.cm.Item({ label: "item 3" });
 
       test.showMenu(null, function (popup) {
 
         // Same again
         test.checkMenu([item0, item2, item1, item3], [], []);
-        prefs.set(OVERFLOW_THRESH_PREF, OVERFLOW_THRESH_DEFAULT);
         test.done();
       });
     });
   });
 };
 
 
+// Checks that if a module's items are all hidden then the overflow menu doesn't
+// get hidden
+exports.testMultipleModulesOverflowHidden = function (test) {
+  test = new TestHelper(test);
+  let loader0 = test.newLoader();
+  let loader1 = test.newLoader();
+
+  let prefs = loader0.loader.require("preferences-service");
+  prefs.set(OVERFLOW_THRESH_PREF, 0);
+
+  // Use each module to add an item, then unload each module in turn.
+  let item0 = new loader0.cm.Item({ label: "item 0" });
+  let item1 = new loader1.cm.Item({
+    label: "item 1",
+    context: loader1.cm.SelectorContext("a")
+  });
+
+  test.showMenu(null, function (popup) {
+    // One should be hidden
+    test.checkMenu([item0, item1], [item1], []);
+    test.done();
+  });
+};
+
+
+// Checks that if a module's items are all hidden then the overflow menu doesn't
+// get hidden (reverse order to above)
+exports.testMultipleModulesOverflowHidden2 = function (test) {
+  test = new TestHelper(test);
+  let loader0 = test.newLoader();
+  let loader1 = test.newLoader();
+
+  let prefs = loader0.loader.require("preferences-service");
+  prefs.set(OVERFLOW_THRESH_PREF, 0);
+
+  // Use each module to add an item, then unload each module in turn.
+  let item0 = new loader0.cm.Item({
+    label: "item 0",
+    context: loader0.cm.SelectorContext("a")
+  });
+  let item1 = new loader1.cm.Item({ label: "item 1" });
+
+  test.showMenu(null, function (popup) {
+    // One should be hidden
+    test.checkMenu([item0, item1], [item0], []);
+    test.done();
+  });
+};
+
+
+// Checks that we don't overflow if there are more items than the overflow
+// threshold but not all of them are visible
+exports.testOverflowIgnoresHidden = function (test) {
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+
+  let prefs = loader.loader.require("preferences-service");
+  prefs.set(OVERFLOW_THRESH_PREF, 2);
+
+  let allItems = [
+    new loader.cm.Item({
+      label: "item 0"
+    }),
+    new loader.cm.Item({
+      label: "item 1"
+    }),
+    new loader.cm.Item({
+      label: "item 2",
+      context: loader.cm.SelectorContext("a")
+    })
+  ];
+
+  test.showMenu(null, function (popup) {
+    // One should be hidden
+    test.checkMenu(allItems, [allItems[2]], []);
+    test.done();
+  });
+};
+
+
+// Checks that we don't overflow if there are more items than the overflow
+// threshold but not all of them are visible
+exports.testOverflowIgnoresHiddenMultipleModules1 = function (test) {
+  test = new TestHelper(test);
+  let loader0 = test.newLoader();
+  let loader1 = test.newLoader();
+
+  let prefs = loader0.loader.require("preferences-service");
+  prefs.set(OVERFLOW_THRESH_PREF, 2);
+
+  let allItems = [
+    new loader0.cm.Item({
+      label: "item 0"
+    }),
+    new loader0.cm.Item({
+      label: "item 1"
+    }),
+    new loader1.cm.Item({
+      label: "item 2",
+      context: loader1.cm.SelectorContext("a")
+    }),
+    new loader1.cm.Item({
+      label: "item 3",
+      context: loader1.cm.SelectorContext("a")
+    })
+  ];
+
+  test.showMenu(null, function (popup) {
+    // One should be hidden
+    test.checkMenu(allItems, [allItems[2], allItems[3]], []);
+    test.done();
+  });
+};
+
+
+// Checks that we don't overflow if there are more items than the overflow
+// threshold but not all of them are visible
+exports.testOverflowIgnoresHiddenMultipleModules2 = function (test) {
+  test = new TestHelper(test);
+  let loader0 = test.newLoader();
+  let loader1 = test.newLoader();
+
+  let prefs = loader0.loader.require("preferences-service");
+  prefs.set(OVERFLOW_THRESH_PREF, 2);
+
+  let allItems = [
+    new loader0.cm.Item({
+      label: "item 0"
+    }),
+    new loader0.cm.Item({
+      label: "item 1",
+      context: loader0.cm.SelectorContext("a")
+    }),
+    new loader1.cm.Item({
+      label: "item 2"
+    }),
+    new loader1.cm.Item({
+      label: "item 3",
+      context: loader1.cm.SelectorContext("a")
+    })
+  ];
+
+  test.showMenu(null, function (popup) {
+    // One should be hidden
+    test.checkMenu(allItems, [allItems[1], allItems[3]], []);
+    test.done();
+  });
+};
+
+
+// Checks that we don't overflow if there are more items than the overflow
+// threshold but not all of them are visible
+exports.testOverflowIgnoresHiddenMultipleModules3 = function (test) {
+  test = new TestHelper(test);
+  let loader0 = test.newLoader();
+  let loader1 = test.newLoader();
+
+  let prefs = loader0.loader.require("preferences-service");
+  prefs.set(OVERFLOW_THRESH_PREF, 2);
+
+  let allItems = [
+    new loader0.cm.Item({
+      label: "item 0",
+      context: loader0.cm.SelectorContext("a")
+    }),
+    new loader0.cm.Item({
+      label: "item 1",
+      context: loader0.cm.SelectorContext("a")
+    }),
+    new loader1.cm.Item({
+      label: "item 2"
+    }),
+    new loader1.cm.Item({
+      label: "item 3"
+    })
+  ];
+
+  test.showMenu(null, function (popup) {
+    // One should be hidden
+    test.checkMenu(allItems, [allItems[0], allItems[1]], []);
+    test.done();
+  });
+};
+
+
+// Tests that we transition between overflowing to non-overflowing to no items
+// and back again
+exports.testOverflowTransition = function (test) {
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+
+  let prefs = loader.loader.require("preferences-service");
+  prefs.set(OVERFLOW_THRESH_PREF, 2);
+
+  let pItems = [
+    new loader.cm.Item({
+      label: "item 0",
+      context: loader.cm.SelectorContext("p")
+    }),
+    new loader.cm.Item({
+      label: "item 1",
+      context: loader.cm.SelectorContext("p")
+    })
+  ];
+
+  let aItems = [
+    new loader.cm.Item({
+      label: "item 2",
+      context: loader.cm.SelectorContext("a")
+    }),
+    new loader.cm.Item({
+      label: "item 3",
+      context: loader.cm.SelectorContext("a")
+    })
+  ];
+
+  let allItems = pItems.concat(aItems);
+
+  test.withTestDoc(function (window, doc) {
+    test.showMenu(doc.getElementById("link"), function (popup) {
+      // The menu should contain all items and will overflow
+      test.checkMenu(allItems, [], []);
+      popup.hidePopup();
+
+      test.showMenu(doc.getElementById("text"), function (popup) {
+        // Only contains hald the items and will not overflow
+        test.checkMenu(allItems, aItems, []);
+        popup.hidePopup();
+
+        test.showMenu(null, function (popup) {
+          // None of the items will be visible
+          test.checkMenu(allItems, allItems, []);
+          popup.hidePopup();
+
+          test.showMenu(doc.getElementById("text"), function (popup) {
+            // Only contains hald the items and will not overflow
+            test.checkMenu(allItems, aItems, []);
+            popup.hidePopup();
+
+            test.showMenu(doc.getElementById("link"), function (popup) {
+              // The menu should contain all items and will overflow
+              test.checkMenu(allItems, [], []);
+              popup.hidePopup();
+
+              test.showMenu(null, function (popup) {
+                // None of the items will be visible
+                test.checkMenu(allItems, allItems, []);
+                popup.hidePopup();
+
+                test.showMenu(doc.getElementById("link"), function (popup) {
+                  // The menu should contain all items and will overflow
+                  test.checkMenu(allItems, [], []);
+                  test.done();
+                });
+              });
+            });
+          });
+        });
+      });
+    });
+  });
+};
+
+
+// An item's command listener should work.
+exports.testItemCommand = function (test) {
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+
+  let item = new loader.cm.Item({
+    label: "item",
+    data: "item data",
+    contentScript: 'self.on("click", function (node, data) {' +
+                   '  self.postMessage({' +
+                   '    tagName: node.tagName,' +
+                   '    data: data' +
+                   '  });' +
+                   '});',
+    onMessage: function (data) {
+      test.assertEqual(this, item, "`this` inside onMessage should be item");
+      test.assertEqual(data.tagName, "HTML", "node should be an HTML element");
+      test.assertEqual(data.data, item.data, "data should be item data");
+      test.done();
+    }
+  });
+
+  test.showMenu(null, function (popup) {
+    test.checkMenu([item], [], []);
+    let elt = test.getItemElt(popup, item);
+
+    // create a command event
+    let evt = elt.ownerDocument.createEvent('Event');
+    evt.initEvent('command', true, true);
+    elt.dispatchEvent(evt);
+  });
+};
+
+
+// A menu's click listener should work and receive bubbling 'command' events from
+// sub-items appropriately.  This also tests menus and ensures that when a CSS
+// selector context matches the clicked node's ancestor, the matching ancestor
+// is passed to listeners as the clicked node.
+exports.testMenuCommand = function (test) {
+  // Create a top-level menu, submenu, and item, like this:
+  // topMenu -> submenu -> item
+  // Click the item and make sure the click bubbles.
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+
+  let item = new loader.cm.Item({
+    label: "submenu item",
+    data: "submenu item data",
+    context: loader.cm.SelectorContext("a"),
+  });
+
+  let submenu = new loader.cm.Menu({
+    label: "submenu",
+    context: loader.cm.SelectorContext("a"),
+    items: [item]
+  });
+
+  let topMenu = new loader.cm.Menu({
+    label: "top menu",
+    contentScript: 'self.on("click", function (node, data) {' +
+                   '  let Ci = Components["interfaces"];' +
+                   '  self.postMessage({' +
+                   '    tagName: node.tagName,' +
+                   '    data: data' +
+                   '  });' +
+                   '});',
+    onMessage: function (data) {
+      test.assertEqual(this, topMenu, "`this` inside top menu should be menu");
+      test.assertEqual(data.tagName, "A", "Clicked node should be anchor");
+      test.assertEqual(data.data, item.data,
+                       "Clicked item data should be correct");
+      test.done();
+    },
+    items: [submenu],
+    context: loader.cm.SelectorContext("a")
+  });
+
+  test.withTestDoc(function (window, doc) {
+    test.showMenu(doc.getElementById("span-link"), function (popup) {
+      test.checkMenu([topMenu], [], []);
+      let topMenuElt = test.getItemElt(popup, topMenu);
+      let topMenuPopup = topMenuElt.firstChild;
+      let submenuElt = test.getItemElt(topMenuPopup, submenu);
+      let submenuPopup = submenuElt.firstChild;
+      let itemElt = test.getItemElt(submenuPopup, item);
+
+      // create a command event
+      let evt = itemElt.ownerDocument.createEvent('Event');
+      evt.initEvent('command', true, true);
+      itemElt.dispatchEvent(evt);
+    });
+  });
+};
+
+
+// Click listeners should work when multiple modules are loaded.
+exports.testItemCommandMultipleModules = function (test) {
+  test = new TestHelper(test);
+  let loader0 = test.newLoader();
+  let loader1 = test.newLoader();
+
+  let item0 = loader0.cm.Item({
+    label: "loader 0 item",
+    contentScript: 'self.on("click", self.postMessage);',
+    onMessage: function () {
+      test.fail("loader 0 item should not emit click event");
+    }
+  });
+  let item1 = loader1.cm.Item({
+    label: "loader 1 item",
+    contentScript: 'self.on("click", self.postMessage);',
+    onMessage: function () {
+      test.pass("loader 1 item clicked as expected");
+      test.done();
+    }
+  });
+
+  test.showMenu(null, function (popup) {
+    test.checkMenu([item0, item1], [], []);
+    let item1Elt = test.getItemElt(popup, item1);
+
+    // create a command event
+    let evt = item1Elt.ownerDocument.createEvent('Event');
+    evt.initEvent('command', true, true);
+    item1Elt.dispatchEvent(evt);
+  });
+};
+
+
+
+
 // An item's click listener should work.
 exports.testItemClick = function (test) {
   test = new TestHelper(test);
   let loader = test.newLoader();
 
   let item = new loader.cm.Item({
     label: "item",
     data: "item data",
@@ -1521,16 +2138,17 @@ exports.testDrawImageOnClickNode = funct
     });
     test.showMenu(doc.getElementById("image"), function (popup) {
       test.checkMenu([item], [], []);
       test.getItemElt(popup, item).click();
     });
   });
 };
 
+
 // Setting an item's label before the menu is ever shown should correctly change
 // its label.
 exports.testSetLabelBeforeShow = function (test) {
   test = new TestHelper(test);
   let loader = test.newLoader();
 
   let items = [
     new loader.cm.Item({ label: "a" }),
@@ -1584,17 +2202,16 @@ exports.testSetLabelBeforeShowOverflow =
     new loader.cm.Item({ label: "a" }),
     new loader.cm.Item({ label: "b" })
   ]
   items[0].label = "z";
   test.assertEqual(items[0].label, "z");
 
   test.showMenu(null, function (popup) {
     test.checkMenu(items, [], []);
-    prefs.set(OVERFLOW_THRESH_PREF, OVERFLOW_THRESH_DEFAULT);
     test.done();
   });
 };
 
 
 // Setting an item's label after the menu is shown should correctly change its
 // label.
 exports.testSetLabelAfterShowOverflow = function (test) {
@@ -1612,17 +2229,16 @@ exports.testSetLabelAfterShowOverflow = 
   test.showMenu(null, function (popup) {
     test.checkMenu(items, [], []);
     popup.hidePopup();
 
     items[0].label = "z";
     test.assertEqual(items[0].label, "z");
     test.showMenu(null, function (popup) {
       test.checkMenu(items, [], []);
-      prefs.set(OVERFLOW_THRESH_PREF, OVERFLOW_THRESH_DEFAULT);
       test.done();
     });
   });
 };
 
 
 // Setting the label of an item in a Menu should work.
 exports.testSetLabelMenuItem = function (test) {
@@ -2085,16 +2701,18 @@ exports.testSubItemDefaultVisible = func
   test.withTestDoc(function (window, doc) {
     test.showMenu(doc.getElementById("image"), function (popup) {
       test.checkMenu(items, hiddenItems, []);
       test.done();
     });
   });
 };
 
+// Tests that the click event on sub menuitem
+// tiggers the click event for the sub menuitem and the parent menu
 exports.testSubItemClick = function (test) {
   test = new TestHelper(test);
   let loader = test.newLoader();
 
   let state = 0;
 
   let items = [
     loader.cm.Menu({
@@ -2140,16 +2758,78 @@ exports.testSubItemClick = function (tes
       let topMenuElt = test.getItemElt(popup, items[0]);
       let topMenuPopup = topMenuElt.firstChild;
       let itemElt = test.getItemElt(topMenuPopup, items[0].items[0]);
       itemElt.click();
     });
   });
 };
 
+// Tests that the command event on sub menuitem
+// tiggers the click event for the sub menuitem and the parent menu
+exports.testSubItemCommand = function (test) {
+  test = new TestHelper(test);
+  let loader = test.newLoader();
+
+  let state = 0;
+
+  let items = [
+    loader.cm.Menu({
+      label: "menu 1",
+      items: [
+        loader.cm.Item({
+          label: "subitem 1",
+          data: "foobar",
+          contentScript: 'self.on("click", function (node, data) {' +
+                         '  self.postMessage({' +
+                         '    tagName: node.tagName,' +
+                         '    data: data' +
+                         '  });' +
+                         '});',
+          onMessage: function(msg) {
+            test.assertEqual(msg.tagName, "HTML", "should have seen the right node");
+            test.assertEqual(msg.data, "foobar", "should have seen the right data");
+            test.assertEqual(state, 0, "should have seen the event at the right time");
+            state++;
+          }
+        })
+      ],
+      contentScript: 'self.on("click", function (node, data) {' +
+                     '  self.postMessage({' +
+                     '    tagName: node.tagName,' +
+                     '    data: data' +
+                     '  });' +
+                     '});',
+      onMessage: function(msg) {
+        test.assertEqual(msg.tagName, "HTML", "should have seen the right node");
+        test.assertEqual(msg.data, "foobar", "should have seen the right data");
+        test.assertEqual(state, 1, "should have seen the event at the right time");
+        state++
+
+        test.done();
+      }
+    })
+  ];
+
+  test.withTestDoc(function (window, doc) {
+    test.showMenu(null, function (popup) {
+      test.checkMenu(items, [], []);
+
+      let topMenuElt = test.getItemElt(popup, items[0]);
+      let topMenuPopup = topMenuElt.firstChild;
+      let itemElt = test.getItemElt(topMenuPopup, items[0].items[0]);
+
+      // create a command event
+      let evt = itemElt.ownerDocument.createEvent('Event');
+      evt.initEvent('command', true, true);
+      itemElt.dispatchEvent(evt);
+    });
+  });
+};
+
 // Tests that opening a context menu for an outer frame when an inner frame
 // has a selection doesn't activate the SelectionContext
 exports.testSelectionInInnerFrameNoMatch = function (test) {
   test = new TestHelper(test);
   let loader = test.newLoader();
 
   let state = 0;
 
@@ -2244,16 +2924,18 @@ function TestHelper(test) {
   // default waitUntilDone timeout is 10s, which is too short on the win7
   // buildslave
   test.waitUntilDone(30*1000);
   this.test = test;
   this.loaders = [];
   this.browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"].
                        getService(Ci.nsIWindowMediator).
                        getMostRecentWindow("navigator:browser");
+  this.overflowThreshValue = require("sdk/preferences/service").
+                             get(OVERFLOW_THRESH_PREF, OVERFLOW_THRESH_DEFAULT);
 }
 
 TestHelper.prototype = {
   get contextMenuPopup() {
     return this.browserWindow.document.getElementById("contentAreaContextMenu");
   },
 
   get contextMenuSeparator() {
@@ -2346,47 +3028,58 @@ TestHelper.prototype = {
     else {
       this.test.assert(separator && !separator.hidden,
                        "separator should be present");
     }
 
     let mainNodes = this.browserWindow.document.querySelectorAll("#contentAreaContextMenu > ." + ITEM_CLASS);
     let overflowNodes = this.browserWindow.document.querySelectorAll("." + OVERFLOW_POPUP_CLASS + " > ." + ITEM_CLASS);
 
+    this.test.assert(mainNodes.length == 0 || overflowNodes.length == 0,
+                     "Should only see nodes at the top level or in overflow");
+
     let overflow = this.overflowSubmenu;
     if (this.shouldOverflow(total)) {
       this.test.assert(overflow && !overflow.hidden,
                        "overflow menu should be present");
       this.test.assertEqual(mainNodes.length, 0,
                             "should be no items in the main context menu");
     }
     else {
       this.test.assert(!overflow || overflow.hidden,
                        "overflow menu should not be present");
-      this.test.assertEqual(overflowNodes.length, 0,
-                            "should be no items in the overflow context menu");
+      // When visible nodes == 0 they could be in overflow or top level
+      if (total > 0) {
+        this.test.assertEqual(overflowNodes.length, 0,
+                              "should be no items in the overflow context menu");
+      }
     }
 
-    let nodes = this.shouldOverflow(total) ? overflowNodes : mainNodes;
-
+    // Iterate over wherever the nodes have ended up
+    let nodes = mainNodes.length ? mainNodes : overflowNodes;
     this.checkNodes(nodes, presentItems, absentItems, removedItems)
     let pos = 0;
   },
 
   // Recurses through the item hierarchy of presentItems comparing it to the
   // node hierarchy of nodes. Any items in removedItems will be skipped (so
   // should not exist in the XUL), any items in absentItems must exist and be
   // hidden
   checkNodes: function (nodes, presentItems, absentItems, removedItems) {
     let pos = 0;
     for (let item of presentItems) {
       // Removed items shouldn't be in the list
       if (removedItems.indexOf(item) >= 0)
         continue;
 
+      if (nodes.length <= pos) {
+        this.test.assert(false, "Not enough nodes");
+        return;
+      }
+
       let hidden = absentItems.indexOf(item) >= 0;
 
       this.checkItemElt(nodes[pos], item);
       this.test.assertEqual(nodes[pos].hidden, hidden,
                             "hidden should be set correctly");
 
       // The contents of hidden menus doesn't matter so much
       if (!hidden && this.getItemType(item) == "Menu") {
@@ -2427,22 +3120,26 @@ TestHelper.prototype = {
           self.test.done();
         }
       }, 20);
     }, useCapture);
   },
 
   // Call to finish the test.
   done: function () {
+    const self = this;
     function commonDone() {
       this.closeTab();
 
       while (this.loaders.length) {
         this.loaders[0].unload();
       }
+
+      require("sdk/preferences/service").set(OVERFLOW_THRESH_PREF, self.overflowThreshValue);
+
       this.test.done();
     }
 
     function closeBrowserWindow() {
       if (this.oldBrowserWindow) {
         this.delayedEventListener(this.browserWindow, "unload", commonDone,
                                   false);
         this.browserWindow.close();
--- a/addon-sdk/source/test/test-httpd.js
+++ b/addon-sdk/source/test/test-httpd.js
@@ -1,32 +1,28 @@
 /* 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/. */
 
 const port = 8099;
 const file = require("sdk/io/file");
 const { pathFor } = require("sdk/system");
-const { Loader } = require("sdk/test/loader");
-const options = require("@test/options");
-
-const loader = Loader(module);
-const httpd = loader.require("sdk/test/httpd");
-if (options.parseable || options.verbose)
-  loader.sandbox("sdk/test/httpd").DEBUG = true;
 
 exports.testBasicHTTPServer = function(test) {
-  let basePath = pathFor("TmpD");
+  // Use the profile directory for the temporary file as that will be deleted
+  // when tests are complete
+  let basePath = pathFor("ProfD");
   let filePath = file.join(basePath, 'test-httpd.txt');
   let content = "This is the HTTPD test file.\n";
   let fileStream = file.open(filePath, 'w');
   fileStream.write(content);
   fileStream.close();
 
-  let srv = httpd.startServerAsync(port, basePath);
+  let { startServerAsync } = require("sdk/test/httpd");
+  let srv = startServerAsync(port, basePath);
 
   test.waitUntilDone();
 
   // Request this very file.
   let Request = require('sdk/request').Request;
   Request({
     url: "http://localhost:" + port + "/test-httpd.txt",
     onComplete: function (response) {
@@ -40,17 +36,18 @@ exports.testBasicHTTPServer = function(t
       test.done();
     });
   }
 };
 
 exports.testDynamicServer = function (test) {
   let content = "This is the HTTPD test file.\n";
 
-  let srv = httpd.startServerAsync(port);
+  let { startServerAsync } = require("sdk/test/httpd");
+  let srv = startServerAsync(port);
 
   // See documentation here:
   //http://doxygen.db48x.net/mozilla/html/interfacensIHttpServer.html#a81fc7e7e29d82aac5ce7d56d0bedfb3a
   //http://doxygen.db48x.net/mozilla/html/interfacensIHttpRequestHandler.html
   srv.registerPathHandler("/test-httpd.txt", function handle(request, response) {
     // Add text content type, only to avoid error in `Request` API
     response.setHeader("Content-Type", "text/plain", false);
     response.write(content);
--- a/addon-sdk/source/test/test-page-mod.js
+++ b/addon-sdk/source/test/test-page-mod.js
@@ -1024,8 +1024,9 @@ if (require("sdk/system/xul-app").is("Fe
   module.exports = {
     "test Unsupported Test": function UnsupportedTest (test) {
         test.pass(
           "Skipping this test until Fennec support is implemented." +
           "See bug 784224");
     }
   }
 }
+
--- a/addon-sdk/source/test/test-private-browsing.js
+++ b/addon-sdk/source/test/test-private-browsing.js
@@ -23,8 +23,9 @@ exports.testWindowDefaults = function(te
   test.assertEqual(pbUtils.isWindowPrivate(chromeWin), false);
 }
 
 // tests for the case where private browsing doesn't exist
 exports.testIsActiveDefault = function(test) {
   test.assertEqual(pb.isActive, false,
                    'pb.isActive returns false when private browsing isn\'t supported');
 };
+
--- a/addon-sdk/source/test/test-request.js
+++ b/addon-sdk/source/test/test-request.js
@@ -10,17 +10,19 @@ const { Loader } = require("sdk/test/loa
 const options = require("@test/options");
 
 const loader = Loader(module);
 const httpd = loader.require("sdk/test/httpd");
 if (options.parseable || options.verbose)
   loader.sandbox("sdk/test/httpd").DEBUG = true;
 const { startServerAsync } = httpd;
 
-const basePath = pathFor("TmpD")
+// Use the profile directory for the temporary files as that will be deleted
+// when tests are complete
+const basePath = pathFor("ProfD")
 const port = 8099;
 
 
 exports.testOptionsValidator = function(test) {
   // First, a simple test to make sure we didn't break normal functionality.
   test.assertRaises(function () {
     Request({
       url: null
--- a/addon-sdk/source/test/test-tab.js
+++ b/addon-sdk/source/test/test-tab.js
@@ -104,16 +104,38 @@ function step3(assert, done) {
   assert.equal(matchedTab, primaryTab,
     "We get the correct tab even when it's in the background");
 
   primaryTab.close(function () {
       auxTab.close(function () { done();});
     });
 }
 
+exports["test behavior on close"] = function(assert, done) {
+
+  tabs.open({
+    url: "about:mozilla",
+    onReady: function(tab) {
+      assert.equal(tab.url, "about:mozilla", "Tab has the expected url");
+      assert.equal(tab.index, 1, "Tab has the expected index");
+      tab.close(function () {
+        assert.equal(tab.url, undefined,
+                     "After being closed, tab attributes are undefined (url)");
+        assert.equal(tab.index, undefined,
+                     "After being closed, tab attributes are undefined (index)");
+        // Ensure that we can call destroy multiple times without throwing
+        tab.destroy();
+        tab.destroy();
+
+        done();
+      });
+    }
+  });
+};
+
 if (require("sdk/system/xul-app").is("Fennec")) {
   module.exports = {
     "test Unsupported Test": function UnsupportedTest (assert) {
         assert.pass(
           "Skipping this test until Fennec support is implemented." +
           "See Bug 809362");
     }
   }
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -541,47 +541,55 @@ pref("dom.workers.mem.gc_allocation_thre
 // Show/Hide scrollbars when active/inactive
 pref("ui.showHideScrollbars", 1);
 
 // Enable the ProcessPriorityManager, and give processes with no visible
 // documents a 1s grace period before they're eligible to be marked as
 // background.
 pref("dom.ipc.processPriorityManager.enabled", true);
 pref("dom.ipc.processPriorityManager.backgroundGracePeriodMS", 1000);
-pref("dom.ipc.processPriorityManager.temporaryPriorityMS", 5000);
+pref("dom.ipc.processPriorityManager.temporaryPriorityLockMS", 5000);
 
 // Kernel parameters for how processes are killed on low-memory.
 pref("gonk.systemMemoryPressureRecoveryPollMS", 5000);
 pref("hal.processPriorityManager.gonk.masterOomScoreAdjust", 0);
 pref("hal.processPriorityManager.gonk.masterKillUnderMB", 1);
-pref("hal.processPriorityManager.gonk.foregroundOomScoreAdjust", 67);
+pref("hal.processPriorityManager.gonk.foregroundHighOomScoreAdjust", 67);
+pref("hal.processPriorityManager.gonk.foregroundHighKillUnderMB", 3);
+pref("hal.processPriorityManager.gonk.foregroundOomScoreAdjust", 134);
 pref("hal.processPriorityManager.gonk.foregroundKillUnderMB", 4);
-pref("hal.processPriorityManager.gonk.backgroundPerceivableOomScoreAdjust", 134);
+pref("hal.processPriorityManager.gonk.backgroundPerceivableOomScoreAdjust", 200);
 pref("hal.processPriorityManager.gonk.backgroundPerceivableKillUnderMB", 5);
-pref("hal.processPriorityManager.gonk.backgroundHomescreenOomScoreAdjust", 200);
+pref("hal.processPriorityManager.gonk.backgroundHomescreenOomScoreAdjust", 267);
 pref("hal.processPriorityManager.gonk.backgroundHomescreenKillUnderMB", 5);
 pref("hal.processPriorityManager.gonk.backgroundOomScoreAdjust", 400);
 pref("hal.processPriorityManager.gonk.backgroundKillUnderMB", 8);
 pref("hal.processPriorityManager.gonk.notifyLowMemUnderMB", 10);
 
 // Niceness values (i.e., CPU priorities) for B2G processes.
 pref("hal.processPriorityManager.gonk.masterNice", 0);
+pref("hal.processPriorityManager.gonk.foregroundHighNice", 0);
 pref("hal.processPriorityManager.gonk.foregroundNice", 1);
 pref("hal.processPriorityManager.gonk.backgroundPerceivableNice", 10);
 pref("hal.processPriorityManager.gonk.backgroundHomescreenNice", 20);
 pref("hal.processPriorityManager.gonk.backgroundNice", 20);
 
 #ifndef DEBUG
 // Enable pre-launching content processes for improved startup time
 // (hiding latency).
 pref("dom.ipc.processPrelaunch.enabled", true);
 // Wait this long before pre-launching a new subprocess.
 pref("dom.ipc.processPrelaunch.delayMs", 5000);
 #endif
 
+// When a process receives a system message, we hold a CPU wake lock on its
+// behalf for this many seconds, or until it handles the system message,
+// whichever comes first.
+pref("dom.ipc.systemMessageCPULockTimeoutSec", 30);
+
 // Ignore the "dialog=1" feature in window.open.
 pref("dom.disable_window_open_dialog_feature", true);
 
 // Screen reader support
 pref("accessibility.accessfu.activate", 2);
 
 // Enable hit-target fluffing
 pref("ui.touch.radius.enabled", false);
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -521,17 +521,18 @@ var shell = {
 
   sendSystemMessage: function shell_sendSystemMessage(msg) {
     let origin = Services.io.newURI(msg.manifest, null, null).prePath;
     this.sendChromeEvent({
       type: 'open-app',
       url: msg.uri,
       manifestURL: msg.manifest,
       isActivity: (msg.type == 'activity'),
-      target: msg.target
+      target: msg.target,
+      expectingSystemMessage: true
     });
   },
 
   receiveMessage: function shell_receiveMessage(message) {
     var names = { 'content-handler': 'view',
                   'dial-handler'   : 'dial',
                   'mail-handler'   : 'new',
                   'sms-handler'    : 'new' }
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -3,16 +3,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/.
 
 var gPluginHandler = {
   PLUGIN_SCRIPTED_STATE_NONE: 0,
   PLUGIN_SCRIPTED_STATE_FIRED: 1,
   PLUGIN_SCRIPTED_STATE_DONE: 2,
 
+  getPluginUI: function (plugin, className) {
+    return plugin.ownerDocument.
+           getAnonymousElementByAttribute(plugin, "class", className);
+  },
+
 #ifdef MOZ_CRASHREPORTER
   get CrashSubmit() {
     delete this.CrashSubmit;
     Cu.import("resource://gre/modules/CrashSubmit.jsm", this);
     return this.CrashSubmit;
   },
 #endif
 
@@ -299,20 +304,29 @@ var gPluginHandler = {
     if (!gPluginHandler.isKnownPlugin(objLoadingContent))
       return false;
 
     let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
     let permissionString = pluginHost.getPermissionStringForType(objLoadingContent.actualType);
     let browser = gBrowser.getBrowserForDocument(objLoadingContent.ownerDocument.defaultView.top.document);
     let pluginPermission = Services.perms.testPermission(browser.currentURI, permissionString);
 
+    let isFallbackTypeValid =
+      objLoadingContent.pluginFallbackType >= Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY &&
+      objLoadingContent.pluginFallbackType <= Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE;
+
+    if (objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW) {
+      // checking if play preview is subject to CTP rules
+      let playPreviewInfo = pluginHost.getPlayPreviewInfo(objLoadingContent.actualType);
+      isFallbackTypeValid = !playPreviewInfo.ignoreCTP;
+    }
+
     return !objLoadingContent.activated &&
            pluginPermission != Ci.nsIPermissionManager.DENY_ACTION &&
-           objLoadingContent.pluginFallbackType >= Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY &&
-           objLoadingContent.pluginFallbackType <= Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE;
+           isFallbackTypeValid;
   },
 
   activatePlugins: function PH_activatePlugins(aContentWindow) {
     let browser = gBrowser.getBrowserForDocument(aContentWindow.document);
     browser._clickToPlayAllPluginsActivated = true;
     let cwu = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                             .getInterface(Ci.nsIDOMWindowUtils);
     let plugins = cwu.plugins;
@@ -395,21 +409,26 @@ var gPluginHandler = {
 
   // Callback for user clicking on the link in a click-to-play plugin
   // (where the plugin has an update)
   openPluginUpdatePage: function (aEvent) {
     openURL(Services.urlFormatter.formatURLPref("plugins.update.url"));
   },
 
 #ifdef MOZ_CRASHREPORTER
-  // Callback for user clicking "submit a report" link
-  submitReport : function(pluginDumpID, browserDumpID) {
-    // The crash reporter wants a DOM element it can append an IFRAME to,
-    // which it uses to submit a form. Let's just give it gBrowser.
-    this.CrashSubmit.submit(pluginDumpID);
+  submitReport: function submitReport(pluginDumpID, browserDumpID, plugin) {
+    let keyVals = {};
+    if (plugin) {
+      let userComment = this.getPluginUI(plugin, "submitComment").value.trim();
+      if (userComment)
+        keyVals.PluginUserComment = userComment;
+      if (this.getPluginUI(plugin, "submitURLOptIn").checked)
+        keyVals.PluginContentURL = plugin.ownerDocument.URL;
+    }
+    this.CrashSubmit.submit(pluginDumpID, { extraExtraKeyVals: keyVals });
     if (browserDumpID)
       this.CrashSubmit.submit(browserDumpID);
   },
 #endif
 
   // Callback for user clicking a "reload page" link
   reloadPage: function (browser) {
     browser.reload();
@@ -467,30 +486,43 @@ var gPluginHandler = {
       }, true);
     }
 
     gPluginHandler._showClickToPlayNotification(browser);
   },
 
   _handlePlayPreviewEvent: function PH_handlePlayPreviewEvent(aPlugin) {
     let doc = aPlugin.ownerDocument;
+    let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
+    let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
+    let pluginInfo = this._getPluginInfo(aPlugin);
+    let playPreviewInfo = pluginHost.getPlayPreviewInfo(pluginInfo.mimetype);
+
+    if (!playPreviewInfo.ignoreCTP) {
+      // if click-to-play rules used, play plugin at once if plugins were
+      // activated for this window
+      if (browser._clickToPlayAllPluginsActivated ||
+          browser._clickToPlayPluginsActivated.get(pluginInfo.pluginName)) {
+        objLoadingContent.playPlugin();
+        return;
+      }
+    }
+
     let previewContent = doc.getAnonymousElementByAttribute(aPlugin, "class", "previewPluginContent");
     let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
     if (!iframe) {
       // lazy initialization of the iframe
       iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
       iframe.className = "previewPluginContentFrame";
       previewContent.appendChild(iframe);
 
       // Force a style flush, so that we ensure our binding is attached.
       aPlugin.clientTop;
     }
-    let pluginInfo = this._getPluginInfo(aPlugin);
-    let playPreviewUri = "data:application/x-moz-playpreview;," + pluginInfo.mimetype;
-    iframe.src = playPreviewUri;
+    iframe.src = playPreviewInfo.redirectURL;
 
     // MozPlayPlugin event can be dispatched from the extension chrome
     // code to replace the preview content with the native plugin
     previewContent.addEventListener("MozPlayPlugin", function playPluginHandler(aEvent) {
       if (!aEvent.isTrusted)
         return;
 
       previewContent.removeEventListener("MozPlayPlugin", playPluginHandler, true);
@@ -498,16 +530,20 @@ var gPluginHandler = {
       let playPlugin = !aEvent.detail;
       gPluginHandler.stopPlayPreview(aPlugin, playPlugin);
 
       // cleaning up: removes overlay iframe from the DOM
       let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
       if (iframe)
         previewContent.removeChild(iframe);
     }, true);
+
+    if (!playPreviewInfo.ignoreCTP) {
+      gPluginHandler._showClickToPlayNotification(browser);
+    }
   },
 
   reshowClickToPlayNotification: function PH_reshowClickToPlayNotification() {
     let browser = gBrowser.selectedBrowser;
     if (gPluginHandler._pluginNeedsActivationExceptThese([]))
       gPluginHandler._showClickToPlayNotification(browser);
   },
 
@@ -906,33 +942,36 @@ var gPluginHandler = {
     if (submittedReport) { // submitReports && !doPrompt, handled in observer
       status = "submitted";
     }
     else if (!submitReports && !doPrompt) {
       status = "noSubmit";
     }
     else { // doPrompt
       status = "please";
-      // XXX can we make the link target actually be blank?
-      let pleaseLink = doc.getAnonymousElementByAttribute(
-                            plugin, "class", "pleaseSubmitLink");
-      this.addLinkClickCallback(pleaseLink, "submitReport",
-                                pluginDumpID, browserDumpID);
+      this.getPluginUI(plugin, "submitButton").addEventListener("click",
+        function (event) {
+          if (event.button != 0 || !event.isTrusted)
+            return;
+          this.submitReport(pluginDumpID, browserDumpID, plugin);
+          pref.setBoolPref("", optInCB.checked);
+        }.bind(this));
+      let optInCB = this.getPluginUI(plugin, "submitURLOptIn");
+      let pref = Services.prefs.getBranch("dom.ipc.plugins.reportCrashURL");
+      optInCB.checked = pref.getBoolPref("");
     }
 
     // If we don't have a minidumpID, we can't (or didn't) submit anything.
     // This can happen if the plugin is killed from the task manager.
     if (!pluginDumpID) {
         status = "noReport";
     }
 
     statusDiv.setAttribute("status", status);
 
-    let bottomLinks = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgBottomLinks");
-    bottomLinks.style.display = "block";
     let helpIcon = doc.getAnonymousElementByAttribute(plugin, "class", "helpIcon");
     this.addLinkClickCallback(helpIcon, "openHelpPage");
 
     // If we're showing the link to manually trigger report submission, we'll
     // want to be able to update all the instances of the UI for this crash to
     // show an updated message when a report is submitted.
     if (doPrompt) {
       let observer = {
@@ -959,41 +998,52 @@ var gPluginHandler = {
       // it from being GC. But I don't want to manually manage the reference's
       // lifetime (which should be no greater than the page).
       // Clever solution? Use a closue with an event listener on the document.
       // When the doc goes away, so do the listener references and the closure.
       doc.addEventListener("mozCleverClosureHack", observer, false);
     }
 #endif
 
-    let crashText = doc.getAnonymousElementByAttribute(plugin, "class", "msg msgCrashed");
+    let crashText = doc.getAnonymousElementByAttribute(plugin, "class", "msgCrashedText");
     crashText.textContent = messageString;
 
     let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
 
     let link = doc.getAnonymousElementByAttribute(plugin, "class", "reloadLink");
     this.addLinkClickCallback(link, "reloadPage", browser);
 
     let notificationBox = gBrowser.getNotificationBox(browser);
 
+    let isShowing = true;
+
     // Is the <object>'s size too small to hold what we want to show?
     if (this.isTooSmall(plugin, overlay)) {
-        // Hide the overlay's contents. Use visibility style, so that it
-        // doesn't collapse down to 0x0.
+      // First try hiding the crash report submission UI.
+      statusDiv.removeAttribute("status");
+
+      if (this.isTooSmall(plugin, overlay)) {
+        // Hide the overlay's contents. Use visibility style, so that it doesn't
+        // collapse down to 0x0.
         overlay.style.visibility = "hidden";
-        // If another plugin on the page was large enough to show our UI, we
-        // don't want to show a notification bar.
-        if (!doc.mozNoPluginCrashedNotification)
-          showNotificationBar(pluginDumpID, browserDumpID);
+        isShowing = false;
+      }
+    }
+
+    if (isShowing) {
+      // If a previous plugin on the page was too small and resulted in adding a
+      // notification bar, then remove it because this plugin instance it big
+      // enough to serve as in-content notification.
+      hideNotificationBar();
+      doc.mozNoPluginCrashedNotification = true;
     } else {
-        // If a previous plugin on the page was too small and resulted in
-        // adding a notification bar, then remove it because this plugin
-        // instance it big enough to serve as in-content notification.
-        hideNotificationBar();
-        doc.mozNoPluginCrashedNotification = true;
+      // If another plugin on the page was large enough to show our UI, we don't
+      // want to show a notification bar.
+      if (!doc.mozNoPluginCrashedNotification)
+        showNotificationBar(pluginDumpID, browserDumpID);
     }
 
     function hideNotificationBar() {
       let notification = notificationBox.getNotificationWithValue("plugin-crashed");
       if (notification)
         notificationBox.removeNotification(notification, true);
     }
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -989,16 +989,19 @@ let gGestureSupport = {
    */
   rotate: function(aEvent) {
     if (!(content.document instanceof ImageDocument))
       return;
 
     let contentElement = content.document.body.firstElementChild;
     if (!contentElement)
       return;
+    // If we're currently snapping, cancel that snap
+    if (contentElement.classList.contains("completeRotation"))
+      this._clearCompleteRotation();
 
     this.rotation = Math.round(this.rotation + aEvent.delta);
     contentElement.style.transform = "rotate(" + this.rotation + "deg)";
     this._lastRotateDelta = aEvent.delta;
   },
 
   /**
    * Perform a rotation end for ImageDocuments
@@ -1031,18 +1034,21 @@ let gGestureSupport = {
     // then snap ahead of rotation to simulate momentum
     if (this._lastRotateDelta > this._rotateMomentumThreshold &&
         this.rotation > transitionRotation)
       transitionRotation += 90;
     else if (this._lastRotateDelta < -1 * this._rotateMomentumThreshold &&
              this.rotation < transitionRotation)
       transitionRotation -= 90;
 
-    contentElement.classList.add("completeRotation");
-    contentElement.addEventListener("transitionend", this._clearCompleteRotation);
+    // Only add the completeRotation class if it is is necessary
+    if (transitionRotation != this.rotation) {
+      contentElement.classList.add("completeRotation");
+      contentElement.addEventListener("transitionend", this._clearCompleteRotation);
+    }
 
     contentElement.style.transform = "rotate(" + transitionRotation + "deg)";
     this.rotation = transitionRotation;
   },
 
   /**
    * Gets the current rotation for the ImageDocument
    */
@@ -1089,18 +1095,24 @@ let gGestureSupport = {
     this.rotation = Math.round(Math.atan2(transformValue[1], transformValue[0]) *
                                (180 / Math.PI));
   },
 
   /**
    * Removes the transition rule by removing the completeRotation class
    */
   _clearCompleteRotation: function() {
-    this.classList.remove("completeRotation");
-    this.removeEventListener("transitionend", this._clearCompleteRotation);
+    let contentElement = content.document &&
+                         content.document instanceof ImageDocument &&
+                         content.document.body &&
+                         content.document.body.firstElementChild;
+    if (!contentElement)
+      return;
+    contentElement.classList.remove("completeRotation");
+    contentElement.removeEventListener("transitionend", this._clearCompleteRotation);
   },
 };
 
 var gBrowserInit = {
   onLoad: function() {
     // window.arguments[0]: URI to load (string), or an nsISupportsArray of
     //                      nsISupportsStrings to load, or a xul:tab of
     //                      a tabbrowser, which will be replaced by this
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -181,16 +181,17 @@ endif
                  browser_locationBarExternalLoad.js \
                  browser_page_style_menu.js \
                  browser_pinnedTabs.js \
                  browser_plainTextLinks.js \
                  browser_pluginnotification.js \
                  browser_plugins_added_dynamically.js \
                  browser_CTPScriptPlugin.js \
                  browser_pluginplaypreview.js \
+                 browser_pluginplaypreview2.js \
                  browser_private_browsing_window.js \
                  browser_relatedTabs.js \
                  browser_sanitize-passwordDisabledHosts.js \
                  browser_sanitize-sitepermissions.js \
                  browser_sanitize-timespans.js \
                  browser_clearplugindata.js \
                  browser_clearplugindata.html \
                  browser_clearplugindata_noage.html \
@@ -297,16 +298,18 @@ endif
                  browser_utilityOverlay.js \
                  browser_bug676619.js \
                  download_page.html \
                  browser_URLBarSetURI.js \
                  browser_bookmark_titles.js \
                  browser_pageInfo_plugins.js \
                  browser_pageInfo.js \
                  feed_tab.html \
+                 browser_pluginCrashCommentAndURL.js \
+                 pluginCrashCommentAndURL.html \
                  $(NULL)
 
 ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 _BROWSER_FILES += \
 		browser_bug462289.js \
 		$(NULL)
 else
 _BROWSER_FILES += \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_pluginCrashCommentAndURL.js
@@ -0,0 +1,154 @@
+/* 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/. */
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+const CRASH_URL = "http://example.com/browser/browser/base/content/test/pluginCrashCommentAndURL.html";
+
+const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
+
+function test() {
+  // Crashing the plugin takes up a lot of time, so extend the test timeout.
+  requestLongerTimeout(runs.length);
+  waitForExplicitFinish();
+
+  // The test harness sets MOZ_CRASHREPORTER_NO_REPORT, which disables plugin
+  // crash reports.  This test needs them enabled.  The test also needs a mock
+  // report server, and fortunately one is already set up by toolkit/
+  // crashreporter/test/Makefile.in.  Assign its URL to MOZ_CRASHREPORTER_URL,
+  // which CrashSubmit.jsm uses as a server override.
+  let env = Cc["@mozilla.org/process/environment;1"].
+            getService(Components.interfaces.nsIEnvironment);
+  let noReport = env.get("MOZ_CRASHREPORTER_NO_REPORT");
+  let serverURL = env.get("MOZ_CRASHREPORTER_URL");
+  env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
+  env.set("MOZ_CRASHREPORTER_URL", SERVER_URL);
+
+  let tab = gBrowser.loadOneTab("about:blank", { inBackground: false });
+  let browser = gBrowser.getBrowserForTab(tab);
+  browser.addEventListener("PluginCrashed", onCrash, false);
+  Services.obs.addObserver(onSubmitStatus, "crash-report-status", false);
+
+  registerCleanupFunction(function cleanUp() {
+    env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
+    env.set("MOZ_CRASHREPORTER_URL", serverURL);
+    gBrowser.selectedBrowser.removeEventListener("PluginCrashed", onCrash,
+                                                 false);
+    Services.obs.removeObserver(onSubmitStatus, "crash-report-status");
+    gBrowser.removeCurrentTab();
+  });
+
+  doNextRun();
+}
+
+let runs = [
+  {
+    shouldSubmissionUIBeVisible: true,
+    comment: "",
+    urlOptIn: false,
+  },
+  {
+    shouldSubmissionUIBeVisible: true,
+    comment: "a test comment",
+    urlOptIn: true,
+  },
+  {
+    width: 300,
+    height: 300,
+    shouldSubmissionUIBeVisible: false,
+  },
+];
+
+let currentRun = null;
+
+function doNextRun() {
+  try {
+    if (!runs.length) {
+      finish();
+      return;
+    }
+    currentRun = runs.shift();
+    let args = ["width", "height"].reduce(function (memo, arg) {
+      if (arg in currentRun)
+        memo[arg] = currentRun[arg];
+      return memo;
+    }, {});
+    gBrowser.loadURI(CRASH_URL + "?" +
+                     encodeURIComponent(JSON.stringify(args)));
+    // And now wait for the crash.
+  }
+  catch (err) {
+    failWithException(err);
+    finish();
+  }
+}
+
+function onCrash() {
+  try {
+    let plugin = gBrowser.contentDocument.getElementById("plugin");
+    let elt = gPluginHandler.getPluginUI.bind(gPluginHandler, plugin);
+    let style =
+      gBrowser.contentWindow.getComputedStyle(elt("msg msgPleaseSubmit"));
+    is(style.display,
+       currentRun.shouldSubmissionUIBeVisible ? "block" : "none",
+       "Submission UI visibility should be correct");
+    if (!currentRun.shouldSubmissionUIBeVisible) {
+      // Done with this run.
+      doNextRun();
+      return;
+    }
+    elt("submitComment").value = currentRun.comment;
+    elt("submitURLOptIn").checked = currentRun.urlOptIn;
+    elt("submitButton").click();
+    // And now wait for the submission status notification.
+  }
+  catch (err) {
+    failWithException(err);
+    doNextRun();
+  }
+}
+
+function onSubmitStatus(subj, topic, data) {
+  try {
+    // Wait for success or failed, doesn't matter which.
+    if (data != "success" && data != "failed")
+      return;
+
+    let extra = getPropertyBagValue(subj.QueryInterface(Ci.nsIPropertyBag),
+                                    "extra");
+    ok(extra instanceof Ci.nsIPropertyBag, "Extra data should be property bag");
+
+    let val = getPropertyBagValue(extra, "PluginUserComment");
+    if (currentRun.comment)
+      is(val, currentRun.comment,
+         "Comment in extra data should match comment in textbox");
+    else
+      ok(val === undefined,
+         "Comment should be absent from extra data when textbox is empty");
+
+    val = getPropertyBagValue(extra, "PluginContentURL");
+    if (currentRun.urlOptIn)
+      is(val, gBrowser.currentURI.spec,
+         "URL in extra data should match browser URL when opt-in checked");
+    else
+      ok(val === undefined,
+         "URL should be absent from extra data when opt-in not checked");
+  }
+  catch (err) {
+    failWithException(err);
+  }
+  doNextRun();
+}
+
+function getPropertyBagValue(bag, key) {
+  try {
+    var val = bag.getProperty(key);
+  }
+  catch (e if e.result == Cr.NS_ERROR_FAILURE) {}
+  return val;
+}
+
+function failWithException(err) {
+  ok(false, "Uncaught exception: " + err + "\n" + err.stack);
+}
--- a/browser/base/content/test/browser_pluginplaypreview.js
+++ b/browser/base/content/test/browser_pluginplaypreview.js
@@ -106,17 +106,17 @@ function registerPlayPreview(mimeType, t
 
     // nsIRequestObserver::onStopRequest
     onStopRequest: function(aRequest, aContext, aStatusCode) {
       // Do nothing.
     }
   };
 
   var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
-  ph.registerPlayPreviewMimeType(mimeType);
+  ph.registerPlayPreviewMimeType(mimeType, true); // ignoring CTP rules
 
   var factory = new StreamConverterFactory();
   factory.register(OverlayStreamConverter);
 
   return (gPlayPreviewRegistration = {
     unregister: function() {
       ph.unregisterPlayPreviewMimeType(mimeType);
       factory.unregister();
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_pluginplaypreview2.js
@@ -0,0 +1,173 @@
+/* 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/. */
+
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir;
+
+var gTestBrowser = null;
+var gNextTest = null;
+var gNextTestSkip = 0;
+var gPlayPreviewPluginActualEvents = 0;
+var gPlayPreviewPluginExpectedEvents = 1;
+
+var gPlayPreviewRegistration = null;
+
+function registerPlayPreview(mimeType, targetUrl) {
+  var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
+  ph.registerPlayPreviewMimeType(mimeType, false, targetUrl);
+
+  return (gPlayPreviewRegistration = {
+    unregister: function() {
+      ph.unregisterPlayPreviewMimeType(mimeType);
+      gPlayPreviewRegistration = null;
+    }
+  });
+}
+
+function unregisterPlayPreview() {
+  gPlayPreviewRegistration.unregister();
+}
+
+Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+
+function test() {
+  waitForExplicitFinish();
+  registerCleanupFunction(function() {
+    if (gPlayPreviewRegistration)
+      gPlayPreviewRegistration.unregister();
+    Services.prefs.clearUserPref("plugins.click_to_play");
+  });
+
+  var newTab = gBrowser.addTab();
+  gBrowser.selectedTab = newTab;
+  gTestBrowser = gBrowser.selectedBrowser;
+  gTestBrowser.addEventListener("load", pageLoad, true);
+  gTestBrowser.addEventListener("PluginBindingAttached", handleBindingAttached, true, true);
+
+  Services.prefs.setBoolPref("plugins.click_to_play", true);
+
+  registerPlayPreview('application/x-test', 'about:');
+  prepareTest(test1a, gTestRoot + "plugin_test.html", 1);
+}
+
+function finishTest() {
+  gTestBrowser.removeEventListener("load", pageLoad, true);
+  gTestBrowser.removeEventListener("PluginBindingAttached", handleBindingAttached, true, true);
+  gBrowser.removeCurrentTab();
+  window.focus();
+  finish();
+}
+
+function handleBindingAttached(evt) {
+  if (evt.target instanceof Ci.nsIObjectLoadingContent &&
+      evt.target.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW)
+    gPlayPreviewPluginActualEvents++;
+}
+
+function pageLoad() {
+  // The plugin events are async dispatched and can come after the load event
+  // This just allows the events to fire before we then go on to test the states
+
+  // iframe might triggers load event as well, making sure we skip some to let
+  // all iframes on the page be loaded as well
+  if (gNextTestSkip) {
+    gNextTestSkip--;
+    return;
+  }
+  executeSoon(gNextTest);
+}
+
+function prepareTest(nextTest, url, skip) {
+  gNextTest = nextTest;
+  gNextTestSkip = skip;
+  gTestBrowser.contentWindow.location = url;
+}
+
+// Tests a page with normal play preview registration (1/2)
+function test1a() {
+  var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
+  ok(!notificationBox.getNotificationWithValue("missing-plugins"), "Test 1a, Should not have displayed the missing plugin notification");
+  ok(!notificationBox.getNotificationWithValue("blocked-plugins"), "Test 1a, Should not have displayed the blocked plugin notification");
+
+  var pluginInfo = getTestPlugin();
+  ok(pluginInfo, "Should have a test plugin");
+
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 1a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
+  ok(!objLoadingContent.activated, "Test 1a, Plugin should not be activated");
+
+  var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
+  ok(overlay, "Test 1a, the overlay div is expected");
+
+  var iframe = overlay.getElementsByClassName("previewPluginContentFrame")[0];
+  ok(iframe && iframe.localName == "iframe", "Test 1a, the overlay iframe is expected");
+  var iframeHref = iframe.contentWindow.location.href;
+  ok(iframeHref == "about:", "Test 1a, the overlay about: content is expected");
+
+  var rect = iframe.getBoundingClientRect();
+  ok(rect.width == 200, "Test 1a, Plugin with id=" + plugin.id + " overlay rect should have 200px width before being replaced by actual plugin");
+  ok(rect.height == 200, "Test 1a, Plugin with id=" + plugin.id + " overlay rect should have 200px height before being replaced by actual plugin");
+
+  var e = overlay.ownerDocument.createEvent("CustomEvent");
+  e.initCustomEvent("MozPlayPlugin", true, true, null);
+  overlay.dispatchEvent(e);
+  var condition = function() objLoadingContent.activated;
+  waitForCondition(condition, test1b, "Test 1a, Waited too long for plugin to stop play preview");
+}
+
+// Tests that activating via MozPlayPlugin through the notification works (part 2/2)
+function test1b() {
+  var plugin = gTestBrowser.contentDocument.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 1b, Plugin should be activated");
+
+  is(gPlayPreviewPluginActualEvents, gPlayPreviewPluginExpectedEvents,
+     "There should be exactly one PluginPlayPreview event");
+
+  unregisterPlayPreview();
+
+  prepareTest(test2, gTestRoot + "plugin_test.html");
+}
+
+// Tests a page with a working plugin in it -- the mime type was just unregistered.
+function test2() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.pluginFallbackType != Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 2, plugin fallback type should not be PLUGIN_PLAY_PREVIEW");
+  ok(!objLoadingContent.activated, "Test 2, Plugin should not be activated");
+
+  registerPlayPreview('application/x-unknown', 'about:');
+
+  prepareTest(test3, gTestRoot + "plugin_test.html");
+}
+
+// Tests a page with a working plugin in it -- diffent play preview type is reserved.
+function test3() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.pluginFallbackType != Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 3, plugin fallback type should not be PLUGIN_PLAY_PREVIEW");
+  ok(!objLoadingContent.activated, "Test 3, Plugin should not be activated");
+
+  unregisterPlayPreview();
+
+  registerPlayPreview('application/x-test', 'about:');
+  Services.prefs.setBoolPref("plugins.click_to_play", false);
+  prepareTest(test4, gTestRoot + "plugin_test.html");
+}
+
+// Tests a page with a working plugin in it -- click-to-play is off
+function test4() {
+  var plugin = gTestBrowser.contentDocument.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 4, Plugin should be activated");
+
+  finishTest();
+}
+
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/pluginCrashCommentAndURL.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+    <script type="text/javascript">
+      function crash() {
+        var plugin = document.getElementById("plugin");
+        var argStr = decodeURIComponent(window.location.search.substr(1));
+        if (argStr) {
+          var args = JSON.parse(argStr);
+          for (var key in args)
+            plugin.setAttribute(key, args[key]);
+        }
+        try {
+          plugin.crash();
+        }
+        catch (err) {}
+      }
+    </script>
+  </head>
+  <body onload="crash();">
+    <embed id="plugin" type="application/x-test"
+           width="400" height="400"
+           drawmode="solid" color="FF00FFFF">
+    </embed>
+  </body>
+</html>
--- a/browser/metro/shell/commandexecutehandler/CEHHelper.cpp
+++ b/browser/metro/shell/commandexecutehandler/CEHHelper.cpp
@@ -1,15 +1,19 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "CEHHelper.h"
 
+#ifdef SHOW_CONSOLE
+#include <io.h> // _open_osfhandle
+#endif
+
 HANDLE sCon;
 LPCWSTR metroDX10Available = L"MetroD3DAvailable";
 
 typedef HRESULT (WINAPI*D3D10CreateDevice1Func)
   (IDXGIAdapter *, D3D10_DRIVER_TYPE, HMODULE, UINT,
    D3D10_FEATURE_LEVEL1, UINT, ID3D10Device1 **);
 typedef HRESULT(WINAPI*CreateDXGIFactory1Func)(REFIID , void **);
 
--- a/browser/metro/shell/commandexecutehandler/CEHHelper.h
+++ b/browser/metro/shell/commandexecutehandler/CEHHelper.h
@@ -16,14 +16,14 @@
 
 //#define SHOW_CONSOLE 1
 extern HANDLE sCon;
 extern LPCWSTR metroDX10Available;
 
 void Log(const wchar_t *fmt, ...);
 
 #if defined(SHOW_CONSOLE)
-static void SetupConsole();
+void SetupConsole();
 #endif
 
 bool IsDX10Available();
 bool GetDWORDRegKey(LPCWSTR name, DWORD &value);
 bool SetDWORDRegKey(LPCWSTR name, DWORD value);
--- a/browser/metro/shell/commandexecutehandler/CommandExecuteHandler.cpp
+++ b/browser/metro/shell/commandexecutehandler/CommandExecuteHandler.cpp
@@ -141,17 +141,17 @@ public:
     DWORD count = 0;
     aArray->GetCount(&count);
     if (!count) {
       return E_FAIL;
     }
 
 #ifdef SHOW_CONSOLE
     Log(L"SetSelection param count: %d", count);
-    for (int idx = 0; idx < count; idx++) {
+    for (DWORD idx = 0; idx < count; idx++) {
       IShellItem* item = NULL;
       if (SUCCEEDED(aArray->GetItemAt(idx, &item))) {
         LPWSTR str = NULL;
         if (FAILED(item->GetDisplayName(SIGDN_FILESYSPATH, &str))) {
           if (FAILED(item->GetDisplayName(SIGDN_URL, &str))) {
             Log(L"Failed to get a shell item array item.");
             item->Release();
             continue;
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -528,16 +528,20 @@ user_pref("security.notification_enable_
 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);
 
 // Don't allow the Data Reporting service to prompt for policy acceptance.
 user_pref("datareporting.policy.dataSubmissionPolicyBypassAcceptance", true);
 
+// Point Firefox Health Report at a local server. We don't care if it actually
+// works. It just can't hit the default production endpoint.
+user_pref("datareporting.healthreport.documentServerURI", "http://%(server)s/healthreport/");
+
 // Make sure CSS error reporting is enabled for tests
 user_pref("layout.css.report_errors", true);
 """ % { "server" : self.webServer + ":" + str(self.httpPort) }
     prefs.append(part)
 
     if useServerLocations:
       # We need to proxy every server but the primary one.
       origins = ["'%s://%s:%s'" % (l.scheme, l.host, l.port)
@@ -1285,9 +1289,10 @@ user_pref("camino.use_system_proxy_setti
       # "destination directory must not already exist".
       shutil.copytree(extensionSource, os.path.join(extensionsRootDir, extensionID))
 
     else:
       self.log.info("INFO | automation.py | Cannot install extension, invalid extensionSource at: %s", extensionSource)
 
   def elf_arm(self, filename):
     data = open(filename, 'rb').read(20)
-    return data[:4] == "\x7fELF" and ord(data[18]) == 40 # EM_ARM
\ No newline at end of file
+    return data[:4] == "\x7fELF" and ord(data[18]) == 40 # EM_ARM
+
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -35,17 +35,16 @@
 #include "nsDirectoryServiceDefs.h"
 #include "nsIFile.h"
 #include "nsIFileURL.h"
 #include "nsIZipReader.h"
 #include "nsIXPConnect.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsIPrompt.h"
 #include "nsIWindowWatcher.h"
 #include "nsIConsoleService.h"
 #include "nsISecurityCheckedComponent.h"
 #include "nsIJSRuntimeService.h"
 #include "nsIObserverService.h"
 #include "nsIContent.h"
 #include "nsAutoPtr.h"
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -84,17 +84,16 @@
 
 #include "nsNodeInfoManager.h"
 #include "nsICategoryManager.h"
 #include "nsIDOMDocumentType.h"
 #include "nsIDOMUserDataHandler.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIEditor.h"
 #include "nsIEditorIMESupport.h"
-#include "nsIEditorDocShell.h"
 #include "nsEventDispatcher.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsIControllers.h"
 #include "nsView.h"
 #include "nsViewManager.h"
 #include "nsIScrollableFrame.h"
 #include "nsXBLInsertionPoint.h"
 #include "mozilla/css/StyleRule.h" /* For nsCSSSelectorList */
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -83,17 +83,16 @@
 
 #include "nsNodeInfoManager.h"
 #include "nsICategoryManager.h"
 #include "nsIDOMDocumentType.h"
 #include "nsIDOMUserDataHandler.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIEditor.h"
 #include "nsIEditorIMESupport.h"
-#include "nsIEditorDocShell.h"
 #include "nsEventDispatcher.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsIControllers.h"
 #include "nsView.h"
 #include "nsViewManager.h"
 #include "nsIScrollableFrame.h"
 #include "nsXBLInsertionPoint.h"
 #include "mozilla/css/StyleRule.h" /* For nsCSSSelectorList */
--- a/content/base/src/nsCCUncollectableMarker.cpp
+++ b/content/base/src/nsCCUncollectableMarker.cpp
@@ -1,17 +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 "nsCCUncollectableMarker.h"
 #include "nsIObserverService.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIContentViewer.h"
 #include "nsIDocument.h"
 #include "nsXULDocument.h"
 #include "nsIWindowMediator.h"
 #include "nsPIDOMWindow.h"
 #include "nsIWebNavigation.h"
 #include "nsISHistory.h"
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -12,17 +12,16 @@
 #include "nsContentSink.h"
 #include "nsScriptLoader.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "mozilla/css/Loader.h"
 #include "nsStyleLinkElement.h"
 #include "nsIDocShell.h"
 #include "nsILoadContext.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsCPrefetchService.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsIHttpChannel.h"
 #include "nsIContent.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsViewManager.h"
@@ -802,32 +801,28 @@ nsContentSink::PrefetchHref(const nsAStr
   // walk up the docshell tree to see if any containing
   // docshell are of type MAIL.
   //
   if (!mDocShell)
     return;
 
   nsCOMPtr<nsIDocShell> docshell = mDocShell;
 
-  nsCOMPtr<nsIDocShellTreeItem> treeItem, parentItem;
+  nsCOMPtr<nsIDocShellTreeItem> parentItem;
   do {
     uint32_t appType = 0;
     nsresult rv = docshell->GetAppType(&appType);
     if (NS_FAILED(rv) || appType == nsIDocShell::APP_TYPE_MAIL)
       return; // do not prefetch from mailnews
-    treeItem = do_QueryInterface(docshell);
-    if (treeItem) {
-      treeItem->GetParent(getter_AddRefs(parentItem));
-      if (parentItem) {
-        treeItem = parentItem;
-        docshell = do_QueryInterface(treeItem);
-        if (!docshell) {
-          NS_ERROR("cannot get a docshell from a treeItem!");
-          return;
-        }
+    docshell->GetParent(getter_AddRefs(parentItem));
+    if (parentItem) {
+      docshell = do_QueryInterface(parentItem);
+      if (!docshell) {
+        NS_ERROR("cannot get a docshell from a treeItem!");
+        return;
       }
     }
   } while (parentItem);
   
   // OK, we passed the security check...
   
   nsCOMPtr<nsIPrefetchService> prefetchService(do_GetService(NS_PREFETCHSERVICE_CONTRACTID));
   if (prefetchService) {
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -36,17 +36,16 @@
 #include "nsIDOMNode.h"
 #include "nsIIOService.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsPIDOMWindow.h"
 #include "nsIJSContextStack.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsParserCIID.h"
 #include "nsIParser.h"
 #include "nsIFragmentContentSink.h"
 #include "nsIContentSink.h"
 #include "nsContentList.h"
 #include "nsIHTMLDocument.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsIDOMHTMLElement.h"
@@ -155,17 +154,16 @@
 #include "mozilla/Preferences.h"
 #include "nsDOMMutationObserver.h"
 #include "nsIDOMDocumentType.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsICharsetDetector.h"
 #include "nsICharsetDetectionObserver.h"
 #include "nsIPlatformCharset.h"
 #include "nsIEditor.h"
-#include "nsIEditorDocShell.h"
 #include "mozilla/Attributes.h"
 #include "nsIParserService.h"
 #include "nsIDOMScriptObjectFactory.h"
 #include "nsSandboxFlags.h"
 #include "nsSVGFeatures.h"
 #include "MediaDecoder.h"
 #include "DecoderTraits.h"
 
@@ -6797,24 +6795,24 @@ nsContentUtils::GetSelectionInTextContro
   aOutStartOffset = std::min(anchorOffset, focusOffset);
   aOutEndOffset = std::max(anchorOffset, focusOffset);
 }
 
 nsIEditor*
 nsContentUtils::GetHTMLEditor(nsPresContext* aPresContext)
 {
   nsCOMPtr<nsISupports> container = aPresContext->GetContainer();
-  nsCOMPtr<nsIEditorDocShell> editorDocShell(do_QueryInterface(container));
+  nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
   bool isEditable;
-  if (!editorDocShell ||
-      NS_FAILED(editorDocShell->GetEditable(&isEditable)) || !isEditable)
+  if (!docShell ||
+      NS_FAILED(docShell->GetEditable(&isEditable)) || !isEditable)
     return nullptr;
 
   nsCOMPtr<nsIEditor> editor;
-  editorDocShell->GetEditor(getter_AddRefs(editor));
+  docShell->GetEditor(getter_AddRefs(editor));
   return editor;
 }
 
 bool
 nsContentUtils::InternalIsSupported(nsISupports* aObject,
                                     const nsAString& aFeature,
                                     const nsAString& aVersion)
 {
--- a/content/base/src/nsDocumentEncoder.cpp
+++ b/content/base/src/nsDocumentEncoder.cpp
@@ -43,17 +43,16 @@
 #include "nsITransferable.h" // for kUnicodeMime
 #include "nsContentUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsReadableUtils.h"
 #include "nsTArray.h"
 #include "nsIFrame.h"
 #include "nsStringBuffer.h"
 #include "mozilla/dom/Element.h"
-#include "nsIEditorDocShell.h"
 #include "nsIEditor.h"
 #include "nsIHTMLEditor.h"
 #include "nsIDocShell.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsresult NS_NewDomSelection(nsISelection **aDomSelection);
@@ -338,27 +337,24 @@ IsInvisibleBreak(nsINode *aNode) {
 
   // Grab the editor associated with the document
   nsIDocument *doc = aNode->GetCurrentDoc();
   if (doc) {
     nsPIDOMWindow *window = doc->GetWindow();
     if (window) {
       nsIDocShell *docShell = window->GetDocShell();
       if (docShell) {
-        nsCOMPtr<nsIEditorDocShell> editorDocShell = do_QueryInterface(docShell);
-        if (editorDocShell) {
-          nsCOMPtr<nsIEditor> editor;
-          editorDocShell->GetEditor(getter_AddRefs(editor));
-          nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
-          if (htmlEditor) {
-            bool isVisible = false;
-            nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(aNode);
-            htmlEditor->BreakIsVisible(domNode, &isVisible);
-            return !isVisible;
-          }
+        nsCOMPtr<nsIEditor> editor;
+        docShell->GetEditor(getter_AddRefs(editor));
+        nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
+        if (htmlEditor) {
+          bool isVisible = false;
+          nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(aNode);
+          htmlEditor->BreakIsVisible(domNode, &isVisible);
+          return !isVisible;
         }
       }
     }
   }
   return false;
 }
 
 nsresult
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -23,18 +23,16 @@
 #include "nsIContentViewer.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMFile.h"
 #include "nsPIDOMWindow.h"
 #include "nsIWebNavigation.h"
 #include "nsIWebProgress.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellTreeItem.h"
-#include "nsIDocShellTreeNode.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocShellLoadInfo.h"
 #include "nsIDOMApplicationRegistry.h"
 #include "nsIBaseWindow.h"
 #include "nsContentUtils.h"
 #include "nsIXPConnect.h"
 #include "nsIJSContextStack.h"
 #include "nsUnicharUtils.h"
@@ -50,17 +48,16 @@
 #include "nsGUIEvent.h"
 #include "nsEventDispatcher.h"
 #include "nsISHistory.h"
 #include "nsISHistoryInternal.h"
 #include "nsIDocShellHistory.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIXULWindow.h"
 #include "nsIEditor.h"
-#include "nsIEditorDocShell.h"
 #include "nsIMozBrowserFrame.h"
 #include "nsIPermissionManager.h"
 
 #include "nsLayoutUtils.h"
 #include "nsView.h"
 #include "nsAsyncDOMEvent.h"
 
 #include "nsIURI.h"
@@ -94,16 +91,17 @@
 
 #include "mozilla/dom/StructuredCloneUtils.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #endif
 
 using namespace mozilla;
+using namespace mozilla::hal;
 using namespace mozilla::dom;
 using namespace mozilla::dom::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::layout;
 typedef FrameMetrics::ViewID ViewID;
 
 class nsAsyncDocShellDestroyer : public nsRunnable
 {
@@ -848,36 +846,32 @@ nsFrameLoader::Show(int32_t marginWidth,
 
     if (doc) {
       nsAutoString designMode;
       doc->GetDesignMode(designMode);
 
       if (designMode.EqualsLiteral("on")) {
         // Hold on to the editor object to let the document reattach to the
         // same editor object, instead of creating a new one.
-        nsCOMPtr<nsIEditorDocShell> editorDocshell = do_QueryInterface(mDocShell);
         nsCOMPtr<nsIEditor> editor;
-        nsresult rv = editorDocshell->GetEditor(getter_AddRefs(editor));
+        nsresult rv = mDocShell->GetEditor(getter_AddRefs(editor));
         NS_ENSURE_SUCCESS(rv, false);
 
         doc->SetDesignMode(NS_LITERAL_STRING("off"));
         doc->SetDesignMode(NS_LITERAL_STRING("on"));
       } else {
         // Re-initialize the presentation for contenteditable documents
-        nsCOMPtr<nsIEditorDocShell> editorDocshell = do_QueryInterface(mDocShell);
-        if (editorDocshell) {
-          bool editable = false,
-                 hasEditingSession = false;
-          editorDocshell->GetEditable(&editable);
-          editorDocshell->GetHasEditingSession(&hasEditingSession);
-          nsCOMPtr<nsIEditor> editor;
-          editorDocshell->GetEditor(getter_AddRefs(editor));
-          if (editable && hasEditingSession && editor) {
-            editor->PostCreate();
-          }
+        bool editable = false,
+             hasEditingSession = false;
+        mDocShell->GetEditable(&editable);
+        mDocShell->GetHasEditingSession(&hasEditingSession);
+        nsCOMPtr<nsIEditor> editor;
+        mDocShell->GetEditor(getter_AddRefs(editor));
+        if (editable && hasEditingSession && editor) {
+          editor->PostCreate();
         }
       }
     }
   }
 
   mInShow = false;
   if (mHideCalled) {
     mHideCalled = false;
@@ -1025,72 +1019,69 @@ nsFrameLoader::SwapWithOtherLoader(nsFra
   if (!ourDocshell || !otherDocshell) {
     // How odd
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   // To avoid having to mess with session history, avoid swapping
   // frameloaders that don't correspond to root same-type docshells,
   // unless both roots have session history disabled.
-  nsCOMPtr<nsIDocShellTreeItem> ourTreeItem = do_QueryInterface(ourDocshell);
-  nsCOMPtr<nsIDocShellTreeItem> otherTreeItem =
-    do_QueryInterface(otherDocshell);
   nsCOMPtr<nsIDocShellTreeItem> ourRootTreeItem, otherRootTreeItem;
-  ourTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(ourRootTreeItem));
-  otherTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(otherRootTreeItem));
+  ourDocshell->GetSameTypeRootTreeItem(getter_AddRefs(ourRootTreeItem));
+  otherDocshell->GetSameTypeRootTreeItem(getter_AddRefs(otherRootTreeItem));
   nsCOMPtr<nsIWebNavigation> ourRootWebnav =
     do_QueryInterface(ourRootTreeItem);
   nsCOMPtr<nsIWebNavigation> otherRootWebnav =
     do_QueryInterface(otherRootTreeItem);
 
   if (!ourRootWebnav || !otherRootWebnav) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   nsCOMPtr<nsISHistory> ourHistory;
   nsCOMPtr<nsISHistory> otherHistory;
   ourRootWebnav->GetSessionHistory(getter_AddRefs(ourHistory));
   otherRootWebnav->GetSessionHistory(getter_AddRefs(otherHistory));
 
-  if ((ourRootTreeItem != ourTreeItem || otherRootTreeItem != otherTreeItem) &&
+  if ((ourRootTreeItem != ourDocshell || otherRootTreeItem != otherDocshell) &&
       (ourHistory || otherHistory)) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   // Also make sure that the two docshells are the same type. Otherwise
   // swapping is certainly not safe. If this needs to be changed then
   // the code below needs to be audited as it assumes identical types.
   int32_t ourType = nsIDocShellTreeItem::typeChrome;
   int32_t otherType = nsIDocShellTreeItem::typeChrome;
-  ourTreeItem->GetItemType(&ourType);
-  otherTreeItem->GetItemType(&otherType);
+  ourDocshell->GetItemType(&ourType);
+  otherDocshell->GetItemType(&otherType);
   if (ourType != otherType) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   // One more twist here.  Setting up the right treeowners in a heterogeneous
   // tree is a bit of a pain.  So make sure that if ourType is not
   // nsIDocShellTreeItem::typeContent then all of our descendants are the same
   // type as us.
   if (ourType != nsIDocShellTreeItem::typeContent &&
-      (!AllDescendantsOfType(ourTreeItem, ourType) ||
-       !AllDescendantsOfType(otherTreeItem, otherType))) {
+      (!AllDescendantsOfType(ourDocshell, ourType) ||
+       !AllDescendantsOfType(otherDocshell, otherType))) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
   
   // Save off the tree owners, frame elements, chrome event handlers, and
   // docshell and document parents before doing anything else.
   nsCOMPtr<nsIDocShellTreeOwner> ourOwner, otherOwner;
-  ourTreeItem->GetTreeOwner(getter_AddRefs(ourOwner));
-  otherTreeItem->GetTreeOwner(getter_AddRefs(otherOwner));
+  ourDocshell->GetTreeOwner(getter_AddRefs(ourOwner));
+  otherDocshell->GetTreeOwner(getter_AddRefs(otherOwner));
   // Note: it's OK to have null treeowners.
 
   nsCOMPtr<nsIDocShellTreeItem> ourParentItem, otherParentItem;
-  ourTreeItem->GetParent(getter_AddRefs(ourParentItem));
-  otherTreeItem->GetParent(getter_AddRefs(otherParentItem));
+  ourDocshell->GetParent(getter_AddRefs(ourParentItem));
+  otherDocshell->GetParent(getter_AddRefs(otherParentItem));
   if (!ourParentItem || !otherParentItem) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   // Make sure our parents are the same type too
   int32_t ourParentType = nsIDocShellTreeItem::typeContent;
   int32_t otherParentType = nsIDocShellTreeItem::typeContent;
   ourParentItem->GetItemType(&ourParentType);
@@ -1158,77 +1149,77 @@ nsFrameLoader::SwapWithOtherLoader(nsFra
   if (mInSwap || aOther->mInSwap) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
   mInSwap = aOther->mInSwap = true;
 
   // Fire pageshow events on still-loading pages, and then fire pagehide
   // events.  Note that we do NOT fire these in the normal way, but just fire
   // them on the chrome event handlers.
-  FirePageShowEvent(ourTreeItem, ourChromeEventHandler, false);
-  FirePageShowEvent(otherTreeItem, otherChromeEventHandler, false);
-  FirePageHideEvent(ourTreeItem, ourChromeEventHandler);
-  FirePageHideEvent(otherTreeItem, otherChromeEventHandler);
+  FirePageShowEvent(ourDocshell, ourChromeEventHandler, false);
+  FirePageShowEvent(otherDocshell, otherChromeEventHandler, false);
+  FirePageHideEvent(ourDocshell, ourChromeEventHandler);
+  FirePageHideEvent(otherDocshell, otherChromeEventHandler);
   
   nsIFrame* ourFrame = ourContent->GetPrimaryFrame();
   nsIFrame* otherFrame = otherContent->GetPrimaryFrame();
   if (!ourFrame || !otherFrame) {
     mInSwap = aOther->mInSwap = false;
-    FirePageShowEvent(ourTreeItem, ourChromeEventHandler, true);
-    FirePageShowEvent(otherTreeItem, otherChromeEventHandler, true);
+    FirePageShowEvent(ourDocshell, ourChromeEventHandler, true);
+    FirePageShowEvent(otherDocshell, otherChromeEventHandler, true);
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   nsSubDocumentFrame* ourFrameFrame = do_QueryFrame(ourFrame);
   if (!ourFrameFrame) {
     mInSwap = aOther->mInSwap = false;
-    FirePageShowEvent(ourTreeItem, ourChromeEventHandler, true);
-    FirePageShowEvent(otherTreeItem, otherChromeEventHandler, true);
+    FirePageShowEvent(ourDocshell, ourChromeEventHandler, true);
+    FirePageShowEvent(otherDocshell, otherChromeEventHandler, true);
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   // OK.  First begin to swap the docshells in the two nsIFrames
   rv = ourFrameFrame->BeginSwapDocShells(otherFrame);
   if (NS_FAILED(rv)) {
     mInSwap = aOther->mInSwap = false;
-    FirePageShowEvent(ourTreeItem, ourChromeEventHandler, true);
-    FirePageShowEvent(otherTreeItem, otherChromeEventHandler, true);
+    FirePageShowEvent(ourDocshell, ourChromeEventHandler, true);
+    FirePageShowEvent(otherDocshell, otherChromeEventHandler, true);
     return rv;
   }
 
   // Now move the docshells to the right docshell trees.  Note that this
   // resets their treeowners to null.
-  ourParentItem->RemoveChild(ourTreeItem);
-  otherParentItem->RemoveChild(otherTreeItem);
+  ourParentItem->RemoveChild(ourDocshell);
+  otherParentItem->RemoveChild(otherDocshell);
   if (ourType == nsIDocShellTreeItem::typeContent) {
-    ourOwner->ContentShellRemoved(ourTreeItem);
-    otherOwner->ContentShellRemoved(otherTreeItem);
+    ourOwner->ContentShellRemoved(ourDocshell);
+    otherOwner->ContentShellRemoved(otherDocshell);
   }
   
-  ourParentItem->AddChild(otherTreeItem);
-  otherParentItem->AddChild(ourTreeItem);
+  ourParentItem->AddChild(otherDocshell);
+  otherParentItem->AddChild(ourDocshell);
 
   // Restore the correct chrome event handlers.
   ourDocshell->SetChromeEventHandler(otherChromeEventHandler);
   otherDocshell->SetChromeEventHandler(ourChromeEventHandler);
   // Restore the correct treeowners
   // (and also chrome event handlers for content frames only).
-  SetTreeOwnerAndChromeEventHandlerOnDocshellTree(ourTreeItem, otherOwner,
+  SetTreeOwnerAndChromeEventHandlerOnDocshellTree(ourDocshell, otherOwner,
     ourType == nsIDocShellTreeItem::typeContent ? otherChromeEventHandler : nullptr);
-  SetTreeOwnerAndChromeEventHandlerOnDocshellTree(otherTreeItem, ourOwner,
+  SetTreeOwnerAndChromeEventHandlerOnDocshellTree(otherDocshell, ourOwner,
     ourType == nsIDocShellTreeItem::typeContent ? ourChromeEventHandler : nullptr);
 
   // Switch the owner content before we start calling AddTreeItemToTreeOwner.
   // Note that we rely on this to deal with setting mObservingOwnerContent to
   // false and calling RemoveMutationObserver as needed.
   SetOwnerContent(otherContent);
   aOther->SetOwnerContent(ourContent);
 
-  AddTreeItemToTreeOwner(ourTreeItem, otherOwner, otherParentType, nullptr);
-  aOther->AddTreeItemToTreeOwner(otherTreeItem, ourOwner, ourParentType,
+  AddTreeItemToTreeOwner(ourDocshell, otherOwner, otherParentType, nullptr);
+  aOther->AddTreeItemToTreeOwner(otherDocshell, ourOwner, ourParentType,
                                  nullptr);
 
   // SetSubDocumentFor nulls out parent documents on the old child doc if a
   // new non-null document is passed in, so just go ahead and remove both
   // kids before reinserting in the parent subdoc maps, to avoid
   // complications.
   ourParentDocument->SetSubDocumentFor(ourContent, nullptr);
   otherParentDocument->SetSubDocumentFor(otherContent, nullptr);
@@ -1302,18 +1293,18 @@ nsFrameLoader::SwapWithOtherLoader(nsFra
   // the wrong appUnitsPerDevPixel value. So we tell the PresShells that their
   // backing scale factor may have changed. (Bug 822266)
   ourShell->BackingScaleFactorChanged();
   otherShell->BackingScaleFactorChanged();
 
   ourParentDocument->FlushPendingNotifications(Flush_Layout);
   otherParentDocument->FlushPendingNotifications(Flush_Layout);
 
-  FirePageShowEvent(ourTreeItem, otherChromeEventHandler, true);
-  FirePageShowEvent(otherTreeItem, ourChromeEventHandler, true);
+  FirePageShowEvent(ourDocshell, otherChromeEventHandler, true);
+  FirePageShowEvent(otherDocshell, ourChromeEventHandler, true);
 
   mInSwap = aOther->mInSwap = false;
   return NS_OK;
 }
 
 void
 nsFrameLoader::DestroyChild()
 {
@@ -1355,23 +1346,22 @@ nsFrameLoader::Destroy()
     nsCOMPtr<nsIDocShellHistory> dhistory = do_QueryInterface(mDocShell);
     if (dhistory) {
       dhistory->RemoveFromSessionHistory();
     }
   }
 
   // Let the tree owner know we're gone.
   if (mIsTopLevelContent) {
-    nsCOMPtr<nsIDocShellTreeItem> ourItem = do_QueryInterface(mDocShell);
-    if (ourItem) {
+    if (mDocShell) {
       nsCOMPtr<nsIDocShellTreeItem> parentItem;
-      ourItem->GetParent(getter_AddRefs(parentItem));
+      mDocShell->GetParent(getter_AddRefs(parentItem));
       nsCOMPtr<nsIDocShellTreeOwner> owner = do_GetInterface(parentItem);
       if (owner) {
-        owner->ContentShellRemoved(ourItem);
+        owner->ContentShellRemoved(mDocShell);
       }
     }
   }
   
   // Let our window know that we are gone
   nsCOMPtr<nsPIDOMWindow> win_private(do_GetInterface(mDocShell));
   if (win_private) {
     win_private->SetFrameElementInternal(nullptr);
@@ -1564,34 +1554,33 @@ nsFrameLoader::MaybeCreateDocShell()
   if (!mNetworkCreated) {
     nsCOMPtr<nsIDocShellHistory> history = do_QueryInterface(mDocShell);
     if (history) {
       history->SetCreatedDynamically(true);
     }
   }
 
   // Get the frame name and tell the docshell about it.
-  nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
-  NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
+  NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
   nsAutoString frameName;
 
   int32_t namespaceID = mOwnerContent->GetNameSpaceID();
   if (namespaceID == kNameSpaceID_XHTML && !mOwnerContent->IsInHTMLDocument()) {
     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
   } else {
     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, frameName);
     // XXX if no NAME then use ID, after a transition period this will be
     // changed so that XUL only uses ID too (bug 254284).
     if (frameName.IsEmpty() && namespaceID == kNameSpaceID_XUL) {
       mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
     }
   }
 
   if (!frameName.IsEmpty()) {
-    docShellAsItem->SetName(frameName.get());
+    mDocShell->SetName(frameName.get());
   }
 
   // If our container is a web-shell, inform it that it has a new
   // child. If it's not a web-shell then some things will not operate
   // properly.
 
   nsCOMPtr<nsIDocShellTreeNode> parentAsNode(do_QueryInterface(parentAsWebNav));
   if (parentAsNode) {
@@ -1605,17 +1594,17 @@ nsFrameLoader::MaybeCreateDocShell()
     parentAsItem->GetItemType(&parentType);
 
     // XXXbz why is this in content code, exactly?  We should handle
     // this some other way.....  Not sure how yet.
     nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
     parentAsItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
     NS_ENSURE_STATE(parentTreeOwner);
     mIsTopLevelContent =
-      AddTreeItemToTreeOwner(docShellAsItem, parentTreeOwner, parentType,
+      AddTreeItemToTreeOwner(mDocShell, parentTreeOwner, parentType,
                              parentAsNode);
 
     // Make sure all shells have links back to the content element
     // in the nearest enclosing chrome shell.
     nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
 
     if (parentType == nsIDocShellTreeItem::typeChrome) {
       // Our parent shell is a chrome shell. It is therefore our nearest
@@ -1729,39 +1718,36 @@ nsFrameLoader::CheckForRecursiveLoad(nsI
     return rv;
   }
   NS_ASSERTION(!mRemoteFrame,
                "Shouldn't call CheckForRecursiveLoad on remote frames.");
   if (!mDocShell) {
     return NS_ERROR_FAILURE;
   }
 
-  nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
-  NS_ASSERTION(treeItem, "docshell must be a treeitem!");
-
   // Check that we're still in the docshell tree.
   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
-  treeItem->GetTreeOwner(getter_AddRefs(treeOwner));
+  mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
   NS_WARN_IF_FALSE(treeOwner,
                    "Trying to load a new url to a docshell without owner!");
   NS_ENSURE_STATE(treeOwner);
   
   
   int32_t ourType;
-  rv = treeItem->GetItemType(&ourType);
+  rv = mDocShell->GetItemType(&ourType);
   if (NS_SUCCEEDED(rv) && ourType != nsIDocShellTreeItem::typeContent) {
     // No need to do recursion-protection here XXXbz why not??  Do we really
     // trust people not to screw up with non-content docshells?
     return NS_OK;
   }
 
   // Bug 8065: Don't exceed some maximum depth in content frames
   // (MAX_DEPTH_CONTENT_FRAMES)
   nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
-  treeItem->GetSameTypeParent(getter_AddRefs(parentAsItem));
+  mDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem));
   int32_t depth = 0;
   while (parentAsItem) {
     ++depth;
     
     if (depth >= MAX_DEPTH_CONTENT_FRAMES) {
       mDepthTooGreat = true;
       NS_WARNING("Too many nested content frames so giving up");
 
@@ -1770,17 +1756,17 @@ nsFrameLoader::CheckForRecursiveLoad(nsI
 
     nsCOMPtr<nsIDocShellTreeItem> temp;
     temp.swap(parentAsItem);
     temp->GetSameTypeParent(getter_AddRefs(parentAsItem));
   }
   
   // Bug 136580: Check for recursive frame loading
   int32_t matchCount = 0;
-  treeItem->GetSameTypeParent(getter_AddRefs(parentAsItem));
+  mDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem));
   while (parentAsItem) {
     // Check the parent URI with the URI we're loading
     nsCOMPtr<nsIWebNavigation> parentAsNav(do_QueryInterface(parentAsItem));
     if (parentAsNav) {
       // Does the URI match the one we're about to load?
       nsCOMPtr<nsIURI> parentURI;
       parentAsNav->GetCurrentURI(getter_AddRefs(parentURI));
       if (parentURI) {
@@ -2055,29 +2041,19 @@ nsFrameLoader::TryRemoteBrowser()
   }
   if (ownApp) {
     context.SetTabContextForAppFrame(ownApp, containingApp, scrollingBehavior);
   } else if (OwnerIsBrowserFrame()) {
     // The |else| above is unnecessary; OwnerIsBrowserFrame() implies !ownApp.
     context.SetTabContextForBrowserFrame(containingApp, scrollingBehavior);
   }
 
-  mRemoteBrowser = ContentParent::CreateBrowserOrApp(context);
+  nsCOMPtr<nsIDOMElement> ownerElement = do_QueryInterface(mOwnerContent);
+  mRemoteBrowser = ContentParent::CreateBrowserOrApp(context, ownerElement);
   if (mRemoteBrowser) {
-    nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mOwnerContent);
-    mRemoteBrowser->SetOwnerElement(element);
-
-    // If we're an app, send the frame element's mozapptype down to the child
-    // process.  This ends up in TabChild::GetAppType().
-    if (ownApp) {
-      nsAutoString appType;
-      mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::mozapptype, appType);
-      mRemoteBrowser->SendSetAppType(appType);
-    }
-
     nsCOMPtr<nsIDocShellTreeItem> rootItem;
     parentAsItem->GetRootTreeItem(getter_AddRefs(rootItem));
     nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
     nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(rootWin);
     NS_ABORT_IF_FALSE(rootChromeWin, "How did we not get a chrome window here?");
 
     nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
     rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
@@ -2476,24 +2452,22 @@ nsFrameLoader::AttributeChanged(nsIDocum
   }
 
   // Note: This logic duplicates a lot of logic in
   // MaybeCreateDocshell.  We should fix that.
 
   // Notify our enclosing chrome that our type has changed.  We only do this
   // if our parent is chrome, since in all other cases we're random content
   // subframes and the treeowner shouldn't worry about us.
-
-  nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
-  if (!docShellAsItem) {
+  if (!mDocShell) {
     return;
   }
 
   nsCOMPtr<nsIDocShellTreeItem> parentItem;
-  docShellAsItem->GetParent(getter_AddRefs(parentItem));
+  mDocShell->GetParent(getter_AddRefs(parentItem));
   if (!parentItem) {
     return;
   }
 
   int32_t parentType;
   parentItem->GetItemType(&parentType);
 
   if (parentType != nsIDocShellTreeItem::typeChrome) {
@@ -2511,28 +2485,28 @@ nsFrameLoader::AttributeChanged(nsIDocum
 
   bool is_primary = value.LowerCaseEqualsLiteral("content-primary");
 
 #ifdef MOZ_XUL
   // when a content panel is no longer primary, hide any open popups it may have
   if (!is_primary) {
     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     if (pm)
-      pm->HidePopupsInDocShell(docShellAsItem);
+      pm->HidePopupsInDocShell(mDocShell);
   }
 #endif
 
-  parentTreeOwner->ContentShellRemoved(docShellAsItem);
+  parentTreeOwner->ContentShellRemoved(mDocShell);
   if (value.LowerCaseEqualsLiteral("content") ||
       StringBeginsWith(value, NS_LITERAL_STRING("content-"),
                        nsCaseInsensitiveStringComparator())) {
     bool is_targetable = is_primary ||
       value.LowerCaseEqualsLiteral("content-targetable");
 
-    parentTreeOwner->ContentShellAdded(docShellAsItem, is_primary,
+    parentTreeOwner->ContentShellAdded(mDocShell, is_primary,
                                        is_targetable, value);
   }
 }
 
 void
 nsFrameLoader::ResetPermissionManagerStatus()
 {
   // The resetting of the permissions status can run only
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -337,16 +337,17 @@ GK_ATOM(end_before, "end_before")
 GK_ATOM(equalsize, "equalsize")
 GK_ATOM(error, "error")
 GK_ATOM(even, "even")
 GK_ATOM(event, "event")
 GK_ATOM(events, "events")
 GK_ATOM(excludeResultPrefixes, "exclude-result-prefixes")
 GK_ATOM(excludes, "excludes")
 GK_ATOM(expr, "expr")
+GK_ATOM(expectingSystemMessage, "expecting-system-message")
 GK_ATOM(extends, "extends")
 GK_ATOM(extensionElementPrefixes, "extension-element-prefixes")
 GK_ATOM(face, "face")
 GK_ATOM(fallback, "fallback")
 GK_ATOM(_false, "false")
 GK_ATOM(farthest, "farthest")
 GK_ATOM(field, "field")
 GK_ATOM(fieldset, "fieldset")
--- a/content/base/src/nsHTMLContentSerializer.cpp
+++ b/content/base/src/nsHTMLContentSerializer.cpp
@@ -28,17 +28,16 @@
 #include "nsITextToSubURI.h"
 #include "nsCRT.h"
 #include "nsIParserService.h"
 #include "nsContentUtils.h"
 #include "nsLWBrkCIID.h"
 #include "nsIScriptElement.h"
 #include "nsAttrName.h"
 #include "nsIDocShell.h"
-#include "nsIEditorDocShell.h"
 #include "nsIEditor.h"
 #include "nsIHTMLEditor.h"
 #include "mozilla/dom/Element.h"
 #include "nsParserConstants.h"
 
 using namespace mozilla::dom;
 
 static const int32_t kLongLineLen = 128;
--- a/content/base/src/nsINode.cpp
+++ b/content/base/src/nsINode.cpp
@@ -53,17 +53,16 @@
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentType.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMEventListener.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMUserDataHandler.h"
-#include "nsIEditorDocShell.h"
 #include "nsIEditor.h"
 #include "nsIEditorIMESupport.h"
 #include "nsIFrame.h"
 #include "nsIJSContextStack.h"
 #include "nsILinkHandler.h"
 #include "nsINameSpaceManager.h"
 #include "nsINodeInfo.h"
 #include "nsIPresShell.h"
--- a/content/base/src/nsMixedContentBlocker.cpp
+++ b/content/base/src/nsMixedContentBlocker.cpp
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsMixedContentBlocker.h"
 #include "nsContentPolicyUtils.h"
 
 #include "nsINode.h"
 #include "nsCOMPtr.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsISecurityEventSink.h"
 #include "nsIWebProgressListener.h"
 #include "nsContentUtils.h"
 #include "nsNetUtil.h"
 #include "nsIRequest.h"
 #include "nsIDocument.h"
 #include "nsIContentViewer.h"
 #include "nsIChannel.h"
@@ -56,22 +55,21 @@ public:
     // calling NS_CP_GetDocShellFromContext on the context, and QI'ing to
     // nsISecurityEventSink.
 
 
     // Mixed content was allowed and is about to load; get the document and
     // set the approriate flag to true if we are about to load Mixed Active
     // Content.
     nsCOMPtr<nsIDocShell> docShell = NS_CP_GetDocShellFromContext(mContext);
-    nsCOMPtr<nsIDocShellTreeItem> currentDocShellTreeItem(do_QueryInterface(docShell));
-    if (!currentDocShellTreeItem) {
+    if (!docShell) {
         return NS_OK;
     }
     nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
-    currentDocShellTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
+    docShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
     NS_ASSERTION(sameTypeRoot, "No document shell root tree item from document shell tree item!");
 
     // now get the document from sameTypeRoot
     nsCOMPtr<nsIDocument> rootDoc = do_GetInterface(sameTypeRoot);
     NS_ASSERTION(rootDoc, "No root document from document shell root tree item.");
 
 
     if (mType == eMixedScript) {
@@ -363,20 +361,18 @@ nsMixedContentBlocker::ShouldLoad(uint32
   bool allowMixedContent = false;
   bool isRootDocShell = false;
   rv = docShell->GetAllowMixedContentAndConnectionData(&rootHasSecureConnection, &allowMixedContent, &isRootDocShell);
   if (NS_FAILED(rv)) {
      return rv;
   }
 
   // Get the root document from the docshell
-  nsCOMPtr<nsIDocShellTreeItem> currentDocShellTreeItem(do_QueryInterface(docShell));
-  NS_ASSERTION(currentDocShellTreeItem, "No DocShellTreeItem from docshell");  
   nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
-  currentDocShellTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
+  docShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
   NS_ASSERTION(sameTypeRoot, "No document shell root tree item from document shell tree item!");
   nsCOMPtr<nsIDocument> rootDoc = do_GetInterface(sameTypeRoot);
   NS_ASSERTION(rootDoc, "No root document from document shell root tree item.");
 
   // Get eventSink and the current security state from the docShell
   nsCOMPtr<nsISecurityEventSink> eventSink = do_QueryInterface(docShell);
   NS_ASSERTION(eventSink, "No eventSink from docShell.");
   nsCOMPtr<nsIDocShell> rootShell = do_GetInterface(sameTypeRoot);
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -1753,36 +1753,30 @@ nsObjectLoadingContent::LoadObject(bool 
         //            reject plugins
         fallbackType = eFallbackUserDisabled;
       } else {
         fallbackType = eFallbackSuppressed;
       }
     }
   }
 
-  // Items resolved as Image/Document will not be checked for previews, as well
-  // as invalid plugins (they will not have the mContentType set).
-  if ((mType == eType_Null || mType == eType_Plugin) && ShouldPreview()) {
-    // If plugin preview exists, we shall use it
-    LOG(("OBJLC [%p]: Using plugin preview", this));
-    mType = eType_Null;
-    fallbackType = eFallbackPlayPreview;
-  }
-
   // If we're a plugin but shouldn't start yet, load fallback with
-  // reason click-to-play instead
+  // reason click-to-play instead. Items resolved as Image/Document
+  // will not be checked for previews, as well as invalid plugins
+  // (they will not have the mContentType set).
   FallbackType clickToPlayReason;
-  if (mType == eType_Plugin && !ShouldPlay(clickToPlayReason)) {
+  if ((mType == eType_Null || mType == eType_Plugin) &&
+      !ShouldPlay(clickToPlayReason)) {
     LOG(("OBJLC [%p]: Marking plugin as click-to-play", this));
     mType = eType_Null;
     fallbackType = clickToPlayReason;
   }
 
   if (!mActivated && mType == eType_Plugin) {
-    // Object passed ShouldPlay and !ShouldPreview, so it should be considered
+    // Object passed ShouldPlay, so it should be considered
     // activated until it changes content type
     LOG(("OBJLC [%p]: Object implicitly activated", this));
     mActivated = true;
   }
 
   // Sanity check: We shouldn't have any loaded resources, pending events, or
   // a final listener at this point
   if (mFrameLoader || mPendingInstantiateEvent || mInstanceOwner ||
@@ -2645,37 +2639,44 @@ nsObjectLoadingContent::CancelPlayPrevie
   if (mType == eType_Null && mFallbackType == eFallbackPlayPreview) {
     return LoadObject(true, true);
   }
 
   return NS_OK;
 }
 
 bool
-nsObjectLoadingContent::ShouldPreview()
-{
-  if (mPlayPreviewCanceled || mActivated)
-    return false;
-
-  nsRefPtr<nsPluginHost> pluginHost =
-    already_AddRefed<nsPluginHost>(nsPluginHost::GetInst());
-
-  return pluginHost->IsPluginPlayPreviewForType(mContentType.get());
-}
-
-bool
 nsObjectLoadingContent::ShouldPlay(FallbackType &aReason)
 {
   // mActivated is true if we've been activated via PlayPlugin() (e.g. user has
   // clicked through). Otherwise, only play if click-to-play is off or if page
   // is whitelisted
 
   nsRefPtr<nsPluginHost> pluginHost =
     already_AddRefed<nsPluginHost>(nsPluginHost::GetInst());
 
+  nsCOMPtr<nsIPluginPlayPreviewInfo> playPreviewInfo;
+  bool isPlayPreviewSpecified = NS_SUCCEEDED(pluginHost->GetPlayPreviewInfo(
+    mContentType, getter_AddRefs(playPreviewInfo)));
+  bool ignoreCTP = false;
+  if (isPlayPreviewSpecified) {
+    playPreviewInfo->GetIgnoreCTP(&ignoreCTP);
+  }
+  if (isPlayPreviewSpecified && !mPlayPreviewCanceled && !mActivated &&
+      ignoreCTP) {
+    // play preview in ignoreCTP mode is shown even if the native plugin
+    // is not present/installed
+    aReason = eFallbackPlayPreview;
+    return false;
+  }
+  // at this point if it's not a plugin, we let it play/fallback
+  if (mType != eType_Plugin) {
+    return true;
+  }
+
   bool isCTP;
   nsresult rv = pluginHost->IsPluginClickToPlayForType(mContentType, &isCTP);
   if (NS_FAILED(rv)) {
     return false;
   }
 
   if (!isCTP || mActivated) {
     return true;
@@ -2730,11 +2731,17 @@ nsObjectLoadingContent::ShouldPlay(Fallb
     uint32_t permission;
     rv = permissionManager->TestPermissionFromPrincipal(topDoc->NodePrincipal(),
                                                         permissionString.Data(),
                                                         &permission);
     NS_ENSURE_SUCCESS(rv, false);
     allowPerm = permission == nsIPermissionManager::ALLOW_ACTION;
   }
 
+  if (aReason == eFallbackClickToPlay && isPlayPreviewSpecified &&
+      !mPlayPreviewCanceled && !ignoreCTP) {
+    // play preview in click-to-play mode is shown instead of standard CTP UI
+    aReason = eFallbackPlayPreview;
+  }
+
   return allowPerm;
 }
 
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -297,21 +297,16 @@ class nsObjectLoadingContent : public ns
     /**
      * If this object is allowed to play plugin content, or if it would display
      * click-to-play instead.
      * NOTE that this does not actually check if the object is a loadable plugin
      */
     bool ShouldPlay(FallbackType &aReason);
 
     /**
-     * If the object should display preview content for the current mContentType
-     */
-    bool ShouldPreview();
-
-    /**
      * Helper to check if our current URI passes policy
      *
      * @param aContentPolicy [out] The result of the content policy decision
      *
      * @return true if call succeeded and NS_CP_ACCEPTED(*aContentPolicy)
      */
     bool CheckLoadPolicy(int16_t *aContentPolicy);
 
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -38,18 +38,16 @@
 #include "nsReadableUtils.h"
 
 #include "nsColor.h"
 #include "nsGfxCIID.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIDocShell.h"
 #include "nsIDOMWindow.h"
 #include "nsPIDOMWindow.h"
-#include "nsIDocShellTreeItem.h"
-#include "nsIDocShellTreeNode.h"
 #include "nsIXPConnect.h"
 #include "nsDisplayList.h"
 
 #include "nsTArray.h"
 
 #include "imgIEncoder.h"
 
 #include "gfxContext.h"
--- a/content/canvas/src/DocumentRendererChild.cpp
+++ b/content/canvas/src/DocumentRendererChild.cpp
@@ -6,18 +6,16 @@
 
 #include "base/basictypes.h"
 
 #include "gfxImageSurface.h"
 #include "gfxPattern.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDOMWindow.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellTreeNode.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsCSSParser.h"
 #include "nsPresContext.h"
 #include "nsCOMPtr.h"
 #include "nsColor.h"
 #include "gfxContext.h"
 #include "nsLayoutUtils.h"
--- a/content/events/src/nsDOMDataTransfer.cpp
+++ b/content/events/src/nsDOMDataTransfer.cpp
@@ -20,17 +20,16 @@
 #include "nsError.h"
 #include "nsIDragService.h"
 #include "nsIScriptableRegion.h"
 #include "nsContentUtils.h"
 #include "nsIContent.h"
 #include "nsCRT.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIWebNavigation.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsIScriptContext.h"
 
 using namespace mozilla;
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMDataTransfer)
   if (tmp->mFiles) {
     tmp->mFiles->Disconnect();
     NS_IMPL_CYCLE_COLLECTION_UNLINK(mFiles)
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -15,31 +15,28 @@
 #include "nsINodeInfo.h"
 #include "nsIDocument.h"
 #include "nsIFrame.h"
 #include "nsIWidget.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsDOMEvent.h"
 #include "nsGkAtoms.h"
-#include "nsIEditorDocShell.h"
 #include "nsIFormControl.h"
 #include "nsIComboboxControlFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIDOMXULControlElement.h"
 #include "nsINameSpaceManager.h"
 #include "nsIBaseWindow.h"
 #include "nsISelection.h"
 #include "nsFrameSelection.h"
 #include "nsPIDOMWindow.h"
 #include "nsPIWindowRoot.h"
 #include "nsIEnumerator.h"
-#include "nsIDocShellTreeItem.h"
-#include "nsIDocShellTreeNode.h"
 #include "nsIWebNavigation.h"
 #include "nsIContentViewer.h"
 #include <algorithm>
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #endif
 #include "nsFrameManager.h"
 
--- a/content/events/src/nsIMEStateManager.cpp
+++ b/content/events/src/nsIMEStateManager.cpp
@@ -6,17 +6,16 @@
 
 #include "nsIMEStateManager.h"
 #include "nsCOMPtr.h"
 #include "nsViewManager.h"
 #include "nsIPresShell.h"
 #include "nsISupports.h"
 #include "nsPIDOMWindow.h"
 #include "nsIInterfaceRequestorUtils.h"
-#include "nsIEditorDocShell.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsPresContext.h"
 #include "nsIDOMWindow.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsContentUtils.h"
 #include "nsINode.h"
 #include "nsIFrame.h"
--- a/content/html/content/public/nsHTMLMediaElement.h
+++ b/content/html/content/public/nsHTMLMediaElement.h
@@ -14,17 +14,17 @@
 #include "nsThreadUtils.h"
 #include "nsIDOMRange.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsILoadGroup.h"
 #include "nsIObserver.h"
 #include "AudioStream.h"
 #include "VideoFrameContainer.h"
 #include "mozilla/CORSMode.h"
-#include "nsDOMMediaStream.h"
+#include "DOMMediaStream.h"
 #include "mozilla/Mutex.h"
 #include "nsTimeRanges.h"
 #include "nsIDOMWakeLock.h"
 #include "AudioChannelCommon.h"
 #include "DecoderTraits.h"
 #include "MediaMetadataManager.h"
 #include "AudioChannelAgent.h"
 
@@ -49,16 +49,17 @@ public:
   typedef mozilla::layers::ImageContainer ImageContainer;
   typedef mozilla::VideoFrameContainer VideoFrameContainer;
   typedef mozilla::MediaStream MediaStream;
   typedef mozilla::MediaResource MediaResource;
   typedef mozilla::MediaDecoderOwner MediaDecoderOwner;
   typedef mozilla::MetadataTags MetadataTags;
   typedef mozilla::AudioStream AudioStream;
   typedef mozilla::MediaDecoder MediaDecoder;
+  typedef mozilla::DOMMediaStream DOMMediaStream;
 
   mozilla::CORSMode GetCORSMode() {
     return mCORSMode;
   }
 
   nsHTMLMediaElement(already_AddRefed<nsINodeInfo> aNodeInfo);
   virtual ~nsHTMLMediaElement();
 
@@ -363,30 +364,30 @@ protected:
    * we'll force a reflow so that the video frame gets reflowed to reflect
    * the poster hiding or showing immediately.
    */
   void SetPlayedOrSeeked(bool aValue);
 
   /**
    * Initialize the media element for playback of aStream
    */
-  void SetupSrcMediaStreamPlayback(nsDOMMediaStream* aStream);
+  void SetupSrcMediaStreamPlayback(DOMMediaStream* aStream);
   /**
    * Stop playback on mSrcStream.
    */
   void EndSrcMediaStreamPlayback();
 
   /**
    * Returns an nsDOMMediaStream containing the played contents of this
    * element. When aFinishWhenEnded is true, when this element ends playback
    * we will finish the stream and not play any more into it.
    * When aFinishWhenEnded is false, ending playback does not finish the stream.
    * The stream will never finish.
    */
-  already_AddRefed<nsDOMMediaStream> CaptureStreamInternal(bool aFinishWhenEnded);
+  already_AddRefed<DOMMediaStream> CaptureStreamInternal(bool aFinishWhenEnded);
 
   /**
    * Create a decoder for the given aMIMEType. Returns null if we
    * were unable to create the decoder.
    */
   already_AddRefed<MediaDecoder> CreateDecoder(const nsACString& aMIMEType);
 
   /**
@@ -634,27 +635,27 @@ protected:
   nsRefPtr<MediaDecoder> mDecoder;
 
   // A reference to the VideoFrameContainer which contains the current frame
   // of video to display.
   nsRefPtr<VideoFrameContainer> mVideoFrameContainer;
 
   // Holds a reference to the DOM wrapper for the MediaStream that has been
   // set in the src attribute.
-  nsRefPtr<nsDOMMediaStream> mSrcAttrStream;
+  nsRefPtr<DOMMediaStream> mSrcAttrStream;
 
   // Holds a reference to the DOM wrapper for the MediaStream that we're
   // actually playing.
   // At most one of mDecoder and mSrcStream can be non-null.
-  nsRefPtr<nsDOMMediaStream> mSrcStream;
+  nsRefPtr<DOMMediaStream> mSrcStream;
 
   // Holds references to the DOM wrappers for the MediaStreams that we're
   // writing to.
   struct OutputMediaStream {
-    nsRefPtr<nsDOMMediaStream> mStream;
+    nsRefPtr<DOMMediaStream> mStream;
     bool mFinishWhenEnded;
   };
   nsTArray<OutputMediaStream> mOutputStreams;
 
   // Holds a reference to the MediaStreamListener attached to mSrcStream.
   nsRefPtr<StreamListener> mSrcStreamListener;
 
   // Holds a reference to the first channel we open to the media resource.
--- a/content/html/content/src/HTMLBodyElement.cpp
+++ b/content/html/content/src/HTMLBodyElement.cpp
@@ -14,17 +14,16 @@
 #include "nsIPresShell.h"
 #include "nsIDocument.h"
 #include "nsHTMLStyleSheet.h"
 #include "nsIEditor.h"
 #include "nsIMarkupDocumentViewer.h"
 #include "nsMappedAttributes.h"
 #include "nsRuleData.h"
 #include "nsIDocShell.h"
-#include "nsIEditorDocShell.h"
 #include "nsRuleWalker.h"
 #include "nsGlobalWindow.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Body)
 DOMCI_NODE_DATA(HTMLBodyElement, mozilla::dom::HTMLBodyElement)
 
 namespace mozilla {
 namespace dom {
@@ -471,22 +470,22 @@ HTMLBodyElement::GetAssociatedEditor()
 
   // For designmode, try to get document's editor
   nsPresContext* presContext = GetPresContext();
   if (!presContext) {
     return nullptr;
   }
 
   nsCOMPtr<nsISupports> container = presContext->GetContainer();
-  nsCOMPtr<nsIEditorDocShell> editorDocShell = do_QueryInterface(container);
-  if (!editorDocShell) {
+  nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(container);
+  if (!docShell) {
     return nullptr;
   }
 
-  editorDocShell->GetEditor(getter_AddRefs(editor));
+  docShell->GetEditor(getter_AddRefs(editor));
   return editor.forget();
 }
 
 bool
 HTMLBodyElement::IsEventAttributeName(nsIAtom *aName)
 {
   return nsContentUtils::IsEventAttributeName(aName,
                                               EventNameType_HTML |
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -38,17 +38,16 @@
 #include "nsIScrollableFrame.h"
 #include "nsView.h"
 #include "nsViewManager.h"
 #include "nsIWidget.h"
 #include "nsRange.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsINameSpaceManager.h"
 #include "nsError.h"
 #include "nsScriptLoader.h"
 #include "nsRuleData.h"
 
 #include "nsPresState.h"
 #include "nsILayoutHistoryState.h"
 
--- a/content/html/content/src/nsGenericHTMLFrameElement.cpp
+++ b/content/html/content/src/nsGenericHTMLFrameElement.cpp
@@ -316,16 +316,29 @@ nsGenericHTMLFrameElement::GetReallyIsAp
 {
   nsAutoString manifestURL;
   GetAppManifestURL(manifestURL);
 
   *aOut = !manifestURL.IsEmpty();
   return NS_OK;
 }
 
+/* [infallible] */ NS_IMETHODIMP
+nsGenericHTMLFrameElement::GetIsExpectingSystemMessage(bool *aOut)
+{
+  *aOut = false;
+
+  if (!nsIMozBrowserFrame::GetReallyIsApp()) {
+    return NS_OK;
+  }
+
+  *aOut = HasAttr(kNameSpaceID_None, nsGkAtoms::expectingSystemMessage);
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 nsGenericHTMLFrameElement::GetAppManifestURL(nsAString& aOut)
 {
   aOut.Truncate();
 
   // At the moment, you can't be an app without being a browser.
   if (!nsIMozBrowserFrame::GetReallyIsBrowserOrApp()) {
     return NS_OK;
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -1081,17 +1081,17 @@ nsHTMLInputElement::ConvertStringToNumbe
   MOZ_ASSERT(DoesValueAsNumberApply(),
              "ConvertStringToNumber only applies if .valueAsNumber applies");
 
   switch (mType) {
     case NS_FORM_INPUT_NUMBER:
       {
         nsresult ec;
         aResultValue = PromiseFlatString(aValue).ToDouble(&ec);
-        if (NS_FAILED(ec)) {
+        if (NS_FAILED(ec) || !MOZ_DOUBLE_IS_FINITE(aResultValue)) {
           return false;
         }
 
         return true;
       }
     case NS_FORM_INPUT_DATE:
       {
         SafeAutoJSContext ctx;
@@ -3069,18 +3069,18 @@ nsHTMLInputElement::SanitizeValue(nsAStr
         aValue.StripChars(crlf);
 
         aValue = nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aValue);
       }
       break;
     case NS_FORM_INPUT_NUMBER:
       {
         nsresult ec;
-        PromiseFlatString(aValue).ToDouble(&ec);
-        if (NS_FAILED(ec)) {
+        double val = PromiseFlatString(aValue).ToDouble(&ec);
+        if (NS_FAILED(ec) || !MOZ_DOUBLE_IS_FINITE(val)) {
           aValue.Truncate();
         }
       }
       break;
     case NS_FORM_INPUT_DATE:
       {
         if (!aValue.IsEmpty() && !IsValidDate(aValue)) {
           aValue.Truncate();
@@ -4513,17 +4513,17 @@ nsHTMLInputElement::GetStep() const
 
   if (stepStr.LowerCaseEqualsLiteral("any")) {
     // The element can't suffer from step mismatch if there is no step.
     return kStepAny;
   }
 
   nsresult ec;
   double step = stepStr.ToDouble(&ec);
-  if (NS_FAILED(ec) || step <= 0) {
+  if (NS_FAILED(ec) || !MOZ_DOUBLE_IS_FINITE(step) || step <= 0) {
     step = GetDefaultStep();
   }
 
   // TODO: This multiplication can lead to inexact results, we should use a
   // type that supports a better precision than double. Bug 783607.
   return step * GetStepScaleFactor();
 }
 
--- a/content/html/content/src/nsHTMLInputElement.h
+++ b/content/html/content/src/nsHTMLInputElement.h
@@ -658,27 +658,29 @@ protected:
    * Update the HAS_RANGE bit field value.
    */
   void UpdateHasRange();
 
   /**
    * Returns the input's "minimum" (as defined by the HTML5 spec) as a double.
    * Note this takes account of any default minimum that the type may have.
    * Returns NaN if the min attribute isn't a valid floating point number and
-   * the input's type does not have a default minimum.
+   * the input's type does not have a default minimum. Otherwise, guaranteed
+   * to return a finite value.
    *
    * NOTE: Only call this if you know DoesMinMaxApply() returns true.
    */
   double GetMinimum() const;
 
   /**
    * Returns the input's "maximum" (as defined by the HTML5 spec) as a double.
    * Note this takes account of any default maximum that the type may have.
    * Returns NaN if the max attribute isn't a valid floating point number and
-   * the input's type does not have a default maximum.
+   * the input's type does not have a default maximum. Otherwise, guaranteed
+   * to return a finite value.
    *
    * NOTE:Only call this if you know DoesMinMaxApply() returns true.
    */
   double GetMaximum() const;
 
    /**
     * Get the step scale value for the current type.
     * See:
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -48,26 +48,24 @@
 #include "nsContentPolicyUtils.h"
 #include "nsCrossSiteListenerProxy.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsICachingChannel.h"
 #include "nsLayoutUtils.h"
 #include "nsVideoFrame.h"
 #include "BasicLayers.h"
 #include <limits>
-#include "nsIDocShellTreeItem.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIAppShell.h"
 #include "nsWidgetsCID.h"
 #include "nsIDOMNotifyAudioAvailableEvent.h"
 #include "nsMediaFragmentURIParser.h"
 #include "nsURIHashKey.h"
 #include "nsJSUtils.h"
 #include "MediaStreamGraph.h"
-#include "nsDOMMediaStream.h"
 #include "nsIScriptError.h"
 #include "nsHostObjectProtocolHandler.h"
 #include "MediaMetadataManager.h"
 
 #include "AudioChannelService.h"
 
 #include "nsCSSParser.h"
 #include "nsIMediaList.h"
@@ -493,17 +491,17 @@ nsHTMLMediaElement::SetMozSrcObject(JSCo
     Load();
     return NS_OK;
   }
   if (aParams.isObject()) {
     nsCOMPtr<nsIDOMMediaStream> stream;
     stream = do_QueryInterface(nsContentUtils::XPConnect()->
         GetNativeOfWrapper(aCtx, JSVAL_TO_OBJECT(aParams)));
     if (stream) {
-      mSrcAttrStream = static_cast<nsDOMMediaStream*>(stream.get());
+      mSrcAttrStream = static_cast<DOMMediaStream*>(stream.get());
       Load();
       return NS_OK;
     }
   }
   // Should we store unsupported values on the element's attribute anyway?
   // Let's not.
   return NS_OK;
 }
@@ -1108,17 +1106,17 @@ nsresult nsHTMLMediaElement::LoadResourc
     if (NS_FAILED(rv)) {
       nsCString specUTF8;
       mLoadingSrc->GetSpec(specUTF8);
       NS_ConvertUTF8toUTF16 spec(specUTF8);
       const PRUnichar* params[] = { spec.get() };
       ReportLoadError("MediaLoadInvalidURI", params, ArrayLength(params));
       return rv;
     }
-    SetupSrcMediaStreamPlayback(static_cast<nsDOMMediaStream*>(stream.get()));
+    SetupSrcMediaStreamPlayback(static_cast<DOMMediaStream*>(stream.get()));
     return NS_OK;
   }
 
   nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
 
   // check for a Content Security Policy to pass down to the channel
   // created to load the media content
   nsCOMPtr<nsIChannelPolicy> channelPolicy;
@@ -1596,48 +1594,59 @@ NS_IMETHODIMP nsHTMLMediaElement::SetMut
   mMuted = aMuted;
   SetMutedInternal(aMuted);
 
   DispatchAsyncEvent(NS_LITERAL_STRING("volumechange"));
 
   return NS_OK;
 }
 
-already_AddRefed<nsDOMMediaStream>
+already_AddRefed<DOMMediaStream>
 nsHTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded)
 {
+  nsIDOMWindow* window = OwnerDoc()->GetInnerWindow();
+  if (!window) {
+    return nullptr;
+  }
+
   OutputMediaStream* out = mOutputStreams.AppendElement();
-  out->mStream = nsDOMMediaStream::CreateTrackUnionStream();
+  out->mStream = DOMMediaStream::CreateTrackUnionStream(window);
   nsRefPtr<nsIPrincipal> principal = GetCurrentPrincipal();
   out->mStream->CombineWithPrincipal(principal);
   out->mFinishWhenEnded = aFinishWhenEnded;
 
   mAudioCaptured = true;
   // Block the output stream initially.
   // Decoders are responsible for removing the block while they are playing
   // back into the output stream.
   out->mStream->GetStream()->ChangeExplicitBlockerCount(1);
   if (mDecoder) {
     mDecoder->SetAudioCaptured(true);
     mDecoder->AddOutputStream(
         out->mStream->GetStream()->AsProcessedStream(), aFinishWhenEnded);
   }
-  nsRefPtr<nsDOMMediaStream> result = out->mStream;
+  nsRefPtr<DOMMediaStream> result = out->mStream;
   return result.forget();
 }
 
 NS_IMETHODIMP nsHTMLMediaElement::MozCaptureStream(nsIDOMMediaStream** aStream)
 {
   *aStream = CaptureStreamInternal(false).get();
+  if (!*aStream) {
+    return NS_ERROR_FAILURE;
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP nsHTMLMediaElement::MozCaptureStreamUntilEnded(nsIDOMMediaStream** aStream)
 {
   *aStream = CaptureStreamInternal(true).get();
+  if (!*aStream) {
+    return NS_ERROR_FAILURE;
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP nsHTMLMediaElement::GetMozAudioCaptured(bool *aCaptured)
 {
   *aCaptured = mAudioCaptured;
   return NS_OK;
 }
@@ -2511,17 +2520,17 @@ private:
   bool mBlocked;
 
   // mMutex protects the fields below; they can be accessed on any thread
   Mutex mMutex;
   bool mPendingNotifyOutput;
   bool mDidHaveCurrentData;
 };
 
-void nsHTMLMediaElement::SetupSrcMediaStreamPlayback(nsDOMMediaStream* aStream)
+void nsHTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
 {
   NS_ASSERTION(!mSrcStream && !mSrcStreamListener, "Should have been ended already");
 
   mSrcStream = aStream;
   // XXX if we ever support capturing the output of a media element which is
   // playing a stream, we'll need to add a CombineWithPrincipal call here.
   mSrcStreamListener = new StreamListener(this);
   GetSrcMediaStream()->AddListener(mSrcStreamListener);
--- a/content/html/document/src/ImageDocument.cpp
+++ b/content/html/document/src/ImageDocument.cpp
@@ -31,17 +31,16 @@
 #include "nsPIDOMWindow.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsError.h"
 #include "nsURILoader.h"
 #include "nsIDocShell.h"
 #include "nsIContentViewer.h"
 #include "nsIMarkupDocumentViewer.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsThreadUtils.h"
 #include "nsIScrollableFrame.h"
 #include "nsContentUtils.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/Preferences.h"
 #include <algorithm>
 
 #define AUTOMATIC_IMAGE_RESIZING_PREF "browser.enable_automatic_image_resizing"
--- a/content/html/document/src/VideoDocument.cpp
+++ b/content/html/document/src/VideoDocument.cpp
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaDocument.h"
 #include "nsGkAtoms.h"
 #include "nsNodeInfoManager.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsHTMLMediaElement.h"
 #include "nsIDocumentInlines.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsContentUtils.h"
 #include "mozilla/dom/Element.h"
 
 namespace mozilla {
 namespace dom {
 
 class VideoDocument : public MediaDocument
 {
--- a/content/html/document/src/nsHTMLContentSink.cpp
+++ b/content/html/document/src/nsHTMLContentSink.cpp
@@ -2064,22 +2064,20 @@ HTMLContentSink::SetDocumentCharset(nsAC
     mDocShell->GetContentViewer(getter_AddRefs(cv));
     if (cv) {
        muCV = do_QueryInterface(cv);
     } else {
       // in this block of code, if we get an error result, we return
       // it but if we get a null pointer, that's perfectly legal for
       // parent and parentContentViewer
 
-      nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
-        do_QueryInterface(mDocShell);
-      NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
+      NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
 
       nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
-      docShellAsItem->GetSameTypeParent(getter_AddRefs(parentAsItem));
+      mDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem));
 
       nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
       if (parent) {
         nsCOMPtr<nsIContentViewer> parentContentViewer;
         nsresult rv =
           parent->GetContentViewer(getter_AddRefs(parentContentViewer));
         if (NS_SUCCEEDED(rv) && parentContentViewer) {
           muCV = do_QueryInterface(parentContentViewer);
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -27,17 +27,16 @@
 #include "nsIStreamListener.h"
 #include "nsIURI.h"
 #include "nsIIOService.h"
 #include "nsNetUtil.h"
 #include "nsIContentViewerContainer.h"
 #include "nsIContentViewer.h"
 #include "nsIMarkupDocumentViewer.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsDocShellLoadTypes.h"
 #include "nsIWebNavigation.h"
 #include "nsIBaseWindow.h"
 #include "nsIWebShellServices.h"
 #include "nsIScriptContext.h"
 #include "nsIXPConnect.h"
 #include "nsContentList.h"
 #include "nsError.h"
@@ -83,17 +82,16 @@
 //AHMED 12-2
 #include "nsBidiUtils.h"
 
 #include "nsIEditingSession.h"
 #include "nsIEditor.h"
 #include "nsNodeInfoManager.h"
 #include "nsIPlaintextEditor.h"
 #include "nsIHTMLEditor.h"
-#include "nsIEditorDocShell.h"
 #include "nsIEditorStyleSheets.h"
 #include "nsIInlineSpellChecker.h"
 #include "nsRange.h"
 #include "mozAutoDocUpdate.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsHtml5Module.h"
 #include "prprf.h"
 #include "mozilla/dom/Element.h"
@@ -678,22 +676,19 @@ nsHTMLDocument::StartDocumentLoad(const 
   // Look for the parent document.  Note that at this point we don't have our
   // content viewer set up yet, and therefore do not have a useful
   // mParentDocument.
 
   // in this block of code, if we get an error result, we return it
   // but if we get a null pointer, that's perfectly legal for parent
   // and parentContentViewer
   nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aContainer));
-
-  nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(docShell));
-
   nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
-  if (docShellAsItem) {
-    docShellAsItem->GetSameTypeParent(getter_AddRefs(parentAsItem));
+  if (docShell) {
+    docShell->GetSameTypeParent(getter_AddRefs(parentAsItem));
   }
 
   nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
   nsCOMPtr<nsIDocument> parentDocument;
   nsCOMPtr<nsIContentViewer> parentContentViewer;
   if (parent) {
     rv = parent->GetContentViewer(getter_AddRefs(parentContentViewer));
     NS_ENSURE_SUCCESS(rv, rv);
@@ -746,17 +741,17 @@ nsHTMLDocument::StartDocumentLoad(const 
   if (!IsHTML() || !docShell) { // no docshell for text/html XHR
     charsetSource = IsHTML() ? kCharsetFromWeakDocTypeDefault
                              : kCharsetFromDocTypeDefault;
     charset.AssignLiteral("UTF-8");
     TryChannelCharset(aChannel, charsetSource, charset, executor);
     parserCharsetSource = charsetSource;
     parserCharset = charset;
   } else {
-    NS_ASSERTION(docShell && docShellAsItem, "Unexpected null value");
+    NS_ASSERTION(docShell, "Unexpected null value");
 
     charsetSource = kCharsetUninitialized;
     wyciwygChannel = do_QueryInterface(aChannel);
 
     // The following will try to get the character encoding from various
     // sources. Each Try* function will return early if the source is already
     // at least as large as any of the sources it might look at.  Some of
     // these functions (like TryHintCharset and TryParentCharset) can set
@@ -2609,22 +2604,18 @@ nsHTMLDocument::DeferredContentEditableC
       nsPIDOMWindow *window = GetWindow();
       if (!window)
         return;
 
       nsIDocShell *docshell = window->GetDocShell();
       if (!docshell)
         return;
 
-      nsCOMPtr<nsIEditorDocShell> editorDocShell =
-        do_QueryInterface(docshell, &rv);
-      NS_ENSURE_SUCCESS_VOID(rv);
-
       nsCOMPtr<nsIEditor> editor;
-      editorDocShell->GetEditor(getter_AddRefs(editor));
+      docshell->GetEditor(getter_AddRefs(editor));
       if (editor) {
         nsRefPtr<nsRange> range = new nsRange();
         rv = range->SelectNode(node);
         if (NS_FAILED(rv)) {
           // The node might be detached from the document at this point,
           // which would cause this call to fail.  In this case, we can
           // safely ignore the contenteditable count change.
           return;
@@ -2886,21 +2877,17 @@ nsHTMLDocument::EditingStateChanged()
       // XXX This can cause flushing which can change the editing state, so make
       //     sure to avoid recursing.
       rv = editSession->MakeWindowEditable(window, "html", false, false,
                                            true);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     // XXX Need to call TearDownEditorOnWindow for all failures.
-    nsCOMPtr<nsIEditorDocShell> editorDocShell =
-      do_QueryInterface(docshell, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    editorDocShell->GetEditor(getter_AddRefs(editor));
+    docshell->GetEditor(getter_AddRefs(editor));
     if (!editor)
       return NS_ERROR_FAILURE;
 
     nsCOMPtr<nsIPresShell> presShell = GetShell();
     NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
 
     // If we're entering the design mode, put the selection at the beginning of
     // the document for compatibility reasons.
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -23,17 +23,16 @@
 #include "nsIWyciwygChannel.h"
 #include "nsILoadGroup.h"
 #include "nsNetUtil.h"
 
 #include "nsICommandManager.h"
 #include "mozilla/dom/HTMLSharedElement.h"
 
 class nsIEditor;
-class nsIEditorDocShell;
 class nsIParser;
 class nsIURI;
 class nsIMarkupDocumentViewer;
 class nsIDocShell;
 class nsICachingChannel;
 
 class nsHTMLDocument : public nsDocument,
                        public nsIHTMLDocument,
rename from content/media/nsDOMMediaStream.cpp
rename to content/media/DOMMediaStream.cpp
--- a/content/media/nsDOMMediaStream.cpp
+++ b/content/media/DOMMediaStream.cpp
@@ -1,117 +1,134 @@
 /* -*- 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 "nsDOMMediaStream.h"
+#include "DOMMediaStream.h"
 #include "nsDOMClassInfoID.h"
 #include "nsContentUtils.h"
+#include "mozilla/dom/MediaStreamBinding.h"
+#include "mozilla/dom/LocalMediaStreamBinding.h"
+#include "MediaStreamGraph.h"
 
 using namespace mozilla;
 
-DOMCI_DATA(MediaStream, nsDOMMediaStream)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMMediaStream)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMMediaStream)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMediaStream)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MediaStream)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMMediaStream)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMMediaStream)
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMMediaStream)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMMediaStream)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMMediaStream)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DOMMediaStream, mWindow)
 
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMMediaStream)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-// LocalMediaStream currently is the same C++ class as MediaStream;
-// they may eventually split
-DOMCI_DATA(LocalMediaStream, nsDOMLocalMediaStream)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMLocalMediaStream)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMLocalMediaStream)
   NS_INTERFACE_MAP_ENTRY(nsIDOMLocalMediaStream)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMMediaStream, nsDOMMediaStream)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMLocalMediaStream)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(LocalMediaStream)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMLocalMediaStream)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMLocalMediaStream)
+NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMLocalMediaStream)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_ADDREF_INHERITED(DOMLocalMediaStream, DOMMediaStream)
+NS_IMPL_RELEASE_INHERITED(DOMLocalMediaStream, DOMMediaStream)
+NS_IMPL_CYCLE_COLLECTION_INHERITED_0(DOMLocalMediaStream, DOMMediaStream)
 
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMLocalMediaStream)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-
-nsDOMMediaStream::~nsDOMMediaStream()
+DOMMediaStream::~DOMMediaStream()
 {
   if (mStream) {
     mStream->Destroy();
   }
 }
 
-NS_IMETHODIMP
-nsDOMMediaStream::GetCurrentTime(double *aCurrentTime)
+JSObject*
+DOMMediaStream::WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap)
+{
+  return dom::MediaStreamBinding::Wrap(aCx, aScope, this, aTriedToWrap);
+}
+
+double
+DOMMediaStream::CurrentTime()
 {
-  *aCurrentTime = mStream ? MediaTimeToSeconds(mStream->GetCurrentTime()) : 0.0;
-  return NS_OK;
+  return mStream ? MediaTimeToSeconds(mStream->GetCurrentTime()) : 0.0;
+}
+
+bool
+DOMMediaStream::IsFinished()
+{
+  return !mStream || mStream->IsFinished();
+}
+
+void
+DOMMediaStream::InitSourceStream(nsIDOMWindow* aWindow, uint32_t aHintContents)
+{
+  mWindow = aWindow;
+  SetHintContents(aHintContents);
+  MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
+  mStream = gm->CreateSourceStream(this);
 }
 
-nsDOMLocalMediaStream::~nsDOMLocalMediaStream()
+void
+DOMMediaStream::InitTrackUnionStream(nsIDOMWindow* aWindow, uint32_t aHintContents)
+{
+  mWindow = aWindow;
+  SetHintContents(aHintContents);
+  MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
+  mStream = gm->CreateTrackUnionStream(this);
+}
+
+already_AddRefed<DOMMediaStream>
+DOMMediaStream::CreateSourceStream(nsIDOMWindow* aWindow, uint32_t aHintContents)
+{
+  nsRefPtr<DOMMediaStream> stream = new DOMMediaStream();
+  stream->InitSourceStream(aWindow, aHintContents);
+  return stream.forget();
+}
+
+already_AddRefed<DOMMediaStream>
+DOMMediaStream::CreateTrackUnionStream(nsIDOMWindow* aWindow, uint32_t aHintContents)
+{
+  nsRefPtr<DOMMediaStream> stream = new DOMMediaStream();
+  stream->InitTrackUnionStream(aWindow, aHintContents);
+  return stream.forget();
+}
+
+bool
+DOMMediaStream::CombineWithPrincipal(nsIPrincipal* aPrincipal)
+{
+  return nsContentUtils::CombineResourcePrincipals(&mPrincipal, aPrincipal);
+}
+
+DOMLocalMediaStream::~DOMLocalMediaStream()
 {
   if (mStream) {
     // Make sure Listeners of this stream know it's going away
     Stop();
   }
 }
 
-NS_IMETHODIMP
-nsDOMLocalMediaStream::Stop()
+JSObject*
+DOMLocalMediaStream::WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap)
+{
+  return dom::LocalMediaStreamBinding::Wrap(aCx, aScope, this, aTriedToWrap);
+}
+
+void
+DOMLocalMediaStream::Stop()
 {
   if (mStream && mStream->AsSourceStream()) {
     mStream->AsSourceStream()->EndAllTrackAndFinish();
   }
-  return NS_OK;
 }
 
-already_AddRefed<nsDOMMediaStream>
-nsDOMMediaStream::CreateSourceStream(uint32_t aHintContents)
+already_AddRefed<DOMLocalMediaStream>
+DOMLocalMediaStream::CreateSourceStream(nsIDOMWindow* aWindow, uint32_t aHintContents)
 {
-  nsRefPtr<nsDOMMediaStream> stream = new nsDOMMediaStream();
-  stream->InitSourceStream(aHintContents);
-  return stream.forget();
-}
-
-already_AddRefed<nsDOMLocalMediaStream>
-nsDOMLocalMediaStream::CreateSourceStream(uint32_t aHintContents)
-{
-  nsRefPtr<nsDOMLocalMediaStream> stream = new nsDOMLocalMediaStream();
-  stream->InitSourceStream(aHintContents);
+  nsRefPtr<DOMLocalMediaStream> stream = new DOMLocalMediaStream();
+  stream->InitSourceStream(aWindow, aHintContents);
   return stream.forget();
 }
 
-already_AddRefed<nsDOMMediaStream>
-nsDOMMediaStream::CreateTrackUnionStream(uint32_t aHintContents)
+already_AddRefed<DOMLocalMediaStream>
+DOMLocalMediaStream::CreateTrackUnionStream(nsIDOMWindow* aWindow, uint32_t aHintContents)
 {
-  nsRefPtr<nsDOMMediaStream> stream = new nsDOMMediaStream();
-  stream->InitTrackUnionStream(aHintContents);
+  nsRefPtr<DOMLocalMediaStream> stream = new DOMLocalMediaStream();
+  stream->InitTrackUnionStream(aWindow, aHintContents);
   return stream.forget();
 }
-
-already_AddRefed<nsDOMLocalMediaStream>
-nsDOMLocalMediaStream::CreateTrackUnionStream(uint32_t aHintContents)
-{
-  nsRefPtr<nsDOMLocalMediaStream> stream = new nsDOMLocalMediaStream();
-  stream->InitTrackUnionStream(aHintContents);
-  return stream.forget();
-}
-
-bool
-nsDOMMediaStream::CombineWithPrincipal(nsIPrincipal* aPrincipal)
-{
-  return nsContentUtils::CombineResourcePrincipals(&mPrincipal, aPrincipal);
-}
rename from content/media/nsDOMMediaStream.h
rename to content/media/DOMMediaStream.h
--- a/content/media/nsDOMMediaStream.h
+++ b/content/media/DOMMediaStream.h
@@ -2,50 +2,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/. */
 
 #ifndef NSDOMMEDIASTREAM_H_
 #define NSDOMMEDIASTREAM_H_
 
 #include "nsIDOMMediaStream.h"
-#include "MediaStreamGraph.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIPrincipal.h"
+#include "nsWrapperCache.h"
+#include "nsIDOMWindow.h"
 
 class nsXPCClassInfo;
 
 // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
 // GetTickCount() and conflicts with NS_DECL_NSIDOMMEDIASTREAM, containing
 // currentTime getter.
 #ifdef GetCurrentTime
 #undef GetCurrentTime
 #endif
+// X11 has a #define for CurrentTime. Unbelievable :-(.
+#ifdef CurrentTime
+#undef CurrentTime
+#endif
+
+namespace mozilla {
+
+class MediaStream;
 
 /**
  * DOM wrapper for MediaStreams.
  */
-class nsDOMMediaStream : public nsIDOMMediaStream
+class DOMMediaStream : public nsIDOMMediaStream,
+                       public nsWrapperCache
 {
-  friend class nsDOMLocalMediaStream;
+  friend class DOMLocalMediaStream;
 
 public:
-  typedef mozilla::MediaStream MediaStream;
-  typedef mozilla::MediaStreamGraph MediaStreamGraph;
+  DOMMediaStream() : mStream(nullptr), mHintContents(0)
+  {
+    SetIsDOMBinding();
+  }
+  virtual ~DOMMediaStream();
 
-  nsDOMMediaStream() : mStream(nullptr), mHintContents(0) {}
-  virtual ~nsDOMMediaStream();
-
-  NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMMediaStream)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMMediaStream)
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
-  NS_DECL_NSIDOMMEDIASTREAM
+  nsIDOMWindow* GetParentObject() const
+  {
+    return mWindow;
+  }
+  virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap);
 
+  double CurrentTime();
   MediaStream* GetStream() { return mStream; }
-  bool IsFinished() { return !mStream || mStream->IsFinished(); }
+  bool IsFinished();
   /**
    * Returns a principal indicating who may access this stream. The stream contents
    * can only be accessed by principals subsuming this principal.
    */
   nsIPrincipal* GetPrincipal() { return mPrincipal; }
 
   /**
    * Indicate that data will be contributed to this stream from origin aPrincipal.
@@ -53,75 +68,75 @@ public:
    * of this stream can only be accessed by principals that subsume aPrincipal.
    * Returns true if the stream's principal changed.
    */
   bool CombineWithPrincipal(nsIPrincipal* aPrincipal);
 
   /**
    * Create an nsDOMMediaStream whose underlying stream is a SourceMediaStream.
    */
-  static already_AddRefed<nsDOMMediaStream> CreateSourceStream(uint32_t aHintContents);
+  static already_AddRefed<DOMMediaStream>
+  CreateSourceStream(nsIDOMWindow* aWindow, uint32_t aHintContents);
 
   // Hints to tell the SDP generator about whether this
   // MediaStream probably has audio and/or video
   enum {
     HINT_CONTENTS_AUDIO = 0x00000001U,
     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<DOMMediaStream>
+  CreateTrackUnionStream(nsIDOMWindow* aWindow, uint32_t aHintContents = 0);
 
 protected:
-  void InitSourceStream(uint32_t aHintContents)
-  {
-    SetHintContents(aHintContents);
-    MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
-    mStream = gm->CreateSourceStream(this);
-  }
-  void InitTrackUnionStream(uint32_t aHintContents)
-  {
-    SetHintContents(aHintContents);
-    MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
-    mStream = gm->CreateTrackUnionStream(this);
-  }
+  void InitSourceStream(nsIDOMWindow* aWindow, uint32_t aHintContents);
+  void InitTrackUnionStream(nsIDOMWindow* aWindow, uint32_t aHintContents);
+
+  // We need this to track our parent object.
+  nsCOMPtr<nsIDOMWindow> mWindow;
 
   // 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;
 
   // tells the SDP generator about whether this
   // MediaStream probably has audio and/or video
   uint32_t mHintContents;
 };
 
-class nsDOMLocalMediaStream : public nsDOMMediaStream,
-                              public nsIDOMLocalMediaStream
+class DOMLocalMediaStream : public DOMMediaStream,
+                            public nsIDOMLocalMediaStream
 {
 public:
-  nsDOMLocalMediaStream() {}
-  virtual ~nsDOMLocalMediaStream();
+  DOMLocalMediaStream() {}
+  virtual ~DOMLocalMediaStream();
 
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMLocalMediaStream, nsDOMMediaStream)
-  NS_DECL_NSIDOMLOCALMEDIASTREAM
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DOMLocalMediaStream, DOMMediaStream)
 
-  NS_FORWARD_NSIDOMMEDIASTREAM(nsDOMMediaStream::)
+  virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap);
+
+  virtual void Stop();
 
   /**
    * Create an nsDOMLocalMediaStream whose underlying stream is a SourceMediaStream.
    */
-  static already_AddRefed<nsDOMLocalMediaStream> CreateSourceStream(uint32_t aHintContents);
+  static already_AddRefed<DOMLocalMediaStream>
+  CreateSourceStream(nsIDOMWindow* aWindow, uint32_t aHintContents);
 
   /**
    * Create an nsDOMLocalMediaStream whose underlying stream is a TrackUnionStream.
    */
-  static already_AddRefed<nsDOMLocalMediaStream> CreateTrackUnionStream(uint32_t aHintContents = 0);
+  static already_AddRefed<DOMLocalMediaStream>
+  CreateTrackUnionStream(nsIDOMWindow* aWindow, uint32_t aHintContents = 0);
 };
 
+}
+
 #endif /* NSDOMMEDIASTREAM_H_ */
--- a/content/media/Makefile.in
+++ b/content/media/Makefile.in
@@ -21,26 +21,26 @@ EXPORTS = \
   AudioChannelFormat.h \
   AudioEventTimeline.h \
   AudioNodeEngine.h \
   AudioNodeStream.h \
   AudioSampleFormat.h \
   AudioSegment.h \
   BufferMediaResource.h \
   DecoderTraits.h \
+  DOMMediaStream.h \
   FileBlockCache.h \
   MediaDecoderOwner.h \
   MediaResource.h \
   MediaSegment.h \
   MediaStreamGraph.h \
   AudioAvailableEventManager.h \
   MediaDecoder.h \
   MediaDecoderStateMachine.h \
   MediaDecoderReader.h \
-  nsDOMMediaStream.h \
   MediaCache.h \
   SharedBuffer.h \
   StreamBuffer.h \
   TimeVarying.h \
   VideoFrameContainer.h \
   VideoUtils.h \
   VideoSegment.h \
   VorbisUtils.h \
@@ -48,24 +48,24 @@ EXPORTS = \
   $(NULL)
 
 CPPSRCS = \
   AudioChannelFormat.cpp \
   AudioNodeEngine.cpp \
   AudioNodeStream.cpp \
   AudioSegment.cpp \
   DecoderTraits.cpp \
+  DOMMediaStream.cpp \
   FileBlockCache.cpp \
   MediaResource.cpp \
   MediaStreamGraph.cpp \
   AudioAvailableEventManager.cpp \
   MediaDecoder.cpp \
   MediaDecoderStateMachine.cpp \
   MediaDecoderReader.cpp \
-  nsDOMMediaStream.cpp \
   MediaCache.cpp \
   StreamBuffer.cpp \
   VideoFrameContainer.cpp \
   VideoSegment.cpp \
   VideoUtils.cpp \
   $(NULL)
 
 ifdef MOZ_SYDNEYAUDIO
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -1951,28 +1951,28 @@ MediaStreamGraph::GetInstance()
     gGraph = new MediaStreamGraphImpl();
     LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", gGraph));
   }
 
   return gGraph;
 }
 
 SourceMediaStream*
-MediaStreamGraph::CreateSourceStream(nsDOMMediaStream* aWrapper)
+MediaStreamGraph::CreateSourceStream(DOMMediaStream* aWrapper)
 {
   SourceMediaStream* stream = new SourceMediaStream(aWrapper);
   NS_ADDREF(stream);
   MediaStreamGraphImpl* graph = static_cast<MediaStreamGraphImpl*>(this);
   stream->SetGraphImpl(graph);
   graph->AppendMessage(new CreateMessage(stream));
   return stream;
 }
 
 ProcessedMediaStream*
-MediaStreamGraph::CreateTrackUnionStream(nsDOMMediaStream* aWrapper)
+MediaStreamGraph::CreateTrackUnionStream(DOMMediaStream* aWrapper)
 {
   TrackUnionStream* stream = new TrackUnionStream(aWrapper);
   NS_ADDREF(stream);
   MediaStreamGraphImpl* graph = static_cast<MediaStreamGraphImpl*>(this);
   stream->SetGraphImpl(graph);
   graph->AppendMessage(new CreateMessage(stream));
   return stream;
 }
--- a/content/media/MediaStreamGraph.h
+++ b/content/media/MediaStreamGraph.h
@@ -12,19 +12,19 @@
 #include "nsIRunnable.h"
 #include "nsISupportsImpl.h"
 #include "StreamBuffer.h"
 #include "TimeVarying.h"
 #include "VideoFrameContainer.h"
 #include "VideoSegment.h"
 #include "nsThreadUtils.h"
 
-class nsDOMMediaStream;
+namespace mozilla {
 
-namespace mozilla {
+class DOMMediaStream;
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gMediaStreamGraphLog;
 #endif
 
 /**
  * Microseconds relative to the start of the graph timeline.
  */
@@ -255,17 +255,17 @@ struct AudioChunk;
  * collected via cycle collection. Destroy messages will be sent
  * for those objects in arbitrary order and the MediaStreamGraph has to be able
  * to handle this.
  */
 class MediaStream {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStream)
 
-  MediaStream(nsDOMMediaStream* aWrapper)
+  MediaStream(DOMMediaStream* aWrapper)
     : mBufferStartTime(0)
     , mExplicitBlockerCount(0)
     , mBlocked(false)
     , mGraphUpdateIndices(0)
     , mFinished(false)
     , mNotifiedFinished(false)
     , mNotifiedBlocked(false)
     , mWrapper(aWrapper)
@@ -510,17 +510,17 @@ protected:
   // Temporary data for computing blocking status of streams
   // True if we've added this stream to the set of streams we're computing
   // blocking for.
   bool mInBlockingSet;
   // True if this stream should be blocked in this phase.
   bool mBlockInThisPhase;
 
   // This state is only used on the main thread.
-  nsDOMMediaStream* mWrapper;
+  DOMMediaStream* mWrapper;
   // Main-thread views of state
   StreamTime mMainThreadCurrentTime;
   bool mMainThreadFinished;
   bool mMainThreadDestroyed;
 
   // Our media stream graph
   MediaStreamGraphImpl* mGraph;
 };
@@ -528,17 +528,17 @@ protected:
 /**
  * This is a stream into which a decoder can write audio and video.
  *
  * Audio and video can be written on any thread, but you probably want to
  * always write from the same thread to avoid unexpected interleavings.
  */
 class SourceMediaStream : public MediaStream {
 public:
-  SourceMediaStream(nsDOMMediaStream* aWrapper) :
+  SourceMediaStream(DOMMediaStream* aWrapper) :
     MediaStream(aWrapper),
     mLastConsumptionState(MediaStreamListener::NOT_CONSUMED),
     mMutex("mozilla::media::SourceMediaStream"),
     mUpdateKnownTracksTime(0),
     mPullEnabled(false),
     mUpdateFinished(false), mDestroyed(false)
   {}
 
@@ -772,17 +772,17 @@ protected:
 
 /**
  * This stream processes zero or more input streams in parallel to produce
  * its output. The details of how the output is produced are handled by
  * subclasses overriding the ProduceOutput method.
  */
 class ProcessedMediaStream : public MediaStream {
 public:
-  ProcessedMediaStream(nsDOMMediaStream* aWrapper)
+  ProcessedMediaStream(DOMMediaStream* aWrapper)
     : MediaStream(aWrapper), mAutofinish(false), mInCycle(false)
   {}
 
   // Control API.
   /**
    * Allocates a new input port attached to source aStream.
    * This stream can be removed by calling MediaInputPort::Remove().
    */
@@ -855,32 +855,32 @@ public:
 
   // Main thread only
   static MediaStreamGraph* GetInstance();
   // Control API.
   /**
    * Create a stream that a media decoder (or some other source of
    * media data, such as a camera) can write to.
    */
-  SourceMediaStream* CreateSourceStream(nsDOMMediaStream* aWrapper);
+  SourceMediaStream* CreateSourceStream(DOMMediaStream* aWrapper);
   /**
    * Create a stream that will form the union of the tracks of its input
    * streams.
    * A TrackUnionStream contains all the tracks of all its input streams.
    * Adding a new input stream makes that stream's tracks immediately appear as new
    * tracks starting at the time the input stream was added.
    * Removing an input stream makes the output tracks corresponding to the
    * removed tracks immediately end.
    * For each added track, the track ID of the output track is the track ID
    * of the input track or one plus the maximum ID of all previously added
    * tracks, whichever is greater.
    * TODO at some point we will probably need to add API to select
    * particular tracks of each input stream.
    */
-  ProcessedMediaStream* CreateTrackUnionStream(nsDOMMediaStream* aWrapper);
+  ProcessedMediaStream* CreateTrackUnionStream(DOMMediaStream* aWrapper);
   /**
    * Create a stream that will process audio for an AudioNode.
    * Takes ownership of aEngine.
    */
   AudioNodeStream* CreateAudioNodeStream(AudioNodeEngine* aEngine);
   /**
    * Returns the number of graph updates sent. This can be used to track
    * whether a given update has been processed by the graph thread and reflected
--- a/content/media/TrackUnionStream.h
+++ b/content/media/TrackUnionStream.h
@@ -19,17 +19,17 @@ namespace mozilla {
 
 /**
  * See MediaStreamGraph::CreateTrackUnionStream.
  * This file is only included by MediaStreamGraph.cpp so it's OK to put the
  * entire implementation in this header file.
  */
 class TrackUnionStream : public ProcessedMediaStream {
 public:
-  TrackUnionStream(nsDOMMediaStream* aWrapper) :
+  TrackUnionStream(DOMMediaStream* aWrapper) :
     ProcessedMediaStream(aWrapper),
     mMaxTrackID(0) {}
 
   virtual void RemoveInput(MediaInputPort* aPort)
   {
     for (int32_t i = mTrackMap.Length() - 1; i >= 0; --i) {
       if (mTrackMap[i].mInputPort == aPort) {
         EndTrack(i);
--- a/content/media/webrtc/MediaEngine.h
+++ b/content/media/webrtc/MediaEngine.h
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MEDIAENGINE_H_
 #define MEDIAENGINE_H_
 
 #include "nsIDOMFile.h"
-#include "nsDOMMediaStream.h"
+#include "DOMMediaStream.h"
 #include "MediaStreamGraph.h"
 
 namespace mozilla {
 
 /**
  * Abstract interface for managing audio and video devices. Each platform
  * must implement a concrete class that will map these classes and methods
  * to the appropriate backend. For example, on Desktop platforms, these will
--- a/content/media/webrtc/MediaEngineDefault.h
+++ b/content/media/webrtc/MediaEngineDefault.h
@@ -3,17 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MEDIAENGINEDEFAULT_H_
 #define MEDIAENGINEDEFAULT_H_
 
 #include "nsITimer.h"
 
 #include "nsCOMPtr.h"
-#include "nsDOMMediaStream.h"
+#include "DOMMediaStream.h"
 #include "nsComponentManagerUtils.h"
 
 #include "VideoUtils.h"
 #include "MediaEngine.h"
 #include "VideoSegment.h"
 #include "AudioSegment.h"
 #include "StreamBuffer.h"
 #include "MediaStreamGraph.h"
--- a/content/media/webrtc/MediaEngineWebRTC.h
+++ b/content/media/webrtc/MediaEngineWebRTC.h
@@ -9,17 +9,17 @@
 #include "prthread.h"
 #include "nsIThread.h"
 #include "nsIRunnable.h"
 
 #include "mozilla/Mutex.h"
 #include "nsCOMPtr.h"
 #include "nsDOMFile.h"
 #include "nsThreadUtils.h"
-#include "nsDOMMediaStream.h"
+#include "DOMMediaStream.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsComponentManagerUtils.h"
 
 #include "VideoUtils.h"
 #include "MediaEngine.h"
 #include "VideoSegment.h"
 #include "AudioSegment.h"
 #include "StreamBuffer.h"
--- a/content/xml/document/src/nsXMLContentSink.cpp
+++ b/content/xml/document/src/nsXMLContentSink.cpp
@@ -9,17 +9,16 @@
 #include "nsIParser.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentType.h"
 #include "nsIContent.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsIDOMComment.h"
 #include "nsIDOMCDATASection.h"
 #include "DocumentType.h"
 #include "nsHTMLParts.h"
 #include "nsCRT.h"
 #include "nsCSSStyleSheet.h"
 #include "mozilla/css/Loader.h"
--- a/content/xul/document/src/nsXULDocument.cpp
+++ b/content/xul/document/src/nsXULDocument.cpp
@@ -76,17 +76,16 @@
 #include "nsIParserService.h"
 #include "nsCSSStyleSheet.h"
 #include "mozilla/css/Loader.h"
 #include "nsIScriptError.h"
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsEventDispatcher.h"
 #include "nsIObserverService.h"
 #include "nsNodeUtils.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIXULWindow.h"
 #include "nsXULPopupManager.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsURILoader.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/Preferences.h"
 
--- a/docshell/base/Makefile.in
+++ b/docshell/base/Makefile.in
@@ -37,17 +37,16 @@ XPIDLSRCS = \
   nsITextScroll.idl \
   nsIDocCharset.idl \
   nsIWebNavigation.idl \
   nsIWebNavigationInfo.idl \
   nsIContentViewer.idl \
   nsIContentViewerEdit.idl \
   nsIContentViewerFile.idl \
   nsIURIFixup.idl \
-  nsIEditorDocShell.idl \
   nsIWebPageDescriptor.idl \
   nsIDownloadHistory.idl \
   nsILoadContext.idl \
   nsIRefreshURI.idl \
   nsIContentViewerContainer.idl \
   nsIDocumentLoaderFactory.idl \
   nsIPrivacyTransitionObserver.idl \
   $(NULL)
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -867,18 +867,18 @@ nsDocShell::Init()
                                      nsIWebProgress::NOTIFY_STATE_NETWORK);
     
 }
 
 void
 nsDocShell::DestroyChildren()
 {
     nsCOMPtr<nsIDocShellTreeItem> shell;
-    int32_t n = mChildList.Count();
-    for (int32_t i = 0; i < n; i++) {
+    uint32_t n = mChildList.Length();
+    for (uint32_t i = 0; i < n; i++) {
         shell = do_QueryInterface(ChildAt(i));
         NS_ASSERTION(shell, "docshell has null child");
 
         if (shell) {
             shell->SetTreeOwner(nullptr);
         }
     }
 
@@ -902,17 +902,16 @@ NS_INTERFACE_MAP_BEGIN(nsDocShell)
     NS_INTERFACE_MAP_ENTRY(nsIScrollable)
     NS_INTERFACE_MAP_ENTRY(nsITextScroll)
     NS_INTERFACE_MAP_ENTRY(nsIDocCharset)
     NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObjectOwner)
     NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
     NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     NS_INTERFACE_MAP_ENTRY(nsIContentViewerContainer)
-    NS_INTERFACE_MAP_ENTRY(nsIEditorDocShell)
     NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
     NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
     NS_INTERFACE_MAP_ENTRY(nsIObserver)
     NS_INTERFACE_MAP_ENTRY(nsILoadContext)
     NS_INTERFACE_MAP_ENTRY(nsIWebShellServices)
     NS_INTERFACE_MAP_ENTRY(nsILinkHandler)
     NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands)
 NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
@@ -1624,24 +1623,24 @@ nsDocShell::FirePageHideNotification(boo
 
         mContentViewer->PageHide(aIsUnload);
 
         if (mTiming) {
             mTiming->NotifyUnloadEventEnd();
         }
 
         nsAutoTArray<nsCOMPtr<nsIDocShell>, 8> kids;
-        int32_t i, n = mChildList.Count();
+        uint32_t n = mChildList.Length();
         kids.SetCapacity(n);
-        for (i = 0; i < n; i++) {
+        for (uint32_t i = 0; i < n; i++) {
             kids.AppendElement(do_QueryInterface(ChildAt(i)));
         }
 
         n = kids.Length();
-        for (i = 0; i < n; ++i) {
+        for (uint32_t i = 0; i < n; ++i) {
             if (kids[i]) {
                 kids[i]->FirePageHideNotification(aIsUnload);
             }
         }
         // Now make sure our editor, if any, is detached before we go
         // any farther.
         DetachEditorFromWindow();
     }
@@ -2076,18 +2075,18 @@ nsDocShell::SetPrivateBrowsing(bool aUse
             if (aUsePrivateBrowsing) {
                 IncreasePrivateDocShellCount();
             } else {
                 DecreasePrivateDocShellCount();
             }
         }
     }
 
-    int32_t count = mChildList.Count();
-    for (int32_t i = 0; i < count; ++i) {
+    uint32_t count = mChildList.Length();
+    for (uint32_t i = 0; i < count; ++i) {
         nsCOMPtr<nsILoadContext> shell = do_QueryInterface(ChildAt(i));
         if (shell) {
             shell->SetPrivateBrowsing(aUsePrivateBrowsing);
         }
     }
 
     if (changed) {
         nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mPrivacyObservers);
@@ -2112,18 +2111,18 @@ nsDocShell::SetAffectPrivateSessionLifet
         if (aAffectLifetime) {
             IncreasePrivateDocShellCount();
         } else {
             DecreasePrivateDocShellCount();
         }
     }
     mAffectPrivateSessionLifetime = aAffectLifetime;
 
-    int32_t count = mChildList.Count();
-    for (int32_t i = 0; i < count; ++i) {
+    uint32_t count = mChildList.Length();
+    for (uint32_t i = 0; i < count; ++i) {
         nsCOMPtr<nsIDocShell> shell = do_QueryInterface(ChildAt(i));
         if (shell) {
             shell->SetAffectPrivateSessionLifetime(aAffectLifetime);
         }
     }
     return NS_OK;
 }
 
@@ -2484,18 +2483,18 @@ nsDocShell::HistoryPurged(int32_t aNumEn
     // These indices are used for fastback cache eviction, to determine
     // which session history entries are candidates for content viewer
     // eviction.  We need to adjust by the number of entries that we
     // just purged from history, so that we look at the right session history
     // entries during eviction.
     mPreviousTransIndex = std::max(-1, mPreviousTransIndex - aNumEntries);
     mLoadedTransIndex = std::max(0, mLoadedTransIndex - aNumEntries);
 
-    int32_t count = mChildList.Count();
-    for (int32_t i = 0; i < count; ++i) {
+    uint32_t count = mChildList.Length();
+    for (uint32_t i = 0; i < count; ++i) {
         nsCOMPtr<nsIDocShell> shell = do_QueryInterface(ChildAt(i));
         if (shell) {
             shell->HistoryPurged(aNumEntries);
         }
     }
 
     return NS_OK;
 }
@@ -2514,18 +2513,18 @@ nsDocShell::HistoryTransactionRemoved(in
         --mPreviousTransIndex;
     }
     if (mLoadedTransIndex == aIndex) {
         mLoadedTransIndex = 0;
     } else if (aIndex < mLoadedTransIndex) {
         --mLoadedTransIndex;
     }
                             
-    int32_t count = mChildList.Count();
-    for (int32_t i = 0; i < count; ++i) {
+    uint32_t count = mChildList.Length();
+    for (uint32_t i = 0; i < count; ++i) {
         nsCOMPtr<nsIDocShell> shell = do_QueryInterface(ChildAt(i));
         if (shell) {
             static_cast<nsDocShell*>(shell.get())->
                 HistoryTransactionRemoved(aIndex);
         }
     }
 
     return NS_OK;
@@ -3399,18 +3398,18 @@ nsDocShell::SetTreeOwner(nsIDocShellTree
                 webProgress->AddProgressListener(newListener,
                                                  nsIWebProgress::NOTIFY_ALL);
             }
         }
     }
 
     mTreeOwner = aTreeOwner;    // Weak reference per API
 
-    int32_t i, n = mChildList.Count();
-    for (i = 0; i < n; i++) {
+    uint32_t n = mChildList.Length();
+    for (uint32_t i = 0; i < n; i++) {
         nsCOMPtr<nsIDocShellTreeItem> child = do_QueryInterface(ChildAt(i));
         NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
         int32_t childType = ~mItemType; // Set it to not us in case the get fails
         child->GetItemType(&childType); // We don't care if this fails, if it does we won't set the owner
         if (childType == mItemType)
             child->SetTreeOwner(aTreeOwner);
     }
 
@@ -3441,17 +3440,17 @@ nsDocShell::GetIsInUnload(bool* aIsInUnl
 //*****************************************************************************
 // nsDocShell::nsIDocShellTreeNode
 //*****************************************************************************   
 
 NS_IMETHODIMP
 nsDocShell::GetChildCount(int32_t * aChildCount)
 {
     NS_ENSURE_ARG_POINTER(aChildCount);
-    *aChildCount = mChildList.Count();
+    *aChildCount = mChildList.Length();
     return NS_OK;
 }
 
 
 
 NS_IMETHODIMP
 nsDocShell::AddChild(nsIDocShellTreeItem * aChild)
 {
@@ -3476,32 +3475,32 @@ nsDocShell::AddChild(nsIDocShellTreeItem
     }
 
     // Make sure to clear the treeowner in case this child is a different type
     // from us.
     aChild->SetTreeOwner(nullptr);
     
     nsresult res = AddChildLoader(childAsDocLoader);
     NS_ENSURE_SUCCESS(res, res);
-    NS_ASSERTION(mChildList.Count() > 0,
+    NS_ASSERTION(!mChildList.IsEmpty(),
                  "child list must not be empty after a successful add");
 
     nsCOMPtr<nsIDocShellHistory> docshellhistory = do_QueryInterface(aChild);
     bool dynamic = false;
     docshellhistory->GetCreatedDynamically(&dynamic);
     if (!dynamic) {
         nsCOMPtr<nsISHEntry> currentSH;
         bool oshe = false;
         GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
         if (currentSH) {
             currentSH->HasDynamicallyAddedChild(&dynamic);
         }
     }
     nsCOMPtr<nsIDocShell> childDocShell = do_QueryInterface(aChild);
-    childDocShell->SetChildOffset(dynamic ? -1 : mChildList.Count() - 1);
+    childDocShell->SetChildOffset(dynamic ? -1 : mChildList.Length() - 1);
 
     /* Set the child's global history if the parent has one */
     if (mUseGlobalHistory) {
         nsCOMPtr<nsIDocShellHistory>
             dsHistoryChild(do_QueryInterface(aChild));
         if (dsHistoryChild)
             dsHistoryChild->SetUseGlobalHistory(true);
     }
@@ -3594,17 +3593,17 @@ NS_IMETHODIMP
 nsDocShell::GetChildAt(int32_t aIndex, nsIDocShellTreeItem ** aChild)
 {
     NS_ENSURE_ARG_POINTER(aChild);
 
 #ifdef DEBUG
     if (aIndex < 0) {
       NS_WARNING("Negative index passed to GetChildAt");
     }
-    else if (aIndex >= mChildList.Count()) {
+    else if (aIndex >= mChildList.Length()) {
       NS_WARNING("Too large an index passed to GetChildAt");
     }
 #endif
 
     nsIDocumentLoader* child = SafeChildAt(aIndex);
     NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED);
     
     return CallQueryInterface(child, aChild);
@@ -3621,18 +3620,18 @@ nsDocShell::FindChildWithName(const PRUn
     NS_ENSURE_ARG_POINTER(_retval);
 
     *_retval = nullptr;          // if we don't find one, we return NS_OK and a null result 
 
     if (!*aName)
         return NS_OK;
 
     nsXPIDLString childName;
-    int32_t i, n = mChildList.Count();
-    for (i = 0; i < n; i++) {
+    uint32_t n = mChildList.Length();
+    for (uint32_t i = 0; i < n; i++) {
         nsCOMPtr<nsIDocShellTreeItem> child = do_QueryInterface(ChildAt(i));
         NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
         int32_t childType;
         child->GetItemType(&childType);
 
         if (aSameType && (childType != mItemType))
             continue;
 
@@ -4673,19 +4672,18 @@ nsDocShell::Stop(uint32_t aStopFlags)
         }
 
         // XXXbz We could also pass |this| to nsIURILoader::Stop.  That will
         // just call Stop() on us as an nsIDocumentLoader... We need fewer
         // redundant apis!
         Stop();
     }
 
-    int32_t n;
-    int32_t count = mChildList.Count();
-    for (n = 0; n < count; n++) {
+    uint32_t count = mChildList.Length();
+    for (uint32_t n = 0; n < count; n++) {
         nsCOMPtr<nsIWebNavigation> shellAsNav(do_QueryInterface(ChildAt(n)));
         if (shellAsNav)
             shellAsNav->Stop(aStopFlags);
     }
 
     return NS_OK;
 }
 
@@ -5288,18 +5286,18 @@ nsDocShell::SetIsActive(bool aIsActive)
       nsCOMPtr<nsIDocument> doc = do_QueryInterface(win->GetExtantDocument());
       if (doc) {
           doc->PostVisibilityUpdateEvent();
       }
   }
 
   // Recursively tell all of our children, but don't tell <iframe mozbrowser>
   // children; they handle their state separately.
-  int32_t n = mChildList.Count();
-  for (int32_t i = 0; i < n; ++i) {
+  uint32_t n = mChildList.Length();
+  for (uint32_t i = 0; i < n; ++i) {
       nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(ChildAt(i));
       if (!docshell) {
           continue;
       }
 
       if (!docshell->GetIsBrowserOrApp()) {
           docshell->SetIsActive(aIsActive);
       }
@@ -6211,36 +6209,34 @@ nsDocShell::SuspendRefreshURIs()
             nsCOMPtr<nsITimerCallback> rt = do_QueryInterface(callback);
             NS_ASSERTION(rt, "RefreshURIList timer callbacks should only be RefreshTimer objects");
 
             mRefreshURIList->ReplaceElementAt(rt, i);
         }
     }
 
     // Suspend refresh URIs for our child shells as well.
-    int32_t n = mChildList.Count();
-
-    for (int32_t i = 0; i < n; ++i) {
+    uint32_t n = mChildList.Length();
+    for (uint32_t i = 0; i < n; ++i) {
         nsCOMPtr<nsIDocShell> shell = do_QueryInterface(ChildAt(i));
         if (shell)
             shell->SuspendRefreshURIs();
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::ResumeRefreshURIs()
 {
     RefreshURIFromQueue();
 
     // Resume refresh URIs for our child shells as well.
-    int32_t n = mChildList.Count();
-
-    for (int32_t i = 0; i < n; ++i) {
+    uint32_t n = mChildList.Length();
+    for (uint32_t i = 0; i < n; ++i) {
         nsCOMPtr<nsIDocShell> shell = do_QueryInterface(ChildAt(i));
         if (shell)
             shell->ResumeRefreshURIs();
     }
 
     return NS_OK;
 }
 
@@ -7207,18 +7203,18 @@ nsDocShell::CaptureState()
         mContentViewer->GetBounds(bounds);
         rv = mOSHE->SetViewerBounds(bounds);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     // Capture the docshell hierarchy.
     mOSHE->ClearChildShells();
 
-    int32_t childCount = mChildList.Count();
-    for (int32_t i = 0; i < childCount; ++i) {
+    uint32_t childCount = mChildList.Length();
+    for (uint32_t i = 0; i < childCount; ++i) {
         nsCOMPtr<nsIDocShellTreeItem> childShell = do_QueryInterface(ChildAt(i));
         NS_ASSERTION(childShell, "null child shell");
 
         mOSHE->AddChildShell(childShell);
     }
 
     return NS_OK;
 }
@@ -7276,35 +7272,35 @@ nsDocShell::BeginRestore(nsIContentViewe
     }
 
     return NS_OK;
 }
 
 nsresult
 nsDocShell::BeginRestoreChildren()
 {
-    int32_t n = mChildList.Count();
-    for (int32_t i = 0; i < n; ++i) {
+    uint32_t n = mChildList.Length();
+    for (uint32_t i = 0; i < n; ++i) {
         nsCOMPtr<nsIDocShell> child = do_QueryInterface(ChildAt(i));
         if (child) {
             nsresult rv = child->BeginRestore(nullptr, false);
             NS_ENSURE_SUCCESS(rv, rv);
         }
     }
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::FinishRestore()
 {
     // First we call finishRestore() on our children.  In the simulated load,
     // all of the child frames finish loading before the main document.
 
-    int32_t n = mChildList.Count();
-    for (int32_t i = 0; i < n; ++i) {
+    uint32_t n = mChildList.Length();
+    for (uint32_t i = 0; i < n; ++i) {
         nsCOMPtr<nsIDocShell> child = do_QueryInterface(ChildAt(i));
         if (child) {
             child->FinishRestore();
         }
     }
 
     if (mOSHE && mOSHE->HasDetachedEditor()) {
       ReattachEditorToWindow(mOSHE);
@@ -7798,18 +7794,18 @@ nsDocShell::RestoreFromHistory()
     privWin->ResumeTimeouts();
 
     // Restore the refresh URI list.  The refresh timers will be restarted
     // when EndPageLoad() is called.
     mRefreshURIList = refreshURIList;
 
     // Meta-refresh timers have been restarted for this shell, but not
     // for our children.  Walk the child shells and restart their timers.
-    int32_t n = mChildList.Count();
-    for (i = 0; i < n; ++i) {
+    uint32_t n = mChildList.Length();
+    for (uint32_t i = 0; i < n; ++i) {
         nsCOMPtr<nsIDocShell> child = do_QueryInterface(ChildAt(i));
         if (child)
             child->ResumeRefreshURIs();
     }
 
     // Make sure this presentation is the same size as the previous
     // presentation.  If this is not the same size we showed it at last time,
     // then we need to resize the widget.
@@ -10809,18 +10805,18 @@ nsDocShell::WalkHistoryEntries(nsISHEntr
             continue;
         }
 
         nsDocShell *childShell = nullptr;
         if (aRootShell) {
             // Walk the children of aRootShell and see if one of them
             // has srcChild as a SHEntry.
 
-            int32_t childCount = aRootShell->mChildList.Count();
-            for (int32_t j = 0; j < childCount; ++j) {
+            uint32_t childCount = aRootShell->mChildList.Length();
+            for (uint32_t j = 0; j < childCount; ++j) {
                 nsDocShell *child =
                     static_cast<nsDocShell*>(aRootShell->ChildAt(j));
 
                 if (child->HasHistoryEntry(childEntry)) {
                     childShell = child;
                     break;
                 }
             }
@@ -11102,20 +11098,16 @@ nsDocShell::ShouldDiscardLayoutState(nsI
     bool noStore = false, noCache = false;
     aChannel->GetSecurityInfo(getter_AddRefs(securityInfo));
     aChannel->IsNoStoreResponse(&noStore);
     aChannel->IsNoCacheResponse(&noCache);
 
     return (noStore || (noCache && securityInfo));
 }
 
-//*****************************************************************************
-// nsDocShell: nsIEditorDocShell
-//*****************************************************************************   
-
 NS_IMETHODIMP nsDocShell::GetEditor(nsIEditor * *aEditor)
 {
   NS_ENSURE_ARG_POINTER(aEditor);
 
   if (!mEditorData) {
     *aEditor = nullptr;
     return NS_OK;
   }
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -21,17 +21,16 @@
 #include "nsIBaseWindow.h"
 #include "nsIScrollable.h"
 #include "nsITextScroll.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIContentViewerContainer.h"
 
 #include "nsDocLoader.h"
 #include "nsIURILoader.h"
-#include "nsIEditorDocShell.h"
 
 #include "nsWeakReference.h"
 
 // Local Includes
 #include "nsDSURIContentListener.h"
 #include "nsDocShellEditorData.h"
 
 // Helper Classes
@@ -126,28 +125,26 @@ typedef enum {
 } eCharsetReloadState;
 
 //*****************************************************************************
 //***    nsDocShell
 //*****************************************************************************
 
 class nsDocShell : public nsDocLoader,
                    public nsIDocShell,
-                   public nsIDocShellTreeItem, 
                    public nsIDocShellHistory,
                    public nsIWebNavigation,
                    public nsIBaseWindow, 
                    public nsIScrollable, 
                    public nsITextScroll, 
                    public nsIDocCharset, 
                    public nsIContentViewerContainer,
                    public nsIScriptGlobalObjectOwner,
                    public nsIRefreshURI,
                    public nsIWebProgressListener,
-                   public nsIEditorDocShell,
                    public nsIWebPageDescriptor,
                    public nsIAuthPromptProvider,
                    public nsIObserver,
                    public nsILoadContext,
                    public nsIWebShellServices,
                    public nsILinkHandler,
                    public nsIClipboardCommands
 {
@@ -171,17 +168,16 @@ public:
     NS_DECL_NSIBASEWINDOW
     NS_DECL_NSISCROLLABLE
     NS_DECL_NSITEXTSCROLL
     NS_DECL_NSIDOCCHARSET
     NS_DECL_NSIINTERFACEREQUESTOR
     NS_DECL_NSIWEBPROGRESSLISTENER
     NS_DECL_NSIREFRESHURI
     NS_DECL_NSICONTENTVIEWERCONTAINER
-    NS_DECL_NSIEDITORDOCSHELL
     NS_DECL_NSIWEBPAGEDESCRIPTOR
     NS_DECL_NSIAUTHPROMPTPROVIDER
     NS_DECL_NSIOBSERVER
     NS_DECL_NSICLIPBOARDCOMMANDS
     NS_DECL_NSIWEBSHELLSERVICES
 
     NS_IMETHOD Stop() {
         // Need this here because otherwise nsIWebNavigation::Stop
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -1,15 +1,15 @@
 /* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsISupports.idl"
+#include "nsIDocShellTreeItem.idl"
 #include "nsIAtom.idl"
 
 %{ C++
 class nsPresContext;
 class nsIPresShell;
 struct JSContext;
 %}
 
@@ -21,31 +21,32 @@ struct JSContext;
 [ptr] native nsIPresShell(nsIPresShell);
 
 interface nsIURI;
 interface nsIChannel;
 interface nsIContentViewer;
 interface nsIURIContentListener;
 interface nsIDOMEventTarget;
 interface nsIDocShellLoadInfo;
+interface nsIEditor;
 interface nsIWebNavigation;
 interface nsISimpleEnumerator;
 interface nsIInputStream;
 interface nsIRequest;
 interface nsISHEntry;
 interface nsILayoutHistoryState;
 interface nsISecureBrowserUI;
 interface nsIDOMStorage;
 interface nsIPrincipal;
 interface nsIWebBrowserPrint;
 interface nsIVariant;
 interface nsIPrivacyTransitionObserver;
 
-[scriptable, builtinclass, uuid(5ea80008-a166-4692-8a7e-39690dd192c6)]
-interface nsIDocShell : nsISupports
+[scriptable, builtinclass, uuid(e8f6f3e5-8cee-4be3-8d56-5ed617305bf8)]
+interface nsIDocShell : nsIDocShellTreeItem
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing	this interface.  If it can't be loaded here
    * however, the URL dispatcher will go through its normal process of content
    * loading.
    *
    * @param uri        - The URI to load.
@@ -784,9 +785,22 @@ interface nsIDocShell : nsISupports
 
   [noscript, infallible] attribute boolean affectPrivateSessionLifetime;
 
   /**
    * Indicates whether the UI may enable the character encoding menu. The UI
    * must disable the menu when this property is false.
    */
   [infallible] readonly attribute boolean mayEnableCharacterEncodingMenu;
+
+           attribute  nsIEditor editor;
+  readonly attribute  boolean   editable;             /* this docShell is editable */
+  readonly attribute  boolean   hasEditingSession;    /* this docShell has an editing session */
+    
+  /**
+   * Make this docShell editable, setting a flag that causes
+   * an editor to get created, either immediately, or after
+   * a url has been loaded.
+   *      @param  inWaitForUriLoad    true to wait for a URI before
+   *                                  creating the editor.
+   */     
+  void makeEditable(in boolean inWaitForUriLoad);
 };
deleted file mode 100644
--- a/docshell/base/nsIEditorDocShell.idl
+++ /dev/null
@@ -1,34 +0,0 @@
-/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsISupports.idl"
-
-interface nsIEditor;
-
-/**
- * nsIEditorDocShell provides a way to get an editor from
- * a specific frame in a docShell hierarchy. It is intended
- * to be only used internally. Use nsIEditingShell.getEditorForFrame
- * from out side.
- */
-
-[scriptable, uuid(3BDB8F01-F141-11D4-A73C-FBA4ABA8A3FC)]
-interface nsIEditorDocShell : nsISupports
-{
-             attribute  nsIEditor editor;
-    readonly attribute  boolean   editable;             /* this docShell is editable */
-    readonly attribute  boolean   hasEditingSession;    /* this docShell has an editing session */
-    
-    /**
-     * Make this docShell editable, setting a flag that causes
-     * an editor to get created, either immediately, or after
-     * a url has been loaded.
-     *      @param  inWaitForUriLoad    true to wait for a URI before
-     *                                  creating the editor.
-     */     
-    void makeEditable(in boolean inWaitForUriLoad);
-};
-
--- a/dom/alarm/AlarmService.jsm
+++ b/dom/alarm/AlarmService.jsm
@@ -42,34 +42,31 @@ this.AlarmService = {
 
     let alarmHalService = this._alarmHalService = Cc["@mozilla.org/alarmHalService;1"].getService(Ci.nsIAlarmHalService);
     alarmHalService.setAlarmFiredCb(this._onAlarmFired.bind(this));
     alarmHalService.setTimezoneChangedCb(this._onTimezoneChanged.bind(this));
 
     // add the messages to be listened
     const messages = ["AlarmsManager:GetAll",
                       "AlarmsManager:Add",
-                      "AlarmsManager:Remove",
-                      "SystemMessageManager:HandleMessageDone"];
+                      "AlarmsManager:Remove"];
     messages.forEach(function addMessage(msgName) {
         ppmm.addMessageListener(msgName, this);
     }.bind(this));
 
     // set the indexeddb database
     let idbManager = Cc["@mozilla.org/dom/indexeddb/manager;1"].getService(Ci.nsIIndexedDatabaseManager);
     idbManager.initWindowless(myGlobal);
     this._db = new AlarmDB(myGlobal);
     this._db.init(myGlobal);
 
     // variable to save alarms waiting to be set
     this._alarmQueue = [];
 
     this._restoreAlarmsFromDb();
-
-    this._cpuWakeLocks = {};
   },
 
   // getter/setter to access the current alarm set in system
   _alarm: null,
   get _currentAlarm() {
     return this._alarm;
   },
   set _currentAlarm(aAlarm) {
@@ -211,24 +208,16 @@ this.AlarmService = {
 
             // no alarm waiting to be set in the queue
             this._currentAlarm = null;
             this._debugCurrentAlarm();
           }.bind(this)
         );
         break;
 
-      case "SystemMessageManager:HandleMessageDone":
-        if (json.type != "alarm") {
-          return;
-        }
-        debug("Unlock the CPU wake lock after the alarm is handled for sure.");
-        this._unlockCpuWakeLock(json.message.id);
-        break;
-
       default:
         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
         break;
     }
   },
 
   _sendAsyncMessage: function _sendAsyncMessage(aMessageManager, aMessageName, aSuccess, aRequestId, aData) {
     debug("_sendAsyncMessage()");
@@ -280,54 +269,29 @@ this.AlarmService = {
         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
       }
     );
   },
 
   _fireSystemMessage: function _fireSystemMessage(aAlarm) {
     debug("Fire system message: " + JSON.stringify(aAlarm));
 
-    // We have to ensure the CPU doesn't sleep during the process of
-    // handling alarm message, so that it can be handled on time.
-    this._cpuWakeLocks[aAlarm.id] = {
-      wakeLock: powerManagerService.newWakeLock("cpu"),
-      timer: Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer)
-    };
-
-    // Set a watchdog to avoid locking the CPU wake lock too long,
-    // because it'd exhaust the battery quickly which is very bad.
-    // This could probably happen if the app failed to launch or
-    // handle the alarm message due to any unexpected reasons.
-    this._cpuWakeLocks[aAlarm.id].timer.initWithCallback(function timerCb() {
-      debug("Unlock the CPU wake lock if the alarm isn't properly handled.");
-      this._unlockCpuWakeLock(aAlarm.id);
-    }.bind(this), 30000, Ci.nsITimer.TYPE_ONE_SHOT);
-
     let manifestURI = Services.io.newURI(aAlarm.manifestURL, null, null);
     let pageURI = Services.io.newURI(aAlarm.pageURL, null, null);
 
     // We don't need to expose everything to the web content.
     let alarm = { "id":              aAlarm.id,
                   "date":            aAlarm.date,
                   "respectTimezone": aAlarm.ignoreTimezone ?
                                        "ignoreTimezone" : "honorTimezone", 
                   "data":            aAlarm.data };
 
     messenger.sendMessage("alarm", alarm, pageURI, manifestURI);
   },
 
-  _unlockCpuWakeLock: function _unlockCpuWakeLock(aAlarmId) {
-    let cpuWakeLock = this._cpuWakeLocks[aAlarmId];
-    if (cpuWakeLock) {
-      cpuWakeLock.wakeLock.unlock();
-      cpuWakeLock.timer.cancel();
-      delete this._cpuWakeLocks[aAlarmId];
-    }
-  },
-
   _onAlarmFired: function _onAlarmFired() {
     debug("_onAlarmFired()");
 
     if (this._currentAlarm) {
       this._fireSystemMessage(this._currentAlarm);
       this._removeAlarmFromDb(this._currentAlarm.id, null);
       this._currentAlarm = null;
     }
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -20,16 +20,17 @@
 
 #include "nsThreadUtils.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsIAudioManager.h"
 #endif
 using namespace mozilla;
 using namespace mozilla::dom;
+using namespace mozilla::hal;
 
 StaticRefPtr<AudioChannelService> gAudioChannelService;
 
 // static
 AudioChannelService*
 AudioChannelService::GetAudioChannelService()
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -88,17 +89,17 @@ AudioChannelService::~AudioChannelServic
 void
 AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
                                                AudioChannelType aType)
 {
   AudioChannelAgentData* data = new AudioChannelAgentData(aType,
                                                           true /* mElementHidden */,
                                                           true /* mMuted */);
   mAgents.Put(aAgent, data);
-  RegisterType(aType, CONTENT_PARENT_NO_CHILD_ID);
+  RegisterType(aType, CONTENT_PROCESS_ID_MAIN);
 }
 
 void
 AudioChannelService::RegisterType(AudioChannelType aType, uint64_t aChildID)
 {
   AudioChannelInternalType type = GetInternalType(aType, true);
   mChannelCounters[type].AppendElement(aChildID);
 
@@ -112,17 +113,17 @@ AudioChannelService::RegisterType(AudioC
 
 void
 AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent)
 {
   nsAutoPtr<AudioChannelAgentData> data;
   mAgents.RemoveAndForget(aAgent, data);
 
   if (data) {
-    UnregisterType(data->mType, data->mElementHidden, CONTENT_PARENT_NO_CHILD_ID);
+    UnregisterType(data->mType, data->mElementHidden, CONTENT_PROCESS_ID_MAIN);
   }
 }
 
 void
 AudioChannelService::UnregisterType(AudioChannelType aType,
                                     bool aElementHidden,
                                     uint64_t aChildID)
 {
@@ -146,17 +147,17 @@ AudioChannelService::GetMuted(AudioChann
   if (!mAgents.Get(aAgent, &data)) {
     return true;
   }
 
   bool oldElementHidden = data->mElementHidden;
   // Update visibility.
   data->mElementHidden = aElementHidden;
 
-  bool muted = GetMutedInternal(data->mType, CONTENT_PARENT_NO_CHILD_ID,
+  bool muted = GetMutedInternal(data->mType, CONTENT_PROCESS_ID_MAIN,
                                 aElementHidden, oldElementHidden);
   data->mMuted = muted;
 
   SendAudioChannelChangedNotification();
   return muted;
 }
 
 bool
new file mode 100644
--- /dev/null
+++ b/dom/base/DOMCursor.cpp
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "DOMCursor.h"
+#include "nsIDOMClassInfo.h"
+#include "nsError.h"
+
+DOMCI_DATA(DOMCursor, mozilla::dom::DOMCursor)
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DOMCursor,
+                                                  DOMRequest)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DOMCursor,
+                                                DOMRequest)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMCursor)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMDOMCursor)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DOMCursor)
+NS_INTERFACE_MAP_END_INHERITING(DOMRequest)
+
+NS_IMPL_ADDREF_INHERITED(DOMCursor, DOMRequest)
+NS_IMPL_RELEASE_INHERITED(DOMCursor, DOMRequest)
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(DOMCursor, DOMRequest)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+DOMCursor::DOMCursor(nsIDOMWindow* aWindow, nsICursorContinueCallback* aCallback)
+  : DOMRequest(aWindow)
+  , mCallback(aCallback)
+  , mFinished(false)
+{
+  MOZ_ASSERT(aCallback);
+}
+
+void
+DOMCursor::Reset()
+{
+  MOZ_ASSERT(!mFinished);
+
+  // Reset the request state so we can FireSuccess() again.
+  if (mRooted) {
+    UnrootResultVal();
+  }
+  mResult = JSVAL_VOID;
+  mDone = false;
+}
+
+void
+DOMCursor::FireDone()
+{
+  Reset();
+  mFinished = true;
+  FireSuccess(JSVAL_VOID);
+}
+
+NS_IMETHODIMP
+DOMCursor::GetDone(bool *aDone)
+{
+  *aDone = mFinished;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMCursor::Continue()
+{
+  // We need to have a result here because we must be in a 'success' state.
+  if (mResult == JSVAL_VOID) {
+    return NS_ERROR_DOM_INVALID_STATE_ERR;
+  }
+
+  Reset();
+  mCallback->HandleContinue();
+
+  return NS_OK;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/base/DOMCursor.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_domcursor_h__
+#define mozilla_dom_domcursor_h__
+
+#include "nsIDOMDOMCursor.h"
+#include "DOMRequest.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsCOMPtr.h"
+#include "mozilla/Attributes.h"
+
+namespace mozilla {
+namespace dom {
+
+class DOMCursor : public nsIDOMDOMCursor
+                , public DOMRequest
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIDOMDOMCURSOR
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(DOMCursor,
+                                                         DOMRequest)
+
+  DOMCursor() MOZ_DELETE;
+  DOMCursor(nsIDOMWindow* aWindow, nsICursorContinueCallback *aCallback);
+
+  void Reset();
+  void FireDone();
+
+private:
+  nsCOMPtr<nsICursorContinueCallback> mCallback;
+  bool mFinished;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif /* mozilla_dom_domcursor_h__ */
--- a/dom/base/DOMRequest.cpp
+++ b/dom/base/DOMRequest.cpp
@@ -8,19 +8,21 @@
 
 #include "mozilla/Util.h"
 #include "nsDOMClassInfo.h"
 #include "DOMError.h"
 #include "nsEventDispatcher.h"
 #include "nsDOMEvent.h"
 #include "nsContentUtils.h"
 #include "nsThreadUtils.h"
+#include "DOMCursor.h"
 
 using mozilla::dom::DOMRequest;
 using mozilla::dom::DOMRequestService;
+using mozilla::dom::DOMCursor;
 
 DOMRequest::DOMRequest(nsIDOMWindow* aWindow)
   : mResult(JSVAL_VOID)
   , mDone(false)
   , mRooted(false)
 {
   Init(aWindow);
 }
@@ -189,17 +191,26 @@ DOMRequest::UnrootResultVal()
 NS_IMPL_ISUPPORTS1(DOMRequestService, nsIDOMRequestService)
 
 NS_IMETHODIMP
 DOMRequestService::CreateRequest(nsIDOMWindow* aWindow,
                                  nsIDOMDOMRequest** aRequest)
 {
   NS_ENSURE_STATE(aWindow);
   NS_ADDREF(*aRequest = new DOMRequest(aWindow));
-  
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMRequestService::CreateCursor(nsIDOMWindow* aWindow,
+                                nsICursorContinueCallback* aCallback,
+                                nsIDOMDOMCursor** aCursor) {
+  NS_ADDREF(*aCursor = new DOMCursor(aWindow, aCallback));
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DOMRequestService::FireSuccess(nsIDOMDOMRequest* aRequest,
                                const jsval& aResult)
 {
   NS_ENSURE_STATE(aRequest);
@@ -301,8 +312,16 @@ DOMRequestService::FireErrorAsync(nsIDOM
   nsCOMPtr<nsIRunnable> asyncTask =
     new FireErrorAsyncTask(static_cast<DOMRequest*>(aRequest), aError);
   if (NS_FAILED(NS_DispatchToMainThread(asyncTask))) {
     NS_WARNING("Failed to dispatch to main thread!");
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
+
+NS_IMETHODIMP
+DOMRequestService::FireDone(nsIDOMDOMCursor* aCursor) {
+  NS_ENSURE_STATE(aCursor);
+  static_cast<DOMCursor*>(aCursor)->FireDone();
+
+  return NS_OK;
+}
--- a/dom/base/Makefile.in
+++ b/dom/base/Makefile.in
@@ -39,16 +39,17 @@ EXTRA_JS_MODULES += \
   DOMRequestHelper.jsm \
   IndexedDBHelper.jsm \
   ObjectWrapper.jsm \
   $(NULL)
 
 XPIDLSRCS = \
   nsIDOMDOMError.idl \
   nsIDOMDOMRequest.idl \
+  nsIDOMDOMCursor.idl \
   nsIEntropyCollector.idl \
   nsIScriptChannel.idl \
   nsISiteSpecificUserAgent.idl \
   $(NULL)
 
 EXPORTS = \
   nsDOMCID.h \
   nsDOMClassInfoClasses.h \
@@ -79,16 +80,17 @@ EXPORTS = \
   nsStructuredCloneContainer.h \
   nsWindowMemoryReporter.h \
   $(NULL)
 
 EXPORTS_NAMESPACES = mozilla/dom
 EXPORTS_mozilla/dom = \
   DOMError.h \
   DOMRequest.h \
+  DOMCursor.h \
   StructuredCloneTags.h \
   ScreenOrientation.h \
   URL.h \
   $(NULL)
 
 CPPSRCS =			\
 	nsBarProps.cpp          \
 	nsDOMException.cpp 	\
@@ -112,16 +114,17 @@ CPPSRCS =			\
 	nsQueryContentEventResult.cpp \
 	nsContentPermissionHelper.cpp \
 	nsStructuredCloneContainer.cpp \
 	nsDOMNavigationTiming.cpp \
 	nsPerformance.cpp	\
 	nsWindowMemoryReporter.cpp \
 	DOMError.cpp \
 	DOMRequest.cpp \
+	DOMCursor.cpp \
 	Navigator.cpp \
 	URL.cpp \
 	$(NULL)
 
 include $(topsrcdir)/dom/dom-config.mk
 
 ifdef MOZ_JSDEBUGGER
 DEFINES += -DMOZ_JSDEBUGGER
--- a/dom/base/URL.cpp
+++ b/dom/base/URL.cpp
@@ -2,17 +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 "URL.h"
 
 #include "nsGlobalWindow.h"
 #include "nsIDOMFile.h"
-#include "nsIDOMMediaStream.h"
+#include "DOMMediaStream.h"
 #include "nsIDocument.h"
 #include "nsIPrincipal.h"
 #include "nsContentUtils.h"
 #include "nsHostObjectProtocolHandler.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -23,22 +23,22 @@ URL::CreateObjectURL(const GlobalObject&
                      ErrorResult& aError)
 {
   CreateObjectURLInternal(aGlobal.Get(), aBlob,
                           NS_LITERAL_CSTRING(BLOBURI_SCHEME), aOptions, aResult,
                           aError);
 }
 
 void
-URL::CreateObjectURL(const GlobalObject& aGlobal, nsIDOMMediaStream* aStream,
+URL::CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream,
                      const mozilla::dom::objectURLOptions& aOptions,
                      nsString& aResult,
                      ErrorResult& aError)
 {
-  CreateObjectURLInternal(aGlobal.Get(), aStream,
+  CreateObjectURLInternal(aGlobal.Get(), &aStream,
                           NS_LITERAL_CSTRING(MEDIASTREAMURI_SCHEME), aOptions,
                           aResult, aError);
 }
 
 void
 URL::CreateObjectURLInternal(nsISupports* aGlobal, nsISupports* aObject,
                              const nsACString& aScheme,
                              const mozilla::dom::objectURLOptions& aOptions,
--- a/dom/base/URL.h
+++ b/dom/base/URL.h
@@ -4,31 +4,33 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef URL_h___
 #define URL_h___
 
 #include "nscore.h"
 #include "mozilla/dom/URLBinding.h"
 
 class nsIDOMBlob;
-class nsIDOMMediaStream;
 
 namespace mozilla {
+
+class DOMMediaStream;
+
 namespace dom {
 
 class URL MOZ_FINAL
 {
 public:
   // WebIDL methods
   static void CreateObjectURL(const GlobalObject& aGlobal, nsIDOMBlob* aBlob,
                               const objectURLOptions& aOptions,
                               nsString& aResult,
                               ErrorResult& aError);
   static void CreateObjectURL(const GlobalObject& aGlobal,
-                              nsIDOMMediaStream* aStream,
+                              DOMMediaStream& aStream,
                               const mozilla::dom::objectURLOptions& aOptions,
                               nsString& aResult,
                               mozilla::ErrorResult& aError);
   static void RevokeObjectURL(const GlobalObject& aGlobal,
                               const nsAString& aURL);
 
 private:
   static void CreateObjectURLInternal(nsISupports* aGlobal, nsISupports* aObject,
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -259,19 +259,16 @@
 #include "nsIDOMHTMLTitleElement.h"
 #include "nsIDOMHTMLUListElement.h"
 #include "nsIDOMHTMLUnknownElement.h"
 #include "nsIDOMMediaError.h"
 #include "nsIDOMTimeRanges.h"
 #include "nsIDOMHTMLSourceElement.h"
 #include "nsIDOMHTMLVideoElement.h"
 #include "nsIDOMHTMLAudioElement.h"
-#if defined (MOZ_MEDIA)
-#include "nsIDOMMediaStream.h"
-#endif
 #include "nsIDOMProgressEvent.h"
 #include "nsIDOMCSSCharsetRule.h"
 #include "nsIDOMCSSImportRule.h"
 #include "nsIDOMCSSMediaRule.h"
 #include "nsIDOMCSSFontFaceRule.h"
 #include "nsIDOMCSSMozDocumentRule.h"
 #include "nsIDOMCSSSupportsRule.h"
 #include "nsIDOMMozCSSKeyframeRule.h"
@@ -439,16 +436,17 @@ using mozilla::dom::workers::ResolveWork
 #endif
 
 #include "nsIDOMNavigatorSystemMessages.h"
 #include "DOMCameraManager.h"
 #include "DOMCameraControl.h"
 #include "DOMCameraCapabilities.h"
 #include "DOMError.h"
 #include "DOMRequest.h"
+#include "DOMCursor.h"
 #include "nsIOpenWindowEventDetail.h"
 #include "nsIAsyncScrollEventDetail.h"
 #include "nsIDOMGlobalObjectConstructor.h"
 #include "nsIDOMCanvasRenderingContext2D.h"
 #include "DOMFileHandle.h"
 #include "FileRequest.h"
 #include "LockedFile.h"
 #include "GeneratedEvents.h"
@@ -1088,31 +1086,31 @@ static nsDOMClassInfoData sClassInfoData
   // other SVG classes
   NS_DEFINE_CLASSINFO_DATA(SVGAnimatedEnumeration, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGAnimatedInteger, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGAnimatedLength, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGAnimatedNumber, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)    
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGAnimatedRect, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGAnimatedString, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGLength, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGNumber, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGRect, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGStringList, nsSVGStringListSH,
-                           ARRAY_SCRIPTABLE_FLAGS)    
+                           ARRAY_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGZoomEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(HTMLCanvasElement, nsElementSH,
                            ELEMENT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CanvasGradient, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CanvasPattern, nsDOMGenericSH,
@@ -1197,20 +1195,20 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(DeviceStorage, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(DeviceStorageCursor, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(GeoGeolocation, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  
+
   NS_DEFINE_CLASSINFO_DATA(GeoPosition, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS) 
-  
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+
   NS_DEFINE_CLASSINFO_DATA(GeoPositionCoords, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(GeoPositionError, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(MozPowerManager, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -1256,23 +1254,19 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(HTMLSourceElement, nsElementSH,
                            ELEMENT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MediaError, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(HTMLAudioElement, nsElementSH,
                            ELEMENT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(TimeRanges, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(MediaStream, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(LocalMediaStream, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #endif
 
-  // DOM Traversal NodeIterator class  
+  // DOM Traversal NodeIterator class
   NS_DEFINE_CLASSINFO_DATA(NodeIterator, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   // data transfer for drag and drop
   NS_DEFINE_CLASSINFO_DATA(DataTransfer, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(NotifyPaintEvent, nsDOMGenericSH,
@@ -1390,16 +1384,20 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(CameraCapabilities, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(DOMError, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(DOMRequest, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
+
+  NS_DEFINE_CLASSINFO_DATA(DOMCursor, nsEventTargetSH,
+                           EVENTTARGET_SCRIPTABLE_FLAGS)
+
   NS_DEFINE_CLASSINFO_DATA(OpenWindowEventDetail, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(AsyncScrollEventDetail, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA_WITH_NAME(DOMFileHandle, FileHandle, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(FileRequest, nsEventTargetSH,
@@ -1702,17 +1700,17 @@ WrapNativeParent(JSContext *cx, JSObject
 {
   // In the common case, |native| is a wrapper cache with an existing wrapper
 #ifdef DEBUG
   nsWrapperCache* cache = nullptr;
   CallQueryInterface(native, &cache);
   NS_PRECONDITION(nativeWrapperCache &&
                   cache == nativeWrapperCache, "What happened here?");
 #endif
-  
+
   JSObject* obj = nativeWrapperCache->GetWrapper();
   if (obj) {
 #ifdef DEBUG
     jsval debugVal;
     nsresult rv = WrapNative(cx, scope, native, nativeWrapperCache, false,
                              &debugVal);
     NS_ASSERTION(NS_SUCCEEDED(rv) && JSVAL_TO_OBJECT(debugVal) == obj,
                  "Unexpected object in nsWrapperCache");
@@ -1981,17 +1979,17 @@ nsDOMClassInfo::RegisterExternalClasses(
     d.mDisabled = _disabled;                                                  \
     static const nsIID *interface_list[] = {
 
 #define DOM_CLASSINFO_MAP_BEGIN(_class, _interface)                           \
   _DOM_CLASSINFO_MAP_BEGIN(_class, &NS_GET_IID(_interface), true, false)
 
 #define DOM_CLASSINFO_MAP_BEGIN_MAYBE_DISABLE(_class, _interface, _disable)   \
   _DOM_CLASSINFO_MAP_BEGIN(_class, &NS_GET_IID(_interface), true, _disable)
-  
+
 #define DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(_class, _interface)               \
   _DOM_CLASSINFO_MAP_BEGIN(_class, &NS_GET_IID(_interface), false, false)
 
 #define DOM_CLASSINFO_MAP_ENTRY(_if)                                          \
       &NS_GET_IID(_if),
 
 #define DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(_if, _cond)                       \
       (_cond) ? &NS_GET_IID(_if) : nullptr,
@@ -2293,17 +2291,17 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(MutationEvent, nsIDOMMutationEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMutationEvent)
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(UIEvent, nsIDOMUIEvent)
     DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
-  
+
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(KeyboardEvent, nsIDOMKeyEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMKeyEvent)
     DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(CompositionEvent, nsIDOMCompositionEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCompositionEvent)
     DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
@@ -3164,17 +3162,17 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(OfflineResourceList, nsIDOMOfflineResourceList)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMOfflineResourceList)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(ClientRect, nsIDOMClientRect)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMClientRect)
    DOM_CLASSINFO_MAP_END
- 
+
   DOM_CLASSINFO_MAP_BEGIN(ClientRectList, nsIDOMClientRectList)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMClientRectList)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(FileList, nsIDOMFileList)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMFileList)
   DOM_CLASSINFO_MAP_END
 
@@ -3319,24 +3317,16 @@ nsDOMClassInfo::Init()
 
   DOM_CLASSINFO_MAP_BEGIN(HTMLAudioElement, nsIDOMHTMLAudioElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLAudioElement)
     DOM_CLASSINFO_GENERIC_HTML_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(TimeRanges, nsIDOMTimeRanges)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMTimeRanges)
-  DOM_CLASSINFO_MAP_END  
-
-  DOM_CLASSINFO_MAP_BEGIN(MediaStream, nsIDOMMediaStream)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMMediaStream)
-  DOM_CLASSINFO_MAP_END
-
-  DOM_CLASSINFO_MAP_BEGIN(LocalMediaStream, nsIDOMLocalMediaStream)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMLocalMediaStream)
   DOM_CLASSINFO_MAP_END
 #endif
 
   DOM_CLASSINFO_MAP_BEGIN(DataTransfer, nsIDOMDataTransfer)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDataTransfer)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(NotifyPaintEvent, nsIDOMNotifyPaintEvent)
@@ -3362,17 +3352,17 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers)
     DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver,
                                         nsDOMTouchEvent::PrefEnabled())
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(PaintRequest, nsIDOMPaintRequest)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPaintRequest)
    DOM_CLASSINFO_MAP_END
- 
+
   DOM_CLASSINFO_MAP_BEGIN(PaintRequestList, nsIDOMPaintRequestList)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMPaintRequestList)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(ScrollAreaEvent, nsIDOMScrollAreaEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMScrollAreaEvent)
     DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
@@ -3480,17 +3470,17 @@ nsDOMClassInfo::Init()
                                         !nsDOMTouchEvent::PrefEnabled())
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMTouch)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN_MAYBE_DISABLE(TouchList, nsIDOMTouchList,
                                         !nsDOMTouchEvent::PrefEnabled())
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMTouchList)
   DOM_CLASSINFO_MAP_END
-  
+
   DOM_CLASSINFO_MAP_BEGIN_MAYBE_DISABLE(TouchEvent, nsIDOMTouchEvent,
                                         !nsDOMTouchEvent::PrefEnabled())
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMTouchEvent)
     DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(MozCSSKeyframeRule, nsIDOMMozCSSKeyframeRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozCSSKeyframeRule)
@@ -3551,17 +3541,17 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIFMRadio)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
   DOM_CLASSINFO_MAP_END
 #endif
 
 #ifdef MOZ_B2G_BT
   DOM_CLASSINFO_MAP_BEGIN(BluetoothManager, nsIDOMBluetoothManager)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothManager)
-  DOM_CLASSINFO_MAP_END  
+  DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(BluetoothAdapter, nsIDOMBluetoothAdapter)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothAdapter)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(BluetoothDevice, nsIDOMBluetoothDevice)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothDevice)
   DOM_CLASSINFO_MAP_END
@@ -3583,16 +3573,22 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMError)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DOMRequest, nsIDOMDOMRequest)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMRequest)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(DOMCursor, nsIDOMDOMCursor)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMCursor)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMRequest)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(OpenWindowEventDetail, nsIOpenWindowEventDetail)
     DOM_CLASSINFO_MAP_ENTRY(nsIOpenWindowEventDetail)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(AsyncScrollEventDetail, nsIAsyncScrollEventDetail)
     DOM_CLASSINFO_MAP_ENTRY(nsIAsyncScrollEventDetail)
   DOM_CLASSINFO_MAP_END
 
@@ -4899,17 +4895,17 @@ DefineInterfaceConstants(JSContext *cx, 
 // This code is temporary until we remove support for the constants defined
 // on IDBCursor/IDBRequest/IDBTransaction
 
 struct IDBConstant
 {
   const char* interface;
   const char* name;
   const char* value;
-  
+
   static const char* IDBCursor;
   static const char* IDBRequest;
   static const char* IDBTransaction;
 };
 
 const char* IDBConstant::IDBCursor = "IDBCursor";
 const char* IDBConstant::IDBRequest = "IDBRequest";
 const char* IDBConstant::IDBTransaction = "IDBTransaction";
@@ -6062,17 +6058,17 @@ LocationSetterGuts(JSContext *cx, JSObje
 
   if (!location) {
     // Make this a no-op
     return NS_OK;
   }
 
   nsDependentJSString depStr;
   NS_ENSURE_TRUE(depStr.init(cx, val), NS_ERROR_UNEXPECTED);
-  
+
   return location->SetHref(depStr);
 }
 
 template<class Interface>
 static JSBool
 LocationSetter(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict,
                JSMutableHandleValue vp)
 {
@@ -6722,25 +6718,25 @@ static JSBool
 GetterShim(JSContext *cx, JSHandleObject obj, JSHandleId /* unused */, JSMutableHandleValue vp)
 {
   nsresult rv = (*func)(cx, obj, vp.address());
   if (NS_FAILED(rv)) {
     xpc::Throw(cx, rv);
     return JS_FALSE;
   }
 
-  return JS_TRUE;  
+  return JS_TRUE;
 }
 
 NS_IMETHODIMP
 nsNodeSH::PreCreate(nsISupports *nativeObj, JSContext *cx, JSObject *globalObj,
                     JSObject **parentObj)
 {
   nsINode *node = static_cast<nsINode*>(nativeObj);
-  
+
 #ifdef DEBUG
   {
     nsCOMPtr<nsINode> node_qi(do_QueryInterface(nativeObj));
 
     // If this assertion fires the QI implementation for the object in
     // question doesn't use the nsINode pointer as the nsISupports
     // pointer. That must be fixed, or we'll crash...
     NS_ABORT_IF_FALSE(node_qi == node, "Uh, fix QI!");
@@ -6776,17 +6772,17 @@ nsNodeSH::PreCreate(nsISupports *nativeO
 
     if (!native_parent) {
       native_parent = doc;
     }
   } else if (!node->IsNodeOfType(nsINode::eDOCUMENT)) {
     NS_ASSERTION(node->IsNodeOfType(nsINode::eCONTENT) ||
                  node->IsNodeOfType(nsINode::eATTRIBUTE),
                  "Unexpected node type");
-                 
+
     // For attributes and non-XUL content, use the document as scope parent.
     native_parent = doc;
 
     // But for HTML form controls, use the form as scope parent.
     if (nodeIsElement) {
       if (node->IsNodeOfType(nsINode::eHTML_FORM_CONTROL)) {
         nsCOMPtr<nsIFormControl> form_control(do_QueryInterface(node));
 
@@ -7143,17 +7139,17 @@ nsElementSH::PostCreate(nsIXPConnectWrap
   // We have a binding that must be installed.
   bool dummy;
 
   nsXBLService* xblService = nsXBLService::GetInstance();
   NS_ENSURE_TRUE(xblService, NS_ERROR_NOT_AVAILABLE);
 
   nsRefPtr<nsXBLBinding> binding;
   xblService->LoadBindings(element, uri, principal, getter_AddRefs(binding), &dummy);
-  
+
   if (binding) {
     if (nsContentUtils::IsSafeToRunScript()) {
       binding->ExecuteAttachedHandler();
     }
     else {
       nsContentUtils::AddScriptRunner(
         NS_NewRunnableMethod(binding, &nsXBLBinding::ExecuteAttachedHandler));
     }
@@ -7178,17 +7174,17 @@ NS_IMETHODIMP
 nsGenericArraySH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                              JSObject *obj, jsid id, uint32_t flags,
                              JSObject **objp, bool *_retval)
 {
   if (id == sLength_id) {
     // Bail early; this isn't something we're interested in
     return NS_OK;
   }
-  
+
   bool is_number = false;
   int32_t n = GetArrayIndexFromId(cx, id, &is_number);
 
   if (is_number && n >= 0) {
     // XXX The following is a cheap optimization to avoid hitting xpconnect to
     // get the length. We may want to consider asking our concrete
     // implementation for the length, and falling back onto the GetProperty if
     // it doesn't provide one.
@@ -8828,17 +8824,17 @@ nsHTMLPluginObjElementSH::NewResolve(nsI
 
   nsRefPtr<nsNPAPIPluginInstance> pi;
   nsresult rv = GetPluginInstanceIfSafe(wrapper, obj, cx, getter_AddRefs(pi));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return nsElementSH::NewResolve(wrapper, cx, obj, id, flags, objp,
                                  _retval);
 }
- 
+
 // Plugin helper
 
 nsISupports*
 nsPluginSH::GetItemAt(nsISupports *aNative, uint32_t aIndex,
                       nsWrapperCache **aCache, nsresult *aResult)
 {
   nsPluginElement* plugin = nsPluginElement::FromSupports(aNative);
 
@@ -9456,17 +9452,17 @@ nsSVGStringListSH::GetStringAt(nsISuppor
     return NS_OK;
   }
 
   DOMSVGStringList* list = static_cast<DOMSVGStringList*>(
                              static_cast<nsIDOMSVGStringList*>(aNative));
 #ifdef DEBUG
   {
     nsCOMPtr<nsIDOMSVGStringList> list_qi = do_QueryInterface(aNative);
-    
+
     // If this assertion fires the QI implementation for the object in
     // question doesn't use the nsIDOMDOMSVGStringList pointer as the
     // nsISupports pointer. That must be fixed, or we'll crash...
     NS_ABORT_IF_FALSE(list_qi == list, "Uh, fix QI!");
   }
 #endif
 
   nsresult rv = list->GetItem(aIndex, aResult);
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -146,32 +146,32 @@ DOMCI_CLASS(BoxObject)
 #ifdef MOZ_XUL
 DOMCI_CLASS(TreeSelection)
 DOMCI_CLASS(TreeContentView)
 #endif
 
 // Crypto classes
 DOMCI_CLASS(Crypto)
 DOMCI_CLASS(CRMFObject)
-  
+
 // DOM Traversal classes
 DOMCI_CLASS(TreeWalker)
 
 // Rect object used by getComputedStyle
 DOMCI_CLASS(CSSRect)
 
 // DOM Chrome Window class, almost identical to Window
 DOMCI_CLASS(ChromeWindow)
 
 // ContentList object used for various live NodeLists
 DOMCI_CLASS(ContentList)
-  
+
 // Processing-instruction with target "xml-stylesheet"
 DOMCI_CLASS(XMLStylesheetProcessingInstruction)
-  
+
 DOMCI_CLASS(ImageDocument)
 
 #ifdef MOZ_XUL
 DOMCI_CLASS(XULTemplateBuilder)
 DOMCI_CLASS(XULTreeBuilder)
 #endif
 
 // DOMStringList object
@@ -318,20 +318,16 @@ DOMCI_CLASS(CSSFontFaceRule)
 
 #if defined(MOZ_MEDIA)
 // WhatWG Video Element
 DOMCI_CLASS(HTMLVideoElement)
 DOMCI_CLASS(HTMLSourceElement)
 DOMCI_CLASS(MediaError)
 DOMCI_CLASS(HTMLAudioElement)
 DOMCI_CLASS(TimeRanges)
-
-// Media streams
-DOMCI_CLASS(MediaStream)
-DOMCI_CLASS(LocalMediaStream)
 #endif
 
 // DOM Traversal NodeIterator class
 DOMCI_CLASS(NodeIterator)
 
 DOMCI_CLASS(DataTransfer)
 
 DOMCI_CLASS(NotifyPaintEvent)
@@ -402,16 +398,17 @@ DOMCI_CLASS(BluetoothDevice)
 #endif
 
 DOMCI_CLASS(CameraManager)
 DOMCI_CLASS(CameraControl)
 DOMCI_CLASS(CameraCapabilities)
 
 DOMCI_CLASS(DOMError)
 DOMCI_CLASS(DOMRequest)
+DOMCI_CLASS(DOMCursor)
 DOMCI_CLASS(OpenWindowEventDetail)
 DOMCI_CLASS(AsyncScrollEventDetail)
 
 DOMCI_CLASS(DOMFileHandle)
 DOMCI_CLASS(FileRequest)
 DOMCI_CLASS(LockedFile)
 
 #ifdef MOZ_SYS_MSG
--- a/dom/base/nsDOMWindowList.cpp
+++ b/dom/base/nsDOMWindowList.cpp
@@ -9,18 +9,16 @@
 // Helper classes
 #include "nsCOMPtr.h"
 
 // Interfaces needed
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMWindow.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellTreeItem.h"
-#include "nsIDocShellTreeNode.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIWebNavigation.h"
 
 nsDOMWindowList::nsDOMWindowList(nsIDocShell *aDocShell)
 {
   SetDocShell(aDocShell);
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -20,18 +20,16 @@
 #include "nsIDOMHTMLFrameElement.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMHTMLMapElement.h"
 #include "nsIDOMHTMLLegendElement.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMRange.h"
 #include "nsIHTMLDocument.h"
 #include "nsIDocShell.h"
-#include "nsIEditorDocShell.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsLayoutUtils.h"
 #include "nsIPresShell.h"
 #include "nsIContentViewer.h"
 #include "nsFrameTraversal.h"
 #include "nsObjectFrame.h"
 #include "nsEventDispatcher.h"
 #include "nsEventStateManager.h"
@@ -602,28 +600,25 @@ nsFocusManager::MoveCaretToFocus(nsIDOMW
 {
   int32_t itemType = nsIDocShellTreeItem::typeChrome;
 
   nsCOMPtr<nsIWebNavigation> webnav = do_GetInterface(aWindow);
   nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(webnav);
   if (dsti) {
     dsti->GetItemType(&itemType);
     if (itemType != nsIDocShellTreeItem::typeChrome) {
-      // don't move the caret for editable documents
-      nsCOMPtr<nsIEditorDocShell> editorDocShell(do_QueryInterface(dsti));
-      if (editorDocShell) {
-        bool isEditable;
-        editorDocShell->GetEditable(&isEditable);
-        if (isEditable)
-          return NS_OK;
-      }
-
       nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(dsti);
       NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
 
+      // don't move the caret for editable documents
+      bool isEditable;
+      docShell->GetEditable(&isEditable);
+      if (isEditable)
+        return NS_OK;
+
       nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
       NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
 
       nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aWindow));
       nsCOMPtr<nsIContent> content = window->GetFocusedNode();
       if (content)
         MoveCaretToFocus(presShell, content);
     }
@@ -1110,19 +1105,18 @@ nsFocusManager::SetFocusInner(nsIContent
     if (inUnload)
       return;
 
     bool beingDestroyed;
     docShell->IsBeingDestroyed(&beingDestroyed);
     if (beingDestroyed)
       return;
 
-    nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(docShell);
     nsCOMPtr<nsIDocShellTreeItem> parentDsti;
-    dsti->GetParent(getter_AddRefs(parentDsti));
+    docShell->GetParent(getter_AddRefs(parentDsti));
     docShell = do_QueryInterface(parentDsti);
   }
 
   // if the new element is in the same window as the currently focused element 
   bool isElementInFocusedWindow = (mFocusedWindow == newWindow);
 
   if (!isElementInFocusedWindow && mFocusedWindow && newWindow &&
       nsContentUtils::IsHandlingKeyBoardEvent()) {
@@ -2027,32 +2021,29 @@ nsFocusManager::UpdateCaret(bool aMoveCa
   nsCOMPtr<nsIPresShell> presShell = focusedDocShell->GetPresShell();
   if (!presShell)
     return;
 
   // If this is an editable document which isn't contentEditable, or a
   // contentEditable document and the node to focus is contentEditable,
   // return, so that we don't mess with caret visibility.
   bool isEditable = false;
-  nsCOMPtr<nsIEditorDocShell> editorDocShell(do_QueryInterface(dsti));
-  if (editorDocShell) {
-    editorDocShell->GetEditable(&isEditable);
-
-    if (isEditable) {
-      nsCOMPtr<nsIHTMLDocument> doc =
-        do_QueryInterface(presShell->GetDocument());
-
-      bool isContentEditableDoc =
-        doc && doc->GetEditingState() == nsIHTMLDocument::eContentEditable;
-
-      bool isFocusEditable =
-        aContent && aContent->HasFlag(NODE_IS_EDITABLE);
-      if (!isContentEditableDoc || isFocusEditable)
-        return;
-    }
+  focusedDocShell->GetEditable(&isEditable);
+
+  if (isEditable) {
+    nsCOMPtr<nsIHTMLDocument> doc =
+      do_QueryInterface(presShell->GetDocument());
+
+    bool isContentEditableDoc =
+      doc && doc->GetEditingState() == nsIHTMLDocument::eContentEditable;
+
+    bool isFocusEditable =
+      aContent && aContent->HasFlag(NODE_IS_EDITABLE);
+    if (!isContentEditableDoc || isFocusEditable)
+      return;
   }
 
   if (!isEditable && aMoveCaretToFocus)
     MoveCaretToFocus(presShell, aContent);
 
   if (!aUpdateVisibility)
     return;
 
@@ -2444,18 +2435,17 @@ nsFocusManager::DetermineElementToMoveFo
     if (popupFrame) {
       rootContent = popupFrame->GetContent();
       NS_ASSERTION(rootContent, "Popup frame doesn't have a content node");
       startContent = rootContent;
     }
     else {
       // Otherwise, for content shells, start from the location of the caret.
       int32_t itemType;
-      nsCOMPtr<nsIDocShellTreeItem> shellItem = do_QueryInterface(docShell);
-      shellItem->GetItemType(&itemType);
+      docShell->GetItemType(&itemType);
       if (itemType != nsIDocShellTreeItem::typeChrome) {
         nsCOMPtr<nsIContent> endSelectionContent;
         GetSelectionLocation(doc, presShell,
                              getter_AddRefs(startContent),
                              getter_AddRefs(endSelectionContent));
         // If the selection is on the rootContent, then there is no selection
         if (startContent == rootContent) {
           startContent = nullptr;
@@ -2548,20 +2538,18 @@ nsFocusManager::DetermineElementToMoveFo
     if (aNoParentTraversal) {
       startContent = rootContent;
       tabIndex = forward ? 1 : 0;
       continue;
     }
 
     // reached the beginning or end of the document. Traverse up to the parent
     // document and try again.
-    nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(docShell);
-
     nsCOMPtr<nsIDocShellTreeItem> docShellParent;
-    dsti->GetParent(getter_AddRefs(docShellParent));
+    docShell->GetParent(getter_AddRefs(docShellParent));
     if (docShellParent) {
       // move up to the parent shell and try again from there.
 
       // first, get the frame element this window is inside.
       nsCOMPtr<nsPIDOMWindow> piWindow = do_GetInterface(docShell);
       NS_ENSURE_TRUE(piWindow, NS_ERROR_FAILURE);
 
       // Next, retrieve the parent docshell, document and presshell.
@@ -2964,18 +2952,18 @@ nsFocusManager::GetRootForFocus(nsPIDOMW
 
       nsIFrame* frame = docContent->GetPrimaryFrame();
       if (!frame || !frame->IsFocusable(nullptr, 0))
         return nullptr;
     }
   }
   else  {
     int32_t itemType;
-    nsCOMPtr<nsIDocShellTreeItem> shellItem = do_QueryInterface(aWindow->GetDocShell());
-    shellItem->GetItemType(&itemType);
+    nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
+    docShell->GetItemType(&itemType);
 
     if (itemType == nsIDocShellTreeItem::typeChrome)
       return nullptr;
   }
 
   if (aCheckVisibility && !IsWindowVisible(aWindow))
     return nullptr;
 
@@ -3140,55 +3128,55 @@ nsFocusManager::GetNextTabbablePanel(nsI
 }
 
 nsIContent*
 nsFocusManager::GetNextTabbableDocument(nsIContent* aStartContent, bool aForward)
 {
   // If currentPopup is set, then the starting content is in a panel.
   nsIFrame* currentPopup = nullptr;
   nsCOMPtr<nsIDocument> doc;
-  nsCOMPtr<nsIDocShellTreeItem> startItem;
+  nsCOMPtr<nsIDocShell> startDocShell;
 
   if (aStartContent) {
     doc = aStartContent->GetCurrentDoc();
     if (doc) {
-      startItem = do_QueryInterface(doc->GetWindow()->GetDocShell());
+      startDocShell = doc->GetWindow()->GetDocShell();
     }
 
     // Check if the starting content is inside a panel. Document navigation
     // must start from this panel instead of the document root.
     nsIContent* content = aStartContent;
     while (content) {
       if (content->NodeInfo()->Equals(nsGkAtoms::panel, kNameSpaceID_XUL)) {
         currentPopup = content->GetPrimaryFrame();
         break;
       }
       content = content->GetParent();
     }
   }
   else if (mFocusedWindow) {
-    startItem = do_QueryInterface(mFocusedWindow->GetDocShell());
+    startDocShell = mFocusedWindow->GetDocShell();
     doc = mFocusedWindow->GetExtantDoc();
   }
   else {
     nsCOMPtr<nsIWebNavigation> webnav = do_GetInterface(mActiveWindow);
-    startItem = do_QueryInterface(webnav);
+    startDocShell = do_QueryInterface(webnav);
 
     if (mActiveWindow) {
       doc = mActiveWindow->GetExtantDoc();
     }
   }
 
-  if (!startItem)
+  if (!startDocShell)
     return nullptr;
 
   // perform a depth first search (preorder) of the docshell tree
   // looking for an HTML Frame or a chrome document
   nsIContent* content = aStartContent;
-  nsCOMPtr<nsIDocShellTreeItem> curItem = startItem;
+  nsCOMPtr<nsIDocShellTreeItem> curItem = startDocShell.get();
   nsCOMPtr<nsIDocShellTreeItem> nextItem;
   do {
     // If moving forward, check for a panel in the starting document. If one
     // exists with focusable content, return that content instead of the next
     // document. If currentPopup is set, then, another panel may exist. If no
     // such panel exists, then continue on to check the next document.
     // When moving backwards, and the starting content is in a panel, then
     // check for additional panels in the starting document. If the starting
@@ -3211,25 +3199,25 @@ nsFocusManager::GetNextTabbableDocument(
     }
 
     // Look for the next or previous document.
     if (!nextFrame) {
       if (aForward) {
         GetNextDocShell(curItem, getter_AddRefs(nextItem));
         if (!nextItem) {
           // wrap around to the beginning, which is the top of the tree
-          startItem->GetRootTreeItem(getter_AddRefs(nextItem));
+          startDocShell->GetRootTreeItem(getter_AddRefs(nextItem));
         }
       }
       else {
         GetPreviousDocShell(curItem, getter_AddRefs(nextItem));
         if (!nextItem) {
           // wrap around to the end, which is the last item in the tree
           nsCOMPtr<nsIDocShellTreeItem> rootItem;
-          startItem->GetRootTreeItem(getter_AddRefs(rootItem));
+          startDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
           GetLastDocShell(rootItem, getter_AddRefs(nextItem));
         }
 
         // When going back to the previous document, check for any focusable
         // popups in that previous document first.
         checkPopups = true;
       }
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -75,19 +75,16 @@
 #include "nsIWidget.h"
 #include "nsIWidgetListener.h"
 #include "nsIBaseWindow.h"
 #include "nsDeviceSensors.h"
 #include "nsIContent.h"
 #include "nsIContentViewerEdit.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellLoadInfo.h"
-#include "nsIDocShellTreeItem.h"
-#include "nsIDocShellTreeNode.h"
-#include "nsIEditorDocShell.h"
 #include "nsIDocCharset.h"
 #include "nsIDocument.h"
 #include "nsIHTMLDocument.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLElement.h"
 #ifndef MOZ_DISABLE_DOMCRYPTO
 #include "nsIDOMCrypto.h"
 #endif
@@ -1760,18 +1757,17 @@ nsGlobalWindow::SetInitialPrincipalToSub
   if (!newWindowPrincipal) {
     newWindowPrincipal = systemPrincipal;
   }
 
   // Now, if we're about to use the system principal, make sure we're not using
   // it for a content docshell.
   if (newWindowPrincipal == systemPrincipal) {
     int32_t itemType;
-    nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(GetDocShell());
-    nsresult rv = item->GetItemType(&itemType);
+    nsresult rv = GetDocShell()->GetItemType(&itemType);
     if (NS_FAILED(rv) || itemType != nsIDocShellTreeItem::typeChrome) {
       newWindowPrincipal = nullptr;
     }
   }
 
   // If there's an existing document, bail if it either:
   if (mDoc) {
     // (a) is not an initial about:blank document, or
@@ -2373,20 +2369,19 @@ nsGlobalWindow::SetNewDocument(nsIDocume
   mContext->GC(js::gcreason::SET_NEW_DOCUMENT);
   mContext->DidInitializeContext();
 
   if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) {
     // We should probably notify. However if this is the, arguably bad,
     // situation when we're creating a temporary non-chrome-about-blank
     // document in a chrome docshell, don't notify just yet. Instead wait
     // until we have a real chrome doc.
-    nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
     int32_t itemType = nsIDocShellTreeItem::typeContent;
-    if (treeItem) {
-      treeItem->GetItemType(&itemType);
+    if (mDocShell) {
+      mDocShell->GetItemType(&itemType);
     }
 
     if (itemType != nsIDocShellTreeItem::typeChrome ||
         nsContentUtils::IsSystemPrincipal(mDoc->NodePrincipal())) {
       newInnerWindow->mHasNotifiedGlobalCreated = true;
       nsContentUtils::AddScriptRunner(
         NS_NewRunnableMethod(this, &nsGlobalWindow::DispatchDOMWindowCreated));
     }
@@ -2905,23 +2900,22 @@ nsGlobalWindow::PostHandleEvent(nsEventC
     mIsDocumentLoaded = false;
   } else if (aVisitor.mEvent->message == NS_LOAD &&
              aVisitor.mEvent->mFlags.mIsTrusted) {
     // This is page load event since load events don't propagate to |window|.
     // @see nsDocument::PreHandleEvent.
     mIsDocumentLoaded = true;
 
     nsCOMPtr<nsIContent> content(do_QueryInterface(GetFrameElementInternal()));
-    nsCOMPtr<nsIDocShellTreeItem> treeItem =
-      do_QueryInterface(GetDocShell());
+    nsIDocShell* docShell = GetDocShell();
 
     int32_t itemType = nsIDocShellTreeItem::typeChrome;
 
-    if (treeItem) {
-      treeItem->GetItemType(&itemType);
+    if (docShell) {
+      docShell->GetItemType(&itemType);
     }
 
     if (content && GetParentInternal() &&
         itemType != nsIDocShellTreeItem::typeChrome) {
       // If we're not in chrome, or at a chrome boundary, fire the
       // onload event for the frame element.
 
       nsEventStatus status = nsEventStatus_eIgnore;
@@ -3346,18 +3340,17 @@ nsGlobalWindow::GetContent(nsIDOMWindow*
     // which is "good enough", for now.
     nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(mDocShell));
 
     if (baseWin) {
       bool visible = false;
       baseWin->GetVisibility(&visible);
 
       if (!visible) {
-        nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(mDocShell));
-        treeItem->GetSameTypeRootTreeItem(getter_AddRefs(primaryContent));
+        mDocShell->GetSameTypeRootTreeItem(getter_AddRefs(primaryContent));
       }
     }
   }
 
   if (!primaryContent) {
     nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
     GetTreeOwner(getter_AddRefs(treeOwner));
     NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
@@ -3662,22 +3655,21 @@ nsGlobalWindow::GetOpener(nsIDOMWindow**
   nsGlobalWindow *win = static_cast<nsGlobalWindow *>(openerPwin.get());
   if (win->IsChromeWindow()) {
     return NS_OK;
   }
 
   // We don't want to reveal the opener if the opener is a mail window,
   // because opener can be used to spoof the contents of a message (bug 105050).
   // So, we look in the opener's root docshell to see if it's a mail window.
-  nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
-    do_QueryInterface(openerPwin->GetDocShell());
-
-  if (docShellAsItem) {
+  nsCOMPtr<nsIDocShell> openerDocShell = openerPwin->GetDocShell();
+
+  if (openerDocShell) {
     nsCOMPtr<nsIDocShellTreeItem> openerRootItem;
-    docShellAsItem->GetRootTreeItem(getter_AddRefs(openerRootItem));
+    openerDocShell->GetRootTreeItem(getter_AddRefs(openerRootItem));
     nsCOMPtr<nsIDocShell> openerRootDocShell(do_QueryInterface(openerRootItem));
     if (openerRootDocShell) {
       uint32_t appType;
       nsresult rv = openerRootDocShell->GetAppType(&appType);
       if (NS_SUCCEEDED(rv) && appType != nsIDocShell::APP_TYPE_MAIL) {
         *aOpener = opener;
       }
     }
@@ -3774,33 +3766,31 @@ nsGlobalWindow::SetDefaultStatus(const n
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::GetName(nsAString& aName)
 {
   FORWARD_TO_OUTER(GetName, (aName), NS_ERROR_NOT_INITIALIZED);
 
   nsXPIDLString name;
-  nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
-  if (docShellAsItem)
-    docShellAsItem->GetName(getter_Copies(name));
+  if (mDocShell)
+    mDocShell->GetName(getter_Copies(name));
 
   aName.Assign(name);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::SetName(const nsAString& aName)
 {
   FORWARD_TO_OUTER(SetName, (aName), NS_ERROR_NOT_INITIALIZED);
 
   nsresult result = NS_OK;
-  nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
-  if (docShellAsItem)
-    result = docShellAsItem->SetName(PromiseFlatString(aName).get());
+  if (mDocShell)
+    result = mDocShell->SetName(PromiseFlatString(aName).get());
   return result;
 }
 
 // Helper functions used by many methods below.
 int32_t
 nsGlobalWindow::DevToCSSIntPixels(int32_t px)
 {
   if (!mDocShell)
@@ -4406,24 +4396,23 @@ nsGlobalWindow::CheckSecurityWidthAndHei
 
   return NS_OK;
 }
 
 // NOTE: Arguments to this function should have values in device pixels
 nsresult
 nsGlobalWindow::SetDocShellWidthAndHeight(int32_t aInnerWidth, int32_t aInnerHeight)
 {
-  nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
-  NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
+  NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
-  docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
+  mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
   NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
 
-  NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(docShellAsItem, aInnerWidth, aInnerHeight),
+  NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(mDocShell, aInnerWidth, aInnerHeight),
                     NS_ERROR_FAILURE);
 
   return NS_OK;
 }
 
 // NOTE: Arguments to this function should have values in app units
 nsresult
 nsGlobalWindow::SetCSSViewportWidthAndHeight(nscoord aInnerWidth, nscoord aInnerHeight)
@@ -4689,27 +4678,23 @@ nsGlobalWindow::WindowExists(const nsASt
   NS_PRECONDITION(IsOuterWindow(), "Must be outer window");
   NS_PRECONDITION(mDocShell, "Must have docshell");
 
   nsCOMPtr<nsIDocShellTreeItem> caller;
   if (aLookForCallerOnJSStack) {
     caller = GetCallerDocShellTreeItem();
   }
 
-  nsCOMPtr<nsIDocShellTreeItem> docShell = do_QueryInterface(mDocShell);
-  NS_ASSERTION(docShell,
-               "Docshell doesn't implement nsIDocShellTreeItem?");
-
   if (!caller) {
-    caller = docShell;
+    caller = mDocShell;
   }
 
   nsCOMPtr<nsIDocShellTreeItem> namedItem;
-  docShell->FindItemWithName(PromiseFlatString(aName).get(), nullptr, caller,
-                             getter_AddRefs(namedItem));
+  mDocShell->FindItemWithName(PromiseFlatString(aName).get(), nullptr, caller,
+                              getter_AddRefs(namedItem));
   return namedItem != nullptr;
 }
 
 already_AddRefed<nsIWidget>
 nsGlobalWindow::GetMainWidget()
 {
   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
@@ -4755,29 +4740,28 @@ nsGlobalWindow::SetFullScreenInternal(bo
   if (aFullScreen == rootWinFullScreen || 
       (aRequireTrust && !nsContentUtils::IsCallerChrome())) {
     return NS_OK;
   }
 
   // SetFullScreen needs to be called on the root window, so get that
   // via the DocShell tree, and if we are not already the root,
   // call SetFullScreen on that window instead.
-  nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
   nsCOMPtr<nsIDocShellTreeItem> rootItem;
-  treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
+  mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
   nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(rootItem);
   if (!window)
     return NS_ERROR_FAILURE;
-  if (rootItem != treeItem)
+  if (rootItem != mDocShell)
     return window->SetFullScreenInternal(aFullScreen, aRequireTrust);
 
   // make sure we don't try to set full screen on a non-chrome window,
   // which might happen in embedding world
   int32_t itemType;
-  treeItem->GetItemType(&itemType);
+  mDocShell->GetItemType(&itemType);
   if (itemType != nsIDocShellTreeItem::typeChrome)
     return NS_ERROR_FAILURE;
 
   // If we are already in full screen mode, just return.
   if (mFullScreen == aFullScreen)
     return NS_OK;
 
   // dispatch a "fullscreen" DOM event so that XUL apps can
@@ -4833,21 +4817,20 @@ nsGlobalWindow::SetFullScreenInternal(bo
 
 NS_IMETHODIMP
 nsGlobalWindow::GetFullScreen(bool* aFullScreen)
 {
   FORWARD_TO_OUTER(GetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
 
   // Get the fullscreen value of the root window, to always have the value
   // accurate, even when called from content.
-  nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
-  if (treeItem) {
+  if (mDocShell) {
     nsCOMPtr<nsIDocShellTreeItem> rootItem;
-    treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
-    if (rootItem != treeItem) {
+    mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
+    if (rootItem != mDocShell) {
       nsCOMPtr<nsIDOMWindow> window = do_GetInterface(rootItem);
       if (window)
         return window->GetFullScreen(aFullScreen);
     }
   }
 
   // We are the root window, or something went wrong. Return our internal value.
   *aFullScreen = mFullScreen;
@@ -5332,20 +5315,18 @@ nsGlobalWindow::Focus()
   // (bugs 355482 and 369306).
   bool canFocus = CanSetProperty("dom.disable_window_flip") ||
                     (opener == caller &&
                      RevisePopupAbuseLevel(gPopupControlState) < openAbused);
 
   nsCOMPtr<nsIDOMWindow> activeWindow;
   fm->GetActiveWindow(getter_AddRefs(activeWindow));
 
-  nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
-  NS_ASSERTION(treeItem, "What happened?");
   nsCOMPtr<nsIDocShellTreeItem> rootItem;
-  treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
+  mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
   nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
   bool isActive = (rootWin == activeWindow);
 
   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin;
   GetTreeOwner(getter_AddRefs(treeOwnerAsWin));
   if (treeOwnerAsWin && (canFocus || isActive)) {
     bool isEnabled = true;
     if (NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled)) && !isEnabled) {
@@ -5363,34 +5344,34 @@ nsGlobalWindow::Focus()
     return NS_OK;
 
   nsCOMPtr<nsIPresShell> presShell;
   // Don't look for a presshell if we're a root chrome window that's got
   // about:blank loaded.  We don't want to focus our widget in that case.
   // XXXbz should we really be checking for IsInitialDocument() instead?
   bool lookForPresShell = true;
   int32_t itemType = nsIDocShellTreeItem::typeContent;
-  treeItem->GetItemType(&itemType);
+  mDocShell->GetItemType(&itemType);
   if (itemType == nsIDocShellTreeItem::typeChrome &&
       GetPrivateRoot() == static_cast<nsIDOMWindow*>(this) &&
       mDocument) {
     nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
     NS_ASSERTION(doc, "Bogus doc?");
     nsIURI* ourURI = doc->GetDocumentURI();
     if (ourURI) {
       lookForPresShell = !NS_IsAboutBlank(ourURI);
     }
   }
 
   if (lookForPresShell) {
     mDocShell->GetEldestPresShell(getter_AddRefs(presShell));
   }
 
   nsCOMPtr<nsIDocShellTreeItem> parentDsti;
-  treeItem->GetParent(getter_AddRefs(parentDsti));
+  mDocShell->GetParent(getter_AddRefs(parentDsti));
 
   // set the parent's current focus to the frame containing this window.
   nsCOMPtr<nsIDOMWindow> parent(do_GetInterface(parentDsti));
   if (parent) {
     nsCOMPtr<nsIDOMDocument> parentdomdoc;
     parent->GetDocument(getter_AddRefs(parentdomdoc));
 
     nsCOMPtr<nsIDocument> parentdoc = do_QueryInterface(parentdomdoc);
@@ -5797,18 +5778,17 @@ nsGlobalWindow::SizeToContent()
 
   nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
   NS_ENSURE_SUCCESS(CheckSecurityWidthAndHeight(&cssSize.width,
                                                 &cssSize.height),
                     NS_ERROR_FAILURE);
 
   nsIntSize newDevSize(CSSToDevIntPixels(cssSize));
 
-  nsCOMPtr<nsIDocShellTreeItem> docShellAsItem = do_QueryInterface(mDocShell);
-  NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(docShellAsItem,
+  NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(mDocShell,
                                            newDevSize.width, newDevSize.height),
                     NS_ERROR_FAILURE);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::GetWindowRoot(nsIDOMEventTarget **aWindowRoot)
@@ -6094,22 +6074,18 @@ nsGlobalWindow::PopupWhitelisted()
  */
 PopupControlState
 nsGlobalWindow::RevisePopupAbuseLevel(PopupControlState aControl)
 {
   FORWARD_TO_OUTER(RevisePopupAbuseLevel, (aControl), aControl);
 
   NS_ASSERTION(mDocShell, "Must have docshell");
   
-  nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(mDocShell));
-
-  NS_ASSERTION(item, "Docshell doesn't implement nsIDocShellTreeItem?");
-
   int32_t type = nsIDocShellTreeItem::typeChrome;
-  item->GetItemType(&type);
+  mDocShell->GetItemType(&type);
   if (type != nsIDocShellTreeItem::typeContent)
     return openAllowed;
 
   PopupControlState abuse = aControl;
   switch (abuse) {
   case openControlled:
   case openAbused:
   case openOverridden:
@@ -6954,21 +6930,20 @@ nsGlobalWindow::ReallyCloseWindow()
 
   // If there's no treeOwnerAsWin, this window must already be closed.
 
   if (treeOwnerAsWin) {
 
     // but if we're a browser window we could be in some nasty
     // self-destroying cascade that we should mostly ignore
 
-    nsCOMPtr<nsIDocShellTreeItem> docItem(do_QueryInterface(mDocShell));
-    if (docItem) {
+    if (mDocShell) {
       nsCOMPtr<nsIBrowserDOMWindow> bwin;
       nsCOMPtr<nsIDocShellTreeItem> rootItem;
-      docItem->GetRootTreeItem(getter_AddRefs(rootItem));
+      mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
       nsCOMPtr<nsIDOMWindow> rootWin(do_GetInterface(rootItem));
       nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(rootWin));
       if (chromeWin)
         chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
 
       if (rootWin) {
         /* Normally we destroy the entire window, but not if
            this DOM window belongs to a tabbed browser and doesn't
@@ -8185,24 +8160,24 @@ nsGlobalWindow::SetKeyboardIndicators(UI
 
   // only change the flags that have been modified
   if (aShowAccelerators != UIStateChangeType_NoChange)
     mShowAccelerators = aShowAccelerators == UIStateChangeType_Set;
   if (aShowFocusRings != UIStateChangeType_NoChange)
     mShowFocusRings = aShowFocusRings == UIStateChangeType_Set;
 
   // propagate the indicators to child windows
-  nsCOMPtr<nsIDocShellTreeNode> node = do_QueryInterface(GetDocShell());
-  if (node) {
+  nsCOMPtr<nsIDocShell> docShell = GetDocShell();
+  if (docShell) {
     int32_t childCount = 0;
-    node->GetChildCount(&childCount);
+    docShell->GetChildCount(&childCount);
 
     for (int32_t i = 0; i < childCount; ++i) {
       nsCOMPtr<nsIDocShellTreeItem> childShell;
-      node->GetChildAt(i, getter_AddRefs(childShell));
+      docShell->GetChildAt(i, getter_AddRefs(childShell));
       nsCOMPtr<nsPIDOMWindow> childWindow = do_GetInterface(childShell);
       if (childWindow) {
         childWindow->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings);
       }
     }
   }
 
   bool newShouldShowFocusRing = ShouldShowFocusRing();
@@ -8476,23 +8451,20 @@ static nsCanvasFrame* FindCanvasFrame(ns
 void
 nsGlobalWindow::UpdateCanvasFocus(bool aFocusChanged, nsIContent* aNewContent)
 {
   // this is called from the inner window so use GetDocShell
   nsIDocShell* docShell = GetDocShell();
   if (!docShell)
     return;
 
-  nsCOMPtr<nsIEditorDocShell> editorDocShell = do_QueryInterface(docShell);
-  if (editorDocShell) {
-    bool editable;
-    editorDocShell->GetEditable(&editable);
-    if (editable)
-      return;
-  }
+  bool editable;
+  docShell->GetEditable(&editable);
+  if (editable)
+    return;
 
   nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
   if (!presShell || !mDocument)
     return;
 
   nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
   Element *rootElement = doc->GetRootElement();
   if (rootElement) {
@@ -9490,25 +9462,24 @@ nsGlobalWindow::FireDelayedDOMEvents()
     HandleIdleActiveEvent();
   }
 
   if (mNotifyIdleObserversActiveOnThaw) {
     mNotifyIdleObserversActiveOnThaw = false;
     ScheduleActiveTimerCallback();
   }
 
-  nsCOMPtr<nsIDocShellTreeNode> node =
-    do_QueryInterface(GetDocShell());
-  if (node) {
+  nsCOMPtr<nsIDocShell> docShell = GetDocShell();
+  if (docShell) {
     int32_t childCount = 0;
-    node->GetChildCount(&childCount);
+    docShell->GetChildCount(&childCount);
 
     for (int32_t i = 0; i < childCount; ++i) {
       nsCOMPtr<nsIDocShellTreeItem> childShell;
-      node->GetChildAt(i, getter_AddRefs(childShell));
+      docShell->GetChildAt(i, getter_AddRefs(childShell));
       NS_ASSERTION(childShell, "null child shell");
 
       nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
       if (pWin) {
         nsGlobalWindow *win =
           static_cast<nsGlobalWindow*>
                      (static_cast<nsPIDOMWindow*>(pWin));
         win->FireDelayedDOMEvents();
@@ -10527,43 +10498,40 @@ nsGlobalWindow::TimerCallback(nsITimer *
 // nsGlobalWindow: Helper Functions
 //*****************************************************************************
 
 nsresult
 nsGlobalWindow::GetTreeOwner(nsIDocShellTreeOwner **aTreeOwner)
 {
   FORWARD_TO_OUTER(GetTreeOwner, (aTreeOwner), NS_ERROR_NOT_INITIALIZED);
 
-  nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
-
   // If there's no docShellAsItem, this window must have been closed,
   // in that case there is no tree owner.
 
-  if (!docShellAsItem) {
+  if (!mDocShell) {
     *aTreeOwner = nullptr;
 
     return NS_OK;
   }
 
-  return docShellAsItem->GetTreeOwner(aTreeOwner);
+  return mDocShell->GetTreeOwner(aTreeOwner);
 }
 
 nsresult
 nsGlobalWindow::GetTreeOwner(nsIBaseWindow **aTreeOwner)
 {
   FORWARD_TO_OUTER(GetTreeOwner, (aTreeOwner), NS_ERROR_NOT_INITIALIZED);
 
-  nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
 
-  // If there's no docShellAsItem, this window must have been closed,
+  // If there's no mDocShell, this window must have been closed,
   // in that case there is no tree owner.
 
-  if (docShellAsItem) {
-    docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
+  if (mDocShell) {
+    mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
   }
 
   if (!treeOwner) {
     *aTreeOwner = nullptr;
     return NS_OK;
   }
 
   return CallQueryInterface(treeOwner, aTreeOwner);
@@ -10813,24 +10781,24 @@ nsGlobalWindow::SuspendTimeouts(uint32_t
         // passing null for the context, since this shouldn't actually release this
         // timeout.
         t->Release();
       }
     }
   }
 
   // Suspend our children as well.
-  nsCOMPtr<nsIDocShellTreeNode> node(do_QueryInterface(GetDocShell()));
-  if (node) {
+  nsCOMPtr<nsIDocShell> docShell = GetDocShell();
+  if (docShell) {
     int32_t childCount = 0;
-    node->GetChildCount(&childCount);
+    docShell->GetChildCount(&childCount);
 
     for (int32_t i = 0; i < childCount; ++i) {
       nsCOMPtr<nsIDocShellTreeItem> childShell;
-      node->GetChildAt(i, getter_AddRefs(childShell));
+      docShell->GetChildAt(i, getter_AddRefs(childShell));
       NS_ASSERTION(childShell, "null child shell");
 
       nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
       if (pWin) {
         nsGlobalWindow *win =
           static_cast<nsGlobalWindow*>
                      (static_cast<nsPIDOMWindow*>(pWin));
         NS_ASSERTION(win->IsOuterWindow(), "Expected outer window");
@@ -10917,25 +10885,24 @@ nsGlobalWindow::ResumeTimeouts(bool aTha
       }
 
       // Add a reference for the new timer's closure.
       t->AddRef();
     }
   }
 
   // Resume our children as well.
-  nsCOMPtr<nsIDocShellTreeNode> node =
-    do_QueryInterface(GetDocShell());
-  if (node) {
+  nsCOMPtr<nsIDocShell> docShell = GetDocShell();
+  if (docShell) {
     int32_t childCount = 0;
-    node->GetChildCount(&childCount);
+    docShell->GetChildCount(&childCount);
 
     for (int32_t i = 0; i < childCount; ++i) {
       nsCOMPtr<nsIDocShellTreeItem> childShell;
-      node->GetChildAt(i, getter_AddRefs(childShell));
+      docShell->GetChildAt(i, getter_AddRefs(childShell));
       NS_ASSERTION(childShell, "null child shell");
 
       nsCOMPtr<nsPIDOMWindow> pWin = do_GetInterface(childShell);
       if (pWin) {
         nsGlobalWindow *win =
           static_cast<nsGlobalWindow*>
                      (static_cast<nsPIDOMWindow*>(pWin));
 
--- a/dom/base/nsGlobalWindowCommands.cpp
+++ b/dom/base/nsGlobalWindowCommands.cpp
@@ -14,17 +14,16 @@
 #include "mozilla/Util.h"
 
 #include "nsIControllerCommandTable.h"
 #include "nsICommandParams.h"
 
 #include "nsPIDOMWindow.h"
 #include "nsIPresShell.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsISelectionController.h"
 #include "nsIWebNavigation.h"
 #include "nsIContentViewerEdit.h"
 #include "nsIContentViewer.h"
 #include "nsFocusManager.h"
 #include "nsCopySupport.h"
 #include "nsGUIEvent.h"
 #include "mozilla/Attributes.h"
@@ -238,20 +237,20 @@ nsSelectMoveScrollCommand::DoCommand(con
   // We allow the caret to be moved with arrow keys on any window for which
   // the caret is enabled. In particular, this includes caret-browsing mode
   // in non-chrome documents.
   bool caretOn = false;
   selCont->GetCaretEnabled(&caretOn);
   if (!caretOn) {
     caretOn = Preferences::GetBool("accessibility.browsewithcaret");
     if (caretOn) {
-      nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(piWindow->GetDocShell());
-      if (dsti) {
+      nsCOMPtr<nsIDocShell> docShell = piWindow->GetDocShell();
+      if (docShell) {
         int32_t itemType;
-        dsti->GetItemType(&itemType);
+        docShell->GetItemType(&itemType);
         if (itemType == nsIDocShellTreeItem::typeChrome) {
           caretOn = false;
         }
       }
     }
   }
 
   for (size_t i = 0; i < ArrayLength(browseCommands); i++) {
--- a/dom/base/nsHistory.cpp
+++ b/dom/base/nsHistory.cpp
@@ -9,17 +9,16 @@
 #include "nsCOMPtr.h"
 #include "nscore.h"
 #include "nsPIDOMWindow.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIDocument.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsIDocShell.h"
-#include "nsIDocShellTreeItem.h"
 #include "nsIWebNavigation.h"
 #include "nsIHistoryEntry.h"
 #include "nsIURI.h"
 #include "nsIServiceManager.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsXPIDLString.h"
 #include "nsReadableUtils.h"
 #include "nsDOMClassInfoID.h"
@@ -372,22 +371,21 @@ nsHistory::GetSessionHistoryFromDocShell
 
   NS_ENSURE_TRUE(aDocShell, NS_ERROR_FAILURE);
   /* The docshell we have may or may not be
    * the root docshell. So, get a handle to
    * SH from the root docshell
    */
   
   // QI mDocShell to nsIDocShellTreeItem
-  nsCOMPtr<nsIDocShellTreeItem> dsTreeItem(do_QueryInterface(aDocShell));
-  NS_ENSURE_TRUE(dsTreeItem, NS_ERROR_FAILURE);
+  NS_ENSURE_TRUE(aDocShell, NS_ERROR_FAILURE);
 
   // Get the root DocShell from it
   nsCOMPtr<nsIDocShellTreeItem> root;
-  dsTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
+  aDocShell->GetSameTypeRootTreeItem(getter_AddRefs(root));
   NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
   
   //QI root to nsIWebNavigation
   nsCOMPtr<nsIWebNavigation>   webNav(do_QueryInterface(root));
   NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
 
   //Get  SH from nsIWebNavigation
   return webNav->GetSessionHistory(aReturn);
new file mode 100644
--- /dev/null
+++ b/dom/base/nsIDOMDOMCursor.idl
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+[scriptable, function, uuid(3a75d80a-9258-4ab8-95fd-ec0b5f634df1)]
+interface nsICursorContinueCallback : nsISupports
+{
+  void handleContinue();
+};
+
+[scriptable, builtinclass, uuid(062ea35a-5158-425a-b7bc-3ae9daa84398)]
+interface nsIDOMDOMCursor : nsISupports
+{
+  readonly attribute boolean done;
+  void continue();
+};
--- a/dom/base/nsIDOMDOMRequest.idl
+++ b/dom/base/nsIDOMDOMRequest.idl
@@ -3,31 +3,41 @@
 /* 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 "nsIDOMEventTarget.idl"
 
 interface nsIDOMDOMError;
 interface nsIDOMWindow;
+interface nsIDOMDOMCursor;
+interface nsICursorContinueCallback;
 
 [scriptable, builtinclass, uuid(d88998b7-ee30-4ae5-bbed-58f5711929de)]
 interface nsIDOMDOMRequest : nsIDOMEventTarget
 {
   readonly attribute DOMString readyState; // "pending" or "done"
 
   readonly attribute jsval result;
   readonly attribute nsIDOMDOMError error;
 
   [implicit_jscontext] attribute jsval onsuccess;
   [implicit_jscontext] attribute jsval onerror;
 };
 
-[scriptable, builtinclass, uuid(10996de9-e6f6-4058-97bd-45f1fe065eb5)]
+[scriptable, builtinclass, uuid(060df968-fd71-47ca-91a8-6b64dadceb2c)]
 interface nsIDOMRequestService : nsISupports
 {
   nsIDOMDOMRequest createRequest(in nsIDOMWindow window);
+  /*
+   * @param aCallback
+   *        Called when `continue()' is called in the cursor, should be used to
+   *        notify the data provider that content wants the next result.
+   */
+  nsIDOMDOMCursor createCursor(in nsIDOMWindow window,
+                               in nsICursorContinueCallback aCallback);
 
   void fireSuccess(in nsIDOMDOMRequest request, in jsval result);
   void fireError(in nsIDOMDOMRequest request, in DOMString error);
   void fireSuccessAsync(in nsIDOMDOMRequest request, in jsval result);
   void fireErrorAsync(in nsIDOMDOMRequest request, in DOMString error);
+  void fireDone(in nsIDOMDOMCursor cursor);
 };
--- a/dom/base/nsPerformance.cpp
+++ b/dom/base/nsPerformance.cpp
@@ -7,34 +7,26 @@
 #include "TimeStamp.h"
 #include "nsCOMPtr.h"
 #include "nscore.h"
 #include "nsIDocShell.h"
 #include "nsITimedChannel.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsContentUtils.h"
 #include "nsIDOMWindow.h"
-#include "nsDOMClassInfoID.h"
 #include "mozilla/dom/PerformanceBinding.h"
 #include "mozilla/dom/PerformanceTimingBinding.h"
 #include "mozilla/dom/PerformanceNavigationBinding.h"
 
 using namespace mozilla;
 
-DOMCI_DATA(PerformanceTiming, nsPerformanceTiming)
-
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsPerformanceTiming, mPerformance)
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPerformanceTiming)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPerformanceTiming)
 
-// QueryInterface implementation for nsPerformanceTiming
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPerformanceTiming)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsPerformanceTiming, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsPerformanceTiming, Release)
 
 nsPerformanceTiming::nsPerformanceTiming(nsPerformance* aPerformance,
                                          nsITimedChannel* aChannel)
   : mPerformance(aPerformance),
     mChannel(aChannel)
 {
   MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
   SetIsDOMBinding();
@@ -135,28 +127,20 @@ JSObject*
 nsPerformanceTiming::WrapObject(JSContext *cx, JSObject *scope,
                                 bool *triedToWrap)
 {
   return dom::PerformanceTimingBinding::Wrap(cx, scope, this,
                                              triedToWrap);
 }
 
 
-
-DOMCI_DATA(PerformanceNavigation, nsPerformanceNavigation)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsPerformanceNavigation, mPerformance)
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsPerformanceNavigation, mPerformance)
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPerformanceNavigation)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPerformanceNavigation)
-
-// QueryInterface implementation for nsPerformanceNavigation
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPerformanceNavigation)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsPerformanceNavigation, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsPerformanceNavigation, Release)
 
 nsPerformanceNavigation::nsPerformanceNavigation(nsPerformance* aPerformance)
   : mPerformance(aPerformance)
 {
   MOZ_ASSERT(aPerformance, "Parent performance object should be provided");
   SetIsDOMBinding();
 }
 
@@ -168,18 +152,16 @@ JSObject*
 nsPerformanceNavigation::WrapObject(JSContext *cx, JSObject *scope,
                                     bool *triedToWrap)
 {
   return dom::PerformanceNavigationBinding::Wrap(cx, scope, this,
                                                  triedToWrap);
 }
 
 
-DOMCI_DATA(Performance, nsPerformance)
-
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(nsPerformance,
                                         mWindow, mTiming,
                                         mNavigation)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPerformance)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPerformance)
 
 nsPerformance::nsPerformance(nsIDOMWindow* aWindow,
                              nsDOMNavigationTiming* aDOMTiming,
--- a/dom/base/nsPerformance.h
+++ b/dom/base/nsPerformance.h
@@ -15,24 +15,23 @@
 class nsIURI;
 class nsITimedChannel;
 class nsIDOMWindow;
 class nsPerformance;
 class JSObject;
 struct JSContext;
 
 // Script "performance.timing" object
-class nsPerformanceTiming MOZ_FINAL : public nsISupports,
-                                      public nsWrapperCache
+class nsPerformanceTiming MOZ_FINAL : public nsWrapperCache
 {
 public:
   nsPerformanceTiming(nsPerformance* aPerformance,
                       nsITimedChannel* aChannel);
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsPerformanceTiming)
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsPerformanceTiming)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(nsPerformanceTiming)
 
   nsDOMNavigationTiming* GetDOMTiming() const;
 
   nsPerformance* GetParentObject() const
   {
     return mPerformance;
   }
 
@@ -88,23 +87,22 @@ public:
 
 private:
   ~nsPerformanceTiming();
   nsRefPtr<nsPerformance> mPerformance;
   nsCOMPtr<nsITimedChannel> mChannel;
 };
 
 // Script "performance.navigation" object
-class nsPerformanceNavigation MOZ_FINAL : public nsISupports,
-                                          public nsWrapperCache
+class nsPerformanceNavigation MOZ_FINAL : public nsWrapperCache
 {
 public:
   explicit nsPerformanceNavigation(nsPerformance* aPerformance);
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsPerformanceNavigation)
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsPerformanceNavigation)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(nsPerformanceNavigation)
 
   nsDOMNavigationTiming* GetDOMTiming() const;
 
   nsPerformance* GetParentObject() const
   {
     return mPerformance;
   }
 
--- a/dom/base/nsScreen.cpp
+++ b/dom/base/nsScreen.cpp
@@ -19,23 +19,22 @@
 using namespace mozilla;
 using namespace mozilla::dom;
 
 namespace {
 
 bool
 IsChromeType(nsIDocShell *aDocShell)
 {
-  nsCOMPtr<nsIDocShellTreeItem> ds = do_QueryInterface(aDocShell);
-  if (!ds) {
+  if (!aDocShell) {
     return false;
   }
 
   int32_t itemType;
-  ds->GetItemType(&itemType);
+  aDocShell->GetItemType(&itemType);
   return itemType == nsIDocShellTreeItem::typeChrome;
 }
 
 } // anonymous namespace
 
 /* static */ already_AddRefed<nsScreen>
 nsScreen::Create(nsPIDOMWindow* aWindow)
 {
--- a/dom/base/test/Makefile.in
+++ b/dom/base/test/Makefile.in
@@ -20,16 +20,17 @@ MOCHITEST_FILES = \
   test_gsp-quirks.html \
   test_gsp-qualified.html \
   test_nondomexception.html \
   test_screen_orientation.html \
   test_window_constructor.html \
   test_window_enumeration.html \
   test_window_indexing.html \
   test_writable-replaceable.html \
+  test_domcursor.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_domcursor.html
@@ -0,0 +1,145 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for DOMCursor</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+var reqserv = SpecialPowers.getDOMRequestService();
+ok("createRequest" in reqserv, "appears to be a service");
+
+var req;
+var lastContinue = false;
+
+var index = 0;
+
+function next() {
+  if (index < tests.length) {
+    ok(true, "Begin test");
+    tests[index++]();
+  } else {
+    ok(true, "All done");
+    SimpleTest.finish();
+  }
+}
+
+var tests = [
+  function() {
+    // create a cursor, test its interface and its initial state
+    req = reqserv.createCursor(window, function() {
+      if (lastContinue) {
+        reqserv.fireDone(req);
+      } else {
+        reqserv.fireSuccess(req, "next result")
+      }
+    });
+    ok("result" in req, "cursor has result");
+    ok("error" in req, "cursor has error");
+    ok("onsuccess" in req, "cursor has onsuccess");
+    ok("onerror" in req, "cursor has onerror");
+    ok("readyState" in req, "cursor has readyState");
+    ok("done" in req, "cursor has finished");
+    ok("continue" in req, "cursor has continue");
+
+    is(req.readyState, "pending", "readyState is pending");
+    is(req.result, undefined, "result is undefined");
+    is(req.onsuccess, null, "onsuccess is null");
+    is(req.onerror, null, "onerror is null");
+    next();
+  },
+  function() {
+    // fire success
+    req.onsuccess = function(e) {
+      ok(e, "got success event");
+      is(e.type, "success", "correct type during success");
+      is(e.target, req, "correct target during success");
+      is(req.readyState, "done", "correct readyState after success");
+      is(req.error, null, "correct error after success");
+      is(req.result, "my result", "correct result after success");
+      is(req.done, false, "cursor is not done after continue")
+      next();
+    }
+    reqserv.fireSuccess(req, "my result");
+  },
+  function() {
+    // continue
+    req.onsuccess = function(e) {
+      ok(e, "got success event after continue");
+      is(e.type, "success", "correct type during continue");
+      is(e.target, req, "correct target during continue");
+      is(req.readyState, "done", "correct readyState after continue");
+      is(req.error, null, "correct error after continue");
+      is(req.result, "next result", "correct result after continue");
+      is(req.done, false, "cursor is not done after continue")
+      next();
+    }
+    req.continue();
+    try {
+      req.continue();
+      ok(false, "calling continue twice should fail");
+    } catch (e) {
+      ok(true, "calling continue twice should fail");
+    }
+  },
+  function() {
+    // FireDone
+    req.onsuccess = function(e) {
+      ok(e, "got success event after continue");
+      is(e.type, "success", "correct type during continue");
+      is(e.target, req, "correct target during continue");
+      is(req.readyState, "done", "correct readyState after continue");
+      is(req.error, null, "correct error after continue");
+      is(req.result, undefined, "no result after last continue");
+      is(req.done, true, "cursor is done after last continue")
+      try {
+        req.continue();
+        ok(false, "continue when cursor is done should fail");
+      } catch (e) {
+        ok(true, "continue when cursor is done should fail");
+      }
+
+      next();
+    }
+    lastContinue = true;
+    req.continue();
+  },
+  function() {
+    // fire error
+    req = reqserv.createCursor(window, function(){});
+    req.onerror = function(e) {
+      ok(e, "got success event");
+      is(e.type, "error", "correct type during error");
+      is(e.target, req, "correct target during error");
+      is(req.readyState, "done", "correct readyState after error");
+      is(req.error.name, "error msg", "correct error after error");
+      is(req.result, undefined, "correct result after error");
+      try {
+        req.continue();
+        ok(false, "continue while in an error state should fail");
+      } catch (e) {
+        ok(true, "continue while in an error state should fail");
+      }
+
+      next();
+    }
+    reqserv.fireError(req, "error msg");
+  }
+];
+
+next();
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/base/test/test_domrequest.html
+++ b/dom/base/test/test_domrequest.html
@@ -1,12 +1,12 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-  <title>Test for XMLHttpRequest</title>
+  <title>Test for DOMRequest</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <p id="display"></p>
 <div id="content" style="display: none">
 
 </div>
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -601,24 +601,30 @@ DOMInterfaces = {
     'register': False
 },
 
 'MediaError': {
     'hasInstanceInterface': 'nsIDOMMediaError',
 },
 
 'MediaStream': [{
-    'nativeType': 'nsIDOMMediaStream',
+    'headerFile': 'DOMMediaStream.h',
+    'nativeType': 'mozilla::DOMMediaStream'
 },
 {
     'nativeType': 'JSObject',
     'workers': True,
     'skipGen': True
 }],
 
+'LocalMediaStream': {
+    'headerFile': 'DOMMediaStream.h',
+    'nativeType': 'mozilla::DOMLocalMediaStream'
+},
+
 'MediaStreamList': {
     'headerFile': 'MediaStreamList.h',
     'wrapperCache': False,
     'nativeOwnership': 'owned',
     'resultNotAddRefed': [ '__indexedGetter' ],
     'binaryNames': { '__indexedGetter': 'IndexedGetter' }
 },
 
@@ -683,22 +689,24 @@ DOMInterfaces = {
 
 'Performance': {
     'nativeType': 'nsPerformance',
     'resultNotAddRefed': [ 'timing', 'navigation' ]
 },
 
 'PerformanceTiming': {
     'nativeType': 'nsPerformanceTiming',
-    'headerFile': 'nsPerformance.h'
+    'headerFile': 'nsPerformance.h',
+    'nativeOwnership': 'refcounted'
 },
 
 'PerformanceNavigation': {
     'nativeType': 'nsPerformanceNavigation',
-    'headerFile': 'nsPerformance.h'
+    'headerFile': 'nsPerformance.h',
+    'nativeOwnership': 'refcounted'
 },
 
 'ProcessingInstruction': {
     'hasInstanceInterface': 'nsIDOMProcessingInstruction',
 },
 
 'PropertyNodeList': {
     'headerFile': 'HTMLPropertiesCollection.h',
@@ -706,16 +714,17 @@ DOMInterfaces = {
 },
 
 'Rect': {
     "nativeType": "nsDOMCSSRect",
     'resultNotAddRefed': [ "top", "right", "bottom", "left" ]
 },
 
 'RGBColor': {
+    "nativeOwnership": "refcounted",
     "nativeType": "nsDOMCSSRGBColor",
     'resultNotAddRefed': [ "alpha", "blue", "green", "red" ]
 },
 
 'Screen': {
     'nativeType': 'nsScreen',
 },
 
@@ -961,21 +970,25 @@ DOMInterfaces = {
 
 'Text': {
     'nativeType': 'nsTextNode',
     'hasInstanceInterface': 'nsIDOMText',
 },
 
 'TextDecoder': [
 {
+    'nativeOwnership': 'refcounted',
+},
+{
     'workers': True,
 }],
 
 'TextEncoder': [
 {
+    'nativeOwnership': 'refcounted',
     'implicitJSContext': [ 'encode' ],
 },
 {
     'workers': True,
     'implicitJSContext': [ 'encode' ],
 }],
 
 'URL' : [{
--- a/dom/bluetooth/BluetoothService.cpp
+++ b/dom/bluetooth/BluetoothService.cpp
@@ -272,17 +272,17 @@ BluetoothService::~BluetoothService()
 
 PLDHashOperator
 RemoveObserversExceptBluetoothManager
   (const nsAString& key,
    nsAutoPtr<BluetoothSignalObserverList>& value,
    void* arg)
 {
   if (!key.EqualsLiteral("/")) {
-    static_cast<BluetoothService*>(arg)->RemoveObserverFromTable(key);
+    return PL_DHASH_REMOVE;
   }
 
   return PL_DHASH_NEXT;
 }
 
 void
 BluetoothService::RemoveObserverFromTable(const nsAString& key)
 {
@@ -480,17 +480,17 @@ BluetoothService::SetEnabled(bool aEnabl
   if (!aEnabled) {
     /**
      * Remove all handlers except BluetoothManager when turning off bluetooth
      * since it is possible that the event 'onAdapterAdded' would be fired after
      * BluetoothManagers of child process are registered. Please see Bug 827759
      * for more details.
      */
     mBluetoothSignalObserverTable.Enumerate(
-      RemoveObserversExceptBluetoothManager, this);
+      RemoveObserversExceptBluetoothManager, nullptr);
   }
 
   /**
    * mEnabled: real status of bluetooth
    * aEnabled: expected status of bluetooth
    */
   if (mEnabled == aEnabled) {
     NS_WARNING("Bluetooth has already been enabled/disabled before\
--- a/dom/browser-element/BrowserElementChildPreload.js
+++ b/dom/browser-element/BrowserElementChildPreload.js
@@ -636,18 +636,28 @@ BrowserElementChild.prototype = {
         menuObj.items.push(menuitem);
       }
     }
     return menuObj;
   },
 
   _recvSetVisible: function(data) {
     debug("Received setVisible message: (" + data.json.visible + ")");
+    if (this._forcedVisible == data.json.visible) {
+      return;
+    }
+
     this._forcedVisible = data.json.visible;
     this._updateDocShellVisibility();
+
+    // Fire a notification to the ProcessPriorityManager to reset this
+    // process's priority now (as opposed to after a brief delay).
+    var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
+    os.notifyObservers(/* subject */ null, 'process-priority:reset-now',
+                       /* data */ null);
   },
 
   _recvVisible: function(data) {
     sendAsyncMsg('got-visible', {
       id: data.json.id,
       successRv: docShell.isActive
     });
   },
--- a/dom/camera/CameraControlImpl.cpp
+++ b/dom/camera/CameraControlImpl.cpp
@@ -2,16 +2,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 "base/basictypes.h"
 #include "DOMCameraPreview.h"
 #include "CameraRecorderProfiles.h"
 #include "CameraControlImpl.h"
 #include "CameraCommon.h"
+#include "nsGlobalWindow.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::idl;
 
 CameraControlImpl::CameraControlImpl(uint32_t aCameraId, nsIThread* aCameraThread, uint64_t aWindowId)
   : mCameraId(aCameraId)
   , mCameraThread(aCameraThread)
@@ -415,14 +416,17 @@ GetPreviewStreamResult::Run()
   /**
    * The camera preview stream object is DOM-facing, and as such
    * must be a cycle-collection participant created on the main
    * thread.
    */
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsICameraPreviewStreamCallback> onSuccess = mOnSuccessCb.get();
-  if (onSuccess && nsDOMCameraManager::IsWindowStillActive(mWindowId)) {
-    nsCOMPtr<nsIDOMMediaStream> stream = new DOMCameraPreview(mCameraControl, mWidth, mHeight, mWindowId, mFramesPerSecond);
+  nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
+  if (onSuccess && nsDOMCameraManager::IsWindowStillActive(mWindowId) && window) {
+    nsCOMPtr<nsIDOMMediaStream> stream =
+      new DOMCameraPreview(window, mCameraControl, mWidth, mHeight,
+	                         mFramesPerSecond);
     onSuccess->HandleEvent(stream);
   }
   return NS_OK;
 }
--- a/dom/camera/DOMCameraControl.h
+++ b/dom/camera/DOMCameraControl.h
@@ -21,17 +21,19 @@ namespace mozilla {
 // Main camera control.
 class nsDOMCameraControl : public nsICameraControl
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMCameraControl)
   NS_DECL_NSICAMERACONTROL
 
-  nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThread, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, uint64_t aWindowId);
+  nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThread,
+                     nsICameraGetCameraCallback* onSuccess,
+                     nsICameraErrorCallback* onError, uint64_t aWindowId);
   nsresult Result(nsresult aResult, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, uint64_t aWindowId);
 
   void Shutdown();
 
 protected:
   virtual ~nsDOMCameraControl();
 
 private:
--- a/dom/camera/DOMCameraManager.h
+++ b/dom/camera/DOMCameraManager.h
@@ -47,17 +47,17 @@ public:
   void OnNavigation(uint64_t aWindowId);
 
 protected:
   void XpComShutdown();
   void Shutdown(uint64_t aWindowId);
   ~nsDOMCameraManager();
 
 private:
-  nsDOMCameraManager();
+  nsDOMCameraManager() MOZ_DELETE;
   nsDOMCameraManager(uint64_t aWindowId);
   nsDOMCameraManager(const nsDOMCameraManager&) MOZ_DELETE;
   nsDOMCameraManager& operator=(const nsDOMCameraManager&) MOZ_DELETE;
 
 protected:
   uint64_t mWindowId;
   nsCOMPtr<nsIThread> mCameraThread;
   /**
--- a/dom/camera/DOMCameraPreview.cpp
+++ b/dom/camera/DOMCameraPreview.cpp
@@ -135,42 +135,44 @@ public:
     }
   }
 
 protected:
   // Raw pointer; if we exist, 'mDOMPreview' exists as well
   DOMCameraPreview* mDOMPreview;
 };
 
-DOMCameraPreview::DOMCameraPreview(ICameraControl* aCameraControl, uint32_t aWidth, uint32_t aHeight, uint64_t aWindowId, uint32_t aFrameRate)
-  : nsDOMMediaStream()
+DOMCameraPreview::DOMCameraPreview(nsGlobalWindow* aWindow,
+                                   ICameraControl* aCameraControl,
+                                   uint32_t aWidth, uint32_t aHeight,
+                                   uint32_t aFrameRate)
+  : DOMMediaStream()
   , mState(STOPPED)
   , mWidth(aWidth)
   , mHeight(aHeight)
   , mFramesPerSecond(aFrameRate)
   , mFrameCount(0)
   , mCameraControl(aCameraControl)
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p : mWidth=%d, mHeight=%d, mFramesPerSecond=%d\n", __func__, __LINE__, this, mWidth, mHeight, mFramesPerSecond);
 
   mImageContainer = LayerManager::CreateImageContainer();
   MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
   mStream = gm->CreateSourceStream(this);
+  mWindow = aWindow;
   mInput = GetStream()->AsSourceStream();
 
   mListener = new DOMCameraPreviewListener(this);
   mInput->AddListener(mListener);
 
   mInput->AddTrack(TRACK_VIDEO, mFramesPerSecond, 0, new VideoSegment());
   mInput->AdvanceKnownTracksTime(MEDIA_TIME_MAX);
 
-  nsPIDOMWindow *window = static_cast<nsPIDOMWindow*>
-     (nsGlobalWindow::GetInnerWindowWithId(aWindowId));
-  if (window && window->GetExtantDoc()) {
-    this->CombineWithPrincipal(window->GetExtantDoc()->NodePrincipal());
+  if (aWindow->GetExtantDoc()) {
+    CombineWithPrincipal(aWindow->GetExtantDoc()->NodePrincipal());
   }
 }
 
 DOMCameraPreview::~DOMCameraPreview()
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p, mListener=%p\n", __func__, __LINE__, this, mListener);
   mInput->RemoveListener(mListener);
 }
--- a/dom/camera/DOMCameraPreview.h
+++ b/dom/camera/DOMCameraPreview.h
@@ -4,42 +4,43 @@
 
 #ifndef DOM_CAMERA_DOMCAMERAPREVIEW_H
 #define DOM_CAMERA_DOMCAMERAPREVIEW_H
 
 #include "nsCycleCollectionParticipant.h"
 #include "MediaStreamGraph.h"
 #include "StreamBuffer.h"
 #include "ICameraControl.h"
-#include "nsDOMMediaStream.h"
+#include "DOMMediaStream.h"
 #include "CameraCommon.h"
 
+class nsGlobalWindow;
+
 namespace mozilla {
 
 typedef void (*FrameBuilder)(mozilla::layers::Image* aImage, void* aBuffer, uint32_t aWidth, uint32_t aHeight);
 
 /**
  * DOMCameraPreview is only exposed to the DOM as an nsDOMMediaStream,
- * which is a cycle-collection participant already.
+ * which is a cycle-collection participant already, and we don't
+ * add any traceable fields here, so we don't need to declare any
+ * more cycle-collection goop.
  */
-class DOMCameraPreview : public nsDOMMediaStream
+class DOMCameraPreview : public DOMMediaStream
 {
 protected:
   enum { TRACK_VIDEO = 1 };
 
 public:
-  DOMCameraPreview(ICameraControl* aCameraControl, uint32_t aWidth, uint32_t aHeight, uint64_t aWindowId, uint32_t aFramesPerSecond = 30);
+  DOMCameraPreview(nsGlobalWindow* aWindow, ICameraControl* aCameraControl,
+                   uint32_t aWidth, uint32_t aHeight, uint32_t aFramesPerSecond = 30);
+
   bool ReceiveFrame(void* aBuffer, ImageFormat aFormat, mozilla::FrameBuilder aBuilder);
   bool HaveEnoughBuffered();
 
-  NS_IMETHODIMP
-  GetCurrentTime(double* aCurrentTime) {
-    return nsDOMMediaStream::GetCurrentTime(aCurrentTime);
-  }
-
   void Start();   // called by the MediaStreamListener to start preview
   void Started(); // called by the CameraControl when preview is started
   void StopPreview(); // called by the MediaStreamListener to stop preview
   void Stopped(bool aForced = false);
                   // called by the CameraControl when preview is stopped
   void Error();   // something went wrong, NS_RELEASE needed
 
   void SetStateStarted();
--- a/dom/encoding/TextDecoder.cpp
+++ b/dom/encoding/TextDecoder.cpp
@@ -102,19 +102,15 @@ TextDecoderBase::Decode(const char* aInp
 
 void
 TextDecoderBase::GetEncoding(nsAString& aEncoding)
 {
   CopyASCIItoUTF16(mEncoding, aEncoding);
   nsContentUtils::ASCIIToLower(aEncoding);
 }
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(TextDecoder)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(TextDecoder)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextDecoder)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(TextDecoder, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(TextDecoder, Release)
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(TextDecoder, mGlobal)
 
 } // dom
 } // mozilla
--- a/dom/encoding/TextDecoder.h
+++ b/dom/encoding/TextDecoder.h
@@ -7,21 +7,21 @@
 
 #include "mozilla/dom/TextDecoderBase.h"
 #include "mozilla/dom/TextDecoderBinding.h"
 
 namespace mozilla {
 namespace dom {
 
 class TextDecoder MOZ_FINAL
-  : public nsISupports, public nsWrapperCache, public TextDecoderBase
+  : public nsWrapperCache, public TextDecoderBase
 {
 public:
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TextDecoder)
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(TextDecoder)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(TextDecoder)
 
   // The WebIDL constructor.
   static already_AddRefed<TextDecoder>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aEncoding,
               const TextDecoderOptions& aOptions,
               ErrorResult& aRv)
   {
--- a/dom/encoding/TextEncoder.cpp
+++ b/dom/encoding/TextEncoder.cpp
@@ -102,19 +102,15 @@ TextEncoderBase::Encode(JSContext* aCx,
 
 void
 TextEncoderBase::GetEncoding(nsAString& aEncoding)
 {
   CopyASCIItoUTF16(mEncoding, aEncoding);
   nsContentUtils::ASCIIToLower(aEncoding);
 }
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(TextEncoder)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(TextEncoder)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextEncoder)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(TextEncoder, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(TextEncoder, Release)
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(TextEncoder, mGlobal)
 
 } // dom
 } // mozilla
--- a/dom/encoding/TextEncoder.h
+++ b/dom/encoding/TextEncoder.h
@@ -7,21 +7,21 @@
 
 #include "mozilla/dom/TextEncoderBase.h"
 #include "mozilla/dom/TextEncoderBinding.h"
 
 namespace mozilla {
 namespace dom {
 
 class TextEncoder MOZ_FINAL
-  : public nsISupports, public nsWrapperCache, public TextEncoderBase
+  : public nsWrapperCache, public TextEncoderBase
 {
 public:
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TextEncoder)
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(TextEncoder)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(TextEncoder)
 
   // The WebIDL constructor.
   static already_AddRefed<TextEncoder>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aEncoding,
               ErrorResult& aRv)
   {
     nsRefPtr<TextEncoder> txtEncoder = new TextEncoder(aGlobal.Get());
--- a/dom/interfaces/html/nsIMozBrowserFrame.idl
+++ b/dom/interfaces/html/nsIMozBrowserFrame.idl
@@ -26,16 +26,26 @@ interface nsIMozBrowserFrame : nsIDOMMoz
    *
    * In order to really be an app frame, this frame must really be a browser
    * frame (this requirement will go away eventually), and the frame's mozapp
    * attribute must point to the manifest of a valid app.
    */
   [infallible] readonly attribute boolean reallyIsApp;
 
   /**
+   * This corresponds to the expecting-system-message attribute, which tells us
+   * whether we should expect that this frame will receive a system message once
+   * it starts up.
+   *
+   * It's the embedder's job to set this attribute on a frame.  Its presence
+   * might cause us to increase the priority of the frame's process.
+   */
+  [infallible] readonly attribute boolean isExpectingSystemMessage;
+
+  /**
    * Gets this frame's app manifest URL, if the frame really is an app frame.
    * Otherwise, returns the empty string.
    *
    * This method is guaranteed not to fail.
    */
   readonly attribute AString appManifestURL;
 
   /**
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -225,16 +225,49 @@ ConsoleListener::Observe(nsIConsoleMessa
 
     nsXPIDLString msg;
     nsresult rv = aMessage->GetMessageMoz(getter_Copies(msg));
     NS_ENSURE_SUCCESS(rv, rv);
     mChild->SendConsoleMessage(msg);
     return NS_OK;
 }
 
+class SystemMessageHandledObserver MOZ_FINAL : public nsIObserver
+{
+public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIOBSERVER
+
+    void Init();
+};
+
+void SystemMessageHandledObserver::Init()
+{
+    nsCOMPtr<nsIObserverService> os =
+        mozilla::services::GetObserverService();
+
+    if (os) {
+        os->AddObserver(this, "SystemMessageManager:HandleMessageDone",
+                        /* ownsWeak */ false);
+    }
+}
+
+NS_IMETHODIMP
+SystemMessageHandledObserver::Observe(nsISupports* aSubject,
+                                      const char* aTopic,
+                                      const PRUnichar* aData)
+{
+    if (ContentChild::GetSingleton()) {
+        ContentChild::GetSingleton()->SendSystemMessageHandled();
+    }
+    return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS1(SystemMessageHandledObserver, nsIObserver)
+
 ContentChild* ContentChild::sSingleton;
 
 ContentChild::ContentChild()
  : mID(uint64_t(-1))
 #ifdef ANDROID
    ,mScreenSize(0, 0)
 #endif
 {
@@ -342,16 +375,21 @@ ContentChild::InitXPCOM()
         NS_WARNING("Couldn't register console listener for child process");
 
     bool isOffline;
     SendGetXPCOMProcessAttributes(&isOffline);
     RecvSetOffline(isOffline);
 
     DebugOnly<FileUpdateDispatcher*> observer = FileUpdateDispatcher::GetSingleton();
     NS_ASSERTION(observer, "FileUpdateDispatcher is null");
+
+    // This object is held alive by the observer service.
+    nsRefPtr<SystemMessageHandledObserver> sysMsgObserver =
+        new SystemMessageHandledObserver();
+    sysMsgObserver->Init();
 }
 
 PMemoryReportRequestChild*
 ContentChild::AllocPMemoryReportRequest()
 {
     return new MemoryReportRequestChild();
 }
 
@@ -530,21 +568,22 @@ ContentChild::AllocPBrowser(const IPCTab
     static bool hasRunOnce = false;
     if (!hasRunOnce) {
         hasRunOnce = true;
 
         MOZ_ASSERT(!sFirstIdleTask);
         sFirstIdleTask = NewRunnableFunction(FirstIdle);
         MessageLoop::current()->PostIdleTask(FROM_HERE, sFirstIdleTask);
 
-        // If we are the preallocated process transforming into an app process,
-        // we'll have background priority at this point.  Give ourselves a
-        // priority boost for a few seconds, so we don't get killed while we're
-        // loading our first TabChild.
-        TemporarilySetProcessPriorityToForeground();
+        // We are either a brand-new process loading its first PBrowser, or we
+        // are the preallocated process transforming into a particular
+        // app/browser.  Either way, our parent has already set our process
+        // priority, and we want to leave it there for a few seconds while we
+        // start up.
+        TemporarilyLockProcessPriority();
     }
 
     // We'll happily accept any kind of IPCTabContext here; we don't need to
     // check that it's of a certain type for security purposes, because we
     // believe whatever the parent process tells us.
 
     nsRefPtr<TabChild> child = TabChild::Create(TabContext(aContext), aChromeFlags);
 
@@ -1132,9 +1171,9 @@ ContentChild::RecvFileSystemUpdate(const
     unused << aName;
     unused << aState;
     unused << aMountGeneration;
 #endif
     return true;
 }
 
 } // namespace dom
-} // namespace mozilla
\ No newline at end of file
+} // namespace mozilla
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -23,16 +23,17 @@
 #include "IHistory.h"
 #include "IDBFactory.h"
 #include "IndexedDBParent.h"
 #include "IndexedDatabaseManager.h"
 #include "mozIApplication.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/ExternalHelperAppParent.h"
 #include "mozilla/dom/PMemoryReportRequestParent.h"
+#include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/StorageParent.h"
 #include "mozilla/dom/bluetooth/PBluetoothParent.h"
 #include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
 #include "SmsParent.h"
 #include "mozilla/Hal.h"
 #include "mozilla/hal_sandbox/PHalParent.h"
 #include "mozilla/ipc/TestShellParent.h"
 #include "mozilla/layers/CompositorParent.h"
@@ -56,19 +57,21 @@
 #include "nsDOMFile.h"
 #include "nsExternalHelperAppService.h"
 #include "nsFrameMessageManager.h"
 #include "nsHashPropertyBag.h"
 #include "nsIAlertsService.h"
 #include "nsIClipboard.h"
 #include "nsIDOMApplicationRegistry.h"
 #include "nsIDOMGeoGeolocation.h"
+#include "nsIDOMWakeLock.h"
 #include "nsIDOMWindow.h"
 #include "nsIFilePicker.h"
 #include "nsIMemoryReporter.h"
+#include "nsIMozBrowserFrame.h"
 #include "nsIMutable.h"
 #include "nsIObserverService.h"
 #include "nsIPresShell.h"
 #include "nsIRemoteBlob.h"
 #include "nsIScriptError.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIWindowWatcher.h"
@@ -113,18 +116,19 @@ using namespace mozilla::system;
 
 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
 static const char* sClipboardTextFlavors[] = { kUnicodeMime };
 
 using base::ChildPrivileges;
 using base::KillProcess;
 using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::devicestorage;
+using namespace mozilla::dom::indexedDB;
+using namespace mozilla::dom::power;
 using namespace mozilla::dom::sms;
-using namespace mozilla::dom::indexedDB;
 using namespace mozilla::hal;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::net;
 
 namespace mozilla {
 namespace dom {
 
@@ -220,17 +224,18 @@ ContentParent::PreallocateAppProcess()
         sPreallocateAppProcessTask = nullptr;
     }
 
     sPreallocatedAppProcess =
         new ContentParent(MAGIC_PREALLOCATED_APP_MANIFEST_URL,
                           /*isBrowserElement=*/false,
                           // Final privileges are set when we
                           // transform into our app.
-                          base::PRIVILEGES_INHERIT);
+                          base::PRIVILEGES_INHERIT,
+                          PROCESS_PRIORITY_BACKGROUND);
     sPreallocatedAppProcess->Init();
 }
 
 /*static*/ void
 ContentParent::DelayedPreallocateAppProcess()
 {
     sPreallocateAppProcessTask = nullptr;
     if (!sPreallocatedAppProcess) {
@@ -247,29 +252,28 @@ ContentParent::ScheduleDelayedPreallocat
     sPreallocateAppProcessTask =
         NewRunnableFunction(DelayedPreallocateAppProcess);
     MessageLoop::current()->PostDelayedTask(
         FROM_HERE, sPreallocateAppProcessTask, sPreallocateDelayMs);
 }
 
 /*static*/ already_AddRefed<ContentParent>
 ContentParent::MaybeTakePreallocatedAppProcess(const nsAString& aAppManifestURL,
-                                               ChildPrivileges aPrivs)
+                                               ChildPrivileges aPrivs,
+                                               ProcessPriority aInitialPriority)
 {
     nsRefPtr<ContentParent> process = sPreallocatedAppProcess.get();
     sPreallocatedAppProcess = nullptr;
 
     if (!process) {
         return nullptr;
     }
 
-    if (!process->TransformPreallocatedIntoApp(aAppManifestURL, aPrivs)) {
-        NS_WARNING("Can't TransformPrealocatedIntoApp.  Maybe "
-                   "the preallocated process died?");
-
+    if (!process->SetPriorityAndCheckIsAlive(aInitialPriority) ||
+        !process->TransformPreallocatedIntoApp(aAppManifestURL, aPrivs)) {
         // Kill the process just in case it's not actually dead; we don't want
         // to "leak" this process!
         process->KillHard();
         return nullptr;
     }
 
     return process.forget();
 }
@@ -377,17 +381,19 @@ ContentParent::GetNewOrUsed(bool aForBro
         uint32_t idx = rand() % gNonAppContentParents->Length();
         ContentParent* p = (*gNonAppContentParents)[idx];
         NS_ASSERTION(p->IsAlive(), "Non-alive contentparent in gNonAppContentParents?");
         return p;
     }
 
     nsRefPtr<ContentParent> p =
         new ContentParent(/* appManifestURL = */ EmptyString(),
-                          aForBrowserElement);
+                          aForBrowserElement,
+                          base::PRIVILEGES_DEFAULT,
+                          PROCESS_PRIORITY_FOREGROUND);
     p->Init();
     gNonAppContentParents->AppendElement(p);
     return p;
 }
 
 namespace {
 struct SpecialPermission {
     const char* perm;           // an app permission
@@ -414,26 +420,56 @@ PrivilegesForApp(mozIApplication* aApp)
             break;
         } else if (hasPermission) {
             return specialPermissions[i].privs;
         }
     }
     return base::PRIVILEGES_DEFAULT;
 }
 
+/*static*/ ProcessPriority
+ContentParent::GetInitialProcessPriority(nsIDOMElement* aFrameElement)
+{
+    // Frames with mozapptype == critical which are expecting a system message
+    // get FOREGROUND_HIGH priority.  All other frames get FOREGROUND priority.
+
+    if (!aFrameElement) {
+        return PROCESS_PRIORITY_FOREGROUND;
+    }
+
+    nsAutoString appType;
+    nsCOMPtr<Element> frameElement = do_QueryInterface(aFrameElement);
+    frameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::mozapptype, appType);
+    if (appType != NS_LITERAL_STRING("critical")) {
+        return PROCESS_PRIORITY_FOREGROUND;
+    }
+
+    nsCOMPtr<nsIMozBrowserFrame> browserFrame =
+        do_QueryInterface(aFrameElement);
+    if (!browserFrame) {
+        return PROCESS_PRIORITY_FOREGROUND;
+    }
+
+    return browserFrame->GetIsExpectingSystemMessage() ?
+               PROCESS_PRIORITY_FOREGROUND_HIGH :
+               PROCESS_PRIORITY_FOREGROUND;
+}
+
 /*static*/ TabParent*
-ContentParent::CreateBrowserOrApp(const TabContext& aContext)
+ContentParent::CreateBrowserOrApp(const TabContext& aContext,
+                                  nsIDOMElement* aFrameElement)
 {
     if (!sCanLaunchSubprocesses) {
         return nullptr;
     }
 
     if (aContext.IsBrowserElement() || !aContext.HasOwnApp()) {
         if (ContentParent* cp = GetNewOrUsed(aContext.IsBrowserElement())) {
             nsRefPtr<TabParent> tp(new TabParent(aContext));
+            tp->SetOwnerElement(aFrameElement);
             PBrowserParent* browser = cp->SendPBrowserConstructor(
                 tp.forget().get(), // DeallocPBrowserParent() releases this ref.
                 aContext.AsIPCTabContext(),
                 /* chromeFlags */ 0);
             return static_cast<TabParent*>(browser);
         }
         return nullptr;
     }
@@ -451,34 +487,62 @@ ContentParent::CreateBrowserOrApp(const 
 
     // Each app gets its own ContentParent instance.
     nsAutoString manifestURL;
     if (NS_FAILED(ownApp->GetManifestURL(manifestURL))) {
         NS_ERROR("Failed to get manifest URL");
         return nullptr;
     }
 
+    ProcessPriority initialPriority = GetInitialProcessPriority(aFrameElement);
+
     nsRefPtr<ContentParent> p = gAppContentParents->Get(manifestURL);
+    if (p) {
+        // Check that the process is still alive and set its priority.
+        // Hopefully the process won't die after this point, if this call
+        // succeeds.
+        if (!p->SetPriorityAndCheckIsAlive(initialPriority)) {
+            p = nullptr;
+        }
+    }
+
     if (!p) {
         ChildPrivileges privs = PrivilegesForApp(ownApp);
-        p = MaybeTakePreallocatedAppProcess(manifestURL, privs);
+        p = MaybeTakePreallocatedAppProcess(manifestURL, privs,
+                                            initialPriority);
         if (!p) {
             NS_WARNING("Unable to use pre-allocated app process");
             p = new ContentParent(manifestURL, /* isBrowserElement = */ false,
-                                  privs);
+                                  privs, initialPriority);
             p->Init();
         }
         gAppContentParents->Put(manifestURL, p);
     }
 
     nsRefPtr<TabParent> tp = new TabParent(aContext);
+    tp->SetOwnerElement(aFrameElement);
     PBrowserParent* browser = p->SendPBrowserConstructor(
         tp.forget().get(), // DeallocPBrowserParent() releases this ref.
         aContext.AsIPCTabContext(),
         /* chromeFlags */ 0);
+
+    // Send the frame element's mozapptype down to the child process.  This ends
+    // up in TabChild::GetAppType().  We have to do this /before/ we acquire the
+    // CPU wake lock for this process, because if the child sees that it has a
+    // CPU wake lock but its TabChild doesn't have the right mozapptype, it
+    // might downgrade its process priority.
+    nsCOMPtr<Element> frameElement = do_QueryInterface(aFrameElement);
+    if (frameElement) {
+      nsAutoString appType;
+      frameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::mozapptype, appType);
+      unused << browser->SendSetAppType(appType);
+    }
+
+    p->MaybeTakeCPUWakeLock(aFrameElement);
+
     return static_cast<TabParent*>(browser);
 }
 
 static PLDHashOperator
 AppendToTArray(const nsAString& aKey, ContentParent* aValue, void* aArray)
 {
     nsTArray<ContentParent*> *array =
         static_cast<nsTArray<ContentParent*>*>(aArray);
@@ -541,35 +605,166 @@ ContentParent::Init()
         unused << SendActivateA11y();
     }
 #endif
 
     DebugOnly<FileUpdateDispatcher*> observer = FileUpdateDispatcher::GetSingleton();
     NS_ASSERTION(observer, "FileUpdateDispatcher is null");
 }
 
+namespace {
+
+class SystemMessageHandledListener MOZ_FINAL
+    : public nsITimerCallback
+    , public LinkedListElement<SystemMessageHandledListener>
+{
+public:
+    NS_DECL_ISUPPORTS
+
+    SystemMessageHandledListener() {}
+
+    static void OnSystemMessageHandled()
+    {
+        if (!sListeners) {
+            return;
+        }
+
+        SystemMessageHandledListener* listener = sListeners->popFirst();
+        if (!listener) {
+            return;
+        }
+
+        // Careful: ShutDown() may delete |this|.
+        listener->ShutDown();
+    }
+
+    void Init(nsIDOMMozWakeLock* aWakeLock)
+    {
+        MOZ_ASSERT(!mWakeLock);
+        MOZ_ASSERT(!mTimer);
+
+        // mTimer keeps a strong reference to |this|.  When this object's
+        // destructor runs, it will remove itself from the LinkedList.
+
+        if (!sListeners) {
+            sListeners = new LinkedList<SystemMessageHandledListener>();
+            ClearOnShutdown(&sListeners);
+        }
+        sListeners->insertBack(this);
+
+        mWakeLock = aWakeLock;
+
+        mTimer = do_CreateInstance("@mozilla.org/timer;1");
+
+        uint32_t timeoutSec =
+            Preferences::GetInt("dom.ipc.systemMessageCPULockTimeoutSec", 30);
+        mTimer->InitWithCallback(this, timeoutSec * 1000,
+                                 nsITimer::TYPE_ONE_SHOT);
+    }
+
+    NS_IMETHOD Notify(nsITimer* aTimer)
+    {
+        // Careful: ShutDown() may delete |this|.
+        ShutDown();
+        return NS_OK;
+    }
+
+private:
+    static StaticAutoPtr<LinkedList<SystemMessageHandledListener> > sListeners;
+
+    void ShutDown()
+    {
+        nsRefPtr<SystemMessageHandledListener> kungFuDeathGrip = this;
+
+        mWakeLock->Unlock();
+
+        if (mTimer) {
+            mTimer->Cancel();
+            mTimer = nullptr;
+        }
+    }
+
+    nsCOMPtr<nsIDOMMozWakeLock> mWakeLock;
+    nsCOMPtr<nsITimer> mTimer;
+};
+
+StaticAutoPtr<LinkedList<SystemMessageHandledListener> >
+    SystemMessageHandledListener::sListeners;
+
+NS_IMPL_ISUPPORTS1(SystemMessageHandledListener,
+                   nsITimerCallback)
+
+} // anonymous namespace
+
+void
+ContentParent::SetProcessPriority(ProcessPriority aPriority)
+{
+    if (!Preferences::GetBool("dom.ipc.processPriorityManager.enabled")) {
+        return;
+    }
+
+    hal::SetProcessPriority(base::GetProcId(mSubprocess->GetChildProcessHandle()),
+                            aPriority);
+}
+
+void
+ContentParent::MaybeTakeCPUWakeLock(nsIDOMElement* aFrameElement)
+{
+    // Take the CPU wake lock on behalf of this processs if it's expecting a
+    // system message.  We'll release the CPU lock once the message is
+    // delivered, or after some period of time, which ever comes first.
+
+    nsCOMPtr<nsIMozBrowserFrame> browserFrame =
+        do_QueryInterface(aFrameElement);
+    if (!browserFrame ||
+        !browserFrame->GetIsExpectingSystemMessage()) {
+        return;
+    }
+
+    nsRefPtr<PowerManagerService> pms = PowerManagerService::GetInstance();
+    nsCOMPtr<nsIDOMMozWakeLock> lock =
+        pms->NewWakeLockOnBehalfOfProcess(NS_LITERAL_STRING("cpu"), this);
+
+    // This object's Init() function keeps it alive.
+    nsRefPtr<SystemMessageHandledListener> listener =
+        new SystemMessageHandledListener();
+    listener->Init(lock);
+}
+
+bool
+ContentParent::SetPriorityAndCheckIsAlive(ProcessPriority aPriority)
+{
+    SetProcessPriority(aPriority);
+