Merge inbound to mozilla-central. a=merge
authorCiure Andrei <aciure@mozilla.com>
Wed, 09 May 2018 01:58:44 +0300
changeset 474196 0cd106a2eb78aa04fd481785257e6f4f9b94707b
parent 474073 ecbcf736a436b73d67e03b4a8eafe490f9ea7018 (current diff)
parent 474195 b3147109d3af0945ed9783d513b14ffe3d755df3 (diff)
child 474211 35e7f3b5f06cf96a3738eaeba1cffa02eea36fc4
child 474249 db6fbfbb688c44c63ba91b7ff0a140f37d320584
push id1757
push userffxbld-merge
push dateFri, 24 Aug 2018 17:02:43 +0000
treeherdermozilla-release@736023aebdb1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone62.0a1
first release with
nightly linux32
0cd106a2eb78 / 62.0a1 / 20180508231737 / files
nightly linux64
0cd106a2eb78 / 62.0a1 / 20180508231737 / files
nightly mac
0cd106a2eb78 / 62.0a1 / 20180508231737 / files
nightly win32
0cd106a2eb78 / 62.0a1 / 20180508231737 / files
nightly win64
0cd106a2eb78 / 62.0a1 / 20180508231737 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
browser/app/profile/firefox.js
dom/base/nsISelection.idl
dom/base/nsISelectionPrivate.idl
dom/ipc/ContentParent.cpp
layout/painting/nsDisplayList.cpp
modules/freetype2/builds/newline
modules/freetype2/builds/windows/ftver.rc
testing/web-platform/meta/MANIFEST.json
testing/web-platform/meta/dom/events/Event-dispatch-detached-click.html.ini
testing/web-platform/meta/dom/events/Event-dispatch-other-document.html.ini
testing/web-platform/meta/dom/events/EventListener-handleEvent.html.ini
testing/web-platform/meta/fetch/api/cors/cors-expose-star-worker.html.ini
testing/web-platform/meta/fetch/api/cors/cors-expose-star.html.ini
testing/web-platform/meta/fetch/api/cors/cors-multiple-origins-worker.html.ini
testing/web-platform/meta/fetch/api/cors/cors-multiple-origins.html.ini
testing/web-platform/meta/fetch/api/redirect/redirect-location-worker.html.ini
testing/web-platform/meta/fetch/api/redirect/redirect-location.html.ini
testing/web-platform/meta/fetch/api/redirect/redirect-origin-worker.html.ini
testing/web-platform/meta/fetch/api/redirect/redirect-origin.html.ini
testing/web-platform/meta/fetch/api/redirect/redirect-to-dataurl-worker.html.ini
testing/web-platform/meta/fetch/api/redirect/redirect-to-dataurl.html.ini
testing/web-platform/meta/payment-request/PaymentCurrencyAmount/currencySystem-member.https.html.ini
testing/web-platform/meta/webdriver/tests/get_title/user_prompts.py.ini
testing/web-platform/tests/config.default.json
testing/web-platform/tests/fetch/api/cors/cors-expose-star-worker.html
testing/web-platform/tests/fetch/api/cors/cors-expose-star.html
testing/web-platform/tests/fetch/api/cors/cors-expose-star.js
testing/web-platform/tests/fetch/api/cors/cors-multiple-origins-worker.html
testing/web-platform/tests/fetch/api/cors/cors-multiple-origins.html
testing/web-platform/tests/fetch/api/cors/cors-multiple-origins.js
testing/web-platform/tests/fetch/api/redirect/redirect-count-worker.html
testing/web-platform/tests/fetch/api/redirect/redirect-count.html
testing/web-platform/tests/fetch/api/redirect/redirect-count.js
testing/web-platform/tests/fetch/api/redirect/redirect-empty-location-worker.html
testing/web-platform/tests/fetch/api/redirect/redirect-empty-location.html
testing/web-platform/tests/fetch/api/redirect/redirect-empty-location.js
testing/web-platform/tests/fetch/api/redirect/redirect-location-worker.html
testing/web-platform/tests/fetch/api/redirect/redirect-location.html
testing/web-platform/tests/fetch/api/redirect/redirect-location.js
testing/web-platform/tests/fetch/api/redirect/redirect-method-worker.html
testing/web-platform/tests/fetch/api/redirect/redirect-method.html
testing/web-platform/tests/fetch/api/redirect/redirect-method.js
testing/web-platform/tests/fetch/api/redirect/redirect-mode-worker.html
testing/web-platform/tests/fetch/api/redirect/redirect-mode.html
testing/web-platform/tests/fetch/api/redirect/redirect-mode.js
testing/web-platform/tests/fetch/api/redirect/redirect-origin-worker.html
testing/web-platform/tests/fetch/api/redirect/redirect-origin.html
testing/web-platform/tests/fetch/api/redirect/redirect-origin.js
testing/web-platform/tests/fetch/api/redirect/redirect-referrer-worker.html
testing/web-platform/tests/fetch/api/redirect/redirect-referrer.html
testing/web-platform/tests/fetch/api/redirect/redirect-referrer.js
testing/web-platform/tests/fetch/api/redirect/redirect-to-dataurl-worker.html
testing/web-platform/tests/fetch/api/redirect/redirect-to-dataurl.html
testing/web-platform/tests/fetch/api/redirect/redirect-to-dataurl.js
testing/web-platform/tests/html/browsers/origin/.gitkeep
testing/web-platform/tests/html/browsers/origin/relaxing-the-same-origin-restriction/.gitkeep
testing/web-platform/tests/html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter_iframe.html
testing/web-platform/tests/payment-request/PaymentCurrencyAmount/currencySystem-member.https.html
testing/web-platform/tests/tools/sslutils/__init__.py
testing/web-platform/tests/tools/sslutils/base.py
testing/web-platform/tests/tools/sslutils/openssl.py
testing/web-platform/tests/tools/sslutils/pregenerated.py
testing/web-platform/tests/tools/wptrunner/wptrunner/browsers/firefox.py
toolkit/components/telemetry/Scalars.yaml
--- a/accessible/atk/nsMaiInterfaceComponent.cpp
+++ b/accessible/atk/nsMaiInterfaceComponent.cpp
@@ -47,16 +47,56 @@ grabFocusCB(AtkComponent* aComponent)
   ProxyAccessible* proxy = GetProxy(atkObject);
   if (proxy) {
     proxy->TakeFocus();
     return TRUE;
   }
 
   return FALSE;
 }
+
+// ScrollType is compatible
+static gboolean
+scrollToCB(AtkComponent* aComponent, AtkScrollType type)
+{
+  AtkObject* atkObject = ATK_OBJECT(aComponent);
+  AccessibleWrap* accWrap = GetAccessibleWrap(atkObject);
+  if (accWrap) {
+    accWrap->ScrollTo(type);
+    return TRUE;
+  }
+
+  ProxyAccessible* proxy = GetProxy(atkObject);
+  if (proxy) {
+    proxy->ScrollTo(type);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+// CoordType is compatible
+static gboolean
+scrollToPointCB(AtkComponent* aComponent, AtkCoordType coords, gint x, gint y)
+{
+  AtkObject* atkObject = ATK_OBJECT(aComponent);
+  AccessibleWrap* accWrap = GetAccessibleWrap(atkObject);
+  if (accWrap) {
+    accWrap->ScrollToPoint(coords, x, y);
+    return TRUE;
+  }
+
+  ProxyAccessible* proxy = GetProxy(atkObject);
+  if (proxy) {
+    proxy->ScrollToPoint(coords, x, y);
+    return TRUE;
+  }
+
+  return FALSE;
+}
 }
 
 AtkObject*
 refAccessibleAtPointHelper(AtkObject* aAtkObj, gint aX, gint aY,
                            AtkCoordType aCoordType)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
   if (accWrap) {
@@ -144,9 +184,13 @@ componentInterfaceInitCB(AtkComponentIfa
 
   /*
    * Use default implementation in atk for contains, get_position,
    * and get_size
    */
   aIface->ref_accessible_at_point = refAccessibleAtPointCB;
   aIface->get_extents = getExtentsCB;
   aIface->grab_focus = grabFocusCB;
+  if (IsAtkVersionAtLeast(2, 30)) {
+    aIface->scroll_to = scrollToCB;
+    aIface->scroll_to_point = scrollToPointCB;
+  }
 }
--- a/accessible/base/Logging.cpp
+++ b/accessible/base/Logging.cpp
@@ -11,24 +11,25 @@
 #include "DocAccessible.h"
 #include "nsAccessibilityService.h"
 #include "nsCoreUtils.h"
 #include "OuterDocAccessible.h"
 
 #include "nsDocShellLoadTypes.h"
 #include "nsIChannel.h"
 #include "nsIInterfaceRequestorUtils.h"
-#include "nsISelectionPrivate.h"
+#include "nsISelectionController.h"
 #include "nsTraceRefcnt.h"
 #include "nsIWebProgress.h"
 #include "prenv.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIURI.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLBodyElement.h"
+#include "mozilla/dom/Selection.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Logging helpers
 
 static uint32_t sModules = 0;
@@ -585,28 +586,25 @@ void
 logging::FocusDispatched(Accessible* aTarget)
 {
   SubMsgBegin();
   AccessibleNNode("A11y target", aTarget);
   SubMsgEnd();
 }
 
 void
-logging::SelChange(nsISelection* aSelection, DocAccessible* aDocument,
+logging::SelChange(dom::Selection* aSelection, DocAccessible* aDocument,
                    int16_t aReason)
 {
-  nsCOMPtr<nsISelectionPrivate> privSel(do_QueryInterface(aSelection));
-
-  int16_t type = 0;
-  privSel->GetType(&type);
+  SelectionType type = aSelection->GetType();
 
   const char* strType = 0;
-  if (type == nsISelectionController::SELECTION_NORMAL)
+  if (type == SelectionType::eNormal)
     strType = "normal";
-  else if (type == nsISelectionController::SELECTION_SPELLCHECK)
+  else if (type == SelectionType::eSpellCheck)
     strType = "spellcheck";
   else
     strType = "unknown";
 
   bool isIgnored = !aDocument || !aDocument->IsContentLoaded();
   printf("\nSelection changed, selection type: %s, notification %s, reason: %d\n",
          strType, (isIgnored ? "ignored" : "pending"), aReason);
 
--- a/accessible/base/Logging.h
+++ b/accessible/base/Logging.h
@@ -9,21 +9,25 @@
 
 #include "nscore.h"
 #include "nsStringFwd.h"
 #include "mozilla/Attributes.h"
 
 class nsIDocument;
 class nsINode;
 class nsIRequest;
-class nsISelection;
 class nsISupports;
 class nsIWebProgress;
 
 namespace mozilla {
+
+namespace dom {
+class Selection;
+} // namespace dom
+
 namespace a11y {
 
 class AccEvent;
 class Accessible;
 class DocAccessible;
 class OuterDocAccessible;
 
 namespace logging {
@@ -123,17 +127,17 @@ void ActiveWidget(Accessible* aWidget);
 /**
  * Log the focus event was dispatched (submessage).
  */
 void FocusDispatched(Accessible* aTarget);
 
 /**
  * Log the selection change.
  */
-void SelChange(nsISelection* aSelection, DocAccessible* aDocument,
+void SelChange(dom::Selection* aSelection, DocAccessible* aDocument,
                int16_t aReason);
 
 /**
  * Log the given accessible elements info.
  */
 void TreeInfo(const char* aMsg, uint32_t aExtraFlags, ...);
 void TreeInfo(const char* aMsg, uint32_t aExtraFlags,
               const char* aMsg1, Accessible* aAcc,
--- a/accessible/base/MarkupMap.h
+++ b/accessible/base/MarkupMap.h
@@ -319,25 +319,92 @@ MARKUPMAP(q,
 MARKUPMAP(section,
           New_HyperText,
           roles::SECTION)
 
 MARKUPMAP(summary,
           New_HTMLSummary,
           roles::SUMMARY)
 
+MARKUPMAP(
+  table,
+  [](Element* aElement, Accessible* aContext) -> Accessible* {
+     if (aElement->GetPrimaryFrame()->AccessibleType() != eHTMLTableType) {
+       return new ARIAGridAccessible(aElement, aContext->Document());
+     }
+     return nullptr;
+  },
+  0
+)
+
 MARKUPMAP(time,
           New_HyperText,
           0,
           Attr(xmlroles, time),
           AttrFromDOM(datetime, datetime))
 
-MARKUPMAP(td,
-          New_HTMLTableHeaderCellIfScope,
-          0)
+MARKUPMAP(
+  td,
+  [](Element* aElement, Accessible* aContext) -> Accessible* {
+     if (aContext->IsTableRow() && aContext->GetContent() == aElement->GetParent()) {
+       // If HTML:td element is part of its HTML:table, which has CSS
+       // display style other than 'table', then create a generic table cell
+       // accessible, because there's no underlying table layout and thus native
+       // HTML table cell class doesn't work.
+       if (!aContext->IsHTMLTableRow()) {
+         return new ARIAGridCellAccessible(aElement, aContext->Document());
+       }
+       if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::scope)) {
+         return new HTMLTableHeaderCellAccessibleWrap(aElement, aContext->Document());
+       }
+     }
+     return nullptr;
+  },
+  0
+)
 
-MARKUPMAP(th,
-          New_HTMLTableHeaderCell,
-          0)
+MARKUPMAP(
+  th,
+  [](Element* aElement, Accessible* aContext) -> Accessible* {
+     if (aContext->IsTableRow() && aContext->GetContent() == aElement->GetParent()) {
+       if (!aContext->IsHTMLTableRow()) {
+         return new ARIAGridCellAccessible(aElement, aContext->Document());
+       }
+       return new HTMLTableHeaderCellAccessibleWrap(aElement, aContext->Document());
+     }
+     return nullptr;
+  },
+  0
+)
+
+MARKUPMAP(
+  tr,
+  [](Element* aElement, Accessible* aContext) -> Accessible* {
+     // If HTML:tr element is part of its HTML:table, which has CSS
+     // display style other than 'table', then create a generic table row
+     // accessible, because there's no underlying table layout and thus native
+     // HTML table row class doesn't work. Refer to
+     // CreateAccessibleByFrameType dual logic.
+     Accessible* table = aContext->IsTable() ? aContext : nullptr;
+     if (!table && aContext->Parent() && aContext->Parent()->IsTable()) {
+        table = aContext->Parent();
+     }
+     if (table) {
+        nsIContent* parentContent = aElement->GetParent();
+        nsIFrame* parentFrame = parentContent->GetPrimaryFrame();
+        if (!parentFrame->IsTableWrapperFrame()) {
+          parentContent = parentContent->GetParent();
+          parentFrame = parentContent->GetPrimaryFrame();
+          if (table->GetContent() == parentContent &&
+              (!parentFrame->IsTableWrapperFrame() ||
+               aElement->GetPrimaryFrame()->AccessibleType() != eHTMLTableRowType)) {
+            return new ARIARowAccessible(aElement, aContext->Document());
+          }
+        }
+      }
+      return nullptr;
+  },
+  0
+)
 
 MARKUPMAP(ul,
           New_HTMLList,
           roles::LIST)
--- a/accessible/base/SelectionManager.cpp
+++ b/accessible/base/SelectionManager.cpp
@@ -10,17 +10,17 @@
 #include "HyperTextAccessible-inl.h"
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "nsEventShell.h"
 #include "nsFrameSelection.h"
 
 #include "nsIAccessibleTypes.h"
-#include "nsIDOMDocument.h"
+#include "nsIDocument.h"
 #include "nsIPresShell.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 using mozilla::dom::Selection;
 
@@ -43,29 +43,26 @@ SelectionManager::SelectionManager() :
   mCaretOffset(-1), mAccWithCaret(nullptr)
 {
 
 }
 
 void
 SelectionManager::ClearControlSelectionListener()
 {
-
   // Remove 'this' registered as selection listener for the normal selection.
-  nsCOMPtr<nsISelection> normalSel = do_QueryReferent(mCurrCtrlNormalSel);
-  if (normalSel) {
-    normalSel->AsSelection()->RemoveSelectionListener(this);
+  if (mCurrCtrlNormalSel) {
+    mCurrCtrlNormalSel->RemoveSelectionListener(this);
     mCurrCtrlNormalSel = nullptr;
   }
 
   // Remove 'this' registered as selection listener for the spellcheck
   // selection.
-  nsCOMPtr<nsISelection> spellSel = do_QueryReferent(mCurrCtrlSpellSel);
-  if (spellSel) {
-    spellSel->AsSelection()->RemoveSelectionListener(this);
+  if (mCurrCtrlSpellSel) {
+    mCurrCtrlSpellSel->RemoveSelectionListener(this);
     mCurrCtrlSpellSel = nullptr;
   }
 }
 
 void
 SelectionManager::SetControlSelectionListener(dom::Element* aFocusedElm)
 {
   // When focus moves such that the caret is part of a new frame selection
@@ -78,24 +75,24 @@ SelectionManager::SetControlSelectionLis
     return;
 
   const nsFrameSelection* frameSel = controlFrame->GetConstFrameSelection();
   NS_ASSERTION(frameSel, "No frame selection for focused element!");
   if (!frameSel)
     return;
 
   // Register 'this' as selection listener for the normal selection.
-  nsCOMPtr<nsISelection> normalSel = frameSel->GetSelection(SelectionType::eNormal);
-  normalSel->AsSelection()->AddSelectionListener(this);
-  mCurrCtrlNormalSel = do_GetWeakReference(normalSel);
+  Selection* normalSel = frameSel->GetSelection(SelectionType::eNormal);
+  normalSel->AddSelectionListener(this);
+  mCurrCtrlNormalSel = normalSel;
 
   // Register 'this' as selection listener for the spell check selection.
-  nsCOMPtr<nsISelection> spellSel = frameSel->GetSelection(SelectionType::eSpellCheck);
-  spellSel->AsSelection()->AddSelectionListener(this);
-  mCurrCtrlSpellSel = do_GetWeakReference(spellSel);
+  Selection* spellSel = frameSel->GetSelection(SelectionType::eSpellCheck);
+  spellSel->AddSelectionListener(this);
+  mCurrCtrlSpellSel = spellSel;
 }
 
 void
 SelectionManager::AddDocSelectionListener(nsIPresShell* aPresShell)
 {
   const nsFrameSelection* frameSel = aPresShell->ConstFrameSelection();
 
   // Register 'this' as selection listener for the normal selection.
@@ -157,38 +154,36 @@ SelectionManager::ProcessTextSelChangeEv
   if (mCaretOffset != -1) {
     RefPtr<AccCaretMoveEvent> caretMoveEvent =
       new AccCaretMoveEvent(caretCntr, mCaretOffset, aEvent->FromUserInput());
     nsEventShell::FireEvent(caretMoveEvent);
   }
 }
 
 NS_IMETHODIMP
-SelectionManager::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
-                                         nsISelection* aSelection,
+SelectionManager::NotifySelectionChanged(nsIDocument* aDocument,
+                                         Selection* aSelection,
                                          int16_t aReason)
 {
-  if (NS_WARN_IF(!aDOMDocument) || NS_WARN_IF(!aSelection)) {
+  if (NS_WARN_IF(!aDocument) || NS_WARN_IF(!aSelection)) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  nsCOMPtr<nsIDocument> documentNode(do_QueryInterface(aDOMDocument));
-  DocAccessible* document = GetAccService()->GetDocAccessible(documentNode);
+  DocAccessible* document = GetAccService()->GetDocAccessible(aDocument);
 
 #ifdef A11Y_LOG
   if (logging::IsEnabled(logging::eSelection))
     logging::SelChange(aSelection, document, aReason);
 #endif
 
   if (document) {
     // Selection manager has longer lifetime than any document accessible,
     // so that we are guaranteed that the notification is processed before
     // the selection manager is destroyed.
-    RefPtr<SelData> selData =
-      new SelData(aSelection->AsSelection(), aReason);
+    RefPtr<SelData> selData = new SelData(aSelection, aReason);
     document->HandleNotification<SelectionManager, SelData>
       (this, &SelectionManager::ProcessSelectionChanged, selData);
   }
 
   return NS_OK;
 }
 
 void
--- a/accessible/base/SelectionManager.h
+++ b/accessible/base/SelectionManager.h
@@ -3,23 +3,25 @@
  * 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_a11y_SelectionManager_h__
 #define mozilla_a11y_SelectionManager_h__
 
 #include "nsIFrame.h"
 #include "nsISelectionListener.h"
+#include "mozilla/WeakPtr.h"
 
 class nsIPresShell;
 
 namespace mozilla {
 
 namespace dom {
 class Element;
+class Selection;
 }
 
 namespace a11y {
 
 class AccEvent;
 class HyperTextAccessible;
 
 /**
@@ -118,16 +120,16 @@ protected:
    * Process DOM selection change. Fire selection and caret move events.
    */
   void ProcessSelectionChanged(SelData* aSelData);
 
 private:
   // Currently focused control.
   int32_t mCaretOffset;
   HyperTextAccessible* mAccWithCaret;
-  nsWeakPtr mCurrCtrlNormalSel;
-  nsWeakPtr mCurrCtrlSpellSel;
+  WeakPtr<dom::Selection> mCurrCtrlNormalSel;
+  WeakPtr<dom::Selection> mCurrCtrlSpellSel;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -268,33 +268,16 @@ New_HTMLTableAccessible(Element* aElemen
 static Accessible*
 New_HTMLTableRowAccessible(Element* aElement, Accessible* aContext)
   { return new HTMLTableRowAccessible(aElement, aContext->Document()); }
 
 static Accessible*
 New_HTMLTableCellAccessible(Element* aElement, Accessible* aContext)
   { return new HTMLTableCellAccessible(aElement, aContext->Document()); }
 
-static Accessible*
-New_HTMLTableHeaderCell(Element* aElement, Accessible* aContext)
-{
-  if (aContext->IsTableRow() && aContext->GetContent() == aElement->GetParent())
-    return new HTMLTableHeaderCellAccessibleWrap(aElement, aContext->Document());
-  return nullptr;
-}
-
-static Accessible*
-New_HTMLTableHeaderCellIfScope(Element* aElement, Accessible* aContext)
-{
-  if (aContext->IsTableRow() && aContext->GetContent() == aElement->GetParent() &&
-      aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::scope))
-    return new HTMLTableHeaderCellAccessibleWrap(aElement, aContext->Document());
-  return nullptr;
-}
-
 /**
  * Cached value of the PREF_ACCESSIBILITY_FORCE_DISABLED preference.
  */
 static int32_t sPlatformDisabledState = 0;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Markup maps array.
 
--- a/accessible/base/nsCoreUtils.cpp
+++ b/accessible/base/nsCoreUtils.cpp
@@ -14,17 +14,16 @@
 #include "nsIBoxObject.h"
 #include "nsXULElement.h"
 #include "mozilla/dom/BoxObject.h"
 #include "nsIDocShell.h"
 #include "nsIObserverService.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsIScrollableFrame.h"
-#include "nsISelectionPrivate.h"
 #include "nsISelectionController.h"
 #include "nsISimpleEnumerator.h"
 #include "mozilla/dom/TouchEvent.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TouchEvents.h"
@@ -264,27 +263,26 @@ nsCoreUtils::ScrollSubstringTo(nsIFrame*
 
   nsPresContext *presContext = aFrame->PresContext();
 
   nsCOMPtr<nsISelectionController> selCon;
   aFrame->GetSelectionController(presContext, getter_AddRefs(selCon));
   NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
 
   RefPtr<dom::Selection> selection =
-    selCon->GetDOMSelection(nsISelectionController::SELECTION_ACCESSIBILITY);
+    selCon->GetSelection(nsISelectionController::SELECTION_ACCESSIBILITY);
 
-  nsCOMPtr<nsISelectionPrivate> privSel(do_QueryObject(selection));
   selection->RemoveAllRanges(IgnoreErrors());
   selection->AddRange(*aRange, IgnoreErrors());
 
-  privSel->ScrollIntoViewInternal(
-    nsISelectionController::SELECTION_ANCHOR_REGION,
-    true, aVertical, aHorizontal);
+  selection->ScrollIntoView(nsISelectionController::SELECTION_ANCHOR_REGION,
+                            aVertical, aHorizontal,
+                            Selection::SCROLL_SYNCHRONOUS);
 
-  selection->CollapseToStart();
+  selection->CollapseToStart(IgnoreErrors());
 
   return NS_OK;
 }
 
 void
 nsCoreUtils::ScrollFrameToPoint(nsIFrame *aScrollableFrame,
                                 nsIFrame *aFrame,
                                 const nsIntPoint& aPoint)
--- a/accessible/generic/ARIAGridAccessible.cpp
+++ b/accessible/generic/ARIAGridAccessible.cpp
@@ -25,16 +25,24 @@ using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Constructor
 
 ARIAGridAccessible::
   ARIAGridAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   AccessibleWrap(aContent, aDoc)
 {
+  mGenericTypes |= eTable;
+}
+
+role
+ARIAGridAccessible::NativeRole()
+{
+  a11y::role r = GetAccService()->MarkupRole(mContent);
+  return r != roles::NOTHING ? r : roles::TABLE;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Table
 
 uint32_t
 ARIAGridAccessible::ColCount()
 {
@@ -536,16 +544,23 @@ ARIAGridAccessible::SetARIASelected(Acce
 
 ARIARowAccessible::
   ARIARowAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   AccessibleWrap(aContent, aDoc)
 {
   mGenericTypes |= eTableRow;
 }
 
+role
+ARIARowAccessible::NativeRole()
+{
+  a11y::role r = GetAccService()->MarkupRole(mContent);
+  return r != roles::NOTHING ? r : roles::ROW;
+}
+
 GroupPos
 ARIARowAccessible::GroupPosition()
 {
   int32_t count = 0, index = 0;
   Accessible* table = nsAccUtils::TableFor(this);
   if (table && nsCoreUtils::GetUIntAttr(table->GetContent(),
                                         nsGkAtoms::aria_rowcount, &count) &&
       nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_rowindex, &index)) {
@@ -566,16 +581,23 @@ ARIARowAccessible::GroupPosition()
 
 ARIAGridCellAccessible::
   ARIAGridCellAccessible(nsIContent* aContent, DocAccessible* aDoc) :
   HyperTextAccessibleWrap(aContent, aDoc)
 {
   mGenericTypes |= eTableCell;
 }
 
+role
+ARIAGridCellAccessible::NativeRole()
+{
+  a11y::role r = GetAccService()->MarkupRole(mContent);
+  return r != roles::NOTHING ? r : roles::CELL;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // TableCell
 
 TableAccessible*
 ARIAGridCellAccessible::Table() const
 {
   Accessible* table = nsAccUtils::TableFor(Row());
   return table ? table->AsTable() : nullptr;
--- a/accessible/generic/ARIAGridAccessible.h
+++ b/accessible/generic/ARIAGridAccessible.h
@@ -20,16 +20,17 @@ class ARIAGridAccessible : public Access
                            public TableAccessible
 {
 public:
   ARIAGridAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   NS_INLINE_DECL_REFCOUNTING_INHERITED(ARIAGridAccessible, AccessibleWrap)
 
   // Accessible
+  virtual a11y::role NativeRole() override;
   virtual TableAccessible* AsTable() override { return this; }
 
   // TableAccessible
   virtual uint32_t ColCount() override;
   virtual uint32_t RowCount() override;
   virtual Accessible* CellAt(uint32_t aRowIndex, uint32_t aColumnIndex) override;
   virtual bool IsColSelected(uint32_t aColIdx) override;
   virtual bool IsRowSelected(uint32_t aRowIdx) override;
@@ -79,16 +80,17 @@ protected:
 class ARIARowAccessible : public AccessibleWrap
 {
 public:
   ARIARowAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   NS_INLINE_DECL_REFCOUNTING_INHERITED(ARIARowAccessible, AccessibleWrap)
 
   // Accessible
+  virtual a11y::role NativeRole() override;
   virtual mozilla::a11y::GroupPos GroupPosition() override;
 
 protected:
   virtual ~ARIARowAccessible() {}
 };
 
 
 /**
@@ -99,16 +101,17 @@ class ARIAGridCellAccessible : public Hy
 {
 public:
   ARIAGridCellAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   NS_INLINE_DECL_REFCOUNTING_INHERITED(ARIAGridCellAccessible,
                                        HyperTextAccessibleWrap)
 
   // Accessible
+  virtual a11y::role NativeRole() override;
   virtual TableCellAccessible* AsTableCell() override { return this; }
   virtual void ApplyARIAState(uint64_t* aState) const override;
   virtual already_AddRefed<nsIPersistentProperties> NativeAttributes() override;
   virtual mozilla::a11y::GroupPos GroupPosition() override;
 
 protected:
   virtual ~ARIAGridCellAccessible() {}
 
--- a/accessible/html/HTMLTableAccessible.cpp
+++ b/accessible/html/HTMLTableAccessible.cpp
@@ -14,17 +14,16 @@
 #include "nsTextEquivUtils.h"
 #include "Relation.h"
 #include "Role.h"
 #include "States.h"
 #include "TreeWalker.h"
 
 #include "mozilla/dom/HTMLTableElement.h"
 #include "nsIDOMRange.h"
-#include "nsISelectionPrivate.h"
 #include "nsIHTMLCollection.h"
 #include "nsIDocument.h"
 #include "nsIMutableArray.h"
 #include "nsIPersistentProperties2.h"
 #include "nsIPresShell.h"
 #include "nsITableCellLayout.h"
 #include "nsFrameSelection.h"
 #include "nsError.h"
@@ -729,58 +728,50 @@ HTMLTableAccessible::IsCellSelected(uint
   nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(aRowIdx, aColIdx);
   return cellFrame ? cellFrame->IsSelected() : false;
 }
 
 void
 HTMLTableAccessible::SelectRow(uint32_t aRowIdx)
 {
   DebugOnly<nsresult> rv =
-    RemoveRowsOrColumnsFromSelection(aRowIdx,
-                                     nsISelectionPrivate::TABLESELECTION_ROW,
-                                     true);
+    RemoveRowsOrColumnsFromSelection(aRowIdx, TableSelection::Row, true);
   NS_ASSERTION(NS_SUCCEEDED(rv),
                "RemoveRowsOrColumnsFromSelection() Shouldn't fail!");
 
-  AddRowOrColumnToSelection(aRowIdx, nsISelectionPrivate::TABLESELECTION_ROW);
+  AddRowOrColumnToSelection(aRowIdx, TableSelection::Row);
 }
 
 void
 HTMLTableAccessible::SelectCol(uint32_t aColIdx)
 {
   DebugOnly<nsresult> rv =
-    RemoveRowsOrColumnsFromSelection(aColIdx,
-                                     nsISelectionPrivate::TABLESELECTION_COLUMN,
-                                     true);
+    RemoveRowsOrColumnsFromSelection(aColIdx, TableSelection::Column, true);
   NS_ASSERTION(NS_SUCCEEDED(rv),
                "RemoveRowsOrColumnsFromSelection() Shouldn't fail!");
 
-  AddRowOrColumnToSelection(aColIdx, nsISelectionPrivate::TABLESELECTION_COLUMN);
+  AddRowOrColumnToSelection(aColIdx, TableSelection::Column);
 }
 
 void
 HTMLTableAccessible::UnselectRow(uint32_t aRowIdx)
 {
-  RemoveRowsOrColumnsFromSelection(aRowIdx,
-                                   nsISelectionPrivate::TABLESELECTION_ROW,
-                                   false);
+  RemoveRowsOrColumnsFromSelection(aRowIdx, TableSelection::Row, false);
 }
 
 void
 HTMLTableAccessible::UnselectCol(uint32_t aColIdx)
 {
-  RemoveRowsOrColumnsFromSelection(aColIdx,
-                                   nsISelectionPrivate::TABLESELECTION_COLUMN,
-                                   false);
+  RemoveRowsOrColumnsFromSelection(aColIdx, TableSelection::Column, false);
 }
 
 nsresult
-HTMLTableAccessible::AddRowOrColumnToSelection(int32_t aIndex, uint32_t aTarget)
+HTMLTableAccessible::AddRowOrColumnToSelection(int32_t aIndex, TableSelection aTarget)
 {
-  bool doSelectRow = (aTarget == nsISelectionPrivate::TABLESELECTION_ROW);
+  bool doSelectRow = (aTarget == TableSelection::Row);
 
   nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
   if (!tableFrame)
     return NS_OK;
 
   uint32_t count = 0;
   if (doSelectRow)
     count = ColCount();
@@ -801,28 +792,28 @@ HTMLTableAccessible::AddRowOrColumnToSel
     }
   }
 
   return NS_OK;
 }
 
 nsresult
 HTMLTableAccessible::RemoveRowsOrColumnsFromSelection(int32_t aIndex,
-                                                      uint32_t aTarget,
+                                                      TableSelection aTarget,
                                                       bool aIsOuter)
 {
   nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
   if (!tableFrame)
     return NS_OK;
 
   nsIPresShell* presShell(mDoc->PresShell());
   RefPtr<nsFrameSelection> tableSelection =
     const_cast<nsFrameSelection*>(presShell->ConstFrameSelection());
 
-  bool doUnselectRow = (aTarget == nsISelectionPrivate::TABLESELECTION_ROW);
+  bool doUnselectRow = (aTarget == TableSelection::Row);
   uint32_t count = doUnselectRow ? ColCount() : RowCount();
 
   int32_t startRowIdx = doUnselectRow ? aIndex : 0;
   int32_t endRowIdx = doUnselectRow ? aIndex : count - 1;
   int32_t startColIdx = doUnselectRow ? 0 : aIndex;
   int32_t endColIdx = doUnselectRow ? count - 1 : aIndex;
 
   if (aIsOuter)
--- a/accessible/html/HTMLTableAccessible.h
+++ b/accessible/html/HTMLTableAccessible.h
@@ -9,16 +9,19 @@
 #include "HyperTextAccessibleWrap.h"
 #include "TableAccessible.h"
 #include "TableCellAccessible.h"
 
 class nsITableCellLayout;
 class nsTableCellFrame;
 
 namespace mozilla {
+
+enum class TableSelection : uint32_t;
+
 namespace a11y {
 
 /**
  * HTML table cell accessible (html:td).
  */
 class HTMLTableCellAccessible : public HyperTextAccessibleWrap,
                                 public TableCellAccessible
 {
@@ -174,31 +177,31 @@ protected:
 
   // HTMLTableAccessible
 
   /**
    * Add row or column to selection.
    *
    * @param aIndex   [in] index of row or column to be selected
    * @param aTarget  [in] indicates what should be selected, either row or column
-   *                  (see nsISelectionPrivate)
+   *                  (see nsFrameSelection)
    */
-  nsresult AddRowOrColumnToSelection(int32_t aIndex, uint32_t aTarget);
+  nsresult AddRowOrColumnToSelection(int32_t aIndex, TableSelection aTarget);
 
   /**
    * Removes rows or columns at the given index or outside it from selection.
    *
    * @param  aIndex    [in] row or column index
    * @param  aTarget   [in] indicates whether row or column should unselected
    * @param  aIsOuter  [in] indicates whether all rows or column excepting
    *                    the given one should be unselected or the given one
    *                    should be unselected only
    */
   nsresult RemoveRowsOrColumnsFromSelection(int32_t aIndex,
-                                            uint32_t aTarget,
+                                            TableSelection aTarget,
                                             bool aIsOuter);
 
   /**
    * Return true if table has an element with the given tag name.
    *
    * @param  aTagName     [in] tag name of searched element
    * @param  aAllowEmpty  [in, optional] points if found element can be empty
    *                       or contain whitespace text only.
--- a/accessible/tests/mochitest/tree/a11y.ini
+++ b/accessible/tests/mochitest/tree/a11y.ini
@@ -42,12 +42,14 @@ skip-if = buildapp == "mulet"
 [test_map.html]
 [test_media.html]
 skip-if = buildapp == "mulet"
 [test_select.html]
 [test_tabbox.xul]
 [test_tabbrowser.xul]
 skip-if = (os == 'linux' && debug) || (os == 'win' && ccov) # Bug 1389365 || bug 1423218
 [test_table.html]
+[test_table_2.html]
+[test_table_3.html]
 [test_tree.xul]
 [test_txtcntr.html]
 [test_txtctrl.html]
 [test_txtctrl.xul]
--- a/accessible/tests/mochitest/tree/test_aria_grid.html
+++ b/accessible/tests/mochitest/tree/test_aria_grid.html
@@ -69,18 +69,18 @@
 
       accTree = {
         role: ROLE_TABLE,
         children: [
           { // tr@role="row"
             role: ROLE_ROW,
             tagName: "TR",
             children: [
-              { // td generic accessible
-                role: ROLE_TEXT_CONTAINER,
+              { // td generic cell accessible
+                role: ROLE_CELL,
                 children: [
                   { // td text leaf
                     role: ROLE_TEXT_LEAF,
                     name: "cell1",
                     children: [ ]
                   }
                 ]
               },
--- a/accessible/tests/mochitest/tree/test_brokencontext.html
+++ b/accessible/tests/mochitest/tree/test_brokencontext.html
@@ -48,34 +48,16 @@
             ] },
             { NOTHING: [ // td
               { TEXT_LEAF: [ ] }
             ] }
           ] }
       ] };
     testAccessibleTree("button_table", tree);
 
-    // HTML table display:inline
-    checkIfNotAccessible("inline_table1");
-    checkIfNotAccessible("tr_in_inline_table1");
-    checkIfTDGeneric("td1_in_inline_table1");
-    checkIfTDGeneric("td2_in_inline_table1");
-
-    // HTML table display:inline inside table. We shouldn't be fooled
-    // by the outside table and shouldn't create table accessible and table cell
-    // accessible in this case.
-    checkIfNotAccessible("inline_table2");
-    checkIfNotAccessible("tr_in_inline_table2");
-    checkIfTDGeneric("td_in_inline_table2");
-
-    // HTML table display:block inside table.
-    checkIfNotAccessible("block_table");
-    checkIfNotAccessible("tr_in_block_table");
-    checkIfTDGeneric("td_in_block_table");
-
     // //////////////////////////////////////////////////////////////////////////
     // HTML list elements outside list context.
 
     ok(!isAccessible("presentation_ul"),
                      "presentational ul shouldn't be accessible");
     ok(isAccessible("item_in_presentation_ul"),
                     "li in presentational ul should have generic accessible");
     ok(isAccessible("styleditem_in_presentation_ul"),
@@ -185,44 +167,16 @@
 
   <table role="button" id="button_table">
     <tr id="tr_in_button_table">
       <th id="th_in_button_table">not a header</th>
       <td id="td_in_button_table">not a cell</td>
     </tr>
   </table>
 
-   <table id="inline_table1" border="1" style="display:inline">
-    <tr id="tr_in_inline_table1">
-     <td id="td1_in_inline_table1">table1 cell1</td>
-     <td id="td2_in_inline_table1">table1 cell2</td>
-    </tr>
-   </table>
-
-   <table id="table_containing_inlinetable"><tr><td>
-     <table id="inline_table2" border="1" style="display:inline">
-      <tr id="tr_in_inline_table2">
-       <td id="td_in_inline_table2">cell</td>
-      </tr>
-     </table>
-   </td></tr></table>
-
-  <table>
-    <tr>
-      <td style="display:block">
-        <table id="block_table" style="display:inline">
-          <tr id="tr_in_block_table">
-            <td id="td_in_block_table">cell0</td>
-          </tr>
-        </table>
-      </td>
-      <td>cell1</td>
-   </tr>
-  </table>
-
   <!-- HTML list elements out of list -->
   <ul role="presentation" id="presentation_ul">
     <li id="item_in_presentation_ul">item</li>
     <span id="styleditem_in_presentation_ul"
           style="display:list-item">Oranges</span>
   </ul>
 
   <ol role="presentation" id="presentation_ol">
--- a/accessible/tests/mochitest/tree/test_table.html
+++ b/accessible/tests/mochitest/tree/test_table.html
@@ -168,16 +168,61 @@
           { ROW: [
             { CELL: [
               { TEXT_LEAF: [ ] }
             ] }
           ] }
         ] };
       testAccessibleTree("logtable", accTree);
 
+      // ///////////////////////////////////////////////////////////////////////
+      // display:block table
+      accTree =
+        { TABLE: [
+          { ROW: [
+            { CELL: [
+              { TEXT_LEAF: [ ] }
+            ] }
+          ] }
+        ] };
+      testAccessibleTree("block_table", accTree);
+
+      // ///////////////////////////////////////////////////////////////////////
+      // display:inline table
+      accTree =
+        { TABLE: [
+          { ROW: [
+            { CELL: [
+              { TEXT_LEAF: [ ] }
+            ] },
+            { CELL: [
+              { TEXT_LEAF: [ ] }
+            ] }
+          ] }
+        ] };
+      testAccessibleTree("inline_table1", accTree);
+
+      // ///////////////////////////////////////////////////////////////////////
+      // display:inline table
+      accTree =
+        { TABLE: [
+          { ROW: [
+            { CELL: [
+              { TABLE: [
+                { ROW: [
+                  { CELL: [
+                    { TEXT_LEAF: [ ] }
+                  ] }
+                ] }
+              ] },
+            ] }
+          ] }
+        ] };
+      testAccessibleTree("table_containing_inlinetable", accTree);
+
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 <body>
@@ -272,10 +317,31 @@
     <tbody style="display:block;overflow:auto;">
       <tr>
         <td>bla</td>
       </tr>
     </tbody>
   </table>
 
   <table id="logtable" role="log"><tr><td>blah</td></tr></table>
+
+  <table id="block_table" style="display: block;">
+    <tr>
+      <td>bla</td>
+    </tr>
+  </table>
+
+  <table id="inline_table1" border="1" style="display:inline">
+    <tr>
+     <td>table1 cell1</td>
+     <td>table1 cell2</td>
+    </tr>
+   </table>
+
+   <table id="table_containing_inlinetable"><tr><td>
+     <table id="inline_table2" border="1" style="display:inline">
+       <tr id="tr_in_inline_table2">
+         <td id="td_in_inline_table2">cell</td>
+       </tr>
+     </table>
+   </td></tr></table>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/tree/test_table_2.html
@@ -0,0 +1,241 @@
+<!DOCTYPE HTML PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<link rel="stylesheet" type="text/css"
+      href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+<style>
+.responsive-table {
+  width: 100%;
+  margin-bottom: 1.5em;
+}
+.responsive-table thead {
+  position: absolute;
+  clip: rect(1px 1px 1px 1px);
+  /* IE6, IE7 */
+  clip: rect(1px, 1px, 1px, 1px);
+  padding: 0;
+  border: 0;
+  height: 1px;
+  width: 1px;
+  overflow: hidden;
+}
+.responsive-table thead th {
+  background-color: #1d96b2;
+  border: 1px solid #1d96b2;
+  font-weight: normal;
+  text-align: center;
+  color: white;
+}
+.responsive-table thead th:first-of-type {
+  text-align: left;
+}
+.responsive-table tbody,
+.responsive-table tr,
+.responsive-table th,
+.responsive-table td {
+  display: block;
+  padding: 0;
+  text-align: left;
+  white-space: normal;
+}
+.responsive-table th,
+.responsive-table td {
+  padding: .5em;
+  vertical-align: middle;
+}
+.responsive-table caption {
+  margin-bottom: 1em;
+  font-size: 1em;
+  font-weight: bold;
+  text-align: center;
+}
+.responsive-table tfoot {
+  font-size: .8em;
+  font-style: italic;
+}
+.responsive-table tbody tr {
+  margin-bottom: 1em;
+  border: 2px solid #1d96b2;
+}
+.responsive-table tbody tr:last-of-type {
+  margin-bottom: 0;
+}
+.responsive-table tbody th[scope="row"] {
+  background-color: #1d96b2;
+  color: white;
+}
+.responsive-table tbody td[data-type=currency] {
+  text-align: right;
+}
+.responsive-table tbody td[data-title]:before {
+  content: attr(data-title);
+  float: left;
+  font-size: .8em;
+  color: rgba(94, 93, 82, 0.75);
+}
+.responsive-table tbody td {
+  text-align: right;
+  border-bottom: 1px solid #1d96b2;
+}
+
+.responsive-table {
+  font-size: .9em;
+}
+.responsive-table thead {
+  position: relative;
+  clip: auto;
+  height: auto;
+  width: auto;
+  overflow: auto;
+}
+.responsive-table tr {
+  display: table-row;
+}
+.responsive-table th,
+.responsive-table td {
+  display: table-cell;
+  padding: .5em;
+}
+
+.responsive-table caption {
+  font-size: 1.5em;
+}
+.responsive-table tbody {
+  display: table-row-group;
+}
+.responsive-table tbody tr {
+  display: table-row;
+  border-width: 1px;
+}
+.responsive-table tbody tr:nth-of-type(even) {
+  background-color: rgba(94, 93, 82, 0.1);
+}
+.responsive-table tbody th[scope="row"] {
+  background-color: transparent;
+  color: #5e5d52;
+  text-align: left;
+}
+.responsive-table tbody td {
+  text-align: center;
+}
+.responsive-table tbody td[data-title]:before {
+  content: none;
+}
+</style>
+
+<script type="application/javascript"
+        src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script type="application/javascript"
+        src="../common.js"></script>
+<script type="application/javascript"
+          src="../role.js"></script>
+  <script type="application/javascript"
+          src="../table.js"></script>
+
+<script type="application/javascript">
+
+const COLHEADER = ROLE_COLUMNHEADER;
+const ROWHEADER = ROLE_ROWHEADER;
+const CELL = ROLE_CELL;
+const TEXT_LEAF = ROLE_TEXT_LEAF;
+
+function doTest() {
+  let accTree =
+    { TABLE: [
+      { CAPTION: [
+        {
+          role: ROLE_TEXT_LEAF,
+          name: "Top 10 Grossing Animated Films of All Time"
+         }
+      ] },
+      { ROW: [
+        { role: COLHEADER, name: "Film Title" },
+        { role: COLHEADER, name: "Released" },
+        { role: COLHEADER, name: "Studio" },
+        { role: COLHEADER, name: "Worldwide Gross" },
+        { role: COLHEADER, name: "Domestic Gross" },
+        { role: COLHEADER, name: "Foreign Gross" },
+        { role: COLHEADER, name: "Budget" }
+      ] },
+      { ROW: [
+        { role: CELL }
+      ] },
+      { ROW: [
+        { role: ROWHEADER, name: "Toy Story 3" },
+        { CELL: [ { role: TEXT_LEAF, name: "2010" }] },
+        { CELL: [ { role: TEXT_LEAF, name: "Disney Pixar" }] },
+        { CELL: [ { role: TEXT_LEAF, name: "$1,063,171,911" }] },
+        { CELL: [ { role: TEXT_LEAF, name: "$415,004,880" }] },
+        { CELL: [ { role: TEXT_LEAF, name: "$648,167,031" }] },
+        { CELL: [ { role: TEXT_LEAF, name: "$200,000,000" }] }
+      ] },
+      { ROW: [
+        { role: ROWHEADER, name: "Shrek Forever After" },
+        { CELL: [ { role: TEXT_LEAF, name: "2010" }] },
+        { CELL: [ { role: TEXT_LEAF, name: "Dreamworks" }] },
+        { CELL: [ { role: TEXT_LEAF, name: "$752,600,867" }] },
+        { CELL: [ { role: TEXT_LEAF, name: "$238,736,787" }] },
+        { CELL: [ { role: TEXT_LEAF, name: "$513,864,080" }] },
+        { CELL: [ { role: TEXT_LEAF, name: "$165,000,000" }] }
+      ] }
+    ] };
+
+  testAccessibleTree("table", accTree);
+
+  SimpleTest.finish();
+}
+SimpleTest.waitForExplicitFinish();
+addA11yLoadEvent(doTest);
+</script>
+</head>
+
+<body>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <table class="responsive-table" id="table">
+  <caption>Top 10 Grossing Animated Films of All Time</caption>
+  <thead>
+    <tr>
+      <th scope="col">Film Title</th>
+      <th scope="col">Released</th>
+      <th scope="col">Studio</th>
+      <th scope="col">Worldwide Gross</th>
+      <th scope="col">Domestic Gross</th>
+      <th scope="col">Foreign Gross</th>
+      <th scope="col">Budget</th>
+    </tr>
+  </thead>
+  <tfoot>
+    <tr>
+      <td colspan="7">Sources: <a href="http://en.wikipedia.org/wiki/List_of_highest-grossing_animated_films" rel="external">Wikipedia</a> &amp; <a href="http://www.boxofficemojo.com/genres/chart/?id=animation.htm" rel="external">Box Office Mojo</a>. Data is current as of March 12, 2014</td>
+    </tr>
+  </tfoot>
+  <tbody>
+    <tr>
+      <th scope="row">Toy Story 3</th>
+      <td data-title="Released">2010</td>
+      <td data-title="Studio">Disney Pixar</td>
+      <td data-title="Worldwide Gross" data-type="currency">$1,063,171,911</td>
+      <td data-title="Domestic Gross" data-type="currency">$415,004,880</td>
+      <td data-title="Foreign Gross" data-type="currency">$648,167,031</td>
+      <td data-title="Budget" data-type="currency">$200,000,000</td>
+    </tr>
+    <tr>
+      <th scope="row">Shrek Forever After</th>
+      <td data-title="Released">2010</td>
+      <td data-title="Studio">Dreamworks</td>
+      <td data-title="Worldwide Gross" data-type="currency">$752,600,867</td>
+      <td data-title="Domestic Gross" data-type="currency">$238,736,787</td>
+      <td data-title="Foreign Gross" data-type="currency">$513,864,080</td>
+      <td data-title="Budget" data-type="currency">$165,000,000</td>
+    </tr>
+  </tbody>
+  </table>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/tree/test_table_3.html
@@ -0,0 +1,245 @@
+<!DOCTYPE HTML PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<link rel="stylesheet" type="text/css"
+      href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+<style>
+.responsive-table {
+  width: 100%;
+  margin-bottom: 1.5em;
+}
+.responsive-table thead {
+  position: absolute;
+  clip: rect(1px 1px 1px 1px);
+  /* IE6, IE7 */
+  clip: rect(1px, 1px, 1px, 1px);
+  padding: 0;
+  border: 0;
+  height: 1px;
+  width: 1px;
+  overflow: hidden;
+}
+.responsive-table thead th {
+  background-color: #1d96b2;
+  border: 1px solid #1d96b2;
+  font-weight: normal;
+  text-align: center;
+  color: white;
+}
+.responsive-table thead th:first-of-type {
+  text-align: left;
+}
+.responsive-table tbody,
+.responsive-table tr,
+.responsive-table th,
+.responsive-table td {
+  display: block;
+  padding: 0;
+  text-align: left;
+  white-space: normal;
+}
+.responsive-table th,
+.responsive-table td {
+  padding: .5em;
+  vertical-align: middle;
+}
+.responsive-table caption {
+  margin-bottom: 1em;
+  font-size: 1em;
+  font-weight: bold;
+  text-align: center;
+}
+.responsive-table tfoot {
+  font-size: .8em;
+  font-style: italic;
+}
+.responsive-table tbody tr {
+  margin-bottom: 1em;
+  border: 2px solid #1d96b2;
+}
+.responsive-table tbody tr:last-of-type {
+  margin-bottom: 0;
+}
+.responsive-table tbody th[scope="row"] {
+  background-color: #1d96b2;
+  color: white;
+}
+.responsive-table tbody td[data-type=currency] {
+  text-align: right;
+}
+.responsive-table tbody td[data-title]:before {
+  content: attr(data-title);
+  float: left;
+  font-size: .8em;
+  color: #1d96b2;
+  font-weight: bold;
+}
+.responsive-table tbody td {
+  text-align: right;
+  border-bottom: 1px solid #1d96b2;
+}
+
+/* float everything */
+.responsive-table tbody tr {
+  float: left;
+  width: 48%;
+  margin-left: 2%;
+}
+</style>
+
+<script type="application/javascript"
+        src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script type="application/javascript"
+        src="../common.js"></script>
+<script type="application/javascript"
+          src="../role.js"></script>
+  <script type="application/javascript"
+          src="../table.js"></script>
+
+<script type="application/javascript">
+
+const COLHEADER = ROLE_COLUMNHEADER;
+const ROWHEADER = ROLE_ROWHEADER;
+const CELL = ROLE_CELL;
+const STATICTEXT = ROLE_STATICTEXT;
+const TEXT_LEAF = ROLE_TEXT_LEAF;
+const TEXT_CONTAINER = ROLE_TEXT_CONTAINER;
+
+function doTest() {
+  let accTree =
+    { TABLE: [
+      { CAPTION: [
+        {
+          role: ROLE_TEXT_LEAF,
+          name: "Top 10 Grossing Animated Films of All Time"
+         }
+      ] },
+      { ROW: [
+        { CELL: [ { role: TEXT_LEAF, name: "Film Title" } ] },
+        { CELL: [ { role: TEXT_LEAF, name: "Released" } ] },
+        { CELL: [ { role: TEXT_LEAF, name: "Studio" } ] },
+        { CELL: [ { role: TEXT_LEAF, name: "Worldwide Gross" } ] },
+        { CELL: [ { role: TEXT_LEAF, name: "Domestic Gross" } ] },
+        { CELL: [ { role: TEXT_LEAF, name: "Foreign Gross" } ] },
+        { CELL: [ { role: TEXT_LEAF, name: "Budget" } ] }
+      ] },
+      { ROW: [
+        { role: CELL }
+      ] },
+      { TEXT_CONTAINER: [
+        { ROW: [
+          { CELL: [ { role: TEXT_LEAF, name: "Toy Story 3" } ] },
+          { CELL: [
+            { role: STATICTEXT, name: "Released" },
+            { role: TEXT_LEAF, name: "2010" }
+          ] },
+          { CELL: [
+            { role: STATICTEXT, name: "Studio" },
+            { role: TEXT_LEAF, name: "Disney Pixar" }
+          ] },
+          { CELL: [
+            { role: STATICTEXT, name: "Worldwide Gross" },
+            { role: TEXT_LEAF, name: "$1,063,171,911" }
+          ] },
+          { CELL: [
+            { role: STATICTEXT, name: "Domestic Gross" },
+            { role: TEXT_LEAF, name: "$415,004,880" }
+          ] },
+          { CELL: [
+            { role: STATICTEXT, name: "Foreign Gross" },
+            { role: TEXT_LEAF, name: "$648,167,031" }
+          ] },
+          { CELL: [
+            { role: STATICTEXT, name: "Budget" },
+            { role: TEXT_LEAF, name: "$200,000,000" }
+          ]}
+        ] },
+        { ROW: [
+          { CELL: [ { role: TEXT_LEAF, name: "Shrek Forever After" } ] },
+          { CELL: [
+            { role: STATICTEXT, name: "Released" },
+            { role: TEXT_LEAF, name: "2010" }
+          ] },
+          { CELL: [
+            { role: STATICTEXT, name: "Studio" },
+            { role: TEXT_LEAF, name: "Dreamworks" }
+          ] },
+          { CELL: [
+            { role: STATICTEXT, name: "Worldwide Gross" },
+            { role: TEXT_LEAF, name: "$752,600,867" }
+          ] },
+          { CELL: [
+            { role: STATICTEXT, name: "Domestic Gross" },
+            { role: TEXT_LEAF, name: "$238,736,787" }
+          ] },
+          { CELL: [
+            { role: STATICTEXT, name: "Foreign Gross" },
+            { role: TEXT_LEAF, name: "$513,864,080" }
+          ] },
+          { CELL: [
+            { role: STATICTEXT, name: "Budget" },
+            { role: TEXT_LEAF, name: "$165,000,000" }
+          ] }
+        ] }
+      ] }
+    ] };
+
+  testAccessibleTree("table", accTree);
+
+  SimpleTest.finish();
+}
+SimpleTest.waitForExplicitFinish();
+addA11yLoadEvent(doTest);
+</script>
+</head>
+
+<body>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <table class="responsive-table" id="table">
+    <caption>Top 10 Grossing Animated Films of All Time</caption>
+    <thead>
+      <tr>
+        <th scope="col">Film Title</th>
+        <th scope="col">Released</th>
+        <th scope="col">Studio</th>
+        <th scope="col">Worldwide Gross</th>
+        <th scope="col">Domestic Gross</th>
+        <th scope="col">Foreign Gross</th>
+        <th scope="col">Budget</th>
+      </tr>
+    </thead>
+    <tfoot>
+      <tr>
+        <td colspan="7">Sources: <a href="http://en.wikipedia.org/wiki/List_of_highest-grossing_animated_films" rel="external">Wikipedia</a> &amp; <a href="http://www.boxofficemojo.com/genres/chart/?id=animation.htm" rel="external">Box Office Mojo</a>. Data is current as of March 12, 2014</td>
+      </tr>
+    </tfoot>
+    <tbody>
+      <tr>
+        <th scope="row">Toy Story 3</th>
+        <td data-title="Released">2010</td>
+        <td data-title="Studio">Disney Pixar</td>
+        <td data-title="Worldwide Gross" data-type="currency">$1,063,171,911</td>
+        <td data-title="Domestic Gross" data-type="currency">$415,004,880</td>
+        <td data-title="Foreign Gross" data-type="currency">$648,167,031</td>
+        <td data-title="Budget" data-type="currency">$200,000,000</td>
+      </tr>
+      <tr>
+        <th scope="row">Shrek Forever After</th>
+        <td data-title="Released">2010</td>
+        <td data-title="Studio">Dreamworks</td>
+        <td data-title="Worldwide Gross" data-type="currency">$752,600,867</td>
+        <td data-title="Domestic Gross" data-type="currency">$238,736,787</td>
+        <td data-title="Foreign Gross" data-type="currency">$513,864,080</td>
+        <td data-title="Budget" data-type="currency">$165,000,000</td>
+      </tr>
+    </tbody>
+  </table>
+</body>
+</html>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -75,16 +75,20 @@ pref("extensions.geckoProfiler.getSymbol
 // Add-on content security policies.
 pref("extensions.webextensions.base-content-security-policy", "script-src 'self' https://* moz-extension: blob: filesystem: 'unsafe-eval' 'unsafe-inline'; object-src 'self' https://* moz-extension: blob: filesystem:;");
 pref("extensions.webextensions.default-content-security-policy", "script-src 'self'; object-src 'self';");
 
 #if defined(XP_WIN) || defined(XP_MACOSX)
 pref("extensions.webextensions.remote", true);
 #endif
 
+#ifdef NIGHTLY_BUILD
+pref("extensions.webextensions.background-delayed-startup", true);
+#endif
+
 // Extensions that should not be flagged as legacy in about:addons
 pref("extensions.legacy.exceptions", "testpilot@cliqz.com,@testpilot-containers,jid1-NeEaf3sAHdKHPA@jetpack,@activity-streams,pulse@mozilla.com,@testpilot-addon,@min-vid,tabcentertest1@mozilla.com,snoozetabs@mozilla.com,speaktome@mozilla.com,hoverpad@mozilla.com");
 
 // Require signed add-ons by default
 pref("extensions.langpacks.signatures.required", true);
 pref("xpinstall.signatures.required", true);
 pref("xpinstall.signatures.devInfoURL", "https://wiki.mozilla.org/Addons/Extension_Signing");
 
new file mode 100644
--- /dev/null
+++ b/browser/base/content/aboutRestartRequired.js
@@ -0,0 +1,33 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* eslint-env mozilla/frame-script */
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+var AboutRestartRequired = {
+  /* Only do autofocus if we're the toplevel frame; otherwise we
+     don't want to call attention to ourselves!  The key part is
+     that autofocus happens on insertion into the tree, so we
+     can remove the button, add @autofocus, and reinsert the
+     button.
+  */
+  addAutofocus() {
+    if (window.top == window) {
+      var button = document.getElementById("restart");
+      var parent = button.parentNode;
+      button.remove();
+      button.setAttribute("autofocus", "true");
+      parent.insertAdjacentElement("afterbegin", button);
+    }
+  },
+  restart() {
+    Services.startup.quit(Ci.nsIAppStartup.eRestart |
+                          Ci.nsIAppStartup.eAttemptQuit);
+  },
+  init() {
+    this.addAutofocus();
+  },
+};
+
+AboutRestartRequired.init();
new file mode 100644
--- /dev/null
+++ b/browser/base/content/aboutRestartRequired.xhtml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!DOCTYPE html [
+  <!ENTITY % htmlDTD
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "DTD/xhtml1-strict.dtd">
+  %htmlDTD;
+  <!ENTITY % globalDTD
+    SYSTEM "chrome://global/locale/global.dtd">
+  %globalDTD;
+  <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
+  %brandDTD;
+  <!ENTITY % restartRequiredDTD
+    SYSTEM "chrome://browser/locale/aboutRestartRequired.dtd">
+  %restartRequiredDTD;
+]>
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>&restartRequired.title;</title>
+    <link rel="stylesheet" type="text/css" media="all"
+          href="chrome://browser/skin/aboutRestartRequired.css"/>
+    <!-- If the location of the favicon is changed here, the
+         FAVICON_ERRORPAGE_URL symbol in
+         toolkit/components/places/src/nsFaviconService.h should be updated. -->
+    <link rel="icon" type="image/png" id="favicon"
+          href="chrome://global/skin/icons/warning-16.png"/>
+  </head>
+
+  <body dir="&locale.dir;">
+    <!-- PAGE CONTAINER (for styling purposes only) -->
+    <div id="errorPageContainer">
+      <div id="text-container">
+        <div id="title">
+          <h1 id="title-text">&restartRequired.header;</h1>
+        </div>
+        <div id="errorLongContent">
+          <div id="errorLongDesc">&restartRequired.description;</div>
+        </div>
+      </div>
+      <!-- Restart Button -->
+      <div id="restartButtonContainer" class="button-container">
+        <button id="restart" class="primary" autocomplete="off"
+                onclick="AboutRestartRequired.restart();">
+          &restartButton.label;
+        </button>
+      </div>
+    </div>
+  </body>
+  <script type="text/javascript"
+           src="chrome://browser/content/aboutRestartRequired.js"/>
+</html>
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -4106,26 +4106,37 @@ window._gBrowser = {
         this.removePreloadedBrowser();
         return;
       }
 
       let icon = browser.mIconURL;
       let tab = this.getTabForBrowser(browser);
 
       if (this.selectedBrowser == browser) {
-        TabCrashHandler.onSelectedBrowserCrash(browser);
+        TabCrashHandler.onSelectedBrowserCrash(browser, false);
       } else {
         this.updateBrowserRemoteness(browser, false);
         SessionStore.reviveCrashedTab(tab);
       }
 
       tab.removeAttribute("soundplaying");
       this.setIcon(tab, icon, browser.contentPrincipal, browser.contentRequestContextID);
     });
 
+    this.addEventListener("oop-browser-buildid-mismatch", (event) => {
+      if (!event.isTrusted)
+        return;
+
+      let browser = event.originalTarget;
+
+      if (this.selectedBrowser == browser) {
+        TabCrashHandler.onSelectedBrowserCrash(browser, true);
+      }
+    });
+
     this.addEventListener("DOMAudioPlaybackStarted", (event) => {
       var tab = this.getTabFromAudioEvent(event);
       if (!tab) {
         return;
       }
 
       clearTimeout(tab._soundPlayingAttrRemovalTimer);
       tab._soundPlayingAttrRemovalTimer = 0;
--- a/browser/base/content/test/chrome/chrome.ini
+++ b/browser/base/content/test/chrome/chrome.ini
@@ -1,3 +1,4 @@
 [DEFAULT]
 
 [test_aboutCrashed.xul]
+[test_aboutRestartRequired.xul]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/chrome/test_aboutRestartRequired.xul
@@ -0,0 +1,78 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+  <iframe type="content" id="frame1"/>
+  <iframe type="content" id="frame2" onload="doTest()"/>
+  <script type="application/javascript"><![CDATA[
+    ChromeUtils.import("resource://gre/modules/Services.jsm");
+    ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+    SimpleTest.waitForExplicitFinish();
+
+    // Load error pages do not fire "load" events, so let's use a progressListener.
+    function waitForErrorPage(frame) {
+      return new Promise(resolve => {
+        let progressListener = {
+          onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) {
+            if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
+              frame.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+                            .getInterface(Ci.nsIWebProgress)
+                            .removeProgressListener(progressListener,
+                                                    Ci.nsIWebProgress.NOTIFY_LOCATION);
+
+              resolve();
+            }
+          },
+
+          QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
+                                                 Ci.nsISupportsWeakReference])
+        };
+
+        frame.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+                      .getInterface(Ci.nsIWebProgress)
+                      .addProgressListener(progressListener,
+                                           Ci.nsIWebProgress.NOTIFY_LOCATION);
+      });
+    }
+
+  function doTest() {
+    (async function testBody() {
+      let frame1 = document.getElementById("frame1");
+      let frame2 = document.getElementById("frame2");
+      let uri1 = Services.io.newURI("http://www.example.com/1");
+      let uri2 = Services.io.newURI("http://www.example.com/2");
+
+      let errorPageReady = waitForErrorPage(frame1);
+      frame1.docShell.displayLoadError(Cr.NS_ERROR_BUILDID_MISMATCH, uri1, null);
+
+      await errorPageReady;
+      frame1.docShell.chromeEventHandler.removeAttribute("crashedPageTitle");
+
+      SimpleTest.is(frame1.contentDocument.documentURI,
+                    "about:restartrequired?e=restartrequired&u=http%3A//www.example.com/1&c=UTF-8&f=regular&d=%20",
+                    "Correct about:restartrequired displayed for page with title.");
+
+      errorPageReady = waitForErrorPage(frame2);
+      frame2.docShell.displayLoadError(Cr.NS_ERROR_BUILDID_MISMATCH, uri2, null);
+
+      await errorPageReady;
+
+      SimpleTest.is(frame2.contentDocument.documentURI,
+                    "about:restartrequired?e=restartrequired&u=http%3A//www.example.com/2&c=UTF-8&f=regular&d=%20",
+                    "Correct about:restartrequired displayed for page with no title.");
+
+      SimpleTest.finish();
+    })().catch(ex => SimpleTest.ok(false, ex));
+  }
+  ]]></script>
+
+  <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;" />
+</window>
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -430,17 +430,17 @@ support-files =
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_tabReorder.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_tab_detach_restore.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_tab_drag_drop_perwindow.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_tab_dragdrop.js]
-skip-if = buildapp == 'mulet' || (e10s && debug) # Bug 1312436
+skip-if = debug || (os == 'linux') || (os == 'mac') # Bug 1312436, Bug 1388973
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_tab_dragdrop2.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_tabbar_big_widgets.js]
 skip-if = os == "linux" || os == "mac" # No tabs in titlebar on linux
                                        # Disabled on OS X because of bug 967917
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_tabfocus.js]
--- a/browser/base/content/test/tabcrashed/browser.ini
+++ b/browser/base/content/test/tabcrashed/browser.ini
@@ -4,9 +4,10 @@ support-files =
   head.js
 
 [browser_autoSubmitRequest.js]
 [browser_clearEmail.js]
 [browser_noPermanentKey.js]
 skip-if = (os == "linux") # Bug 1383315
 [browser_showForm.js]
 [browser_shown.js]
+[browser_shownRestartRequired.js]
 [browser_withoutDump.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabcrashed/browser_shownRestartRequired.js
@@ -0,0 +1,48 @@
+"use strict";
+
+const PAGE =
+  "data:text/html,<html><body>A%20regular,%20everyday,%20normal%20page.";
+
+/**
+ * This function returns a Promise that resolves once the following
+ * actions have taken place:
+ *
+ * 1) A new tab is opened up at PAGE
+ * 2) The tab is crashed
+ * 3) The about:restartrequired page is displayed
+ *
+ * @returns Promise
+ */
+function crashTabTestHelper() {
+  return BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: PAGE,
+  }, async function(browser) {
+    // Simulate buildID mismatch.
+    TabCrashHandler.testBuildIDMismatch = true;
+
+    await BrowserTestUtils.crashBrowser(browser, false);
+    let doc = browser.contentDocument;
+
+    // Since about:restartRequired will run in the parent process, we can safely
+    // manipulate its DOM nodes directly
+    let title = doc.getElementById("title");
+    let description = doc.getElementById("errorLongContent");
+    let restartButton = doc.getElementById("restart");
+
+    ok(title, "Title element exists.");
+    ok(description, "Description element exists.");
+    ok(restartButton, "Restart button exists.");
+
+    // Reset
+    TabCrashHandler.testBuildIDMismatch = false;
+  });
+}
+
+/**
+ * Tests that the about:restartrequired page appears when buildID mismatches
+ * between parent and child processes are encountered.
+ */
+add_task(async function test_default() {
+  await crashTabTestHelper();
+});
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -1108,18 +1108,17 @@ file, You can obtain one at http://mozil
       <method name="_getSelectedValueForClipboard">
         <body><![CDATA[
           // Grab the actual input field's value, not our value, which could
           // include "moz-action:".
           var inputVal = this.inputField.value;
           let selection = this.editor.selection;
           const flags = Ci.nsIDocumentEncoder.OutputPreformatted |
                         Ci.nsIDocumentEncoder.OutputRaw;
-          let selectedVal = selection.QueryInterface(Ci.nsISelectionPrivate)
-                                     .toStringWithFormat("text/plain", flags, 0);
+          let selectedVal = selection.toStringWithFormat("text/plain", flags, 0);
 
           // Handle multiple-range selection as a string for simplicity.
           if (selection.rangeCount > 1) {
              return selectedVal;
           }
 
           // If the selection doesn't start at the beginning or doesn't span the
           // full domain or the URL bar is modified or there is no text at all,
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -3,16 +3,18 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 browser.jar:
 %  content browser %content/browser/ contentaccessible=yes
 
         content/browser/aboutDialog-appUpdater.js     (content/aboutDialog-appUpdater.js)
 *       content/browser/aboutDialog.xul               (content/aboutDialog.xul)
         content/browser/aboutDialog.js                (content/aboutDialog.js)
         content/browser/aboutDialog.css               (content/aboutDialog.css)
+        content/browser/aboutRestartRequired.js       (content/aboutRestartRequired.js)
+        content/browser/aboutRestartRequired.xhtml    (content/aboutRestartRequired.xhtml)
         content/browser/aboutRobots.xhtml             (content/aboutRobots.xhtml)
         content/browser/aboutRobots.js                (content/aboutRobots.js)
         content/browser/aboutRobots.css               (content/aboutRobots.css)
 *       content/browser/abouthome/aboutHome.xhtml     (content/abouthome/aboutHome.xhtml)
         content/browser/abouthome/aboutHome.js        (content/abouthome/aboutHome.js)
 *       content/browser/abouthome/aboutHome.css       (content/abouthome/aboutHome.css)
         content/browser/abouthome/snippet1.png        (content/abouthome/snippet1.png)
         content/browser/abouthome/snippet2.png        (content/abouthome/snippet2.png)
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -93,16 +93,18 @@ static const RedirEntry kRedirMap[] = {
     nsIAboutModule::ALLOW_SCRIPT },
   { "downloads", "chrome://browser/content/downloads/contentAreaDownloadsView.xul",
     nsIAboutModule::ALLOW_SCRIPT },
   { "reader", "chrome://global/content/reader/aboutReader.html",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT },
+  { "restartrequired", "chrome://browser/content/aboutRestartRequired.xhtml",
+    nsIAboutModule::ALLOW_SCRIPT },
 };
 
 static nsAutoCString
 GetAboutModuleName(nsIURI *aURI)
 {
   nsAutoCString path;
   aURI->GetPathQueryRef(path);
 
--- a/browser/components/build/nsModule.cpp
+++ b/browser/components/build/nsModule.cpp
@@ -95,16 +95,17 @@ static const mozilla::Module::ContractID
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "sessionrestore", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "welcomeback", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "home", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "newtab", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "library", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "preferences", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "downloads", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "reader", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
+    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "restartrequired", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
 #if defined(XP_WIN)
     { NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID },
 #elif defined(XP_MACOSX)
     { NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
 #endif
     { nullptr }
 };
 
--- a/browser/components/places/PlacesUIUtils.jsm
+++ b/browser/components/places/PlacesUIUtils.jsm
@@ -599,23 +599,17 @@ var PlacesUIUtils = {
 
   /** aItemsToOpen needs to be an array of objects of the form:
     * {uri: string, isBookmark: boolean}
     */
   _openTabset: function PUIU__openTabset(aItemsToOpen, aEvent, aWindow) {
     if (!aItemsToOpen.length)
       return;
 
-    // Prefer the caller window if it's a browser window, otherwise use
-    // the top browser window.
-    var browserWindow = null;
-    browserWindow =
-      aWindow && aWindow.document.documentElement.getAttribute("windowtype") == "navigator:browser" ?
-      aWindow : BrowserWindowTracker.getTopWindow();
-
+    let browserWindow = getBrowserWindow(aWindow);
     var urls = [];
     let skipMarking = browserWindow && PrivateBrowsingUtils.isWindowPrivate(browserWindow);
     for (let item of aItemsToOpen) {
       urls.push(item.uri);
       if (skipMarking) {
         continue;
       }
 
@@ -702,20 +696,26 @@ var PlacesUIUtils = {
    * @param   aEvent
    *          The DOM mouse/key event with modifier keys set that track the
    *          user's preferred destination window or tab.
    */
   openNodeWithEvent:
   function PUIU_openNodeWithEvent(aNode, aEvent) {
     let window = aEvent.target.ownerGlobal;
 
+    let browserWindow = getBrowserWindow(window);
+
     let where = window.whereToOpenLink(aEvent, false, true);
-    if (where == "current" && this.loadBookmarksInTabs &&
-        PlacesUtils.nodeIsBookmark(aNode) && !aNode.uri.startsWith("javascript:")) {
-      where = "tab";
+    if (this.loadBookmarksInTabs && PlacesUtils.nodeIsBookmark(aNode)) {
+      if (where == "current" && !aNode.uri.startsWith("javascript:")) {
+        where = "tab";
+      }
+      if (where == "tab" && browserWindow.isTabEmpty(browserWindow.gBrowser.selectedTab)) {
+        where = "current";
+      }
     }
 
     this._openNodeIn(aNode, where, window);
     let view = this.getViewForNode(aEvent.target);
     if (view && view.controller.hasCachedLivemarkInfo(aNode.parent)) {
       Services.telemetry.scalarAdd("browser.feeds.livebookmark_item_opened", 1);
     }
   },
@@ -1295,8 +1295,15 @@ async function getTransactionsForCopy(it
     transactions.push(transaction);
 
     if (index != -1) {
       index++;
     }
   }
   return transactions;
 }
+
+function getBrowserWindow(aWindow) {
+  // Prefer the caller window if it's a browser window, otherwise use
+  // the top browser window.
+  return aWindow && aWindow.document.documentElement.getAttribute("windowtype") == "navigator:browser" ?
+    aWindow : BrowserWindowTracker.getTopWindow();
+}
--- a/browser/components/places/tests/browser/browser_click_bookmarks_on_toolbar.js
+++ b/browser/components/places/tests/browser/browser_click_bookmarks_on_toolbar.js
@@ -121,16 +121,27 @@ add_task(async function clickWithPrefSet
 
   promise = waitForLoad(gBrowser.selectedBrowser, TEST_PAGES[1]);
   let open = document.getElementById("placesContext_open");
   EventUtils.synthesizeMouseAtCenter(open, {
     button: 0
   });
   await promise;
 
+  // With loadBookmarksInTabs, reuse current tab if blank
+  for (let button of [0, 1]) {
+    await BrowserTestUtils.withNewTab({gBrowser}, async (tab) => {
+      promise = waitForLoad(gBrowser.selectedBrowser, TEST_PAGES[1]);
+      EventUtils.synthesizeMouseAtCenter(gBookmarkElements[1], {
+        button
+      });
+      await promise;
+    });
+  }
+
   await SpecialPowers.popPrefEnv();
 });
 
 // Open a tab, then quickly open the context menu to ensure that the command
 // enabled state of the menuitems is updated properly.
 add_task(async function quickContextMenu() {
   await SpecialPowers.pushPrefEnv({set: [
     [PREF_LOAD_BOOKMARKS_IN_TABS, true]
--- a/browser/components/places/tests/browser/browser_sidebar_open_bookmarks.js
+++ b/browser/components/places/tests/browser/browser_sidebar_open_bookmarks.js
@@ -1,13 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+const PREF_LOAD_BOOKMARKS_IN_TABS = "browser.tabs.loadBookmarksInTabs";
+
 var gBms;
 
 add_task(async function setup() {
   gBms = await PlacesUtils.bookmarks.insertTree({
     guid: PlacesUtils.bookmarks.unfiledGuid,
     children: [{
       title: "bm1",
       url: "about:buildconfig"
@@ -60,16 +62,45 @@ add_task(async function test_open_bookma
 
     // An assert to make the test happy.
     Assert.ok(true, "The bookmark was loaded successfully.");
   });
 
   await BrowserTestUtils.removeTab(tab);
 });
 
+add_task(async function test_open_bookmark_in_tab_from_sidebar() {
+  await SpecialPowers.pushPrefEnv({set: [
+    [PREF_LOAD_BOOKMARKS_IN_TABS, true]
+  ]});
+
+  await BrowserTestUtils.withNewTab({gBrowser}, async (initialTab) => {
+    await withSidebarTree("bookmarks", async (tree) => {
+      tree.selectItems([gBms[0].guid]);
+      let loadedPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser,
+        false, gBms[0].url
+      );
+      tree.focus();
+      EventUtils.sendKey("return");
+      await loadedPromise;
+      Assert.ok(true, "The bookmark reused the empty tab.");
+
+      tree.selectItems([gBms[1].guid]);
+      let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, gBms[1].url);
+      tree.focus();
+      EventUtils.sendKey("return");
+      let newTab = await newTabPromise;
+      Assert.ok(true, "The bookmark was opened in a new tab.");
+      BrowserTestUtils.removeTab(newTab);
+    });
+  });
+
+  await SpecialPowers.popPrefEnv();
+});
+
 add_task(async function test_open_bookmark_folder_from_sidebar() {
   await withSidebarTree("bookmarks", async (tree) => {
     tree.selectItems([PlacesUtils.bookmarks.virtualUnfiledGuid]);
 
     Assert.equal(tree.view.selection.getRangeCount(), 1,
       "Should only have one range selected");
 
     let loadedPromises = [];
new file mode 100644
--- /dev/null
+++ b/browser/locales/en-US/chrome/browser/aboutRestartRequired.dtd
@@ -0,0 +1,13 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!ENTITY restartRequired.title "Restart Required">
+
+<!ENTITY restartRequired.header "Sorry. We just need to do one small thing to keep going.">
+<!ENTITY restartRequired.description "
+<p>We have just installed an update in the background. Click Restart &brandShortName; to finish applying it.</p>
+<p>We will restore all your pages, windows and tabs afterwards, so you can be on your way quickly.</p>
+">
+
+<!ENTITY restartButton.label "Restart &brandShortName;">
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -13,16 +13,17 @@
 @AB_CD@.jar:
 % locale browser @AB_CD@ %locale/browser/
 *   locale/browser/bookmarks.html                  (generic/profile/bookmarks.html.in)
     locale/browser/aboutDialog.dtd                 (%chrome/browser/aboutDialog.dtd)
     locale/browser/aboutPrivateBrowsing.dtd        (%chrome/browser/aboutPrivateBrowsing.dtd)
     locale/browser/aboutRobots.dtd                 (%chrome/browser/aboutRobots.dtd)
     locale/browser/aboutHome.dtd                   (%chrome/browser/aboutHome.dtd)
     locale/browser/accounts.properties             (%chrome/browser/accounts.properties)
+    locale/browser/aboutRestartRequired.dtd        (%chrome/browser/aboutRestartRequired.dtd)
     locale/browser/aboutSearchReset.dtd            (%chrome/browser/aboutSearchReset.dtd)
     locale/browser/aboutSessionRestore.dtd         (%chrome/browser/aboutSessionRestore.dtd)
     locale/browser/aboutTabCrashed.dtd             (%chrome/browser/aboutTabCrashed.dtd)
     locale/browser/browser.dtd                     (%chrome/browser/browser.dtd)
     locale/browser/baseMenuOverlay.dtd             (%chrome/browser/baseMenuOverlay.dtd)
     locale/browser/browser.properties              (%chrome/browser/browser.properties)
     locale/browser/customizableui/customizableWidgets.properties (%chrome/browser/customizableui/customizableWidgets.properties)
     locale/browser/lightweightThemes.properties    (%chrome/browser/lightweightThemes.properties)
--- a/browser/modules/ContentCrashHandlers.jsm
+++ b/browser/modules/ContentCrashHandlers.jsm
@@ -69,16 +69,17 @@ class BrowserWeakMap extends WeakMap {
 }
 
 var TabCrashHandler = {
   _crashedTabCount: 0,
   childMap: new Map(),
   browserMap: new BrowserWeakMap(),
   unseenCrashedChildIDs: [],
   crashedBrowserQueues: new Map(),
+  testBuildIDMismatch: false,
 
   get prefs() {
     delete this.prefs;
     return this.prefs = Services.prefs.getBranch("browser.tabs.crashReporting.");
   },
 
   init() {
     if (this.initialized)
@@ -218,35 +219,41 @@ var TabCrashHandler = {
     if (!browserQueue) {
       return false;
     }
 
     this.crashedBrowserQueues.delete(childID);
 
     let sentBrowser = false;
     for (let weakBrowser of browserQueue) {
-      let browser = weakBrowser.get();
+      let browser = weakBrowser.browser.get();
       if (browser) {
-        this.sendToTabCrashedPage(browser);
+        if (weakBrowser.restartRequired || this.testBuildIDMismatch) {
+          this.sendToRestartRequiredPage(browser);
+        } else {
+          this.sendToTabCrashedPage(browser);
+        }
         sentBrowser = true;
       }
     }
 
     return sentBrowser;
   },
 
   /**
    * Called by a tabbrowser when it notices that its selected browser
    * has crashed. This will queue the browser to show the tab crash
    * page once the content process has finished tearing down.
    *
    * @param browser (<xul:browser>)
    *        The selected browser that just crashed.
+   * @param restartRequired (bool)
+   *        Whether or not a browser restart is required to recover.
    */
-  onSelectedBrowserCrash(browser) {
+  onSelectedBrowserCrash(browser, restartRequired) {
     if (!browser.isRemoteBrowser) {
       Cu.reportError("Selected crashed browser is not remote.");
       return;
     }
     if (!browser.frameLoader) {
       Cu.reportError("Selected crashed browser has no frameloader.");
       return;
     }
@@ -258,17 +265,18 @@ var TabCrashHandler = {
       this.crashedBrowserQueues.set(childID, browserQueue);
     }
     // It's probably unnecessary to store this browser as a
     // weak reference, since the content process should complete
     // its teardown in the same tick of the event loop, and then
     // this queue will be flushed. The weak reference is to avoid
     // leaking browsers in case anything goes wrong during this
     // teardown process.
-    browserQueue.push(Cu.getWeakReference(browser));
+    browserQueue.push({browser: Cu.getWeakReference(browser),
+                       restartRequired});
   },
 
   /**
    * This method is exposed for SessionStore to call if the user selects
    * a tab which will restore on demand. It's possible that the tab
    * is in this state because it recently crashed. If that's the case, then
    * it's also possible that the user has not seen the tab crash page for
    * that particular crash, in which case, we might show it to them instead
@@ -301,16 +309,33 @@ var TabCrashHandler = {
         this.sendToTabCrashedPage(browser);
         return true;
       }
     }
 
     return false;
   },
 
+  sendToRestartRequiredPage(browser) {
+    let uri = browser.currentURI;
+    let gBrowser = browser.ownerGlobal.gBrowser;
+    let tab = gBrowser.getTabForBrowser(browser);
+    // The restart required page is non-remote by default.
+    gBrowser.updateBrowserRemoteness(browser, false);
+
+    browser.docShell.displayLoadError(Cr.NS_ERROR_BUILDID_MISMATCH, uri, null);
+    tab.setAttribute("crashed", true);
+
+    // Make sure to only count once even if there are multiple windows
+    // that will all show about:restartrequired.
+    if (this._crashedTabCount == 1) {
+      Services.telemetry.scalarAdd("dom.contentprocess.buildID_mismatch", 1);
+    }
+  },
+
   /**
    * We show a special page to users when a normal browser tab has crashed.
    * This method should be called to send a browser to that page once the
    * process has completely closed.
    *
    * @param browser (<xul:browser>)
    *        The browser that has recently crashed.
    */
--- a/browser/modules/WindowsJumpLists.jsm
+++ b/browser/modules/WindowsJumpLists.jsm
@@ -57,18 +57,17 @@ ChromeUtils.defineModuleGetter(this, "Pl
 ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "gHistoryObserver", function() {
   return Object.freeze({
     onClearHistory() {
       WinTaskbarJumpList.update();
     },
-    QueryInterface: XPCOMUtils.generateQI(Ci.nsINavHistoryObserver),
-    __noSuchMethod__: () => {}, // Catch all of the other notifications.
+    QueryInterface: ChromeUtils.generateQI([Ci.nsINavHistoryObserver]),
   });
 });
 
 /**
  * Global functions
  */
 
 function _getString(name) {
--- a/browser/modules/test/browser/browser.ini
+++ b/browser/modules/test/browser/browser.ini
@@ -45,8 +45,9 @@ support-files =
   usageTelemetrySearchSuggestions.sjs
   usageTelemetrySearchSuggestions.xml
 [browser_UsageTelemetry_searchbar.js]
 support-files =
   usageTelemetrySearchSuggestions.sjs
   usageTelemetrySearchSuggestions.xml
 [browser_UsageTelemetry_content.js]
 [browser_UsageTelemetry_content_aboutHome.js]
+[browser_UsageTelemetry_content_aboutRestartRequired.js]
new file mode 100644
--- /dev/null
+++ b/browser/modules/test/browser/browser_UsageTelemetry_content_aboutRestartRequired.js
@@ -0,0 +1,30 @@
+"use strict";
+
+const SCALAR_BUILDID_MISMATCH = "dom.contentprocess.buildID_mismatch";
+
+add_task(async function test_aboutRestartRequired() {
+  let CrashHandlers = {};
+  ChromeUtils.import("resource:///modules/ContentCrashHandlers.jsm",
+                     CrashHandlers);
+
+  // Let's reset the counts.
+  Services.telemetry.clearScalars();
+
+  let scalars =
+    getParentProcessScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT);
+
+  // Check preconditions
+  is(scalars[SCALAR_BUILDID_MISMATCH], undefined,
+     "Build ID mismatch count should be undefined");
+
+  // Simulate buildID mismatch
+  CrashHandlers.TabCrashHandler._crashedTabCount = 1;
+  CrashHandlers.TabCrashHandler.sendToRestartRequiredPage(
+    gBrowser.selectedTab.linkedBrowser);
+
+  scalars =
+    getParentProcessScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT);
+
+  is(scalars[SCALAR_BUILDID_MISMATCH], 1,
+     "Build ID mismatch count should be 1.");
+});
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/aboutRestartRequired.css
@@ -0,0 +1,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/. */
+
+@import url("chrome://browser/skin/error-pages.css");
+
+.illustrated #errorPageContainer {
+  min-height: 300px;
+  display: flex;
+  flex-direction: column;
+  background-position: left center;
+}
+
+body[dir="rtl"] #errorPageContainer {
+  background-position: right center;
+}
+
+#header {
+  background: none;
+  padding-inline-start: 0;
+  margin-inline-start: 0;
+}
+
+#text-container {
+  margin: auto;
+  padding-inline-start: 38%;
+}
+
+#errorPageContainer {
+  min-height: 350px;
+  display: flex;
+  flex-direction: column;
+  background-position: left center;
+  background-repeat: no-repeat;
+  background-size: 38%;
+  background-image: url("chrome://browser/content/illustrations/error-connection-failure.svg");
+}
+
+#restart {
+  margin-top: 1.2em;
+}
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -5,16 +5,17 @@
 # This is not a complete / proper jar manifest. It is included by the
 # actual theme-specific manifests, so that shared resources need only
 # be specified once. As a result, the source file paths are relative
 # to the location of the actual manifest.
 
   skin/classic/browser/aboutNetError.css                       (../shared/aboutNetError.css)
   skin/classic/browser/blockedSite.css                         (../shared/blockedSite.css)
   skin/classic/browser/error-pages.css                         (../shared/error-pages.css)
+  skin/classic/browser/aboutRestartRequired.css                (../shared/aboutRestartRequired.css)
 * skin/classic/browser/aboutSessionRestore.css                 (../shared/aboutSessionRestore.css)
   skin/classic/browser/aboutLibrary.css                        (../shared/aboutLibrary.css)
   skin/classic/browser/aboutTabCrashed.css                     (../shared/aboutTabCrashed.css)
   skin/classic/browser/aboutWelcomeBack.css                    (../shared/aboutWelcomeBack.css)
   skin/classic/browser/addons/addon-install-blocked.svg        (../shared/addons/addon-install-blocked.svg)
   skin/classic/browser/addons/addon-install-confirm.svg        (../shared/addons/addon-install-confirm.svg)
   skin/classic/browser/addons/addon-install-downloading.svg    (../shared/addons/addon-install-downloading.svg)
   skin/classic/browser/addons/addon-install-error.svg          (../shared/addons/addon-install-error.svg)
--- a/devtools/server/actors/accessibility.js
+++ b/devtools/server/actors/accessibility.js
@@ -115,29 +115,46 @@ function isDefunct(accessible) {
   // now dead.
   if (!Services.appinfo.accessibilityEnabled) {
     return true;
   }
 
   let defunct = false;
 
   try {
-    let extState = {};
-    accessible.getState({}, extState);
-    // extState.value is a bitmask. We are applying bitwise AND to mask out
+    let extraState = {};
+    accessible.getState({}, extraState);
+    // extraState.value is a bitmask. We are applying bitwise AND to mask out
     // irrelevant states.
-    defunct = !!(extState.value & Ci.nsIAccessibleStates.EXT_STATE_DEFUNCT);
+    defunct = !!(extraState.value & Ci.nsIAccessibleStates.EXT_STATE_DEFUNCT);
   } catch (e) {
     defunct = true;
   }
 
   return defunct;
 }
 
 /**
+ * Helper function that determines if nsIAccessible object is in stale state. When an
+ * object is stale it means its subtree is not up to date.
+ *
+ * @param  {nsIAccessible}  accessible
+ *         object to be tested.
+ * @return {Boolean}
+ *         True if accessible object is stale, false otherwise.
+ */
+function isStale(accessible) {
+  let extraState = {};
+  accessible.getState({}, extraState);
+  // extraState.value is a bitmask. We are applying bitwise AND to mask out
+  // irrelevant states.
+  return !!(extraState.value & Ci.nsIAccessibleStates.EXT_STATE_STALE);
+}
+
+/**
  * Set of actors that expose accessibility tree information to the
  * devtools protocol clients.
  *
  * The |Accessibility| actor is the main entry point. It is used to request
  * an AccessibleWalker actor that caches the tree of Accessible actors.
  *
  * The |AccessibleWalker| actor is used to cache all seen Accessible actors as
  * well as observe all relevant accessible events.
@@ -502,19 +519,17 @@ const AccessibleWalkerActor = ActorClass
     }
 
     if (isXUL(this.rootWin)) {
       let doc = this.addRef(this.getRawAccessibleFor(this.rootDoc));
       return Promise.resolve(doc);
     }
 
     let doc = this.getRawAccessibleFor(this.rootDoc);
-    let state = {};
-    doc.getState(state, {});
-    if (state.value & Ci.nsIAccessibleStates.STATE_BUSY) {
+    if (isStale(doc)) {
       return this.once("document-ready").then(docAcc => this.addRef(docAcc));
     }
 
     return Promise.resolve(this.addRef(doc));
   },
 
   /**
    * Get an accessible actor for a domnode actor.
@@ -572,29 +587,34 @@ const AccessibleWalkerActor = ActorClass
    * @param {nsIAccessibleEvent} subject
    *                                      accessible event object.
    */
   observe(subject) {
     let event = subject.QueryInterface(nsIAccessibleEvent);
     let rawAccessible = event.accessible;
     let accessible = this.getRef(rawAccessible);
 
+    if ((rawAccessible instanceof Ci.nsIAccessibleDocument) && !accessible) {
+      let rootDocAcc = this.getRawAccessibleFor(this.rootDoc);
+      if (rawAccessible === rootDocAcc && !isStale(rawAccessible)) {
+        this.purgeSubtree(rawAccessible, event.DOMNode);
+        // If it's a top level document notify listeners about the document
+        // being ready.
+        events.emit(this, "document-ready", rawAccessible);
+      }
+    }
+
     switch (event.eventType) {
       case EVENT_STATE_CHANGE:
         let { state, isEnabled } = event.QueryInterface(nsIAccessibleStateChangeEvent);
         let isBusy = state & Ci.nsIAccessibleStates.STATE_BUSY;
         // Accessible document is recreated.
         if (isBusy && !isEnabled && rawAccessible instanceof Ci.nsIAccessibleDocument) {
           // Remove its existing cache from tree.
           this.purgeSubtree(rawAccessible, event.DOMNode);
-          // If it's a top level document notify listeners about the document
-          // being ready.
-          if (event.DOMNode == this.rootDoc) {
-            events.emit(this, "document-ready", rawAccessible);
-          }
         }
 
         if (accessible) {
           // Only propagate state change events for active accessibles.
           if (isBusy && isEnabled) {
             if (rawAccessible instanceof Ci.nsIAccessibleDocument) {
               // Remove its existing cache from tree.
               this.purgeSubtree(rawAccessible, event.DOMNode);
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -4707,16 +4707,26 @@ nsDocShell::DisplayLoadError(nsresult aE
     }
 
     // DisplayLoadError requires a non-empty messageStr to proceed and call
     // LoadErrorPage. If the page doesn't have a title, we will use a blank
     // space which will be trimmed and thus treated as empty by the front-end.
     if (messageStr.IsEmpty()) {
       messageStr.AssignLiteral(u" ");
     }
+  } else if (NS_ERROR_BUILDID_MISMATCH == aError) {
+    errorPage.AssignLiteral("restartrequired");
+    error = "restartrequired";
+
+    // DisplayLoadError requires a non-empty messageStr to proceed and call
+    // LoadErrorPage. If the page doesn't have a title, we will use a blank
+    // space which will be trimmed and thus treated as empty by the front-end.
+    if (messageStr.IsEmpty()) {
+      messageStr.AssignLiteral(u" ");
+    }
   } else {
     // Errors requiring simple formatting
     switch (aError) {
       case NS_ERROR_MALFORMED_URI:
         // URI is malformed
         error = "malformedURI";
         errorDescriptionID = "malformedURI2";
         break;
--- a/dom/base/DocGroup.cpp
+++ b/dom/base/DocGroup.cpp
@@ -154,27 +154,35 @@ DocGroup::AbstractMainThreadFor(TaskCate
 
 bool*
 DocGroup::GetValidAccessPtr()
 {
   return mTabGroup->GetValidAccessPtr();
 }
 
 void
-DocGroup::SignalSlotChange(const HTMLSlotElement* aSlot)
+DocGroup::SignalSlotChange(HTMLSlotElement& aSlot)
 {
-  if (mSignalSlotList.Contains(aSlot)) {
-    return;
-  }
-
-  mSignalSlotList.AppendElement(const_cast<HTMLSlotElement*>(aSlot));
+  MOZ_ASSERT(!mSignalSlotList.Contains(&aSlot));
+  mSignalSlotList.AppendElement(&aSlot);
 
   if (!sPendingDocGroups) {
     // Queue a mutation observer compound microtask.
     nsDOMMutationObserver::QueueMutationObserverMicroTask();
     sPendingDocGroups = new AutoTArray<RefPtr<DocGroup>, 2>;
   }
 
   sPendingDocGroups->AppendElement(this);
 }
 
+void
+DocGroup::MoveSignalSlotListTo(nsTArray<RefPtr<HTMLSlotElement>>& aDest)
+{
+  aDest.SetCapacity(aDest.Length() + mSignalSlotList.Length());
+  for (RefPtr<HTMLSlotElement>& slot : mSignalSlotList) {
+    slot->RemovedFromSignalSlotList();
+    aDest.AppendElement(Move(slot));
+  }
+  mSignalSlotList.Clear();
+}
+
 }
 }
--- a/dom/base/DocGroup.h
+++ b/dom/base/DocGroup.h
@@ -108,29 +108,21 @@ public:
     mTabGroup->ValidateAccess();
   }
 
   // Return a pointer that can be continually checked to see if access to this
   // DocGroup is valid. This pointer should live at least as long as the
   // DocGroup.
   bool* GetValidAccessPtr();
 
-  // Append aSlot to the list of signal slot list, if it's not in it already
-  // list, and queue a mutation observer microtask.
-  void SignalSlotChange(const mozilla::dom::HTMLSlotElement* aSlot);
+  // Append aSlot to the list of signal slot list, and queue a mutation observer
+  // microtask.
+  void SignalSlotChange(HTMLSlotElement& aSlot);
 
-  const nsTArray<RefPtr<HTMLSlotElement>>& SignalSlotList() const
-  {
-    return mSignalSlotList;
-  }
-
-  void ClearSignalSlotList()
-  {
-    mSignalSlotList.Clear();
-  }
+  void MoveSignalSlotListTo(nsTArray<RefPtr<HTMLSlotElement>>& aDest);
 
   // List of DocGroups that has non-empty signal slot list.
   static AutoTArray<RefPtr<DocGroup>, 2>* sPendingDocGroups;
 
 private:
   DocGroup(TabGroup* aTabGroup, const nsACString& aKey);
   ~DocGroup();
 
--- a/dom/base/Selection.cpp
+++ b/dom/base/Selection.cpp
@@ -403,53 +403,37 @@ void printRange(nsRange *aDomRange)
   printf("range: 0x%lx\t start: 0x%lx %ld, \t end: 0x%lx,%ld\n",
          (unsigned long)aDomRange,
          (unsigned long)startNode, (long)startOffset,
          (unsigned long)endNode, (long)endOffset);
 
 }
 #endif /* PRINT_RANGE */
 
-NS_IMETHODIMP
-Selection::ToString(nsAString& aReturn)
+void
+Selection::Stringify(nsAString& aResult)
 {
   // We need FlushType::Frames here to make sure frames have been created for
   // the selected content.  Use mFrameSelection->GetShell() which returns
   // null if the Selection has been disconnected (the shell is Destroyed).
   nsCOMPtr<nsIPresShell> shell =
     mFrameSelection ? mFrameSelection->GetShell() : nullptr;
   if (!shell) {
-    aReturn.Truncate();
-    return NS_OK;
+    aResult.Truncate();
+    return;
   }
   shell->FlushPendingNotifications(FlushType::Frames);
 
-  return ToStringWithFormat("text/plain",
-                            nsIDocumentEncoder::SkipInvisibleContent,
-                            0, aReturn);
-}
-
-void
-Selection::Stringify(nsAString& aResult)
-{
-  // Eat the error code
-  ToString(aResult);
-}
-
-NS_IMETHODIMP
-Selection::ToStringWithFormat(const char* aFormatType, uint32_t aFlags,
-                              int32_t aWrapCol, nsAString& aReturn)
-{
-  ErrorResult result;
-  NS_ConvertUTF8toUTF16 format(aFormatType);
-  ToStringWithFormat(format, aFlags, aWrapCol, aReturn, result);
-  if (result.Failed()) {
-    return result.StealNSResult();
+  IgnoredErrorResult rv;
+  ToStringWithFormat(NS_LITERAL_STRING("text/plain"),
+                     nsIDocumentEncoder::SkipInvisibleContent,
+                     0, aResult, rv);
+  if (rv.Failed()) {
+    aResult.Truncate();
   }
-  return NS_OK;
 }
 
 void
 Selection::ToStringWithFormat(const nsAString& aFormatType, uint32_t aFlags,
                               int32_t aWrapCol, nsAString& aReturn,
                               ErrorResult& aRv)
 {
   nsresult rv = NS_OK;
@@ -488,48 +472,26 @@ Selection::ToStringWithFormat(const nsAS
     encoder->SetWrapColumn(aWrapCol);
 
   rv = encoder->EncodeToString(aReturn);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
   }
 }
 
-NS_IMETHODIMP
-Selection::SetInterlinePosition(bool aHintRight)
-{
-  ErrorResult result;
-  SetInterlinePosition(aHintRight, result);
-  if (result.Failed()) {
-    return result.StealNSResult();
-  }
-  return NS_OK;
-}
-
 void
 Selection::SetInterlinePosition(bool aHintRight, ErrorResult& aRv)
 {
   if (!mFrameSelection) {
     aRv.Throw(NS_ERROR_NOT_INITIALIZED); // Can't do selection
     return;
   }
   mFrameSelection->SetHint(aHintRight ? CARET_ASSOCIATE_AFTER : CARET_ASSOCIATE_BEFORE);
 }
 
-NS_IMETHODIMP
-Selection::GetInterlinePosition(bool* aHintRight)
-{
-  ErrorResult result;
-  *aHintRight = GetInterlinePosition(result);
-  if (result.Failed()) {
-    return result.StealNSResult();
-  }
-  return NS_OK;
-}
-
 bool
 Selection::GetInterlinePosition(ErrorResult& aRv)
 {
   if (!mFrameSelection) {
     aRv.Throw(NS_ERROR_NOT_INITIALIZED); // Can't do selection
     return false;
   }
   return mFrameSelection->GetHint() == CARET_ASSOCIATE_AFTER;
@@ -558,36 +520,37 @@ Selection::SetCaretBidiLevel(const Nulla
     mFrameSelection->UndefineCaretBidiLevel();
   } else {
     mFrameSelection->SetCaretBidiLevel(aCaretBidiLevel.Value());
   }
 }
 
 nsresult
 Selection::GetTableCellLocationFromRange(nsRange* aRange,
-                                         int32_t* aSelectionType,
+                                         TableSelection* aSelectionType,
                                          int32_t* aRow, int32_t* aCol)
 {
   if (!aRange || !aSelectionType || !aRow || !aCol)
     return NS_ERROR_NULL_POINTER;
 
-  *aSelectionType = nsISelectionPrivate::TABLESELECTION_NONE;
+  *aSelectionType = TableSelection::None;
   *aRow = 0;
   *aCol = 0;
 
   // Must have access to frame selection to get cell info
   if (!mFrameSelection) return NS_OK;
 
   nsresult result = GetTableSelectionType(aRange, aSelectionType);
   if (NS_FAILED(result)) return result;
 
   // Don't fail if range does not point to a single table cell,
   //  let aSelectionType tell user if we don't have a cell
-  if (*aSelectionType  != nsISelectionPrivate::TABLESELECTION_CELL)
+  if (*aSelectionType  != TableSelection::Cell) {
     return NS_OK;
+  }
 
   // Get the child content (the cell) pointed to by starting node of range
   // We do minimal checking since GetTableSelectionType assures
   //   us that this really is a table cell
   nsCOMPtr<nsIContent> child = aRange->GetChildAtStartOffset();
   if (!child)
     return NS_ERROR_FAILURE;
 
@@ -625,84 +588,84 @@ Selection::AddTableCellRange(nsRange* aR
     return NS_OK;
 
   if (!aRange)
     return NS_ERROR_NULL_POINTER;
 
   nsresult result;
 
   // Get if we are adding a cell selection and the row, col of cell if we are
-  int32_t newRow, newCol, tableMode;
+  int32_t newRow, newCol;
+  TableSelection tableMode;
   result = GetTableCellLocationFromRange(aRange, &tableMode, &newRow, &newCol);
   if (NS_FAILED(result)) return result;
 
   // If not adding a cell range, we are done here
-  if (tableMode != nsISelectionPrivate::TABLESELECTION_CELL)
+  if (tableMode != TableSelection::Cell)
   {
     mFrameSelection->mSelectingTableCellMode = tableMode;
     // Don't fail if range isn't a selected cell, aDidAddRange tells caller if we didn't proceed
     return NS_OK;
   }
 
   // Set frame selection mode only if not already set to a table mode
   //  so we don't lose the select row and column flags (not detected by getTableCellLocation)
-  if (mFrameSelection->mSelectingTableCellMode == TABLESELECTION_NONE)
+  if (mFrameSelection->mSelectingTableCellMode == TableSelection::None)
     mFrameSelection->mSelectingTableCellMode = tableMode;
 
   *aDidAddRange = true;
   return AddItem(aRange, aOutIndex);
 }
 
-//TODO: Figure out TABLESELECTION_COLUMN and TABLESELECTION_ALLCELLS
+//TODO: Figure out TableSelection::Column and TableSelection::AllCells
 nsresult
-Selection::GetTableSelectionType(nsIDOMRange* aDOMRange,
-                                 int32_t* aTableSelectionType)
+Selection::GetTableSelectionType(nsRange* aRange,
+                                 TableSelection* aTableSelectionType)
 {
-  if (!aDOMRange || !aTableSelectionType)
+  if (!aRange || !aTableSelectionType)
     return NS_ERROR_NULL_POINTER;
-  nsRange* range = static_cast<nsRange*>(aDOMRange);
-
-  *aTableSelectionType = nsISelectionPrivate::TABLESELECTION_NONE;
+
+  *aTableSelectionType = TableSelection::None;
 
   // Must have access to frame selection to get cell info
   if(!mFrameSelection) return NS_OK;
 
-  nsINode* startNode = range->GetStartContainer();
+  nsINode* startNode = aRange->GetStartContainer();
   if (!startNode) return NS_ERROR_FAILURE;
 
-  nsINode* endNode = range->GetEndContainer();
+  nsINode* endNode = aRange->GetEndContainer();
   if (!endNode) return NS_ERROR_FAILURE;
 
   // Not a single selected node
   if (startNode != endNode) return NS_OK;
 
-  nsIContent* child = range->GetChildAtStartOffset();
+  nsIContent* child = aRange->GetChildAtStartOffset();
 
   // Not a single selected node
-  if (!child || child->GetNextSibling() != range->GetChildAtEndOffset()) {
+  if (!child || child->GetNextSibling() != aRange->GetChildAtEndOffset()) {
     return NS_OK;
   }
 
   nsIContent* startContent = static_cast<nsIContent*>(startNode);
   if (!(startNode->IsElement() && startContent->IsHTMLElement())) {
     // Implies a check for being an element; if we ever make this work
     // for non-HTML, need to keep checking for elements.
     return NS_OK;
   }
 
   if (startContent->IsHTMLElement(nsGkAtoms::tr))
   {
-    *aTableSelectionType = nsISelectionPrivate::TABLESELECTION_CELL;
+    *aTableSelectionType = TableSelection::Cell;
   }
   else //check to see if we are selecting a table or row (column and all cells not done yet)
   {
     if (child->IsHTMLElement(nsGkAtoms::table))
-      *aTableSelectionType = nsISelectionPrivate::TABLESELECTION_TABLE;
+      *aTableSelectionType = TableSelection::Table;
     else if (child->IsHTMLElement(nsGkAtoms::tr))
-      *aTableSelectionType = nsISelectionPrivate::TABLESELECTION_ROW;
+      *aTableSelectionType = TableSelection::Row;
   }
 
   return NS_OK;
 }
 
 Selection::Selection()
   : mCachedOffsetForFrame(nullptr)
   , mDirection(eDirNext)
@@ -794,20 +757,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameSelection)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectionListeners)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Selection)
 
 // QueryInterface implementation for Selection
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Selection)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY(nsISelection)
-  NS_INTERFACE_MAP_ENTRY(nsISelectionPrivate)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISelection)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_ADDREF(Selection)
 NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE(Selection)
 
 const RangeBoundary&
 Selection::AnchorRef()
 {
@@ -833,55 +794,16 @@ Selection::FocusRef()
 
   if (GetDirection() == eDirNext){
     return mAnchorFocusRange->EndRef();
   }
 
   return mAnchorFocusRange->StartRef();
 }
 
-NS_IMETHODIMP
-Selection::GetAnchorNode(nsIDOMNode** aAnchorNode)
-{
-  nsINode* anchorNode = GetAnchorNode();
-  if (anchorNode) {
-    return CallQueryInterface(anchorNode, aAnchorNode);
-  }
-
-  *aAnchorNode = nullptr;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-Selection::GetAnchorOffset(int32_t* aAnchorOffset)
-{
-  *aAnchorOffset = static_cast<int32_t>(AnchorOffset());
-  return NS_OK;
-}
-
-// note: this can return a nil focus node
-NS_IMETHODIMP
-Selection::GetFocusNode(nsIDOMNode** aFocusNode)
-{
-  nsINode* focusNode = GetFocusNode();
-  if (focusNode) {
-    return CallQueryInterface(focusNode, aFocusNode);
-  }
-
-  *aFocusNode = nullptr;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-Selection::GetFocusOffset(int32_t* aFocusOffset)
-{
-  *aFocusOffset = static_cast<int32_t>(FocusOffset());
-  return NS_OK;
-}
-
 void
 Selection::SetAnchorFocusRange(int32_t indx)
 {
   if (indx >= (int32_t)mRanges.Length())
     return;
   if (indx < 0) //release all
   {
     mAnchorFocusRange = nullptr;
@@ -1076,17 +998,17 @@ Selection::AddItem(nsRange* aItem, int32
 
     nsIDocument* doc = GetParentObject();
     bool selectEventsEnabled =
       nsFrameSelection::sSelectionEventsEnabled ||
       (doc && nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()));
 
     if (!aNoStartSelect &&
         mSelectionType == SelectionType::eNormal &&
-        selectEventsEnabled && Collapsed() &&
+        selectEventsEnabled && IsCollapsed() &&
         !IsBlockingSelectionChangeEvents()) {
       // First, we generate the ranges to add with a scratch range, which is a
       // clone of the original range passed in. We do this seperately, because the
       // selectstart event could have caused the world to change, and required
       // ranges to be re-generated
       RefPtr<nsRange> scratchRange = aItem->CloneRange();
       UserSelectRangesToAdd(scratchRange, rangesToAdd);
       bool newRangesNonEmpty = rangesToAdd.Length() > 1 ||
@@ -1327,24 +1249,16 @@ Selection::Clear(nsPresContext* aPresCon
       mFrameSelection->GetDisplaySelection() ==
       nsISelectionController::SELECTION_ATTENTION) {
     mFrameSelection->SetDisplaySelection(nsISelectionController::SELECTION_ON);
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-Selection::GetType(int16_t* aType)
-{
-  NS_ENSURE_ARG_POINTER(aType);
-  *aType = ToRawSelectionType(Type());
-  return NS_OK;
-}
-
 // RangeMatches*Point
 //
 //    Compares the range beginning or ending point, and returns true if it
 //    exactly matches the given DOM point.
 
 static inline bool
 RangeMatchesBeginPoint(nsRange* aRange, nsINode* aNode, int32_t aOffset)
 {
@@ -1373,59 +1287,16 @@ Selection::EqualsRangeAtPoint(
     nsRange* range = mRanges[aRangeIndex].mRange;
     if (RangeMatchesBeginPoint(range, aBeginNode, aBeginOffset) &&
         RangeMatchesEndPoint(range, aEndNode, aEndOffset))
       return true;
   }
   return false;
 }
 
-// Selection::GetRangesForInterval
-//
-//    XPCOM wrapper for the nsTArray version
-
-NS_IMETHODIMP
-Selection::GetRangesForInterval(nsIDOMNode* aBeginNode, int32_t aBeginOffset,
-                                nsIDOMNode* aEndNode, int32_t aEndOffset,
-                                bool aAllowAdjacent,
-                                uint32_t* aResultCount,
-                                nsIDOMRange*** aResults)
-{
-  if (!aBeginNode || ! aEndNode || ! aResultCount || ! aResults)
-    return NS_ERROR_NULL_POINTER;
-
-  *aResultCount = 0;
-  *aResults = nullptr;
-
-  nsTArray<RefPtr<nsRange>> results;
-  ErrorResult result;
-  nsCOMPtr<nsINode> beginNode = do_QueryInterface(aBeginNode);
-  nsCOMPtr<nsINode> endNode = do_QueryInterface(aEndNode);
-  NS_ENSURE_TRUE(beginNode && endNode, NS_ERROR_NULL_POINTER);
-  GetRangesForInterval(*beginNode, aBeginOffset, *endNode, aEndOffset,
-                       aAllowAdjacent, results, result);
-  if (result.Failed()) {
-    return result.StealNSResult();
-  }
-  *aResultCount = results.Length();
-  if (*aResultCount == 0) {
-    return NS_OK;
-  }
-
-  *aResults = static_cast<nsIDOMRange**>
-                         (moz_xmalloc(sizeof(nsIDOMRange*) * *aResultCount));
-  NS_ENSURE_TRUE(*aResults, NS_ERROR_OUT_OF_MEMORY);
-
-  for (uint32_t i = 0; i < *aResultCount; i++) {
-    (*aResults)[i] = results[i].forget().take();
-  }
-  return NS_OK;
-}
-
-
 void
 Selection::GetRangesForInterval(nsINode& aBeginNode, int32_t aBeginOffset,
                                 nsINode& aEndNode, int32_t aEndOffset,
                                 bool aAllowAdjacent,
                                 nsTArray<RefPtr<nsRange>>& aReturn,
                                 mozilla::ErrorResult& aRv)
 {
   nsTArray<nsRange*> results;
@@ -1438,36 +1309,16 @@ Selection::GetRangesForInterval(nsINode&
   }
 
   aReturn.SetLength(results.Length());
   for (uint32_t i = 0; i < results.Length(); ++i) {
     aReturn[i] = results[i]; // AddRefs
   }
 }
 
-// Selection::GetRangesForIntervalArray
-//
-//    Fills a nsTArray with the ranges overlapping the range specified by
-//    the given endpoints. Ranges in the selection exactly adjacent to the
-//    input range are not returned unless aAllowAdjacent is set.
-//
-//    For example, if the following ranges were in the selection
-//    (assume everything is within the same node)
-//
-//    Start Offset: 0 2 7 9
-//      End Offset: 2 5 9 10
-//
-//    and passed aBeginOffset of 2 and aEndOffset of 9, then with
-//    aAllowAdjacent set, all the ranges should be returned. If
-//    aAllowAdjacent was false, the ranges [2, 5] and [7, 9] only
-//    should be returned
-//
-//    Now that overlapping ranges are disallowed, there can be a maximum of
-//    2 adjacent ranges
-
 nsresult
 Selection::GetRangesForIntervalArray(nsINode* aBeginNode, int32_t aBeginOffset,
                                      nsINode* aEndNode, int32_t aEndOffset,
                                      bool aAllowAdjacent,
                                      nsTArray<nsRange*>* aRanges)
 {
   aRanges->Clear();
   int32_t startIndex, endIndex;
@@ -2007,48 +1858,33 @@ Selection::Repaint(nsPresContext* aPresC
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-Selection::GetCanCacheFrameOffset(bool* aCanCacheFrameOffset)
-{
-  NS_ENSURE_ARG_POINTER(aCanCacheFrameOffset);
-
-  if (mCachedOffsetForFrame)
-    *aCanCacheFrameOffset = mCachedOffsetForFrame->mCanCacheFrameOffset;
-  else
-    *aCanCacheFrameOffset = false;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
+void
 Selection::SetCanCacheFrameOffset(bool aCanCacheFrameOffset)
 {
   if (!mCachedOffsetForFrame) {
     mCachedOffsetForFrame = new CachedOffsetForFrame;
   }
 
   mCachedOffsetForFrame->mCanCacheFrameOffset = aCanCacheFrameOffset;
 
   // clean up cached frame when turn off cache
   // fix bug 207936
   if (!aCanCacheFrameOffset) {
     mCachedOffsetForFrame->mLastCaretFrame = nullptr;
   }
-
-  return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 Selection::GetCachedFrameOffset(nsIFrame* aFrame, int32_t inOffset,
                                 nsPoint& aPoint)
 {
   if (!mCachedOffsetForFrame) {
     mCachedOffsetForFrame = new CachedOffsetForFrame;
   }
 
   nsresult rv = NS_OK;
@@ -2070,34 +1906,32 @@ Selection::GetCachedFrameOffset(nsIFrame
        mCachedOffsetForFrame->mLastCaretFrame = aFrame;
        mCachedOffsetForFrame->mLastContentOffset = inOffset;
      }
   }
 
   return rv;
 }
 
-NS_IMETHODIMP
-Selection::GetAncestorLimiter(nsIContent** aContent)
+nsIContent*
+Selection::GetAncestorLimiter() const
 {
   if (mFrameSelection) {
-    nsCOMPtr<nsIContent> c = mFrameSelection->GetAncestorLimiter();
-    c.forget(aContent);
+    return mFrameSelection->GetAncestorLimiter();
   }
-  return NS_OK;
+  return nullptr;
 }
 
-NS_IMETHODIMP
-Selection::SetAncestorLimiter(nsIContent* aContent)
+void
+Selection::SetAncestorLimiter(nsIContent* aLimiter)
 {
   if (mFrameSelection) {
     RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
-    frameSelection->SetAncestorLimiter(aContent);
+    frameSelection->SetAncestorLimiter(aLimiter);
   }
-  return NS_OK;
 }
 
 RangeData*
 Selection::FindRangeData(nsIDOMRange* aRange)
 {
   NS_ENSURE_TRUE(aRange, nullptr);
   for (uint32_t i = 0; i < mRanges.Length(); i++) {
     if (mRanges[i].mRange == aRange)
@@ -2333,17 +2167,17 @@ Selection::AddRangeInternal(nsRange& aRa
   if (rangeIndex < 0) {
     return;
   }
 
   SetAnchorFocusRange(rangeIndex);
 
   // Make sure the caret appears on the next line, if at a newline
   if (mSelectionType == SelectionType::eNormal) {
-    SetInterlinePosition(true);
+    SetInterlinePosition(true, IgnoreErrors());
   }
 
   RefPtr<nsPresContext>  presContext = GetPresContext();
   SelectFrames(presContext, &aRange, true);
 
   if (!mFrameSelection)
     return;//nothing to do
 
@@ -2442,29 +2276,16 @@ Selection::RemoveRange(nsRange& aRange, 
   }
 }
 
 
 
 /*
  * Collapse sets the whole selection to be one point.
  */
-NS_IMETHODIMP
-Selection::Collapse(nsIDOMNode* aContainer, int32_t aOffset)
-{
-  nsCOMPtr<nsINode> container = do_QueryInterface(aContainer);
-  return Collapse(RawRangeBoundary(container, aOffset));
-}
-
-NS_IMETHODIMP
-Selection::CollapseNative(nsINode* aContainer, int32_t aOffset)
-{
-  return Collapse(RawRangeBoundary(aContainer, aOffset));
-}
-
 void
 Selection::CollapseJS(nsINode* aContainer, uint32_t aOffset, ErrorResult& aRv)
 {
   AutoRestore<bool> calledFromJSRestorer(mCalledByJS);
   mCalledByJS = true;
   if (!aContainer) {
     RemoveAllRanges(aRv);
     return;
@@ -2591,24 +2412,16 @@ Selection::Collapse(const RawRangeBounda
     aRv.Throw(result);
   }
 }
 
 /*
  * Sets the whole selection to be one point
  * at the start of the current selection
  */
-NS_IMETHODIMP
-Selection::CollapseToStart()
-{
-  ErrorResult result;
-  CollapseToStart(result);
-  return result.StealNSResult();
-}
-
 void
 Selection::CollapseToStartJS(ErrorResult& aRv)
 {
   AutoRestore<bool> calledFromJSRestorer(mCalledByJS);
   mCalledByJS = true;
   CollapseToStart(aRv);
 }
 
@@ -2638,24 +2451,16 @@ Selection::CollapseToStart(ErrorResult& 
   }
   Collapse(*container, firstRange->StartOffset(), aRv);
 }
 
 /*
  * Sets the whole selection to be one point
  * at the end of the current selection
  */
-NS_IMETHODIMP
-Selection::CollapseToEnd()
-{
-  ErrorResult result;
-  CollapseToEnd(result);
-  return result.StealNSResult();
-}
-
 void
 Selection::CollapseToEndJS(ErrorResult& aRv)
 {
   AutoRestore<bool> calledFromJSRestorer(mCalledByJS);
   mCalledByJS = true;
   CollapseToEnd(aRv);
 }
 
@@ -2682,32 +2487,16 @@ Selection::CollapseToEnd(ErrorResult& aR
   nsINode* container = lastRange->GetEndContainer();
   if (!container) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
   Collapse(*container, lastRange->EndOffset(), aRv);
 }
 
-/* virtual */
-bool
-Selection::Collapsed()
-{
-  return IsCollapsed();
-}
-
-NS_IMETHODIMP
-Selection::GetIsCollapsed(bool* aIsCollapsed)
-{
-  NS_ENSURE_TRUE(aIsCollapsed, NS_ERROR_NULL_POINTER);
-
-  *aIsCollapsed = IsCollapsed();
-  return NS_OK;
-}
-
 void
 Selection::GetType(nsAString& aOutType) const
 {
   if (!RangeCount()) {
     aOutType.AssignLiteral("None");
   } else if (IsCollapsed()) {
     aOutType.AssignLiteral("Caret");
   } else {
@@ -2737,17 +2526,17 @@ Selection::GetRangeAt(int32_t aIndex) co
 /*
 utility function
 */
 nsresult
 Selection::SetAnchorFocusToRange(nsRange* aRange)
 {
   NS_ENSURE_STATE(mAnchorFocusRange);
 
-  bool collapsed = Collapsed();
+  bool collapsed = IsCollapsed();
 
   nsresult res = RemoveItem(mAnchorFocusRange);
   if (NS_FAILED(res))
     return res;
 
   int32_t aOutIndex = -1;
   res = AddItem(aRange, &aOutIndex, !collapsed);
   if (NS_FAILED(res))
@@ -2819,29 +2608,16 @@ 1  2  a deselect from 1 to 2
 2  1  a = continue selection from 2 to 1
 */
 
 
 /*
  * Extend extends the selection away from the anchor.
  * We don't need to know the direction, because we always change the focus.
  */
-NS_IMETHODIMP
-Selection::Extend(nsIDOMNode* aContainer, int32_t aOffset)
-{
-  nsCOMPtr<nsINode> container = do_QueryInterface(aContainer);
-  return Extend(container, aOffset);
-}
-
-NS_IMETHODIMP
-Selection::ExtendNative(nsINode* aContainer, int32_t aOffset)
-{
-  return Extend(aContainer, aOffset);
-}
-
 void
 Selection::ExtendJS(nsINode& aContainer, uint32_t aOffset, ErrorResult& aRv)
 {
   AutoRestore<bool> calledFromJSRestorer(mCalledByJS);
   mCalledByJS = true;
   Extend(aContainer, aOffset, aRv);
 }
 
@@ -3139,26 +2915,16 @@ Selection::Extend(nsINode& aContainer, u
   // XXX Why doesn't this call Selection::NotifySelectionListener() directly?
   RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
   res = frameSelection->NotifySelectionListeners(GetType());
   if (NS_FAILED(res)) {
     aRv.Throw(res);
   }
 }
 
-NS_IMETHODIMP
-Selection::SelectAllChildren(nsIDOMNode* aNode)
-{
-  ErrorResult result;
-  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
-  NS_ENSURE_TRUE(node, NS_ERROR_INVALID_ARG);
-  SelectAllChildren(*node, result);
-  return result.StealNSResult();
-}
-
 void
 Selection::SelectAllChildrenJS(nsINode& aNode, ErrorResult& aRv)
 {
   AutoRestore<bool> calledFromJSRestorer(mCalledByJS);
   mCalledByJS = true;
   SelectAllChildren(aNode, aRv);
 }
 
@@ -3183,33 +2949,16 @@ Selection::SelectAllChildren(nsINode& aN
   Collapse(aNode, 0, aRv);
   if (aRv.Failed()) {
     return;
   }
 
   Extend(aNode, aNode.GetChildCount(), aRv);
 }
 
-NS_IMETHODIMP
-Selection::ContainsNode(nsIDOMNode* aNode, bool aAllowPartial, bool* aYes)
-{
-  if (!aYes) {
-    return NS_ERROR_NULL_POINTER;
-  }
-  *aYes = false;
-
-  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
-  if (!node) {
-    return NS_ERROR_NULL_POINTER;
-  }
-  ErrorResult result;
-  *aYes = ContainsNode(*node, aAllowPartial, result);
-  return result.StealNSResult();
-}
-
 bool
 Selection::ContainsNode(nsINode& aNode, bool aAllowPartial, ErrorResult& aRv)
 {
   nsresult rv;
   if (mRanges.Length() == 0) {
     return false;
   }
 
@@ -3502,50 +3251,31 @@ Selection::PostScrollSelectionIntoViewEv
 
   mScrollEvent =
     new ScrollSelectionIntoViewEvent(this, aRegion, aVertical, aHorizontal,
                                      aFlags);
   refreshDriver->AddEarlyRunner(mScrollEvent.get());
   return NS_OK;
 }
 
-NS_IMETHODIMP
-Selection::ScrollIntoView(SelectionRegion aRegion, bool aIsSynchronous,
-                          int16_t aVPercent, int16_t aHPercent)
-{
-  ErrorResult result;
-  ScrollIntoView(aRegion, aIsSynchronous, aVPercent, aHPercent, result);
-  if (result.Failed()) {
-    return result.StealNSResult();
-  }
-  return NS_OK;
-}
-
 void
 Selection::ScrollIntoView(int16_t aRegion, bool aIsSynchronous,
                           int16_t aVPercent, int16_t aHPercent,
                           ErrorResult& aRv)
 {
-  nsresult rv = ScrollIntoViewInternal(aRegion, aIsSynchronous,
-                                       nsIPresShell::ScrollAxis(aVPercent),
-                                       nsIPresShell::ScrollAxis(aHPercent));
+  int32_t flags = aIsSynchronous ? Selection::SCROLL_SYNCHRONOUS : 0;
+  nsresult rv = ScrollIntoView(aRegion,
+                               nsIPresShell::ScrollAxis(aVPercent),
+                               nsIPresShell::ScrollAxis(aHPercent),
+                               flags);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
   }
 }
 
-NS_IMETHODIMP
-Selection::ScrollIntoViewInternal(SelectionRegion aRegion, bool aIsSynchronous,
-                                  nsIPresShell::ScrollAxis aVertical,
-                                  nsIPresShell::ScrollAxis aHorizontal)
-{
-  return ScrollIntoView(aRegion, aVertical, aHorizontal,
-                        aIsSynchronous ? Selection::SCROLL_SYNCHRONOUS : 0);
-}
-
 nsresult
 Selection::ScrollIntoView(SelectionRegion aRegion,
                           nsIPresShell::ScrollAxis aVertical,
                           nsIPresShell::ScrollAxis aHorizontal,
                           int32_t aFlags)
 {
   if (!mFrameSelection)
     return NS_OK;//nothing to do
@@ -3602,60 +3332,27 @@ Selection::ScrollIntoView(SelectionRegio
     flags |= nsIPresShell::SCROLL_OVERFLOW_HIDDEN;
   }
 
   presShell->ScrollFrameRectIntoView(frame, rect, aVertical, aHorizontal,
     flags);
   return NS_OK;
 }
 
-NS_IMETHODIMP
+void
 Selection::AddSelectionListener(nsISelectionListener* aNewListener)
 {
-  if (!aNewListener)
-    return NS_ERROR_NULL_POINTER;
-  ErrorResult result;
-  AddSelectionListener(aNewListener, result);
-  if (result.Failed()) {
-    return result.StealNSResult();
-  }
-  return NS_OK;
+  MOZ_ASSERT(aNewListener);
+  mSelectionListeners.AppendElement(aNewListener); // AddRefs
 }
 
 void
-Selection::AddSelectionListener(nsISelectionListener* aNewListener,
-                                ErrorResult& aRv)
-{
-  bool result = mSelectionListeners.AppendElement(aNewListener, fallible); // AddRefs
-  if (!result) {
-    aRv.Throw(NS_ERROR_FAILURE);
-  }
-}
-
-NS_IMETHODIMP
 Selection::RemoveSelectionListener(nsISelectionListener* aListenerToRemove)
 {
-  if (!aListenerToRemove)
-    return NS_ERROR_NULL_POINTER;
-  ErrorResult result;
-  RemoveSelectionListener(aListenerToRemove, result);
-  if (result.Failed()) {
-    return result.StealNSResult();
-  }
-  return NS_OK;
-}
-
-void
-Selection::RemoveSelectionListener(nsISelectionListener* aListenerToRemove,
-                                   ErrorResult& aRv)
-{
-  bool result = mSelectionListeners.RemoveElement(aListenerToRemove); // Releases
-  if (!result) {
-    aRv.Throw(NS_ERROR_FAILURE);
-  }
+  mSelectionListeners.RemoveElement(aListenerToRemove); // Releases
 }
 
 Element*
 Selection::GetCommonEditingHostForAllRanges()
 {
   Element* editingHost = nullptr;
   for (RangeData& rangeData : mRanges) {
     nsRange* range = rangeData.mRange;
@@ -3756,26 +3453,25 @@ Selection::NotifySelectionListeners()
   }
   if (mSelectionListeners.IsEmpty()) {
     // If there are no selection listeners, we're done!
     return NS_OK;
   }
   AutoTArray<nsCOMPtr<nsISelectionListener>, 8>
     selectionListeners(mSelectionListeners);
 
-  nsCOMPtr<nsIDOMDocument> domdoc;
+  nsCOMPtr<nsIDocument> doc;
   nsIPresShell* ps = GetPresShell();
   if (ps) {
-    // Avoid using QueryInterface() here because it can be expensive.
-    domdoc = static_cast<nsIDOMDocument*>(ps->GetDocument()->AsDOMNode());
+    doc = ps->GetDocument();
   }
 
   short reason = frameSelection->PopReason();
   for (auto& listener : selectionListeners) {
-    listener->NotifySelectionChanged(domdoc, this, reason);
+    listener->NotifySelectionChanged(doc, this, reason);
   }
   return NS_OK;
 }
 
 void
 Selection::StartBatchChanges()
 {
   if (mFrameSelection) {
@@ -3809,45 +3505,28 @@ Selection::RemoveSelectionChangeBlocker(
 }
 
 bool
 Selection::IsBlockingSelectionChangeEvents() const
 {
   return mSelectionChangeBlockerCount > 0;
 }
 
-NS_IMETHODIMP
-Selection::DeleteFromDocument()
-{
-  ErrorResult result;
-  DeleteFromDocument(result);
-  return result.StealNSResult();
-}
-
 void
 Selection::DeleteFromDocument(ErrorResult& aRv)
 {
   if (!mFrameSelection)
     return;//nothing to do
   RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
   nsresult rv = frameSelection->DeleteFromDocument();
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
   }
 }
 
-NS_IMETHODIMP
-Selection::Modify(const nsAString& aAlter, const nsAString& aDirection,
-                  const nsAString& aGranularity)
-{
-  ErrorResult result;
-  Modify(aAlter, aDirection, aGranularity, result);
-  return result.StealNSResult();
-}
-
 void
 Selection::Modify(const nsAString& aAlter, const nsAString& aDirection,
                   const nsAString& aGranularity, ErrorResult& aRv)
 {
   // Silently exit if there's no selection or no focus node.
   if (!mFrameSelection || !GetAnchorFocusRange() || !GetFocusNode()) {
     return;
   }
@@ -4024,17 +3703,17 @@ Selection::SetBaseAndExtent(nsINode& aAn
   }
 
   SetDirection(relativePosition > 0 ? eDirPrevious : eDirNext);
 }
 
 /** SelectionLanguageChange modifies the cursor Bidi level after a change in keyboard direction
  *  @param aLangRTL is true if the new language is right-to-left or false if the new language is left-to-right
  */
-NS_IMETHODIMP
+nsresult
 Selection::SelectionLanguageChange(bool aLangRTL)
 {
   if (!mFrameSelection)
     return NS_ERROR_NOT_INITIALIZED; // Can't do selection
 
   RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
 
   // if the direction of the language hasn't changed, nothing to do
@@ -4104,28 +3783,16 @@ Selection::SelectionLanguageChange(bool 
 
   // The caret might have moved, so invalidate the desired position
   // for future usages of up-arrow or down-arrow
   frameSelection->InvalidateDesiredPos();
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-Selection::SetColors(const nsAString& aForegroundColor,
-                     const nsAString& aBackgroundColor,
-                     const nsAString& aAltForegroundColor,
-                     const nsAString& aAltBackgroundColor)
-{
-  ErrorResult result;
-  SetColors(aForegroundColor, aBackgroundColor,
-            aAltForegroundColor, aAltBackgroundColor, result);
-  return result.StealNSResult();
-}
-
 void
 Selection::SetColors(const nsAString& aForegroundColor,
                      const nsAString& aBackgroundColor,
                      const nsAString& aAltForegroundColor,
                      const nsAString& aAltBackgroundColor,
                      ErrorResult& aRv)
 {
   if (mSelectionType != SelectionType::eFind) {
@@ -4186,40 +3853,22 @@ Selection::SetColors(const nsAString& aF
       return;
     }
     mCustomColors->mAltBackgroundColor = Some(altBackgroundColor);
   } else {
     mCustomColors->mAltBackgroundColor = Nothing();
   }
 }
 
-NS_IMETHODIMP
-Selection::ResetColors()
-{
-  ErrorResult result;
-  ResetColors(result);
-  return result.StealNSResult();
-}
-
 void
 Selection::ResetColors(ErrorResult& aRv)
 {
   mCustomColors = nullptr;
 }
 
-NS_IMETHODIMP_(nsDirection)
-Selection::GetSelectionDirection() {
-  return mDirection;
-}
-
-NS_IMETHODIMP_(void)
-Selection::SetSelectionDirection(nsDirection aDirection) {
-  mDirection = aDirection;
-}
-
 JSObject*
 Selection::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return mozilla::dom::SelectionBinding::Wrap(aCx, this, aGivenProto);
 }
 
 // AutoHideSelectionChanges
 AutoHideSelectionChanges::AutoHideSelectionChanges(const nsFrameSelection* aFrame)
--- a/dom/base/Selection.h
+++ b/dom/base/Selection.h
@@ -8,21 +8,23 @@
 #define mozilla_Selection_h__
 
 #include "nsIWeakReference.h"
 
 #include "mozilla/AutoRestore.h"
 #include "mozilla/RangeBoundary.h"
 #include "mozilla/TextRange.h"
 #include "mozilla/UniquePtr.h"
-#include "nsISelection.h"
+#include "mozilla/WeakPtr.h"
+#include "nsDirection.h"
+#include "nsIPresShell.h"  // For ScrollAxis
 #include "nsISelectionController.h"
 #include "nsISelectionListener.h"
-#include "nsISelectionPrivate.h"
 #include "nsRange.h"
+#include "nsTArrayForwardDeclare.h"
 #include "nsThreadUtils.h"
 #include "nsWrapperCache.h"
 
 struct CachedOffsetForFrame;
 class nsAutoScrollTimer;
 class nsIContentIterator;
 class nsIDocument;
 class nsIFrame;
@@ -31,56 +33,56 @@ class nsPIDOMWindowOuter;
 struct SelectionDetails;
 struct SelectionCustomColors;
 class nsCopySupport;
 class nsHTMLCopyEncoder;
 
 namespace mozilla {
 class ErrorResult;
 class HTMLEditor;
+enum class TableSelection : uint32_t;
 struct AutoPrepareFocusRange;
 namespace dom {
 class DocGroup;
 } // namespace dom
 } // namespace mozilla
 
 struct RangeData
 {
   explicit RangeData(nsRange* aRange)
     : mRange(aRange)
   {}
 
   RefPtr<nsRange> mRange;
   mozilla::TextRangeStyle mTextRangeStyle;
 };
 
+namespace mozilla {
+namespace dom {
+
 // Note, the ownership of mozilla::dom::Selection depends on which way the
 // object is created. When nsFrameSelection has created Selection,
 // addreffing/releasing the Selection object is aggregated to nsFrameSelection.
 // Otherwise normal addref/release is used.  This ensures that nsFrameSelection
 // is never deleted before its Selections.
-namespace mozilla {
-namespace dom {
-
-class Selection final : public nsISelection,
+class Selection final : public nsSupportsWeakReference,
                         public nsWrapperCache,
-                        public nsISelectionPrivate,
-                        public nsSupportsWeakReference
+                        public SupportsWeakPtr<Selection>
 {
 protected:
   virtual ~Selection();
 
 public:
   Selection();
   explicit Selection(nsFrameSelection *aList);
 
+  MOZ_DECLARE_WEAKREFERENCE_TYPENAME(Selection)
+
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Selection, nsISelection)
-  NS_DECL_NSISELECTION
-  NS_DECL_NSISELECTIONPRIVATE
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Selection)
 
   // match this up with EndbatchChanges. will stop ui updates while multiple
   // selection methods are called
   void StartBatchChanges();
 
   // match this up with StartBatchChanges
   void EndBatchChanges(int16_t aReason = nsISelectionListener::NO_REASON);
 
@@ -249,16 +251,19 @@ public:
   void CollapseToStartJS(mozilla::ErrorResult& aRv);
   void CollapseToEndJS(mozilla::ErrorResult& aRv);
 
   void ExtendJS(nsINode& aContainer, uint32_t aOffset,
                 mozilla::ErrorResult& aRv);
 
   void SelectAllChildrenJS(nsINode& aNode, mozilla::ErrorResult& aRv);
 
+  /**
+   * Deletes this selection from document the nodes belong to.
+   */
   void DeleteFromDocument(mozilla::ErrorResult& aRv);
 
   uint32_t RangeCount() const
   {
     return mRanges.Length();
   }
 
   void GetType(nsAString& aOutType) const;
@@ -273,27 +278,51 @@ public:
    * ranges later.  This tries to cache a removing range if it's possible.
    * If a range is not referred by anything else this selection, the range
    * can be reused later.  Otherwise, this works as same as RemoveAllRanges().
    */
   nsresult RemoveAllRangesTemporarily();
 
   void Stringify(nsAString& aResult);
 
+  /**
+   * Indicates whether the node is part of the selection. If partlyContained
+   * is true, the function returns true when some part of the node
+   * is part of the selection. If partlyContained is false, the
+   * function only returns true when the entire node is part of the selection.
+   */
   bool ContainsNode(nsINode& aNode, bool aPartlyContained, mozilla::ErrorResult& aRv);
 
   /**
    * Check to see if the given point is contained within the selection area. In
    * particular, this iterates through all the rects that make up the selection,
    * not just the bounding box, and checks to see if the given point is contained
    * in any one of them.
    * @param aPoint The point to check, relative to the root frame.
    */
   bool ContainsPoint(const nsPoint& aPoint);
 
+  /**
+   * Modifies the selection.  Note that the parameters are case-insensitive.
+   *
+   * @param alter can be one of { "move", "extend" }
+   *   - "move" collapses the selection to the end of the selection and
+   *      applies the movement direction/granularity to the collapsed
+   *      selection.
+   *   - "extend" leaves the start of the selection unchanged, and applies
+   *      movement direction/granularity to the end of the selection.
+   * @param direction can be one of { "forward", "backward", "left", "right" }
+   * @param granularity can be one of { "character", "word",
+   *                                    "line", "lineboundary" }
+   *
+   * @throws NS_ERROR_NOT_IMPLEMENTED if the granularity is "sentence",
+   * "sentenceboundary", "paragraph", "paragraphboundary", or
+   * "documentboundary".  Throws NS_ERROR_INVALID_ARG if alter, direction,
+   * or granularity has an unrecognized value.
+   */
   void Modify(const nsAString& aAlter, const nsAString& aDirection,
               const nsAString& aGranularity, mozilla::ErrorResult& aRv);
 
   void SetBaseAndExtentJS(nsINode& aAnchorNode, uint32_t aAnchorOffset,
                           nsINode& aFocusNode, uint32_t aFocusOffset,
                           mozilla::ErrorResult& aRv);
 
   bool GetInterlinePosition(mozilla::ErrorResult& aRv);
@@ -302,20 +331,18 @@ public:
   Nullable<int16_t> GetCaretBidiLevel(mozilla::ErrorResult& aRv) const;
   void SetCaretBidiLevel(const Nullable<int16_t>& aCaretBidiLevel, mozilla::ErrorResult& aRv);
 
   void ToStringWithFormat(const nsAString& aFormatType,
                           uint32_t aFlags,
                           int32_t aWrapColumn,
                           nsAString& aReturn,
                           mozilla::ErrorResult& aRv);
-  void AddSelectionListener(nsISelectionListener* aListener,
-                            mozilla::ErrorResult& aRv);
-  void RemoveSelectionListener(nsISelectionListener* aListener,
-                               mozilla::ErrorResult& aRv);
+  void AddSelectionListener(nsISelectionListener* aListener);
+  void RemoveSelectionListener(nsISelectionListener* aListener);
 
   RawSelectionType RawType() const
   {
     return ToRawSelectionType(mSelectionType);
   }
   SelectionType Type() const { return mSelectionType; }
 
   void GetRangesForInterval(nsINode& aBeginNode, int32_t aBeginOffset,
@@ -329,26 +356,62 @@ public:
                       mozilla::ErrorResult& aRv);
 
   void SetColors(const nsAString& aForeColor, const nsAString& aBackColor,
                  const nsAString& aAltForeColor, const nsAString& aAltBackColor,
                  mozilla::ErrorResult& aRv);
 
   void ResetColors(mozilla::ErrorResult& aRv);
 
-  // Non-JS callers should use the following methods.
+  /**
+   * Non-JS callers should use the following
+   * collapse/collapseToStart/extend/etc methods, instead of the *JS
+   * versions that bindings call.
+   */
+
+  /**
+   * Collapses the selection to a single point, at the specified offset
+   * in the given node. When the selection is collapsed, and the content
+   * is focused and editable, the caret will blink there.
+   * @param aContainer The given node where the selection will be set
+   * @param offset      Where in given dom node to place the selection (the offset into the given node)
+   */
   void Collapse(nsINode& aContainer, uint32_t aOffset, ErrorResult& aRv)
   {
     Collapse(RawRangeBoundary(&aContainer, aOffset), aRv);
   }
   void Collapse(const RawRangeBoundary& aPoint, ErrorResult& aRv);
+  /**
+   * Collapses the whole selection to a single point at the start
+   * of the current selection (irrespective of direction).  If content
+   * is focused and editable, the caret will blink there.
+   */
   void CollapseToStart(mozilla::ErrorResult& aRv);
+  /**
+   * Collapses the whole selection to a single point at the end
+   * of the current selection (irrespective of direction).  If content
+   * is focused and editable, the caret will blink there.
+   */
   void CollapseToEnd(mozilla::ErrorResult& aRv);
+
+  /**
+   * Extends the selection by moving the selection end to the specified node and
+   * offset, preserving the selection begin position. The new selection end
+   * result will always be from the anchorNode to the new focusNode, regardless
+   * of direction.
+   *
+   * @param aContainer The node where the selection will be extended to
+   * @param aOffset    Where in aContainer to place the offset of the new selection end.
+   */
   void Extend(nsINode& aContainer, uint32_t aOffset, ErrorResult& aRv);
   void AddRange(nsRange& aRange, mozilla::ErrorResult& aRv);
+  /**
+   * Adds all children of the specified node to the selection.
+   * @param aNode the parent of the children to be added to the selection.
+   */
   void SelectAllChildren(nsINode& aNode, mozilla::ErrorResult& aRv);
   void SetBaseAndExtent(nsINode& aAnchorNode, uint32_t aAnchorOffset,
                         nsINode& aFocusNode, uint32_t aFocusOffset,
                         mozilla::ErrorResult& aRv);
 
   void AddSelectionChangeBlocker();
   void RemoveSelectionChangeBlocker();
   bool IsBlockingSelectionChangeEvents() const;
@@ -356,16 +419,60 @@ public:
   /**
    * Set the painting style for the range. The range must be a range in
    * the selection. The textRangeStyle will be used by text frame
    * when it is painting the selection.
    */
   nsresult SetTextRangeStyle(nsRange* aRange,
                              const TextRangeStyle& aTextRangeStyle);
 
+  // Methods to manipulate our mFrameSelection's ancestor limiter.
+  nsIContent* GetAncestorLimiter() const;
+  void SetAncestorLimiter(nsIContent* aLimiter);
+
+  /*
+   * Frame Offset cache can be used just during calling nsEditor::EndPlaceHolderTransaction.
+   * EndPlaceHolderTransaction will give rise to reflow/refreshing view/scroll, and call times
+   * of nsTextFrame::GetPointFromOffset whose return value is to be cached.
+   * see bugs 35296 and 199412
+   */
+  void SetCanCacheFrameOffset(bool aCanCacheFrameOffset);
+
+  // Selection::GetRangesForIntervalArray
+  //
+  //    Fills a nsTArray with the ranges overlapping the range specified by
+  //    the given endpoints. Ranges in the selection exactly adjacent to the
+  //    input range are not returned unless aAllowAdjacent is set.
+  //
+  //    For example, if the following ranges were in the selection
+  //    (assume everything is within the same node)
+  //
+  //    Start Offset: 0 2 7 9
+  //      End Offset: 2 5 9 10
+  //
+  //    and passed aBeginOffset of 2 and aEndOffset of 9, then with
+  //    aAllowAdjacent set, all the ranges should be returned. If
+  //    aAllowAdjacent was false, the ranges [2, 5] and [7, 9] only
+  //    should be returned
+  //
+  //    Now that overlapping ranges are disallowed, there can be a maximum of
+  //    2 adjacent ranges
+  nsresult
+  GetRangesForIntervalArray(nsINode* aBeginNode, int32_t aBeginOffset,
+                            nsINode* aEndNode, int32_t aEndOffset,
+                            bool aAllowAdjacent,
+                            nsTArray<nsRange*>* aRanges);
+
+  /**
+   * Modifies the cursor Bidi level after a change in keyboard direction
+   * @param langRTL is true if the new language is right-to-left or
+   *                false if the new language is left-to-right.
+   */
+  nsresult SelectionLanguageChange(bool aLangRTL);
+
 private:
   friend class ::nsAutoScrollTimer;
 
   // Note: DoAutoScroll might destroy arbitrary frames etc.
   nsresult DoAutoScroll(nsIFrame* aFrame, nsPoint aPoint);
 
   // We are not allowed to be in nodes whose root is not our document
   bool HasSameRoot(nsINode& aNode);
@@ -380,16 +487,20 @@ private:
   // If aVisual is true, this returns caret frame.
   // If false, this returns primary frame.
   nsresult GetPrimaryOrCaretFrameForNodeOffset(nsIContent* aContent,
                                                uint32_t aOffset,
                                                nsIFrame** aReturnFrame,
                                                int32_t* aOffsetUsed,
                                                bool aVisual) const;
 
+  // Get the cached value for nsTextFrame::GetPointFromOffset.
+  nsresult GetCachedFrameOffset(nsIFrame* aFrame, int32_t inOffset,
+                                nsPoint& aPoint);
+
 public:
   SelectionType GetType() const { return mSelectionType; }
   void SetType(SelectionType aSelectionType)
   {
     mSelectionType = aSelectionType;
   }
 
   SelectionCustomColors* GetCustomColors() const { return mCustomColors.get(); }
@@ -451,18 +562,26 @@ private:
   void SetAnchorFocusRange(int32_t aIndex);
   void SelectFramesForContent(nsIContent* aContent, bool aSelected);
   nsresult SelectAllFramesForContent(nsIContentIterator* aInnerIter,
                                      nsIContent *aContent,
                                      bool aSelected);
   nsresult SelectFrames(nsPresContext* aPresContext,
                         nsRange* aRange,
                         bool aSelect);
+
+  /**
+   * Test whether the supplied range points to a single table element.
+   * Result is one of the TableSelection constants. "None" means
+   * a table element isn't selected.
+   */
+  nsresult GetTableSelectionType(nsRange* aRange,
+                                 TableSelection* aTableSelectionType);
   nsresult GetTableCellLocationFromRange(nsRange* aRange,
-                                         int32_t* aSelectionType,
+                                         TableSelection* aSelectionType,
                                          int32_t* aRow,
                                          int32_t* aCol);
   nsresult AddTableCellRange(nsRange* aRange,
                              bool* aDidAddRange,
                              int32_t* aOutIndex);
 
   nsresult FindInsertionPoint(
       nsTArray<RangeData>* aElementArray,
@@ -541,17 +660,17 @@ private:
   // mCachedRange is set by RemoveAllRangesTemporarily() and used by
   // Collapse() and SetBaseAndExtent().  If there is a range which will be
   // released by Clear(), RemoveAllRangesTemporarily() stores it with this.
   // If Collapse() is called without existing ranges, it'll reuse this range
   // for saving the creation cost.
   RefPtr<nsRange> mCachedRange;
   RefPtr<nsFrameSelection> mFrameSelection;
   RefPtr<nsAutoScrollTimer> mAutoScrollTimer;
-  FallibleTArray<nsCOMPtr<nsISelectionListener>> mSelectionListeners;
+  nsTArray<nsCOMPtr<nsISelectionListener>> mSelectionListeners;
   nsRevocableEventPtr<ScrollSelectionIntoViewEvent> mScrollEvent;
   CachedOffsetForFrame* mCachedOffsetForFrame;
   nsDirection mDirection;
   SelectionType mSelectionType;
   UniquePtr<SelectionCustomColors> mCustomColors;
 
   /**
    * True if the current selection operation was initiated by user action.
@@ -656,15 +775,9 @@ ToSelectionTypeMask(SelectionType aSelec
 {
   MOZ_ASSERT(aSelectionType != SelectionType::eInvalid);
   return aSelectionType == SelectionType::eNone ? 0 :
            (1 << (static_cast<uint8_t>(aSelectionType) - 1));
 }
 
 } // namespace mozilla
 
-inline mozilla::dom::Selection*
-nsISelection::AsSelection()
-{
-  return static_cast<mozilla::dom::Selection*>(this);
-}
-
 #endif // mozilla_Selection_h__
--- a/dom/base/SelectionChangeListener.cpp
+++ b/dom/base/SelectionChangeListener.cpp
@@ -9,20 +9,19 @@
  */
 
 #include "SelectionChangeListener.h"
 
 #include "mozilla/AsyncEventDispatcher.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsIDocument.h"
-#include "nsIDOMDocument.h"
 #include "nsFrameSelection.h"
 #include "nsRange.h"
-#include "Selection.h"
+#include "mozilla/dom/Selection.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 SelectionChangeListener::RawRangeData::RawRangeData(const nsRange* aRange)
 {
   mozilla::ErrorResult rv;
   mStartContainer = aRange->GetStartContainer(rv);
@@ -76,108 +75,105 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsISelectionListener)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(SelectionChangeListener)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(SelectionChangeListener)
 
 NS_IMETHODIMP
-SelectionChangeListener::NotifySelectionChanged(nsIDOMDocument* aDoc,
-                                                nsISelection* aSel, int16_t aReason)
+SelectionChangeListener::NotifySelectionChanged(nsIDocument* aDoc,
+                                                Selection* aSel, int16_t aReason)
 {
-  RefPtr<Selection> sel = aSel->AsSelection();
-
-  nsIDocument* doc = sel->GetParentObject();
+  nsIDocument* doc = aSel->GetParentObject();
   if (!(doc && nsContentUtils::IsSystemPrincipal(doc->NodePrincipal())) &&
       !nsFrameSelection::sSelectionEventsEnabled) {
     return NS_OK;
   }
 
   // Check if the ranges have actually changed
   // Don't bother checking this if we are hiding changes.
-  if (mOldRanges.Length() == sel->RangeCount() && !sel->IsBlockingSelectionChangeEvents()) {
+  if (mOldRanges.Length() == aSel->RangeCount() &&
+      !aSel->IsBlockingSelectionChangeEvents()) {
     bool changed = false;
 
     for (size_t i = 0; i < mOldRanges.Length(); i++) {
-      if (!mOldRanges[i].Equals(sel->GetRangeAt(i))) {
+      if (!mOldRanges[i].Equals(aSel->GetRangeAt(i))) {
         changed = true;
         break;
       }
     }
 
     if (!changed) {
       return NS_OK;
     }
   }
 
   // The ranges have actually changed, update the mOldRanges array
   mOldRanges.ClearAndRetainStorage();
-  for (size_t i = 0; i < sel->RangeCount(); i++) {
-    mOldRanges.AppendElement(RawRangeData(sel->GetRangeAt(i)));
+  for (size_t i = 0; i < aSel->RangeCount(); i++) {
+    mOldRanges.AppendElement(RawRangeData(aSel->GetRangeAt(i)));
   }
 
   if (doc) {
     nsPIDOMWindowInner* inner = doc->GetInnerWindow();
     if (inner && !inner->HasSelectionChangeEventListeners()) {
       return NS_OK;
     }
   }
 
   // If we are hiding changes, then don't do anything else. We do this after we
   // update mOldRanges so that changes after the changes stop being hidden don't
   // incorrectly trigger a change, even though they didn't change anything
-  if (sel->IsBlockingSelectionChangeEvents()) {
+  if (aSel->IsBlockingSelectionChangeEvents()) {
     return NS_OK;
   }
 
   // The spec currently doesn't say that we should dispatch this event on text
   // controls, so for now we only support doing that under a pref, disabled by
   // default.
   // See https://github.com/w3c/selection-api/issues/53.
   if (nsFrameSelection::sSelectionEventsOnTextControlsEnabled) {
     nsCOMPtr<nsINode> target;
 
     // Check if we should be firing this event to a different node than the
     // document. The limiter of the nsFrameSelection will be within the native
     // anonymous subtree of the node we want to fire the event on. We need to
     // climb up the parent chain to escape the native anonymous subtree, and then
     // fire the event.
-    if (const nsFrameSelection* fs = sel->GetFrameSelection()) {
+    if (const nsFrameSelection* fs = aSel->GetFrameSelection()) {
       if (nsCOMPtr<nsIContent> root = fs->GetLimiter()) {
         while (root && root->IsInNativeAnonymousSubtree()) {
           root = root->GetParent();
         }
 
         target = root.forget();
       }
     }
 
     // If we didn't get a target before, we can instead fire the event at the document.
     if (!target) {
-      nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
-      target = doc.forget();
+      target = aDoc;
     }
 
     if (target) {
       RefPtr<AsyncEventDispatcher> asyncDispatcher =
         new AsyncEventDispatcher(target, eSelectionChange, false);
       asyncDispatcher->PostDOMEvent();
     }
   } else {
-    if (const nsFrameSelection* fs = sel->GetFrameSelection()) {
+    if (const nsFrameSelection* fs = aSel->GetFrameSelection()) {
       if (nsCOMPtr<nsIContent> root = fs->GetLimiter()) {
         if (root->IsInNativeAnonymousSubtree()) {
           return NS_OK;
         }
       }
     }
 
-    nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
-    if (doc) {
+    if (aDoc) {
       RefPtr<AsyncEventDispatcher> asyncDispatcher =
-        new AsyncEventDispatcher(doc, eSelectionChange, false);
+        new AsyncEventDispatcher(aDoc, eSelectionChange, false);
       asyncDispatcher->PostDOMEvent();
     }
   }
 
   return NS_OK;
 }
--- a/dom/base/SelectionChangeListener.h
+++ b/dom/base/SelectionChangeListener.h
@@ -3,17 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_SelectionChangeListener_h_
 #define mozilla_SelectionChangeListener_h_
 
 #include "nsISelectionListener.h"
-#include "nsISelectionPrivate.h"
 #include "mozilla/Attributes.h"
 
 namespace mozilla {
 namespace dom {
 
 class SelectionChangeListener final : public nsISelectionListener
 {
 public:
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -20,21 +20,19 @@ XPIDL_SOURCES += [
     'nsIDroppedLinkHandler.idl',
     'nsIFrameLoaderOwner.idl',
     'nsIImageLoadingContent.idl',
     'nsIMessageManager.idl',
     'nsIObjectLoadingContent.idl',
     'nsIPerformanceMetrics.idl',
     'nsIRemoteWindowContext.idl',
     'nsIScriptChannel.idl',
-    'nsISelection.idl',
     'nsISelectionController.idl',
     'nsISelectionDisplay.idl',
     'nsISelectionListener.idl',
-    'nsISelectionPrivate.idl',
     'nsISlowScriptDebug.idl',
 ]
 
 XPIDL_MODULE = 'dom'
 
 EXPORTS += [
     'AutocompleteFieldList.h',
     'Crypto.h',
--- a/dom/base/nsContentAreaDragDrop.cpp
+++ b/dom/base/nsContentAreaDragDrop.cpp
@@ -9,17 +9,16 @@
 // Local Includes
 #include "nsContentAreaDragDrop.h"
 
 // Helper Classes
 #include "nsString.h"
 
 // Interfaces needed to be included
 #include "nsCopySupport.h"
-#include "nsISelection.h"
 #include "nsISelectionController.h"
 #include "nsIDOMNode.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDOMRange.h"
 #include "nsIFormControl.h"
 #include "nsITransferable.h"
 #include "nsComponentManagerUtils.h"
 #include "nsXPCOM.h"
@@ -48,44 +47,45 @@
 #include "imgIRequest.h"
 #include "mozilla/dom/DataTransfer.h"
 #include "nsIMIMEInfo.h"
 #include "nsRange.h"
 #include "TabParent.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLAreaElement.h"
 #include "mozilla/dom/HTMLAnchorElement.h"
+#include "mozilla/dom/Selection.h"
 #include "nsVariant.h"
 
 using namespace mozilla::dom;
 using mozilla::IgnoreErrors;
 
 class MOZ_STACK_CLASS DragDataProducer
 {
 public:
   DragDataProducer(nsPIDOMWindowOuter* aWindow,
                    nsIContent* aTarget,
                    nsIContent* aSelectionTargetNode,
                    bool aIsAltKeyPressed);
   nsresult Produce(DataTransfer* aDataTransfer,
                    bool* aCanDrag,
-                   nsISelection** aSelection,
+                   Selection** aSelection,
                    nsIContent** aDragNode,
                    nsACString& aPrincipalURISpec);
 
 private:
   void AddString(DataTransfer* aDataTransfer,
                  const nsAString& aFlavor,
                  const nsAString& aData,
                  nsIPrincipal* aPrincipal,
                  bool aHidden=false);
   nsresult AddStringsToDataTransfer(nsIContent* aDragNode,
                                     DataTransfer* aDataTransfer);
   nsresult GetImageData(imgIContainer* aImage, imgIRequest* aRequest);
-  static nsresult GetDraggableSelectionData(nsISelection* inSelection,
+  static nsresult GetDraggableSelectionData(Selection* inSelection,
                                             nsIContent* inRealTargetNode,
                                             nsIContent **outImageOrLinkNode,
                                             bool* outDragSelectedText);
   static already_AddRefed<nsIContent> FindParentLinkNode(nsIContent* inNode);
   static MOZ_MUST_USE nsresult
   GetAnchorURL(nsIContent* inNode, nsAString& outURL);
   static void GetNodeString(nsIContent* inNode, nsAString & outNodeString);
   static void CreateLinkText(const nsAString& inURL, const nsAString & inText,
@@ -115,17 +115,17 @@ private:
 
 nsresult
 nsContentAreaDragDrop::GetDragData(nsPIDOMWindowOuter* aWindow,
                                    nsIContent* aTarget,
                                    nsIContent* aSelectionTargetNode,
                                    bool aIsAltKeyPressed,
                                    DataTransfer* aDataTransfer,
                                    bool* aCanDrag,
-                                   nsISelection** aSelection,
+                                   Selection** aSelection,
                                    nsIContent** aDragNode,
                                    nsACString& aPrincipalURISpec)
 {
   NS_ENSURE_TRUE(aSelectionTargetNode, NS_ERROR_INVALID_ARG);
 
   *aCanDrag = true;
 
   DragDataProducer
@@ -533,17 +533,17 @@ DragDataProducer::GetImageData(imgIConta
   }
 
   return NS_OK;
 }
 
 nsresult
 DragDataProducer::Produce(DataTransfer* aDataTransfer,
                           bool* aCanDrag,
-                          nsISelection** aSelection,
+                          Selection** aSelection,
                           nsIContent** aDragNode,
                           nsACString& aPrincipalURISpec)
 {
   MOZ_ASSERT(aCanDrag && aSelection && aDataTransfer && aDragNode,
              "null pointer passed to Produce");
   NS_ASSERTION(mWindow, "window not set");
   NS_ASSERTION(mSelectionTargetNode, "selection target node should have been set");
 
@@ -551,25 +551,25 @@ DragDataProducer::Produce(DataTransfer* 
 
   nsresult rv;
   nsIContent* dragNode = nullptr;
   *aSelection = nullptr;
 
   // Find the selection to see what we could be dragging and if what we're
   // dragging is in what is selected. If this is an editable textbox, use
   // the textbox's selection, otherwise use the window's selection.
-  nsCOMPtr<nsISelection> selection;
+  RefPtr<Selection> selection;
   nsIContent* editingElement = mSelectionTargetNode->IsEditable() ?
                                mSelectionTargetNode->GetEditingHost() : nullptr;
   nsCOMPtr<nsITextControlElement> textControl =
     nsITextControlElement::GetTextControlElementFromEditingHost(editingElement);
   if (textControl) {
     nsISelectionController* selcon = textControl->GetSelectionController();
     if (selcon) {
-      selcon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
+      selection = selcon->GetSelection(nsISelectionController::SELECTION_NORMAL);
     }
 
     if (!selection)
       return NS_OK;
   }
   else {
     selection = mWindow->GetSelection();
     if (!selection)
@@ -609,20 +609,17 @@ DragDataProducer::Produce(DataTransfer* 
         }
       }
     }
     return NS_OK;
   }
 
   if (isChromeShell && textControl) {
     // Only use the selection if the target node is in the selection.
-    bool selectionContainsTarget = false;
-    nsCOMPtr<nsIDOMNode> targetNode = do_QueryInterface(mSelectionTargetNode);
-    selection->ContainsNode(targetNode, false, &selectionContainsTarget);
-    if (!selectionContainsTarget)
+    if (!selection->ContainsNode(*mSelectionTargetNode, false, IgnoreErrors()))
       return NS_OK;
 
     selection.swap(*aSelection);
   }
   else {
     // In content shells, a number of checks are made below to determine
     // whether an image or a link is being dragged. If so, add additional
     // data to the data transfer. This is also done for chrome shells, but
@@ -939,58 +936,46 @@ DragDataProducer::AddStringsToDataTransf
   }
 
   return NS_OK;
 }
 
 // note that this can return NS_OK, but a null out param (by design)
 // static
 nsresult
-DragDataProducer::GetDraggableSelectionData(nsISelection* inSelection,
+DragDataProducer::GetDraggableSelectionData(Selection* inSelection,
                                             nsIContent* inRealTargetNode,
                                             nsIContent **outImageOrLinkNode,
                                             bool* outDragSelectedText)
 {
   NS_ENSURE_ARG(inSelection);
   NS_ENSURE_ARG(inRealTargetNode);
   NS_ENSURE_ARG_POINTER(outImageOrLinkNode);
 
   *outImageOrLinkNode = nullptr;
   *outDragSelectedText = false;
 
-  bool selectionContainsTarget = false;
-
-  bool isCollapsed = false;
-  inSelection->GetIsCollapsed(&isCollapsed);
-  if (!isCollapsed) {
-    nsCOMPtr<nsIDOMNode> realTargetNode = do_QueryInterface(inRealTargetNode);
-    inSelection->ContainsNode(realTargetNode, false,
-                              &selectionContainsTarget);
-
-    if (selectionContainsTarget) {
+  if (!inSelection->IsCollapsed()) {
+    if (inSelection->ContainsNode(*inRealTargetNode, false, IgnoreErrors())) {
       // track down the anchor node, if any, for the url
-      nsCOMPtr<nsIDOMNode> selectionStart;
-      inSelection->GetAnchorNode(getter_AddRefs(selectionStart));
-
-      nsCOMPtr<nsIDOMNode> selectionEnd;
-      inSelection->GetFocusNode(getter_AddRefs(selectionEnd));
+      nsINode* selectionStart = inSelection->GetAnchorNode();
+      nsINode* selectionEnd = inSelection->GetFocusNode();
 
       // look for a selection around a single node, like an image.
       // in this case, drag the image, rather than a serialization of the HTML
       // XXX generalize this to other draggable element types?
       if (selectionStart == selectionEnd) {
-        nsCOMPtr<nsIContent> selStartContent = do_QueryInterface(selectionStart);
+        nsCOMPtr<nsIContent> selStartContent = nsIContent::FromNodeOrNull(selectionStart);
         if (selStartContent && selStartContent->HasChildNodes()) {
           // see if just one node is selected
-          int32_t anchorOffset, focusOffset;
-          inSelection->GetAnchorOffset(&anchorOffset);
-          inSelection->GetFocusOffset(&focusOffset);
-          if (abs(anchorOffset - focusOffset) == 1) {
-            int32_t childOffset =
-              (anchorOffset < focusOffset) ? anchorOffset : focusOffset;
+          uint32_t anchorOffset = inSelection->AnchorOffset();
+          uint32_t focusOffset = inSelection->FocusOffset();
+          if (anchorOffset == focusOffset + 1 ||
+              focusOffset == anchorOffset + 1) {
+            uint32_t childOffset = std::min(anchorOffset, focusOffset);
             nsIContent *childContent =
               selStartContent->GetChildAt_Deprecated(childOffset);
             // if we find an image, we'll fall into the node-dragging code,
             // rather the the selection-dragging code
             if (nsContentUtils::IsDraggableImage(childContent)) {
               NS_ADDREF(*outImageOrLinkNode = childContent);
               return NS_OK;
             }
--- a/dom/base/nsContentAreaDragDrop.h
+++ b/dom/base/nsContentAreaDragDrop.h
@@ -10,24 +10,24 @@
 
 
 #include "nsCOMPtr.h"
 
 #include "nsIDOMEventListener.h"
 #include "nsITransferable.h"
 
 class nsPIDOMWindowOuter;
-class nsISelection;
 class nsITransferable;
 class nsIContent;
 class nsIFile;
 
 namespace mozilla {
 namespace dom {
 class DataTransfer;
+class Selection;
 } // namespace dom
 } // namespace mozilla
 
 //
 // class nsContentAreaDragDrop, used to generate the dragdata
 //
 class nsContentAreaDragDrop
 {
@@ -55,17 +55,17 @@ public:
    *                           browser chrome or OS
    */
   static nsresult GetDragData(nsPIDOMWindowOuter* aWindow,
                               nsIContent* aTarget,
                               nsIContent* aSelectionTargetNode,
                               bool aIsAltKeyPressed,
                               mozilla::dom::DataTransfer* aDataTransfer,
                               bool* aCanDrag,
-                              nsISelection** aSelection,
+                              mozilla::dom::Selection** aSelection,
                               nsIContent** aDragNode,
                               nsACString& aPrincipalURISpec);
 };
 
 // this is used to save images to disk lazily when the image data is asked for
 // during the drop instead of when it is added to the drag data transfer. This
 // ensures that the image data is only created when an image drop is allowed.
 class nsContentAreaDragDropDataProvider : public nsIFlavorDataProvider
--- a/dom/base/nsCopySupport.cpp
+++ b/dom/base/nsCopySupport.cpp
@@ -7,17 +7,16 @@
 #include "nsCopySupport.h"
 #include "nsIDocumentEncoder.h"
 #include "nsISupports.h"
 #include "nsIContent.h"
 #include "nsIComponentManager.h"
 #include "nsIServiceManager.h"
 #include "nsIClipboard.h"
 #include "nsIFormControl.h"
-#include "nsISelection.h"
 #include "nsWidgetsCID.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIDOMRange.h"
 #include "nsRange.h"
 #include "imgIContainer.h"
 #include "imgIRequest.h"
 #include "nsIPresShell.h"
@@ -84,17 +83,17 @@ static nsresult AppendDOMNode(nsITransfe
 static nsresult AppendImagePromise(nsITransferable* aTransferable,
                                    imgIRequest* aImgRequest,
                                    nsIImageLoadingContent* aImageElement);
 #endif
 
 // Helper used for HTMLCopy and GetTransferableForSelection since both routines
 // share common code.
 static nsresult
-SelectionCopyHelper(nsISelection *aSel, nsIDocument *aDoc,
+SelectionCopyHelper(Selection *aSel, nsIDocument *aDoc,
                     bool doPutOnClipboard, int16_t aClipboardID,
                     uint32_t aFlags, nsITransferable ** aTransferable)
 {
   // Clear the output parameter for the transferable, if provided.
   if (aTransferable) {
     *aTransferable = nullptr;
   }
 
@@ -285,17 +284,17 @@ SelectionCopyHelper(nsISelection *aSel, 
         trans.swap(*aTransferable);
       }
     }
   }
   return rv;
 }
 
 nsresult
-nsCopySupport::HTMLCopy(nsISelection* aSel, nsIDocument* aDoc,
+nsCopySupport::HTMLCopy(Selection* aSel, nsIDocument* aDoc,
                         int16_t aClipboardID, bool aWithRubyAnnotation)
 {
   uint32_t flags = nsIDocumentEncoder::SkipInvisibleContent;
   if (aWithRubyAnnotation) {
     flags |= nsIDocumentEncoder::OutputRubyAnnotation;
   }
   return SelectionCopyHelper(aSel, aDoc, true, aClipboardID, flags, nullptr);
 }
@@ -305,52 +304,52 @@ nsCopySupport::ClearSelectionCache()
 {
   nsresult rv;
   nsCOMPtr<nsIClipboard> clipboard = do_GetService(kCClipboardCID, &rv);
   clipboard->EmptyClipboard(nsIClipboard::kSelectionCache);
   return rv;
 }
 
 nsresult
-nsCopySupport::GetTransferableForSelection(nsISelection* aSel,
+nsCopySupport::GetTransferableForSelection(Selection* aSel,
                                            nsIDocument* aDoc,
                                            nsITransferable** aTransferable)
 {
   return SelectionCopyHelper(aSel, aDoc, false, 0,
                              nsIDocumentEncoder::SkipInvisibleContent,
                              aTransferable);
 }
 
 nsresult
 nsCopySupport::GetTransferableForNode(nsINode* aNode,
                                       nsIDocument* aDoc,
                                       nsITransferable** aTransferable)
 {
   // Make a temporary selection with aNode in a single range.
   // XXX We should try to get rid of the Selection object here.
   // XXX bug 1245883
-  nsCOMPtr<nsISelection> selection = new Selection();
+  RefPtr<Selection> selection = new Selection();
   RefPtr<nsRange> range = new nsRange(aNode);
   ErrorResult result;
   range->SelectNode(*aNode, result);
   if (NS_WARN_IF(result.Failed())) {
     return result.StealNSResult();
   }
-  selection->AsSelection()->AddRangeInternal(*range, aDoc, result);
+  selection->AddRangeInternal(*range, aDoc, result);
   if (NS_WARN_IF(result.Failed())) {
     return result.StealNSResult();
   }
   // It's not the primary selection - so don't skip invisible content.
   uint32_t flags = 0;
   return SelectionCopyHelper(selection, aDoc, false, 0, flags,
                              aTransferable);
 }
 
 nsresult
-nsCopySupport::GetContents(const nsACString& aMimeType, uint32_t aFlags, nsISelection *aSel, nsIDocument *aDoc, nsAString& outdata)
+nsCopySupport::GetContents(const nsACString& aMimeType, uint32_t aFlags, Selection *aSel, nsIDocument *aDoc, nsAString& outdata)
 {
   nsresult rv = NS_OK;
 
   nsCOMPtr<nsIDocumentEncoder> docEncoder;
 
   nsAutoCString encoderContractID(NS_DOC_ENCODER_CONTRACTID_BASE);
   encoderContractID.Append(aMimeType);
 
@@ -647,17 +646,17 @@ nsCopySupport::GetSelectionForCopy(nsIDo
   nsCOMPtr<nsISelectionController> selectionController =
     presShell->GetSelectionControllerForFocusedContent(
       getter_AddRefs(focusedContent));
   if (!selectionController) {
     return nullptr;
   }
 
   RefPtr<Selection> sel =
-    selectionController->GetDOMSelection(nsISelectionController::SELECTION_NORMAL);
+    selectionController->GetSelection(nsISelectionController::SELECTION_NORMAL);
   sel.forget(aSelection);
   return focusedContent;
 }
 
 bool
 nsCopySupport::CanCopy(nsIDocument* aDocument)
 {
   if (!aDocument)
@@ -829,19 +828,17 @@ nsCopySupport::FireClipboardEvent(EventM
         return false;
       }
     }
 
     // when cutting non-editable content, do nothing
     // XXX this is probably the wrong editable flag to check
     if (originalEventMessage != eCut || content->IsEditable()) {
       // get the data from the selection if any
-      bool isCollapsed;
-      sel->GetIsCollapsed(&isCollapsed);
-      if (isCollapsed) {
+      if (sel->IsCollapsed()) {
         if (aActionTaken) {
           *aActionTaken = true;
         }
         return false;
       }
       // XXX Code which decides whether we should copy text with ruby
       // annotation is currenct depending on whether each range of the
       // selection is inside a same ruby container. But we really should
--- a/dom/base/nsCopySupport.h
+++ b/dom/base/nsCopySupport.h
@@ -7,17 +7,16 @@
 #define nsCopySupport_h__
 
 #include "nsError.h"
 #include "nsIDocument.h"
 #include "nsStringFwd.h"
 #include "mozilla/EventForwards.h"
 
 class nsINode;
-class nsISelection;
 class nsIDocument;
 class nsIImageLoadingContent;
 class nsIContent;
 class nsITransferable;
 class nsIPresShell;
 class nsILoadContext;
 
 namespace mozilla {
@@ -26,33 +25,35 @@ class Selection;
 } // namespace dom
 } // namespace mozilla
 
 class nsCopySupport
 {
   // class of static helper functions for copy support
   public:
     static nsresult ClearSelectionCache();
-    static nsresult HTMLCopy(nsISelection *aSel, nsIDocument *aDoc,
-                             int16_t aClipboardID, bool aWithRubyAnnotation);
+  static nsresult HTMLCopy(mozilla::dom::Selection* aSel, nsIDocument* aDoc,
+                           int16_t aClipboardID, bool aWithRubyAnnotation);
 
     // Get the selection, or entire document, in the format specified by the mime type
     // (text/html or text/plain). If aSel is non-null, use it, otherwise get the entire
     // doc.
-    static nsresult GetContents(const nsACString& aMimeType, uint32_t aFlags, nsISelection *aSel, nsIDocument *aDoc, nsAString& outdata);
+    static nsresult GetContents(const nsACString& aMimeType, uint32_t aFlags,
+                                mozilla::dom::Selection* aSel,
+                                nsIDocument *aDoc, nsAString& outdata);
 
     static nsresult ImageCopy(nsIImageLoadingContent* aImageElement,
                               nsILoadContext* aLoadContext,
                               int32_t aCopyFlags);
 
     // Get the selection as a transferable. Similar to HTMLCopy except does
     // not deal with the clipboard.
-    static nsresult GetTransferableForSelection(nsISelection* aSelection,
-                                                nsIDocument* aDocument,
-                                                nsITransferable** aTransferable);
+  static nsresult GetTransferableForSelection(mozilla::dom::Selection* aSelection,
+                                              nsIDocument* aDocument,
+                                              nsITransferable** aTransferable);
 
     // Same as GetTransferableForSelection, but doesn't skip invisible content.
     static nsresult GetTransferableForNode(nsINode* aNode,
                                            nsIDocument* aDoc,
                                            nsITransferable** aTransferable);
     /**
      * Retrieve the selection for the given document. If the current focus
      * within the document has its own selection, aSelection will be set to it
--- a/dom/base/nsDOMMutationObserver.cpp
+++ b/dom/base/nsDOMMutationObserver.cpp
@@ -895,27 +895,25 @@ nsDOMMutationObserver::HandleMutation()
   mCallback->Call(this, mutations, *this);
 }
 
 void
 nsDOMMutationObserver::HandleMutationsInternal(AutoSlowOperation& aAso)
 {
   nsTArray<RefPtr<nsDOMMutationObserver> >* suppressedObservers = nullptr;
 
-  // Let signalList be a copy of unit of related similar-origin browsing
-  // contexts' signal slot list.
+  // This loop implements:
+  //  * Let signalList be a copy of unit of related similar-origin browsing
+  //    contexts' signal slot list.
+  //  * Empty unit of related similar-origin browsing contexts' signal slot
+  //    list.
   nsTArray<RefPtr<HTMLSlotElement>> signalList;
   if (DocGroup::sPendingDocGroups) {
-    for (uint32_t i = 0; i < DocGroup::sPendingDocGroups->Length(); ++i) {
-      DocGroup* docGroup = DocGroup::sPendingDocGroups->ElementAt(i);
-      signalList.AppendElements(docGroup->SignalSlotList());
-
-      // Empty unit of related similar-origin browsing contexts' signal slot
-      // list.
-      docGroup->ClearSignalSlotList();
+    for (DocGroup* docGroup : *DocGroup::sPendingDocGroups) {
+      docGroup->MoveSignalSlotListTo(signalList);
     }
     delete DocGroup::sPendingDocGroups;
     DocGroup::sPendingDocGroups = nullptr;
   }
 
   if (sScheduledMutationObservers) {
     AutoTArray<RefPtr<nsDOMMutationObserver>, 4>* observers =
       sScheduledMutationObservers;
--- a/dom/base/nsDocumentEncoder.cpp
+++ b/dom/base/nsDocumentEncoder.cpp
@@ -23,17 +23,16 @@
 #include "nsRange.h"
 #include "nsIDOMDocument.h"
 #include "nsGkAtoms.h"
 #include "nsIContent.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
 #include "mozilla/dom/Selection.h"
-#include "nsISelectionPrivate.h"
 #include "nsITransferable.h" // for kUnicodeMime
 #include "nsContentUtils.h"
 #include "nsElementTable.h"
 #include "nsNodeUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsReadableUtils.h"
 #include "nsTArray.h"
 #include "nsIFrame.h"
@@ -283,19 +282,19 @@ nsDocumentEncoder::NativeInit(nsIDocumen
 NS_IMETHODIMP
 nsDocumentEncoder::SetWrapColumn(uint32_t aWC)
 {
   mWrapColumn = aWC;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDocumentEncoder::SetSelection(nsISelection* aSelection)
+nsDocumentEncoder::SetSelection(Selection* aSelection)
 {
-  mSelection = aSelection->AsSelection();
+  mSelection = aSelection;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocumentEncoder::SetRange(nsIDOMRange* aRange)
 {
   mRange = static_cast<nsRange*>(aRange);
   return NS_OK;
@@ -1151,17 +1150,17 @@ class nsHTMLCopyEncoder : public nsDocum
 public:
 
   nsHTMLCopyEncoder();
   virtual ~nsHTMLCopyEncoder();
 
   NS_IMETHOD Init(nsIDOMDocument* aDocument, const nsAString& aMimeType, uint32_t aFlags) override;
 
   // overridden methods from nsDocumentEncoder
-  NS_IMETHOD SetSelection(nsISelection* aSelection) override;
+  NS_IMETHOD SetSelection(Selection* aSelection) override;
   NS_IMETHOD EncodeToStringWithContext(nsAString& aContextString,
                                        nsAString& aInfoString,
                                        nsAString& aEncodedString) override;
   NS_IMETHOD EncodeToString(nsAString& aOutputString) override;
 
 protected:
 
   enum Endpoint
@@ -1231,44 +1230,43 @@ nsHTMLCopyEncoder::Init(nsIDOMDocument* 
 
   if (!mDocument->IsScriptEnabled())
     mFlags |= OutputNoScriptContent;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
+nsHTMLCopyEncoder::SetSelection(Selection* aSelection)
 {
   // check for text widgets: we need to recognize these so that
   // we don't tweak the selection to be outside of the magic
   // div that ender-lite text widgets are embedded in.
 
   if (!aSelection)
     return NS_ERROR_NULL_POINTER;
 
-  Selection* selection = aSelection->AsSelection();
-  uint32_t rangeCount = selection->RangeCount();
+  uint32_t rangeCount = aSelection->RangeCount();
 
   // if selection is uninitialized return
   if (!rangeCount) {
     return NS_ERROR_FAILURE;
   }
 
   // we'll just use the common parent of the first range.  Implicit assumption
   // here that multi-range selections are table cell selections, in which case
   // the common parent is somewhere in the table and we don't really care where.
   //
   // FIXME(emilio, bug 1455894): This assumption is already wrong, and will
   // probably be more wrong in a Shadow DOM world...
   //
   // We should be able to write this as "Find the common ancestor of the
   // selection, then go through the flattened tree and serialize the selected
   // nodes", effectively serializing the composed tree.
-  RefPtr<nsRange> range = selection->GetRangeAt(0);
+  RefPtr<nsRange> range = aSelection->GetRangeAt(0);
   nsINode* commonParent = range->GetCommonAncestor();
 
   for (nsCOMPtr<nsIContent> selContent(do_QueryInterface(commonParent));
        selContent;
        selContent = selContent->GetParent())
   {
     // checking for selection inside a plaintext form widget
     if (selContent->IsAnyOfHTMLElements(nsGkAtoms::input, nsGkAtoms::textarea))
@@ -1317,41 +1315,41 @@ nsHTMLCopyEncoder::SetSelection(nsISelec
       }
     }
 #endif
   }
 
   // normalize selection if we are not in a widget
   if (mIsTextWidget)
   {
-    mSelection = selection;
+    mSelection = aSelection;
     mMimeType.AssignLiteral("text/plain");
     return NS_OK;
   }
 
   // XXX We should try to get rid of the Selection object here.
   // XXX bug 1245883
 
   // also consider ourselves in a text widget if we can't find an html document
   nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
   if (!(htmlDoc && mDocument->IsHTMLDocument())) {
     mIsTextWidget = true;
-    mSelection = selection;
+    mSelection = aSelection;
     // mMimeType is set to text/plain when encoding starts.
     return NS_OK;
   }
 
   // there's no Clone() for selection! fix...
   //nsresult rv = aSelection->Clone(getter_AddRefs(mSelection);
   //NS_ENSURE_SUCCESS(rv, rv);
   mSelection = new Selection();
 
   // loop thru the ranges in the selection
   for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
-    range = selection->GetRangeAt(rangeIdx);
+    range = aSelection->GetRangeAt(rangeIdx);
     NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
     RefPtr<nsRange> myRange = range->CloneRange();
     MOZ_ASSERT(myRange);
 
     // adjust range to include any ancestors who's children are entirely selected
     nsresult rv = PromoteRange(myRange);
     NS_ENSURE_SUCCESS(rv, rv);
 
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -2456,17 +2456,17 @@ nsFocusManager::MoveCaretToFocus(nsIPres
             aContent->IsNodeOfType(nsINode::eHTML_FORM_CONTROL)) {
           // If current focus node is a leaf, set range to before the
           // node by using the parent as a container.
           // This prevents it from appearing as selected.
           newRange->SetStartBefore(*aContent, IgnoreErrors());
           newRange->SetEndBefore(*aContent, IgnoreErrors());
         }
         domSelection->AddRange(*newRange, IgnoreErrors());
-        domSelection->CollapseToStart();
+        domSelection->CollapseToStart(IgnoreErrors());
       }
     }
   }
 }
 
 nsresult
 nsFocusManager::SetCaretVisible(nsIPresShell* aPresShell,
                                 bool aVisible,
@@ -2491,17 +2491,17 @@ nsFocusManager::SetCaretVisible(nsIPresS
     if (focusFrame)
       frameSelection = focusFrame->GetFrameSelection();
   }
 
   RefPtr<nsFrameSelection> docFrameSelection = aPresShell->FrameSelection();
 
   if (docFrameSelection && caret &&
      (frameSelection == docFrameSelection || !aContent)) {
-    nsISelection* domSelection =
+    Selection* domSelection =
       docFrameSelection->GetSelection(SelectionType::eNormal);
     if (domSelection) {
       nsCOMPtr<nsISelectionController> selCon(do_QueryInterface(aPresShell));
       if (!selCon) {
         return NS_ERROR_FAILURE;
       }
       // First, hide the caret to prevent attempting to show it in SetCaretDOMSelection
       selCon->SetCaretEnabled(false);
--- a/dom/base/nsGlobalWindowCommands.cpp
+++ b/dom/base/nsGlobalWindowCommands.cpp
@@ -557,17 +557,17 @@ nsClipboardCommand::DoCommand(const char
     nsCopySupport::FireClipboardEvent(eventMessage,
                                       nsIClipboard::kGlobalClipboard,
                                       presShell, nullptr, &actionTaken);
 
   if (notCancelled && !strcmp(aCommandName, "cmd_copyAndCollapseToEnd")) {
     dom::Selection *sel =
       presShell->GetCurrentSelection(SelectionType::eNormal);
     NS_ENSURE_TRUE(sel, NS_ERROR_FAILURE);
-    sel->CollapseToEnd();
+    sel->CollapseToEnd(IgnoreErrors());
   }
 
   return actionTaken ? NS_OK : NS_SUCCESS_DOM_NO_OPERATION;
 }
 
 NS_IMETHODIMP
 nsClipboardCommand::GetCommandStateParams(const char *aCommandName,
                                               nsICommandParams *aParams, nsISupports *aCommandContext)
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -116,17 +116,16 @@
 #include "nsIEmbeddingSiteWindow.h"
 #include "nsThreadUtils.h"
 #include "nsILoadContext.h"
 #include "nsIPresShell.h"
 #include "nsIScrollableFrame.h"
 #include "nsView.h"
 #include "nsViewManager.h"
 #include "nsISelectionController.h"
-#include "nsISelection.h"
 #include "nsIPrompt.h"
 #include "nsIPromptService.h"
 #include "nsIPromptFactory.h"
 #include "nsIAddonPolicyService.h"
 #include "nsIWritablePropertyBag2.h"
 #include "nsIWebNavigation.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIWebBrowserFind.h"  // For window.find()
@@ -4427,17 +4426,17 @@ nsGlobalWindowInner::ConvertDialogOption
         !token.EqualsLiteral(";")) {
       break;
     }
   }
 }
 
 void
 nsGlobalWindowInner::UpdateCommands(const nsAString& anAction,
-                                    nsISelection* aSel,
+                                    Selection* aSel,
                                     int16_t aReason)
 {
   if (GetOuterWindowInternal()) {
     GetOuterWindowInternal()->UpdateCommands(anAction, aSel, aReason);
   }
 }
 
 Selection*
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -892,17 +892,18 @@ public:
 
   already_AddRefed<nsPIDOMWindowOuter>
   OpenDialog(JSContext* aCx,
              const nsAString& aUrl,
              const nsAString& aName,
              const nsAString& aOptions,
              const mozilla::dom::Sequence<JS::Value>& aExtraArgument,
              mozilla::ErrorResult& aError);
-  void UpdateCommands(const nsAString& anAction, nsISelection* aSel, int16_t aReason);
+  void UpdateCommands(const nsAString& anAction, mozilla::dom::Selection* aSel,
+                      int16_t aReason);
 
   void GetContent(JSContext* aCx,
                   JS::MutableHandle<JSObject*> aRetval,
                   mozilla::dom::CallerType aCallerType,
                   mozilla::ErrorResult& aError);
 
   already_AddRefed<mozilla::dom::Promise>
   CreateImageBitmap(JSContext* aCx,
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -113,17 +113,16 @@
 #include "nsIEmbeddingSiteWindow.h"
 #include "nsThreadUtils.h"
 #include "nsILoadContext.h"
 #include "nsIPresShell.h"
 #include "nsIScrollableFrame.h"
 #include "nsView.h"
 #include "nsViewManager.h"
 #include "nsISelectionController.h"
-#include "nsISelection.h"
 #include "nsIPrompt.h"
 #include "nsIPromptService.h"
 #include "nsIPromptFactory.h"
 #include "nsIAddonPolicyService.h"
 #include "nsIWritablePropertyBag2.h"
 #include "nsIWebNavigation.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIWebBrowserFind.h"  // For window.find()
@@ -6270,17 +6269,17 @@ public:
 
   nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
   nsString                             mAction;
 };
 } // anonymous namespace
 
 void
 nsGlobalWindowOuter::UpdateCommands(const nsAString& anAction,
-                                    nsISelection* aSel,
+                                    Selection* aSel,
                                     int16_t aReason)
 {
   // If this is a child process, redirect to the parent process.
   if (nsIDocShell* docShell = GetDocShell()) {
     if (nsCOMPtr<nsITabChild> child = docShell->GetTabChild()) {
       nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
       if (root) {
         nsContentUtils::AddScriptRunner(
@@ -6319,25 +6318,23 @@ nsGlobalWindowOuter::GetSelectionOuter()
   if (!mDocShell) {
     return nullptr;
   }
 
   nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
   if (!presShell) {
     return nullptr;
   }
-  nsISelection* domSelection =
-    presShell->GetCurrentSelection(SelectionType::eNormal);
-  return domSelection ? domSelection->AsSelection() : nullptr;
-}
-
-already_AddRefed<nsISelection>
+  return presShell->GetCurrentSelection(SelectionType::eNormal);
+}
+
+already_AddRefed<Selection>
 nsGlobalWindowOuter::GetSelection()
 {
-  nsCOMPtr<nsISelection> selection = GetSelectionOuter();
+  RefPtr<Selection> selection = GetSelectionOuter();
   return selection.forget();
 }
 
 bool
 nsGlobalWindowOuter::FindOuter(const nsAString& aString, bool aCaseSensitive,
                                bool aBackwards, bool aWrapAround, bool aWholeWord,
                                bool aSearchInFrames, bool aShowDialog,
                                ErrorResult& aError)
--- a/dom/base/nsGlobalWindowOuter.h
+++ b/dom/base/nsGlobalWindowOuter.h
@@ -633,17 +633,17 @@ public:
                     nsIPrincipal& aSubjectPrincipal,
                     mozilla::ErrorResult& aError);
   void PromptOuter(const nsAString& aMessage, const nsAString& aInitial,
                    nsAString& aReturn,
                    nsIPrincipal& aSubjectPrincipal,
                    mozilla::ErrorResult& aError);
   void PrintOuter(mozilla::ErrorResult& aError);
   mozilla::dom::Selection* GetSelectionOuter();
-  already_AddRefed<nsISelection> GetSelection() override;
+  already_AddRefed<mozilla::dom::Selection> GetSelection() override;
   already_AddRefed<mozilla::dom::MediaQueryList> MatchMediaOuter(
     const nsAString& aQuery,
     mozilla::dom::CallerType aCallerType);
   nsScreen* GetScreen();
   void MoveToOuter(int32_t aXPos, int32_t aYPos,
                    mozilla::dom::CallerType aCallerType,
                    mozilla::ErrorResult& aError);
   void MoveByOuter(int32_t aXDif, int32_t aYDif,
@@ -687,17 +687,18 @@ public:
                   const nsAString& aName,
                   const nsAString& aOptions,
                   const mozilla::dom::Sequence<JS::Value>& aExtraArgument,
                   mozilla::ErrorResult& aError);
   nsresult OpenDialog(const nsAString& aUrl, const nsAString& aName,
                       const nsAString& aOptions,
                       nsISupports* aExtraArgument,
                       nsPIDOMWindowOuter** _retval) override;
-  void UpdateCommands(const nsAString& anAction, nsISelection* aSel, int16_t aReason) override;
+  void UpdateCommands(const nsAString& anAction, mozilla::dom::Selection* aSel,
+                      int16_t aReason) override;
 
   already_AddRefed<nsPIDOMWindowOuter>
   GetContentInternal(mozilla::ErrorResult& aError,
                      mozilla::dom::CallerType aCallerType);
   void GetContentOuter(JSContext* aCx,
                        JS::MutableHandle<JSObject*> aRetval,
                        mozilla::dom::CallerType aCallerType,
                        mozilla::ErrorResult& aError);
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -67,16 +67,18 @@ public:
   }
 #endif // MOZILLA_INTERNAL_API
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENT_IID)
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(nsIContent)
 
+  NS_IMPL_FROMNODE_HELPER(nsIContent, IsContent())
+
   /**
    * Bind this content node to a tree.  If this method throws, the caller must
    * call UnbindFromTree() on the node.  In the typical case of a node being
    * appended to a parent, this will be called after the node has been added to
    * the parent's child list and before nsIDocumentObserver notifications for
    * the addition are dispatched.
    * @param aDocument The new document for the content node.  May not be null
    *                  if aParent is null.  Must match the current document of
--- a/dom/base/nsIDocumentEncoder.idl
+++ b/dom/base/nsIDocumentEncoder.idl
@@ -2,20 +2,21 @@
 /* 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 nsIDOMDocument;
 interface nsIDOMRange;
-interface nsISelection;
 interface nsIDOMNode;
 interface nsIOutputStream;
 
+webidl Selection;
+
 %{ C++
 class nsINode;
 class nsIDocument;
 %}
 [ptr] native nsINodePtr(nsINode);
 [ptr] native nsIDocumentPtr(nsIDocument);
 
 [scriptable, uuid(3d9371d8-a2ad-403e-8b0e-8885ad3562e3)]
@@ -243,17 +244,17 @@ interface nsIDocumentEncoder : nsISuppor
                              in unsigned long aFlags);
 
   /**
    *  If the selection is set to a non-null value, then the
    *  selection is used for encoding, otherwise the entire
    *  document is encoded.
    * @param aSelection The selection to encode.
    */
-  void setSelection(in nsISelection aSelection);
+  void setSelection(in Selection aSelection);
 
   /**
    *  If the range is set to a non-null value, then the
    *  range is used for encoding, otherwise the entire
    *  document or selection is encoded.
    * @param aRange The range to encode.
    */
   void setRange(in nsIDOMRange aRange);
deleted file mode 100644
--- a/dom/base/nsISelection.idl
+++ /dev/null
@@ -1,145 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* 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"
-
-/* THIS IS A PUBLIC INTERFACE */
-
-interface nsIDOMNode;
-interface nsINode;
-
-%{C++
-namespace mozilla {
-namespace dom {
-class Selection;
-} // namespace dom
-} // namespace mozilla
-%}
-
-/**
- * Interface for manipulating and querying the current selected range
- * of nodes within the document.
- *
- * @version 1.0
- */
-
-[shim(Selection), uuid(e0a4d4b3-f34e-44bd-b1f2-4e3bde9b6915)]
-interface nsISelection : nsISupports
-{
-    /**
-     * Returns the node in which the selection begins.
-     */
-    readonly attribute nsIDOMNode anchorNode;
-
-    /**
-     * The offset within the (text) node where the selection begins.
-     */
-    readonly attribute long anchorOffset;
-
-    /**
-     * Returns the node in which the selection ends.
-     */
-    readonly attribute nsIDOMNode focusNode;
-
-    /**
-     * The offset within the (text) node where the selection ends.
-     */
-    readonly attribute long focusOffset;
-
-    /**
-     * Indicates if the selection is collapsed or not.
-     */
-    readonly attribute boolean isCollapsed;
-    [noscript,notxpcom,nostdcall] boolean collapsed();
-
-    /**
-     * Collapses the selection to a single point, at the specified offset
-     * in the given DOM node. When the selection is collapsed, and the content
-     * is focused and editable, the caret will blink there.
-     * @param parentNode      The given dom node where the selection will be set
-     * @param offset          Where in given dom node to place the selection (the offset into the given node)
-     */
-    void collapse(in nsIDOMNode parentNode, in long offset);
-    [noscript] void collapseNative(in nsINode parentNode, in long offset);
-
-    /**
-     * Extends the selection by moving the selection end to the specified node and offset,
-     * preserving the selection begin position. The new selection end result will always
-     * be from the anchorNode to the new focusNode, regardless of direction.
-     * @param parentNode      The node where the selection will be extended to
-     * @param offset          Where in node to place the offset in the new selection end
-     */
-    void extend(in nsIDOMNode parentNode, in long offset);
-    [noscript] void extendNative(in nsINode parentNode, in long offset);
-
-    /**
-     * Collapses the whole selection to a single point at the start
-     * of the current selection (irrespective of direction).  If content
-     * is focused and editable, the caret will blink there.
-     */
-    void collapseToStart();
-
-    /**
-     * Collapses the whole selection to a single point at the end
-     * of the current selection (irrespective of direction).  If content
-     * is focused and editable, the caret will blink there.
-     */
-    void collapseToEnd();
-
-    /**
-     * Indicates whether the node is part of the selection. If partlyContained 
-     * is set to PR_TRUE, the function returns true when some part of the node 
-     * is part of the selection. If partlyContained is set to PR_FALSE, the
-     * function only returns true when the entire node is part of the selection.
-     */
-    boolean containsNode(in nsIDOMNode node, in boolean partlyContained);
-
-    /**
-     * Adds all children of the specified node to the selection.
-     * @param parentNode  the parent of the children to be added to the selection.
-     */
-    void selectAllChildren(in nsIDOMNode parentNode);
-
-    /**
-     * Deletes this selection from document the nodes belong to.
-     */
-    void deleteFromDocument();
-
-    /**
-     * Returns the whole selection into a plain text string.
-     */
-    DOMString toString();
-
-    /**
-     * Modifies the selection.  Note that the parameters are case-insensitive.
-     *
-     * @param alter can be one of { "move", "extend" }
-     *   - "move" collapses the selection to the end of the selection and
-     *      applies the movement direction/granularity to the collapsed
-     *      selection.
-     *   - "extend" leaves the start of the selection unchanged, and applies
-     *      movement direction/granularity to the end of the selection.
-     * @param direction can be one of { "forward", "backward", "left", "right" }
-     * @param granularity can be one of { "character", "word",
-     *                                    "line", "lineboundary" }
-     *
-     * @returns NS_ERROR_NOT_IMPLEMENTED if the granularity is "sentence",
-     * "sentenceboundary", "paragraph", "paragraphboundary", or
-     * "documentboundary".  Returns NS_ERROR_INVALID_ARG if alter, direction,
-     * or granularity has an unrecognized value.
-     */
-    void modify(in DOMString alter, in DOMString direction,
-                in DOMString granularity);
-
-%{C++
-    /**
-     * AsSelection() returns a pointer to Selection class.
-     *
-     * In order to avoid circular dependency issues, this method is defined
-     * in mozilla/dom/Selection.h.  Consumers need to #include that header.
-     */
-    inline mozilla::dom::Selection* AsSelection();
-%}
-};
--- a/dom/base/nsISelectionController.idl
+++ b/dom/base/nsISelectionController.idl
@@ -12,20 +12,19 @@ namespace mozilla {
 namespace dom {
 class Selection;
 } // namespace dom
 } // namespace mozilla
 %}
 
 interface nsIContent;
 interface nsIDOMNode;
-interface nsISelection;
 interface nsISelectionDisplay;
 
-[ptr] native SelectionPtr(mozilla::dom::Selection);
+webidl Selection;
 
 [scriptable, uuid(3801c9d4-8e69-4bfc-9edb-b58278621f8f)]
 interface nsISelectionController : nsISelectionDisplay
 {
    // RawSelectionType values:
    const short SELECTION_NONE                      = 0;
    const short SELECTION_NORMAL                    = 1;
    const short SELECTION_SPELLCHECK                = 2;
@@ -65,22 +64,24 @@ interface nsISelectionController : nsISe
    /**
    * GetSelection will return the selection that the presentation
    *  shell may implement.
    *
    * @param aType This will hold the type of selection.  This value must be one
    *              of RawSelectionType values.
    * @param _return will hold the return value
    */
-    nsISelection getSelection(in short type);
+    [binaryname(GetSelectionFromScript)]
+    Selection getSelection(in short type);
 
    /**
    * Return the selection object corresponding to a selection type.
    */
-    [noscript,nostdcall,notxpcom] SelectionPtr getDOMSelection(in short aType);
+    [noscript,nostdcall,notxpcom,binaryname(GetSelection)]
+    Selection getDOMSelection(in short aType);
 
    const short SCROLL_SYNCHRONOUS = 1<<1;
    const short SCROLL_FIRST_ANCESTOR_ONLY = 1<<2;
    const short SCROLL_CENTER_VERTICALLY = 1<<4;
    const short SCROLL_OVERFLOW_HIDDEN = 1<<5;
    const short SCROLL_FOR_CARET_MOVE = 1<<6;
 
    /**
--- a/dom/base/nsISelectionListener.idl
+++ b/dom/base/nsISelectionListener.idl
@@ -1,27 +1,28 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 nsIDOMDocument;
-interface nsISelection;
+webidl Document;
+webidl Selection;
 
 [scriptable, uuid(45686299-ae2b-46bc-9502-c56c35691ab9)]
 interface nsISelectionListener : nsISupports
 {
   const short NO_REASON=0;
   const short DRAG_REASON=1;
   const short MOUSEDOWN_REASON=2;/*bitflags*/
   const short MOUSEUP_REASON=4;/*bitflags*/
   const short KEYPRESS_REASON=8;/*bitflags*/
   const short SELECTALL_REASON=16;
   const short COLLAPSETOSTART_REASON=32;
   const short COLLAPSETOEND_REASON=64;
   const short IME_REASON=128;
 
-	void			notifySelectionChanged(in nsIDOMDocument doc, in nsISelection sel, in short reason);
+  void notifySelectionChanged(in Document doc, in Selection sel,
+                              in short reason);
 };
 
 
deleted file mode 100644
--- a/dom/base/nsISelectionPrivate.idl
+++ /dev/null
@@ -1,177 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* 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 "nsISelection.idl"
-
-interface nsRange;
-interface nsIDOMNode;
-interface nsISelectionListener;
-interface nsIContent;
-interface nsINode;
-interface nsIDOMRange;
-
-%{C++
-class nsIFrame;
-struct nsPoint;
-struct ScrollAxis;
-#include "nsDirection.h"
-#include "nsIPresShell.h" // TODO: Remove this include
-#include "nsTArrayForwardDeclare.h"
-#include "mozilla/EventForwards.h"
-%}
-
-[ptr] native nsIFrame(nsIFrame);
-[ptr] native RangeArray(nsTArray<nsRange*>);
-[ref] native nsPointRef(nsPoint);
-native nsDirection(nsDirection);
-native ScrollAxis(nsIPresShell::ScrollAxis);
-
-[scriptable, builtinclass, uuid(0c9f4f74-ee7e-4fe9-be6b-0ba856368178)]
-interface nsISelectionPrivate : nsISupports
- {
-    const short ENDOFPRECEDINGLINE=0;
-    const short STARTOFNEXTLINE=1;
-
-    attribute boolean interlinePosition;
-    [noscript] attribute nsIContent ancestorLimiter;
-
-    DOMString  toStringWithFormat(in string formatType, in unsigned long flags, in int32_t wrapColumn);
-    void  addSelectionListener(in nsISelectionListener newListener);
-    void  removeSelectionListener(in nsISelectionListener listenerToRemove);
-
-    /* Table selection stuff
-       We should probably move this and table-related
-       items in nsFrameSelection  to a
-       new nsITableSelection interface
-    */
-    const long TABLESELECTION_NONE     = 0;
-    const long TABLESELECTION_CELL     = 1;
-    const long TABLESELECTION_ROW      = 2;
-    const long TABLESELECTION_COLUMN   = 3;
-    const long TABLESELECTION_TABLE    = 4;
-    const long TABLESELECTION_ALLCELLS = 5;
-
-    /** Test if supplied range points to a single table element:
-      *    Result is one of above constants. "None" means
-      *    a table element isn't selected.
-      */
-    [noscript] long getTableSelectionType(in nsIDOMRange range);
-
-    /* canCacheFrameOffset
-     * Frame Offset cache can be used just during calling nsEditor::EndPlaceHolderTransaction.
-     * EndPlaceHolderTransaction will give rise to reflow/refreshing view/scroll, and call times
-     * of nsTextFrame::GetPointFromOffset whose return value is to be cached.
-     * see bugs 35296 and 199412
-     */
-    [noscript] attribute boolean canCacheFrameOffset;
-
-    /* GetCachedOffsetForFrame
-     * Returns cached value for nsTextFrame::GetPointFromOffset.
-     */
-    [noscript] void getCachedFrameOffset(in nsIFrame aFrame, in int32_t inOffset, in nsPointRef aPoint);
-
-    /**
-     * Get the direction of the selection.
-     */
-    [noscript, notxpcom] nsDirection getSelectionDirection();
-    [noscript, notxpcom] void setSelectionDirection(in nsDirection aDirection);
-
-    /**
-     * Returns the type of the selection (see nsISelectionController for
-     * available constants).
-     */
-    readonly attribute short type;
-
-    /**
-     * Return array of ranges intersecting with the given DOM interval.
-     */
-    void GetRangesForInterval(
-        in nsIDOMNode beginNode, in int32_t beginOffset,
-        in nsIDOMNode endNode, in int32_t endOffset,
-        in boolean allowAdjacent,
-        out uint32_t resultCount,
-        [retval, array, size_is(resultCount)] out nsIDOMRange results);
-
-    [noscript] void GetRangesForIntervalArray(
-        in nsINode beginNode, in int32_t beginOffset,
-        in nsINode endNode, in int32_t endOffset,
-        in boolean allowAdjacent,
-        in RangeArray results);
-
-    /**
-     * Scrolls a region of the selection, so that it is visible in
-     * the scrolled view.
-     *
-     * @param aRegion - the region inside the selection to scroll into view
-     *                  (see selection region constants defined in
-     *                   nsISelectionController).
-     * @param aIsSynchronous - when true, scrolls the selection into view
-     *                         before returning. If false, posts a request which
-     *                         is processed at some point after the method returns.
-     * @param aVPercent - how to align the frame vertically.
-     * @param aHPercent - how to align the frame horizontally.
-     */
-    void scrollIntoView(in short aRegion, in boolean aIsSynchronous,
-                        in int16_t aVPercent,
-                        in int16_t aHPercent);
-
-    /**
-     * Scrolls a region of the selection, so that it is visible in
-     * the scrolled view.
-     *
-     * @param aRegion - the region inside the selection to scroll into view
-     *                  (see selection region constants defined in
-     *                   nsISelectionController).
-     * @param aIsSynchronous - when true, scrolls the selection into view
-     *                         before returning. If false, posts a request which
-     *                         is processed at some point after the method returns.
-     * @param aVertical - how to align the frame vertically and when.
-     *                    See nsIPresShell.h:ScrollAxis for details.
-     * @param aHorizontal - how to align the frame horizontally and when.
-     *                    See nsIPresShell.h:ScrollAxis for details.
-     */
-    [noscript] void scrollIntoViewInternal(in short aRegion,
-                                           in boolean aIsSynchronous,
-                                           in ScrollAxis aVertical,
-                                           in ScrollAxis aHorizontal);
-
-    /**
-     * Modifies the cursor Bidi level after a change in keyboard direction
-     * @param langRTL is PR_TRUE if the new language is right-to-left or
-     *                PR_FALSE if the new language is left-to-right.
-     */
-    [noscript] void selectionLanguageChange(in boolean langRTL);
-
-    /**
-     * setColors() sets custom colors for the selection.
-     * Currently, this is supported only when the selection type is SELECTION_FIND.
-     * Otherwise, throws an exception.
-     *
-     * @param aForegroundColor     The foreground color of the selection.
-     *                             If this is "currentColor", foreground color
-     *                             isn't changed by this selection.
-     * @param aBackgroundColor     The background color of the selection.
-     *                             If this is "transparent", background color is
-     *                             never painted.
-     * @param aAltForegroundColor  The alternative foreground color of the
-     *                             selection.
-     *                             If aBackgroundColor doesn't have sufficient
-     *                             contrast with its around or foreground color
-     *                             if "currentColor" is specified, alternative
-     *                             colors are used if it have higher contrast.
-     * @param aAltBackgroundColor  The alternative background color of the
-     *                             selection.
-     */
-    void setColors(in DOMString aForegroundColor,
-                   in DOMString aBackgroundColor,
-                   in DOMString aAltForegroundColor,
-                   in DOMString aAltBackgroundColor);
-
-    /**
-     * resetColors() forget the customized colors which were set by setColors().
-     */
-    void resetColors();
-};
-
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -48,16 +48,17 @@ namespace dom {
 class AudioContext;
 class ClientInfo;
 class ClientState;
 class DocGroup;
 class TabGroup;
 class Element;
 class Navigator;
 class Performance;
+class Selection;
 class ServiceWorker;
 class ServiceWorkerDescriptor;
 class Timeout;
 class TimeoutManager;
 class CustomElementRegistry;
 enum class CallerType : uint32_t;
 } // namespace dom
 } // namespace mozilla
@@ -1081,17 +1082,17 @@ public:
 
   // XXX(nika): These feel like they should be inner window only, but they're
   // called on the outer window.
   virtual mozilla::dom::Navigator* GetNavigator() = 0;
   virtual mozilla::dom::Location* GetLocation() = 0;
 
   virtual nsresult GetPrompter(nsIPrompt** aPrompt) = 0;
   virtual nsresult GetControllers(nsIControllers** aControllers) = 0;
-  virtual already_AddRefed<nsISelection> GetSelection() = 0;
+  virtual already_AddRefed<mozilla::dom::Selection> GetSelection() = 0;
   virtual already_AddRefed<nsPIDOMWindowOuter> GetOpener() = 0;
 
   virtual already_AddRefed<nsIDOMWindowCollection> GetFrames() = 0;
 
   // aLoadInfo will be passed on through to the windowwatcher.
   // aForceNoOpener will act just like a "noopener" feature in aOptions except
   //                will not affect any other window features.
   virtual nsresult Open(const nsAString& aUrl, const nsAString& aName,
@@ -1113,17 +1114,19 @@ public:
   virtual bool GetFullScreen() = 0;
   virtual nsresult SetFullScreen(bool aFullScreen) = 0;
 
   virtual nsresult Focus() = 0;
   virtual nsresult Close() = 0;
 
   virtual nsresult MoveBy(int32_t aXDif, int32_t aYDif) = 0;
 
-  virtual void UpdateCommands(const nsAString& anAction, nsISelection* aSel, int16_t aReason) = 0;
+  virtual void UpdateCommands(const nsAString& anAction,
+                              mozilla::dom::Selection* aSel,
+                              int16_t aReason) = 0;
 
   mozilla::dom::DocGroup* GetDocGroup() const;
   virtual nsISerialEventTarget*
   EventTargetFor(mozilla::TaskCategory aCategory) const = 0;
 
   /**
    * These methods provide a way to specify the opener value for the content in
    * the window before the content itself is created. This is important in order
--- a/dom/clients/manager/ClientHandle.cpp
+++ b/dom/clients/manager/ClientHandle.cpp
@@ -45,22 +45,23 @@ ClientHandle::StartOp(const ClientOpCons
   // Hold a ref to the client until the remote operation completes.  Otherwise
   // the ClientHandle might get de-refed and teardown the actor before we
   // get an answer.
   RefPtr<ClientHandle> kungFuGrip = this;
 
   MaybeExecute([aArgs, kungFuGrip, aRejectCallback,
                 resolve = Move(aResolveCallback)] (ClientHandleChild* aActor) {
     ClientHandleOpChild* actor =
-      new ClientHandleOpChild(aArgs, Move(resolve), Move(aRejectCallback));
+      new ClientHandleOpChild(kungFuGrip, aArgs, Move(resolve),
+                              Move(aRejectCallback));
     if (!aActor->SendPClientHandleOpConstructor(actor, aArgs)) {
       // Constructor failure will call reject callback via ActorDestroy()
       return;
     }
-  }, [aRejectCallback, kungFuGrip] {
+  }, [aRejectCallback] {
     aRejectCallback(NS_ERROR_DOM_INVALID_STATE_ERR);
   });
 }
 
 void
 ClientHandle::OnShutdownThing()
 {
   NS_ASSERT_OWNINGTHREAD(ClientHandle);
--- a/dom/clients/manager/ClientHandleOpChild.cpp
+++ b/dom/clients/manager/ClientHandleOpChild.cpp
@@ -1,41 +1,48 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=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 "ClientHandleOpChild.h"
 
+#include "ClientHandle.h"
+
 namespace mozilla {
 namespace dom {
 
 void
 ClientHandleOpChild::ActorDestroy(ActorDestroyReason aReason)
 {
+  mClientHandle = nullptr;
   mRejectCallback(NS_ERROR_DOM_ABORT_ERR);
 }
 
 mozilla::ipc::IPCResult
 ClientHandleOpChild::Recv__delete__(const ClientOpResult& aResult)
 {
+  mClientHandle = nullptr;
   if (aResult.type() == ClientOpResult::Tnsresult &&
       NS_FAILED(aResult.get_nsresult())) {
     mRejectCallback(aResult.get_nsresult());
     return IPC_OK();
   }
   mResolveCallback(aResult);
   return IPC_OK();
 }
 
-ClientHandleOpChild::ClientHandleOpChild(const ClientOpConstructorArgs& aArgs,
+ClientHandleOpChild::ClientHandleOpChild(ClientHandle* aClientHandle,
+                                         const ClientOpConstructorArgs& aArgs,
                                          const ClientOpCallback&& aResolveCallback,
                                          const ClientOpCallback&& aRejectCallback)
-  : mResolveCallback(Move(aResolveCallback))
+  : mClientHandle(aClientHandle)
+  , mResolveCallback(Move(aResolveCallback))
   , mRejectCallback(Move(aRejectCallback))
 {
+  MOZ_DIAGNOSTIC_ASSERT(mClientHandle);
   MOZ_DIAGNOSTIC_ASSERT(mResolveCallback);
   MOZ_DIAGNOSTIC_ASSERT(mRejectCallback);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientHandleOpChild.h
+++ b/dom/clients/manager/ClientHandleOpChild.h
@@ -7,30 +7,34 @@
 #define _mozilla_dom_ClientHandleOpChild_h
 
 #include "mozilla/dom/ClientOpPromise.h"
 #include "mozilla/dom/PClientHandleOpChild.h"
 
 namespace mozilla {
 namespace dom {
 
+class ClientHandle;
+
 class ClientHandleOpChild final : public PClientHandleOpChild
 {
+  RefPtr<ClientHandle> mClientHandle;
   const ClientOpCallback mResolveCallback;
   const ClientOpCallback mRejectCallback;
 
   // PClientHandleOpChild interface
   void
   ActorDestroy(ActorDestroyReason aReason) override;
 
   mozilla::ipc::IPCResult
   Recv__delete__(const ClientOpResult& aResult) override;
 
 public:
-  ClientHandleOpChild(const ClientOpConstructorArgs& aArgs,
+  ClientHandleOpChild(ClientHandle* aClientHandle,
+                      const ClientOpConstructorArgs& aArgs,
                       const ClientOpCallback&& aResolveCallback,
                       const ClientOpCallback&& aRejectCallback);
 
   ~ClientHandleOpChild() = default;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientManager.cpp
+++ b/dom/clients/manager/ClientManager.cpp
@@ -160,22 +160,20 @@ ClientManager::StartOp(const ClientOpCon
 {
   RefPtr<ClientOpPromise::Private> promise =
     new ClientOpPromise::Private(__func__);
 
   // Hold a ref to the client until the remote operation completes.  Otherwise
   // the ClientHandle might get de-refed and teardown the actor before we
   // get an answer.
   RefPtr<ClientManager> kungFuGrip = this;
-  promise->Then(aSerialEventTarget, __func__,
-                [kungFuGrip] (const ClientOpResult&) { },
-                [kungFuGrip] (nsresult) { });
 
-  MaybeExecute([aArgs, promise] (ClientManagerChild* aActor) {
-    ClientManagerOpChild* actor = new ClientManagerOpChild(aArgs, promise);
+  MaybeExecute([aArgs, promise, kungFuGrip] (ClientManagerChild* aActor) {
+    ClientManagerOpChild* actor =
+      new ClientManagerOpChild(kungFuGrip, aArgs, promise);
     if (!aActor->SendPClientManagerOpConstructor(actor, aArgs)) {
       // Constructor failure will reject promise via ActorDestroy()
       return;
     }
   }, [promise] {
     promise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
   });
 
--- a/dom/clients/manager/ClientManagerOpChild.cpp
+++ b/dom/clients/manager/ClientManagerOpChild.cpp
@@ -1,48 +1,54 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=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 "ClientManagerOpChild.h"
 
+#include "mozilla/dom/ClientManager.h"
 #include "mozilla/ipc/ProtocolUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 void
 ClientManagerOpChild::ActorDestroy(ActorDestroyReason aReason)
 {
+  mClientManager = nullptr;
   if (mPromise) {
     mPromise->Reject(NS_ERROR_ABORT, __func__);
     mPromise = nullptr;
   }
 }
 
 mozilla::ipc::IPCResult
 ClientManagerOpChild::Recv__delete__(const ClientOpResult& aResult)
 {
+  mClientManager = nullptr;
   if (aResult.type() == ClientOpResult::Tnsresult &&
       NS_FAILED(aResult.get_nsresult())) {
     mPromise->Reject(aResult.get_nsresult(), __func__);
     mPromise = nullptr;
     return IPC_OK();
   }
   mPromise->Resolve(aResult, __func__);
   mPromise = nullptr;
   return IPC_OK();
 }
 
-ClientManagerOpChild::ClientManagerOpChild(const ClientOpConstructorArgs& aArgs,
+ClientManagerOpChild::ClientManagerOpChild(ClientManager* aClientManager,
+                                           const ClientOpConstructorArgs& aArgs,
                                            ClientOpPromise::Private* aPromise)
-  : mPromise(aPromise)
+  : mClientManager(aClientManager)
+  , mPromise(aPromise)
 {
+  MOZ_DIAGNOSTIC_ASSERT(mClientManager);
   MOZ_DIAGNOSTIC_ASSERT(mPromise);
 }
 
 ClientManagerOpChild::~ClientManagerOpChild()
 {
   MOZ_DIAGNOSTIC_ASSERT(!mPromise);
 }
 
--- a/dom/clients/manager/ClientManagerOpChild.h
+++ b/dom/clients/manager/ClientManagerOpChild.h
@@ -8,29 +8,33 @@
 
 #include "mozilla/dom/ClientOpPromise.h"
 #include "mozilla/dom/PClientManagerOpChild.h"
 #include "mozilla/MozPromise.h"
 
 namespace mozilla {
 namespace dom {
 
+class ClientManager;
+
 class ClientManagerOpChild final : public PClientManagerOpChild
 {
+  RefPtr<ClientManager> mClientManager;
   RefPtr<ClientOpPromise::Private> mPromise;
 
   // PClientManagerOpChild interface
   void
   ActorDestroy(ActorDestroyReason aReason) override;
 
   mozilla::ipc::IPCResult
   Recv__delete__(const ClientOpResult& aResult) override;
 
 public:
-  ClientManagerOpChild(const ClientOpConstructorArgs& aArgs,
+  ClientManagerOpChild(ClientManager* aClientManager,
+                       const ClientOpConstructorArgs& aArgs,
                        ClientOpPromise::Private* aPromise);
 
   ~ClientManagerOpChild();
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -16,17 +16,16 @@
 #include "nsContentUtils.h"
 #include "nsCopySupport.h"
 #include "nsElementTable.h"
 #include "nsFocusManager.h"
 #include "nsFontMetrics.h"
 #include "nsFrameSelection.h"
 #include "nsIContentIterator.h"
 #include "nsIPresShell.h"
-#include "nsISelection.h"
 #include "nsIFrame.h"
 #include "nsIObjectFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsQueryObject.h"
 #include "nsRange.h"
 #include "nsTextFragment.h"
 #include "nsTextFrame.h"
@@ -266,21 +265,17 @@ ContentEventHandler::InitRootContent(Sel
   // selection is typically has at least one range but the other selections
   // not so.  If there is a range, computing its root is easy, but if
   // there are no ranges, we need to use ancestor limit instead.
   MOZ_ASSERT(aNormalSelection->Type() == SelectionType::eNormal);
 
   if (!aNormalSelection->RangeCount()) {
     // If there is no selection range, we should compute the selection root
     // from ancestor limiter or root content of the document.
-    nsresult rv =
-      aNormalSelection->GetAncestorLimiter(getter_AddRefs(mRootContent));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return NS_ERROR_FAILURE;
-    }
+    mRootContent = aNormalSelection->GetAncestorLimiter();
     if (!mRootContent) {
       mRootContent = mDocument->GetRootElement();
       if (NS_WARN_IF(!mRootContent)) {
         return NS_ERROR_NOT_AVAILABLE;
       }
     }
     return NS_OK;
   }
@@ -334,44 +329,29 @@ ContentEventHandler::InitCommon(Selectio
 
   nsCOMPtr<nsISelectionController> selectionController;
   if (nsIPresShell* shell = mDocument->GetShell()) {
     selectionController = shell->GetSelectionControllerForFocusedContent();
   }
   if (NS_WARN_IF(!selectionController)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
-  nsCOMPtr<nsISelection> selection;
-  rv = selectionController->GetSelection(ToRawSelectionType(aSelectionType),
-                                         getter_AddRefs(selection));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return NS_ERROR_UNEXPECTED;
-  }
 
-  mSelection = static_cast<Selection*>(selection.get());
+  mSelection =
+    selectionController->GetSelection(ToRawSelectionType(aSelectionType));
   if (NS_WARN_IF(!mSelection)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   RefPtr<Selection> normalSelection;
   if (mSelection->Type() == SelectionType::eNormal) {
     normalSelection = mSelection;
   } else {
-    nsCOMPtr<nsISelection> domSelection;
-    nsresult rv =
-      selectionController->GetSelection(
-                             nsISelectionController::SELECTION_NORMAL,
-                             getter_AddRefs(domSelection));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return NS_ERROR_UNEXPECTED;
-    }
-    if (NS_WARN_IF(!domSelection)) {
-      return NS_ERROR_NOT_AVAILABLE;
-    }
-    normalSelection = domSelection->AsSelection();
+    normalSelection = 
+      selectionController->GetSelection(nsISelectionController::SELECTION_NORMAL);
     if (NS_WARN_IF(!normalSelection)) {
       return NS_ERROR_NOT_AVAILABLE;
     }
   }
 
   rv = InitRootContent(normalSelection);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -3142,21 +3122,21 @@ static void AdjustRangeForSelection(nsIC
 nsresult
 ContentEventHandler::OnSelectionEvent(WidgetSelectionEvent* aEvent)
 {
   aEvent->mSucceeded = false;
 
   // Get selection to manipulate
   // XXX why do we need to get them from ISM? This method should work fine
   //     without ISM.
-  nsCOMPtr<nsISelection> sel;
+  RefPtr<Selection> sel;
   nsresult rv =
     IMEStateManager::GetFocusSelectionAndRoot(getter_AddRefs(sel),
                                               getter_AddRefs(mRootContent));
-  mSelection = sel ? sel->AsSelection() : nullptr;
+  mSelection = sel;
   if (rv != NS_ERROR_NOT_AVAILABLE) {
     NS_ENSURE_SUCCESS(rv, rv);
   } else {
     rv = Init(aEvent);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Get range from offset and length
@@ -3199,19 +3179,19 @@ ContentEventHandler::OnSelectionEvent(Wi
     }
   }
 
   // Pass the eSetSelection events reason along with the BatchChange-end
   // selection change notifications.
   mSelection->EndBatchChanges(aEvent->mReason);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  mSelection->ScrollIntoViewInternal(
+  mSelection->ScrollIntoView(
     nsISelectionController::SELECTION_FOCUS_REGION,
-    false, nsIPresShell::ScrollAxis(), nsIPresShell::ScrollAxis());
+    nsIPresShell::ScrollAxis(), nsIPresShell::ScrollAxis(), 0);
   aEvent->mSucceeded = true;
   return NS_OK;
 }
 
 nsRect
 ContentEventHandler::FrameRelativeRect::RectRelativeTo(
                                           nsIFrame* aDestFrame) const
 {
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -233,27 +233,16 @@ Event::GetType(nsAString& aType) const
 }
 
 EventTarget*
 Event::GetTarget() const
 {
   return mEvent->GetDOMEventTarget();
 }
 
-bool
-Event::IsSrcElementEnabled(JSContext* /* unused */, JSObject* /* unused */)
-{
-  // Not a pref, because that's a pain on workers.
-#ifdef NIGHTLY_BUILD
-  return true;
-#else
-  return false;
-#endif
-}
-
 EventTarget*
 Event::GetCurrentTarget() const
 {
   return mEvent->GetCurrentDOMEventTarget();
 }
 
 void
 Event::ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath)
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -196,17 +196,16 @@ public:
   static already_AddRefed<Event> Constructor(const GlobalObject& aGlobal,
                                              const nsAString& aType,
                                              const EventInit& aParam,
                                              ErrorResult& aRv);
 
   void GetType(nsAString& aType) const;
 
   EventTarget* GetTarget() const;
-  static bool IsSrcElementEnabled(JSContext* /* unused */, JSObject* /* unused */);
   EventTarget* GetCurrentTarget() const;
 
   void ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath);
 
   uint16_t EventPhase() const;
 
   void StopPropagation();
 
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -43,17 +43,16 @@
 #include "nsIPresShell.h"
 #include "nsGkAtoms.h"
 #include "nsIFormControl.h"
 #include "nsIComboboxControlFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsIDOMXULControlElement.h"
 #include "nsNameSpaceManager.h"
 #include "nsIBaseWindow.h"
-#include "nsISelection.h"
 #include "nsFrameSelection.h"
 #include "nsPIDOMWindow.h"
 #include "nsPIWindowRoot.h"
 #include "nsIWebNavigation.h"
 #include "nsIContentViewer.h"
 #include "nsFrameManager.h"
 #include "nsITabChild.h"
 #include "nsPluginFrame.h"
@@ -83,16 +82,17 @@
 #ifdef MOZ_XUL
 #include "nsTreeBodyFrame.h"
 #endif
 #include "nsIController.h"
 #include "nsICommandParams.h"
 #include "mozilla/Services.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/HTMLLabelElement.h"
+#include "mozilla/dom/Selection.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/LookAndFeel.h"
 #include "GeckoProfiler.h"
 #include "Units.h"
 #include "nsIObjectLoadingContent.h"
 
 #ifdef XP_MACOSX
@@ -1932,17 +1932,17 @@ EventStateManager::GenerateDragGesture(n
       RefPtr<DataTransfer> dataTransfer =
         new DataTransfer(window, eDragStart, false, -1);
       auto protectDataTransfer = MakeScopeExit([&] {
         if (dataTransfer) {
           dataTransfer->Disconnect();
         }
       });
 
-      nsCOMPtr<nsISelection> selection;
+      RefPtr<Selection> selection;
       nsCOMPtr<nsIContent> eventContent, targetContent;
       nsCString principalURISpec;
       mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
       if (eventContent)
         DetermineDragTargetAndDefaultData(window, eventContent, dataTransfer,
                                           getter_AddRefs(selection),
                                           getter_AddRefs(targetContent),
                                           principalURISpec);
@@ -2025,17 +2025,17 @@ EventStateManager::GenerateDragGesture(n
     FlushPendingEvents(aPresContext);
   }
 } // GenerateDragGesture
 
 void
 EventStateManager::DetermineDragTargetAndDefaultData(nsPIDOMWindowOuter* aWindow,
                                                      nsIContent* aSelectionTarget,
                                                      DataTransfer* aDataTransfer,
-                                                     nsISelection** aSelection,
+                                                     Selection** aSelection,
                                                      nsIContent** aTargetNode,
                                                      nsACString& aPrincipalURISpec)
 {
   *aTargetNode = nullptr;
 
   // GetDragData determines if a selection, link or image in the content
   // should be dragged, and places the data associated with the drag in the
   // data transfer.
@@ -2107,17 +2107,17 @@ EventStateManager::DetermineDragTargetAn
   }
 }
 
 bool
 EventStateManager::DoDefaultDragStart(nsPresContext* aPresContext,
                                       WidgetDragEvent* aDragEvent,
                                       DataTransfer* aDataTransfer,
                                       nsIContent* aDragTarget,
-                                      nsISelection* aSelection,
+                                      Selection* aSelection,
                                       const nsACString& aPrincipalURISpec)
 {
   nsCOMPtr<nsIDragService> dragService =
     do_GetService("@mozilla.org/widget/dragservice;1");
   if (!dragService)
     return false;
 
   // Default handling for the dragstart event.
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -39,16 +39,17 @@ class EnterLeaveDispatcher;
 class EventStates;
 class IMEContentObserver;
 class ScrollbarsForWheel;
 class WheelTransaction;
 
 namespace dom {
 class DataTransfer;
 class Element;
+class Selection;
 class TabParent;
 } // namespace dom
 
 class OverOutElementsWrapper final : public nsISupports
 {
   ~OverOutElementsWrapper();
 
 public:
@@ -1019,17 +1020,17 @@ protected:
    * aTargetNode - [out] the draggable node, or null if there isn't one
    * aPrincipalURISpec - [out] set to the URI of the triggering principal of
    *                           the drag, or an empty string if it's from
    *                           browser chrome or OS
    */
   void DetermineDragTargetAndDefaultData(nsPIDOMWindowOuter* aWindow,
                                          nsIContent* aSelectionTarget,
                                          dom::DataTransfer* aDataTransfer,
-                                         nsISelection** aSelection,
+                                         dom::Selection** aSelection,
                                          nsIContent** aTargetNode,
                                          nsACString& aPrincipalURISpec);
 
   /*
    * Perform the default handling for the dragstart event and set up a
    * drag for aDataTransfer if it contains any data. Returns true if a drag has
    * started.
    *
@@ -1039,17 +1040,17 @@ protected:
    * aSelection - the selection to be dragged
    * aPrincipalURISpec - the URI of the triggering principal of the drag,
    *                     or an empty string if it's from browser chrome or OS
    */
   bool DoDefaultDragStart(nsPresContext* aPresContext,
                           WidgetDragEvent* aDragEvent,
                           dom::DataTransfer* aDataTransfer,
                           nsIContent* aDragTarget,
-                          nsISelection* aSelection,
+                          dom::Selection* aSelection,
                           const nsACString& aPrincipalURISpec);
 
   bool IsTrackingDragGesture ( ) const { return mGestureDownContent != nullptr; }
   /**
    * Set the fields of aEvent to reflect the mouse position and modifier keys
    * that were set when the user first pressed the mouse button (stored by
    * BeginTrackingDragGesture). aEvent->mWidget must be
    * mCurrentTarget->GetNearestWidget().
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -344,17 +344,17 @@ IMEContentObserver::InitWithEditor(nsPre
     selCon = do_QueryInterface(presShell);
   }
 
   if (NS_WARN_IF(!selCon)) {
     return false;
   }
 
   mSelection =
-    selCon->GetDOMSelection(nsISelectionController::SELECTION_NORMAL);
+    selCon->GetSelection(nsISelectionController::SELECTION_NORMAL);
   if (NS_WARN_IF(!mSelection)) {
     return false;
   }
 
   if (nsRange* selRange = mSelection->GetRangeAt(0)) {
     if (NS_WARN_IF(!selRange->GetStartContainer())) {
       return false;
     }
@@ -399,17 +399,17 @@ IMEContentObserver::InitWithPlugin(nsPre
     return false;
   }
   nsCOMPtr<nsISelectionController> selCon;
   frame->GetSelectionController(aPresContext, getter_AddRefs(selCon));
   if (NS_WARN_IF(!selCon)) {
     return false;
   }
   mSelection =
-    selCon->GetDOMSelection(nsISelectionController::SELECTION_NORMAL);
+    selCon->GetSelection(nsISelectionController::SELECTION_NORMAL);
   if (NS_WARN_IF(!mSelection)) {
     return false;
   }
 
   mEditorBase = nullptr;
   mEditableNode = aContent;
   mRootContent = aContent;
   // Should be safe to clear mDocumentObserver here even though it *might*
@@ -691,17 +691,17 @@ IMEContentObserver::IsEditorComposing() 
   // compositionstart event listener which is run before EditorBase handles it.
   if (NS_WARN_IF(!mEditorBase)) {
     return false;
   }
   return mEditorBase->IsIMEComposing();
 }
 
 nsresult
-IMEContentObserver::GetSelectionAndRoot(nsISelection** aSelection,
+IMEContentObserver::GetSelectionAndRoot(dom::Selection** aSelection,
                                         nsIContent** aRootContent) const
 {
   if (!mEditableNode || !mSelection) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   NS_ASSERTION(mSelection && mRootContent, "uninitialized content observer");
   NS_ADDREF(*aSelection = mSelection);
--- a/dom/events/IMEContentObserver.h
+++ b/dom/events/IMEContentObserver.h
@@ -18,17 +18,16 @@
 #include "nsIWidget.h"
 #include "nsStubDocumentObserver.h"
 #include "nsStubMutationObserver.h"
 #include "nsThreadUtils.h"
 #include "nsWeakReference.h"
 
 class nsIContent;
 class nsINode;
-class nsISelection;
 class nsPresContext;
 
 namespace mozilla {
 
 class EventStateManager;
 class TextComposition;
 
 namespace dom {
@@ -145,17 +144,17 @@ public:
   {
     return mIMENotificationRequests &&
            mIMENotificationRequests->WantDuringDeactive();
   }
   nsIWidget* GetWidget() const { return mWidget; }
   void SuppressNotifyingIME();
   void UnsuppressNotifyingIME();
   nsPresContext* GetPresContext() const;
-  nsresult GetSelectionAndRoot(nsISelection** aSelection,
+  nsresult GetSelectionAndRoot(dom::Selection** aSelection,
                                nsIContent** aRoot) const;
 
   /**
    * TryToFlushPendingNotifications() should be called when pending events
    * should be flushed.  This tries to run the queued IMENotificationSender.
    * Doesn't do anything in child processes where flushing happens
    * asynchronously unless aAllowAsync is false.
    */
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -29,17 +29,16 @@
 #include "nsContentUtils.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIForm.h"
 #include "nsIFormControl.h"
 #include "nsINode.h"
 #include "nsIObserverService.h"
 #include "nsIPresShell.h"
-#include "nsISelection.h"
 #include "nsISupports.h"
 #include "nsPresContext.h"
 
 namespace mozilla {
 
 using namespace dom;
 using namespace widget;
 
@@ -1944,17 +1943,17 @@ IMEStateManager::CreateIMEContentObserve
   // instance.  So, sActiveIMEContentObserver would be replaced with new one.
   // We should hold the current instance here.
   RefPtr<IMEContentObserver> activeIMEContentObserver(sActiveIMEContentObserver);
   activeIMEContentObserver->Init(widget, sPresContext, sContent, aEditorBase);
 }
 
 // static
 nsresult
-IMEStateManager::GetFocusSelectionAndRoot(nsISelection** aSelection,
+IMEStateManager::GetFocusSelectionAndRoot(Selection** aSelection,
                                           nsIContent** aRootContent)
 {
   if (!sActiveIMEContentObserver) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   return sActiveIMEContentObserver->GetSelectionAndRoot(aSelection,
                                                         aRootContent);
 }
--- a/dom/events/IMEStateManager.h
+++ b/dom/events/IMEStateManager.h
@@ -10,26 +10,29 @@
 #include "mozilla/EventForwards.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/dom/TabParent.h"
 #include "nsIWidget.h"
 
 class nsIContent;
 class nsINode;
 class nsPresContext;
-class nsISelection;
 
 namespace mozilla {
 
 class EditorBase;
 class EventDispatchingCallback;
 class IMEContentObserver;
 class TextCompositionArray;
 class TextComposition;
 
+namespace dom {
+class Selection;
+} // namespace dom
+
 /**
  * IMEStateManager manages InputContext (e.g., active editor type, IME enabled
  * state and IME open state) of nsIWidget instances, manages IMEContentObserver
  * and provides useful API for IME.
  */
 
 class IMEStateManager
 {
@@ -146,17 +149,17 @@ public:
    */
   static void OnInstalledMenuKeyboardListener(bool aInstalling);
 
   // These two methods manage focus and selection/text observers.
   // They are separate from OnChangeFocus above because this offers finer
   // control compared to having the two methods incorporated into OnChangeFocus
 
   // Get the focused editor's selection and root
-  static nsresult GetFocusSelectionAndRoot(nsISelection** aSel,
+  static nsresult GetFocusSelectionAndRoot(dom::Selection** aSel,
                                            nsIContent** aRoot);
   // This method updates the current IME state.  However, if the enabled state
   // isn't changed by the new state, this method does nothing.
   // Note that this method changes the IME state of the active element in the
   // widget.  So, the caller must have focus.
   static void UpdateIMEState(const IMEState &aNewIMEState,
                              nsIContent* aContent,
                              EditorBase* aEditorBase);
--- a/dom/html/HTMLSlotElement.cpp
+++ b/dom/html/HTMLSlotElement.cpp
@@ -29,19 +29,17 @@ NS_NewHTMLSlotElement(already_AddRefed<m
 namespace mozilla {
 namespace dom {
 
 HTMLSlotElement::HTMLSlotElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
 {
 }
 
-HTMLSlotElement::~HTMLSlotElement()
-{
-}
+HTMLSlotElement::~HTMLSlotElement() = default;
 
 NS_IMPL_ADDREF_INHERITED(HTMLSlotElement, nsGenericHTMLElement)
 NS_IMPL_RELEASE_INHERITED(HTMLSlotElement, nsGenericHTMLElement)
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLSlotElement,
                                    nsGenericHTMLElement,
                                    mAssignedNodes)
 
@@ -211,24 +209,35 @@ HTMLSlotElement::ClearAssignedNodes()
                node->AsContent()->GetAssignedSlot() == this, "How exactly?");
     node->AsContent()->SetAssignedSlot(nullptr);
   }
 
   mAssignedNodes.Clear();
 }
 
 void
-HTMLSlotElement::EnqueueSlotChangeEvent() const
+HTMLSlotElement::EnqueueSlotChangeEvent()
 {
+  if (mInSignalSlotList) {
+    return;
+  }
+
+  // FIXME(bug 1459704): Need to figure out how to deal with microtasks posted
+  // during shutdown.
+  if (gXPCOMThreadsShutDown) {
+    return;
+  }
+
   DocGroup* docGroup = OwnerDoc()->GetDocGroup();
   if (!docGroup) {
     return;
   }
 
-  docGroup->SignalSlotChange(this);
+  mInSignalSlotList = true;
+  docGroup->SignalSlotChange(*this);
 }
 
 void
 HTMLSlotElement::FireSlotChangeEvent()
 {
   nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
                                        static_cast<nsIContent*>(this),
                                        NS_LITERAL_STRING("slotchange"), true,
--- a/dom/html/HTMLSlotElement.h
+++ b/dom/html/HTMLSlotElement.h
@@ -58,23 +58,34 @@ public:
 
   // Helper methods
   const nsTArray<RefPtr<nsINode>>& AssignedNodes() const;
   void InsertAssignedNode(uint32_t aIndex, nsINode* aNode);
   void AppendAssignedNode(nsINode* aNode);
   void RemoveAssignedNode(nsINode* aNode);
   void ClearAssignedNodes();
 
-  void EnqueueSlotChangeEvent() const;
+  void EnqueueSlotChangeEvent();
+  void RemovedFromSignalSlotList()
+  {
+    MOZ_ASSERT(mInSignalSlotList);
+    mInSignalSlotList = false;
+  }
+
   void FireSlotChangeEvent();
 
 protected:
   virtual ~HTMLSlotElement();
-  virtual JSObject*
-  WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+  JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) final;
 
   nsTArray<RefPtr<nsINode>> mAssignedNodes;
+
+  // Whether we're in the signal slot list of our unit of related similar-origin
+  // browsing contexts.
+  //
+  // https://dom.spec.whatwg.org/#signal-slot-list
+  bool mInSignalSlotList = false;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLSlotElement_h
--- a/dom/html/TextInputListener.h
+++ b/dom/html/TextInputListener.h
@@ -8,22 +8,25 @@
 #define mozilla_TextInputListener_h
 
 #include "nsCycleCollectionParticipant.h"
 #include "nsIDOMEventListener.h"
 #include "nsStringFwd.h"
 #include "nsWeakReference.h"
 
 class nsIFrame;
-class nsISelection;
 class nsITextControlElement;
 class nsTextControlFrame;
 
 namespace mozilla {
 
+namespace dom {
+class Selection;
+} // namespace dom
+
 class TextInputListener final : public nsIDOMEventListener
                               , public nsSupportsWeakReference
 {
 public:
   explicit TextInputListener(nsITextControlElement* aTextControlElement);
 
   void SetFrame(nsIFrame* aTextControlFrame)
   {
@@ -70,17 +73,17 @@ public:
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(TextInputListener,
                                            nsIDOMEventListener)
   NS_DECL_NSIDOMEVENTLISTENER
 
 protected:
   virtual ~TextInputListener() = default;
 
   nsresult UpdateTextInputCommands(const nsAString& aCommandsToUpdate,
-                                   nsISelection* aSelection = nullptr,
+                                   dom::Selection* aSelection = nullptr,
                                    int16_t aReason = 0);
 
 protected:
   nsIFrame* mFrame;
   nsITextControlElement* const mTxtCtrlElement;
 
   bool mSelectionWasCollapsed;
 
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -55,17 +55,16 @@
 #include "nsIComponentManager.h"
 #include "nsParserCIID.h"
 #include "nsNameSpaceManager.h"
 #include "nsGenericHTMLElement.h"
 #include "mozilla/css/Loader.h"
 #include "nsIHttpChannel.h"
 #include "nsIFile.h"
 #include "nsFrameSelection.h"
-#include "nsISelectionPrivate.h" //for toStringwithformat code
 
 #include "nsContentUtils.h"
 #include "nsJSUtils.h"
 #include "nsIDocumentInlines.h"
 #include "nsIDocumentEncoder.h" //for outputting selection
 #include "nsICachingChannel.h"
 #include "nsIContentViewer.h"
 #include "nsIWyciwygChannel.h"
@@ -2536,17 +2535,17 @@ nsHTMLDocument::EditingStateChanged()
   if (spellRecheckAll) {
     nsCOMPtr<nsISelectionController> selectionController =
       htmlEditor->GetSelectionController();
     if (NS_WARN_IF(!selectionController)) {
       return NS_ERROR_FAILURE;
     }
 
     RefPtr<Selection> spellCheckSelection =
-      selectionController->GetDOMSelection(
+      selectionController->GetSelection(
         nsISelectionController::SELECTION_SPELLCHECK);
     if (spellCheckSelection) {
       spellCheckSelection->RemoveAllRanges(IgnoreErrors());
     }
   }
   htmlEditor->SyncRealTimeSpell();
 
   return NS_OK;
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -22,17 +22,16 @@
 #include "nsIControllerContext.h"
 #include "nsAttrValue.h"
 #include "nsAttrValueInlines.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIDOMEventListener.h"
 #include "nsIEditorObserver.h"
 #include "nsIWidget.h"
 #include "nsIDocumentEncoder.h"
-#include "nsISelectionPrivate.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/TextEditRules.h"
 #include "mozilla/EventListenerManager.h"
 #include "nsContentUtils.h"
 #include "mozilla/Preferences.h"
 #include "nsTextNode.h"
@@ -294,19 +293,19 @@ public:
   // Will return null if !mFrameSelection.
   Selection* GetSelection(SelectionType aSelectionType);
 
   //NSISELECTIONCONTROLLER INTERFACES
   NS_IMETHOD SetDisplaySelection(int16_t toggle) override;
   NS_IMETHOD GetDisplaySelection(int16_t* _retval) override;
   NS_IMETHOD SetSelectionFlags(int16_t aInEnable) override;
   NS_IMETHOD GetSelectionFlags(int16_t *aOutEnable) override;
-  NS_IMETHOD GetSelection(RawSelectionType aRawSelectionType,
-                          nsISelection** aSelection) override;
-  Selection* GetDOMSelection(RawSelectionType aRawSelectionType) override;
+  NS_IMETHOD GetSelectionFromScript(RawSelectionType aRawSelectionType,
+                                    Selection** aSelection) override;
+  Selection* GetSelection(RawSelectionType aRawSelectionType) override;
   NS_IMETHOD ScrollSelectionIntoView(RawSelectionType aRawSelectionType,
                                      int16_t aRegion, int16_t aFlags) override;
   NS_IMETHOD RepaintSelection(RawSelectionType aRawSelectionType) override;
   nsresult RepaintSelection(nsPresContext* aPresContext,
                             SelectionType aSelectionType);
   NS_IMETHOD SetCaretEnabled(bool enabled) override;
   NS_IMETHOD SetCaretReadOnly(bool aReadOnly) override;
   NS_IMETHOD GetCaretEnabled(bool* _retval) override;
@@ -417,18 +416,18 @@ nsTextInputSelectionImpl::SetSelectionFl
 NS_IMETHODIMP
 nsTextInputSelectionImpl::GetSelectionFlags(int16_t *aOutEnable)
 {
   *aOutEnable = nsISelectionDisplay::DISPLAY_TEXT;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsTextInputSelectionImpl::GetSelection(RawSelectionType aRawSelectionType,
-                                       nsISelection** aSelection)
+nsTextInputSelectionImpl::GetSelectionFromScript(RawSelectionType aRawSelectionType,
+                                                 Selection** aSelection)
 {
   if (!mFrameSelection)
     return NS_ERROR_NULL_POINTER;
 
   *aSelection =
     mFrameSelection->GetSelection(ToSelectionType(aRawSelectionType));
 
   // GetSelection() fails only when aRawSelectionType is invalid value.
@@ -436,17 +435,17 @@ nsTextInputSelectionImpl::GetSelection(R
     return NS_ERROR_INVALID_ARG;
   }
 
   NS_ADDREF(*aSelection);
   return NS_OK;
 }
 
 Selection*
-nsTextInputSelectionImpl::GetDOMSelection(RawSelectionType aRawSelectionType)
+nsTextInputSelectionImpl::GetSelection(RawSelectionType aRawSelectionType)
 {
   return GetSelection(ToSelectionType(aRawSelectionType));
 }
 
 NS_IMETHODIMP
 nsTextInputSelectionImpl::ScrollSelectionIntoView(
                             RawSelectionType aRawSelectionType,
                             int16_t aRegion,
@@ -1025,17 +1024,17 @@ TextInputListener::HandleValueChanged(ns
   if (!mSettingValue) {
     mTxtCtrlElement->OnValueChanged(/* aNotify = */ true,
                                     /* aWasInteractiveUserChange = */ true);
   }
 }
 
 nsresult
 TextInputListener::UpdateTextInputCommands(const nsAString& aCommandsToUpdate,
-                                           nsISelection* aSelection,
+                                           Selection* aSelection,
                                            int16_t aReason)
 {
   nsIContent* content = mFrame->GetContent();
   NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIDocument> doc = content->GetComposedDoc();
   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
 
@@ -1657,17 +1656,17 @@ nsTextEditorState::GetSelectionDirection
   }
 
   Selection* sel = mSelCon->GetSelection(SelectionType::eNormal);
   if (NS_WARN_IF(!sel)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nsITextControlFrame::eForward; // Doesn't really matter
   }
 
-  nsDirection direction = sel->GetSelectionDirection();
+  nsDirection direction = sel->GetDirection();
   if (direction == eDirNext) {
     return nsITextControlFrame::eForward;
   }
 
   MOZ_ASSERT(direction == eDirPrevious);
   return nsITextControlFrame::eBackward;
 }
 
--- a/dom/interfaces/base/nsIDOMWindow.idl
+++ b/dom/interfaces/base/nsIDOMWindow.idl
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 
 interface nsIControllers;
 interface nsIDOMBlob;
 interface nsIDOMOfflineResourceList;
 interface nsIPrompt;
-interface nsISelection;
 interface nsIVariant;
 
 /**
  * Empty interface for compatibility with older versions.
  * @deprecated Use WebIDL for script visible features,
  *             nsPIDOMWindow for C++ callers.
  */
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -600,16 +600,17 @@ ContentChild::RecvSetXPCOMProcessAttribu
   InitGraphicsDeviceData(aXPCOMInit.contentDeviceData());
 
   return IPC_OK();
 }
 
 bool
 ContentChild::Init(MessageLoop* aIOLoop,
                    base::ProcessId aParentPid,
+                   const char* aParentBuildID,
                    IPC::Channel* aChannel,
                    uint64_t aChildID,
                    bool aIsForBrowser)
 {
 #ifdef MOZ_WIDGET_GTK
   // When running X11 only build we need to pass a display down
   // to gtk_init because it's not going to use the one from the environment
   // on its own when deciding which backend to use, and when starting under
@@ -668,20 +669,25 @@ ContentChild::Init(MessageLoop* aIOLoop,
 
   // If communications with the parent have broken down, take the process
   // down so it's not hanging around.
   GetIPCChannel()->SetAbortOnError(true);
 #if defined(XP_WIN) && defined(ACCESSIBILITY)
   GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_A11Y_REENTRY);
 #endif
 
-  // This must be sent before any IPDL message, which may hit sentinel
+  // This must be checked before any IPDL message, which may hit sentinel
   // errors due to parent and content processes having different
   // versions.
-  GetIPCChannel()->SendBuildID();
+  MessageChannel* channel = GetIPCChannel();
+  if (channel && !channel->SendBuildIDsMatchMessage(aParentBuildID)) {
+    // We need to quit this process if the buildID doesn't match the parent's.
+    // This can occur when an update occurred in the background.
+    ProcessChild::QuickExit();
+  }
 
 #ifdef MOZ_X11
   if (!gfxPlatform::IsHeadless()) {
     // Send the parent our X socket to act as a proxy reference for our X
     // resources.
     int xSocketFd = ConnectionNumber(DefaultXDisplay());
     SendBackUpXResources(FileDescriptor(xSocketFd));
   }
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -115,16 +115,17 @@ public:
                       const nsACString& aFeatures,
                       bool aForceNoOpener,
                       nsIDocShellLoadInfo* aLoadInfo,
                       bool* aWindowIsNew,
                       mozIDOMWindowProxy** aReturn);
 
   bool Init(MessageLoop* aIOLoop,
             base::ProcessId aParentPid,
+            const char* aParentBuildID,
             IPC::Channel* aChannel,
             uint64_t aChildID,
             bool aIsForBrowser);
 
   void InitXPCOM(const XPCOMInitData& aXPCOMInit,
                  const mozilla::dom::ipc::StructuredCloneData& aInitialData);
 
   void InitGraphicsDeviceData(const ContentDeviceData& aData);
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2049,16 +2049,20 @@ ContentParent::LaunchSubprocess(ProcessP
   nsCString schedulerPrefs = Scheduler::GetPrefs();
   extraArgs.push_back("-schedulerPrefs");
   extraArgs.push_back(schedulerPrefs.get());
 
   if (gSafeMode) {
     extraArgs.push_back("-safeMode");
   }
 
+  nsCString parentBuildID(mozilla::PlatformBuildID());
+  extraArgs.push_back("-parentBuildID");
+  extraArgs.push_back(parentBuildID.get());
+
   SetOtherProcessId(kInvalidProcessId, ProcessIdState::ePending);
   if (!mSubprocess->Launch(extraArgs)) {
     NS_ERROR("failed to launch child in the parent");
     MarkAsDead();
     return false;
   }
 
   OpenWithAsyncPid(mSubprocess->GetChannel());
--- a/dom/ipc/ContentProcess.cpp
+++ b/dom/ipc/ContentProcess.cpp
@@ -94,16 +94,17 @@ SetPrefsFd(int aFd)
 bool
 ContentProcess::Init(int aArgc, char* aArgv[])
 {
   Maybe<uint64_t> childID;
   Maybe<bool> isForBrowser;
   Maybe<base::SharedMemoryHandle> prefsHandle;
   Maybe<size_t> prefsLen;
   Maybe<const char*> schedulerPrefs;
+  Maybe<const char*> parentBuildID;
 #if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
   nsCOMPtr<nsIFile> profileDir;
 #endif
 
   for (int i = 1; i < aArgc; i++) {
     if (!aArgv[i]) {
       continue;
     }
@@ -163,16 +164,22 @@ ContentProcess::Init(int aArgc, char* aA
       if (++i == aArgc) {
         return false;
       }
       schedulerPrefs = Some(aArgv[i]);
 
     } else if (strcmp(aArgv[i], "-safeMode") == 0) {
       gSafeMode = true;
 
+    } else if (strcmp(aArgv[i], "-parentBuildID") == 0) {
+      if (++i == aArgc) {
+        return false;
+      }
+      parentBuildID = Some(aArgv[i]);
+
 #if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
     } else if (strcmp(aArgv[i], "-profile") == 0) {
       if (++i == aArgc) {
         return false;
       }
       bool flag;
       nsresult rv = XRE_GetFileFromPath(aArgv[i], getter_AddRefs(profileDir));
       if (NS_FAILED(rv) || NS_FAILED(profileDir->Exists(&flag)) || !flag) {
@@ -192,17 +199,18 @@ ContentProcess::Init(int aArgc, char* aA
                                           /* auto_close */ true));
 #endif
 
   // Did we find all the mandatory flags?
   if (childID.isNothing() ||
       isForBrowser.isNothing() ||
       prefsHandle.isNothing() ||
       prefsLen.isNothing() ||
-      schedulerPrefs.isNothing()) {
+      schedulerPrefs.isNothing() ||
+      parentBuildID.isNothing()) {
     return false;
   }
 
   // Set up early prefs from the shared memory.
   base::SharedMemory shm;
   if (!shm.SetHandle(*prefsHandle, /* read_only */ true)) {
     NS_ERROR("failed to open shared memory in the child");
     return false;
@@ -212,16 +220,17 @@ ContentProcess::Init(int aArgc, char* aA
     return false;
   }
   Preferences::DeserializePreferences(static_cast<char*>(shm.memory()),
                                       *prefsLen);
 
   Scheduler::SetPrefs(*schedulerPrefs);
   mContent.Init(IOThreadChild::message_loop(),
                 ParentPid(),
+                *parentBuildID,
                 IOThreadChild::channel(),
                 *childID,
                 *isForBrowser);
   mXREEmbed.Start();
 #if (defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
   mContent.SetProfileDir(profileDir);
 #endif
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -461,20 +461,26 @@ TabParent::ActorDestroy(ActorDestroyReas
                           "oop-frameloader-crashed", nullptr);
       nsCOMPtr<nsIFrameLoaderOwner> owner = do_QueryInterface(frameElement);
       if (owner) {
         RefPtr<nsFrameLoader> currentFrameLoader = owner->GetFrameLoader();
         // It's possible that the frameloader owner has already moved on
         // and created a new frameloader. If so, we don't fire the event,
         // since the frameloader owner has clearly moved on.
         if (currentFrameLoader == frameLoader) {
-          nsContentUtils::DispatchTrustedEvent(frameElement->OwnerDoc(), frameElement,
-                                               NS_LITERAL_STRING("oop-browser-crashed"),
-                                               true, true);
-
+          MessageChannel* channel = GetIPCChannel();
+          if (channel && !channel->DoBuildIDsMatch()) {
+            nsContentUtils::DispatchTrustedEvent(
+              frameElement->OwnerDoc(), frameElement,
+              NS_LITERAL_STRING("oop-browser-buildid-mismatch"), true, true);
+          } else {
+            nsContentUtils::DispatchTrustedEvent(
+              frameElement->OwnerDoc(), frameElement,
+              NS_LITERAL_STRING("oop-browser-crashed"), true, true);
+          }
         }
       }
     }
 
     mFrameLoader = nullptr;
   }
 
   if (os) {
new file mode 100644
--- /dev/null
+++ b/dom/security/PolicyTokenizer.cpp
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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 "PolicyTokenizer.h"
+
+static LogModule*
+GetPolicyTokenizerLog()
+{
+  static LazyLogModule gPolicyTokenizerPRLog("PolicyTokenizer");
+  return gPolicyTokenizerPRLog;
+}
+
+#define POLICYTOKENIZERLOG(args) MOZ_LOG(GetPolicyTokenizerLog(), mozilla::LogLevel::Debug, args)
+
+static const char16_t SEMICOL = ';';
+
+PolicyTokenizer::PolicyTokenizer(const char16_t* aStart,
+                                 const char16_t* aEnd)
+  : mCurChar(aStart)
+  , mEndChar(aEnd)
+{
+  POLICYTOKENIZERLOG(("PolicyTokenizer::PolicyTokenizer"));
+}
+
+PolicyTokenizer::~PolicyTokenizer()
+{
+  POLICYTOKENIZERLOG(("PolicyTokenizer::~PolicyTokenizer"));
+}
+
+void
+PolicyTokenizer::generateNextToken()
+{
+  skipWhiteSpaceAndSemicolon();
+  while (!atEnd() &&
+         !nsContentUtils::IsHTMLWhitespace(*mCurChar) &&
+         *mCurChar != SEMICOL) {
+    mCurToken.Append(*mCurChar++);
+  }
+  POLICYTOKENIZERLOG(("PolicyTokenizer::generateNextToken: %s", NS_ConvertUTF16toUTF8(mCurToken).get()));
+}
+
+void
+PolicyTokenizer::generateTokens(policyTokens& outTokens)
+{
+  POLICYTOKENIZERLOG(("PolicyTokenizer::generateTokens"));
+
+  // dirAndSrcs holds one set of [ name, src, src, src, ... ]
+  nsTArray <nsString> dirAndSrcs;
+
+  while (!atEnd()) {
+    generateNextToken();
+    dirAndSrcs.AppendElement(mCurToken);
+    skipWhiteSpace();
+    if (atEnd() || accept(SEMICOL)) {
+      outTokens.AppendElement(dirAndSrcs);
+      dirAndSrcs.Clear();
+    }
+  }
+}
+
+void
+PolicyTokenizer::tokenizePolicy(const nsAString &aPolicyString,
+                                policyTokens& outTokens)
+{
+  POLICYTOKENIZERLOG(("PolicyTokenizer::tokenizePolicy"));
+
+  PolicyTokenizer tokenizer(aPolicyString.BeginReading(),
+                            aPolicyString.EndReading());
+
+  tokenizer.generateTokens(outTokens);
+}
new file mode 100644
--- /dev/null
+++ b/dom/security/PolicyTokenizer.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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 PolicyTokenizer_h___
+#define PolicyTokenizer_h___
+
+#include "nsContentUtils.h"
+#include "nsString.h"
+
+/**
+ * How does the parsing work?
+ *
+ * We generate tokens by splitting the policy-string by whitespace and semicolon.
+ * Interally the tokens are represented as an array of string-arrays:
+ *
+ *  [
+ *    [ name, src, src, src, ... ],
+ *    [ name, src, src, src, ... ],
+ *    [ name, src, src, src, ... ]
+ *  ]
+ *
+ * for example:
+ *  [
+ *    [ img-src, http://www.example.com, http:www.test.com ],
+ *    [ default-src, 'self'],
+ *    [ script-src, 'unsafe-eval', 'unsafe-inline' ],
+ *  ]
+ */
+
+typedef nsTArray< nsTArray<nsString> > policyTokens;
+
+class PolicyTokenizer {
+
+  public:
+    static void tokenizePolicy(const nsAString &aPolicyString, policyTokens& outTokens);
+
+  private:
+    PolicyTokenizer(const char16_t* aStart, const char16_t* aEnd);
+    ~PolicyTokenizer();
+
+    inline bool atEnd()
+    {
+      return mCurChar >= mEndChar;
+    }
+
+    inline void skipWhiteSpace()
+    {
+      while (mCurChar < mEndChar &&
+             nsContentUtils::IsHTMLWhitespace(*mCurChar)) {
+        mCurToken.Append(*mCurChar++);
+      }
+      mCurToken.Truncate();
+    }
+
+    inline void skipWhiteSpaceAndSemicolon()
+    {
+      while (mCurChar < mEndChar && (*mCurChar == ';' ||
+             nsContentUtils::IsHTMLWhitespace(*mCurChar))){
+        mCurToken.Append(*mCurChar++);
+      }
+      mCurToken.Truncate();
+    }
+
+    inline bool accept(char16_t aChar)
+    {
+      NS_ASSERTION(mCurChar < mEndChar, "Trying to dereference mEndChar");
+      if (*mCurChar == aChar) {
+        mCurToken.Append(*mCurChar++);
+        return true;
+      }
+      return false;
+    }
+
+    void generateNextToken();
+    void generateTokens(policyTokens& outTokens);
+
+    const char16_t* mCurChar;
+    const char16_t* mEndChar;
+    nsString        mCurToken;
+};
+
+#endif /* PolicyTokenizer_h___ */
--- a/dom/security/moz.build
+++ b/dom/security/moz.build
@@ -12,16 +12,17 @@ TEST_DIRS += ['test']
 EXPORTS.mozilla.dom += [
     'ContentVerifier.h',
     'FramingChecker.h',
     'nsContentSecurityManager.h',
     'nsCSPContext.h',
     'nsCSPService.h',
     'nsCSPUtils.h',
     'nsMixedContentBlocker.h',
+    'PolicyTokenizer.h',
     'SRICheck.h',
     'SRILogHelper.h',
     'SRIMetadata.h',
 ]
 
 EXPORTS += [
     'nsContentSecurityManager.h',
     'nsMixedContentBlocker.h',
@@ -31,16 +32,17 @@ UNIFIED_SOURCES += [
     'ContentVerifier.cpp',
     'FramingChecker.cpp',
     'nsContentSecurityManager.cpp',
     'nsCSPContext.cpp',
     'nsCSPParser.cpp',
     'nsCSPService.cpp',
     'nsCSPUtils.cpp',
     'nsMixedContentBlocker.cpp',
+    'PolicyTokenizer.cpp',
     'SRICheck.cpp',
     'SRIMetadata.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
--- a/dom/security/nsCSPParser.cpp
+++ b/dom/security/nsCSPParser.cpp
@@ -56,79 +56,21 @@ static const char16_t ATSYMBOL     = '@'
 static const uint32_t kSubHostPathCharacterCutoff = 512;
 
 static const char *const kHashSourceValidFns [] = { "sha256", "sha384", "sha512" };
 static const uint32_t kHashSourceValidFnsLen = 3;
 
 static const char* const kStyle    = "style";
 static const char* const kScript   = "script";
 
-/* ===== nsCSPTokenizer ==================== */
-
-nsCSPTokenizer::nsCSPTokenizer(const char16_t* aStart,
-                               const char16_t* aEnd)
-  : mCurChar(aStart)
-  , mEndChar(aEnd)
-{
-  CSPPARSERLOG(("nsCSPTokenizer::nsCSPTokenizer"));
-}
-
-nsCSPTokenizer::~nsCSPTokenizer()
-{
-  CSPPARSERLOG(("nsCSPTokenizer::~nsCSPTokenizer"));
-}
-
-void
-nsCSPTokenizer::generateNextToken()
-{
-  skipWhiteSpaceAndSemicolon();
-  while (!atEnd() &&
-         !nsContentUtils::IsHTMLWhitespace(*mCurChar) &&
-         *mCurChar != SEMICOLON) {
-    mCurToken.Append(*mCurChar++);
-  }
-  CSPPARSERLOG(("nsCSPTokenizer::generateNextToken: %s", NS_ConvertUTF16toUTF8(mCurToken).get()));
-}
-
-void
-nsCSPTokenizer::generateTokens(cspTokens& outTokens)
-{
-  CSPPARSERLOG(("nsCSPTokenizer::generateTokens"));
-
-  // dirAndSrcs holds one set of [ name, src, src, src, ... ]
-  nsTArray <nsString> dirAndSrcs;
-
-  while (!atEnd()) {
-    generateNextToken();
-    dirAndSrcs.AppendElement(mCurToken);
-    skipWhiteSpace();
-    if (atEnd() || accept(SEMICOLON)) {
-      outTokens.AppendElement(dirAndSrcs);
-      dirAndSrcs.Clear();
-    }
-  }
-}
-
-void
-nsCSPTokenizer::tokenizeCSPPolicy(const nsAString &aPolicyString,
-                                  cspTokens& outTokens)
-{
-  CSPPARSERLOG(("nsCSPTokenizer::tokenizeCSPPolicy"));
-
-  nsCSPTokenizer tokenizer(aPolicyString.BeginReading(),
-                           aPolicyString.EndReading());
-
-  tokenizer.generateTokens(outTokens);
-}
-
 /* ===== nsCSPParser ==================== */
 bool nsCSPParser::sCSPExperimentalEnabled = false;
 bool nsCSPParser::sStrictDynamicEnabled = false;
 
-nsCSPParser::nsCSPParser(cspTokens& aTokens,
+nsCSPParser::nsCSPParser(policyTokens& aTokens,
                          nsIURI* aSelfURI,
                          nsCSPContext* aCSPContext,
                          bool aDeliveredViaMetaTag)
  : mCurChar(nullptr)
  , mEndChar(nullptr)
  , mHasHashOrNonce(false)
  , mStrictDynamic(false)
  , mUnsafeInlineKeywordSrc(nullptr)
@@ -1365,17 +1307,17 @@ nsCSPParser::parseContentSecurityPolicy(
   NS_ASSERTION(aSelfURI, "Can not parseContentSecurityPolicy without aSelfURI");
 
   // Separate all input into tokens and store them in the form of:
   // [ [ name, src, src, ... ], [ name, src, src, ... ], ... ]
   // The tokenizer itself can not fail; all eventual errors
   // are detected in the parser itself.
 
   nsTArray< nsTArray<nsString> > tokens;
-  nsCSPTokenizer::tokenizeCSPPolicy(aPolicyString, tokens);
+  PolicyTokenizer::tokenizePolicy(aPolicyString, tokens);
 
   nsCSPParser parser(tokens, aSelfURI, aCSPContext, aDeliveredViaMetaTag);
 
   // Start the parser to generate a new CSPPolicy using the generated tokens.
   nsCSPPolicy* policy = parser.policy();
 
   // Check that report-only policies define a report-uri, otherwise log warning.
   if (aReportOnly) {
--- a/dom/security/nsCSPParser.h
+++ b/dom/security/nsCSPParser.h
@@ -4,95 +4,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/. */
 
 #ifndef nsCSPParser_h___
 #define nsCSPParser_h___
 
 #include "nsCSPUtils.h"
 #include "nsIURI.h"
-#include "nsString.h"
-
-/**
- * How does the parsing work?
- *
- * We generate tokens by splitting the policy-string by whitespace and semicolon.
- * Interally the tokens are represented as an array of string-arrays:
- *
- *  [
- *    [ name, src, src, src, ... ],
- *    [ name, src, src, src, ... ],
- *    [ name, src, src, src, ... ]
- *  ]
- *
- * for example:
- *  [
- *    [ img-src, http://www.example.com, http:www.test.com ],
- *    [ default-src, 'self'],
- *    [ script-src, 'unsafe-eval', 'unsafe-inline' ],
- *  ]
- *
- * The first element of each array has to be a valid directive-name, otherwise we can
- * ignore the remaining elements of the array. Also, if the
- * directive already exists in the current policy, we can ignore
- * the remaining elements of that array. (http://www.w3.org/TR/CSP/#parsing)
- */
-
-typedef nsTArray< nsTArray<nsString> > cspTokens;
-
-class nsCSPTokenizer {
-
-  public:
-    static void tokenizeCSPPolicy(const nsAString &aPolicyString, cspTokens& outTokens);
-
-  private:
-    nsCSPTokenizer(const char16_t* aStart, const char16_t* aEnd);
-    ~nsCSPTokenizer();
-
-    inline bool atEnd()
-    {
-      return mCurChar >= mEndChar;
-    }
-
-    inline void skipWhiteSpace()
-    {
-      while (mCurChar < mEndChar &&
-             nsContentUtils::IsHTMLWhitespace(*mCurChar)) {
-        mCurToken.Append(*mCurChar++);
-      }
-      mCurToken.Truncate();
-    }
-
-    inline void skipWhiteSpaceAndSemicolon()
-    {
-      while (mCurChar < mEndChar && (*mCurChar == ';' ||
-             nsContentUtils::IsHTMLWhitespace(*mCurChar))){
-        mCurToken.Append(*mCurChar++);
-      }
-      mCurToken.Truncate();
-    }
-
-    inline bool accept(char16_t aChar)
-    {
-      NS_ASSERTION(mCurChar < mEndChar, "Trying to dereference mEndChar");
-      if (*mCurChar == aChar) {
-        mCurToken.Append(*mCurChar++);
-        return true;
-      }
-      return false;
-    }
-
-    void generateNextToken();
-    void generateTokens(cspTokens& outTokens);
-
-    const char16_t* mCurChar;
-    const char16_t* mEndChar;
-    nsString        mCurToken;
-};
-
+#include "PolicyTokenizer.h"
 
 class nsCSPParser {
 
   public:
     /**
      * The CSP parser only has one publicly accessible function, which is parseContentSecurityPolicy.
      * Internally the input string is separated into string tokens and policy() is called, which starts
      * parsing the policy. The parser calls one function after the other according the the source-list
@@ -101,17 +23,17 @@ class nsCSPParser {
      */
     static nsCSPPolicy* parseContentSecurityPolicy(const nsAString &aPolicyString,
                                                    nsIURI *aSelfURI,
                                                    bool aReportOnly,
                                                    nsCSPContext* aCSPContext,
                                                    bool aDeliveredViaMetaTag);
 
   private:
-    nsCSPParser(cspTokens& aTokens,
+    nsCSPParser(policyTokens& aTokens,
                 nsIURI* aSelfURI,
                 nsCSPContext* aCSPContext,
                 bool aDeliveredViaMetaTag);
 
     static bool sCSPExperimentalEnabled;
     static bool sStrictDynamicEnabled;
 
     ~nsCSPParser();
@@ -253,16 +175,16 @@ class nsCSPParser {
     nsCSPDirective*          mFrameSrc;
     nsCSPDirective*          mWorkerSrc;
     nsCSPScriptSrcDirective* mScriptSrc;
 
     // cache variable to let nsCSPHostSrc know that it's within
     // the frame-ancestors directive.
     bool                    mParsingFrameAncestorsDir;
 
-    cspTokens          mTokens;
+    policyTokens       mTokens;
     nsIURI*            mSelfURI;
     nsCSPPolicy*       mPolicy;
     nsCSPContext*      mCSPContext; // used for console logging
     bool               mDeliveredViaMetaTag;
 };
 
 #endif /* nsCSPParser_h___ */
--- a/dom/serviceworkers/ServiceWorker.cpp
+++ b/dom/serviceworkers/ServiceWorker.cpp
@@ -12,17 +12,16 @@
 #include "ServiceWorkerPrivate.h"
 
 #include "mozilla/dom/DOMPrefs.h"
 #include "mozilla/dom/ClientIPCTypes.h"
 #include "mozilla/dom/ClientState.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
 #include "mozilla/dom/WorkerPrivate.h"
-#include "mozilla/dom/ipc/StructuredCloneData.h"
 
 #ifdef XP_WIN
 #undef PostMessage
 #endif
 
 using mozilla::ErrorResult;
 using namespace mozilla::dom;
 
@@ -143,52 +142,17 @@ ServiceWorker::PostMessage(JSContext* aC
                            const Sequence<JSObject*>& aTransferable,
                            ErrorResult& aRv)
 {
   if (State() == ServiceWorkerState::Redundant) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
-  nsPIDOMWindowInner* window = GetOwner();
-  if (NS_WARN_IF(!window || !window->GetExtantDoc())) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return;
-  }
-
-  auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
-  if (storageAllowed != nsContentUtils::StorageAccess::eAllow) {
-    ServiceWorkerManager::LocalizeAndReportToAllClients(
-      mDescriptor.Scope(), "ServiceWorkerPostMessageStorageError",
-      nsTArray<nsString> { NS_ConvertUTF8toUTF16(mDescriptor.Scope()) });
-    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-    return;
-  }
-
-  Maybe<ClientInfo> clientInfo = window->GetClientInfo();
-  Maybe<ClientState> clientState = window->GetClientState();
-  if (NS_WARN_IF(clientInfo.isNothing() || clientState.isNothing())) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return;
-  }
-
-  JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
-  aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
-                                                          &transferable);
-  if (aRv.Failed()) {
-    return;
-  }
-
-  ipc::StructuredCloneData data;
-  data.Write(aCx, aMessage, transferable, aRv);
-  if (aRv.Failed()) {
-    return;
-  }
-
-  mInner->PostMessage(Move(data), clientInfo.ref(), clientState.ref());
+  mInner->PostMessage(GetParentObject(), aCx, aMessage, aTransferable, aRv);
 }
 
 
 const ServiceWorkerDescriptor&
 ServiceWorker::Descriptor() const
 {
   return mDescriptor;
 }
--- a/dom/serviceworkers/ServiceWorker.h
+++ b/dom/serviceworkers/ServiceWorker.h
@@ -15,20 +15,16 @@
 #undef PostMessage
 #endif
 
 class nsIGlobalObject;
 
 namespace mozilla {
 namespace dom {
 
-namespace ipc {
-class StructuredCloneData;
-} // namespace ipc
-
 #define NS_DOM_SERVICEWORKER_IID \
   {0xd42e0611, 0x3647, 0x4319, {0xae, 0x05, 0x19, 0x89, 0x59, 0xba, 0x99, 0x5e}}
 
 bool
 ServiceWorkerVisible(JSContext* aCx, JSObject* aObj);
 
 class ServiceWorker final : public DOMEventTargetHelper
 {
@@ -53,19 +49,20 @@ public:
     AddServiceWorker(ServiceWorker* aWorker) = 0;
 
     // This is called when the DOM ServiceWorker object is
     // destroyed and drops its ref to the Inner object.
     virtual void
     RemoveServiceWorker(ServiceWorker* aWorker) = 0;
 
     virtual void
-    PostMessage(ipc::StructuredCloneData&& aData,
-                const ClientInfo& aClientInfo,
-                const ClientState& aClientState) = 0;
+    PostMessage(nsIGlobalObject* aGlobal,
+                JSContext* aCx, JS::Handle<JS::Value> aMessage,
+                const Sequence<JSObject*>& aTransferable,
+                ErrorResult& aRv) = 0;
 
     NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
   };
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_SERVICEWORKER_IID)
   NS_DECL_ISUPPORTS_INHERITED
 
   IMPL_EVENT_HANDLER(statechange)
--- a/dom/serviceworkers/ServiceWorkerInfo.cpp
+++ b/dom/serviceworkers/ServiceWorkerInfo.cpp
@@ -251,23 +251,48 @@ ServiceWorkerInfo::RemoveServiceWorker(S
     workerURL.Equals(NS_ConvertUTF8toUTF16(mDescriptor.ScriptURL())));
 #endif
 
   DebugOnly<bool> removed = mInstances.RemoveElement(aWorker);
   MOZ_ASSERT(removed);
 }
 
 void
-ServiceWorkerInfo::PostMessage(ipc::StructuredCloneData&& aData,
-                               const ClientInfo& aClientInfo,
-                               const ClientState& aClientState)
+ServiceWorkerInfo::PostMessage(nsIGlobalObject* aGlobal,
+                               JSContext* aCx, JS::Handle<JS::Value> aMessage,
+                               const Sequence<JSObject*>& aTransferable,
+                               ErrorResult& aRv)
 {
-  mServiceWorkerPrivate->SendMessageEvent(Move(aData),
-                                          ClientInfoAndState(aClientInfo.ToIPC(),
-                                                             aClientState.ToIPC()));
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
+  if (NS_WARN_IF(!window || !window->GetExtantDoc())) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
+  }
+
+  auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
+  if (storageAllowed != nsContentUtils::StorageAccess::eAllow) {
+    ServiceWorkerManager::LocalizeAndReportToAllClients(
+      Scope(), "ServiceWorkerPostMessageStorageError",
+      nsTArray<nsString> { NS_ConvertUTF8toUTF16(Scope()) });
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return;
+  }
+
+  Maybe<ClientInfo> clientInfo = window->GetClientInfo();
+  Maybe<ClientState> clientState = window->GetClientState();
+  if (NS_WARN_IF(clientInfo.isNothing() || clientState.isNothing())) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
+  }
+
+  aRv = mServiceWorkerPrivate->SendMessageEvent(aCx, aMessage, aTransferable,
+                                                ClientInfoAndState(clientInfo.ref().ToIPC(),
+                                                                   clientState.ref().ToIPC()));
 }
 
 void
 ServiceWorkerInfo::UpdateInstalledTime()
 {
   MOZ_ASSERT(State() == ServiceWorkerState::Installed);
   MOZ_ASSERT(mInstalledTime == 0);
 
--- a/dom/serviceworkers/ServiceWorkerInfo.h
+++ b/dom/serviceworkers/ServiceWorkerInfo.h
@@ -12,17 +12,16 @@
 #include "mozilla/dom/WorkerCommon.h"
 #include "mozilla/OriginAttributes.h"
 #include "nsIServiceWorkerManager.h"
 #include "ServiceWorker.h"
 
 namespace mozilla {
 namespace dom {
 
-class ClientInfoAndState;
 class ServiceWorkerPrivate;
 
 /*
  * Wherever the spec treats a worker instance and a description of said worker
  * as the same thing; i.e. "Resolve foo with
  * _GetNewestWorker(serviceWorkerRegistration)", we represent the description
  * by this class and spawn a ServiceWorker in the right global when required.
  */
@@ -81,19 +80,20 @@ private:
   // ServiceWorker::Inner implementation
   virtual void
   AddServiceWorker(ServiceWorker* aWorker) override;
 
   virtual void
   RemoveServiceWorker(ServiceWorker* aWorker) override;
 
   virtual void
-  PostMessage(ipc::StructuredCloneData&& aData,
-              const ClientInfo& aClientInfo,
-              const ClientState& aClientState) override;
+  PostMessage(nsIGlobalObject* aGlobal,
+              JSContext* aCx, JS::Handle<JS::Value> aMessage,
+              const Sequence<JSObject*>& aTransferable,
+              ErrorResult& aRv) override;
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISERVICEWORKERINFO
 
   class ServiceWorkerPrivate*
   WorkerPrivate() const
   {
--- a/dom/serviceworkers/ServiceWorkerPrivate.cpp
+++ b/dom/serviceworkers/ServiceWorkerPrivate.cpp
@@ -18,33 +18,30 @@
 #include "nsITimedChannel.h"
 #include "nsIUploadChannel2.h"
 #include "nsNetUtil.h"
 #include "nsProxyRelease.h"
 #include "nsQueryObject.h"
 #include "nsStreamUtils.h"
 #include "nsStringStream.h"
 #include "mozilla/Assertions.h"
-#include "mozilla/JSObjectHolder.h"
 #include "mozilla/dom/Client.h"
 #include "mozilla/dom/ClientIPCTypes.h"
 #include "mozilla/dom/DOMPrefs.h"
 #include "mozilla/dom/FetchUtil.h"
 #include "mozilla/dom/IndexedDatabaseManager.h"
 #include "mozilla/dom/InternalHeaders.h"
 #include "mozilla/dom/NotificationEvent.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/PushEventBinding.h"
 #include "mozilla/dom/RequestBinding.h"
-#include "mozilla/dom/StructuredCloneHolder.h"
 #include "mozilla/dom/WorkerDebugger.h"
 #include "mozilla/dom/WorkerRef.h"
 #include "mozilla/dom/WorkerRunnable.h"
 #include "mozilla/dom/WorkerScope.h"
-#include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/Unused.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 namespace mozilla {
 namespace dom {
 
@@ -210,34 +207,16 @@ ServiceWorkerPrivate::CheckScriptEvaluat
                                                                    aScriptEvaluationCallback);
   if (NS_WARN_IF(!r->Dispatch())) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
-JSObject*
-ServiceWorkerPrivate::GetOrCreateSandbox(JSContext* aCx)
-{
-  AssertIsOnMainThread();
-
-  if (!mSandbox) {
-    nsIXPConnect* xpc = nsContentUtils::XPConnect();
-
-    JS::Rooted<JSObject*> sandbox(aCx);
-    nsresult rv = xpc->CreateSandbox(aCx, mInfo->Principal(), sandbox.address());
-    NS_ENSURE_SUCCESS(rv, nullptr);
-
-    mSandbox = new JSObjectHolder(aCx, sandbox);
-  }
-
-  return mSandbox->GetJSObject();
-}
-
 namespace {
 
 enum ExtendableEventResult {
     Rejected = 0,
     Resolved
 };
 
 class ExtendableEventCallback {
@@ -516,45 +495,45 @@ public:
       return NS_ERROR_XPC_JS_THREW_EXCEPTION;
     }
 
     return NS_OK;
   }
 };
 
 class SendMessageEventRunnable final : public ExtendableEventWorkerRunnable
+                                     , public StructuredCloneHolder
 {
-  StructuredCloneHolder mData;
   const ClientInfoAndState mClientInfoAndState;
 
 public:
   SendMessageEventRunnable(WorkerPrivate*  aWorkerPrivate,
                            KeepAliveToken* aKeepAliveToken,
-                           StructuredCloneHolder&& aData,
                            const ClientInfoAndState& aClientInfoAndState)
     : ExtendableEventWorkerRunnable(aWorkerPrivate, aKeepAliveToken)
-    , mData(Move(aData))
+    , StructuredCloneHolder(CloningSupported, TransferringSupported,
+                            StructuredCloneScope::SameProcessDifferentThread)
     , mClientInfoAndState(aClientInfoAndState)
   {
     MOZ_ASSERT(NS_IsMainThread());
   }
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
     JS::Rooted<JS::Value> messageData(aCx);
     nsCOMPtr<nsIGlobalObject> sgo = aWorkerPrivate->GlobalScope();
     ErrorResult rv;
-    mData.Read(sgo, aCx, &messageData, rv);
+    Read(sgo, aCx, &messageData, rv);
     if (NS_WARN_IF(rv.Failed())) {
       return true;
     }
 
     Sequence<OwningNonNull<MessagePort>> ports;
-    if (!mData.TakeTransferredPortsAsSequence(ports)) {
+    if (!TakeTransferredPortsAsSequence(ports)) {
       return true;
     }
 
     RootedDictionary<ExtendableMessageEventInit> init(aCx);
 
     init.mBubbles = false;
     init.mCancelable = false;
 
@@ -579,92 +558,45 @@ public:
                                                              extendableEvent,
                                                              nullptr));
   }
 };
 
 } // anonymous namespace
 
 nsresult
-ServiceWorkerPrivate::SendMessageEvent(ipc::StructuredCloneData&& aData,
+ServiceWorkerPrivate::SendMessageEvent(JSContext* aCx,
+                                       JS::Handle<JS::Value> aMessage,
+                                       const Sequence<JSObject*>& aTransferable,
                                        const ClientInfoAndState& aClientInfoAndState)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  ErrorResult rv;
-
-  // Ideally we would simply move the StructuredCloneData to the
-  // SendMessageEventRunnable, but we cannot because it uses non-threadsafe
-  // ref-counting.  The following gnarly code unpacks the IPC-friendly
-  // StructuredCloneData and re-packs it into the thread-friendly
-  // StructuredCloneHolder.  In the future we should remove this and make
-  // it easier to simple move the data to the other thread.  See bug 1458936.
-
-  AutoSafeJSContext cx;
-  JSObject* sandbox = GetOrCreateSandbox(cx);
-  NS_ENSURE_TRUE(sandbox, NS_ERROR_FAILURE);
-
-  JS::Rooted<JSObject*> global(cx, sandbox);
-  NS_ENSURE_TRUE(sandbox, NS_ERROR_FAILURE);
-
-  // The CreateSandbox call returns a proxy to the actual sandbox object.  We
-  // don't need a proxy here.
-  global = js::UncheckedUnwrap(global);
-
-  JSAutoCompartment ac(cx, global);
-
-  JS::Rooted<JS::Value> messageData(cx);
-  aData.Read(cx, &messageData, rv);
-  if (rv.Failed()) {
+  ErrorResult rv(SpawnWorkerIfNeeded(MessageEvent));
+  if (NS_WARN_IF(rv.Failed())) {
     return rv.StealNSResult();
   }
 
-  Sequence<OwningNonNull<MessagePort>> ports;
-  if (!aData.TakeTransferredPortsAsSequence(ports)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  JS::Rooted<JSObject*> array(cx, JS_NewArrayObject(cx, ports.Length()));
-  NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
-
-  for (uint32_t i = 0; i < ports.Length(); ++i) {
-    JS::Rooted<JS::Value> value(cx);
-    if (!GetOrCreateDOMReflector(cx, ports[i], &value)) {
-      JS_ClearPendingException(cx);
-      return NS_ERROR_FAILURE;
-    }
+  JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedHandleValue);
 
-    if (!JS_DefineElement(cx, array, i, value, JSPROP_ENUMERATE)) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-  }
-
-  JS::Rooted<JS::Value> transferable(cx);
-  transferable.setObject(*array);
-
-  StructuredCloneHolder holder(StructuredCloneHolder::CloningSupported,
-                               StructuredCloneHolder::TransferringSupported,
-                               JS::StructuredCloneScope::SameProcessDifferentThread);
-  holder.Write(cx, messageData, transferable, JS::CloneDataPolicy(), rv);
-  if (rv.Failed()) {
-    return rv.StealNSResult();
-  }
-
-  // Now that the re-packing is complete, send a runnable to the service worker
-  // thread.
-
-  rv = SpawnWorkerIfNeeded(MessageEvent);
+  rv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
+                                                         &transferable);
   if (NS_WARN_IF(rv.Failed())) {
     return rv.StealNSResult();
   }
 
   RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
   RefPtr<SendMessageEventRunnable> runnable =
-    new SendMessageEventRunnable(mWorkerPrivate, token, Move(holder),
-                                 aClientInfoAndState);
+    new SendMessageEventRunnable(mWorkerPrivate, token, aClientInfoAndState);
+
+  runnable->Write(aCx, aMessage, transferable, JS::CloneDataPolicy(), rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    return rv.StealNSResult();
+  }
+
   if (!runnable->Dispatch()) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 namespace {
--- a/dom/serviceworkers/ServiceWorkerPrivate.h
+++ b/dom/serviceworkers/ServiceWorkerPrivate.h
@@ -11,30 +11,23 @@
 #include "mozilla/dom/WorkerPrivate.h"
 
 #define NOTIFICATION_CLICK_EVENT_NAME "notificationclick"
 #define NOTIFICATION_CLOSE_EVENT_NAME "notificationclose"
 
 class nsIInterceptedChannel;
 
 namespace mozilla {
-
-class JSObjectHolder;
-
 namespace dom {
 
 class ClientInfoAndState;
 class KeepAliveToken;
 class ServiceWorkerInfo;
 class ServiceWorkerRegistrationInfo;
 
-namespace ipc {
-class StructuredCloneData;
-} // namespace ipc
-
 class LifeCycleEventCallback : public Runnable
 {
 public:
   LifeCycleEventCallback() : Runnable("dom::LifeCycleEventCallback") {}
 
   // Called on the worker thread.
   virtual void
   SetResult(bool aResult) = 0;
@@ -84,17 +77,18 @@ public:
 protected:
   nsCycleCollectingAutoRefCnt mRefCnt;
   NS_DECL_OWNINGTHREAD
 
 public:
   explicit ServiceWorkerPrivate(ServiceWorkerInfo* aInfo);
 
   nsresult
-  SendMessageEvent(ipc::StructuredCloneData&& aData,
+  SendMessageEvent(JSContext* aCx, JS::Handle<JS::Value> aMessage,
+                   const Sequence<JSObject*>& aTransferable,
                    const ClientInfoAndState& aClientInfoAndState);
 
   // This is used to validate the worker script and continue the installation
   // process.
   nsresult
   CheckScriptEvaluation(LifeCycleEventCallback* aCallback);
 
   nsresult
@@ -200,40 +194,32 @@ private:
                       bool* aNewWorkerCreated = nullptr,
                       nsILoadGroup* aLoadGroup = nullptr);
 
   ~ServiceWorkerPrivate();
 
   already_AddRefed<KeepAliveToken>
   CreateEventKeepAliveToken();
 
-  JSObject*
-  GetOrCreateSandbox(JSContext* aCx);
-
   // The info object owns us. It is possible to outlive it for a brief period
   // of time if there are pending waitUntil promises, in which case it
   // will be null and |SpawnWorkerIfNeeded| will always fail.
   ServiceWorkerInfo* MOZ_NON_OWNING_REF mInfo;
 
   // The WorkerPrivate object can only be closed by this class or by the
   // RuntimeService class if gecko is shutting down. Closing the worker
   // multiple times is OK, since the second attempt will be a no-op.
   RefPtr<WorkerPrivate> mWorkerPrivate;
 
   nsCOMPtr<nsITimer> mIdleWorkerTimer;
 
   // We keep a token for |dom.serviceWorkers.idle_timeout| seconds to give the
   // worker a grace period after each event.
   RefPtr<KeepAliveToken> mIdleKeepAliveToken;
 
-  // Sandbox global used to re-pack structured clone data before sending
-  // to the service worker thread.  Ideally we would remove this and just
-  // make StructuredCloneData thread safe enough to pass to the worker thread.
-  RefPtr<JSObjectHolder> mSandbox;
-
   uint64_t mDebuggerCount;
 
   uint64_t mTokenCount;
 
   // Meant for keeping objects alive while handling requests from the worker
   // on the main thread. Access to this array is provided through
   // |StoreISupports| and |RemoveISupports|. Note that the array is also
   // cleared whenever the worker is terminated.
--- a/dom/webidl/Event.webidl
+++ b/dom/webidl/Event.webidl
@@ -10,20 +10,18 @@
  * liability, trademark and document use rules apply.
  */
 
 [Constructor(DOMString type, optional EventInit eventInitDict),
  Exposed=(Window,Worker,System), ProbablyShortLivingWrapper]
 interface Event {
   [Pure]
   readonly attribute DOMString type;
-  [Pure]
+  [Pure, BindingAlias="srcElement"]
   readonly attribute EventTarget? target;
-  [Pure, BinaryName="target", Func="Event::IsSrcElementEnabled"]
-  readonly attribute EventTarget? srcElement;
   [Pure]
   readonly attribute EventTarget? currentTarget;
 
   sequence<EventTarget> composedPath();
 
   const unsigned short NONE = 0;
   const unsigned short CAPTURING_PHASE = 1;
   const unsigned short AT_TARGET = 2;
--- a/dom/webidl/Selection.webidl
+++ b/dom/webidl/Selection.webidl
@@ -1,15 +1,15 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
- * https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#concept-selection
+ * https://w3c.github.io/selection-api/#selection-interface
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface Selection {
   readonly attribute Node?         anchorNode;
   readonly attribute unsigned long anchorOffset;
@@ -71,46 +71,84 @@ interface Selection {
 
 // Additional methods not currently in the spec
 partial interface Selection {
   [Throws]
   void modify(DOMString alter, DOMString direction,
               DOMString granularity);
 };
 
-// Additional chrome-only methods from nsISelectionPrivate
+// Additional chrome-only methods.
 interface nsISelectionListener;
 partial interface Selection {
-  [ChromeOnly]
-  const short ENDOFPRECEDINGLINE = 0;
-  [ChromeOnly]
-  const short STARTOFNEXTLINE = 1;
-
+  /**
+   * A true value means "selection after newline"; false means "selection before
+   * newline" when a selection is positioned "between lines".
+   */
   [ChromeOnly,Throws]
   attribute boolean interlinePosition;
 
   [Throws]
   attribute short? caretBidiLevel;
 
   [ChromeOnly,Throws]
   DOMString  toStringWithFormat(DOMString formatType, unsigned long flags, long wrapColumn);
-  [ChromeOnly,Throws]
+  [ChromeOnly]
   void  addSelectionListener(nsISelectionListener newListener);
-  [ChromeOnly,Throws]
+  [ChromeOnly]
   void  removeSelectionListener(nsISelectionListener listenerToRemove);
 
   [ChromeOnly,BinaryName="rawType"]
   readonly attribute short selectionType;
 
+  /**
+   * Return array of ranges intersecting with the given DOM interval.
+   */  
   [ChromeOnly,Throws,Pref="dom.testing.selection.GetRangesForInterval"]
   sequence<Range> GetRangesForInterval(Node beginNode, long beginOffset, Node endNode, long endOffset,
                                        boolean allowAdjacent);
 
+  /**
+   * Scrolls a region of the selection, so that it is visible in
+   * the scrolled view.
+   *
+   * @param aRegion the region inside the selection to scroll into view
+   *                (see selection region constants defined in
+   *                nsISelectionController).
+   * @param aIsSynchronous when true, scrolls the selection into view
+   *                       before returning. If false, posts a request which
+   *                       is processed at some point after the method returns.
+   * @param aVPercent how to align the frame vertically.
+   * @param aHPercent how to align the frame horizontally.
+   */
   [ChromeOnly,Throws]
   void scrollIntoView(short aRegion, boolean aIsSynchronous, short aVPercent, short aHPercent);
 
+  /**
+   * setColors() sets custom colors for the selection.
+   * Currently, this is supported only when the selection type is SELECTION_FIND.
+   * Otherwise, throws an exception.
+   *
+   * @param aForegroundColor     The foreground color of the selection.
+   *                             If this is "currentColor", foreground color
+   *                             isn't changed by this selection.
+   * @param aBackgroundColor     The background color of the selection.
+   *                             If this is "transparent", background color is
+   *                             never painted.
+   * @param aAltForegroundColor  The alternative foreground color of the
+   *                             selection.
+   *                             If aBackgroundColor doesn't have sufficient
+   *                             contrast with its around or foreground color
+   *                             if "currentColor" is specified, alternative
+   *                             colors are used if it have higher contrast.
+   * @param aAltBackgroundColor  The alternative background color of the
+   *                             selection.
+   */
   [ChromeOnly,Throws]
   void setColors(DOMString aForegroundColor, DOMString aBackgroundColor,
                  DOMString aAltForegroundColor, DOMString aAltBackgroundColor);
 
+  /**
+   * resetColors() forget the customized colors which were set by setColors().
+   */
   [ChromeOnly,Throws]
   void resetColors();
 };
--- a/editor/composer/ComposerCommandsUpdater.cpp
+++ b/editor/composer/ComposerCommandsUpdater.cpp
@@ -13,17 +13,16 @@
 #include "nsComponentManagerUtils.h"    // for do_CreateInstance
 #include "nsDebug.h"                    // for NS_ENSURE_TRUE, etc
 #include "nsError.h"                    // for NS_OK, NS_ERROR_FAILURE, etc
 #include "nsICommandManager.h"          // for nsICommandManager
 #include "nsID.h"                       // for NS_GET_IID, etc
 #include "nsIDOMWindow.h"               // for nsIDOMWindow
 #include "nsIDocShell.h"                // for nsIDocShell
 #include "nsIInterfaceRequestorUtils.h"  // for do_GetInterface
-#include "nsISelection.h"               // for nsISelection
 #include "nsITransactionManager.h"      // for nsITransactionManager
 #include "nsLiteralString.h"            // for NS_LITERAL_STRING
 #include "nsPICommandUpdater.h"         // for nsPICommandUpdater
 #include "nsPIDOMWindow.h"              // for nsPIDOMWindow
 
 class nsITransaction;
 
 namespace mozilla {
@@ -345,22 +344,22 @@ ComposerCommandsUpdater::UpdateOneComman
 
 bool
 ComposerCommandsUpdater::SelectionIsCollapsed()
 {
   if (NS_WARN_IF(!mDOMWindow)) {
     return true;
   }
 
-  nsCOMPtr<nsISelection> domSelection = mDOMWindow->GetSelection();
+  RefPtr<dom::Selection> domSelection = mDOMWindow->GetSelection();
   if (NS_WARN_IF(!domSelection)) {
     return false;
   }
 
-  return domSelection->AsSelection()->IsCollapsed();
+  return domSelection->IsCollapsed();
 }
 
 already_AddRefed<nsPICommandUpdater>
 ComposerCommandsUpdater::GetCommandUpdater()
 {
   if (NS_WARN_IF(!mDocShell)) {
     return nullptr;
   }
--- a/editor/composer/nsEditingSession.cpp
+++ b/editor/composer/nsEditingSession.cpp
@@ -31,18 +31,16 @@
 #include "nsIDocumentStateListener.h"
 #include "nsIEditor.h"                  // for nsIEditor
 #include "nsIHTMLDocument.h"            // for nsIHTMLDocument, etc
 #include "nsIInterfaceRequestorUtils.h"  // for do_GetInterface
 #include "nsIPlaintextEditor.h"         // for nsIPlaintextEditor, etc
 #include "nsIPresShell.h"               // for nsIPresShell
 #include "nsIRefreshURI.h"              // for nsIRefreshURI
 #include "nsIRequest.h"                 // for nsIRequest
-#include "nsISelection.h"               // for nsISelection
-#include "nsISelectionPrivate.h"        // for nsISelectionPrivate
 #include "nsITimer.h"                   // for nsITimer, etc
 #include "nsITransactionManager.h"      // for nsITransactionManager
 #include "nsIWeakReference.h"           // for nsISupportsWeakReference, etc
 #include "nsIWebNavigation.h"           // for nsIWebNavigation
 #include "nsIWebProgress.h"             // for nsIWebProgress, etc
 #include "nsLiteralString.h"            // for NS_LITERAL_STRING
 #include "nsPICommandUpdater.h"         // for nsPICommandUpdater
 #include "nsPIDOMWindow.h"              // for nsPIDOMWindow
--- a/editor/libeditor/CompositionTransaction.cpp
+++ b/editor/libeditor/CompositionTransaction.cpp
@@ -239,17 +239,17 @@ CompositionTransaction::SetIMESelection(
   };
 
   nsCOMPtr<nsISelectionController> selCon;
   aEditorBase.GetSelectionController(getter_AddRefs(selCon));
   NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
 
   nsresult rv = NS_OK;
   for (uint32_t i = 0; i < ArrayLength(kIMESelections); ++i) {
-    RefPtr<Selection> selectionOfIME = selCon->GetDOMSelection(kIMESelections[i]);
+    RefPtr<Selection> selectionOfIME = selCon->GetSelection(kIMESelections[i]);
     if (!selectionOfIME) {
       continue;
     }
     selectionOfIME->RemoveAllRanges(IgnoreErrors());
   }
 
   // Set caret position and selection of IME composition with TextRangeArray.
   bool setCaret = false;
@@ -310,17 +310,17 @@ CompositionTransaction::SetIMESelection(
                               getter_AddRefs(clauseRange));
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to create a DOM range for a clause of composition");
       break;
     }
 
     // Set the range of the clause to selection.
     RefPtr<Selection> selectionOfIME =
-      selCon->GetDOMSelection(ToRawSelectionType(textRange.mRangeType));
+      selCon->GetSelection(ToRawSelectionType(textRange.mRangeType));
     if (!selectionOfIME) {
       NS_WARNING("Failed to get IME selection");
       break;
     }
 
     IgnoredErrorResult err;
     selectionOfIME->AddRange(*clauseRange, err);
     if (err.Failed()) {
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -68,16 +68,17 @@
 #include "nsError.h"                    // for NS_OK, etc.
 #include "nsFocusManager.h"             // for nsFocusManager
 #include "nsFrameSelection.h"           // for nsFrameSelection
 #include "nsGenericHTMLElement.h"       // for nsGenericHTMLElement
 #include "nsGkAtoms.h"                  // for nsGkAtoms, nsGkAtoms::dir
 #include "nsIAbsorbingTransaction.h"    // for nsIAbsorbingTransaction
 #include "nsAtom.h"                    // for nsAtom
 #include "nsIContent.h"                 // for nsIContent
+#include "nsIDocument.h"                // for nsIDocument
 #include "nsIDOMDocument.h"             // for nsIDOMDocument
 #include "nsIDOMEventListener.h"        // for nsIDOMEventListener
 #include "nsIDOMNode.h"                 // for nsIDOMNode, etc.
 #include "nsIDocumentStateListener.h"   // for nsIDocumentStateListener
 #include "nsIEditActionListener.h"      // for nsIEditActionListener
 #include "nsIEditorObserver.h"          // for nsIEditorObserver
 #include "nsIEditorSpellCheck.h"        // for nsIEditorSpellCheck
 #include "nsIFrame.h"                   // for nsIFrame
@@ -710,32 +711,38 @@ EditorBase::GetSelectionController(nsISe
 NS_IMETHODIMP
 EditorBase::DeleteSelection(EDirection aAction,
                             EStripWrappers aStripWrappers)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
-EditorBase::GetSelection(nsISelection** aSelection)
+EditorBase::GetSelection(Selection** aSelection)
 {
   return GetSelection(SelectionType::eNormal, aSelection);
 }
 
 nsresult
 EditorBase::GetSelection(SelectionType aSelectionType,
-                         nsISelection** aSelection)
+                         Selection** aSelection)
 {
   NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
   *aSelection = nullptr;
   nsISelectionController* selcon = GetSelectionController();
   if (!selcon) {
     return NS_ERROR_NOT_INITIALIZED;
   }
-  return selcon->GetSelection(ToRawSelectionType(aSelectionType), aSelection);
+  RefPtr<Selection> selection =
+    selcon->GetSelection(ToRawSelectionType(aSelectionType));
+  if (!selection) {
+    return NS_ERROR_INVALID_ARG;
+  }
+  selection.forget(aSelection);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 EditorBase::DoTransaction(nsITransaction* aTxn)
 {
   return DoTransaction(nullptr, aTxn);
 }
 
@@ -2024,37 +2031,32 @@ EditorBase::RemoveEditorObserver(nsIEdit
   NS_WARNING_ASSERTION(mEditorObservers.Length() != 1,
     "All nsIEditorObservers have been removed, this editor becomes faster");
   mEditorObservers.RemoveElement(aObserver);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-EditorBase::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
-                                   nsISelection* aSelection,
+EditorBase::NotifySelectionChanged(nsIDocument* aDocument,
+                                   Selection* aSelection,
                                    int16_t aReason)
 {
-  if (NS_WARN_IF(!aDOMDocument) || NS_WARN_IF(!aSelection)) {
+  if (NS_WARN_IF(!aDocument) || NS_WARN_IF(!aSelection)) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  RefPtr<Selection> selection = aSelection->AsSelection();
-  if (NS_WARN_IF(!selection)) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
   if (mTextInputListener) {
     RefPtr<TextInputListener> textInputListener = mTextInputListener;
-    textInputListener->OnSelectionChange(*selection, aReason);
+    textInputListener->OnSelectionChange(*aSelection, aReason);
   }
 
   if (mIMEContentObserver) {
     RefPtr<IMEContentObserver> observer = mIMEContentObserver;
-    observer->OnSelectionChange(*selection);
+    observer->OnSelectionChange(*aSelection);
   }
 
   return NS_OK;
 }
 
 class EditorInputEventDispatcher final : public Runnable
 {
 public:
@@ -4252,17 +4254,17 @@ EditorBase::CreateTxnForDeleteSelection(
                                         int32_t* aLength)
 {
   RefPtr<Selection> selection = GetSelection();
   if (NS_WARN_IF(!selection)) {
     return nullptr;
   }
 
   // Check whether the selection is collapsed and we should do nothing:
-  if (NS_WARN_IF(selection->Collapsed() && aAction == eNone)) {
+  if (NS_WARN_IF(selection->IsCollapsed() && aAction == eNone)) {
     return nullptr;
   }
 
   // allocate the out-param transaction
   RefPtr<EditAggregateTransaction> aggregateTransaction =
     EditAggregateTransaction::Create();
 
   for (uint32_t rangeIdx = 0; rangeIdx < selection->RangeCount(); ++rangeIdx) {
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -932,17 +932,17 @@ protected:
     // Check for password/readonly/disabled, which are not spellchecked
     // regardless of DOM. Also, check to see if spell check should be skipped
     // or not.
     return !IsPasswordEditor() && !IsReadonly() && !IsDisabled() &&
            !ShouldSkipSpellCheck();
   }
 
   nsresult GetSelection(SelectionType aSelectionType,
-                        nsISelection** aSelection);
+                        Selection** aSelection);
 
   /**
    * (Begin|End)PlaceholderTransaction() are called by AutoPlaceholderBatch.
    * This set of methods are similar to the (Begin|End)Transaction(), but do
    * not use the transaction managers batching feature.  Instead we use a
    * placeholder transaction to wrap up any further transaction while the
    * batch is open.  The advantage of this is that placeholder transactions
    * can later merge, if needed.  Merging is unavailable between transaction
@@ -1433,17 +1433,17 @@ public:
 
   Selection* GetSelection(SelectionType aSelectionType =
                                           SelectionType::eNormal)
   {
     nsISelectionController* sc = GetSelectionController();
     if (!sc) {
       return nullptr;
     }
-    Selection* selection = sc->GetDOMSelection(ToRawSelectionType(aSelectionType));
+    Selection* selection = sc->GetSelection(ToRawSelectionType(aSelectionType));
     return selection;
   }
 
   /**
    * CollapseSelectionToEnd() collapses the selection to the end of the editor.
    */
   nsresult CollapseSelectionToEnd(Selection* aSelection);
 
--- a/editor/libeditor/EditorCommands.cpp
+++ b/editor/libeditor/EditorCommands.cpp
@@ -310,17 +310,17 @@ CutOrDeleteCommand::DoCommand(const char
 {
   nsCOMPtr<nsIEditor> editor = do_QueryInterface(aCommandRefCon);
   if (!editor) {
     return NS_ERROR_FAILURE;
   }
   TextEditor* textEditor = editor->AsTextEditor();
   MOZ_ASSERT(textEditor);
   dom::Selection* selection = textEditor->GetSelection();
-  if (selection && selection->Collapsed()) {
+  if (selection && selection->IsCollapsed()) {
     nsresult rv =
       textEditor->DeleteSelectionAsAction(nsIEditor::eNext,
                                           nsIEditor::eStrip);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
     return NS_OK;
   }
@@ -428,17 +428,17 @@ CopyOrDeleteCommand::DoCommand(const cha
 {
   nsCOMPtr<nsIEditor> editor = do_QueryInterface(aCommandRefCon);
   if (!editor) {
     return NS_ERROR_FAILURE;
   }
   TextEditor* textEditor = editor->AsTextEditor();
   MOZ_ASSERT(textEditor);
   dom::Selection* selection = textEditor->GetSelection();
-  if (selection && selection->Collapsed()) {
+  if (selection && selection->IsCollapsed()) {
     nsresult rv =
       textEditor->DeleteSelectionAsAction(nsIEditor::eNextWord,
                                           nsIEditor::eStrip);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
     return NS_OK;
   }
@@ -496,17 +496,17 @@ CopyAndCollapseToEndCommand::DoCommand(c
   TextEditor* textEditor = editor->AsTextEditor();
   MOZ_ASSERT(textEditor);
   nsresult rv = textEditor->Copy();
   if (NS_FAILED(rv)) {
     return rv;
   }
   RefPtr<dom::Selection> selection = textEditor->GetSelection();
   if (selection) {
-    selection->CollapseToEnd();
+    selection->CollapseToEnd(IgnoreErrors());
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 CopyAndCollapseToEndCommand::DoCommandParams(const char* aCommandName,
                                              nsICommandParams* aParams,
                                              nsISupports* aCommandRefCon)
--- a/editor/libeditor/EditorEventListener.cpp
+++ b/editor/libeditor/EditorEventListener.cpp
@@ -960,17 +960,17 @@ EditorEventListener::CanDrop(DragEvent* 
   }
 
   RefPtr<Selection> selection = editorBase->GetSelection();
   if (!selection) {
     return false;
   }
 
   // If selection is collapsed, allow to drop it always.
-  if (selection->Collapsed()) {
+  if (selection->IsCollapsed()) {
     return true;
   }
 
   nsCOMPtr<nsINode> parent = aEvent->GetRangeParent();
   if (!parent) {
     return false;
   }
 
--- a/editor/libeditor/HTMLAnonymousNodeEditor.cpp
+++ b/editor/libeditor/HTMLAnonymousNodeEditor.cpp
@@ -36,17 +36,16 @@
 #include "nsString.h"
 #include "nsStringFwd.h"
 #include "nsUnicharUtils.h"
 #include "nscore.h"
 #include "nsContentUtils.h" // for nsAutoScriptBlocker
 #include "nsROCSSPrimitiveValue.h"
 
 class nsIDOMEventListener;
-class nsISelection;
 
 namespace mozilla {
 
 using namespace dom;
 
 // Retrieve the rounded number of CSS pixels from a computed CSS property.
 //
 // Note that this should only be called for properties whose resolved value
@@ -297,17 +296,17 @@ HTMLEditor::DeleteRefToAnonymousNode(Man
   // The ManualNACPtr destructor will invoke UnbindFromTree.
 }
 
 // The following method is mostly called by a selection listener. When a
 // selection change is notified, the method is called to check if resizing
 // handles, a grabber and/or inline table editing UI need to be displayed
 // or refreshed
 NS_IMETHODIMP
-HTMLEditor::CheckSelectionStateForAnonymousButtons(nsISelection* aSelection)
+HTMLEditor::CheckSelectionStateForAnonymousButtons(Selection* aSelection)
 {
   NS_ENSURE_ARG_POINTER(aSelection);
 
   // early way out if all contextual UI extensions are disabled
   NS_ENSURE_TRUE(mIsObjectResizingEnabled ||
       mIsAbsolutelyPositioningEnabled ||
       mIsInlineTableEditingEnabled, NS_OK);
 
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -842,17 +842,17 @@ HTMLEditRules::GetAlignment(bool* aMixed
   EditorRawDOMPoint atStartOfSelection(firstRange->StartRef());
   if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
     return NS_ERROR_FAILURE;
   }
   MOZ_ASSERT(atStartOfSelection.IsSetAndValid());
 
   // Is the selection collapsed?
   nsCOMPtr<nsINode> nodeToExamine;
-  if (selection->Collapsed() || atStartOfSelection.GetContainerAsText()) {
+  if (selection->IsCollapsed() || atStartOfSelection.GetContainerAsText()) {
     // If selection is collapsed, we want to look at the container of selection
     // start and its ancestors for divs with alignment on them.  If we are in a
     // text node, then that is the node of interest.
     nodeToExamine = atStartOfSelection.GetContainer();
   } else if (atStartOfSelection.IsContainerHTMLElement(nsGkAtoms::html) &&
              atStartOfSelection.Offset() == static_cast<uint32_t>(rootOffset)) {
     // If we have selected the body, let's look at the first editable node
     nodeToExamine = htmlEditor->GetNextEditableNode(atStartOfSelection);
@@ -1221,17 +1221,17 @@ HTMLEditRules::WillInsert(Selection& aSe
 
   NS_ENSURE_TRUE_VOID(mHTMLEditor);
   RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
 
   // Adjust selection to prevent insertion after a moz-BR.  This next only
   // works for collapsed selections right now, because selection is a pain to
   // work with when not collapsed.  (no good way to extend start or end of
   // selection), so we ignore those types of selections.
-  if (!aSelection.Collapsed()) {
+  if (!aSelection.IsCollapsed()) {
     return;
   }
 
   // If we are after a mozBR in the same block, then move selection to be
   // before it
   nsRange* firstRange = aSelection.GetRangeAt(0);
   if (NS_WARN_IF(!firstRange)) {
     return;
@@ -1298,17 +1298,17 @@ HTMLEditRules::WillInsertText(EditAction
   }
   RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
 
   // initialize out param
   *aCancel = false;
   *aHandled = true;
   // If the selection isn't collapsed, delete it.  Don't delete existing inline
   // tags, because we're hopefully going to insert text (bug 787432).
-  if (!aSelection->Collapsed()) {
+  if (!aSelection->IsCollapsed()) {
     nsresult rv =
       htmlEditor->DeleteSelectionAsAction(nsIEditor::eNone,
                                           nsIEditor::eNoStrip);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
@@ -1532,17 +1532,17 @@ HTMLEditRules::WillInsertText(EditAction
           pointToInsert = pointAfterInsertedString;
         }
       }
     }
 
     // After this block, pointToInsert is updated by AutoTrackDOMPoint.
   }
 
-  aSelection->SetInterlinePosition(false);
+  aSelection->SetInterlinePosition(false, IgnoreErrors());
 
   if (currentPoint.IsSet()) {
     ErrorResult error;
     aSelection->Collapse(currentPoint, error);
     if (error.Failed()) {
       NS_WARNING("Failed to collapse at current point");
       error.SuppressException();
     }
@@ -1631,17 +1631,17 @@ HTMLEditRules::WillInsertBreak(Selection
   MOZ_ASSERT(aCancel && aHandled);
   *aCancel = false;
   *aHandled = false;
 
   NS_ENSURE_STATE(mHTMLEditor);
   RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
 
   // If the selection isn't collapsed, delete it.
-  if (!aSelection.Collapsed()) {
+  if (!aSelection.IsCollapsed()) {
     nsresult rv =
       htmlEditor->DeleteSelectionAsAction(nsIEditor::eNone, nsIEditor::eStrip);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   WillInsert(aSelection, aCancel);
@@ -1925,17 +1925,17 @@ HTMLEditRules::InsertBRElement(Selection
 
   if (brElementIsAfterBlock && brElementIsBeforeBlock) {
     // We just placed a <br> between block boundaries.  This is the one case
     // where we want the selection to be before the br we just placed, as the
     // br will be on a new line, rather than at end of prior line.
     // XXX brElementIsAfterBlock and brElementIsBeforeBlock were set before
     //     modifying the DOM tree.  So, now, the <br> element may not be
     //     between blocks.
-    aSelection.SetInterlinePosition(true);
+    aSelection.SetInterlinePosition(true, IgnoreErrors());
     EditorRawDOMPoint point(brElement);
     ErrorResult error;
     aSelection.Collapse(point, error);
     if (NS_WARN_IF(error.Failed())) {
       return error.StealNSResult();
     }
     return NS_OK;
   }
@@ -1972,17 +1972,18 @@ HTMLEditRules::InsertBRElement(Selection
   // content on the "right".  We want the caret to stick to whatever is past
   // the break.  This is because the break is on the same line we were on,
   // but the next content will be on the following line.
 
   // An exception to this is if the break has a next sibling that is a block
   // node.  Then we stick to the left to avoid an uber caret.
   nsIContent* nextSiblingOfBRElement = brElement->GetNextSibling();
   aSelection.SetInterlinePosition(!(nextSiblingOfBRElement &&
-                                    IsBlockNode(*nextSiblingOfBRElement)));
+                                    IsBlockNode(*nextSiblingOfBRElement)),
+                                  IgnoreErrors());
   ErrorResult error;
   aSelection.Collapse(afterBRElement, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
   return NS_OK;
 }
 
@@ -2095,17 +2096,17 @@ HTMLEditRules::SplitMailCites(Selection*
     return NS_ERROR_FAILURE;
   }
   // Now, offset of pointToInsertBrNode is invalid.  Let's clear it.
   pointToInsertBrNode.Clear();
 
   // Want selection before the break, and on same line.
   EditorDOMPoint atBrNode(brElement);
   Unused << atBrNode.Offset(); // Needs offset after collapsing the selection.
-  aSelection->SetInterlinePosition(true);
+  aSelection->SetInterlinePosition(true, IgnoreErrors());
   ErrorResult error;
   aSelection->Collapse(atBrNode, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
 
   // if citeNode wasn't a block, we might also want another break before it.
   // We need to examine the content both before the br we just added and also
@@ -2223,17 +2224,17 @@ HTMLEditRules::WillDeleteSelection(Selec
   cell = nullptr;
 
   // origCollapsed is used later to determine whether we should join blocks. We
   // don't really care about bCollapsed because it will be modified by
   // ExtendSelectionForDelete later. TryToJoinBlocksWithTransaction() should
   // happen if the original selection is collapsed and the cursor is at the end
   // of a block element, in which case ExtendSelectionForDelete would always
   // make the selection not collapsed.
-  bool bCollapsed = aSelection->Collapsed();
+  bool bCollapsed = aSelection->IsCollapsed();
   bool join = false;
   bool origCollapsed = bCollapsed;
 
   nsCOMPtr<nsINode> selNode;
   int32_t selOffset;
 
   NS_ENSURE_STATE(aSelection->GetRangeAt(0));
   nsCOMPtr<nsINode> startNode = aSelection->GetRangeAt(0)->GetStartContainer();
@@ -2272,17 +2273,17 @@ HTMLEditRules::WillDeleteSelection(Selec
     }
 
     // ExtendSelectionForDelete() may have changed the selection, update it
     NS_ENSURE_STATE(aSelection->GetRangeAt(0));
     startNode = aSelection->GetRangeAt(0)->GetStartContainer();
     startOffset = aSelection->GetRangeAt(0)->StartOffset();
     NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
 
-    bCollapsed = aSelection->Collapsed();
+    bCollapsed = aSelection->IsCollapsed();
   }
 
   if (bCollapsed) {
     // What's in the direction we are deleting?
     NS_ENSURE_STATE(mHTMLEditor);
     WSRunObject wsObj(mHTMLEditor, startNode, startOffset);
     nsCOMPtr<nsINode> visNode;
     int32_t visOffset;
@@ -2431,31 +2432,33 @@ HTMLEditRules::WillDeleteSelection(Selec
         // In any other case we set the position to startnode -1 and
         // interlineposition to false, only moving the caret to the
         // end-of-hr-line position.
         bool moveOnly = true;
 
         selNode = visNode->GetParentNode();
         selOffset = selNode ? selNode->ComputeIndexOf(visNode) : -1;
 
-        bool interLineIsRight;
-        rv = aSelection->GetInterlinePosition(&interLineIsRight);
-        NS_ENSURE_SUCCESS(rv, rv);
+        ErrorResult err;
+        bool interLineIsRight = aSelection->GetInterlinePosition(err);
+        if (NS_WARN_IF(err.Failed())) {
+          return err.StealNSResult();
+        }
 
         if (startNode == selNode && startOffset - 1 == selOffset &&
             !interLineIsRight) {
           moveOnly = false;
         }
 
         if (moveOnly) {
           // Go to the position after the <hr>, but to the end of the <hr> line
           // by setting the interline position to left.
           ++selOffset;
           aSelection->Collapse(selNode, selOffset);
-          aSelection->SetInterlinePosition(false);
+          aSelection->SetInterlinePosition(false, IgnoreErrors());
           mDidExplicitlySetInterline = true;
           *aHandled = true;
 
           // There is one exception to the move only case.  If the <hr> is
           // followed by a <br> we want to delete the <br>.
 
           WSType otherWSType;
           nsCOMPtr<nsINode> otherNode;
@@ -4173,17 +4176,17 @@ HTMLEditRules::MakeBasicBlock(Selection&
 
 nsresult
 HTMLEditRules::DidMakeBasicBlock(Selection* aSelection,
                                  RulesInfo* aInfo,
                                  nsresult aResult)
 {
   NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
   // check for empty block.  if so, put a moz br in it.
-  if (!aSelection->Collapsed()) {
+  if (!aSelection->IsCollapsed()) {
     return NS_OK;
   }
 
   NS_ENSURE_STATE(aSelection->GetRangeAt(0) &&
                   aSelection->GetRangeAt(0)->GetStartContainer());
   nsresult rv =
     InsertMozBRIfNeeded(*aSelection->GetRangeAt(0)->GetStartContainer());
   NS_ENSURE_SUCCESS(rv, rv);
@@ -4236,17 +4239,17 @@ HTMLEditRules::WillCSSIndent(Selection* 
   AutoSelectionRestorer selectionRestorer(aSelection, htmlEditor);
   nsTArray<OwningNonNull<nsRange>> arrayOfRanges;
   nsTArray<OwningNonNull<nsINode>> arrayOfNodes;
 
   // short circuit: detect case of collapsed selection inside an <li>.
   // just sublist that <li>.  This prevents bug 97797.
 
   nsCOMPtr<Element> liNode;
-  if (aSelection->Collapsed()) {
+  if (aSelection->IsCollapsed()) {
     EditorRawDOMPoint selectionStartPoint(
                         EditorBase::GetStartPoint(aSelection));
     if (NS_WARN_IF(!selectionStartPoint.IsSet())) {
       return NS_ERROR_FAILURE;
     }
     Element* block =
       htmlEditor->GetBlock(*selectionStartPoint.GetContainer());
     if (block && HTMLEditUtils::IsListItem(block)) {
@@ -4950,17 +4953,17 @@ HTMLEditRules::WillOutdent(Selection& aS
                               getter_AddRefs(rememberedLeftBQ),
                               getter_AddRefs(rememberedRightBQ));
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
   // Make sure selection didn't stick to last piece of content in old bq (only
   // a problem for collapsed selections)
   if (rememberedLeftBQ || rememberedRightBQ) {
-    if (aSelection.Collapsed()) {
+    if (aSelection.IsCollapsed()) {
       // Push selection past end of rememberedLeftBQ
       NS_ENSURE_TRUE(aSelection.GetRangeAt(0), NS_OK);
       nsCOMPtr<nsINode> startNode =
         aSelection.GetRangeAt(0)->GetStartContainer();
       if (rememberedLeftBQ &&
           (startNode == rememberedLeftBQ ||
            EditorUtils::IsDescendantOf(*startNode, *rememberedLeftBQ))) {
         // Selection is inside rememberedLeftBQ - push it past it.
@@ -5783,17 +5786,17 @@ HTMLEditRules::GetInnerContent(
 
 /**
  * Promotes selection to include blocks that have all their children selected.
  */
 nsresult
 HTMLEditRules::ExpandSelectionForDeletion(Selection& aSelection)
 {
   // Don't need to touch collapsed selections
-  if (aSelection.Collapsed()) {
+  if (aSelection.IsCollapsed()) {
     return NS_OK;
   }
 
   // We don't need to mess with cell selections, and we assume multirange
   // selections are those.
   if (aSelection.RangeCount() != 1) {
     return NS_OK;
   }
@@ -5923,17 +5926,17 @@ HTMLEditRules::ExpandSelectionForDeletio
  * operations to determine what nodes to act on.
  */
 nsresult
 HTMLEditRules::NormalizeSelection(Selection* inSelection)
 {
   NS_ENSURE_TRUE(inSelection, NS_ERROR_NULL_POINTER);
 
   // don't need to touch collapsed selections
-  if (inSelection->Collapsed()) {
+  if (inSelection->IsCollapsed()) {
     return NS_OK;
   }
 
   // we don't need to mess with cell selections, and we assume multirange selections are those.
   if (inSelection->RangeCount() != 1) {
     return NS_OK;
   }
 
@@ -8342,17 +8345,17 @@ HTMLEditRules::AdjustWhitespace(Selectio
   }
   return WSRunObject(mHTMLEditor, selectionStartPoint).AdjustWhitespace();
 }
 
 nsresult
 HTMLEditRules::PinSelectionToNewBlock(Selection* aSelection)
 {
   NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
-  if (!aSelection->Collapsed()) {
+  if (!aSelection->IsCollapsed()) {
     return NS_OK;
   }
 
   if (NS_WARN_IF(!mNewBlock)) {
     return NS_ERROR_NULL_POINTER;
   }
 
   EditorRawDOMPoint selectionStartPoint(EditorBase::GetStartPoint(aSelection));
@@ -8413,17 +8416,17 @@ HTMLEditRules::PinSelectionToNewBlock(Se
   }
   return aSelection->Collapse(atStartOfBlock);
 }
 
 void
 HTMLEditRules::CheckInterlinePosition(Selection& aSelection)
 {
   // If the selection isn't collapsed, do nothing.
-  if (!aSelection.Collapsed()) {
+  if (!aSelection.IsCollapsed()) {
     return;
   }
 
   NS_ENSURE_TRUE_VOID(mHTMLEditor);
   RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
 
   // Get the (collapsed) selection location
   nsRange* firstRange = aSelection.GetRangeAt(0);
@@ -8438,39 +8441,39 @@ HTMLEditRules::CheckInterlinePosition(Se
   MOZ_ASSERT(atStartOfSelection.IsSetAndValid());
 
   // First, let's check to see if we are after a <br>.  We take care of this
   // special-case first so that we don't accidentally fall through into one of
   // the other conditionals.
   nsCOMPtr<nsIContent> node =
     htmlEditor->GetPreviousEditableHTMLNodeInBlock(atStartOfSelection);
   if (node && node->IsHTMLElement(nsGkAtoms::br)) {
-    aSelection.SetInterlinePosition(true);
+    aSelection.SetInterlinePosition(true, IgnoreErrors());
     return;
   }
 
   // Are we after a block?  If so try set caret to following content
   if (atStartOfSelection.GetChild()) {
     node = htmlEditor->GetPriorHTMLSibling(atStartOfSelection.GetChild());
   } else {
     node = nullptr;
   }
   if (node && IsBlockNode(*node)) {
-    aSelection.SetInterlinePosition(true);
+    aSelection.SetInterlinePosition(true, IgnoreErrors());
     return;
   }
 
   // Are we before a block?  If so try set caret to prior content
   if (atStartOfSelection.GetChild()) {
     node = htmlEditor->GetNextHTMLSibling(atStartOfSelection.GetChild());
   } else {
     node = nullptr;
   }
   if (node && IsBlockNode(*node)) {
-    aSelection.SetInterlinePosition(false);
+    aSelection.SetInterlinePosition(false, IgnoreErrors());
   }
 }
 
 nsresult
 HTMLEditRules::AdjustSelection(Selection* aSelection,
                                nsIEditor::EDirection aAction)
 {
   if (NS_WARN_IF(!aSelection)) {
@@ -8480,17 +8483,17 @@ HTMLEditRules::AdjustSelection(Selection
   if (NS_WARN_IF(!mHTMLEditor)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
 
   // if the selection isn't collapsed, do nothing.
   // moose: one thing to do instead is check for the case of
   // only a single break selected, and collapse it.  Good thing?  Beats me.
-  if (!aSelection->Collapsed()) {
+  if (!aSelection->IsCollapsed()) {
     return NS_OK;
   }
 
   // get the (collapsed) selection location
   EditorDOMPoint point(EditorBase::GetStartPoint(aSelection));
   if (NS_WARN_IF(!point.IsSet())) {
     return NS_ERROR_FAILURE;
   }
@@ -8559,29 +8562,29 @@ HTMLEditRules::AdjustSelection(Selection
           // the user will see no new line for the break.  Also, things
           // like table cells won't grow in height.
           RefPtr<Element> brElement = CreateMozBR(point);
           if (NS_WARN_IF(!brElement)) {
             return NS_ERROR_FAILURE;
           }
           point.Set(brElement);
           // selection stays *before* moz-br, sticking to it
-          aSelection->SetInterlinePosition(true);
+          aSelection->SetInterlinePosition(true, IgnoreErrors());
           ErrorResult error;
           aSelection->Collapse(point, error);
           if (NS_WARN_IF(error.Failed())) {
             return error.StealNSResult();
           }
         } else {
           nsCOMPtr<nsIContent> nextNode =
             htmlEditor->GetNextEditableHTMLNodeInBlock(*nearNode);
           if (nextNode && TextEditUtils::IsMozBR(nextNode)) {
             // selection between br and mozbr.  make it stick to mozbr
             // so that it will be on blank line.
-            aSelection->SetInterlinePosition(true);
+            aSelection->SetInterlinePosition(true, IgnoreErrors());
           }
         }
       }
     }
   }
 
   // we aren't in a textnode: are we adjacent to text or a break or an image?
   nearNode = htmlEditor->GetPreviousEditableHTMLNodeInBlock(point);
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -320,55 +320,50 @@ HTMLEditor::PreDestroy(bool aDestroyingF
   // Clean up after our anonymous content -- we don't want these nodes to
   // stay around (which they would, since the frames have an owning reference).
   HideAnonymousEditingUIs();
 
   return TextEditor::PreDestroy(aDestroyingFrames);
 }
 
 NS_IMETHODIMP
-HTMLEditor::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
-                                   nsISelection* aSelection,
+HTMLEditor::NotifySelectionChanged(nsIDocument* aDocument,
+                                   Selection* aSelection,
                                    int16_t aReason)
 {
-  if (NS_WARN_IF(!aDOMDocument) || NS_WARN_IF(!aSelection)) {
+  if (NS_WARN_IF(!aDocument) || NS_WARN_IF(!aSelection)) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  RefPtr<Selection> selection = aSelection->AsSelection();
-  if (NS_WARN_IF(!selection)) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
   if (mTypeInState) {
     RefPtr<TypeInState> typeInState = mTypeInState;
-    typeInState->OnSelectionChange(*selection);
+    typeInState->OnSelectionChange(*aSelection);
 
     // We used a class which derived from nsISelectionListener to call
     // HTMLEditor::CheckSelectionStateForAnonymousButtons().  The lifetime of
     // the class was exactly same as mTypeInState.  So, call it only when
     // mTypeInState is not nullptr.
     if ((aReason & (nsISelectionListener::MOUSEDOWN_REASON |
                     nsISelectionListener::KEYPRESS_REASON |
                     nsISelectionListener::SELECTALL_REASON)) && aSelection) {
       // the selection changed and we need to check if we have to
       // hide and/or redisplay resizing handles
       // FYI: This is an XPCOM method.  So, the caller, Selection, guarantees
       //      the lifetime of this instance.  So, don't need to grab this with
       //      local variable.
-      CheckSelectionStateForAnonymousButtons(selection);
+      CheckSelectionStateForAnonymousButtons(aSelection);
     }
   }
 
   if (mComposerCommandsUpdater) {
     RefPtr<ComposerCommandsUpdater> updater = mComposerCommandsUpdater;
     updater->OnSelectionChange();
   }
 
-  return EditorBase::NotifySelectionChanged(aDOMDocument, aSelection, aReason);
+  return EditorBase::NotifySelectionChanged(aDocument, aSelection, aReason);
 }
 
 void
 HTMLEditor::UpdateRootElement()
 {
   // Use the HTML documents body element as the editor root if we didn't
   // get a root element during initialization.
 
@@ -1127,17 +1122,17 @@ nsresult
 HTMLEditor::InsertBrElementAtSelectionWithTransaction()
 {
   // calling it text insertion to trigger moz br treatment by rules
   AutoRules beginRulesSniffing(this, EditAction::insertText, nsIEditor::eNext);
 
   RefPtr<Selection> selection = GetSelection();
   NS_ENSURE_STATE(selection);
 
-  if (!selection->Collapsed()) {
+  if (!selection->IsCollapsed()) {
     nsresult rv = DeleteSelectionAsAction(eNone, eStrip);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   EditorRawDOMPoint atStartOfSelection(GetStartPoint(selection));
   if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
@@ -1562,19 +1557,19 @@ HTMLEditor::InsertElementAtSelection(Ele
 
     // If deleting, selection will be collapsed.
     // so if not, we collapse it
     if (!aDeleteSelection) {
       // Named Anchor is a special case,
       // We collapse to insert element BEFORE the selection
       // For all other tags, we insert AFTER the selection
       if (HTMLEditUtils::IsNamedAnchor(aElement)) {
-        selection->CollapseToStart();
+        selection->CollapseToStart(IgnoreErrors());
       } else {
-        selection->CollapseToEnd();
+        selection->CollapseToEnd(IgnoreErrors());
       }
     }
 
     if (selection->GetAnchorNode()) {
       EditorRawDOMPoint atAnchor(selection->AnchorRef());
       // Adjust position based on the node we are going to insert.
       EditorRawDOMPoint pointToInsert =
         GetBetterInsertionPointFor(*aElement, atAnchor);
@@ -1797,17 +1792,17 @@ HTMLEditor::GetCSSBackgroundColorState(b
   NS_ENSURE_STATE(selection && selection->GetRangeAt(0));
 
   // get selection location
   nsCOMPtr<nsINode> parent = selection->GetRangeAt(0)->GetStartContainer();
   NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
 
   // is the selection collapsed?
   nsCOMPtr<nsINode> nodeToExamine;
-  if (selection->Collapsed() || IsTextNode(parent)) {
+  if (selection->IsCollapsed() || IsTextNode(parent)) {
     // we want to look at the parent and ancestors
     nodeToExamine = parent;
   } else {
     // otherwise we want to look at the first editable node after
     // {parent,offset} and its ancestors for divs with alignment on them
     nodeToExamine = selection->GetRangeAt(0)->GetChildAtStartOffset();
     //GetNextNode(parent, offset, true, address_of(nodeToExamine));
   }
@@ -1993,17 +1988,17 @@ HTMLEditor::MakeOrChangeList(const nsASt
   ruleInfo.blockType = &aListType;
   ruleInfo.entireList = entireList;
   ruleInfo.bulletType = &aBulletType;
   nsresult rv = rules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
   if (cancel || NS_FAILED(rv)) {
     return rv;
   }
 
-  if (!handled && selection->Collapsed()) {
+  if (!handled && selection->IsCollapsed()) {
     nsRange* firstRange = selection->GetRangeAt(0);
     if (NS_WARN_IF(!firstRange)) {
       return NS_ERROR_FAILURE;
     }
 
     EditorRawDOMPoint atStartOfSelection(firstRange->StartRef());
     if (NS_WARN_IF(!atStartOfSelection.IsSet()) ||
         NS_WARN_IF(!atStartOfSelection.GetContainerAsContent())) {
@@ -2161,17 +2156,17 @@ HTMLEditor::InsertBasicBlockWithTransact
   nsDependentAtomString tagName(&aTagName);
   RulesInfo ruleInfo(EditAction::makeBasicBlock);
   ruleInfo.blockType = &tagName;
   nsresult rv = rules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
   if (cancel || NS_FAILED(rv)) {
     return rv;
   }
 
-  if (!handled && selection->Collapsed()) {
+  if (!handled && selection->IsCollapsed()) {
     nsRange* firstRange = selection->GetRangeAt(0);
     if (NS_WARN_IF(!firstRange)) {
       return NS_ERROR_FAILURE;
     }
 
     EditorRawDOMPoint atStartOfSelection(firstRange->StartRef());
     if (NS_WARN_IF(!atStartOfSelection.IsSet()) ||
         NS_WARN_IF(!atStartOfSelection.GetContainerAsContent())) {
@@ -2248,17 +2243,17 @@ HTMLEditor::Indent(const nsAString& aInd
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
 
   RulesInfo ruleInfo(opID);
   nsresult rv = rules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
   if (cancel || NS_FAILED(rv)) {
     return rv;
   }
 
-  if (!handled && selection->Collapsed() && aIndent.EqualsLiteral("indent")) {
+  if (!handled && selection->IsCollapsed() && aIndent.EqualsLiteral("indent")) {
     nsRange* firstRange = selection->GetRangeAt(0);
     if (NS_WARN_IF(!firstRange)) {
       return NS_ERROR_FAILURE;
     }
 
     EditorRawDOMPoint atStartOfSelection(firstRange->StartRef());
     if (NS_WARN_IF(!atStartOfSelection.IsSet()) ||
         NS_WARN_IF(!atStartOfSelection.GetContainerAsContent())) {
@@ -2463,17 +2458,17 @@ HTMLEditor::GetSelectedElement(const nsA
 
   // default is null - no element found
   *aReturn = nullptr;
 
   // First look for a single element in selection
   RefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
 
-  bool isCollapsed = selection->Collapsed();
+  bool isCollapsed = selection->IsCollapsed();
 
   nsAutoString domTagName;
   nsAutoString TagName(aTagName);
   ToLowerCase(TagName);
   // Empty string indicates we should match any element tag
   bool anyTag = (TagName.IsEmpty());
   bool isLinkTag = IsLinkTag(TagName);
   bool isNamedAnchorTag = IsNamedAnchorTag(TagName);
@@ -2700,17 +2695,17 @@ NS_IMETHODIMP
 HTMLEditor::InsertLinkAroundSelection(Element* aAnchorElement)
 {
   NS_ENSURE_TRUE(aAnchorElement, NS_ERROR_NULL_POINTER);
 
   // We must have a real selection
   RefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
 
-  if (selection->Collapsed()) {
+  if (selection->IsCollapsed()) {
     NS_WARNING("InsertLinkAroundSelection called but there is no selection!!!");
     return NS_OK;
   }
 
 
   // Be sure we were given an anchor element
   RefPtr<HTMLAnchorElement> anchor =
     HTMLAnchorElement::FromNodeOrNull(aAnchorElement);
@@ -3542,18 +3537,17 @@ HTMLEditor::SelectAll()
   nsINode* anchorNode = selection->GetAnchorNode();
   if (NS_WARN_IF(!anchorNode) || NS_WARN_IF(!anchorNode->IsContent())) {
     return NS_ERROR_FAILURE;
   }
 
   nsIContent* anchorContent = anchorNode->AsContent();
   nsIContent* rootContent;
   if (anchorContent->HasIndependentSelection()) {
-    nsresult rv = selection->SetAncestorLimiter(nullptr);
-    NS_ENSURE_SUCCESS(rv, rv);
+    selection->SetAncestorLimiter(nullptr);
     rootContent = mRootElement;
   } else {
     nsCOMPtr<nsIPresShell> ps = GetPresShell();
     rootContent = anchorContent->GetSelectionRootContent(ps);
   }
 
   NS_ENSURE_TRUE(rootContent, NS_ERROR_UNEXPECTED);
 
@@ -4321,17 +4315,17 @@ HTMLEditor::SetCSSBackgroundColorWithTra
   CommitComposition();
 
   // Protect the edit rules object from dying
   RefPtr<TextEditRules> rules(mRules);
 
   RefPtr<Selection> selection = GetSelection();
   NS_ENSURE_STATE(selection);
 
-  bool isCollapsed = selection->Collapsed();
+  bool isCollapsed = selection->IsCollapsed();
 
   AutoPlaceholderBatch batchIt(this);
   AutoRules beginRulesSniffing(this, EditAction::insertElement,
                                nsIEditor::eNext);
   AutoSelectionRestorer selectionRestorer(selection, this);
   AutoTransactionsConserveSelection dontChangeMySelection(this);
 
   bool cancel, handled;
@@ -4672,17 +4666,17 @@ HTMLEditor::GetSelectionContainer()
 {
   // If we don't get the selection, just skip this
   NS_ENSURE_TRUE(GetSelection(), nullptr);
 
   OwningNonNull<Selection> selection = *GetSelection();
 
   nsCOMPtr<nsINode> focusNode;
 
-  if (selection->Collapsed()) {
+  if (selection->IsCollapsed()) {
     focusNode = selection->GetFocusNode();
   } else {
     int32_t rangeCount = selection->RangeCount();
 
     if (rangeCount == 1) {
       RefPtr<nsRange> range = selection->GetRangeAt(0);
 
       nsCOMPtr<nsINode> startContainer = range->GetStartContainer();
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -38,17 +38,16 @@ class nsDocumentFragment;
 class nsHTMLDocument;
 class nsITransferable;
 class nsIClipboard;
 class nsIDOMDocument;
 class nsILinkHandler;
 class nsTableWrapperFrame;
 class nsIDOMRange;
 class nsRange;
-class nsISelection;
 
 namespace mozilla {
 class AutoSelectionSetterAfterTableEdit;
 class HTMLEditorEventListener;
 class HTMLEditRules;
 class ResizerSelectionListener;
 class TypeInState;
 class WSRunObject;
@@ -103,19 +102,17 @@ public:
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLEditor, TextEditor)
 
   HTMLEditor();
 
   bool GetReturnInParagraphCreatesNewParagraph();
   Element* GetSelectionContainer();
 
   // nsISelectionListener overrides
-  NS_IMETHOD NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
-                                    nsISelection* aSelection,
-                                    int16_t aReason) override;
+  NS_DECL_NSISELECTIONLISTENER
 
   // TextEditor overrides
   virtual nsresult Init(nsIDocument& aDoc, Element* aRoot,
                         nsISelectionController* aSelCon, uint32_t aFlags,
                         const nsAString& aValue) override;
   NS_IMETHOD BeginningOfDocument() override;
   virtual nsresult HandleKeyPressEvent(
                      WidgetKeyboardEvent* aKeyboardEvent) override;
--- a/editor/libeditor/HTMLEditorDataTransfer.cpp
+++ b/editor/libeditor/HTMLEditorDataTransfer.cpp
@@ -107,17 +107,17 @@ HTMLEditor::LoadHTML(const nsAString& aI
   nsresult rv = rules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
   NS_ENSURE_SUCCESS(rv, rv);
   if (cancel) {
     return NS_OK; // rules canceled the operation
   }
 
   if (!handled) {
     // Delete Selection, but only if it isn't collapsed, see bug #106269
-    if (!selection->Collapsed()) {
+    if (!selection->IsCollapsed()) {
       rv = DeleteSelectionAsAction(eNone, eStrip);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
 
     // Get the first range in the selection, for context:
     RefPtr<nsRange> range = selection->GetRangeAt(0);
@@ -328,17 +328,17 @@ HTMLEditor::DoInsertHTMLWithContext(cons
     // Braces for artificial block to scope AutoSelectionRestorer.
     // Save current selection since DeleteTableCell() perturbs it.
     {
       AutoSelectionRestorer selectionRestorer(selection, this);
       rv = DeleteTableCell(1);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     // collapse selection to beginning of deleted table content
-    selection->CollapseToStart();
+    selection->CollapseToStart(IgnoreErrors());
   }
 
   // give rules a chance to handle or cancel
   RulesInfo ruleInfo(EditAction::insertElement);
   bool cancel, handled;
   rv = rules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
   NS_ENSURE_SUCCESS(rv, rv);
   if (cancel) {
--- a/editor/libeditor/HTMLEditorEventListener.cpp
+++ b/editor/libeditor/HTMLEditorEventListener.cpp
@@ -109,17 +109,17 @@ HTMLEditorEventListener::MouseDown(Mouse
     // Get location of mouse within target node
     nsCOMPtr<nsINode> parent = aMouseEvent->GetRangeParent();
     NS_ENSURE_TRUE(parent, NS_ERROR_FAILURE);
 
     int32_t offset = aMouseEvent->RangeOffset();
 
     // Detect if mouse point is within current selection for context click
     bool nodeIsInSelection = false;
-    if (isContextClick && !selection->Collapsed()) {
+    if (isContextClick && !selection->IsCollapsed()) {
       uint32_t rangeCount = selection->RangeCount();
 
       for (uint32_t i = 0; i < rangeCount; i++) {
         RefPtr<nsRange> range = selection->GetRangeAt(i);
         if (!range) {
           // Don't bail yet, iterate through them all
           continue;
         }
--- a/editor/libeditor/HTMLEditorObjectResizer.cpp
+++ b/editor/libeditor/HTMLEditorObjectResizer.cpp
@@ -30,18 +30,16 @@
 #include "nsISupportsUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsStringFwd.h"
 #include "nscore.h"
 #include <algorithm>
 
-class nsISelection;
-
 namespace mozilla {
 
 using namespace dom;
 
 /******************************************************************************
  * mozilla::DocumentResizeEventListener
  ******************************************************************************/
 
--- a/editor/libeditor/HTMLStyleEditor.cpp
+++ b/editor/libeditor/HTMLStyleEditor.cpp
@@ -72,17 +72,17 @@ HTMLEditor::SetInlineProperty(nsAtom* aP
   NS_ENSURE_TRUE(aProperty, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(mRules, NS_ERROR_NOT_INITIALIZED);
   RefPtr<TextEditRules> rules(mRules);
   CommitComposition();
 
   RefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
 
-  if (selection->Collapsed()) {
+  if (selection->IsCollapsed()) {
     // Manipulating text attributes on a collapsed selection only sets state
     // for the next text insertion
     mTypeInState->SetProp(aProperty, aAttribute, aValue);
     return NS_OK;
   }
 
   AutoPlaceholderBatch batchIt(this);
   AutoRules beginRulesSniffing(this, EditAction::insertElement,
@@ -978,17 +978,17 @@ HTMLEditor::GetInlinePropertyBase(nsAtom
   *aAny = false;
   *aAll = true;
   *aFirst = false;
   bool first = true;
 
   RefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
 
-  bool isCollapsed = selection->Collapsed();
+  bool isCollapsed = selection->IsCollapsed();
   RefPtr<nsRange> range = selection->GetRangeAt(0);
   // XXX: Should be a while loop, to get each separate range
   // XXX: ERROR_HANDLING can currentItem be null?
   if (range) {
     // For each range, set a flag
     bool firstNodeInRange = true;
 
     if (isCollapsed) {
@@ -1211,17 +1211,17 @@ HTMLEditor::RemoveInlineProperty(nsAtom*
                                  nsAtom* aAttribute)
 {
   NS_ENSURE_TRUE(mRules, NS_ERROR_NOT_INITIALIZED);
   CommitComposition();
 
   RefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
 
-  if (selection->Collapsed()) {
+  if (selection->IsCollapsed()) {
     // Manipulating text attributes on a collapsed selection only sets state
     // for the next text insertion
 
     // For links, aProperty uses "href", use "a" instead
     if (aProperty == nsGkAtoms::href || aProperty == nsGkAtoms::name) {
       aProperty = nsGkAtoms::a;
     }
 
@@ -1361,17 +1361,17 @@ nsresult
 HTMLEditor::RelativeFontChange(FontSize aDir)
 {
   CommitComposition();
 
   // Get the selection
   RefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
   // If selection is collapsed, set typing state
-  if (selection->Collapsed()) {
+  if (selection->IsCollapsed()) {
     nsAtom& atom = aDir == FontSize::incr ? *nsGkAtoms::big :
                                              *nsGkAtoms::small;
 
     // Let's see in what kind of element the selection is
     NS_ENSURE_TRUE(selection->RangeCount() &&
                    selection->GetRangeAt(0)->GetStartContainer(), NS_OK);
     OwningNonNull<nsINode> selectedNode =
       *selection->GetRangeAt(0)->GetStartContainer();
--- a/editor/libeditor/HTMLTableEditor.cpp
+++ b/editor/libeditor/HTMLTableEditor.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/FlushType.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/dom/Element.h"
 #include "nsAString.h"
 #include "nsAlgorithm.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsError.h"
+#include "nsFrameSelection.h"
 #include "nsGkAtoms.h"
 #include "nsAtom.h"
 #include "nsIContent.h"
 #include "nsIDOMNode.h"
 #include "nsIFrame.h"
 #include "nsINode.h"
 #include "nsIPresShell.h"
 #include "nsISupportsUtils.h"
@@ -3202,17 +3203,17 @@ HTMLEditor::GetSelectedCellsType(Element
   RefPtr<Element> selectedCell;
   rv = GetFirstSelectedCell(nullptr, getter_AddRefs(selectedCell));
   NS_ENSURE_SUCCESS(rv, rv);
   if (rv == NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND) {
     return NS_OK;
   }
 
   // We have at least one selected cell, so set return value
-  *aSelectionType = nsISelectionPrivate::TABLESELECTION_CELL;
+  *aSelectionType = static_cast<uint32_t>(TableSelection::Cell);
 
   // Store indexes of each row/col to avoid duplication of searches
   nsTArray<int32_t> indexArray;
 
   bool allCellsInRowAreSelected = false;
   bool allCellsInColAreSelected = false;
   while (NS_SUCCEEDED(rv) && selectedCell) {
     // Get the cell's location in the cellmap
@@ -3229,17 +3230,17 @@ HTMLEditor::GetSelectedCellsType(Element
       if (!allCellsInRowAreSelected) {
         break;
       }
     }
     rv = GetNextSelectedCell(nullptr, getter_AddRefs(selectedCell));
   }
 
   if (allCellsInRowAreSelected) {
-    *aSelectionType = nsISelectionPrivate::TABLESELECTION_ROW;
+    *aSelectionType = static_cast<uint32_t>(TableSelection::Row);
     return NS_OK;
   }
   // Test for columns
 
   // Empty the indexArray
   indexArray.Clear();
 
   // Start at first cell again
@@ -3258,17 +3259,17 @@ HTMLEditor::GetSelectedCellsType(Element
       // We're done as soon as we fail for any column
       if (!allCellsInRowAreSelected) {
         break;
       }
     }
     rv = GetNextSelectedCell(nullptr, getter_AddRefs(selectedCell));
   }
   if (allCellsInColAreSelected) {
-    *aSelectionType = nsISelectionPrivate::TABLESELECTION_COLUMN;
+    *aSelectionType = static_cast<uint32_t>(TableSelection::Column);
   }
 
   return NS_OK;
 }
 
 bool
 HTMLEditor::AllCellsInRowSelected(Element* aTable,
                                   int32_t aRowIndex,
--- a/editor/libeditor/TextEditRules.cpp
+++ b/editor/libeditor/TextEditRules.cpp
@@ -796,17 +796,17 @@ TextEditRules::WillInsertText(EditAction
       return rv;
     }
 
     if (pointAfterStringInserted.IsSet()) {
       // Make the caret attach to the inserted text, unless this text ends with a LF,
       // in which case make the caret attach to the next line.
       bool endsWithLF =
         !outString->IsEmpty() && outString->Last() == nsCRT::LF;
-      aSelection->SetInterlinePosition(endsWithLF);
+      aSelection->SetInterlinePosition(endsWithLF, IgnoreErrors());
 
       MOZ_ASSERT(!pointAfterStringInserted.GetChild(),
         "After inserting text into a text node, pointAfterStringInserted."
         "GetChild() should be nullptr");
       IgnoredErrorResult error;
       aSelection->Collapse(pointAfterStringInserted, error);
       if (error.Failed()) {
         NS_WARNING("Failed to collapse selection after inserting string");
@@ -1109,17 +1109,19 @@ TextEditRules::DidDeleteSelection(Select
     // Be aware, mTextEditor may be nullptr here.
   }
 
   if (mDidExplicitlySetInterline) {
     return NS_OK;
   }
   // We prevent the caret from sticking on the left of prior BR
   // (i.e. the end of previous line) after this deletion.  Bug 92124
-  return aSelection->SetInterlinePosition(true);
+  ErrorResult err;
+  aSelection->SetInterlinePosition(true, err);
+  return err.StealNSResult();
 }
 
 nsresult
 TextEditRules::WillUndo(Selection* aSelection,
                         bool* aCancel,
                         bool* aHandled)
 {
   if (!aSelection || !aCancel || !aHandled) {
--- a/editor/libeditor/TextEditRulesBidi.cpp
+++ b/editor/libeditor/TextEditRulesBidi.cpp
@@ -44,18 +44,17 @@ TextEditRules::CheckBidiLevelForDeletion
   }
 
   if (!aSelectionPoint.GetContainerAsContent()) {
     return NS_ERROR_NULL_POINTER;
   }
 
   nsBidiLevel levelBefore;
   nsBidiLevel levelAfter;
-  RefPtr<nsFrameSelection> frameSelection =
-    aSelection->AsSelection()->GetFrameSelection();
+  RefPtr<nsFrameSelection> frameSelection = aSelection->GetFrameSelection();
   NS_ENSURE_TRUE(frameSelection, NS_ERROR_NULL_POINTER);
 
   nsPrevNextBidiLevels levels = frameSelection->
     GetPrevNextBidiLevels(aSelectionPoint.GetContainerAsContent(),
                           aSelectionPoint.Offset(), true);
 
   levelBefore = levels.mLevelBefore;
   levelAfter = levels.mLevelAfter;
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -496,34 +496,34 @@ TextEditor::InsertBrElementWithTransacti
       return nullptr;
     }
   }
 
   switch (aSelect) {
     case eNone:
       break;
     case eNext: {
-      aSelection.SetInterlinePosition(true);
+      aSelection.SetInterlinePosition(true, IgnoreErrors());
       // Collapse selection after the <br> node.
       EditorRawDOMPoint afterBRElement(newBRElement);
       if (afterBRElement.IsSet()) {
         DebugOnly<bool> advanced = afterBRElement.AdvanceOffset();
         NS_WARNING_ASSERTION(advanced,
           "Failed to advance offset after the <br> element");
         ErrorResult error;
         aSelection.Collapse(afterBRElement, error);
         NS_WARNING_ASSERTION(!error.Failed(),
           "Failed to collapse selection after the <br> element");
       } else {
         NS_WARNING("The <br> node is not in the DOM tree?");
       }
       break;
     }
     case ePrevious: {
-      aSelection.SetInterlinePosition(true);
+      aSelection.SetInterlinePosition(true, IgnoreErrors());
       // Collapse selection at the <br> node.
       EditorRawDOMPoint atBRElement(newBRElement);
       if (atBRElement.IsSet()) {
         ErrorResult error;
         aSelection.Collapse(atBRElement, error);
         NS_WARNING_ASSERTION(!error.Failed(),
           "Failed to collapse selection at the <br> element");
       } else {
@@ -539,17 +539,17 @@ TextEditor::InsertBrElementWithTransacti
 
   return newBRElement.forget();
 }
 
 nsresult
 TextEditor::ExtendSelectionForDelete(Selection* aSelection,
                                      nsIEditor::EDirection* aAction)
 {
-  bool bCollapsed = aSelection->Collapsed();
+  bool bCollapsed = aSelection->IsCollapsed();
 
   if (*aAction == eNextWord ||
       *aAction == ePreviousWord ||
       (*aAction == eNext && bCollapsed) ||
       (*aAction == ePrevious && bCollapsed) ||
       *aAction == eToBeginningOfLine ||
       *aAction == eToEndOfLine) {
     nsCOMPtr<nsISelectionController> selCont;
@@ -675,17 +675,17 @@ TextEditor::DeleteSelectionAsAction(EDir
   RefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
 
   // If there is an existing selection when an extended delete is requested,
   //  platforms that use "caret-style" caret positioning collapse the
   //  selection to the  start and then create a new selection.
   //  Platforms that use "selection-style" caret positioning just delete the
   //  existing selection without extending it.
-  if (!selection->Collapsed()) {
+  if (!selection->IsCollapsed()) {
     switch (aDirection) {
       case eNextWord:
       case ePreviousWord:
       case eToBeginningOfLine:
       case eToEndOfLine: {
         if (mCaretStyle != 1) {
           aDirection = eNone;
           break;
@@ -727,17 +727,17 @@ TextEditor::DeleteSelectionWithTransacti
   RefPtr<Selection> selection = GetSelection();
   if (NS_WARN_IF(!selection)) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   RefPtr<EditAggregateTransaction> deleteSelectionTransaction;
   nsCOMPtr<nsINode> deleteNode;
   int32_t deleteCharOffset = 0, deleteCharLength = 0;
-  if (!selection->Collapsed() || aDirection != eNone) {
+  if (!selection->IsCollapsed() || aDirection != eNone) {
     deleteSelectionTransaction =
       CreateTxnForDeleteSelection(aDirection,
                                   getter_AddRefs(deleteNode),
                                   &deleteCharOffset,
                                   &deleteCharLength);
     if (NS_WARN_IF(!deleteSelectionTransaction)) {
       return NS_ERROR_FAILURE;
     }
@@ -1059,17 +1059,17 @@ TextEditor::InsertParagraphSeparatorAsAc
       if (NS_SUCCEEDED(rv)) {
         // see if we're at the end of the editor range
         EditorRawDOMPoint endPoint = GetEndPoint(selection);
         if (endPoint == pointAfterInsertedLineBreak) {
           // SetInterlinePosition(true) means we want the caret to stick to the
           // content on the "right".  We want the caret to stick to whatever is
           // past the break.  This is because the break is on the same line we
           // were on, but the next content will be on the following line.
-          selection->SetInterlinePosition(true);
+          selection->SetInterlinePosition(true, IgnoreErrors());
         }
       }
     }
   }
 
   if (!cancel) {
     // post-process, always called if WillInsertBreak didn't return cancel==true
     rv = rules->DidDoAction(selection, &ruleInfo, rv);
@@ -1570,17 +1570,17 @@ TextEditor::CanCutOrCopy(PasswordFieldAl
     return false;
   }
 
   if (aPasswordFieldAllowed == ePasswordFieldNotAllowed &&
       IsPasswordEditor()) {
     return false;
   }
 
-  return !selection->Collapsed();
+  return !selection->IsCollapsed();
 }
 
 bool
 TextEditor::FireClipboardEvent(EventMessage aEventMessage,
                                int32_t aSelectionType,
                                bool* aActionTaken)
 {
   if (aEventMessage == ePaste) {
@@ -1885,17 +1885,17 @@ TextEditor::InsertAsCitedQuotation(const
 nsresult
 TextEditor::SharedOutputString(uint32_t aFlags,
                                bool* aIsCollapsed,
                                nsAString& aResult)
 {
   RefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
 
-  *aIsCollapsed = selection->Collapsed();
+  *aIsCollapsed = selection->IsCollapsed();
 
   if (!*aIsCollapsed) {
     aFlags |= nsIDocumentEncoder::OutputSelectionOnly;
   }
   // If the selection isn't collapsed, we'll use the whole document.
 
   return OutputToString(NS_LITERAL_STRING("text/plain"), aFlags, aResult);
 }
--- a/editor/libeditor/TextEditorDataTransfer.cpp
+++ b/editor/libeditor/TextEditorDataTransfer.cpp
@@ -212,17 +212,17 @@ TextEditor::InsertFromDrop(DragEvent* aD
   nsCOMPtr<nsINode> newSelectionParent = aDropEvent->GetRangeParent();
   NS_ENSURE_TRUE(newSelectionParent, NS_ERROR_FAILURE);
 
   int32_t newSelectionOffset = aDropEvent->RangeOffset();
 
   RefPtr<Selection> selection = GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
 
-  bool isCollapsed = selection->Collapsed();
+  bool isCollapsed = selection->IsCollapsed();
 
   // Check if mouse is in the selection
   // if so, jump through some hoops to determine if mouse is over selection (bail)
   // and whether user wants to copy selection or delete it
   if (!isCollapsed) {
     // We never have to delete if selection is already collapsed
     bool cursorIsInSelection = false;
 
--- a/editor/libeditor/TextEditorTest.cpp
+++ b/editor/libeditor/TextEditorTest.cpp
@@ -12,21 +12,23 @@
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
 #include "nsIDocument.h"
 #include "nsIEditor.h"
 #include "nsIHTMLEditor.h"
 #include "nsINodeList.h"
 #include "nsIPlaintextEditor.h"
-#include "nsISelection.h"
 #include "nsLiteralString.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsStringFwd.h"
+#include "mozilla/dom/Selection.h"
+
+using mozilla::dom::Selection;
 
 #define TEST_RESULT(r) { if (NS_FAILED(r)) {printf("FAILURE result=%X\n", static_cast<uint32_t>(r)); return r; } }
 #define TEST_POINTER(p) { if (!p) {printf("FAILURE null pointer\n"); return NS_ERROR_NULL_POINTER; } }
 
 TextEditorTest::TextEditorTest()
 {
   printf("constructed a TextEditorTest\n");
 }
@@ -98,24 +100,24 @@ nsresult TextEditorTest::InitDoc()
   TEST_RESULT(rv);
   rv = mEditor->DeleteSelection(nsIEditor::eNext, nsIEditor::eStrip);
   TEST_RESULT(rv);
   return rv;
 }
 
 nsresult TextEditorTest::TestInsertBreak()
 {
-  nsCOMPtr<nsISelection>selection;
+  RefPtr<Selection>selection;
   nsresult rv = mEditor->GetSelection(getter_AddRefs(selection));
   TEST_RESULT(rv);
   TEST_POINTER(selection.get());
-  nsCOMPtr<nsINode> anchor = selection->AsSelection()->GetAnchorNode();
+  nsCOMPtr<nsINode> anchor = selection->GetAnchorNode();
   TEST_RESULT(rv);
   TEST_POINTER(anchor.get());
-  selection->AsSelection()->Collapse(anchor, 0);
+  selection->Collapse(anchor, 0);
   // insert one break
   printf("inserting a break\n");
   rv = mTextEditor->InsertLineBreak();
   TEST_RESULT(rv);
   mEditor->DebugDumpContent();
 
   // insert a second break adjacent to the first
   printf("inserting a second break\n");
@@ -136,23 +138,23 @@ nsresult TextEditorTest::TestTextPropert
   TEST_POINTER(nodeList.get());
   uint32_t count = nodeList->Length();
   NS_ASSERTION(0 != count, "there are no text nodes in the document!");
   nsCOMPtr<nsINode>textNode = nodeList->Item(count - 1);
   TEST_POINTER(textNode.get());
 
   // set the whole text node to bold
   printf("set the whole first text node to bold\n");
-  nsCOMPtr<nsISelection>selection;
+  RefPtr<Selection>selection;
   nsresult rv = mEditor->GetSelection(getter_AddRefs(selection));
   TEST_RESULT(rv);
   TEST_POINTER(selection.get());
   uint32_t length = textNode->Length();
-  selection->AsSelection()->Collapse(textNode, 0);
-  selection->AsSelection()->Extend(textNode, length);
+  selection->Collapse(textNode, 0);
+  selection->Extend(textNode, length);
 
   nsCOMPtr<nsIHTMLEditor> htmlEditor (do_QueryInterface(mTextEditor));
   NS_ENSURE_TRUE(htmlEditor, NS_ERROR_FAILURE);
 
   bool any = false;
   bool all = false;
   bool first=false;
 
@@ -184,18 +186,18 @@ nsresult TextEditorTest::TestTextPropert
   TEST_RESULT(rv);
   NS_ASSERTION(false==first, "first should be false");
   NS_ASSERTION(false==any, "any should be false");
   NS_ASSERTION(false==all, "all should be false");
   mEditor->DebugDumpContent();
 
   // set all but the first and last character to bold
   printf("set the first text node (1, length-1) to bold and italic, and (2, length-1) to underline.\n");
-  selection->AsSelection()->Collapse(textNode, 1);
-  selection->AsSelection()->Extend(textNode, length-1);
+  selection->Collapse(textNode, 1);
+  selection->Extend(textNode, length-1);
   rv = htmlEditor->SetInlineProperty(b, empty, empty);
   TEST_RESULT(rv);
   rv = htmlEditor->GetInlineProperty(b, empty, empty, &first, &any, &all);
   TEST_RESULT(rv);
   NS_ASSERTION(true==first, "first should be true");
   NS_ASSERTION(true==any, "any should be true");
   NS_ASSERTION(true==all, "all should be true");
   mEditor->DebugDumpContent();
@@ -218,18 +220,18 @@ nsresult TextEditorTest::TestTextPropert
   nodeList = doc->GetElementsByTagName(textTag);
   TEST_POINTER(nodeList.get());
   count = nodeList->Length();
   NS_ASSERTION(0!=count, "there are no text nodes in the document!");
   textNode = nodeList->Item(count-2);
   TEST_POINTER(textNode.get());
   length = textNode->Length();
   NS_ASSERTION(length==915, "wrong text node");
-  selection->AsSelection()->Collapse(textNode, 1);
-  selection->AsSelection()->Extend(textNode, length-2);
+  selection->Collapse(textNode, 1);
+  selection->Extend(textNode, length-2);
   rv = htmlEditor->SetInlineProperty(u, empty, empty);
   TEST_RESULT(rv);
   rv = htmlEditor->GetInlineProperty(u, empty, empty, &first, &any, &all);
   TEST_RESULT(rv);
   NS_ASSERTION(true==first, "first should be true");
   NS_ASSERTION(true==any, "any should be true");
   NS_ASSERTION(true==all, "all should be true");
   mEditor->DebugDumpContent();
--- a/editor/libeditor/TypeInState.cpp
+++ b/editor/libeditor/TypeInState.cpp
@@ -64,17 +64,17 @@ TypeInState::~TypeInState()
 
 nsresult
 TypeInState::UpdateSelState(Selection* aSelection)
 {
   if (NS_WARN_IF(!aSelection)) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  if (!aSelection->Collapsed()) {
+  if (!aSelection->IsCollapsed()) {
     return NS_OK;
   }
 
   mLastSelectionPoint = EditorBase::GetStartPoint(aSelection);
   if (!mLastSelectionPoint.IsSet()) {
     return NS_ERROR_FAILURE;
   }
   // We need to store only offset because referring child may be removed by
--- a/editor/libeditor/tests/test_bug1053048.html
+++ b/editor/libeditor/tests/test_bug1053048.html
@@ -10,27 +10,26 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script src="/tests/SimpleTest/EventUtils.js"></script>
   <link rel="stylesheet" href="/tests/SimpleTest/test.css">
   <script type="application/javascript">
 
   /** Test for Bug 1053048 **/
   SimpleTest.waitForExplicitFinish();
   SimpleTest.waitForFocus(runTests);
 
-  const nsISelectionPrivate = SpecialPowers.Ci.nsISelectionPrivate;
   const nsISelectionListener = SpecialPowers.Ci.nsISelectionListener;
   const nsIDOMNSEditableElement = SpecialPowers.Ci.nsIDOMNSEditableElement;
 
   function runTests()
   {
     var textarea = SpecialPowers.wrap(document.getElementById("textarea"));
     textarea.focus();
 
     var editor = textarea.QueryInterface(nsIDOMNSEditableElement).editor;
-    var selectionPrivate = editor.selection.QueryInterface(nsISelectionPrivate);
+    var selectionPrivate = editor.selection;
 
     var selectionListener = {
       count: 0,
       notifySelectionChanged: function (aDocument, aSelection, aReason)
       {
         ok(true, "selectionStart: " + textarea.selectionStart);
         ok(true, "selectionEnd: " + textarea.selectionEnd);
         this.count++;
--- a/editor/nsIEditActionListener.idl
+++ b/editor/nsIEditActionListener.idl
@@ -1,19 +1,18 @@
 /* -*- 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 "nsISupports.idl"
 #include "domstubs.idl"
 
-interface nsISelection;
-
 webidl CharacterData;
+webidl Selection;
 
 /*
 Editor Action Listener interface to outside world
 */
 
 
 /**
  * A generic editor action listener interface.
@@ -111,16 +110,16 @@ interface nsIEditActionListener : nsISup
                      in long                aOffset,
                      in long                aLength,
                      in nsresult            aResult);
 
   /**
    * Called before the editor deletes the selection.
    * @param aSelection   The selection to be deleted
    */
-  void WillDeleteSelection(in nsISelection aSelection);
+  void WillDeleteSelection(in Selection aSelection);
 
   /**
    * Called after the editor deletes the selection.
    * @param aSelection   The selection, after deletion
    */
-  void DidDeleteSelection(in nsISelection aSelection);
+  void DidDeleteSelection(in Selection aSelection);
 };
--- a/editor/nsIEditor.idl
+++ b/editor/nsIEditor.idl
@@ -4,28 +4,28 @@
  * 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 "domstubs.idl"
 
 interface nsIURI;
 interface nsIContent;
-interface nsISelection;
 interface nsISelectionController;
 interface nsIDocumentStateListener;
 interface nsIOutputStream;
 interface nsITransactionManager;
 interface nsITransaction;
 interface nsIEditorObserver;
 interface nsIEditActionListener;
 interface nsIInlineSpellChecker;
 interface nsITransferable;
 
 webidl Element;
+webidl Selection;
 
 %{C++
 namespace mozilla {
 class EditorBase;
 class HTMLEditor;
 class TextEditor;
 } // namespace mozilla
 %}
@@ -43,17 +43,17 @@ interface nsIEditor  : nsISupports
   const short eNextWord = 3;
   const short ePreviousWord = 4;
   const short eToBeginningOfLine = 5;
   const short eToEndOfLine = 6;
 
   const short eStrip = 0;
   const short eNoStrip = 1;
 
-  readonly attribute nsISelection selection;
+  readonly attribute Selection selection;
 
   void setAttributeOrEquivalent(in Element element,
                                 in AString sourceAttrName,
                                 in AString sourceAttrValue,
                                 in boolean aSuppressTransaction);
   void removeAttributeOrEquivalent(in Element element,
                                    in DOMString sourceAttrName,
                                    in boolean aSuppressTransaction);
--- a/editor/nsIHTMLEditor.idl
+++ b/editor/nsIHTMLEditor.idl
@@ -3,20 +3,20 @@
  * 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 "domstubs.idl"
 
 interface nsIContent;
 interface nsIArray;
-interface nsISelection;
 
 webidl Element;
 webidl Node;
+webidl Selection;
 
 [scriptable, builtinclass, uuid(87ee993e-985f-4a43-a974-0d9512da2fb0)]
 interface nsIHTMLEditor : nsISupports
 {
 %{C++
   typedef short EAlignment;
 %}
 
@@ -196,17 +196,17 @@ interface nsIHTMLEditor : nsISupports
    *   This should be done after the document URL has changed,
    *     such as after saving a file
    *   This is used as base for relativizing link and image urls
    */
   void updateBaseURL();
 
 
   /* ------------ Selection manipulation -------------- */
-  /* Should these be moved to nsISelection? */
+  /* Should these be moved to Selection? */
 
   /**
     * Set the selection at the suppled element
     *
     * @param aElement   An element in the document
     */
   void selectElement(in Element aElement);
 
@@ -449,17 +449,17 @@ interface nsIHTMLEditor : nsISupports
    */
   Element getSelectionContainer();
 
   /**
    * Checks if the anonymous nodes created by the HTML editor have to be
    * refreshed or hidden depending on a possible new state of the selection
    * @param aSelection [IN] a selection
    */
-  void checkSelectionStateForAnonymousButtons(in nsISelection aSelection);
+  void checkSelectionStateForAnonymousButtons(in Selection aSelection);
 
   boolean isAnonymousElement(in Element aElement);
 
   /**
    * A boolean indicating if a return key pressed in a paragraph creates
    * another paragraph or just inserts a <br> at the caret
    *
    * @return    true if CR in a paragraph creates a new paragraph
--- a/editor/nsITableEditor.idl
+++ b/editor/nsITableEditor.idl
@@ -254,23 +254,23 @@ interface nsITableEditor : nsISupports
     * @param aElement           Any table or cell element or any element
     *                           inside a table
     *                           Used to get enclosing table.
     *                           If null, selection's anchorNode is used
     *
     * @return
     *     0                        aCellElement was not a cell
     *                              (returned result = NS_ERROR_FAILURE)
-    *     TABLESELECTION_CELL      There are 1 or more cells selected but
+    *     TableSelection::Cell     There are 1 or more cells selected but
     *                              complete rows or columns are not selected
-    *     TABLESELECTION_ROW       All cells are in 1 or more rows
+    *     TableSelection::Row      All cells are in 1 or more rows
     *                              and in each row, all cells selected
     *                              Note: This is the value if all rows
     *                              (thus all cells) are selected
-    *     TABLESELECTION_COLUMN    All cells are in 1 or more columns
+    *     TableSelection::Column   All cells are in 1 or more columns
     *                              and in each column, all cells are selected
     */
   uint32_t getSelectedCellsType(in Element aElement);
 
   /** Get first selected element from first selection range.
     *   (If multiple cells were selected this is the first in the order they were selected)
     * Assumes cell-selection model where each cell
     * is in a separate range (selection parent node is table row)
--- a/editor/spellchecker/EditorSpellCheck.cpp
+++ b/editor/spellchecker/EditorSpellCheck.cpp
@@ -21,17 +21,16 @@
 #include "nsDebug.h"                    // for NS_ENSURE_TRUE, etc
 #include "nsDependentSubstring.h"       // for Substring
 #include "nsError.h"                    // for NS_ERROR_NOT_INITIALIZED, etc
 #include "nsIContent.h"                 // for nsIContent
 #include "nsIContentPrefService2.h"     // for nsIContentPrefService2, etc
 #include "nsIDocument.h"                // for nsIDocument
 #include "nsIEditor.h"                  // for nsIEditor
 #include "nsILoadContext.h"
-#include "nsISelection.h"               // for nsISelection
 #include "nsISupportsBase.h"            // for nsISupports
 #include "nsISupportsUtils.h"           // for NS_ADDREF
 #include "nsITextServicesFilter.h"      // for nsITextServicesFilter
 #include "nsIURI.h"                     // for nsIURI
 #include "nsThreadUtils.h"              // for GetMainThreadSerialEventTarget
 #include "nsVariant.h"                  // for nsIWritableVariant, etc
 #include "nsLiteralString.h"            // for NS_LITERAL_STRING, etc
 #include "nsMemory.h"                   // for nsMemory
@@ -400,22 +399,21 @@ EditorSpellCheck::InitSpellChecker(nsIEd
   // Pass the editor to the text services document
   rv = textServicesDocument->InitWithEditor(aEditor);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aEnableSelectionChecking) {
     // Find out if the section is collapsed or not.
     // If it isn't, we want to spellcheck just the selection.
 
-    nsCOMPtr<nsISelection> domSelection;
-    aEditor->GetSelection(getter_AddRefs(domSelection));
-    if (NS_WARN_IF(!domSelection)) {
+    RefPtr<Selection> selection;
+    aEditor->GetSelection(getter_AddRefs(selection));
+    if (NS_WARN_IF(!selection)) {
       return NS_ERROR_FAILURE;
     }
-    RefPtr<Selection> selection = domSelection->AsSelection();
 
     if (selection->RangeCount()) {
       RefPtr<nsRange> range = selection->GetRangeAt(0);
       NS_ENSURE_STATE(range);
 
       if (!range->Collapsed()) {
         // We don't want to touch the range in the selection,
         // so create a new copy of it.
--- a/editor/spellchecker/TextServicesDocument.cpp
+++ b/editor/spellchecker/TextServicesDocument.cpp
@@ -19,17 +19,16 @@
 #include "nsGenericHTMLElement.h"       // for nsGenericHTMLElement
 #include "nsIContent.h"                 // for nsIContent, etc
 #include "nsIContentIterator.h"         // for nsIContentIterator
 #include "nsID.h"                       // for NS_GET_IID
 #include "nsIDOMNode.h"                 // for nsIDOMNode, etc
 #include "nsIEditor.h"                  // for nsIEditor, etc
 #include "nsINode.h"                    // for nsINode
 #include "nsIPlaintextEditor.h"         // for nsIPlaintextEditor
-#include "nsISelection.h"               // for nsISelection
 #include "nsISelectionController.h"     // for nsISelectionController, etc
 #include "nsISupportsBase.h"            // for nsISupports
 #include "nsISupportsUtils.h"           // for NS_IF_ADDREF, NS_ADDREF, etc
 #include "nsITextServicesFilter.h"      // for nsITextServicesFilter
 #include "mozilla/intl/WordBreaker.h"   // for WordRange, WordBreaker
 #include "nsRange.h"                    // for nsRange
 #include "nsString.h"                   // for nsString, nsAutoString
 #include "nscore.h"                     // for nsresult, NS_IMETHODIMP, etc
@@ -436,17 +435,17 @@ TextServicesDocument::LastSelectedBlock(
   *aSelOffset = *aSelLength = -1;
 
   if (!mSelCon || !mIterator) {
     UNLOCK_DOC(this);
     return NS_ERROR_FAILURE;
   }
 
   RefPtr<Selection> selection =
-    mSelCon->GetDOMSelection(nsISelectionController::SELECTION_NORMAL);
+    mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL);
   if (NS_WARN_IF(!selection)) {
     UNLOCK_DOC(this);
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIContentIterator> iter;
   RefPtr<nsRange> range;
   nsCOMPtr<nsINode> parent;
@@ -1353,17 +1352,17 @@ TextServicesDocument::InsertText(const n
     // length, adjust the selection indexes, and make sure the
     // caret is properly placed!
 
     itEntry->mLength += strLength;
 
     mSelStartIndex = mSelEndIndex = i;
 
     RefPtr<Selection> selection =
-      mSelCon->GetDOMSelection(nsISelectionController::SELECTION_NORMAL);
+      mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL);
     if (NS_WARN_IF(!selection)) {
       textEditor->EndTransaction();
       UNLOCK_DOC(this);
       return rv;
     }
 
     rv = selection->Collapse(itEntry->mNode,
                              itEntry->mNodeOffset + itEntry->mLength);
@@ -1986,27 +1985,23 @@ TextServicesDocument::SetSelectionIntern
     }
   }
 
   NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
 
   // XXX: If we ever get a SetSelection() method in nsIEditor, we should
   //      use it.
 
-  nsCOMPtr<nsISelection> selection;
+  RefPtr<Selection> selection;
 
   if (aDoUpdate) {
-    nsresult rv =
-      mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
-                            getter_AddRefs(selection));
-
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = selection->AsSelection()->Collapse(startNode, startNodeOffset);
-
+    selection = mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL);
+    NS_ENSURE_STATE(selection);
+
+    nsresult rv = selection->Collapse(startNode, startNodeOffset);
     NS_ENSURE_SUCCESS(rv, rv);
    }
 
   if (aLength <= 0) {
     // We have a collapsed selection. (Caret)
 
     mSelEndIndex  = mSelStartIndex;
     mSelEndOffset = mSelStartOffset;
@@ -2043,17 +2038,17 @@ TextServicesDocument::SetSelectionIntern
       if (endNode) {
         mSelEndIndex = i;
         mSelEndOffset = endOffset;
       }
     }
   }
 
   if (aDoUpdate && endNode) {
-    nsresult rv = selection->AsSelection()->Extend(endNode, endNodeOffset);
+    nsresult rv = selection->Extend(endNode, endNodeOffset);
 
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   //**** KDEBUG ****
   // printf("\n * Sel: (%2d, %4d) (%2d, %4d)\n", mSelStartIndex, mSelStartOffset, mSelEndIndex, mSelEndOffset);
   //**** KDEBUG ****
 
@@ -2073,17 +2068,17 @@ TextServicesDocument::GetSelection(Block
 
   NS_ENSURE_TRUE(mDocument && mSelCon, NS_ERROR_FAILURE);
 
   if (mIteratorStatus == IteratorStatus::eDone) {
     return NS_OK;
   }
 
   RefPtr<Selection> selection =
-    mSelCon->GetDOMSelection(nsISelectionController::SELECTION_NORMAL);
+    mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL);
   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
 
   // XXX: If we expose this method publicly, we need to
   //      add LOCK_DOC/UNLOCK_DOC calls!
 
   // LOCK_DOC(this);
 
   nsresult rv;
@@ -2099,24 +2094,19 @@ TextServicesDocument::GetSelection(Block
   return rv;
 }
 
 nsresult
 TextServicesDocument::GetCollapsedSelection(BlockSelectionStatus* aSelStatus,
                                             int32_t* aSelOffset,
                                             int32_t* aSelLength)
 {
-  nsCOMPtr<nsISelection> domSelection;
-  nsresult rv =
-    mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
-                          getter_AddRefs(domSelection));
-  NS_ENSURE_SUCCESS(rv, rv);
-  NS_ENSURE_TRUE(domSelection, NS_ERROR_FAILURE);
-
-  RefPtr<Selection> selection = domSelection->AsSelection();
+  RefPtr<Selection> selection =
+    mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL);
+  NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
 
   // The calling function should have done the GetIsCollapsed()
   // check already. Just assume it's collapsed!
   *aSelStatus = BlockSelectionStatus::eBlockOutside;
   *aSelOffset = *aSelLength = -1;
 
   int32_t tableCount = mOffsetTable.Length();
 
@@ -2186,18 +2176,18 @@ TextServicesDocument::GetCollapsedSelect
 
   // The caret is in our text block, but it's positioned in some
   // non-text node (ex. <b>). Create a range based on the start
   // and end of the text block, then create an iterator based on
   // this range, with its initial position set to the closest
   // child of this non-text node. Then look for the closest text
   // node.
 
-  rv = nsRange::CreateRange(eStart->mNode, eStartOffset, eEnd->mNode,
-                            eEndOffset, getter_AddRefs(range));