Merge autoland to mozilla-central. a=merge
authorSebastian Hengst <archaeopteryx@coole-files.de>
Tue, 30 Apr 2019 13:31:28 +0200
changeset 471883 ee0dd3b092d03d28da65f5ee686db942b9ce8ec0
parent 471857 596be5bff8b9ec986de13a5a5812f04672f89d08 (current diff)
parent 471882 5d8653071324fa61f37cee5d1beee64da5f82e06 (diff)
child 471894 83950e03831430c0a00db8b83890d51aad0ff43c
push id35941
push userarchaeopteryx@coole-files.de
push dateTue, 30 Apr 2019 11:32:04 +0000
treeherdermozilla-central@ee0dd3b092d0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge autoland to mozilla-central. a=merge
dom/base/Document.cpp
dom/base/nsDOMWindowUtils.cpp
dom/base/nsFocusManager.cpp
dom/base/nsGlobalWindowOuter.cpp
dom/events/EventStateManager.cpp
dom/html/HTMLInputElement.cpp
dom/plugins/base/nsPluginInstanceOwner.cpp
layout/base/PresShell.cpp
layout/base/PresShell.h
layout/base/nsIPresShell.h
layout/base/nsIPresShellInlines.h
layout/generic/nsFrame.cpp
layout/generic/nsFrameSetFrame.cpp
layout/generic/nsImageFrame.cpp
layout/generic/nsPluginFrame.cpp
layout/xul/nsMenuPopupFrame.cpp
--- a/browser/base/content/test/static/browser_parsable_script.js
+++ b/browser/base/content/test/static/browser_parsable_script.js
@@ -1,15 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /* This list allows pre-existing or 'unfixable' JS issues to remain, while we
  * detect newly occurring issues in shipping JS. It is a list of regexes
  * matching files which have errors:
  */
+
+requestLongerTimeout(2);
+
 const kWhitelist = new Set([
   /browser\/content\/browser\/places\/controller.js$/,
 ]);
 
 const kESModuleList = new Set([
   /browser\/res\/payments\/(components|containers|mixins)\/.*\.js$/,
   /browser\/res\/payments\/paymentRequest\.js$/,
   /browser\/res\/payments\/PaymentsStore\.js$/,
--- a/devtools/client/aboutdebugging-new/src/components/RuntimePage.js
+++ b/devtools/client/aboutdebugging-new/src/components/RuntimePage.js
@@ -148,16 +148,25 @@ class RuntimePage extends PureComponent 
     return dom.article(
       {
         className: "page js-runtime-page",
       },
       RuntimeInfo({ ...runtimeDetails.info, runtimeId, dispatch }),
       RuntimeActions({ dispatch, runtimeId, runtimeDetails }),
       runtimeDetails.serviceWorkersAvailable ? null : ServiceWorkersWarning(),
       CompatibilityWarning({ compatibilityReport }),
+      this.renderDebugTargetPane("Tabs",
+                                 this.getIconByType(DEBUG_TARGETS.TAB),
+                                 tabs,
+                                 null,
+                                 InspectAction,
+                                 null,
+                                 TabDetail,
+                                 DEBUG_TARGET_PANE.TAB,
+                                 "about-debugging-runtime-tabs"),
       this.renderDebugTargetPane("Temporary Extensions",
                                  this.getIconByType(DEBUG_TARGETS.EXTENSION),
                                  temporaryExtensions,
                                  this.renderTemporaryExtensionInstallSection(),
                                  ExtensionAction,
                                  TemporaryExtensionAdditionalActions,
                                  TemporaryExtensionDetail,
                                  DEBUG_TARGET_PANE.TEMPORARY_EXTENSION,
@@ -166,25 +175,16 @@ class RuntimePage extends PureComponent 
                                  this.getIconByType(DEBUG_TARGETS.EXTENSION),
                                  installedExtensions,
                                  null,
                                  ExtensionAction,
                                  null,
                                  ExtensionDetail,
                                  DEBUG_TARGET_PANE.INSTALLED_EXTENSION,
                                  "about-debugging-runtime-extensions"),
-      this.renderDebugTargetPane("Tabs",
-                                 this.getIconByType(DEBUG_TARGETS.TAB),
-                                 tabs,
-                                 null,
-                                 InspectAction,
-                                 null,
-                                 TabDetail,
-                                 DEBUG_TARGET_PANE.TAB,
-                                 "about-debugging-runtime-tabs"),
       this.renderDebugTargetPane("Service Workers",
                                  this.getIconByType(DEBUG_TARGETS.WORKER),
                                  serviceWorkers,
                                  null,
                                  ServiceWorkerAction,
                                  ServiceWorkerAdditionalActions,
                                  WorkerDetail,
                                  DEBUG_TARGET_PANE.SERVICE_WORKER,
--- a/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_thisfirefox.js
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_thisfirefox.js
@@ -1,17 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const EXPECTED_TARGET_PANES = [
+  "Tabs",
   "Temporary Extensions",
   "Extensions",
-  "Tabs",
   "Service Workers",
   "Shared Workers",
   "Other Workers",
 ];
 
 /**
  * Check that the This Firefox runtime page contains the expected categories if
  * the preference to enable local tab debugging is true.
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -16,28 +16,28 @@
 #include "mozilla/AnimationPerformanceWarning.h"
 #include "mozilla/AnimationTarget.h"
 #include "mozilla/AnimationUtils.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/ComputedStyleInlines.h"
 #include "mozilla/EffectSet.h"
 #include "mozilla/LayerAnimationInfo.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/RestyleManager.h"
 #include "mozilla/ServoBindings.h"  // Servo_GetProperties_Overriding_Animation
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/TypeTraits.h"  // For std::forward<>
 #include "nsContentUtils.h"
 #include "nsCSSPseudoElements.h"
 #include "nsCSSPropertyIDSet.h"
 #include "nsCSSProps.h"
 #include "nsDisplayItemTypes.h"
 #include "nsAtom.h"
-#include "nsIPresShellInlines.h"
 #include "nsLayoutUtils.h"
 #include "nsTArray.h"
 #include "PendingAnimationTracker.h"
 
 using mozilla::dom::Animation;
 using mozilla::dom::Element;
 using mozilla::dom::KeyframeEffect;
 
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -16,28 +16,28 @@
 #include "mozilla/AutoRestore.h"
 #include "mozilla/ComputedStyleInlines.h"
 #include "mozilla/EffectSet.h"
 #include "mozilla/FloatingPoint.h"  // For IsFinite
 #include "mozilla/LayerAnimationInfo.h"
 #include "mozilla/LookAndFeel.h"  // For LookAndFeel::GetInt
 #include "mozilla/KeyframeUtils.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/TypeTraits.h"
 #include "Layers.h"              // For Layer
 #include "nsComputedDOMStyle.h"  // nsComputedDOMStyle::GetComputedStyle
 #include "nsContentUtils.h"
 #include "nsCSSPropertyIDSet.h"
 #include "nsCSSProps.h"             // For nsCSSProps::PropHasFlags
 #include "nsCSSPseudoElements.h"    // For PseudoStyleType
 #include "nsDOMMutationObserver.h"  // For nsAutoAnimationMutationBatch
 #include "nsIFrame.h"
-#include "nsIPresShellInlines.h"
 #include "nsIScriptError.h"
 #include "nsPresContextInlines.h"
 #include "nsRefreshDriver.h"
 
 namespace mozilla {
 
 void AnimationProperty::SetPerformanceWarning(
     const AnimationPerformanceWarning& aWarning, const Element* aElement) {
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -20,16 +20,17 @@
 #include "mozilla/DebugOnly.h"
 #include "mozilla/EffectSet.h"
 #include "mozilla/EnumSet.h"
 #include "mozilla/IdentifierMapEntry.h"
 #include "mozilla/IntegerRange.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Likely.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/RestyleManager.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/URLExtraData.h"
 #include <algorithm>
 
 #include "mozilla/Logging.h"
 #include "plstr.h"
 #include "mozilla/Sprintf.h"
@@ -278,17 +279,16 @@
 #  include "mozilla/dom/XULPersist.h"
 #  include "nsIXULWindow.h"
 #  include "nsIChromeRegistry.h"
 #  include "nsXULPrototypeDocument.h"
 #  include "nsXULCommandDispatcher.h"
 #  include "nsXULPopupManager.h"
 #  include "nsIDocShellTreeOwner.h"
 #endif
-#include "nsIPresShellInlines.h"
 #include "mozilla/dom/BoxObject.h"
 
 #include "mozilla/DocLoadingTimelineMarker.h"
 
 #include "mozilla/dom/WindowGlobalChild.h"
 
 #include "nsISpeculativeConnect.h"
 
--- a/dom/base/ResponsiveImageSelector.cpp
+++ b/dom/base/ResponsiveImageSelector.cpp
@@ -1,20 +1,20 @@
 /* -*- 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 "mozilla/dom/ResponsiveImageSelector.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/ServoStyleSetInlines.h"
 #include "mozilla/TextUtils.h"
 #include "nsIURI.h"
-#include "nsIPresShellInlines.h"
 #include "mozilla/dom/Document.h"
 #include "nsContentUtils.h"
 #include "nsPresContext.h"
 
 #include "nsCSSProps.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
--- a/dom/base/VisualViewport.h
+++ b/dom/base/VisualViewport.h
@@ -6,17 +6,16 @@
 
 #ifndef mozilla_dom_VisualViewport_h
 #define mozilla_dom_VisualViewport_h
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/WeakPtr.h"
 #include "mozilla/dom/VisualViewportBinding.h"
 #include "Units.h"
-#include "nsIPresShell.h"
 
 namespace mozilla {
 
 class PresShell;
 
 namespace dom {
 
 /* Visual Viewport API spec:
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -6054,34 +6054,33 @@ bool nsContentUtils::CheckMayLoad(nsIPri
 /* static */
 bool nsContentUtils::CanAccessNativeAnon() {
   return LegacyIsCallerChromeOrNativeCode() || IsCallerContentXBL();
 }
 
 /* static */
 nsresult nsContentUtils::DispatchXULCommand(nsIContent* aTarget, bool aTrusted,
                                             Event* aSourceEvent,
-                                            nsIPresShell* aShell, bool aCtrl,
+                                            PresShell* aPresShell, bool aCtrl,
                                             bool aAlt, bool aShift, bool aMeta,
                                             uint16_t aInputSource) {
   NS_ENSURE_STATE(aTarget);
   Document* doc = aTarget->OwnerDoc();
   nsPresContext* presContext = doc->GetPresContext();
 
   RefPtr<XULCommandEvent> xulCommand =
       new XULCommandEvent(doc, presContext, nullptr);
   xulCommand->InitCommandEvent(NS_LITERAL_STRING("command"), true, true,
                                nsGlobalWindowInner::Cast(doc->GetInnerWindow()),
                                0, aCtrl, aAlt, aShift, aMeta, aSourceEvent,
                                aInputSource, IgnoreErrors());
 
-  if (aShell) {
+  if (aPresShell) {
     nsEventStatus status = nsEventStatus_eIgnore;
-    nsCOMPtr<nsIPresShell> kungFuDeathGrip = aShell;
-    return aShell->HandleDOMEventWithTarget(aTarget, xulCommand, &status);
+    return aPresShell->HandleDOMEventWithTarget(aTarget, xulCommand, &status);
   }
 
   ErrorResult rv;
   aTarget->DispatchEvent(*xulCommand, rv);
   return rv.StealNSResult();
 }
 
 // static
@@ -6361,18 +6360,18 @@ void nsContentUtils::PopulateStringFromS
   uint32_t allocStringLen = (aBuf->StorageSize() / sizeof(char16_t)) - 1;
   MOZ_ASSERT(stringLen <= allocStringLen,
              "string buffer lacks null terminator!");
   stringLen = std::min(stringLen, allocStringLen);
 
   aBuf->ToString(stringLen, aResultString);
 }
 
-nsIPresShell* nsContentUtils::FindPresShellForDocument(const Document* aDoc) {
-  const Document* doc = aDoc;
+PresShell* nsContentUtils::FindPresShellForDocument(const Document* aDocument) {
+  const Document* doc = aDocument;
   Document* displayDoc = doc->GetDisplayDocument();
   if (displayDoc) {
     doc = displayDoc;
   }
 
   PresShell* presShell = doc->GetPresShell();
   if (presShell) {
     return presShell;
@@ -6391,32 +6390,34 @@ nsIPresShell* nsContentUtils::FindPresSh
     nsCOMPtr<nsIDocShellTreeItem> parent;
     docShellTreeItem->GetParent(getter_AddRefs(parent));
     docShellTreeItem = parent;
   }
 
   return nullptr;
 }
 
-nsIWidget* nsContentUtils::WidgetForDocument(const Document* aDoc) {
-  nsIPresShell* shell = FindPresShellForDocument(aDoc);
-  if (shell) {
-    nsViewManager* VM = shell->GetViewManager();
-    if (VM) {
-      nsView* rootView = VM->GetRootView();
-      if (rootView) {
-        nsView* displayRoot = nsViewManager::GetDisplayRootFor(rootView);
-        if (displayRoot) {
-          return displayRoot->GetNearestWidget(nullptr);
-        }
-      }
-    }
-  }
-
-  return nullptr;
+nsIWidget* nsContentUtils::WidgetForDocument(const Document* aDocument) {
+  PresShell* presShell = FindPresShellForDocument(aDocument);
+  if (!presShell) {
+    return nullptr;
+  }
+  nsViewManager* vm = presShell->GetViewManager();
+  if (!vm) {
+    return nullptr;
+  }
+  nsView* rootView = vm->GetRootView();
+  if (!rootView) {
+    return nullptr;
+  }
+  nsView* displayRoot = nsViewManager::GetDisplayRootFor(rootView);
+  if (!displayRoot) {
+    return nullptr;
+  }
+  return displayRoot->GetNearestWidget(nullptr);
 }
 
 nsIWidget* nsContentUtils::WidgetForContent(const nsIContent* aContent) {
   nsIFrame* frame = aContent->GetPrimaryFrame();
   if (frame) {
     frame = nsLayoutUtils::GetDisplayRootFrame(frame);
 
     nsView* view = frame->GetView();
@@ -7852,23 +7853,25 @@ mozilla::Modifiers nsContentUtils::GetWi
     result |= mozilla::MODIFIER_SYMBOLLOCK;
   }
   if (aModifiers & nsIDOMWindowUtils::MODIFIER_OS) {
     result |= mozilla::MODIFIER_OS;
   }
   return result;
 }
 
-nsIWidget* nsContentUtils::GetWidget(nsIPresShell* aPresShell,
-                                     nsPoint* aOffset) {
-  if (aPresShell) {
-    nsIFrame* frame = aPresShell->GetRootFrame();
-    if (frame) return frame->GetView()->GetNearestWidget(aOffset);
-  }
-  return nullptr;
+nsIWidget* nsContentUtils::GetWidget(PresShell* aPresShell, nsPoint* aOffset) {
+  if (!aPresShell) {
+    return nullptr;
+  }
+  nsIFrame* frame = aPresShell->GetRootFrame();
+  if (!frame) {
+    return nullptr;
+  }
+  return frame->GetView()->GetNearestWidget(aOffset);
 }
 
 int16_t nsContentUtils::GetButtonsFlagForButton(int32_t aButton) {
   switch (aButton) {
     case -1:
       return MouseButtonsFlag::eNoButtons;
     case MouseButton::eLeft:
       return MouseButtonsFlag::eLeftFlag;
@@ -7891,30 +7894,33 @@ LayoutDeviceIntPoint nsContentUtils::ToW
     nsPresContext* aPresContext) {
   return LayoutDeviceIntPoint::FromAppUnitsRounded(
       (CSSPoint::ToAppUnits(aPoint) + aOffset)
           .ApplyResolution(nsLayoutUtils::GetCurrentAPZResolutionScale(
               aPresContext->PresShell())),
       aPresContext->AppUnitsPerDevPixel());
 }
 
-nsView* nsContentUtils::GetViewToDispatchEvent(nsPresContext* presContext,
-                                               nsIPresShell** presShell) {
-  if (presContext && presShell) {
-    *presShell = presContext->PresShell();
-    if (*presShell) {
-      NS_ADDREF(*presShell);
-      if (nsViewManager* viewManager = (*presShell)->GetViewManager()) {
-        if (nsView* view = viewManager->GetRootView()) {
-          return view;
-        }
-      }
-    }
-  }
-  return nullptr;
+nsView* nsContentUtils::GetViewToDispatchEvent(nsPresContext* aPresContext,
+                                               PresShell** aPresShell) {
+  if (!aPresContext || !aPresShell) {
+    return nullptr;
+  }
+  RefPtr<PresShell> presShell = aPresContext->PresShell();
+  if (NS_WARN_IF(!presShell)) {
+    *aPresShell = nullptr;
+    return nullptr;
+  }
+  nsViewManager* viewManager = presShell->GetViewManager();
+  if (!viewManager) {
+    presShell.forget(aPresShell);  // XXX Is this intentional?
+    return nullptr;
+  }
+  presShell.forget(aPresShell);
+  return viewManager->GetRootView();
 }
 
 nsresult nsContentUtils::SendMouseEvent(
     mozilla::PresShell* aPresShell, const nsAString& aType, float aX, float aY,
     int32_t aButton, int32_t aButtons, int32_t aClickCount, int32_t aModifiers,
     bool aIgnoreRootScrollFrame, float aPressure,
     unsigned short aInputSourceArg, uint32_t aIdentifier, bool aToWindow,
     bool* aPreventDefault, bool aIsDOMEventSynthesized,
@@ -7976,17 +7982,17 @@ nsresult nsContentUtils::SendMouseEvent(
   nsPresContext* presContext = aPresShell->GetPresContext();
   if (!presContext) return NS_ERROR_FAILURE;
 
   event.mRefPoint = ToWidgetPoint(CSSPoint(aX, aY), offset, presContext);
   event.mIgnoreRootScrollFrame = aIgnoreRootScrollFrame;
 
   nsEventStatus status = nsEventStatus_eIgnore;
   if (aToWindow) {
-    nsCOMPtr<nsIPresShell> presShell;
+    RefPtr<PresShell> presShell;
     nsView* view =
         GetViewToDispatchEvent(presContext, getter_AddRefs(presShell));
     if (!presShell || !view) {
       return NS_ERROR_FAILURE;
     }
     return presShell->HandleEvent(view->GetFrame(), &event, false, &status);
   }
   if (gfxPrefs::TestEventsAsyncEnabled()) {
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -78,17 +78,16 @@ class nsIImageLoadingContent;
 class nsIInterfaceRequestor;
 class nsIIOService;
 class nsILoadInfo;
 class nsILoadGroup;
 class nsNameSpaceManager;
 class nsIObserver;
 class nsIParser;
 class nsIPluginTag;
-class nsIPresShell;
 class nsIPrincipal;
 class nsIRequest;
 class nsIRunnable;
 class nsIScriptContext;
 class nsIScriptSecurityManager;
 class nsIStringBundle;
 class nsIStringBundleService;
 class nsISupportsHashKey;
@@ -2144,24 +2143,25 @@ class nsContentUtils {
   static nsresult GetThreadSafeASCIIOrigin(nsIURI* aURI, nsACString& aOrigin);
   static nsresult GetUTFOrigin(nsIPrincipal* aPrincipal, nsAString& aOrigin);
   static nsresult GetUTFOrigin(nsIURI* aURI, nsAString& aOrigin);
   static nsresult GetThreadSafeUTFOrigin(nsIURI* aURI, nsAString& aOrigin);
 
   /**
    * This method creates and dispatches "command" event, which implements
    * XULCommandEvent.
-   * If aShell is not null, dispatching goes via
-   * nsIPresShell::HandleDOMEventWithTarget.
+   * If aPresShell is not null, dispatching goes via
+   * PresShell::HandleDOMEventWithTarget().
    */
+  MOZ_CAN_RUN_SCRIPT
   static nsresult DispatchXULCommand(
       nsIContent* aTarget, bool aTrusted,
       mozilla::dom::Event* aSourceEvent = nullptr,
-      nsIPresShell* aShell = nullptr, bool aCtrl = false, bool aAlt = false,
-      bool aShift = false, bool aMeta = false,
+      mozilla::PresShell* aPresShell = nullptr, bool aCtrl = false,
+      bool aAlt = false, bool aShift = false, bool aMeta = false,
       // Including MouseEventBinding here leads
       // to incude loops, unfortunately.
       uint16_t inputSource = 0 /* MouseEvent_Binding::MOZ_SOURCE_UNKNOWN */);
 
   static bool CheckMayLoad(nsIPrincipal* aPrincipal, nsIChannel* aChannel,
                            bool aAllowIfInheritsPrincipal);
 
   /**
@@ -2248,27 +2248,28 @@ class nsContentUtils {
    * Returns a presshell for this document, if there is one. This will be
    * aDoc's direct presshell if there is one, otherwise we'll look at all
    * ancestor documents to try to find a presshell, so for example this can
    * still find a presshell for documents in display:none frames that have
    * no presentation. So you have to be careful how you use this presshell ---
    * getting generic data like a device context or widget from it is OK, but it
    * might not be this document's actual presentation.
    */
-  static nsIPresShell* FindPresShellForDocument(const Document* aDoc);
+  static mozilla::PresShell* FindPresShellForDocument(
+      const Document* aDocument);
 
   /**
    * Returns the widget for this document if there is one. Looks at all ancestor
    * documents to try to find a widget, so for example this can still find a
    * widget for documents in display:none frames that have no presentation.
    *
    * You should probably use WidgetForContent() instead of this, unless you have
    * a good reason to do otherwise.
    */
-  static nsIWidget* WidgetForDocument(const Document* aDoc);
+  static nsIWidget* WidgetForDocument(const Document* aDocument);
 
   /**
    * Returns the appropriate widget for this element, if there is one. Unlike
    * WidgetForDocument(), this returns the correct widget for content in popups.
    *
    * You should probably use this instead of WidgetForDocument().
    */
   static nsIWidget* WidgetForContent(const nsIContent* aContent);
@@ -2875,23 +2876,23 @@ class nsContentUtils {
    */
   static mozilla::Maybe<mozilla::ipc::Shmem> GetSurfaceData(
       mozilla::gfx::DataSourceSurface* aSurface, size_t* aLength,
       int32_t* aStride, mozilla::ipc::IShmemAllocator* aAlloc);
 
   // Helpers shared by the implementations of nsContentUtils methods and
   // nsIDOMWindowUtils methods.
   static mozilla::Modifiers GetWidgetModifiers(int32_t aModifiers);
-  static nsIWidget* GetWidget(nsIPresShell* aPresShell, nsPoint* aOffset);
+  static nsIWidget* GetWidget(mozilla::PresShell* aPresShell, nsPoint* aOffset);
   static int16_t GetButtonsFlagForButton(int32_t aButton);
   static mozilla::LayoutDeviceIntPoint ToWidgetPoint(
       const mozilla::CSSPoint& aPoint, const nsPoint& aOffset,
       nsPresContext* aPresContext);
   static nsView* GetViewToDispatchEvent(nsPresContext* aPresContext,
-                                        nsIPresShell** aPresShell);
+                                        mozilla::PresShell** aPresShell);
 
   /**
    * Synthesize a mouse event to the given widget
    * (see nsIDOMWindowUtils.sendMouseEvent).
    */
   MOZ_CAN_RUN_SCRIPT
   static nsresult SendMouseEvent(
       mozilla::PresShell* aPresShell, const nsAString& aType, float aX,
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -829,17 +829,17 @@ nsDOMWindowUtils::SendTouchEventCommon(
     RefPtr<Touch> t =
         new Touch(aIdentifiers[i], pt, radius, aRotationAngles[i], aForces[i]);
 
     event.mTouches.AppendElement(t);
   }
 
   nsEventStatus status;
   if (aToWindow) {
-    nsCOMPtr<nsIPresShell> presShell;
+    RefPtr<PresShell> presShell;
     nsView* view = nsContentUtils::GetViewToDispatchEvent(
         presContext, getter_AddRefs(presShell));
     if (!presShell || !view) {
       return NS_ERROR_FAILURE;
     }
     status = nsEventStatus_eIgnore;
     *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault);
     return presShell->HandleEvent(view->GetFrame(), &event, false, &status);
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -100,49 +100,51 @@ LazyLogModule gFocusNavigationLog("Focus
     MOZ_LOG(log, LogLevel::Debug, (format, tag.get()));   \
   }
 
 #define LOGCONTENT(format, content) LOGTAG(gFocusLog, format, content)
 #define LOGCONTENTNAVIGATION(format, content) \
   LOGTAG(gFocusNavigationLog, format, content)
 
 struct nsDelayedBlurOrFocusEvent {
-  nsDelayedBlurOrFocusEvent(EventMessage aEventMessage,
-                            nsIPresShell* aPresShell, Document* aDocument,
-                            EventTarget* aTarget, EventTarget* aRelatedTarget)
+  nsDelayedBlurOrFocusEvent(EventMessage aEventMessage, PresShell* aPresShell,
+                            Document* aDocument, EventTarget* aTarget,
+                            EventTarget* aRelatedTarget)
       : mPresShell(aPresShell),
         mDocument(aDocument),
         mTarget(aTarget),
         mEventMessage(aEventMessage),
         mRelatedTarget(aRelatedTarget) {}
 
   nsDelayedBlurOrFocusEvent(const nsDelayedBlurOrFocusEvent& aOther)
       : mPresShell(aOther.mPresShell),
         mDocument(aOther.mDocument),
         mTarget(aOther.mTarget),
         mEventMessage(aOther.mEventMessage) {}
 
-  nsCOMPtr<nsIPresShell> mPresShell;
+  RefPtr<PresShell> mPresShell;
   nsCOMPtr<Document> mDocument;
   nsCOMPtr<EventTarget> mTarget;
   EventMessage mEventMessage;
   nsCOMPtr<EventTarget> mRelatedTarget;
 };
 
 inline void ImplCycleCollectionUnlink(nsDelayedBlurOrFocusEvent& aField) {
   aField.mPresShell = nullptr;
   aField.mDocument = nullptr;
   aField.mTarget = nullptr;
   aField.mRelatedTarget = nullptr;
 }
 
 inline void ImplCycleCollectionTraverse(
     nsCycleCollectionTraversalCallback& aCallback,
     nsDelayedBlurOrFocusEvent& aField, const char* aName, uint32_t aFlags = 0) {
-  CycleCollectionNoteChild(aCallback, aField.mPresShell.get(), aName, aFlags);
+  CycleCollectionNoteChild(
+      aCallback, static_cast<nsIDocumentObserver*>(aField.mPresShell.get()),
+      aName, aFlags);
   CycleCollectionNoteChild(aCallback, aField.mDocument.get(), aName, aFlags);
   CycleCollectionNoteChild(aCallback, aField.mTarget.get(), aName, aFlags);
   CycleCollectionNoteChild(aCallback, aField.mRelatedTarget.get(), aName,
                            aFlags);
 }
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFocusManager)
   NS_INTERFACE_MAP_ENTRY(nsIFocusManager)
@@ -987,18 +989,17 @@ nsFocusManager::FireDelayedEvents(Docume
         // If the document was navigated away from or is defunct, don't bother
         // firing events on it. Note the symmetry between this condition and
         // the similar one in Document.cpp:FireOrClearDelayedEvents.
         mDelayedBlurFocusEvents.RemoveElementAt(i);
         --i;
       } else if (!aDocument->EventHandlingSuppressed()) {
         EventMessage message = mDelayedBlurFocusEvents[i].mEventMessage;
         nsCOMPtr<EventTarget> target = mDelayedBlurFocusEvents[i].mTarget;
-        nsCOMPtr<nsIPresShell> presShell =
-            mDelayedBlurFocusEvents[i].mPresShell;
+        RefPtr<PresShell> presShell = mDelayedBlurFocusEvents[i].mPresShell;
         nsCOMPtr<EventTarget> relatedTarget =
             mDelayedBlurFocusEvents[i].mRelatedTarget;
         mDelayedBlurFocusEvents.RemoveElementAt(i);
 
         FireFocusOrBlurEvent(message, presShell, target, false, false,
                              relatedTarget);
         --i;
       }
@@ -1071,27 +1072,33 @@ void nsFocusManager::NotifyFocusStateCha
 
 // static
 void nsFocusManager::EnsureCurrentWidgetFocused() {
   if (!mFocusedWindow || sTestMode) return;
 
   // get the main child widget for the focused window and ensure that the
   // platform knows that this widget is focused.
   nsCOMPtr<nsIDocShell> docShell = mFocusedWindow->GetDocShell();
-  if (docShell) {
-    nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
-    if (presShell) {
-      nsViewManager* vm = presShell->GetViewManager();
-      if (vm) {
-        nsCOMPtr<nsIWidget> widget;
-        vm->GetRootWidget(getter_AddRefs(widget));
-        if (widget) widget->SetFocus(false);
-      }
-    }
+  if (!docShell) {
+    return;
+  }
+  RefPtr<PresShell> presShell = docShell->GetPresShell();
+  if (!presShell) {
+    return;
   }
+  nsViewManager* vm = presShell->GetViewManager();
+  if (!vm) {
+    return;
+  }
+  nsCOMPtr<nsIWidget> widget;
+  vm->GetRootWidget(getter_AddRefs(widget));
+  if (!widget) {
+    return;
+  }
+  widget->SetFocus(false);
 }
 
 bool ActivateOrDeactivateChild(BrowserParent* aParent, void* aArg) {
   bool active = static_cast<bool>(aArg);
   Unused << aParent->SendParentActivated(active);
   return false;
 }
 
@@ -2014,29 +2021,29 @@ static Document* GetDocumentHelper(Event
     nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aTarget);
     return win ? win->GetExtantDoc() : nullptr;
   }
 
   return node->OwnerDoc();
 }
 
 void nsFocusManager::FireFocusInOrOutEvent(
-    EventMessage aEventMessage, nsIPresShell* aPresShell, nsISupports* aTarget,
+    EventMessage aEventMessage, PresShell* aPresShell, nsISupports* aTarget,
     nsPIDOMWindowOuter* aCurrentFocusedWindow,
     nsIContent* aCurrentFocusedContent, EventTarget* aRelatedTarget) {
   NS_ASSERTION(aEventMessage == eFocusIn || aEventMessage == eFocusOut,
                "Wrong event type for FireFocusInOrOutEvent");
 
   nsContentUtils::AddScriptRunner(new FocusInOutEvent(
       aTarget, aEventMessage, aPresShell->GetPresContext(),
       aCurrentFocusedWindow, aCurrentFocusedContent, aRelatedTarget));
 }
 
 void nsFocusManager::SendFocusOrBlurEvent(
-    EventMessage aEventMessage, nsIPresShell* aPresShell, Document* aDocument,
+    EventMessage aEventMessage, PresShell* aPresShell, Document* aDocument,
     nsISupports* aTarget, uint32_t aFocusMethod, bool aWindowRaised,
     bool aIsRefocus, EventTarget* aRelatedTarget) {
   NS_ASSERTION(aEventMessage == eFocus || aEventMessage == eBlur,
                "Wrong event type for SendFocusOrBlurEvent");
 
   nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget);
   nsCOMPtr<Document> eventTargetDoc = GetDocumentHelper(eventTarget);
   nsCOMPtr<Document> relatedTargetDoc = GetDocumentHelper(aRelatedTarget);
@@ -2073,17 +2080,17 @@ void nsFocusManager::SendFocusOrBlurEven
     FireDelayedEvents(aDocument);
   }
 
   FireFocusOrBlurEvent(aEventMessage, aPresShell, aTarget, aWindowRaised,
                        aIsRefocus, aRelatedTarget);
 }
 
 void nsFocusManager::FireFocusOrBlurEvent(EventMessage aEventMessage,
-                                          nsIPresShell* aPresShell,
+                                          PresShell* aPresShell,
                                           nsISupports* aTarget,
                                           bool aWindowRaised, bool aIsRefocus,
                                           EventTarget* aRelatedTarget) {
   nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget);
   nsCOMPtr<Document> eventTargetDoc = GetDocumentHelper(eventTarget);
   nsCOMPtr<nsPIDOMWindowOuter> currentWindow = mFocusedWindow;
   nsCOMPtr<nsPIDOMWindowInner> targetWindow = do_QueryInterface(aTarget);
   nsCOMPtr<Document> targetDocument = do_QueryInterface(aTarget);
@@ -2258,17 +2265,17 @@ void nsFocusManager::UpdateCaret(bool aM
       browseWithCaret =
           docElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::showcaret,
                                   NS_LITERAL_STRING("true"), eCaseMatters);
   }
 
   SetCaretVisible(presShell, browseWithCaret, aContent);
 }
 
-void nsFocusManager::MoveCaretToFocus(nsIPresShell* aPresShell,
+void nsFocusManager::MoveCaretToFocus(PresShell* aPresShell,
                                       nsIContent* aContent) {
   nsCOMPtr<Document> doc = aPresShell->GetDocument();
   if (doc) {
     RefPtr<nsFrameSelection> frameSelection = aPresShell->FrameSelection();
     RefPtr<Selection> domSelection =
         frameSelection->GetSelection(SelectionType::eNormal);
     if (domSelection) {
       // First clear the selection. This way, if there is no currently focused
@@ -2296,18 +2303,18 @@ void nsFocusManager::MoveCaretToFocus(ns
         }
         domSelection->AddRange(*newRange, IgnoreErrors());
         domSelection->CollapseToStart(IgnoreErrors());
       }
     }
   }
 }
 
-nsresult nsFocusManager::SetCaretVisible(nsIPresShell* aPresShell,
-                                         bool aVisible, nsIContent* aContent) {
+nsresult nsFocusManager::SetCaretVisible(PresShell* aPresShell, bool aVisible,
+                                         nsIContent* aContent) {
   // When browsing with caret, make sure caret is visible after new focus
   // Return early if there is no caret. This can happen for the testcase
   // for bug 308025 where a window is closed in a blur handler.
   RefPtr<nsCaret> caret = aPresShell->GetCaret();
   if (!caret) return NS_OK;
 
   bool caretVisible = caret->IsVisible();
   if (!aVisible && !caretVisible) return NS_OK;
@@ -2322,43 +2329,39 @@ nsresult nsFocusManager::SetCaretVisible
 
   RefPtr<nsFrameSelection> docFrameSelection = aPresShell->FrameSelection();
 
   if (docFrameSelection && caret &&
       (frameSelection == docFrameSelection || !aContent)) {
     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);
+      aPresShell->SetCaretEnabled(false);
 
       // Caret must blink on non-editable elements
       caret->SetIgnoreUserModify(true);
       // Tell the caret which selection to use
       caret->SetSelection(domSelection);
 
       // In content, we need to set the caret. The only special case is edit
       // fields, which have a different frame selection from the document.
       // They will take care of making the caret visible themselves.
 
-      selCon->SetCaretReadOnly(false);
-      selCon->SetCaretEnabled(aVisible);
+      aPresShell->SetCaretReadOnly(false);
+      aPresShell->SetCaretEnabled(aVisible);
     }
   }
 
   return NS_OK;
 }
 
 nsresult nsFocusManager::GetSelectionLocation(Document* aDocument,
-                                              nsIPresShell* aPresShell,
+                                              PresShell* aPresShell,
                                               nsIContent** aStartContent,
                                               nsIContent** aEndContent) {
   *aStartContent = *aEndContent = nullptr;
   nsPresContext* presContext = aPresShell->GetPresContext();
   NS_ASSERTION(presContext, "mPresContent is null!!");
 
   RefPtr<nsFrameSelection> frameSelection = aPresShell->FrameSelection();
 
@@ -3221,17 +3224,17 @@ static nsIContent* GetTopLevelScopeOwner
       aContent = aContent->GetParent();
     }
   }
 
   return topLevelScopeOwner;
 }
 
 nsresult nsFocusManager::GetNextTabbableContent(
-    nsIPresShell* aPresShell, nsIContent* aRootContent,
+    PresShell* aPresShell, nsIContent* aRootContent,
     nsIContent* aOriginalStartContent, nsIContent* aStartContent, bool aForward,
     int32_t aCurrentTabIndex, bool aIgnoreTabIndex, bool aForDocumentNavigation,
     nsIContent** aResultContent) {
   *aResultContent = nullptr;
 
   nsCOMPtr<nsIContent> startContent = aStartContent;
   if (!startContent) return NS_OK;
 
--- a/dom/base/nsFocusManager.h
+++ b/dom/base/nsFocusManager.h
@@ -346,31 +346,31 @@ class nsFocusManager final : public nsIF
    * event queue if the document is suppressing events.
    *
    * aEventMessage should be either eFocus or eBlur.
    * For blur events, aFocusMethod should normally be non-zero.
    *
    * aWindowRaised should only be true if called from WindowRaised.
    */
   void SendFocusOrBlurEvent(
-      mozilla::EventMessage aEventMessage, nsIPresShell* aPresShell,
+      mozilla::EventMessage aEventMessage, mozilla::PresShell* aPresShell,
       Document* aDocument, nsISupports* aTarget, uint32_t aFocusMethod,
       bool aWindowRaised, bool aIsRefocus = false,
       mozilla::dom::EventTarget* aRelatedTarget = nullptr);
 
   /**
    * Fire a focus or blur event at aTarget.
    *
    * aEventMessage should be either eFocus or eBlur.
    * For blur events, aFocusMethod should normally be non-zero.
    *
    * aWindowRaised should only be true if called from WindowRaised.
    */
   void FireFocusOrBlurEvent(
-      mozilla::EventMessage aEventMessage, nsIPresShell* aPresShell,
+      mozilla::EventMessage aEventMessage, mozilla::PresShell* aPresShell,
       nsISupports* aTarget, bool aWindowRaised, bool aIsRefocus = false,
       mozilla::dom::EventTarget* aRelatedTarget = nullptr);
 
   /**
    *  Fire a focusin or focusout event
    *
    *  aEventMessage should be either eFocusIn or eFocusOut.
    *
@@ -382,17 +382,17 @@ class nsFocusManager final : public nsIF
    *
    *  aCurrentFocusedContent is the content focused before the focus/blur event
    *  was fired.
    *
    *  aRelatedTarget is the content related to the event (the object
    *  losing focus for focusin, the object getting focus for focusout).
    */
   void FireFocusInOrOutEvent(
-      mozilla::EventMessage aEventMessage, nsIPresShell* aPresShell,
+      mozilla::EventMessage aEventMessage, mozilla::PresShell* aPresShell,
       nsISupports* aTarget, nsPIDOMWindowOuter* aCurrentFocusedWindow,
       nsIContent* aCurrentFocusedContent,
       mozilla::dom::EventTarget* aRelatedTarget = nullptr);
 
   /**
    * Scrolls aContent into view unless the FLAG_NOSCROLL flag is set.
    */
   MOZ_CAN_RUN_SCRIPT
@@ -413,31 +413,32 @@ class nsFocusManager final : public nsIF
    * visible or not.
    */
   void UpdateCaret(bool aMoveCaretToFocus, bool aUpdateVisibility,
                    nsIContent* aContent);
 
   /**
    * Helper method to move the caret to the focused element aContent.
    */
-  void MoveCaretToFocus(nsIPresShell* aPresShell, nsIContent* aContent);
+  void MoveCaretToFocus(mozilla::PresShell* aPresShell, nsIContent* aContent);
 
   /**
    * Makes the caret visible or not, depending on aVisible.
    */
-  nsresult SetCaretVisible(nsIPresShell* aPresShell, bool aVisible,
+  nsresult SetCaretVisible(mozilla::PresShell* aPresShell, bool aVisible,
                            nsIContent* aContent);
 
   // the remaining functions are used for tab key and document-navigation
 
   /**
    * Retrieves the start and end points of the current selection for
    * aDocument and stores them in aStartContent and aEndContent.
    */
-  nsresult GetSelectionLocation(Document* aDocument, nsIPresShell* aPresShell,
+  nsresult GetSelectionLocation(Document* aDocument,
+                                mozilla::PresShell* aPresShell,
                                 nsIContent** aStartContent,
                                 nsIContent** aEndContent);
 
   /**
    * Retrieve the next tabbable element in scope owned by aOwner, using
    * focusability and tabindex to determine the tab order.
    *
    * aOwner is the owner of scope to search in.
@@ -534,17 +535,17 @@ class nsFocusManager final : public nsIF
    *
    * aIgnoreTabIndex to ignore the current tabindex and find the element
    * irrespective or the tab index. This will be true when a selection is
    * active, since we just want to focus the next element in tree order
    * from where the selection is. Similarly, if the starting element isn't
    * focusable, since it doesn't really have a defined tab index.
    */
   nsresult GetNextTabbableContent(
-      nsIPresShell* aPresShell, nsIContent* aRootContent,
+      mozilla::PresShell* aPresShell, nsIContent* aRootContent,
       nsIContent* aOriginalStartContent, nsIContent* aStartContent,
       bool aForward, int32_t aCurrentTabIndex, bool aIgnoreTabIndex,
       bool aForDocumentNavigation, nsIContent** aResultContent);
 
   /**
    * Get the next tabbable image map area and returns it.
    *
    * aForward should be true for forward navigation or false for backward
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -25,17 +25,16 @@
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsDocShellLoadState.h"
 #include "nsIBaseWindow.h"
 #include "nsIBrowser.h"
 #include "nsContentUtils.h"
 #include "nsIXPConnect.h"
 #include "nsUnicharUtils.h"
-#include "nsIPresShellInlines.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScrollable.h"
 #include "nsFrameLoader.h"
 #include "nsFrameLoaderOwner.h"
 #include "nsIFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsSubDocumentFrame.h"
@@ -74,16 +73,17 @@
 #include "BrowserParent.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/HTMLEditor.h"
 #include "mozilla/NullPrincipal.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/Unused.h"
 #include "mozilla/dom/ChromeMessageSender.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/FrameLoaderBinding.h"
 #include "mozilla/dom/MozFrameLoaderOwnerBinding.h"
 #include "mozilla/gfx/CrossProcessPaint.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/layout/RenderFrame.h"
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -4491,19 +4491,19 @@ void nsGlobalWindowOuter::FinishFullscre
   // and DOM fullscreen.
   FinishDOMFullscreenChange(mDoc, mFullscreen);
 
   // dispatch a "fullscreen" DOM event so that XUL apps can
   // respond visually if we are kicked into full screen mode
   DispatchCustomEvent(NS_LITERAL_STRING("fullscreen"));
 
   if (!NS_WARN_IF(!IsChromeWindow())) {
-    if (nsCOMPtr<nsIPresShell> shell =
+    if (RefPtr<PresShell> presShell =
             do_QueryReferent(mChromeFields.mFullscreenPresShell)) {
-      if (nsRefreshDriver* rd = shell->GetRefreshDriver()) {
+      if (nsRefreshDriver* rd = presShell->GetRefreshDriver()) {
         rd->Thaw();
       }
       mChromeFields.mFullscreenPresShell = nullptr;
     }
   }
 
   if (!mWakeLock && mFullscreen) {
     RefPtr<power::PowerManagerService> pmService =
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -18,16 +18,17 @@
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/CORSMode.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/HTMLEditor.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TextEditor.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/CharacterData.h"
 #include "mozilla/dom/DocumentType.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"
@@ -62,17 +63,16 @@
 #include "nsIControllers.h"
 #include "mozilla/dom/Document.h"
 #include "mozilla/dom/DocumentInlines.h"
 #include "nsIDOMEventListener.h"
 #include "nsIFrameInlines.h"
 #include "nsILinkHandler.h"
 #include "mozilla/dom/NodeInfo.h"
 #include "mozilla/dom/NodeInfoInlines.h"
-#include "nsIPresShell.h"
 #include "nsIScriptError.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScrollableFrame.h"
 #include "nsIServiceManager.h"
 #include "nsIURL.h"
 #include "nsView.h"
 #include "nsViewManager.h"
@@ -309,17 +309,17 @@ static nsIContent* GetRootForContentSubt
     if (parent == stop) {
       break;
     }
     aContent = parent;
   }
   return aContent;
 }
 
-nsIContent* nsINode::GetSelectionRootContent(nsIPresShell* aPresShell) {
+nsIContent* nsINode::GetSelectionRootContent(PresShell* aPresShell) {
   NS_ENSURE_TRUE(aPresShell, nullptr);
 
   if (IsDocument()) return AsDocument()->GetRootElement();
   if (!IsContent()) return nullptr;
 
   if (GetComposedDoc() != aPresShell->GetDocument()) {
     return nullptr;
   }
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -40,27 +40,27 @@ class nsAttrChildContentList;
 class nsDOMAttributeMap;
 class nsIAnimationObserver;
 class nsIContent;
 class nsIFrame;
 class nsIHTMLCollection;
 class nsIMutationObserver;
 class nsINode;
 class nsINodeList;
-class nsIPresShell;
 class nsIPrincipal;
 class nsIURI;
 class nsNodeSupportsWeakRefTearoff;
 class nsDOMMutationObserver;
 class nsRange;
 class nsWindowSizes;
 struct RawServoSelectorList;
 
 namespace mozilla {
 class EventListenerManager;
+class PresShell;
 class TextEditor;
 namespace dom {
 /**
  * @return true if aChar is what the WHATWG defines as a 'ascii whitespace'.
  * https://infra.spec.whatwg.org/#ascii-whitespace
  */
 inline bool IsSpaceCharacter(char16_t aChar) {
   return aChar == ' ' || aChar == '\t' || aChar == '\n' || aChar == '\r' ||
@@ -1175,17 +1175,17 @@ class nsINode : public mozilla::dom::Eve
   /**
    * Get the nearest selection root, ie. the node that will be selected if the
    * user does "Select All" while the focus is in this node. Note that if this
    * node is not in an editor, the result comes from the nsFrameSelection that
    * is related to aPresShell, so the result might not be the ancestor of this
    * node. Be aware that if this node and the computed selection limiter are
    * not in same subtree, this returns the root content of the closeset subtree.
    */
-  nsIContent* GetSelectionRootContent(nsIPresShell* aPresShell);
+  nsIContent* GetSelectionRootContent(mozilla::PresShell* aPresShell);
 
   nsINodeList* ChildNodes();
 
   nsIContent* GetFirstChild() const { return mFirstChild; }
 
   nsIContent* GetLastChild() const;
 
   /**
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -11,21 +11,21 @@
 #include "nsAutoPtr.h"
 #include "nsIServiceManager.h"
 #include "nsMathUtils.h"
 #include "SVGImageContext.h"
 
 #include "nsContentUtils.h"
 
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/dom/Document.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "SVGObserverUtils.h"
 #include "nsPresContext.h"
-#include "nsIPresShellInlines.h"
 
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIFrame.h"
 #include "nsError.h"
 
 #include "nsCSSPseudoElements.h"
 #include "nsComputedDOMStyle.h"
 
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -1003,31 +1003,36 @@ class CanvasRenderingContext2D final : p
   friend class CanvasGeneralPattern;
   friend class AdjustedTarget;
   friend class AdjustedTargetForShadow;
   friend class AdjustedTargetForFilter;
 
   // other helpers
   void GetAppUnitsValues(int32_t* aPerDevPixel, int32_t* aPerCSSPixel) {
     // If we don't have a canvas element, we just return something generic.
-    int32_t devPixel = 60;
-    int32_t cssPixel = 60;
-
-    nsIPresShell* ps = GetPresShell();
-    nsPresContext* pc;
-
-    if (!ps) goto FINISH;
-    pc = ps->GetPresContext();
-    if (!pc) goto FINISH;
-    devPixel = pc->AppUnitsPerDevPixel();
-    cssPixel = AppUnitsPerCSSPixel();
-
-  FINISH:
-    if (aPerDevPixel) *aPerDevPixel = devPixel;
-    if (aPerCSSPixel) *aPerCSSPixel = cssPixel;
+    if (aPerDevPixel) {
+      *aPerDevPixel = 60;
+    }
+    if (aPerCSSPixel) {
+      *aPerCSSPixel = 60;
+    }
+    PresShell* presShell = GetPresShell();
+    if (!presShell) {
+      return;
+    }
+    nsPresContext* presContext = presShell->GetPresContext();
+    if (!presContext) {
+      return;
+    }
+    if (aPerDevPixel) {
+      *aPerDevPixel = presContext->AppUnitsPerDevPixel();
+    }
+    if (aPerCSSPixel) {
+      *aPerCSSPixel = AppUnitsPerCSSPixel();
+    }
   }
 
   friend struct CanvasBidiProcessor;
   friend class CanvasDrawObserver;
   friend class ImageBitmap;
 
   void SetWriteOnly();
 
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -594,21 +594,21 @@ CSSIntPoint Event::GetClientCoords(nsPre
        aEvent->mClass != eTouchEventClass &&
        aEvent->mClass != eDragEventClass &&
        aEvent->mClass != ePointerEventClass &&
        aEvent->mClass != eSimpleGestureEventClass) ||
       !aPresContext || !aEvent->AsGUIEvent()->mWidget) {
     return aDefaultPoint;
   }
 
-  nsIPresShell* shell = aPresContext->GetPresShell();
-  if (!shell) {
+  PresShell* presShell = aPresContext->GetPresShell();
+  if (!presShell) {
     return CSSIntPoint(0, 0);
   }
-  nsIFrame* rootFrame = shell->GetRootFrame();
+  nsIFrame* rootFrame = presShell->GetRootFrame();
   if (!rootFrame) {
     return CSSIntPoint(0, 0);
   }
   nsPoint pt =
       nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, aPoint, rootFrame);
 
   return CSSIntPoint::FromAppUnitsRounded(pt);
 }
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -4847,19 +4847,19 @@ bool EventStateManager::EventCausesClick
   }
   // Check that the window isn't disabled before firing a click
   // (see bug 366544).
   return !(aMouseEvent.mWidget && !aMouseEvent.mWidget->IsEnabled());
 }
 
 nsresult EventStateManager::InitAndDispatchClickEvent(
     WidgetMouseEvent* aMouseUpEvent, nsEventStatus* aStatus,
-    EventMessage aMessage, nsIPresShell* aPresShell,
-    nsIContent* aMouseUpContent, AutoWeakFrame aCurrentTarget,
-    bool aNoContentDispatch, nsIContent* aOverrideClickTarget) {
+    EventMessage aMessage, PresShell* aPresShell, nsIContent* aMouseUpContent,
+    AutoWeakFrame aCurrentTarget, bool aNoContentDispatch,
+    nsIContent* aOverrideClickTarget) {
   MOZ_ASSERT(aMouseUpEvent);
   MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent));
   MOZ_ASSERT(aMouseUpContent || aCurrentTarget || aOverrideClickTarget);
 
   WidgetMouseEvent event(aMouseUpEvent->IsTrusted(), aMessage,
                          aMouseUpEvent->mWidget, WidgetMouseEvent::eReal);
 
   event.mRefPoint = aMouseUpEvent->mRefPoint;
@@ -4969,17 +4969,17 @@ nsresult EventStateManager::PostHandleMo
   }
 
   // Don't return error even if middle mouse paste fails since we haven't
   // handled it here.
   return NS_OK;
 }
 
 nsresult EventStateManager::DispatchClickEvents(
-    nsIPresShell* aPresShell, WidgetMouseEvent* aMouseUpEvent,
+    PresShell* aPresShell, WidgetMouseEvent* aMouseUpEvent,
     nsEventStatus* aStatus, nsIContent* aClickTarget,
     nsIContent* aOverrideClickTarget) {
   MOZ_ASSERT(aPresShell);
   MOZ_ASSERT(aMouseUpEvent);
   MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent));
   MOZ_ASSERT(aStatus);
   MOZ_ASSERT(aClickTarget || aOverrideClickTarget);
 
@@ -5016,17 +5016,17 @@ nsresult EventStateManager::DispatchClic
       return rv;
     }
   }
 
   return rv;
 }
 
 nsresult EventStateManager::HandleMiddleClickPaste(
-    nsIPresShell* aPresShell, WidgetMouseEvent* aMouseEvent,
+    PresShell* aPresShell, WidgetMouseEvent* aMouseEvent,
     nsEventStatus* aStatus, TextEditor* aTextEditor) {
   MOZ_ASSERT(aPresShell);
   MOZ_ASSERT(aMouseEvent);
   MOZ_ASSERT((aMouseEvent->mMessage == eMouseAuxClick &&
               aMouseEvent->mButton == MouseButton::eMiddle) ||
              EventCausesClickEvents(*aMouseEvent));
   MOZ_ASSERT(aStatus);
   MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault);
@@ -5055,18 +5055,17 @@ nsresult EventStateManager::HandleMiddle
       return NS_ERROR_FAILURE;
     }
   }
 
   // Move selection to the clicked point.
   nsCOMPtr<nsIContent> container;
   int32_t offset;
   nsLayoutUtils::GetContainerAndOffsetAtEvent(
-      static_cast<PresShell*>(aPresShell), aMouseEvent,
-      getter_AddRefs(container), &offset);
+      aPresShell, aMouseEvent, getter_AddRefs(container), &offset);
   if (container) {
     // XXX If readonly or disabled <input> or <textarea> in contenteditable
     //     designMode editor is clicked, the point is in the editor.
     //     However, outer HTMLEditor and Selection should handle it.
     //     So, in such case, Selection::Collapse() will fail.
     DebugOnly<nsresult> rv = selection->Collapse(container, offset);
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                          "Failed to collapse Selection at middle clicked");
@@ -5082,18 +5081,17 @@ nsresult EventStateManager::HandleMiddle
     if (NS_SUCCEEDED(rv) && selectionSupported) {
       clipboardType = nsIClipboard::kSelectionClipboard;
     }
   }
 
   // Fire ePaste event by ourselves since we need to dispatch "paste" event
   // even if the middle click event was consumed for compatibility with
   // Chromium.
-  if (!nsCopySupport::FireClipboardEvent(ePaste, clipboardType,
-                                         static_cast<PresShell*>(aPresShell),
+  if (!nsCopySupport::FireClipboardEvent(ePaste, clipboardType, aPresShell,
                                          selection)) {
     *aStatus = nsEventStatus_eConsumeNoDefault;
     return NS_OK;
   }
 
   // Although we've fired "paste" event, there is no editor to accept the
   // clipboard content.
   if (!aTextEditor) {
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -365,17 +365,17 @@ class EventStateManager : public nsSuppo
    *                                paste.
    * @param aStatus                 The event status of aMouseEvent.
    * @param aTextEditor             TextEditor which may be pasted the
    *                                clipboard text by the middle click.
    *                                If there is no editor for aMouseEvent,
    *                                set nullptr.
    */
   MOZ_CAN_RUN_SCRIPT
-  nsresult HandleMiddleClickPaste(nsIPresShell* aPresShell,
+  nsresult HandleMiddleClickPaste(PresShell* aPresShell,
                                   WidgetMouseEvent* aMouseEvent,
                                   nsEventStatus* aStatus,
                                   TextEditor* aTextEditor);
 
  protected:
   /**
    * Prefs class capsules preference management.
    */
@@ -487,19 +487,19 @@ class EventStateManager : public nsSuppo
    *                                document and window).
    * @param aOverrideClickTarget    Preferred click event target.  If this is
    *                                not nullptr, aMouseUpContent and
    *                                aCurrentTarget are ignored.
    */
   MOZ_CAN_RUN_SCRIPT
   static nsresult InitAndDispatchClickEvent(
       WidgetMouseEvent* aMouseUpEvent, nsEventStatus* aStatus,
-      EventMessage aMessage, nsIPresShell* aPresShell,
-      nsIContent* aMouseUpContent, AutoWeakFrame aCurrentTarget,
-      bool aNoContentDispatch, nsIContent* aOverrideClickTarget);
+      EventMessage aMessage, PresShell* aPresShell, nsIContent* aMouseUpContent,
+      AutoWeakFrame aCurrentTarget, bool aNoContentDispatch,
+      nsIContent* aOverrideClickTarget);
 
   nsresult SetClickCount(WidgetMouseEvent* aEvent, nsEventStatus* aStatus,
                          nsIContent* aOverrideClickTarget = nullptr);
 
   /**
    * EventCausesClickEvents() returns true when aMouseEvent is an eMouseUp
    * event and it should cause eMouseClick, eMouseDoubleClick and/or
    * eMouseAuxClick events.  Note that this method assumes that
@@ -540,17 +540,17 @@ class EventStateManager : public nsSuppo
    *                                consumed, returns
    *                                nsEventStatus_eConsumeNoDefault.
    * @param aMouseUpContent         The event target of aMouseUpEvent.
    * @param aOverrideClickTarget    Preferred click event target.  If this is
    *                                not nullptr, aMouseUpContent and
    *                                current target frame of the ESM are ignored.
    */
   MOZ_CAN_RUN_SCRIPT
-  nsresult DispatchClickEvents(nsIPresShell* aPresShell,
+  nsresult DispatchClickEvents(PresShell* aPresShell,
                                WidgetMouseEvent* aMouseUpEvent,
                                nsEventStatus* aStatus,
                                nsIContent* aMouseUpContent,
                                nsIContent* aOverrideClickTarget);
 
   void EnsureDocument(nsPresContext* aPresContext);
   MOZ_CAN_RUN_SCRIPT_BOUNDARY
   void FlushPendingEvents(nsPresContext* aPresContext);
--- a/dom/html/HTMLButtonElement.cpp
+++ b/dom/html/HTMLButtonElement.cpp
@@ -253,17 +253,17 @@ nsresult HTMLButtonElement::PostHandleEv
       if (mForm &&
           (mType == NS_FORM_BUTTON_SUBMIT || mType == NS_FORM_BUTTON_RESET)) {
         InternalFormEvent event(
             true, (mType == NS_FORM_BUTTON_RESET) ? eFormReset : eFormSubmit);
         event.mOriginator = this;
         nsEventStatus status = nsEventStatus_eIgnore;
 
         RefPtr<PresShell> presShell = aVisitor.mPresContext->GetPresShell();
-        // If |nsIPresShell::Destroy| has been called due to
+        // If |PresShell::Destroy| has been called due to
         // handling the event, the pres context will return
         // a null pres shell.  See bug 125624.
         //
         // Using presShell to dispatch the event. It makes sure that
         // event is not handled if the window is being destroyed.
         if (presShell && (event.mMessage != eFormSubmit ||
                           mForm->SubmissionCanProceed(this))) {
           // TODO: removing this code and have the submit event sent by the form
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -2849,41 +2849,41 @@ HTMLInputElement* HTMLInputElement::GetS
 }
 
 nsresult HTMLInputElement::MaybeSubmitForm(nsPresContext* aPresContext) {
   if (!mForm) {
     // Nothing to do here.
     return NS_OK;
   }
 
-  nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
-  if (!shell) {
+  RefPtr<PresShell> presShell = aPresContext->GetPresShell();
+  if (!presShell) {
     return NS_OK;
   }
 
   // Get the default submit element
   nsIFormControl* submitControl = mForm->GetDefaultSubmitElement();
   if (submitControl) {
     nsCOMPtr<nsIContent> submitContent = do_QueryInterface(submitControl);
     NS_ASSERTION(submitContent, "Form control not implementing nsIContent?!");
     // Fire the button's onclick handler and let the button handle
     // submitting the form.
     WidgetMouseEvent event(true, eMouseClick, nullptr, WidgetMouseEvent::eReal);
     nsEventStatus status = nsEventStatus_eIgnore;
-    shell->HandleDOMEventWithTarget(submitContent, &event, &status);
+    presShell->HandleDOMEventWithTarget(submitContent, &event, &status);
   } else if (!mForm->ImplicitSubmissionIsDisabled() &&
              mForm->SubmissionCanProceed(nullptr)) {
     // TODO: removing this code and have the submit event sent by the form,
     // bug 592124.
     // If there's only one text control, just submit the form
     // Hold strong ref across the event
     RefPtr<mozilla::dom::HTMLFormElement> form = mForm;
     InternalFormEvent event(true, eFormSubmit);
     nsEventStatus status = nsEventStatus_eIgnore;
-    shell->HandleDOMEventWithTarget(form, &event, &status);
+    presShell->HandleDOMEventWithTarget(form, &event, &status);
   }
 
   return NS_OK;
 }
 
 void HTMLInputElement::SetCheckedInternal(bool aChecked, bool aNotify) {
   // Set the value
   mChecked = aChecked;
@@ -3705,21 +3705,20 @@ nsresult HTMLInputElement::PostHandleEve
     WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
     if (mouseEvent && mouseEvent->IsLeftClickEvent() &&
         !ShouldPreventDOMActivateDispatch(aVisitor.mEvent->mOriginalTarget)) {
       // DOMActive event should be trusted since the activation is actually
       // occurred even if the cause is an untrusted click event.
       InternalUIEvent actEvent(true, eLegacyDOMActivate, mouseEvent);
       actEvent.mDetail = 1;
 
-      nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell();
-      if (shell) {
+      if (RefPtr<PresShell> presShell = aVisitor.mPresContext->GetPresShell()) {
         nsEventStatus status = nsEventStatus_eIgnore;
         mInInternalActivate = true;
-        rv = shell->HandleDOMEventWithTarget(this, &actEvent, &status);
+        rv = presShell->HandleDOMEventWithTarget(this, &actEvent, &status);
         mInInternalActivate = false;
 
         // If activate is cancelled, we must do the same as when click is
         // cancelled (revert the checkbox to its original value).
         if (status == nsEventStatus_eConsumeNoDefault) {
           aVisitor.mEventStatus = status;
         }
       }
@@ -4114,20 +4113,20 @@ nsresult HTMLInputElement::PostHandleEve
           case NS_FORM_INPUT_IMAGE:
             if (mForm) {
               InternalFormEvent event(true, (mType == NS_FORM_INPUT_RESET)
                                                 ? eFormReset
                                                 : eFormSubmit);
               event.mOriginator = this;
               nsEventStatus status = nsEventStatus_eIgnore;
 
-              nsCOMPtr<nsIPresShell> presShell =
+              RefPtr<PresShell> presShell =
                   aVisitor.mPresContext->GetPresShell();
 
-              // If |nsIPresShell::Destroy| has been called due to
+              // If |PresShell::Destroy| has been called due to
               // handling the event the pres context will return a null
               // pres shell.  See bug 125624.
               // TODO: removing this code and have the submit event sent by the
               // form, see bug 592124.
               if (presShell && (event.mMessage != eFormSubmit ||
                                 mForm->SubmissionCanProceed(this))) {
                 // Hold a strong ref while dispatching
                 RefPtr<mozilla::dom::HTMLFormElement> form(mForm);
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -465,87 +465,95 @@ nsresult nsTextInputSelectionImpl::Repai
   if (!mFrameSelection) return NS_ERROR_FAILURE;
 
   RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
   return frameSelection->RepaintSelection(aSelectionType);
 }
 
 NS_IMETHODIMP
 nsTextInputSelectionImpl::SetCaretEnabled(bool enabled) {
-  if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
-
-  nsCOMPtr<nsIPresShell> shell = do_QueryReferent(mPresShellWeak);
-  if (!shell) return NS_ERROR_FAILURE;
+  if (!mPresShellWeak) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+  RefPtr<PresShell> presShell = do_QueryReferent(mPresShellWeak);
+  if (!presShell) {
+    return NS_ERROR_FAILURE;
+  }
 
   // tell the pres shell to enable the caret, rather than settings its
   // visibility directly. this way the presShell's idea of caret visibility is
   // maintained.
-  nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(shell);
-  if (!selCon) return NS_ERROR_NO_INTERFACE;
-  selCon->SetCaretEnabled(enabled);
+  presShell->SetCaretEnabled(enabled);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTextInputSelectionImpl::SetCaretReadOnly(bool aReadOnly) {
-  if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
-  nsresult result;
-  nsCOMPtr<nsIPresShell> shell = do_QueryReferent(mPresShellWeak, &result);
-  if (shell) {
-    RefPtr<nsCaret> caret = shell->GetCaret();
-    if (caret) {
-      Selection* selection =
-          mFrameSelection->GetSelection(SelectionType::eNormal);
-      if (selection) {
-        caret->SetCaretReadOnly(aReadOnly);
-      }
-      return NS_OK;
-    }
+  if (!mPresShellWeak) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+  nsresult rv;
+  RefPtr<PresShell> presShell = do_QueryReferent(mPresShellWeak, &rv);
+  if (!presShell) {
+    return NS_ERROR_FAILURE;
   }
-  return NS_ERROR_FAILURE;
+  RefPtr<nsCaret> caret = presShell->GetCaret();
+  if (!caret) {
+    return NS_ERROR_FAILURE;
+  }
+  Selection* selection = mFrameSelection->GetSelection(SelectionType::eNormal);
+  if (selection) {
+    caret->SetCaretReadOnly(aReadOnly);
+  }
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTextInputSelectionImpl::GetCaretEnabled(bool* _retval) {
   return GetCaretVisible(_retval);
 }
 
 NS_IMETHODIMP
 nsTextInputSelectionImpl::GetCaretVisible(bool* _retval) {
-  if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
-  nsresult result;
-  nsCOMPtr<nsIPresShell> shell = do_QueryReferent(mPresShellWeak, &result);
-  if (shell) {
-    RefPtr<nsCaret> caret = shell->GetCaret();
-    if (caret) {
-      *_retval = caret->IsVisible();
-      return NS_OK;
-    }
+  if (!mPresShellWeak) {
+    return NS_ERROR_NOT_INITIALIZED;
   }
-  return NS_ERROR_FAILURE;
+  nsresult rv;
+  RefPtr<PresShell> presShell = do_QueryReferent(mPresShellWeak, &rv);
+  if (!presShell) {
+    return NS_ERROR_FAILURE;
+  }
+  RefPtr<nsCaret> caret = presShell->GetCaret();
+  if (!caret) {
+    return NS_ERROR_FAILURE;
+  }
+  *_retval = caret->IsVisible();
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTextInputSelectionImpl::SetCaretVisibilityDuringSelection(bool aVisibility) {
-  if (!mPresShellWeak) return NS_ERROR_NOT_INITIALIZED;
-  nsresult result;
-  nsCOMPtr<nsIPresShell> shell = do_QueryReferent(mPresShellWeak, &result);
-  if (shell) {
-    RefPtr<nsCaret> caret = shell->GetCaret();
-    if (caret) {
-      Selection* selection =
-          mFrameSelection->GetSelection(SelectionType::eNormal);
-      if (selection) {
-        caret->SetVisibilityDuringSelection(aVisibility);
-      }
-      return NS_OK;
-    }
+  if (!mPresShellWeak) {
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+  nsresult rv;
+  RefPtr<PresShell> presShell = do_QueryReferent(mPresShellWeak, &rv);
+  if (!presShell) {
+    return NS_ERROR_FAILURE;
   }
-  return NS_ERROR_FAILURE;
+  RefPtr<nsCaret> caret = presShell->GetCaret();
+  if (!caret) {
+    return NS_ERROR_FAILURE;
+  }
+  Selection* selection = mFrameSelection->GetSelection(SelectionType::eNormal);
+  if (selection) {
+    caret->SetVisibilityDuringSelection(aVisibility);
+  }
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTextInputSelectionImpl::PhysicalMove(int16_t aDirection, int16_t aAmount,
                                        bool aExtend) {
   if (mFrameSelection) {
     RefPtr<nsFrameSelection> frameSelection = mFrameSelection;
     return frameSelection->PhysicalMove(aDirection, aAmount, aExtend);
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -936,17 +936,17 @@ interface nsIDOMWindowUtils : nsISupport
    * Get the current zoom factor.
    * This is _approximately_ the same as nsIContentViewer.fullZoom,
    * but takes into account Gecko's quantization of the zoom factor, which is
    * implemented by adjusting the (integer) number of appUnits per devPixel.
    */
   readonly attribute float fullZoom;
 
   /**
-   * Dispatches aEvent as a trusted event via the nsIPresShell object of the
+   * Dispatches aEvent as a trusted event via the PresShell object of the
    * window's document.
    * The event is dispatched to aTarget, which should be an object
    * which implements nsIContent interface (#element, #text, etc).
    *
    * Cannot be accessed from unprivileged context (not
    * content-accessible) Will throw a DOM security error if called
    * without chrome privileges.
    *
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -98,16 +98,17 @@
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/media/MediaParent.h"
 #include "mozilla/Move.h"
 #include "mozilla/net/NeckoParent.h"
 #include "mozilla/net/CookieServiceParent.h"
 #include "mozilla/net/PCookieServiceParent.h"
 #include "mozilla/plugins/PluginBridge.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/PresShell.h"
 #include "mozilla/ProcessHangMonitor.h"
 #include "mozilla/ProcessHangMonitorIPC.h"
 #include "mozilla/RDDProcessManager.h"
 #include "mozilla/recordreplay/ParentIPC.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/ScriptPreloader.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
@@ -153,17 +154,16 @@
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsILocalStorageManager.h"
 #include "nsIMemoryInfoDumper.h"
 #include "nsIMemoryReporter.h"
 #include "nsIMozBrowserFrame.h"
 #include "nsIMutable.h"
 #include "nsIObserverService.h"
 #include "nsIParentChannel.h"
-#include "nsIPresShell.h"
 #include "nsIRemoteWindowContext.h"
 #include "nsIScriptError.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISearchService.h"
 #include "nsIServiceWorkerManager.h"
 #include "nsISiteSecurityService.h"
 #include "nsISound.h"
 #include "mozilla/mozSpellChecker.h"
@@ -1276,29 +1276,29 @@ void ContentParent::Init() {
     cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
     obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-created",
                          cpId.get());
   }
 
 #ifdef ACCESSIBILITY
   // If accessibility is running in chrome process then start it in content
   // process.
-  if (nsIPresShell::IsAccessibilityActive()) {
+  if (PresShell::IsAccessibilityActive()) {
 #  if defined(XP_WIN)
     // Don't init content a11y if we detect an incompat version of JAWS in use.
     if (!mozilla::a11y::Compatibility::IsOldJAWS()) {
       Unused << SendActivateA11y(
           ::GetCurrentThreadId(),
           a11y::AccessibleWrap::GetContentProcessIdFor(ChildID()));
     }
 #  else
     Unused << SendActivateA11y(0, 0);
 #  endif
   }
-#endif
+#endif  // #ifdef ACCESSIBILITY
 
 #ifdef MOZ_GECKO_PROFILER
   Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
 #endif
 
   // Ensure that the default set of permissions are avaliable in the content
   // process before we try to load any URIs in it.
   EnsurePermissionsByKey(EmptyCString());
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -3132,32 +3132,32 @@ NS_IMETHODIMP
 nsPluginInstanceOwner::GetContentsScaleFactor(double* result) {
   NS_ENSURE_ARG_POINTER(result);
   double scaleFactor = 1.0;
   // On Mac, device pixels need to be translated to (and from) "display pixels"
   // for plugins. On other platforms, plugin coordinates are always in device
   // pixels.
 #if defined(XP_MACOSX) || defined(XP_WIN)
   nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
-  nsIPresShell* presShell =
+  PresShell* presShell =
       nsContentUtils::FindPresShellForDocument(content->OwnerDoc());
   if (presShell) {
     scaleFactor = double(AppUnitsPerCSSPixel()) /
                   presShell->GetPresContext()
                       ->DeviceContext()
                       ->AppUnitsPerDevPixelAtUnitFullZoom();
   }
 #endif
   *result = scaleFactor;
   return NS_OK;
 }
 
 void nsPluginInstanceOwner::GetCSSZoomFactor(float* result) {
   nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
-  nsIPresShell* presShell =
+  PresShell* presShell =
       nsContentUtils::FindPresShellForDocument(content->OwnerDoc());
   if (presShell) {
     *result = presShell->GetPresContext()->DeviceContext()->GetFullZoom();
   } else {
     *result = 1.0;
   }
 }
 
--- a/dom/smil/SMILAnimationController.cpp
+++ b/dom/smil/SMILAnimationController.cpp
@@ -5,25 +5,25 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SMILAnimationController.h"
 
 #include <algorithm>
 
 #include "mozilla/AutoRestore.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/RestyleManager.h"
 #include "mozilla/SMILTimedElement.h"
 #include "mozilla/dom/DocumentInlines.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/SVGAnimationElement.h"
 #include "nsContentUtils.h"
 #include "nsCSSProps.h"
 #include "mozilla/dom/Document.h"
-#include "nsIPresShellInlines.h"
 #include "nsITimer.h"
 #include "SMILCompositor.h"
 #include "SMILCSSProperty.h"
 
 using namespace mozilla::dom;
 
 namespace mozilla {
 
--- a/dom/smil/SMILCSSValueType.cpp
+++ b/dom/smil/SMILCSSValueType.cpp
@@ -11,18 +11,19 @@
 #include "nsComputedDOMStyle.h"
 #include "nsColor.h"
 #include "nsCSSProps.h"
 #include "nsCSSValue.h"
 #include "nsDebug.h"
 #include "nsPresContext.h"
 #include "nsString.h"
 #include "nsStyleUtil.h"
-#include "nsIPresShellInlines.h"
 #include "mozilla/DeclarationBlock.h"
+#include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/ServoCSSParser.h"
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/SMILParserUtils.h"
 #include "mozilla/SMILValue.h"
 #include "mozilla/dom/BaseKeyframeTypesBinding.h"
 #include "mozilla/dom/Document.h"
--- a/dom/xbl/nsBindingManager.cpp
+++ b/dom/xbl/nsBindingManager.cpp
@@ -14,17 +14,16 @@
 #include "nsIURL.h"
 #include "nsIChannel.h"
 #include "nsString.h"
 #include "plstr.h"
 #include "nsIContent.h"
 #include "nsIContentInlines.h"
 #include "mozilla/dom/Document.h"
 #include "nsContentUtils.h"
-#include "nsIPresShellInlines.h"
 #include "nsIXMLContentSink.h"
 #include "nsContentCID.h"
 #include "mozilla/dom/XMLDocument.h"
 #include "nsIStreamListener.h"
 #include "ChildIterator.h"
 #include "nsITimer.h"
 
 #include "nsXBLBinding.h"
@@ -46,16 +45,17 @@
 #include "nsIScriptContext.h"
 #include "xpcpublic.h"
 #include "js/Wrapper.h"
 
 #include "nsThreadUtils.h"
 #include "mozilla/dom/NodeListBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/Unused.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 // Implement our nsISupports methods
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsBindingManager)
--- a/dom/xbl/nsXBLPrototypeHandler.h
+++ b/dom/xbl/nsXBLPrototypeHandler.h
@@ -197,16 +197,17 @@ class nsXBLPrototypeHandler {
                          mozilla::dom::Element* aElement,
                          const char* aMessageName);
   void GetEventType(nsAString& type);
   bool ModifiersMatchMask(mozilla::dom::UIEvent* aEvent,
                           const IgnoreModifierState& aIgnoreModifierState);
   MOZ_CAN_RUN_SCRIPT
   nsresult DispatchXBLCommand(mozilla::dom::EventTarget* aTarget,
                               mozilla::dom::Event* aEvent);
+  MOZ_CAN_RUN_SCRIPT
   nsresult DispatchXULKeyCommand(mozilla::dom::Event* aEvent);
   nsresult EnsureEventHandler(mozilla::dom::AutoJSAPI& jsapi, nsAtom* aName,
                               JS::MutableHandle<JSObject*> aHandler);
 
   Modifiers GetModifiers() const;
   Modifiers GetModifiersMask() const;
 
   static int32_t KeyToMask(int32_t key);
--- a/dom/xbl/nsXBLService.cpp
+++ b/dom/xbl/nsXBLService.cpp
@@ -11,17 +11,16 @@
 #include "nsNetUtil.h"
 #include "nsXBLService.h"
 #include "nsXBLWindowKeyHandler.h"
 #include "nsIInputStream.h"
 #include "nsNameSpaceManager.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsIChannel.h"
-#include "nsIPresShellInlines.h"
 #include "nsString.h"
 #include "plstr.h"
 #include "nsIContent.h"
 #include "mozilla/dom/Document.h"
 #include "nsIXMLContentSink.h"
 #include "nsContentCID.h"
 #include "mozilla/dom/XMLDocument.h"
 #include "nsGkAtoms.h"
@@ -46,16 +45,17 @@
 #ifdef MOZ_XUL
 #  include "nsXULPrototypeCache.h"
 #endif
 #include "nsIDOMEventListener.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/RestyleManager.h"
 #include "mozilla/dom/ChildIterator.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -1023,19 +1023,19 @@ nsresult nsXULElement::DispatchXULComman
         event = commandEvent->GetSourceEvent();
         inputSource = commandEvent->InputSource();
       } else {
         event = nullptr;
       }
     }
     WidgetInputEvent* orig = aVisitor.mEvent->AsInputEvent();
     nsContentUtils::DispatchXULCommand(
-        commandElt, orig->IsTrusted(), aVisitor.mDOMEvent, nullptr,
-        orig->IsControl(), orig->IsAlt(), orig->IsShift(), orig->IsMeta(),
-        inputSource);
+        commandElt, orig->IsTrusted(), MOZ_KnownLive(aVisitor.mDOMEvent),
+        nullptr, orig->IsControl(), orig->IsAlt(), orig->IsShift(),
+        orig->IsMeta(), inputSource);
   } else {
     NS_WARNING("A XUL element is attached to a command that doesn't exist!\n");
   }
   return NS_OK;
 }
 
 void nsXULElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
   aVisitor.mForceContentDispatch = true;  // FIXME! Bug 329119
@@ -1185,17 +1185,18 @@ void nsXULElement::ClickWithInputSource(
 
   // oncommand is fired when an element is clicked...
   DoCommand();
 }
 
 void nsXULElement::DoCommand() {
   nsCOMPtr<Document> doc = GetComposedDoc();  // strong just in case
   if (doc) {
-    nsContentUtils::DispatchXULCommand(this, true);
+    RefPtr<nsXULElement> self = this;
+    nsContentUtils::DispatchXULCommand(self, true);
   }
 }
 
 bool nsXULElement::IsNodeOfType(uint32_t aFlags) const { return false; }
 
 nsresult nsXULElement::AddPopupListener(nsAtom* aName) {
   // Add a popup listener to the element
   bool isContext =
--- a/dom/xul/nsXULElement.h
+++ b/dom/xul/nsXULElement.h
@@ -319,16 +319,17 @@ class nsXULElement : public nsStyledElem
   NS_IMPL_FROMNODE(nsXULElement, kNameSpaceID_XUL)
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULElement, nsStyledElement)
 
   // nsINode
   void GetEventTargetParent(mozilla::EventChainPreVisitor& aVisitor) override;
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   virtual nsresult PreHandleEvent(
       mozilla::EventChainVisitor& aVisitor) override;
   // nsIContent
   virtual nsresult BindToTree(Document* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent) override;
   virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
   virtual void DestroyContent() override;
   virtual void DoneAddingChildren(bool aHaveNotified) override;
@@ -510,17 +511,17 @@ class nsXULElement : public nsStyledElem
     SetXULBoolAttr(nsGkAtoms::allowevents, aAllowEvents);
   }
   nsIControllers* GetControllers(mozilla::ErrorResult& rv);
   // Note: this can only fail if the do_CreateInstance for the boxobject
   // contact fails for some reason.
   already_AddRefed<mozilla::dom::BoxObject> GetBoxObject(
       mozilla::ErrorResult& rv);
   void Click(mozilla::dom::CallerType aCallerType);
-  void DoCommand();
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY void DoCommand();
   // Style() inherited from nsStyledElement
 
   nsINode* GetScopeChainParent() const override {
     // For XUL, the parent is the parent element, if any
     Element* parent = GetParentElement();
     return parent ? parent : nsStyledElement::GetScopeChainParent();
   }
 
@@ -619,13 +620,14 @@ class nsXULElement : public nsStyledElem
 
   virtual JSObject* WrapNode(JSContext* aCx,
                              JS::Handle<JSObject*> aGivenProto) override;
 
   void MaybeUpdatePrivateLifetime();
 
   bool IsEventStoppedFromAnonymousScrollbar(mozilla::EventMessage aMessage);
 
+  MOZ_CAN_RUN_SCRIPT
   nsresult DispatchXULCommand(const mozilla::EventChainVisitor& aVisitor,
                               nsAutoString& aCommand);
 };
 
 #endif  // nsXULElement_h__
--- a/editor/libeditor/EditorCommands.cpp
+++ b/editor/libeditor/EditorCommands.cpp
@@ -36,31 +36,33 @@ NS_IMETHODIMP
 EditorCommand::IsCommandEnabled(const char* aCommandName,
                                 nsISupports* aCommandRefCon, bool* aIsEnabled) {
   if (NS_WARN_IF(!aCommandName) || NS_WARN_IF(!aIsEnabled)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   nsCOMPtr<nsIEditor> editor = do_QueryInterface(aCommandRefCon);
   TextEditor* textEditor = editor ? editor->AsTextEditor() : nullptr;
-  *aIsEnabled = IsCommandEnabled(aCommandName, MOZ_KnownLive(textEditor));
+  *aIsEnabled = IsCommandEnabled(GetInternalCommand(aCommandName),
+                                 MOZ_KnownLive(textEditor));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 EditorCommand::DoCommand(const char* aCommandName,
                          nsISupports* aCommandRefCon) {
   if (NS_WARN_IF(!aCommandName) || NS_WARN_IF(!aCommandRefCon)) {
     return NS_ERROR_INVALID_ARG;
   }
   nsCOMPtr<nsIEditor> editor = do_QueryInterface(aCommandRefCon);
   if (NS_WARN_IF(!editor)) {
     return NS_ERROR_INVALID_ARG;
   }
-  nsresult rv = DoCommand(aCommandName, MOZ_KnownLive(*editor->AsTextEditor()));
+  nsresult rv = DoCommand(GetInternalCommand(aCommandName),
+                          MOZ_KnownLive(*editor->AsTextEditor()));
   NS_WARNING_ASSERTION(
       NS_SUCCEEDED(rv),
       "Failed to do command from nsIControllerCommand::DoCommand()");
   return rv;
 }
 
 NS_IMETHODIMP
 EditorCommand::DoCommandParams(const char* aCommandName,
@@ -68,316 +70,323 @@ EditorCommand::DoCommandParams(const cha
                                nsISupports* aCommandRefCon) {
   if (NS_WARN_IF(!aCommandName) || NS_WARN_IF(!aCommandRefCon)) {
     return NS_ERROR_INVALID_ARG;
   }
   nsCOMPtr<nsIEditor> editor = do_QueryInterface(aCommandRefCon);
   if (NS_WARN_IF(!editor)) {
     return NS_ERROR_INVALID_ARG;
   }
-  nsresult rv =
-      DoCommandParams(aCommandName, MOZ_KnownLive(aParams->AsCommandParams()),
-                      MOZ_KnownLive(*editor->AsTextEditor()));
+  Command command;
+  nsCommandParams* params = aParams->AsCommandParams();
+  if (params) {
+    nsAutoString value;
+    params->GetString(aCommandName, value);
+    command = GetInternalCommand(aCommandName, value);
+  } else {
+    command = GetInternalCommand(aCommandName);
+  }
+  nsresult rv = DoCommandParams(command, MOZ_KnownLive(params),
+                                MOZ_KnownLive(*editor->AsTextEditor()));
   NS_WARNING_ASSERTION(
       NS_SUCCEEDED(rv),
       "Failed to do command from nsIControllerCommand::DoCommandParams()");
   return rv;
 }
 
 NS_IMETHODIMP
 EditorCommand::GetCommandStateParams(const char* aCommandName,
                                      nsICommandParams* aParams,
                                      nsISupports* aCommandRefCon) {
   if (NS_WARN_IF(!aCommandName) || NS_WARN_IF(!aParams)) {
     return NS_ERROR_INVALID_ARG;
   }
   nsCOMPtr<nsIEditor> editor = do_QueryInterface(aCommandRefCon);
   if (editor) {
-    return GetCommandStateParams(
-        aCommandName, MOZ_KnownLive(*aParams->AsCommandParams()),
-        MOZ_KnownLive(editor->AsTextEditor()), nullptr);
+    return GetCommandStateParams(GetInternalCommand(aCommandName),
+                                 MOZ_KnownLive(*aParams->AsCommandParams()),
+                                 MOZ_KnownLive(editor->AsTextEditor()),
+                                 nullptr);
   }
   nsCOMPtr<nsIEditingSession> editingSession =
       do_QueryInterface(aCommandRefCon);
   if (editingSession) {
-    return GetCommandStateParams(aCommandName,
+    return GetCommandStateParams(GetInternalCommand(aCommandName),
                                  MOZ_KnownLive(*aParams->AsCommandParams()),
                                  nullptr, editingSession);
   }
-  return GetCommandStateParams(aCommandName,
+  return GetCommandStateParams(GetInternalCommand(aCommandName),
                                MOZ_KnownLive(*aParams->AsCommandParams()),
                                nullptr, nullptr);
 }
 
 /******************************************************************************
  * mozilla::UndoCommand
  ******************************************************************************/
 
 StaticRefPtr<UndoCommand> UndoCommand::sInstance;
 
-bool UndoCommand::IsCommandEnabled(const char* aCommandName,
+bool UndoCommand::IsCommandEnabled(Command aCommand,
                                    TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return aTextEditor->IsSelectionEditable() && aTextEditor->CanUndo();
 }
 
-nsresult UndoCommand::DoCommand(const char* aCommandName,
+nsresult UndoCommand::DoCommand(Command aCommand,
                                 TextEditor& aTextEditor) const {
   return aTextEditor.Undo(1);
 }
 
-nsresult UndoCommand::DoCommandParams(const char* aCommandName,
+nsresult UndoCommand::DoCommandParams(Command aCommand,
                                       nsCommandParams* aParams,
                                       TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult UndoCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /******************************************************************************
  * mozilla::RedoCommand
  ******************************************************************************/
 
 StaticRefPtr<RedoCommand> RedoCommand::sInstance;
 
-bool RedoCommand::IsCommandEnabled(const char* aCommandName,
+bool RedoCommand::IsCommandEnabled(Command aCommand,
                                    TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return aTextEditor->IsSelectionEditable() && aTextEditor->CanRedo();
 }
 
-nsresult RedoCommand::DoCommand(const char* aCommandName,
+nsresult RedoCommand::DoCommand(Command aCommand,
                                 TextEditor& aTextEditor) const {
   return aTextEditor.Redo(1);
 }
 
-nsresult RedoCommand::DoCommandParams(const char* aCommandName,
+nsresult RedoCommand::DoCommandParams(Command aCommand,
                                       nsCommandParams* aParams,
                                       TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult RedoCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /******************************************************************************
  * mozilla::CutCommand
  ******************************************************************************/
 
 StaticRefPtr<CutCommand> CutCommand::sInstance;
 
-bool CutCommand::IsCommandEnabled(const char* aCommandName,
+bool CutCommand::IsCommandEnabled(Command aCommand,
                                   TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return aTextEditor->IsSelectionEditable() && aTextEditor->CanCut();
 }
 
-nsresult CutCommand::DoCommand(const char* aCommandName,
+nsresult CutCommand::DoCommand(Command aCommand,
                                TextEditor& aTextEditor) const {
   return aTextEditor.Cut();
 }
 
-nsresult CutCommand::DoCommandParams(const char* aCommandName,
-                                     nsCommandParams* aParams,
+nsresult CutCommand::DoCommandParams(Command aCommand, nsCommandParams* aParams,
                                      TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult CutCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /******************************************************************************
  * mozilla::CutOrDeleteCommand
  ******************************************************************************/
 
 StaticRefPtr<CutOrDeleteCommand> CutOrDeleteCommand::sInstance;
 
-bool CutOrDeleteCommand::IsCommandEnabled(const char* aCommandName,
+bool CutOrDeleteCommand::IsCommandEnabled(Command aCommand,
                                           TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return aTextEditor->IsSelectionEditable();
 }
 
-nsresult CutOrDeleteCommand::DoCommand(const char* aCommandName,
+nsresult CutOrDeleteCommand::DoCommand(Command aCommand,
                                        TextEditor& aTextEditor) const {
   dom::Selection* selection = aTextEditor.GetSelection();
   if (selection && selection->IsCollapsed()) {
     nsresult rv = aTextEditor.DeleteSelectionAsAction(nsIEditor::eNext,
                                                       nsIEditor::eStrip);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
     return NS_OK;
   }
   return aTextEditor.Cut();
 }
 
-nsresult CutOrDeleteCommand::DoCommandParams(const char* aCommandName,
+nsresult CutOrDeleteCommand::DoCommandParams(Command aCommand,
                                              nsCommandParams* aParams,
                                              TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult CutOrDeleteCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /******************************************************************************
  * mozilla::CopyCommand
  ******************************************************************************/
 
 StaticRefPtr<CopyCommand> CopyCommand::sInstance;
 
-bool CopyCommand::IsCommandEnabled(const char* aCommandName,
+bool CopyCommand::IsCommandEnabled(Command aCommand,
                                    TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return aTextEditor->CanCopy();
 }
 
-nsresult CopyCommand::DoCommand(const char* aCommandName,
+nsresult CopyCommand::DoCommand(Command aCommand,
                                 TextEditor& aTextEditor) const {
   return aTextEditor.Copy();
 }
 
-nsresult CopyCommand::DoCommandParams(const char* aCommandName,
+nsresult CopyCommand::DoCommandParams(Command aCommand,
                                       nsCommandParams* aParams,
                                       TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult CopyCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /******************************************************************************
  * mozilla::CopyOrDeleteCommand
  ******************************************************************************/
 
 StaticRefPtr<CopyOrDeleteCommand> CopyOrDeleteCommand::sInstance;
 
-bool CopyOrDeleteCommand::IsCommandEnabled(const char* aCommandName,
+bool CopyOrDeleteCommand::IsCommandEnabled(Command aCommand,
                                            TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return aTextEditor->IsSelectionEditable();
 }
 
-nsresult CopyOrDeleteCommand::DoCommand(const char* aCommandName,
+nsresult CopyOrDeleteCommand::DoCommand(Command aCommand,
                                         TextEditor& aTextEditor) const {
   dom::Selection* selection = aTextEditor.GetSelection();
   if (selection && selection->IsCollapsed()) {
     nsresult rv = aTextEditor.DeleteSelectionAsAction(nsIEditor::eNextWord,
                                                       nsIEditor::eStrip);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
     return NS_OK;
   }
   return aTextEditor.Copy();
 }
 
-nsresult CopyOrDeleteCommand::DoCommandParams(const char* aCommandName,
+nsresult CopyOrDeleteCommand::DoCommandParams(Command aCommand,
                                               nsCommandParams* aParams,
                                               TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult CopyOrDeleteCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /******************************************************************************
  * mozilla::PasteCommand
  ******************************************************************************/
 
 StaticRefPtr<PasteCommand> PasteCommand::sInstance;
 
-bool PasteCommand::IsCommandEnabled(const char* aCommandName,
+bool PasteCommand::IsCommandEnabled(Command aCommand,
                                     TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return aTextEditor->IsSelectionEditable() &&
          aTextEditor->CanPaste(nsIClipboard::kGlobalClipboard);
 }
 
-nsresult PasteCommand::DoCommand(const char* aCommandName,
+nsresult PasteCommand::DoCommand(Command aCommand,
                                  TextEditor& aTextEditor) const {
   return aTextEditor.PasteAsAction(nsIClipboard::kGlobalClipboard, true);
 }
 
-nsresult PasteCommand::DoCommandParams(const char* aCommandName,
+nsresult PasteCommand::DoCommandParams(Command aCommand,
                                        nsCommandParams* aParams,
                                        TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult PasteCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /******************************************************************************
  * mozilla::PasteTransferableCommand
  ******************************************************************************/
 
 StaticRefPtr<PasteTransferableCommand> PasteTransferableCommand::sInstance;
 
-bool PasteTransferableCommand::IsCommandEnabled(const char* aCommandName,
+bool PasteTransferableCommand::IsCommandEnabled(Command aCommand,
                                                 TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return aTextEditor->IsSelectionEditable() &&
          aTextEditor->CanPasteTransferable(nullptr);
 }
 
-nsresult PasteTransferableCommand::DoCommand(const char* aCommandName,
+nsresult PasteTransferableCommand::DoCommand(Command aCommand,
                                              TextEditor& aTextEditor) const {
   return NS_ERROR_FAILURE;
 }
 
 nsresult PasteTransferableCommand::DoCommandParams(
-    const char* aCommandName, nsCommandParams* aParams,
-    TextEditor& aTextEditor) const {
+    Command aCommand, nsCommandParams* aParams, TextEditor& aTextEditor) const {
   if (NS_WARN_IF(!aParams)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   nsCOMPtr<nsISupports> supports = aParams->GetISupports("transferable");
   if (NS_WARN_IF(!supports)) {
     return NS_ERROR_FAILURE;
   }
@@ -392,17 +401,17 @@ nsresult PasteTransferableCommand::DoCom
   nsresult rv = aTextEditor.PasteTransferable(trans);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   return NS_OK;
 }
 
 nsresult PasteTransferableCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   if (NS_WARN_IF(!aTextEditor)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   nsCOMPtr<nsISupports> supports = aParams.GetISupports("transferable");
   if (NS_WARN_IF(!supports)) {
     return NS_ERROR_FAILURE;
@@ -420,209 +429,221 @@ nsresult PasteTransferableCommand::GetCo
 
 /******************************************************************************
  * mozilla::SwitchTextDirectionCommand
  ******************************************************************************/
 
 StaticRefPtr<SwitchTextDirectionCommand> SwitchTextDirectionCommand::sInstance;
 
 bool SwitchTextDirectionCommand::IsCommandEnabled(
-    const char* aCommandName, TextEditor* aTextEditor) const {
+    Command aCommand, TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return aTextEditor->IsSelectionEditable();
 }
 
-nsresult SwitchTextDirectionCommand::DoCommand(const char* aCommandName,
+nsresult SwitchTextDirectionCommand::DoCommand(Command aCommand,
                                                TextEditor& aTextEditor) const {
   return aTextEditor.ToggleTextDirection();
 }
 
 nsresult SwitchTextDirectionCommand::DoCommandParams(
-    const char* aCommandName, nsCommandParams* aParams,
-    TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+    Command aCommand, nsCommandParams* aParams, TextEditor& aTextEditor) const {
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult SwitchTextDirectionCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /******************************************************************************
  * mozilla::DeleteCommand
  ******************************************************************************/
 
 StaticRefPtr<DeleteCommand> DeleteCommand::sInstance;
 
-bool DeleteCommand::IsCommandEnabled(const char* aCommandName,
+bool DeleteCommand::IsCommandEnabled(Command aCommand,
                                      TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   // We can generally delete whenever the selection is editable.  However,
   // cmd_delete doesn't make sense if the selection is collapsed because it's
   // directionless, which is the same condition under which we can't cut.
   bool isEnabled = aTextEditor->IsSelectionEditable();
 
-  if (!nsCRT::strcmp("cmd_delete", aCommandName) && isEnabled) {
+  if (aCommand == Command::Delete && isEnabled) {
     return aTextEditor->CanDelete();
   }
   return isEnabled;
 }
 
-nsresult DeleteCommand::DoCommand(const char* aCommandName,
+nsresult DeleteCommand::DoCommand(Command aCommand,
                                   TextEditor& aTextEditor) const {
   nsIEditor::EDirection deleteDir = nsIEditor::eNone;
-  if (!strcmp("cmd_delete", aCommandName)) {
-    // Really this should probably be eNone, but it only makes a difference if
-    // the selection is collapsed, and then this command is disabled.  So let's
-    // keep it as it always was to avoid breaking things.
-    deleteDir = nsIEditor::ePrevious;
-  } else if (!strcmp("cmd_deleteCharForward", aCommandName)) {
-    deleteDir = nsIEditor::eNext;
-  } else if (!strcmp("cmd_deleteCharBackward", aCommandName)) {
-    deleteDir = nsIEditor::ePrevious;
-  } else if (!strcmp("cmd_deleteWordBackward", aCommandName)) {
-    deleteDir = nsIEditor::ePreviousWord;
-  } else if (!strcmp("cmd_deleteWordForward", aCommandName)) {
-    deleteDir = nsIEditor::eNextWord;
-  } else if (!strcmp("cmd_deleteToBeginningOfLine", aCommandName)) {
-    deleteDir = nsIEditor::eToBeginningOfLine;
-  } else if (!strcmp("cmd_deleteToEndOfLine", aCommandName)) {
-    deleteDir = nsIEditor::eToEndOfLine;
-  } else {
-    MOZ_CRASH("Unrecognized nsDeleteCommand");
+  switch (aCommand) {
+    case Command::Delete:
+      // Really this should probably be eNone, but it only makes a difference
+      // if the selection is collapsed, and then this command is disabled.  So
+      // let's keep it as it always was to avoid breaking things.
+      deleteDir = nsIEditor::ePrevious;
+      break;
+    case Command::DeleteCharForward:
+      deleteDir = nsIEditor::eNext;
+      break;
+    case Command::DeleteCharBackward:
+      deleteDir = nsIEditor::ePrevious;
+      break;
+    case Command::DeleteWordBackward:
+      deleteDir = nsIEditor::ePreviousWord;
+      break;
+    case Command::DeleteWordForward:
+      deleteDir = nsIEditor::eNextWord;
+      break;
+    case Command::DeleteToBeginningOfLine:
+      deleteDir = nsIEditor::eToBeginningOfLine;
+      break;
+    case Command::DeleteToEndOfLine:
+      deleteDir = nsIEditor::eToEndOfLine;
+      break;
+    default:
+      MOZ_CRASH("Unrecognized nsDeleteCommand");
   }
   nsresult rv =
       aTextEditor.DeleteSelectionAsAction(deleteDir, nsIEditor::eStrip);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   return NS_OK;
 }
 
-nsresult DeleteCommand::DoCommandParams(const char* aCommandName,
+nsresult DeleteCommand::DoCommandParams(Command aCommand,
                                         nsCommandParams* aParams,
                                         TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult DeleteCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /******************************************************************************
  * mozilla::SelectAllCommand
  ******************************************************************************/
 
 StaticRefPtr<SelectAllCommand> SelectAllCommand::sInstance;
 
-bool SelectAllCommand::IsCommandEnabled(const char* aCommandName,
+bool SelectAllCommand::IsCommandEnabled(Command aCommand,
                                         TextEditor* aTextEditor) const {
   // You can always select all, unless the selection is editable,
   // and the editable region is empty!
   if (!aTextEditor) {
     return true;
   }
 
   // You can select all if there is an editor which is non-empty
   bool isEmpty = false;
   if (NS_WARN_IF(NS_FAILED(aTextEditor->IsEmpty(&isEmpty)))) {
     return false;
   }
   return !isEmpty;
 }
 
-nsresult SelectAllCommand::DoCommand(const char* aCommandName,
+nsresult SelectAllCommand::DoCommand(Command aCommand,
                                      TextEditor& aTextEditor) const {
   return aTextEditor.SelectAll();
 }
 
-nsresult SelectAllCommand::DoCommandParams(const char* aCommandName,
+nsresult SelectAllCommand::DoCommandParams(Command aCommand,
                                            nsCommandParams* aParams,
                                            TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult SelectAllCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /******************************************************************************
  * mozilla::SelectionMoveCommands
  ******************************************************************************/
 
 StaticRefPtr<SelectionMoveCommands> SelectionMoveCommands::sInstance;
 
-bool SelectionMoveCommands::IsCommandEnabled(const char* aCommandName,
+bool SelectionMoveCommands::IsCommandEnabled(Command aCommand,
                                              TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return aTextEditor->IsSelectionEditable();
 }
 
 static const struct ScrollCommand {
-  const char* reverseScroll;
-  const char* forwardScroll;
+  Command mReverseScroll;
+  Command mForwardScroll;
   nsresult (NS_STDCALL nsISelectionController::*scroll)(bool);
-} scrollCommands[] = {{"cmd_scrollTop", "cmd_scrollBottom",
+} scrollCommands[] = {{Command::ScrollTop, Command::ScrollBottom,
                        &nsISelectionController::CompleteScroll},
-                      {"cmd_scrollPageUp", "cmd_scrollPageDown",
+                      {Command::ScrollPageUp, Command::ScrollPageDown,
                        &nsISelectionController::ScrollPage},
-                      {"cmd_scrollLineUp", "cmd_scrollLineDown",
+                      {Command::ScrollLineUp, Command::ScrollLineDown,
                        &nsISelectionController::ScrollLine}};
 
 static const struct MoveCommand {
-  const char* reverseMove;
-  const char* forwardMove;
-  const char* reverseSelect;
-  const char* forwardSelect;
+  Command mReverseMove;
+  Command mForwardMove;
+  Command mReverseSelect;
+  Command mForwardSelect;
   nsresult (NS_STDCALL nsISelectionController::*move)(bool, bool);
 } moveCommands[] = {
-    {"cmd_charPrevious", "cmd_charNext", "cmd_selectCharPrevious",
-     "cmd_selectCharNext", &nsISelectionController::CharacterMove},
-    {"cmd_linePrevious", "cmd_lineNext", "cmd_selectLinePrevious",
-     "cmd_selectLineNext", &nsISelectionController::LineMove},
-    {"cmd_wordPrevious", "cmd_wordNext", "cmd_selectWordPrevious",
-     "cmd_selectWordNext", &nsISelectionController::WordMove},
-    {"cmd_beginLine", "cmd_endLine", "cmd_selectBeginLine", "cmd_selectEndLine",
-     &nsISelectionController::IntraLineMove},
-    {"cmd_movePageUp", "cmd_movePageDown", "cmd_selectPageUp",
-     "cmd_selectPageDown", &nsISelectionController::PageMove},
-    {"cmd_moveTop", "cmd_moveBottom", "cmd_selectTop", "cmd_selectBottom",
-     &nsISelectionController::CompleteMove}};
+    {Command::CharPrevious, Command::CharNext, Command::SelectCharPrevious,
+     Command::SelectCharNext, &nsISelectionController::CharacterMove},
+    {Command::LinePrevious, Command::LineNext, Command::SelectLinePrevious,
+     Command::SelectLineNext, &nsISelectionController::LineMove},
+    {Command::WordPrevious, Command::WordNext, Command::SelectWordPrevious,
+     Command::SelectWordNext, &nsISelectionController::WordMove},
+    {Command::BeginLine, Command::EndLine, Command::SelectBeginLine,
+     Command::SelectEndLine, &nsISelectionController::IntraLineMove},
+    {Command::MovePageUp, Command::MovePageDown, Command::SelectPageUp,
+     Command::SelectPageDown, &nsISelectionController::PageMove},
+    {Command::MoveTop, Command::MoveBottom, Command::SelectTop,
+     Command::SelectBottom, &nsISelectionController::CompleteMove}};
 
 static const struct PhysicalCommand {
-  const char* move;
-  const char* select;
+  Command mMove;
+  Command mSelect;
   int16_t direction;
   int16_t amount;
 } physicalCommands[] = {
-    {"cmd_moveLeft", "cmd_selectLeft", nsISelectionController::MOVE_LEFT, 0},
-    {"cmd_moveRight", "cmd_selectRight", nsISelectionController::MOVE_RIGHT, 0},
-    {"cmd_moveUp", "cmd_selectUp", nsISelectionController::MOVE_UP, 0},
-    {"cmd_moveDown", "cmd_selectDown", nsISelectionController::MOVE_DOWN, 0},
-    {"cmd_moveLeft2", "cmd_selectLeft2", nsISelectionController::MOVE_LEFT, 1},
-    {"cmd_moveRight2", "cmd_selectRight2", nsISelectionController::MOVE_RIGHT,
-     1},
-    {"cmd_moveUp2", "cmd_selectUp2", nsISelectionController::MOVE_UP, 1},
-    {"cmd_moveDown2", "cmd_selectDown2", nsISelectionController::MOVE_DOWN, 1}};
+    {Command::MoveLeft, Command::SelectLeft, nsISelectionController::MOVE_LEFT,
+     0},
+    {Command::MoveRight, Command::SelectRight,
+     nsISelectionController::MOVE_RIGHT, 0},
+    {Command::MoveUp, Command::SelectUp, nsISelectionController::MOVE_UP, 0},
+    {Command::MoveDown, Command::SelectDown, nsISelectionController::MOVE_DOWN,
+     0},
+    {Command::MoveLeft2, Command::SelectLeft2,
+     nsISelectionController::MOVE_LEFT, 1},
+    {Command::MoveRight2, Command::SelectRight2,
+     nsISelectionController::MOVE_RIGHT, 1},
+    {Command::MoveUp2, Command::SelectUp2, nsISelectionController::MOVE_UP, 1},
+    {Command::MoveDown2, Command::SelectDown2,
+     nsISelectionController::MOVE_DOWN, 1}};
 
-nsresult SelectionMoveCommands::DoCommand(const char* aCommandName,
+nsresult SelectionMoveCommands::DoCommand(Command aCommand,
                                           TextEditor& aTextEditor) const {
   RefPtr<Document> document = aTextEditor.GetDocument();
   if (document) {
     // Most of the commands below (possibly all of them) need layout to
     // be up to date.
     document->FlushPendingNotifications(FlushType::Layout);
   }
 
@@ -630,94 +651,98 @@ nsresult SelectionMoveCommands::DoComman
       aTextEditor.GetSelectionController();
   if (NS_WARN_IF(!selectionController)) {
     return NS_ERROR_FAILURE;
   }
 
   // scroll commands
   for (size_t i = 0; i < ArrayLength(scrollCommands); i++) {
     const ScrollCommand& cmd = scrollCommands[i];
-    if (!strcmp(aCommandName, cmd.reverseScroll)) {
+    if (aCommand == cmd.mReverseScroll) {
       return (selectionController->*(cmd.scroll))(false);
-    } else if (!strcmp(aCommandName, cmd.forwardScroll)) {
+    }
+    if (aCommand == cmd.mForwardScroll) {
       return (selectionController->*(cmd.scroll))(true);
     }
   }
 
   // caret movement/selection commands
   for (size_t i = 0; i < ArrayLength(moveCommands); i++) {
     const MoveCommand& cmd = moveCommands[i];
-    if (!strcmp(aCommandName, cmd.reverseMove)) {
+    if (aCommand == cmd.mReverseMove) {
       return (selectionController->*(cmd.move))(false, false);
-    } else if (!strcmp(aCommandName, cmd.forwardMove)) {
+    }
+    if (aCommand == cmd.mForwardMove) {
       return (selectionController->*(cmd.move))(true, false);
-    } else if (!strcmp(aCommandName, cmd.reverseSelect)) {
+    }
+    if (aCommand == cmd.mReverseSelect) {
       return (selectionController->*(cmd.move))(false, true);
-    } else if (!strcmp(aCommandName, cmd.forwardSelect)) {
+    }
+    if (aCommand == cmd.mForwardSelect) {
       return (selectionController->*(cmd.move))(true, true);
     }
   }
 
   // physical-direction movement/selection
   for (size_t i = 0; i < ArrayLength(physicalCommands); i++) {
     const PhysicalCommand& cmd = physicalCommands[i];
-    if (!strcmp(aCommandName, cmd.move)) {
+    if (aCommand == cmd.mMove) {
       return selectionController->PhysicalMove(cmd.direction, cmd.amount,
                                                false);
-    } else if (!strcmp(aCommandName, cmd.select)) {
+    }
+    if (aCommand == cmd.mSelect) {
       return selectionController->PhysicalMove(cmd.direction, cmd.amount, true);
     }
   }
 
   return NS_ERROR_FAILURE;
 }
 
-nsresult SelectionMoveCommands::DoCommandParams(const char* aCommandName,
+nsresult SelectionMoveCommands::DoCommandParams(Command aCommand,
                                                 nsCommandParams* aParams,
                                                 TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult SelectionMoveCommands::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /******************************************************************************
  * mozilla::InsertPlaintextCommand
  ******************************************************************************/
 
 StaticRefPtr<InsertPlaintextCommand> InsertPlaintextCommand::sInstance;
 
-bool InsertPlaintextCommand::IsCommandEnabled(const char* aCommandName,
+bool InsertPlaintextCommand::IsCommandEnabled(Command aCommand,
                                               TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return aTextEditor->IsSelectionEditable();
 }
 
-nsresult InsertPlaintextCommand::DoCommand(const char* aCommandName,
+nsresult InsertPlaintextCommand::DoCommand(Command aCommand,
                                            TextEditor& aTextEditor) const {
   // XXX InsertTextAsAction() is not same as OnInputText().  However, other
   //     commands to insert line break or paragraph separator use OnInput*().
   //     According to the semantics of those methods, using *AsAction() is
   //     better, however, this may not cause two or more placeholder
   //     transactions to the top transaction since its name may not be
   //     nsGkAtoms::TypingTxnName.
   DebugOnly<nsresult> rv = aTextEditor.InsertTextAsAction(EmptyString());
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert empty string");
   return NS_OK;
 }
 
 nsresult InsertPlaintextCommand::DoCommandParams(
-    const char* aCommandName, nsCommandParams* aParams,
-    TextEditor& aTextEditor) const {
+    Command aCommand, nsCommandParams* aParams, TextEditor& aTextEditor) const {
   if (NS_WARN_IF(!aParams)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   // Get text to insert from command params
   nsAutoString text;
   nsresult rv = aParams->GetString(STATE_DATA, text);
   if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -731,127 +756,125 @@ nsresult InsertPlaintextCommand::DoComma
   //     transactions to the top transaction since its name may not be
   //     nsGkAtoms::TypingTxnName.
   rv = aTextEditor.InsertTextAsAction(text);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert the text");
   return NS_OK;
 }
 
 nsresult InsertPlaintextCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /******************************************************************************
  * mozilla::InsertParagraphCommand
  ******************************************************************************/
 
 StaticRefPtr<InsertParagraphCommand> InsertParagraphCommand::sInstance;
 
-bool InsertParagraphCommand::IsCommandEnabled(const char* aCommandName,
+bool InsertParagraphCommand::IsCommandEnabled(Command aCommand,
                                               TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return aTextEditor->IsSelectionEditable();
 }
 
-nsresult InsertParagraphCommand::DoCommand(const char* aCommandName,
+nsresult InsertParagraphCommand::DoCommand(Command aCommand,
                                            TextEditor& aTextEditor) const {
   HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
   if (!htmlEditor) {
     return NS_OK;  // Do nothing for now.
   }
   return htmlEditor->InsertParagraphSeparatorAsAction();
 }
 
 nsresult InsertParagraphCommand::DoCommandParams(
-    const char* aCommandName, nsCommandParams* aParams,
-    TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+    Command aCommand, nsCommandParams* aParams, TextEditor& aTextEditor) const {
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult InsertParagraphCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /******************************************************************************
  * mozilla::InsertLineBreakCommand
  ******************************************************************************/
 
 StaticRefPtr<InsertLineBreakCommand> InsertLineBreakCommand::sInstance;
 
-bool InsertLineBreakCommand::IsCommandEnabled(const char* aCommandName,
+bool InsertLineBreakCommand::IsCommandEnabled(Command aCommand,
                                               TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return aTextEditor->IsSelectionEditable();
 }
 
-nsresult InsertLineBreakCommand::DoCommand(const char* aCommandName,
+nsresult InsertLineBreakCommand::DoCommand(Command aCommand,
                                            TextEditor& aTextEditor) const {
   HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
   if (!htmlEditor) {
     return NS_ERROR_FAILURE;
   }
   return htmlEditor->InsertLineBreakAsAction();
 }
 
 nsresult InsertLineBreakCommand::DoCommandParams(
-    const char* aCommandName, nsCommandParams* aParams,
-    TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+    Command aCommand, nsCommandParams* aParams, TextEditor& aTextEditor) const {
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult InsertLineBreakCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /******************************************************************************
  * mozilla::PasteQuotationCommand
  ******************************************************************************/
 
 StaticRefPtr<PasteQuotationCommand> PasteQuotationCommand::sInstance;
 
-bool PasteQuotationCommand::IsCommandEnabled(const char* aCommandName,
+bool PasteQuotationCommand::IsCommandEnabled(Command aCommand,
                                              TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return !aTextEditor->IsSingleLineEditor() &&
          aTextEditor->CanPaste(nsIClipboard::kGlobalClipboard);
 }
 
-nsresult PasteQuotationCommand::DoCommand(const char* aCommandName,
+nsresult PasteQuotationCommand::DoCommand(Command aCommand,
                                           TextEditor& aTextEditor) const {
   nsresult rv = aTextEditor.PasteAsQuotationAsAction(
       nsIClipboard::kGlobalClipboard, true);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   return NS_OK;
 }
 
-nsresult PasteQuotationCommand::DoCommandParams(const char* aCommandName,
+nsresult PasteQuotationCommand::DoCommandParams(Command aCommand,
                                                 nsCommandParams* aParams,
                                                 TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult PasteQuotationCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   if (!aTextEditor) {
     return NS_OK;
   }
   aParams.SetBool(STATE_ENABLED,
                   aTextEditor->CanPaste(nsIClipboard::kGlobalClipboard));
   return NS_OK;
 }
--- a/editor/libeditor/EditorCommands.h
+++ b/editor/libeditor/EditorCommands.h
@@ -46,63 +46,60 @@ class EditorCommand : public nsIControll
                              nsICommandParams* aParams,
                              nsISupports* aCommandRefCon) final;
   MOZ_CAN_RUN_SCRIPT_BOUNDARY
   NS_IMETHOD GetCommandStateParams(const char* aCommandName,
                                    nsICommandParams* aParams,
                                    nsISupports* aCommandRefCon) final;
 
   MOZ_CAN_RUN_SCRIPT
-  virtual bool IsCommandEnabled(const char* aCommandName,
+  virtual bool IsCommandEnabled(Command aCommand,
                                 TextEditor* aTextEditor) const = 0;
   MOZ_CAN_RUN_SCRIPT
-  virtual nsresult DoCommand(const char* aCommandName,
+  virtual nsresult DoCommand(Command aCommand,
                              TextEditor& aTextEditor) const = 0;
   MOZ_CAN_RUN_SCRIPT
-  virtual nsresult DoCommandParams(const char* aCommandName,
-                                   nsCommandParams* aParams,
+  virtual nsresult DoCommandParams(Command aCommand, nsCommandParams* aParams,
                                    TextEditor& aTextEditor) const = 0;
   /**
    * @param aTextEditor         If the context is an editor, should be set to
    *                            it.  Otherwise, nullptr.
    * @param aEditingSession     If the context is an editing session, should be
    *                            set to it.  This usually occurs if editor has
    *                            not been created yet during initialization.
    *                            Otherwise, nullptr.
    */
   MOZ_CAN_RUN_SCRIPT
   virtual nsresult GetCommandStateParams(
-      const char* aCommandName, nsCommandParams& aParams,
-      TextEditor* aTextEditor, nsIEditingSession* aEditingSession) const = 0;
+      Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
+      nsIEditingSession* aEditingSession) const = 0;
 
  protected:
   EditorCommand() = default;
   virtual ~EditorCommand() = default;
 };
 
-#define NS_DECL_EDITOR_COMMAND_METHODS(_cmd)                             \
- public:                                                                 \
-  MOZ_CAN_RUN_SCRIPT                                                     \
-  virtual bool IsCommandEnabled(const char* aCommandName,                \
-                                TextEditor* aTextEditor) const final;    \
-  using EditorCommand::IsCommandEnabled;                                 \
-  MOZ_CAN_RUN_SCRIPT                                                     \
-  virtual nsresult DoCommand(const char* aCommandName,                   \
-                             TextEditor& aTextEditor) const final;       \
-  using EditorCommand::DoCommand;                                        \
-  MOZ_CAN_RUN_SCRIPT                                                     \
-  virtual nsresult DoCommandParams(const char* aCommandName,             \
-                                   nsCommandParams* aParams,             \
-                                   TextEditor& aTextEditor) const final; \
-  using EditorCommand::DoCommandParams;                                  \
-  MOZ_CAN_RUN_SCRIPT                                                     \
-  virtual nsresult GetCommandStateParams(                                \
-      const char* aCommandName, nsCommandParams& aParams,                \
-      TextEditor* aTextEditor, nsIEditingSession* aEditingSession)       \
-      const final;                                                       \
+#define NS_DECL_EDITOR_COMMAND_METHODS(_cmd)                                   \
+ public:                                                                       \
+  MOZ_CAN_RUN_SCRIPT                                                           \
+  virtual bool IsCommandEnabled(Command aCommand, TextEditor* aTextEditor)     \
+      const final;                                                             \
+  using EditorCommand::IsCommandEnabled;                                       \
+  MOZ_CAN_RUN_SCRIPT                                                           \
+  virtual nsresult DoCommand(Command aCommand, TextEditor& aTextEditor)        \
+      const final;                                                             \
+  using EditorCommand::DoCommand;                                              \
+  MOZ_CAN_RUN_SCRIPT                                                           \
+  virtual nsresult DoCommandParams(Command aCommand, nsCommandParams* aParams, \
+                                   TextEditor& aTextEditor) const final;       \
+  using EditorCommand::DoCommandParams;                                        \
+  MOZ_CAN_RUN_SCRIPT                                                           \
+  virtual nsresult GetCommandStateParams(                                      \
+      Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,     \
+      nsIEditingSession* aEditingSession) const final;                         \
   using EditorCommand::GetCommandStateParams;
 
 #define NS_INLINE_DECL_EDITOR_COMMAND_MAKE_SINGLETON(_cmd) \
  public:                                                   \
   static _cmd* GetInstance() {                             \
     if (!sInstance) {                                      \
       sInstance = new _cmd();                              \
     }                                                      \
@@ -155,63 +152,79 @@ NS_DECL_EDITOR_COMMAND(PasteQuotationCom
 class StateUpdatingCommandBase : public EditorCommand {
  public:
   NS_INLINE_DECL_REFCOUNTING_INHERITED(StateUpdatingCommandBase, EditorCommand)
 
   NS_DECL_EDITOR_COMMAND_METHODS(StateUpdatingCommandBase)
 
  protected:
   StateUpdatingCommandBase() = default;
-  virtual ~StateUpdatingCommandBase() { sTagNameTable.Clear(); }
+  virtual ~StateUpdatingCommandBase() = default;
 
   // get the current state (on or off) for this style or block format
   MOZ_CAN_RUN_SCRIPT
   virtual nsresult GetCurrentState(nsAtom* aTagName, HTMLEditor* aHTMLEditor,
                                    nsCommandParams& aParams) const = 0;
 
   // add/remove the style
   MOZ_CAN_RUN_SCRIPT
   virtual nsresult ToggleState(nsAtom* aTagName,
                                HTMLEditor* aHTMLEditor) const = 0;
 
-  static already_AddRefed<nsAtom> TagName(const char* aCommandName) {
-    MOZ_DIAGNOSTIC_ASSERT(aCommandName);
-    if (NS_WARN_IF(!aCommandName)) {
-      return nullptr;
+  static nsAtom* GetTagName(Command aCommand) {
+    switch (aCommand) {
+      case Command::FormatBold:
+        return nsGkAtoms::b;
+      case Command::FormatItalic:
+        return nsGkAtoms::i;
+      case Command::FormatUnderline:
+        return nsGkAtoms::u;
+      case Command::FormatTeletypeText:
+        return nsGkAtoms::tt;
+      case Command::FormatStrikeThrough:
+        return nsGkAtoms::strike;
+      case Command::FormatSuperscript:
+        return nsGkAtoms::sup;
+      case Command::FormatSubscript:
+        return nsGkAtoms::sub;
+      case Command::FormatNoBreak:
+        return nsGkAtoms::nobr;
+      case Command::FormatEmphasis:
+        return nsGkAtoms::em;
+      case Command::FormatStrong:
+        return nsGkAtoms::strong;
+      case Command::FormatCitation:
+        return nsGkAtoms::cite;
+      case Command::FormatAbbreviation:
+        return nsGkAtoms::abbr;
+      case Command::FormatAcronym:
+        return nsGkAtoms::acronym;
+      case Command::FormatCode:
+        return nsGkAtoms::code;
+      case Command::FormatSample:
+        return nsGkAtoms::samp;
+      case Command::FormatVariable:
+        return nsGkAtoms::var;
+      case Command::FormatRemoveLink:
+        return nsGkAtoms::href;
+      case Command::InsertOrderedList:
+        return nsGkAtoms::ol;
+      case Command::InsertUnorderedList:
+        return nsGkAtoms::ul;
+      case Command::InsertDefinitionTerm:
+        return nsGkAtoms::dt;
+      case Command::InsertDefinitionDetails:
+        return nsGkAtoms::dd;
+      case Command::FormatAbsolutePosition:
+        return nsGkAtoms::_empty;
+      default:
+        return nullptr;
     }
-    if (!sTagNameTable.Count()) {
-      sTagNameTable.Put("cmd_bold", nsGkAtoms::b);
-      sTagNameTable.Put("cmd_italic", nsGkAtoms::i);
-      sTagNameTable.Put("cmd_underline", nsGkAtoms::u);
-      sTagNameTable.Put("cmd_tt", nsGkAtoms::tt);
-      sTagNameTable.Put("cmd_strikethrough", nsGkAtoms::strike);
-      sTagNameTable.Put("cmd_superscript", nsGkAtoms::sup);
-      sTagNameTable.Put("cmd_subscript", nsGkAtoms::sub);
-      sTagNameTable.Put("cmd_nobreak", nsGkAtoms::nobr);
-      sTagNameTable.Put("cmd_em", nsGkAtoms::em);
-      sTagNameTable.Put("cmd_strong", nsGkAtoms::strong);
-      sTagNameTable.Put("cmd_cite", nsGkAtoms::cite);
-      sTagNameTable.Put("cmd_abbr", nsGkAtoms::abbr);
-      sTagNameTable.Put("cmd_acronym", nsGkAtoms::acronym);
-      sTagNameTable.Put("cmd_code", nsGkAtoms::code);
-      sTagNameTable.Put("cmd_samp", nsGkAtoms::samp);
-      sTagNameTable.Put("cmd_var", nsGkAtoms::var);
-      sTagNameTable.Put("cmd_removeLinks", nsGkAtoms::href);
-      sTagNameTable.Put("cmd_ol", nsGkAtoms::ol);
-      sTagNameTable.Put("cmd_ul", nsGkAtoms::ul);
-      sTagNameTable.Put("cmd_dt", nsGkAtoms::dt);
-      sTagNameTable.Put("cmd_dd", nsGkAtoms::dd);
-      sTagNameTable.Put("cmd_absPos", nsGkAtoms::_empty);
-    }
-    RefPtr<nsAtom> tagName = sTagNameTable.Get(aCommandName);
-    MOZ_DIAGNOSTIC_ASSERT(tagName);
-    return tagName.forget();
   }
-
-  static nsRefPtrHashtable<nsCharPtrHashKey, nsAtom> sTagNameTable;
+  friend class InsertTagCommand;  // for allowing it to access GetTagName()
 };
 
 // Shared class for the various style updating commands like bold, italics etc.
 // Suitable for commands whose state is either 'on' or 'off'.
 class StyleUpdatingCommand final : public StateUpdatingCommandBase {
  public:
   NS_INLINE_DECL_EDITOR_COMMAND_MAKE_SINGLETON(StyleUpdatingCommand)
 
@@ -233,34 +246,30 @@ class InsertTagCommand final : public Ed
  public:
   NS_INLINE_DECL_REFCOUNTING_INHERITED(InsertTagCommand, EditorCommand)
 
   NS_DECL_EDITOR_COMMAND_METHODS(InsertTagCommand)
   NS_INLINE_DECL_EDITOR_COMMAND_MAKE_SINGLETON(InsertTagCommand)
 
  protected:
   InsertTagCommand() = default;
-  virtual ~InsertTagCommand() { sTagNameTable.Clear(); }
+  virtual ~InsertTagCommand() = default;
 
-  static already_AddRefed<nsAtom> TagName(const char* aCommandName) {
-    MOZ_DIAGNOSTIC_ASSERT(aCommandName);
-    if (NS_WARN_IF(!aCommandName)) {
-      return nullptr;
+  static nsAtom* GetTagName(Command aCommand) {
+    switch (aCommand) {
+      case Command::InsertLink:
+        return nsGkAtoms::a;
+      case Command::InsertImage:
+        return nsGkAtoms::img;
+      case Command::InsertHorizontalRule:
+        return nsGkAtoms::hr;
+      default:
+        return StateUpdatingCommandBase::GetTagName(aCommand);
     }
-    if (!sTagNameTable.Count()) {
-      sTagNameTable.Put("cmd_insertLinkNoUI", nsGkAtoms::a);
-      sTagNameTable.Put("cmd_insertImageNoUI", nsGkAtoms::img);
-      sTagNameTable.Put("cmd_insertHR", nsGkAtoms::hr);
-    }
-    RefPtr<nsAtom> tagName = sTagNameTable.Get(aCommandName);
-    MOZ_DIAGNOSTIC_ASSERT(tagName);
-    return tagName.forget();
   }
-
-  static nsRefPtrHashtable<nsCharPtrHashKey, nsAtom> sTagNameTable;
 };
 
 class ListCommand final : public StateUpdatingCommandBase {
  public:
   NS_INLINE_DECL_EDITOR_COMMAND_MAKE_SINGLETON(ListCommand)
 
  protected:
   ListCommand() = default;
--- a/editor/libeditor/HTMLAnonymousNodeEditor.cpp
+++ b/editor/libeditor/HTMLAnonymousNodeEditor.cpp
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/HTMLEditor.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/EventTarget.h"
 #include "mozilla/mozalloc.h"
 #include "nsAString.h"
 #include "nsCOMPtr.h"
 #include "nsComputedDOMStyle.h"
 #include "nsDebug.h"
 #include "nsError.h"
@@ -22,17 +23,16 @@
 #include "nsIDOMWindow.h"
 #include "mozilla/dom/Document.h"
 #include "nsIDocumentObserver.h"
 #include "nsIHTMLAbsPosEditor.h"
 #include "nsIHTMLInlineTableEditor.h"
 #include "nsIHTMLObjectResizer.h"
 #include "nsStubMutationObserver.h"
 #include "nsINode.h"
-#include "nsIPresShellInlines.h"
 #include "nsISupportsImpl.h"
 #include "nsISupportsUtils.h"
 #include "nsLiteralString.h"
 #include "nsPresContext.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsStringFwd.h"
 #include "nsUnicharUtils.h"
--- a/editor/libeditor/HTMLEditorCommands.cpp
+++ b/editor/libeditor/HTMLEditorCommands.cpp
@@ -6,20 +6,20 @@
 #include "mozilla/EditorCommands.h"
 
 #include "mozilla/Assertions.h"  // for MOZ_ASSERT, etc
 #include "mozilla/EditorBase.h"  // for EditorBase
 #include "mozilla/ErrorResult.h"
 #include "mozilla/HTMLEditor.h"  // for HTMLEditor
 #include "mozilla/dom/Element.h"
 #include "nsAString.h"
+#include "nsAtom.h"                   // for nsAtom, nsStaticAtom, etc
 #include "nsCommandParams.h"          // for nsCommandParams, etc
 #include "nsComponentManagerUtils.h"  // for do_CreateInstance
 #include "nsGkAtoms.h"                // for nsGkAtoms, nsGkAtoms::font, etc
-#include "nsAtom.h"                   // for nsAtom, etc
 #include "nsIClipboard.h"             // for nsIClipboard, etc
 #include "nsIEditingSession.h"
 #include "nsLiteralString.h"  // for NS_LITERAL_STRING
 #include "nsReadableUtils.h"  // for EmptyString
 #include "nsString.h"         // for nsAutoString, nsString, etc
 #include "nsStringFwd.h"      // for nsString
 
 class nsISupports;
@@ -41,114 +41,110 @@ static nsresult GetListState(HTMLEditor*
 #define STATE_END "state_end"
 #define STATE_ATTRIBUTE "state_attribute"
 #define STATE_DATA "state_data"
 
 /*****************************************************************************
  * mozilla::StateUpdatingCommandBase
  *****************************************************************************/
 
-nsRefPtrHashtable<nsCharPtrHashKey, nsAtom>
-    StateUpdatingCommandBase::sTagNameTable;
-
-bool StateUpdatingCommandBase::IsCommandEnabled(const char* aCommandName,
+bool StateUpdatingCommandBase::IsCommandEnabled(Command aCommand,
                                                 TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   if (!aTextEditor->IsSelectionEditable()) {
     return false;
   }
-  if (!strcmp(aCommandName, "cmd_absPos")) {
+  if (aCommand == Command::FormatAbsolutePosition) {
     HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
     return htmlEditor && htmlEditor->IsAbsolutePositionEditorEnabled();
   }
   return true;
 }
 
-nsresult StateUpdatingCommandBase::DoCommand(const char* aCommandName,
+nsresult StateUpdatingCommandBase::DoCommand(Command aCommand,
                                              TextEditor& aTextEditor) const {
   HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
   if (NS_WARN_IF(!htmlEditor)) {
     return NS_ERROR_FAILURE;
   }
-  RefPtr<nsAtom> tagName = TagName(aCommandName);
+  nsAtom* tagName = GetTagName(aCommand);
   if (NS_WARN_IF(!tagName)) {
     return NS_ERROR_UNEXPECTED;
   }
-  return ToggleState(tagName, MOZ_KnownLive(htmlEditor));
+  return ToggleState(MOZ_KnownLive(tagName), MOZ_KnownLive(htmlEditor));
 }
 
 nsresult StateUpdatingCommandBase::DoCommandParams(
-    const char* aCommandName, nsCommandParams* aParams,
-    TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+    Command aCommand, nsCommandParams* aParams, TextEditor& aTextEditor) const {
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult StateUpdatingCommandBase::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   if (!aTextEditor) {
     return NS_OK;
   }
   HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
   if (NS_WARN_IF(!htmlEditor)) {
     return NS_ERROR_FAILURE;
   }
-  RefPtr<nsAtom> tagName = TagName(aCommandName);
+  nsAtom* tagName = GetTagName(aCommand);
   if (NS_WARN_IF(!tagName)) {
     return NS_ERROR_UNEXPECTED;
   }
-  return GetCurrentState(tagName, MOZ_KnownLive(htmlEditor), aParams);
+  return GetCurrentState(MOZ_KnownLive(tagName), MOZ_KnownLive(htmlEditor),
+                         aParams);
 }
 
 /*****************************************************************************
  * mozilla::PasteNoFormattingCommand
  *****************************************************************************/
 
 StaticRefPtr<PasteNoFormattingCommand> PasteNoFormattingCommand::sInstance;
 
-bool PasteNoFormattingCommand::IsCommandEnabled(const char* aCommandName,
+bool PasteNoFormattingCommand::IsCommandEnabled(Command aCommand,
                                                 TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
 
   // This command is only implemented by nsIHTMLEditor, since
   //  pasting in a plaintext editor automatically only supplies
   //  "unformatted" text
   HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
   if (!htmlEditor) {
     return false;
   }
   return htmlEditor->CanPaste(nsIClipboard::kGlobalClipboard);
 }
 
-nsresult PasteNoFormattingCommand::DoCommand(const char* aCommandName,
+nsresult PasteNoFormattingCommand::DoCommand(Command aCommand,
                                              TextEditor& aTextEditor) const {
   HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
   if (NS_WARN_IF(!htmlEditor)) {
     return NS_ERROR_FAILURE;
   }
   // Known live because we hold a ref above in "editor"
   return MOZ_KnownLive(htmlEditor)
       ->PasteNoFormatting(nsIClipboard::kGlobalClipboard);
 }
 
 nsresult PasteNoFormattingCommand::DoCommandParams(
-    const char* aCommandName, nsCommandParams* aParams,
-    TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+    Command aCommand, nsCommandParams* aParams, TextEditor& aTextEditor) const {
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult PasteNoFormattingCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /*****************************************************************************
  * mozilla::StyleUpdatingCommand
  *****************************************************************************/
 
 StaticRefPtr<StyleUpdatingCommand> StyleUpdatingCommand::sInstance;
 
@@ -367,17 +363,17 @@ nsresult ListItemCommand::ToggleState(ns
 }
 
 /*****************************************************************************
  * mozilla::RemoveListCommand
  *****************************************************************************/
 
 StaticRefPtr<RemoveListCommand> RemoveListCommand::sInstance;
 
-bool RemoveListCommand::IsCommandEnabled(const char* aCommandName,
+bool RemoveListCommand::IsCommandEnabled(Command aCommand,
                                          TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
 
   if (!aTextEditor->IsSelectionEditable()) {
     return false;
   }
@@ -392,140 +388,140 @@ bool RemoveListCommand::IsCommandEnabled
   nsAutoString localName;
   nsresult rv = GetListState(MOZ_KnownLive(htmlEditor), &bMixed, localName);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
   return bMixed || !localName.IsEmpty();
 }
 
-nsresult RemoveListCommand::DoCommand(const char* aCommandName,
+nsresult RemoveListCommand::DoCommand(Command aCommand,
                                       TextEditor& aTextEditor) const {
   HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
   if (!htmlEditor) {
     return NS_OK;
   }
   // This removes any list type
   return htmlEditor->RemoveList(EmptyString());
 }
 
-nsresult RemoveListCommand::DoCommandParams(const char* aCommandName,
+nsresult RemoveListCommand::DoCommandParams(Command aCommand,
                                             nsCommandParams* aParams,
                                             TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult RemoveListCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /*****************************************************************************
  * mozilla::IndentCommand
  *****************************************************************************/
 
 StaticRefPtr<IndentCommand> IndentCommand::sInstance;
 
-bool IndentCommand::IsCommandEnabled(const char* aCommandName,
+bool IndentCommand::IsCommandEnabled(Command aCommand,
                                      TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return aTextEditor->IsSelectionEditable();
 }
 
-nsresult IndentCommand::DoCommand(const char* aCommandName,
+nsresult IndentCommand::DoCommand(Command aCommand,
                                   TextEditor& aTextEditor) const {
   HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
   if (!htmlEditor) {
     return NS_OK;
   }
   nsresult rv = htmlEditor->IndentAsAction();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   return NS_OK;
 }
 
-nsresult IndentCommand::DoCommandParams(const char* aCommandName,
+nsresult IndentCommand::DoCommandParams(Command aCommand,
                                         nsCommandParams* aParams,
                                         TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult IndentCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /*****************************************************************************
  * mozilla::OutdentCommand
  *****************************************************************************/
 
 StaticRefPtr<OutdentCommand> OutdentCommand::sInstance;
 
-bool OutdentCommand::IsCommandEnabled(const char* aCommandName,
+bool OutdentCommand::IsCommandEnabled(Command aCommand,
                                       TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return aTextEditor->IsSelectionEditable();
 }
 
-nsresult OutdentCommand::DoCommand(const char* aCommandName,
+nsresult OutdentCommand::DoCommand(Command aCommand,
                                    TextEditor& aTextEditor) const {
   HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
   if (!htmlEditor) {
     return NS_OK;
   }
   nsresult rv = htmlEditor->OutdentAsAction();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   return NS_OK;
 }
 
-nsresult OutdentCommand::DoCommandParams(const char* aCommandName,
+nsresult OutdentCommand::DoCommandParams(Command aCommand,
                                          nsCommandParams* aParams,
                                          TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult OutdentCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /*****************************************************************************
  * mozilla::MultiStateCommandBase
  *****************************************************************************/
 
-bool MultiStateCommandBase::IsCommandEnabled(const char* aCommandName,
+bool MultiStateCommandBase::IsCommandEnabled(Command aCommand,
                                              TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   // should be disabled sometimes, like if the current selection is an image
   return aTextEditor->IsSelectionEditable();
 }
 
-nsresult MultiStateCommandBase::DoCommand(const char* aCommandName,
+nsresult MultiStateCommandBase::DoCommand(Command aCommand,
                                           TextEditor& aTextEditor) const {
   NS_WARNING(
       "who is calling MultiStateCommandBase::DoCommand (no implementation)?");
   return NS_OK;
 }
 
-nsresult MultiStateCommandBase::DoCommandParams(const char* aCommandName,
+nsresult MultiStateCommandBase::DoCommandParams(Command aCommand,
                                                 nsCommandParams* aParams,
                                                 TextEditor& aTextEditor) const {
   HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
   if (NS_WARN_IF(!htmlEditor)) {
     return NS_ERROR_FAILURE;
   }
 
   nsAutoString attribute;
@@ -537,17 +533,17 @@ nsresult MultiStateCommandBase::DoComman
     } else {
       aParams->GetString(STATE_ATTRIBUTE, attribute);
     }
   }
   return SetState(MOZ_KnownLive(htmlEditor), attribute);
 }
 
 nsresult MultiStateCommandBase::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   if (!aTextEditor) {
     return NS_OK;
   }
   HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
   if (NS_WARN_IF(!htmlEditor)) {
     return NS_ERROR_FAILURE;
   }
@@ -945,17 +941,17 @@ nsresult AbsolutePositioningCommand::Tog
 }
 
 /*****************************************************************************
  * mozilla::DecreaseZIndexCommand
  *****************************************************************************/
 
 StaticRefPtr<DecreaseZIndexCommand> DecreaseZIndexCommand::sInstance;
 
-bool DecreaseZIndexCommand::IsCommandEnabled(const char* aCommandName,
+bool DecreaseZIndexCommand::IsCommandEnabled(Command aCommand,
                                              TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
   if (!htmlEditor) {
     return false;
   }
@@ -964,220 +960,218 @@ bool DecreaseZIndexCommand::IsCommandEna
   }
   RefPtr<Element> positionedElement = htmlEditor->GetPositionedElement();
   if (!positionedElement) {
     return false;
   }
   return htmlEditor->GetZIndex(*positionedElement) > 0;
 }
 
-nsresult DecreaseZIndexCommand::DoCommand(const char* aCommandName,
+nsresult DecreaseZIndexCommand::DoCommand(Command aCommand,
                                           TextEditor& aTextEditor) const {
   HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
   if (NS_WARN_IF(!htmlEditor)) {
     return NS_ERROR_FAILURE;
   }
   return htmlEditor->AddZIndex(-1);
 }
 
-nsresult DecreaseZIndexCommand::DoCommandParams(const char* aCommandName,
+nsresult DecreaseZIndexCommand::DoCommandParams(Command aCommand,
                                                 nsCommandParams* aParams,
                                                 TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult DecreaseZIndexCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /*****************************************************************************
  * mozilla::IncreaseZIndexCommand
  *****************************************************************************/
 
 StaticRefPtr<IncreaseZIndexCommand> IncreaseZIndexCommand::sInstance;
 
-bool IncreaseZIndexCommand::IsCommandEnabled(const char* aCommandName,
+bool IncreaseZIndexCommand::IsCommandEnabled(Command aCommand,
                                              TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
   if (!htmlEditor) {
     return false;
   }
   if (!htmlEditor->IsAbsolutePositionEditorEnabled()) {
     return false;
   }
   return !!htmlEditor->GetPositionedElement();
 }
 
-nsresult IncreaseZIndexCommand::DoCommand(const char* aCommandName,
+nsresult IncreaseZIndexCommand::DoCommand(Command aCommand,
                                           TextEditor& aTextEditor) const {
   HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
   if (NS_WARN_IF(!htmlEditor)) {
     return NS_ERROR_FAILURE;
   }
   return htmlEditor->AddZIndex(1);
 }
 
-nsresult IncreaseZIndexCommand::DoCommandParams(const char* aCommandName,
+nsresult IncreaseZIndexCommand::DoCommandParams(Command aCommand,
                                                 nsCommandParams* aParams,
                                                 TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult IncreaseZIndexCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /*****************************************************************************
  * mozilla::RemoveStylesCommand
  *****************************************************************************/
 
 StaticRefPtr<RemoveStylesCommand> RemoveStylesCommand::sInstance;
 
-bool RemoveStylesCommand::IsCommandEnabled(const char* aCommandName,
+bool RemoveStylesCommand::IsCommandEnabled(Command aCommand,
                                            TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   // test if we have any styles?
   return aTextEditor->IsSelectionEditable();
 }
 
-nsresult RemoveStylesCommand::DoCommand(const char* aCommandName,
+nsresult RemoveStylesCommand::DoCommand(Command aCommand,
                                         TextEditor& aTextEditor) const {
   HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
   if (!htmlEditor) {
     return NS_OK;
   }
   return MOZ_KnownLive(htmlEditor)->RemoveAllInlineProperties();
 }
 
-nsresult RemoveStylesCommand::DoCommandParams(const char* aCommandName,
+nsresult RemoveStylesCommand::DoCommandParams(Command aCommand,
                                               nsCommandParams* aParams,
                                               TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult RemoveStylesCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /*****************************************************************************
  * mozilla::IncreaseFontSizeCommand
  *****************************************************************************/
 
 StaticRefPtr<IncreaseFontSizeCommand> IncreaseFontSizeCommand::sInstance;
 
-bool IncreaseFontSizeCommand::IsCommandEnabled(const char* aCommandName,
+bool IncreaseFontSizeCommand::IsCommandEnabled(Command aCommand,
                                                TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   // test if we are at max size?
   return aTextEditor->IsSelectionEditable();
 }
 
-nsresult IncreaseFontSizeCommand::DoCommand(const char* aCommandName,
+nsresult IncreaseFontSizeCommand::DoCommand(Command aCommand,
                                             TextEditor& aTextEditor) const {
   HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
   if (!htmlEditor) {
     return NS_OK;
   }
   return MOZ_KnownLive(htmlEditor)->IncreaseFontSize();
 }
 
 nsresult IncreaseFontSizeCommand::DoCommandParams(
-    const char* aCommandName, nsCommandParams* aParams,
-    TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+    Command aCommand, nsCommandParams* aParams, TextEditor& aTextEditor) const {
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult IncreaseFontSizeCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /*****************************************************************************
  * mozilla::DecreaseFontSizeCommand
  *****************************************************************************/
 
 StaticRefPtr<DecreaseFontSizeCommand> DecreaseFontSizeCommand::sInstance;
 
-bool DecreaseFontSizeCommand::IsCommandEnabled(const char* aCommandName,
+bool DecreaseFontSizeCommand::IsCommandEnabled(Command aCommand,
                                                TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   // test if we are at min size?
   return aTextEditor->IsSelectionEditable();
 }
 
-nsresult DecreaseFontSizeCommand::DoCommand(const char* aCommandName,
+nsresult DecreaseFontSizeCommand::DoCommand(Command aCommand,
                                             TextEditor& aTextEditor) const {
   HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
   if (!htmlEditor) {
     return NS_OK;
   }
   return MOZ_KnownLive(htmlEditor)->DecreaseFontSize();
 }
 
 nsresult DecreaseFontSizeCommand::DoCommandParams(
-    const char* aCommandName, nsCommandParams* aParams,
-    TextEditor& aTextEditor) const {
-  return DoCommand(aCommandName, aTextEditor);
+    Command aCommand, nsCommandParams* aParams, TextEditor& aTextEditor) const {
+  return DoCommand(aCommand, aTextEditor);
 }
 
 nsresult DecreaseFontSizeCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /*****************************************************************************
  * mozilla::InsertHTMLCommand
  *****************************************************************************/
 
 StaticRefPtr<InsertHTMLCommand> InsertHTMLCommand::sInstance;
 
-bool InsertHTMLCommand::IsCommandEnabled(const char* aCommandName,
+bool InsertHTMLCommand::IsCommandEnabled(Command aCommand,
                                          TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return aTextEditor->IsSelectionEditable();
 }
 
-nsresult InsertHTMLCommand::DoCommand(const char* aCommandName,
+nsresult InsertHTMLCommand::DoCommand(Command aCommand,
                                       TextEditor& aTextEditor) const {
   // If nsInsertHTMLCommand is called with no parameters, it was probably called
   // with an empty string parameter ''. In this case, it should act the same as
   // the delete command
   HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
   if (NS_WARN_IF(!htmlEditor)) {
     return NS_ERROR_FAILURE;
   }
   nsAutoString html;
   return MOZ_KnownLive(htmlEditor)->InsertHTML(html);
 }
 
-nsresult InsertHTMLCommand::DoCommandParams(const char* aCommandName,
+nsresult InsertHTMLCommand::DoCommandParams(Command aCommand,
                                             nsCommandParams* aParams,
                                             TextEditor& aTextEditor) const {
   if (NS_WARN_IF(!aParams)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
   if (NS_WARN_IF(!htmlEditor)) {
@@ -1189,75 +1183,75 @@ nsresult InsertHTMLCommand::DoCommandPar
   nsresult rv = aParams->GetString(STATE_DATA, html);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   return MOZ_KnownLive(htmlEditor)->InsertHTML(html);
 }
 
 nsresult InsertHTMLCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /*****************************************************************************
  * mozilla::InsertTagCommand
  *****************************************************************************/
 
 StaticRefPtr<InsertTagCommand> InsertTagCommand::sInstance;
-nsRefPtrHashtable<nsCharPtrHashKey, nsAtom> InsertTagCommand::sTagNameTable;
 
-bool InsertTagCommand::IsCommandEnabled(const char* aCommandName,
+bool InsertTagCommand::IsCommandEnabled(Command aCommand,
                                         TextEditor* aTextEditor) const {
   if (!aTextEditor) {
     return false;
   }
   return aTextEditor->IsSelectionEditable();
 }
 
 // corresponding STATE_ATTRIBUTE is: src (img) and href (a)
-nsresult InsertTagCommand::DoCommand(const char* aCmdName,
+nsresult InsertTagCommand::DoCommand(Command aCommand,
                                      TextEditor& aTextEditor) const {
-  RefPtr<nsAtom> tagName = TagName(aCmdName);
+  nsAtom* tagName = GetTagName(aCommand);
   if (NS_WARN_IF(tagName != nsGkAtoms::hr)) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
   if (NS_WARN_IF(!htmlEditor)) {
     return NS_ERROR_FAILURE;
   }
 
   RefPtr<Element> newElement =
-      MOZ_KnownLive(htmlEditor)->CreateElementWithDefaults(*tagName);
+      MOZ_KnownLive(htmlEditor)
+          ->CreateElementWithDefaults(MOZ_KnownLive(*tagName));
   if (NS_WARN_IF(!newElement)) {
     return NS_ERROR_FAILURE;
   }
   nsresult rv =
       MOZ_KnownLive(htmlEditor)->InsertElementAtSelection(newElement, true);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   return NS_OK;
 }
 
-nsresult InsertTagCommand::DoCommandParams(const char* aCommandName,
+nsresult InsertTagCommand::DoCommandParams(Command aCommand,
                                            nsCommandParams* aParams,
                                            TextEditor& aTextEditor) const {
   // inserting an hr shouldn't have an parameters, just call DoCommand for that
-  if (!strcmp(aCommandName, "cmd_insertHR")) {
-    return DoCommand(aCommandName, aTextEditor);
+  if (aCommand == Command::InsertHorizontalRule) {
+    return DoCommand(aCommand, aTextEditor);
   }
 
   if (NS_WARN_IF(!aParams)) {
     return NS_ERROR_INVALID_ARG;
   }
-  RefPtr<nsAtom> tagName = TagName(aCommandName);
+  nsAtom* tagName = GetTagName(aCommand);
   if (NS_WARN_IF(!tagName)) {
     return NS_ERROR_UNEXPECTED;
   }
 
   HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
   if (NS_WARN_IF(!htmlEditor)) {
     return NS_ERROR_FAILURE;
   }
@@ -1280,17 +1274,18 @@ nsresult InsertTagCommand::DoCommandPara
     attribute = nsGkAtoms::href;
   } else if (tagName == nsGkAtoms::img) {
     attribute = nsGkAtoms::src;
   } else {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   RefPtr<Element> newElement =
-      MOZ_KnownLive(htmlEditor)->CreateElementWithDefaults(*tagName);
+      MOZ_KnownLive(htmlEditor)
+          ->CreateElementWithDefaults(MOZ_KnownLive(*tagName));
   if (NS_WARN_IF(!newElement)) {
     return NS_ERROR_FAILURE;
   }
 
   ErrorResult err;
   newElement->SetAttr(attribute, value, err);
   if (NS_WARN_IF(err.Failed())) {
     return err.StealNSResult();
@@ -1308,20 +1303,20 @@ nsresult InsertTagCommand::DoCommandPara
   rv = MOZ_KnownLive(htmlEditor)->InsertElementAtSelection(newElement, true);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   return NS_OK;
 }
 
 nsresult InsertTagCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   return aParams.SetBool(STATE_ENABLED,
-                         IsCommandEnabled(aCommandName, aTextEditor));
+                         IsCommandEnabled(aCommand, aTextEditor));
 }
 
 /*****************************************************************************
  * Helper methods
  *****************************************************************************/
 
 static nsresult GetListState(HTMLEditor* aHTMLEditor, bool* aMixed,
                              nsAString& aLocalName)
--- a/editor/libeditor/HTMLEditorDocumentCommands.cpp
+++ b/editor/libeditor/HTMLEditorDocumentCommands.cpp
@@ -32,345 +32,325 @@ namespace mozilla {
  *  As of 11/11/02, this is just "cmd_setDocumentModified"
  *  Note that you can use the same command class, SetDocumentStateCommand,
  *    for more than one of this type of command
  *    We check the input command param for different behavior
  *****************************************************************************/
 
 StaticRefPtr<SetDocumentStateCommand> SetDocumentStateCommand::sInstance;
 
-bool SetDocumentStateCommand::IsCommandEnabled(const char* aCommandName,
+bool SetDocumentStateCommand::IsCommandEnabled(Command aCommand,
                                                TextEditor* aTextEditor) const {
   // These commands are always enabled
   return true;
 }
 
-nsresult SetDocumentStateCommand::DoCommand(const char* aCommandName,
+nsresult SetDocumentStateCommand::DoCommand(Command aCommand,
                                             TextEditor& aTextEditor) const {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 nsresult SetDocumentStateCommand::DoCommandParams(
-    const char* aCommandName, nsCommandParams* aParams,
-    TextEditor& aTextEditor) const {
+    Command aCommand, nsCommandParams* aParams, TextEditor& aTextEditor) const {
   if (NS_WARN_IF(!aParams)) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  if (!strcmp(aCommandName, "cmd_setDocumentModified")) {
-    ErrorResult error;
-    bool modified = aParams->GetBool(STATE_ATTRIBUTE, error);
-    // Should we fail if this param wasn't set?
-    // I'm not sure we should be that strict
-    if (NS_WARN_IF(error.Failed())) {
-      return error.StealNSResult();
-    }
-    if (modified) {
-      nsresult rv = aTextEditor.IncrementModificationCount(1);
+  switch (aCommand) {
+    case Command::SetDocumentModified: {
+      ErrorResult error;
+      bool modified = aParams->GetBool(STATE_ATTRIBUTE, error);
+      // Should we fail if this param wasn't set?
+      // I'm not sure we should be that strict
+      if (NS_WARN_IF(error.Failed())) {
+        return error.StealNSResult();
+      }
+      if (modified) {
+        nsresult rv = aTextEditor.IncrementModificationCount(1);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
+        return NS_OK;
+      }
+      nsresult rv = aTextEditor.ResetModificationCount();
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       return NS_OK;
     }
-    nsresult rv = aTextEditor.ResetModificationCount();
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
+    case Command::SetDocumentReadOnly: {
+      ErrorResult error;
+      bool isReadOnly = aParams->GetBool(STATE_ATTRIBUTE, error);
+      if (NS_WARN_IF(error.Failed())) {
+        return error.StealNSResult();
+      }
+      if (isReadOnly) {
+        nsresult rv =
+            aTextEditor.AddFlags(nsIPlaintextEditor::eEditorReadonlyMask);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
+        return NS_OK;
+      }
+      nsresult rv =
+          aTextEditor.RemoveFlags(nsIPlaintextEditor::eEditorReadonlyMask);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      return NS_OK;
     }
-    return NS_OK;
-  }
-
-  if (!strcmp(aCommandName, "cmd_setDocumentReadOnly")) {
-    ErrorResult error;
-    bool isReadOnly = aParams->GetBool(STATE_ATTRIBUTE, error);
-    if (NS_WARN_IF(error.Failed())) {
-      return error.StealNSResult();
-    }
-    if (isReadOnly) {
-      nsresult rv =
-          aTextEditor.AddFlags(nsIPlaintextEditor::eEditorReadonlyMask);
+    case Command::SetDocumentUseCSS: {
+      HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
+      if (NS_WARN_IF(!htmlEditor)) {
+        return NS_ERROR_INVALID_ARG;
+      }
+      ErrorResult error;
+      bool desireCSS = aParams->GetBool(STATE_ATTRIBUTE, error);
+      if (NS_WARN_IF(error.Failed())) {
+        return error.StealNSResult();
+      }
+      nsresult rv = htmlEditor->SetIsCSSEnabled(desireCSS);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       return NS_OK;
     }
-    nsresult rv =
-        aTextEditor.RemoveFlags(nsIPlaintextEditor::eEditorReadonlyMask);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-    return NS_OK;
-  }
-
-  if (!strcmp(aCommandName, "cmd_setDocumentUseCSS")) {
-    HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
-    if (NS_WARN_IF(!htmlEditor)) {
-      return NS_ERROR_INVALID_ARG;
-    }
-    ErrorResult error;
-    bool desireCSS = aParams->GetBool(STATE_ATTRIBUTE, error);
-    if (NS_WARN_IF(error.Failed())) {
-      return error.StealNSResult();
-    }
-    nsresult rv = htmlEditor->SetIsCSSEnabled(desireCSS);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-    return NS_OK;
-  }
-
-  if (!strcmp(aCommandName, "cmd_insertBrOnReturn")) {
-    HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
-    if (NS_WARN_IF(!htmlEditor)) {
-      return NS_ERROR_INVALID_ARG;
-    }
-    ErrorResult error;
-    bool insertBrOnReturn = aParams->GetBool(STATE_ATTRIBUTE, error);
-    if (NS_WARN_IF(error.Failed())) {
-      return error.StealNSResult();
-    }
-    nsresult rv =
-        htmlEditor->SetReturnInParagraphCreatesNewParagraph(!insertBrOnReturn);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-    return NS_OK;
-  }
-
-  if (!strcmp(aCommandName, "cmd_defaultParagraphSeparator")) {
-    HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
-    if (NS_WARN_IF(!htmlEditor)) {
-      return NS_ERROR_INVALID_ARG;
-    }
-
-    nsAutoCString newValue;
-    nsresult rv = aParams->GetCString(STATE_ATTRIBUTE, newValue);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    if (newValue.LowerCaseEqualsLiteral("div")) {
-      htmlEditor->SetDefaultParagraphSeparator(ParagraphSeparator::div);
+    case Command::SetDocumentInsertBROnEnterKeyPress: {
+      HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
+      if (NS_WARN_IF(!htmlEditor)) {
+        return NS_ERROR_INVALID_ARG;
+      }
+      ErrorResult error;
+      bool insertBrOnReturn = aParams->GetBool(STATE_ATTRIBUTE, error);
+      if (NS_WARN_IF(error.Failed())) {
+        return error.StealNSResult();
+      }
+      nsresult rv = htmlEditor->SetReturnInParagraphCreatesNewParagraph(
+          !insertBrOnReturn);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
       return NS_OK;
     }
-    if (newValue.LowerCaseEqualsLiteral("p")) {
-      htmlEditor->SetDefaultParagraphSeparator(ParagraphSeparator::p);
-      return NS_OK;
+    case Command::SetDocumentDefaultParagraphSeparator: {
+      HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
+      if (NS_WARN_IF(!htmlEditor)) {
+        return NS_ERROR_INVALID_ARG;
+      }
+
+      nsAutoCString newValue;
+      nsresult rv = aParams->GetCString(STATE_ATTRIBUTE, newValue);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+
+      if (newValue.LowerCaseEqualsLiteral("div")) {
+        htmlEditor->SetDefaultParagraphSeparator(ParagraphSeparator::div);
+        return NS_OK;
+      }
+      if (newValue.LowerCaseEqualsLiteral("p")) {
+        htmlEditor->SetDefaultParagraphSeparator(ParagraphSeparator::p);
+        return NS_OK;
+      }
+      if (newValue.LowerCaseEqualsLiteral("br")) {
+        // Mozilla extension for backwards compatibility
+        htmlEditor->SetDefaultParagraphSeparator(ParagraphSeparator::br);
+        return NS_OK;
+      }
+
+      // This should not be reachable from nsHTMLDocument::ExecCommand
+      NS_WARNING("Invalid default paragraph separator");
+      return NS_ERROR_UNEXPECTED;
     }
-    if (newValue.LowerCaseEqualsLiteral("br")) {
-      // Mozilla extension for backwards compatibility
-      htmlEditor->SetDefaultParagraphSeparator(ParagraphSeparator::br);
+    case Command::ToggleObjectResizers: {
+      HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
+      if (NS_WARN_IF(!htmlEditor)) {
+        return NS_ERROR_INVALID_ARG;
+      }
+      ErrorResult error;
+      bool enabled = aParams->GetBool(STATE_ATTRIBUTE, error);
+      if (NS_WARN_IF(error.Failed())) {
+        return error.StealNSResult();
+      }
+      htmlEditor->EnableObjectResizer(enabled);
       return NS_OK;
     }
-
-    // This should not be reachable from nsHTMLDocument::ExecCommand
-    NS_WARNING("Invalid default paragraph separator");
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  if (!strcmp(aCommandName, "cmd_enableObjectResizing")) {
-    HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
-    if (NS_WARN_IF(!htmlEditor)) {
-      return NS_ERROR_INVALID_ARG;
-    }
-    ErrorResult error;
-    bool enabled = aParams->GetBool(STATE_ATTRIBUTE, error);
-    if (NS_WARN_IF(error.Failed())) {
-      return error.StealNSResult();
-    }
-    htmlEditor->EnableObjectResizer(enabled);
-    return NS_OK;
-  }
-
-  if (!strcmp(aCommandName, "cmd_enableInlineTableEditing")) {
-    HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
-    if (NS_WARN_IF(!htmlEditor)) {
-      return NS_ERROR_INVALID_ARG;
+    case Command::ToggleInlineTableEditor: {
+      HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
+      if (NS_WARN_IF(!htmlEditor)) {
+        return NS_ERROR_INVALID_ARG;
+      }
+      ErrorResult error;
+      bool enabled = aParams->GetBool(STATE_ATTRIBUTE, error);
+      if (NS_WARN_IF(error.Failed())) {
+        return error.StealNSResult();
+      }
+      htmlEditor->EnableInlineTableEditor(enabled);
+      return NS_OK;
     }
-    ErrorResult error;
-    bool enabled = aParams->GetBool(STATE_ATTRIBUTE, error);
-    if (NS_WARN_IF(error.Failed())) {
-      return error.StealNSResult();
+    case Command::ToggleAbsolutePositionEditor: {
+      HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
+      if (NS_WARN_IF(!htmlEditor)) {
+        return NS_ERROR_INVALID_ARG;
+      }
+      ErrorResult error;
+      bool enabled = aParams->GetBool(STATE_ATTRIBUTE, error);
+      if (NS_WARN_IF(error.Failed())) {
+        return error.StealNSResult();
+      }
+      htmlEditor->EnableAbsolutePositionEditor(enabled);
+      return NS_OK;
     }
-    htmlEditor->EnableInlineTableEditor(enabled);
-    return NS_OK;
+    default:
+      return NS_ERROR_NOT_IMPLEMENTED;
   }
-
-  if (!strcmp(aCommandName, "cmd_enableAbsolutePositionEditing")) {
-    HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
-    if (NS_WARN_IF(!htmlEditor)) {
-      return NS_ERROR_INVALID_ARG;
-    }
-    ErrorResult error;
-    bool enabled = aParams->GetBool(STATE_ATTRIBUTE, error);
-    if (NS_WARN_IF(error.Failed())) {
-      return error.StealNSResult();
-    }
-    htmlEditor->EnableAbsolutePositionEditor(enabled);
-    return NS_OK;
-  }
-
-  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 nsresult SetDocumentStateCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
   // If the result is set to STATE_ALL as bool value, queryCommandState()
   // returns the bool value.
   // If the result is set to STATE_ATTRIBUTE as CString value,
   // queryCommandValue() returns the string value.
   // Otherwise, ignored.
 
   // The base editor owns most state info
   if (NS_WARN_IF(!aTextEditor)) {
     return NS_ERROR_INVALID_ARG;
   }
   // Always get the enabled state
-  nsresult rv = aParams.SetBool(STATE_ENABLED,
-                                IsCommandEnabled(aCommandName, aTextEditor));
+  nsresult rv =
+      aParams.SetBool(STATE_ENABLED, IsCommandEnabled(aCommand, aTextEditor));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  // cmd_setDocumentModified is an internal command.
-  if (!strcmp(aCommandName, "cmd_setDocumentModified")) {
-    bool modified;
-    rv = aTextEditor->GetDocumentModified(&modified);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-    // XXX Nobody refers this result due to wrong type.
-    rv = aParams.SetBool(STATE_ATTRIBUTE, modified);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
+  switch (aCommand) {
+    case Command::SetDocumentModified: {
+      bool modified;
+      rv = aTextEditor->GetDocumentModified(&modified);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      // XXX Nobody refers this result due to wrong type.
+      rv = aParams.SetBool(STATE_ATTRIBUTE, modified);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      return NS_OK;
     }
-    return NS_OK;
-  }
-
-  // cmd_setDocumentReadOnly is a Gecko specific command, "contentReadOnly".
-  if (!strcmp(aCommandName, "cmd_setDocumentReadOnly")) {
-    // XXX Nobody refers this result due to wrong type.
-    rv = aParams.SetBool(STATE_ATTRIBUTE, aTextEditor->IsReadonly());
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-    return NS_OK;
-  }
-
-  // cmd_setDocumentUseCSS is a common command, "styleWithCSS".
-  if (!strcmp(aCommandName, "cmd_setDocumentUseCSS")) {
-    HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
-    if (NS_WARN_IF(!htmlEditor)) {
-      return NS_ERROR_INVALID_ARG;
+    case Command::SetDocumentReadOnly: {
+      // XXX Nobody refers this result due to wrong type.
+      rv = aParams.SetBool(STATE_ATTRIBUTE, aTextEditor->IsReadonly());
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      return NS_OK;
     }
-    rv = aParams.SetBool(STATE_ALL, htmlEditor->IsCSSEnabled());
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-    return NS_OK;
-  }
-
-  // cmd_insertBrOnReturn is a Gecko specific command, "insertBrOrReturn".
-  if (!strcmp(aCommandName, "cmd_insertBrOnReturn")) {
-    HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
-    if (NS_WARN_IF(!htmlEditor)) {
-      return NS_ERROR_INVALID_ARG;
+    case Command::SetDocumentUseCSS: {
+      HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
+      if (NS_WARN_IF(!htmlEditor)) {
+        return NS_ERROR_INVALID_ARG;
+      }
+      rv = aParams.SetBool(STATE_ALL, htmlEditor->IsCSSEnabled());
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      return NS_OK;
     }
-    bool createPOnReturn;
-    htmlEditor->GetReturnInParagraphCreatesNewParagraph(&createPOnReturn);
-    // XXX Nobody refers this result due to wrong type.
-    rv = aParams.SetBool(STATE_ATTRIBUTE, !createPOnReturn);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
+    case Command::SetDocumentInsertBROnEnterKeyPress: {
+      HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
+      if (NS_WARN_IF(!htmlEditor)) {
+        return NS_ERROR_INVALID_ARG;
+      }
+      bool createPOnReturn;
+      htmlEditor->GetReturnInParagraphCreatesNewParagraph(&createPOnReturn);
+      // XXX Nobody refers this result due to wrong type.
+      rv = aParams.SetBool(STATE_ATTRIBUTE, !createPOnReturn);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      return NS_OK;
     }
-    return NS_OK;
-  }
-
-  // cmd_defaultParagraphSeparator is a common command,
-  // "defaultParagraphSeparator".
-  if (!strcmp(aCommandName, "cmd_defaultParagraphSeparator")) {
-    HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
-    if (NS_WARN_IF(!htmlEditor)) {
-      return NS_ERROR_INVALID_ARG;
-    }
+    case Command::SetDocumentDefaultParagraphSeparator: {
+      HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
+      if (NS_WARN_IF(!htmlEditor)) {
+        return NS_ERROR_INVALID_ARG;
+      }
 
-    switch (htmlEditor->GetDefaultParagraphSeparator()) {
-      case ParagraphSeparator::div: {
-        DebugOnly<nsresult> rv =
-            aParams.SetCString(STATE_ATTRIBUTE, NS_LITERAL_CSTRING("div"));
-        NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
-                             "Failed to set command params to return \"div\"");
-        return NS_OK;
-      }
-      case ParagraphSeparator::p: {
-        DebugOnly<nsresult> rv =
-            aParams.SetCString(STATE_ATTRIBUTE, NS_LITERAL_CSTRING("p"));
-        NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
-                             "Failed to set command params to return \"p\"");
-        return NS_OK;
+      switch (htmlEditor->GetDefaultParagraphSeparator()) {
+        case ParagraphSeparator::div: {
+          DebugOnly<nsresult> rv =
+              aParams.SetCString(STATE_ATTRIBUTE, NS_LITERAL_CSTRING("div"));
+          NS_WARNING_ASSERTION(
+              NS_SUCCEEDED(rv),
+              "Failed to set command params to return \"div\"");
+          return NS_OK;
+        }
+        case ParagraphSeparator::p: {
+          DebugOnly<nsresult> rv =
+              aParams.SetCString(STATE_ATTRIBUTE, NS_LITERAL_CSTRING("p"));
+          NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                               "Failed to set command params to return \"p\"");
+          return NS_OK;
+        }
+        case ParagraphSeparator::br: {
+          DebugOnly<nsresult> rv =
+              aParams.SetCString(STATE_ATTRIBUTE, NS_LITERAL_CSTRING("br"));
+          NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                               "Failed to set command params to return \"br\"");
+          return NS_OK;
+        }
+        default:
+          MOZ_ASSERT_UNREACHABLE("Invalid paragraph separator value");
+          return NS_ERROR_UNEXPECTED;
       }
-      case ParagraphSeparator::br: {
-        DebugOnly<nsresult> rv =
-            aParams.SetCString(STATE_ATTRIBUTE, NS_LITERAL_CSTRING("br"));
-        NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
-                             "Failed to set command params to return \"br\"");
-        return NS_OK;
-      }
-      default:
-        MOZ_ASSERT_UNREACHABLE("Invalid paragraph separator value");
-        return NS_ERROR_UNEXPECTED;
-    }
-  }
-
-  // cmd_enableObjectResizing is a Gecko specific command,
-  // "enableObjectResizing".
-  if (!strcmp(aCommandName, "cmd_enableObjectResizing")) {
-    HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
-    if (NS_WARN_IF(!htmlEditor)) {
-      return NS_ERROR_INVALID_ARG;
     }
-    // We returned the result as STATE_ATTRIBUTE with bool value 60 or earlier.
-    // So, the result was ignored by both nsHTMLDocument::QueryCommandValue()
-    // and nsHTMLDocument::QueryCommandState().
-    rv = aParams.SetBool(STATE_ALL, htmlEditor->IsObjectResizerEnabled());
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-    return NS_OK;
-  }
-
-  // cmd_enableInlineTableEditing is a Gecko specific command,
-  // "enableInlineTableEditing".
-  if (!strcmp(aCommandName, "cmd_enableInlineTableEditing")) {
-    HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
-    if (NS_WARN_IF(!htmlEditor)) {
-      return NS_ERROR_INVALID_ARG;
+    case Command::ToggleObjectResizers: {
+      HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
+      if (NS_WARN_IF(!htmlEditor)) {
+        return NS_ERROR_INVALID_ARG;
+      }
+      // We returned the result as STATE_ATTRIBUTE with bool value 60 or
+      // earlier. So, the result was ignored by both
+      // nsHTMLDocument::QueryCommandValue() and
+      // nsHTMLDocument::QueryCommandState().
+      rv = aParams.SetBool(STATE_ALL, htmlEditor->IsObjectResizerEnabled());
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      return NS_OK;
     }
-    // We returned the result as STATE_ATTRIBUTE with bool value 60 or earlier.
-    // So, the result was ignored by both nsHTMLDocument::QueryCommandValue()
-    // and nsHTMLDocument::QueryCommandState().
-    rv = aParams.SetBool(STATE_ALL, htmlEditor->IsInlineTableEditorEnabled());
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
+    case Command::ToggleInlineTableEditor: {
+      HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
+      if (NS_WARN_IF(!htmlEditor)) {
+        return NS_ERROR_INVALID_ARG;
+      }
+      // We returned the result as STATE_ATTRIBUTE with bool value 60 or
+      // earlier. So, the result was ignored by both
+      // nsHTMLDocument::QueryCommandValue() and
+      // nsHTMLDocument::QueryCommandState().
+      rv = aParams.SetBool(STATE_ALL, htmlEditor->IsInlineTableEditorEnabled());
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      return NS_OK;
     }
-    return NS_OK;
+    case Command::ToggleAbsolutePositionEditor: {
+      HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
+      if (NS_WARN_IF(!htmlEditor)) {
+        return NS_ERROR_INVALID_ARG;
+      }
+      return aParams.SetBool(STATE_ALL,
+                             htmlEditor->IsAbsolutePositionEditorEnabled());
+    }
+    default:
+      return NS_ERROR_NOT_IMPLEMENTED;
   }
-
-  // cmd_enableAbsolutePositionEditing is a Gecko specific command,
-  // "cenableAbsolutePositionEditing".
-  if (!strcmp(aCommandName, "cmd_enableAbsolutePositionEditing")) {
-    HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
-    if (NS_WARN_IF(!htmlEditor)) {
-      return NS_ERROR_INVALID_ARG;
-    }
-    return aParams.SetBool(STATE_ALL,
-                           htmlEditor->IsAbsolutePositionEditorEnabled());
-  }
-
-  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /*****************************************************************************
  * mozilla::DocumentStateCommand
  *
  * Commands just for state notification
  *  As of 11/21/02, possible commands are:
  *    "obs_documentCreated"
@@ -402,74 +382,75 @@ nsresult SetDocumentStateCommand::GetCom
  *  5. Use GetCommandStateParams() to obtain state information
  *     e.g., any creation state codes when creating an editor are
  *     supplied for "obs_documentCreated" command in the
  *     "state_data" param's value
  *****************************************************************************/
 
 StaticRefPtr<DocumentStateCommand> DocumentStateCommand::sInstance;
 
-bool DocumentStateCommand::IsCommandEnabled(const char* aCommandName,
+bool DocumentStateCommand::IsCommandEnabled(Command aCommand,
                                             TextEditor* aTextEditor) const {
   // Always return false to discourage callers from using DoCommand()
   return false;
 }
 
-nsresult DocumentStateCommand::DoCommand(const char* aCommandName,
+nsresult DocumentStateCommand::DoCommand(Command aCommand,
                                          TextEditor& aTextEditor) const {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-nsresult DocumentStateCommand::DoCommandParams(const char* aCommandName,
+nsresult DocumentStateCommand::DoCommandParams(Command aCommand,
                                                nsCommandParams* aParams,
                                                TextEditor& aTextEditor) const {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 nsresult DocumentStateCommand::GetCommandStateParams(
-    const char* aCommandName, nsCommandParams& aParams, TextEditor* aTextEditor,
+    Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
     nsIEditingSession* aEditingSession) const {
-  if (!strcmp(aCommandName, "obs_documentCreated")) {
-    uint32_t editorStatus = nsIEditingSession::eEditorErrorUnknown;
-    if (aEditingSession) {
-      // Current context is initially set to nsIEditingSession until editor is
-      // successfully created and source doc is loaded.  Embedder gets error
-      // status if this fails.  If called before startup is finished,
-      // status will be eEditorCreationInProgress.
-      nsresult rv = aEditingSession->GetEditorStatus(&editorStatus);
+  switch (aCommand) {
+    case Command::EditorObserverDocumentCreated: {
+      uint32_t editorStatus = nsIEditingSession::eEditorErrorUnknown;
+      if (aEditingSession) {
+        // Current context is initially set to nsIEditingSession until editor is
+        // successfully created and source doc is loaded.  Embedder gets error
+        // status if this fails.  If called before startup is finished,
+        // status will be eEditorCreationInProgress.
+        nsresult rv = aEditingSession->GetEditorStatus(&editorStatus);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return rv;
+        }
+      } else if (aTextEditor) {
+        // If current context is an editor, then everything started up OK!
+        editorStatus = nsIEditingSession::eEditorOK;
+      }
+
+      // Note that if refCon is not-null, but is neither
+      // an nsIEditingSession or nsIEditor, we return "eEditorErrorUnknown"
+      DebugOnly<nsresult> rv = aParams.SetInt(STATE_DATA, editorStatus);
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to set editor status");
+      return NS_OK;
+    }
+    case Command::EditorObserverDocumentLocationChanged: {
+      if (!aTextEditor) {
+        return NS_OK;
+      }
+      Document* document = aTextEditor->GetDocument();
+      if (NS_WARN_IF(!document)) {
+        return NS_ERROR_FAILURE;
+      }
+      nsIURI* uri = document->GetDocumentURI();
+      if (NS_WARN_IF(!uri)) {
+        return NS_ERROR_FAILURE;
+      }
+      nsresult rv = aParams.SetISupports(STATE_DATA, uri);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
-    } else if (aTextEditor) {
-      // If current context is an editor, then everything started up OK!
-      editorStatus = nsIEditingSession::eEditorOK;
-    }
-
-    // Note that if refCon is not-null, but is neither
-    // an nsIEditingSession or nsIEditor, we return "eEditorErrorUnknown"
-    DebugOnly<nsresult> rv = aParams.SetInt(STATE_DATA, editorStatus);
-    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to set editor status");
-    return NS_OK;
-  }
-
-  if (!strcmp(aCommandName, "obs_documentLocationChanged")) {
-    if (!aTextEditor) {
       return NS_OK;
     }
-    Document* document = aTextEditor->GetDocument();
-    if (NS_WARN_IF(!document)) {
-      return NS_ERROR_FAILURE;
-    }
-    nsIURI* uri = document->GetDocumentURI();
-    if (NS_WARN_IF(!uri)) {
-      return NS_ERROR_FAILURE;
-    }
-    nsresult rv = aParams.SetISupports(STATE_DATA, uri);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-    return NS_OK;
+    default:
+      return NS_ERROR_NOT_IMPLEMENTED;
   }
-
-  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 }  // namespace mozilla
--- a/ipc/mscom/ProcessRuntime.cpp
+++ b/ipc/mscom/ProcessRuntime.cpp
@@ -14,20 +14,21 @@
 #include "mozilla/mscom/ProcessRuntimeShared.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Unused.h"
 #include "mozilla/Vector.h"
 #include "mozilla/WindowsVersion.h"
 #include "nsWindowsHelpers.h"
 
-#if defined(MOZILLA_INTERNAL_API)
+#if defined(MOZILLA_INTERNAL_API) && defined(MOZ_SANDBOX)
 #  include "mozilla/mscom/EnsureMTA.h"
+#  include "mozilla/sandboxTarget.h"
 #  include "nsThreadManager.h"
-#endif  // defined(MOZILLA_INTERNAL_API)
+#endif  // defined(MOZILLA_INTERNAL_API) && defined(MOZ_SANDBOX)
 
 #include <accctrl.h>
 #include <aclapi.h>
 #include <objbase.h>
 #include <objidl.h>
 
 // This API from oleaut32.dll is not declared in Windows SDK headers
 extern "C" void __cdecl SetOaNoCache(void);
@@ -38,34 +39,81 @@ namespace mscom {
 ProcessRuntime::ProcessRuntime(GeckoProcessType aProcessType)
     : mInitResult(CO_E_NOTINITIALIZED),
       mIsParentProcess(aProcessType == GeckoProcessType_Default)
 #if defined(ACCESSIBILITY) && defined(MOZILLA_INTERNAL_API)
       ,
       mActCtxRgn(a11y::Compatibility::GetActCtxResourceId())
 #endif  // defined(ACCESSIBILITY) && defined(MOZILLA_INTERNAL_API)
 {
-#if defined(MOZILLA_INTERNAL_API)
+#if defined(MOZILLA_INTERNAL_API) && defined(MOZ_SANDBOX)
   // If our process is running under Win32k lockdown, we cannot initialize
   // COM with single-threaded apartments. This is because STAs create a hidden
   // window, which implicitly requires user32 and Win32k, which are blocked.
   // Instead we start a multi-threaded apartment and conduct our process-wide
   // COM initialization on that MTA background thread.
   if (!mIsParentProcess && IsWin32kLockedDown()) {
     // It is possible that we're running so early that we might need to start
     // the thread manager ourselves.
     nsresult rv = nsThreadManager::get().Init();
     MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
     if (NS_FAILED(rv)) {
       return;
     }
 
-    EnsureMTA([this]() -> void { InitInsideApartment(); });
+    // Use the current thread's impersonation token to initialize COM, as
+    // it might fail otherwise (depending on sandbox policy).
+    HANDLE rawCurThreadImpToken;
+    if (!::OpenThreadToken(::GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY,
+                           FALSE, &rawCurThreadImpToken)) {
+      mInitResult = HRESULT_FROM_WIN32(::GetLastError());
+      return;
+    }
+    nsAutoHandle curThreadImpToken(rawCurThreadImpToken);
+
+#if defined(DEBUG)
+    // Ensure that our current token is still an impersonation token (ie, we
+    // have not yet called RevertToSelf() on this thread).
+    DWORD len;
+    TOKEN_TYPE tokenType;
+    MOZ_ASSERT(::GetTokenInformation(rawCurThreadImpToken, TokenType,
+                                     &tokenType, sizeof(tokenType), &len) &&
+               len == sizeof(tokenType) && tokenType == TokenImpersonation);
+#endif  // defined(DEBUG)
+
+    // Create an impersonation token based on the current thread's token
+    HANDLE rawMtaThreadImpToken = nullptr;
+    if (!::DuplicateToken(rawCurThreadImpToken, SecurityImpersonation,
+                          &rawMtaThreadImpToken)) {
+      mInitResult = HRESULT_FROM_WIN32(::GetLastError());
+      return;
+    }
+    nsAutoHandle mtaThreadImpToken(rawMtaThreadImpToken);
+
+    SandboxTarget::Instance()->RegisterSandboxStartCallback([]() -> void {
+      EnsureMTA([]() -> void {
+        // This is a security risk if it fails, so we release assert
+        MOZ_RELEASE_ASSERT(::RevertToSelf(),
+                           "mscom::ProcessRuntime RevertToSelf failed");
+      }, EnsureMTA::Option::ForceDispatch);
+    });
+
+    // Impersonate and initialize.
+    EnsureMTA([this, rawMtaThreadImpToken]() -> void {
+      if (!::SetThreadToken(nullptr, rawMtaThreadImpToken)) {
+        mInitResult = HRESULT_FROM_WIN32(::GetLastError());
+        return;
+      }
+
+      InitInsideApartment();
+    }, EnsureMTA::Option::ForceDispatch);
+
     return;
   }
+
 #endif  // defined(MOZILLA_INTERNAL_API)
 
   // Otherwise we initialize a single-threaded apartment on the current thread.
   mAptRegion.Init(COINIT_APARTMENTTHREADED);
 
   // We must be the outermost COM initialization on this thread. The COM runtime
   // cannot be configured once we start manipulating objects
   MOZ_ASSERT(mAptRegion.IsValidOutermost());
--- a/ipc/mscom/ProcessRuntime.h
+++ b/ipc/mscom/ProcessRuntime.h
@@ -41,17 +41,17 @@ class MOZ_NON_TEMPORARY_CLASS ProcessRun
    */
   static DWORD GetClientThreadId();
 
  private:
   void InitInsideApartment();
   HRESULT InitializeSecurity();
 
   HRESULT mInitResult;
-  bool mIsParentProcess;
+  const bool mIsParentProcess;
 #if defined(ACCESSIBILITY) && defined(MOZILLA_INTERNAL_API)
   ActivationContextRegion mActCtxRgn;
 #endif  // defined(ACCESSIBILITY) && defined(MOZILLA_INTERNAL_API)
   ApartmentRegion mAptRegion;
 };
 
 }  // namespace mscom
 }  // namespace mozilla
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -18,16 +18,17 @@
 #include "mozilla/EventStates.h"
 #include "mozilla/GeckoMVMContext.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/BrowserChild.h"
 #include "mozilla/Likely.h"
 #include "mozilla/Logging.h"
 #include "mozilla/MouseEvents.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/TouchEvents.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Unused.h"
 #include "MobileViewportManager.h"
@@ -38,17 +39,16 @@
 #endif
 
 #include "gfxContext.h"
 #include "gfxPrefs.h"
 #include "gfxUserFontSet.h"
 #include "nsContentList.h"
 #include "nsPresContext.h"
 #include "nsIContent.h"
-#include "nsIPresShellInlines.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/PointerEventHandler.h"
 #include "mozilla/dom/PopupBlocker.h"
 #include "mozilla/dom/Document.h"
 #include "mozilla/dom/DocumentInlines.h"
 #include "nsAnimationManager.h"
 #include "nsNameSpaceManager.h"  // for Pref-related rule management (bugs 22963,20760,31816)
 #include "nsFrame.h"
@@ -764,19 +764,16 @@ bool PresShell::AccessibleCaretEnabled(n
   }
   // Otherwise, disabled.
   return false;
 }
 
 nsIPresShell::nsIPresShell()
     : mViewManager(nullptr),
       mFrameManager(nullptr),
-#ifdef ACCESSIBILITY
-      mDocAccessible(nullptr),
-#endif
       mPaintCount(0),
       mAutoWeakFrames(nullptr),
       mCanvasBackgroundColor(NS_RGBA(0, 0, 0, 0)),
       mSelectionFlags(0),
       mChangeNestCount(0),
       mRenderFlags(0),
       mDidInitialize(false),
       mIsDestroying(false),
@@ -789,23 +786,19 @@ nsIPresShell::nsIPresShell()
       mLastRootReflowHadUnconstrainedBSize(false),
       mShouldUnsuppressPainting(false),
       mIgnoreFrameDestruction(false),
       mIsActive(false),
       mFrozen(false),
       mIsFirstPaint(false),
       mObservesMutationsForPrint(false),
       mWasLastReflowInterrupted(false),
-      mVisualViewportSizeSet(false),
-      mNeedLayoutFlush(true),
-      mNeedStyleFlush(true),
       mObservingStyleFlushes(false),
       mObservingLayoutFlushes(false),
       mResizeEventPending(false),
-      mNeedThrottledAnimationFlush(true),
       mFontSizeInflationForceEnabled(false),
       mFontSizeInflationDisabledInMasterProcess(false),
       mFontSizeInflationEnabled(false),
       mPaintingIsFrozen(false),
       mIsNeverPainting(false),
       mResolutionUpdated(false),
       mResolutionUpdatedByApz(false),
       mPresShellId(0),
@@ -814,18 +807,25 @@ nsIPresShell::nsIPresShell()
       mFontSizeInflationLineThreshold(0),
       mInFlush(false),
       mCurrentEventFrame(nullptr) {
 }
 
 PresShell::PresShell()
     : mCaretEnabled(false),
       mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE),
+#ifdef ACCESSIBILITY
+      mDocAccessible(nullptr),
+#endif  // #ifdef ACCESSIBILITY
       mAPZFocusSequenceNumber(0),
       mActiveSuppressDisplayport(0),
+      mNeedLayoutFlush(true),
+      mNeedStyleFlush(true),
+      mNeedThrottledAnimationFlush(true),
+      mVisualViewportSizeSet(false),
       mDocumentLoading(false),
       mNoDelayedMouseEvents(false),
       mNoDelayedKeyEvents(false),
       mApproximateFrameVisibilityVisited(false),
       mNextPaintCompressed(false),
       mHasCSSBackgroundColor(false),
       mIsLastChromeOnlyEscapeKeyConsumed(false),
       mHasReceivedPaintMessage(false),
@@ -849,34 +849,49 @@ PresShell::PresShell()
       nsISelectionDisplay::DISPLAY_TEXT | nsISelectionDisplay::DISPLAY_IMAGES;
   mIsActive = true;
   // FIXME/bug 735029: find a better solution to this problem
   mIsFirstPaint = true;
   mPresShellId = sNextPresShellId++;
   mFrozen = false;
   mRenderFlags = 0;
 
-  mVisualViewportSizeSet = false;
-
   static bool addedSynthMouseMove = false;
   if (!addedSynthMouseMove) {
     Preferences::AddBoolVarCache(&sSynthMouseMove,
                                  "layout.reflow.synthMouseMove", true);
     addedSynthMouseMove = true;
   }
   PointerEventHandler::Initialize();
   mPaintingIsFrozen = false;
   mHasCSSBackgroundColor = true;
   mIsLastChromeOnlyEscapeKeyConsumed = false;
   mHasReceivedPaintMessage = false;
 }
 
-NS_IMPL_ISUPPORTS(PresShell, nsIPresShell, nsIDocumentObserver,
-                  nsISelectionController, nsISelectionDisplay, nsIObserver,
-                  nsISupportsWeakReference, nsIMutationObserver)
+NS_INTERFACE_TABLE_HEAD(PresShell)
+  NS_INTERFACE_TABLE_BEGIN
+    // In most cases, PresShell should be treated as concrete class, but need to
+    // QI for weak reference.  Therefore, the case needed by do_QueryReferent()
+    // should be tested first.
+    NS_INTERFACE_TABLE_ENTRY(PresShell, PresShell)
+    NS_INTERFACE_TABLE_ENTRY(PresShell, nsIPresShell)
+    NS_INTERFACE_TABLE_ENTRY(PresShell, nsIDocumentObserver)
+    NS_INTERFACE_TABLE_ENTRY(PresShell, nsISelectionController)
+    NS_INTERFACE_TABLE_ENTRY(PresShell, nsISelectionDisplay)
+    NS_INTERFACE_TABLE_ENTRY(PresShell, nsIObserver)
+    NS_INTERFACE_TABLE_ENTRY(PresShell, nsISupportsWeakReference)
+    NS_INTERFACE_TABLE_ENTRY(PresShell, nsIMutationObserver)
+    NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(PresShell, nsISupports, nsIObserver)
+  NS_INTERFACE_TABLE_END
+  NS_INTERFACE_TABLE_TO_MAP_SEGUE
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(PresShell)
+NS_IMPL_RELEASE(PresShell)
 
 PresShell::~PresShell() {
   MOZ_RELEASE_ASSERT(!mForbiddenToFlush,
                      "Flag should only be set temporarily, while doing things "
                      "that shouldn't cause destruction");
   MOZ_LOG(gLog, LogLevel::Debug, ("PresShell::~PresShell this=%p", this));
 
   if (!mHaveShutDown) {
@@ -1391,35 +1406,35 @@ void nsIPresShell::StartObservingRefresh
     rd->AddStyleFlushObserver(static_cast<PresShell*>(this));
   }
 }
 
 nsRefreshDriver* nsIPresShell::GetRefreshDriver() const {
   return mPresContext ? mPresContext->RefreshDriver() : nullptr;
 }
 
-void nsIPresShell::SetAuthorStyleDisabled(bool aStyleDisabled) {
+void PresShell::SetAuthorStyleDisabled(bool aStyleDisabled) {
   if (aStyleDisabled != StyleSet()->GetAuthorStyleDisabled()) {
     StyleSet()->SetAuthorStyleDisabled(aStyleDisabled);
     mDocument->ApplicableStylesChanged();
 
     nsCOMPtr<nsIObserverService> observerService =
         mozilla::services::GetObserverService();
     if (observerService) {
       observerService->NotifyObservers(
           ToSupports(mDocument), "author-style-disabled-changed", nullptr);
     }
   }
 }
 
-bool nsIPresShell::GetAuthorStyleDisabled() const {
+bool PresShell::GetAuthorStyleDisabled() const {
   return StyleSet()->GetAuthorStyleDisabled();
 }
 
-void nsIPresShell::UpdatePreferenceStyles() {
+void PresShell::UpdatePreferenceStyles() {
   if (!mDocument) {
     return;
   }
 
   // If the document doesn't have a window there's no need to notify
   // its presshell about changes to preferences since the document is
   // in a state where it doesn't matter any more (see
   // nsDocumentViewer::Close()).
@@ -1449,24 +1464,24 @@ void nsIPresShell::UpdatePreferenceStyle
   // NOTE(emilio): This sheet is added as an agent sheet, because we don't want
   // it to be modifiable from devtools and similar, see bugs 1239336 and
   // 1436782. I think it conceptually should be a user sheet, and could be
   // without too much trouble I'd think.
   StyleSet()->AppendStyleSheet(StyleOrigin::UserAgent, newPrefSheet);
   mPrefStyleSheet = newPrefSheet;
 }
 
-void nsIPresShell::RemovePreferenceStyles() {
+void PresShell::RemovePreferenceStyles() {
   if (mPrefStyleSheet) {
     StyleSet()->RemoveStyleSheet(StyleOrigin::UserAgent, mPrefStyleSheet);
     mPrefStyleSheet = nullptr;
   }
 }
 
-void nsIPresShell::AddUserSheet(StyleSheet* aSheet) {
+void PresShell::AddUserSheet(StyleSheet* aSheet) {
   // Make sure this does what nsDocumentViewer::CreateStyleSet does wrt
   // ordering. We want this new sheet to come after all the existing stylesheet
   // service sheets (which are at the start), but before other user sheets; see
   // nsIStyleSheetService.idl for the ordering.
 
   nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
   nsTArray<RefPtr<StyleSheet>>& userSheets = *sheetService->UserStyleSheets();
 
@@ -1491,38 +1506,38 @@ void nsIPresShell::AddUserSheet(StyleShe
   } else {
     StyleSheet* ref = StyleSet()->SheetAt(StyleOrigin::User, index);
     StyleSet()->InsertStyleSheetBefore(StyleOrigin::User, aSheet, ref);
   }
 
   mDocument->ApplicableStylesChanged();
 }
 
-void nsIPresShell::AddAgentSheet(StyleSheet* aSheet) {
+void PresShell::AddAgentSheet(StyleSheet* aSheet) {
   // Make sure this does what nsDocumentViewer::CreateStyleSet does
   // wrt ordering.
   StyleSet()->AppendStyleSheet(StyleOrigin::UserAgent, aSheet);
   mDocument->ApplicableStylesChanged();
 }
 
-void nsIPresShell::AddAuthorSheet(StyleSheet* aSheet) {
+void PresShell::AddAuthorSheet(StyleSheet* aSheet) {
   // Document specific "additional" Author sheets should be stronger than the
   // ones added with the StyleSheetService.
   StyleSheet* firstAuthorSheet = mDocument->GetFirstAdditionalAuthorSheet();
   if (firstAuthorSheet) {
     StyleSet()->InsertStyleSheetBefore(StyleOrigin::Author, aSheet,
                                        firstAuthorSheet);
   } else {
     StyleSet()->AppendStyleSheet(StyleOrigin::Author, aSheet);
   }
 
   mDocument->ApplicableStylesChanged();
 }
 
-void nsIPresShell::RemoveSheet(StyleOrigin aOrigin, StyleSheet* aSheet) {
+void PresShell::RemoveSheet(StyleOrigin aOrigin, StyleSheet* aSheet) {
   StyleSet()->RemoveStyleSheet(aOrigin, aSheet);
   mDocument->ApplicableStylesChanged();
 }
 
 NS_IMETHODIMP
 PresShell::SetDisplaySelection(int16_t aToggle) {
   RefPtr<nsFrameSelection> frameSelection = mSelection;
   frameSelection->SetDisplaySelection(aToggle);
@@ -2061,17 +2076,17 @@ void nsIPresShell::SetIgnoreFrameDestruc
   if (mDocument) {
     // We need to tell the ImageLoader to drop all its references to frames
     // because they're about to go away and it won't get notifications of that.
     mDocument->StyleImageLoader()->ClearFrames(mPresContext);
   }
   mIgnoreFrameDestruction = aIgnore;
 }
 
-void nsIPresShell::NotifyDestroyingFrame(nsIFrame* aFrame) {
+void PresShell::NotifyDestroyingFrame(nsIFrame* aFrame) {
   // We must remove these from FrameLayerBuilder::DisplayItemData::mFrameList
   // here, otherwise the DisplayItemData destructor will use the destroyed frame
   // when it tries to remove it from the (array) value of this property.
   aFrame->RemoveDisplayItemDataForDeletion();
 
   if (!mIgnoreFrameDestruction) {
     if (aFrame->HasImageRequest()) {
       mDocument->StyleImageLoader()->DropRequestsForFrame(aFrame);
@@ -2501,17 +2516,17 @@ void PresShell::LoadComplete() {
         LogTextPerfStats(tp, this, tp->cumulative, loadTime.ToMilliseconds(),
                          eLog_loaddone, spec.get());
       }
     }
   }
 }
 
 #ifdef DEBUG
-void nsIPresShell::VerifyHasDirtyRootAncestor(nsIFrame* aFrame) {
+void PresShell::VerifyHasDirtyRootAncestor(nsIFrame* aFrame) {
   // XXXbz due to bug 372769, can't actually assert anything here...
   return;
 
   // XXXbz shouldn't need this part; remove it once FrameNeedsReflow
   // handles the root frame correctly.
   if (!aFrame->GetParent()) {
     return;
   }
@@ -2558,20 +2573,20 @@ void nsIPresShell::FlushPendingScrollAnc
   for (auto iter = mPendingScrollAnchorAdjustment.Iter(); !iter.Done();
        iter.Next()) {
     nsIScrollableFrame* scroll = iter.Get()->GetKey();
     scroll->Anchor()->ApplyAdjustments();
   }
   mPendingScrollAnchorAdjustment.Clear();
 }
 
-void nsIPresShell::FrameNeedsReflow(nsIFrame* aFrame,
-                                    IntrinsicDirty aIntrinsicDirty,
-                                    nsFrameState aBitToAdd,
-                                    ReflowRootHandling aRootHandling) {
+void PresShell::FrameNeedsReflow(nsIFrame* aFrame,
+                                 IntrinsicDirty aIntrinsicDirty,
+                                 nsFrameState aBitToAdd,
+                                 ReflowRootHandling aRootHandling) {
   MOZ_ASSERT(aBitToAdd == NS_FRAME_IS_DIRTY ||
                  aBitToAdd == NS_FRAME_HAS_DIRTY_CHILDREN || !aBitToAdd,
              "Unexpected bits being added");
 
   // FIXME bug 478135
   NS_ASSERTION(!(aIntrinsicDirty == IntrinsicDirty::StyleChange &&
                  aBitToAdd == NS_FRAME_HAS_DIRTY_CHILDREN),
                "bits don't correspond to style change reason");
@@ -2723,17 +2738,17 @@ void nsIPresShell::FrameNeedsReflow(nsIF
         break;
       }
     }
   } while (subtrees.Length() != 0);
 
   MaybeScheduleReflow();
 }
 
-void nsIPresShell::FrameNeedsToContinueReflow(nsIFrame* aFrame) {
+void PresShell::FrameNeedsToContinueReflow(nsIFrame* aFrame) {
   NS_ASSERTION(mIsReflowing, "Must be in reflow when marking path dirty.");
   MOZ_ASSERT(mCurrentReflowRoot, "Must have a current reflow root here");
   NS_ASSERTION(
       aFrame == mCurrentReflowRoot ||
           nsLayoutUtils::IsProperAncestorFrame(mCurrentReflowRoot, aFrame),
       "Frame passed in is not the descendant of mCurrentReflowRoot");
   NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_IN_REFLOW,
                "Frame passed in not in reflow?");
@@ -3143,20 +3158,21 @@ nsresult PresShell::GoToAnchor(const nsA
         // Scroll to the top of the page
         sf->ScrollTo(nsPoint(0, 0), ScrollMode::Instant);
       }
     }
   }
 
 #ifdef ACCESSIBILITY
   if (anchorTarget) {
-    nsAccessibilityService* accService = AccService();
-    if (accService) accService->NotifyOfAnchorJumpTo(anchorTarget);
-  }
-#endif
+    if (nsAccessibilityService* accService = GetAccessibilityService()) {
+      accService->NotifyOfAnchorJumpTo(anchorTarget);
+    }
+  }
+#endif  // #ifdef ACCESSIBILITY
 
   return rv;
 }
 
 nsresult PresShell::ScrollToAnchor() {
   if (!mLastAnchorScrolledTo) {
     return NS_OK;
   }
@@ -7609,17 +7625,17 @@ Document* PresShell::GetPrimaryContentDo
   if (!childDocShell) {
     return nullptr;
   }
 
   return childDocShell->GetDocument();
 }
 
 #ifdef DEBUG
-void nsIPresShell::ShowEventTargetDebug() {
+void PresShell::ShowEventTargetDebug() {
   if (nsFrame::GetShowEventTargetFrameBorder() && GetCurrentEventFrame()) {
     if (mDrawEventTargetFrame) {
       mDrawEventTargetFrame->InvalidateFrame();
     }
 
     mDrawEventTargetFrame = mCurrentEventFrame;
     mDrawEventTargetFrame->InvalidateFrame();
   }
@@ -9027,18 +9043,18 @@ bool nsIPresShell::ScheduleReflowOffTime
         getter_AddRefs(mReflowContinueTimer), sReflowContinueCallback, this, 30,
         nsITimer::TYPE_ONE_SHOT, "sReflowContinueCallback",
         mDocument->EventTargetFor(TaskCategory::Other));
     return NS_SUCCEEDED(rv);
   }
   return true;
 }
 
-bool nsIPresShell::DoReflow(nsIFrame* target, bool aInterruptible,
-                            OverflowChangedTracker* aOverflowTracker) {
+bool PresShell::DoReflow(nsIFrame* target, bool aInterruptible,
+                         OverflowChangedTracker* aOverflowTracker) {
 #ifdef MOZ_GECKO_PROFILER
   nsIURI* uri = mDocument->GetDocumentURI();
   AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(
       "Reflow", LAYOUT_Reflow,
       uri ? uri->GetSpecOrDefault() : NS_LITERAL_CSTRING("N/A"));
 #endif
 
   gfxTextPerfMetrics* tp = mPresContext->GetTextPerfMetrics();
@@ -9264,17 +9280,17 @@ bool nsIPresShell::DoReflow(nsIFrame* ta
   if (isTimelineRecording) {
     timelines->AddMarkerForDocShell(docShell, "Reflow", MarkerTracingType::END);
   }
 
   return !interrupted;
 }
 
 #ifdef DEBUG
-void nsIPresShell::DoVerifyReflow() {
+void PresShell::DoVerifyReflow() {
   if (GetVerifyReflowEnable()) {
     // First synchronously render what we have so far so that we can
     // see it.
     nsView* rootView = mViewManager->GetRootView();
     mViewManager->InvalidateView(rootView);
 
     FlushPendingNotifications(FlushType::Layout);
     mInVerifyReflow = true;
@@ -9762,17 +9778,17 @@ FindTopFrame(nsIFrame* aRoot)
   return nullptr;
 }
 #endif
 
 #ifdef DEBUG
 
 // After an incremental reflow, we verify the correctness by doing a
 // full reflow into a fresh frame tree.
-bool nsIPresShell::VerifyIncrementalReflow() {
+bool PresShell::VerifyIncrementalReflow() {
   if (VerifyReflowFlags::Noisy & gVerifyReflowFlags) {
     printf("Building Verification Tree...\n");
   }
 
   // Create a presentation context to view the new frame tree
   RefPtr<nsPresContext> cx = new nsRootPresContext(
       mDocument, mPresContext->IsPaginated()
                      ? nsPresContext::eContext_PrintPreview
@@ -10327,22 +10343,26 @@ void ReflowCountMgr::DisplayDiffsInTotal
 #endif  // MOZ_REFLOW_PERF
 
 nsIFrame* nsIPresShell::GetAbsoluteContainingBlock(nsIFrame* aFrame) {
   return FrameConstructor()->GetAbsoluteContainingBlock(
       aFrame, nsCSSFrameConstructor::ABS_POS);
 }
 
 #ifdef ACCESSIBILITY
-bool nsIPresShell::IsAccessibilityActive() {
-  return GetAccService() != nullptr;
-}
-
-nsAccessibilityService* nsIPresShell::AccService() { return GetAccService(); }
-#endif
+
+// static
+bool PresShell::IsAccessibilityActive() { return GetAccService() != nullptr; }
+
+// static
+nsAccessibilityService* PresShell::GetAccessibilityService() {
+  return GetAccService();
+}
+
+#endif  // #ifdef ACCESSIBILITY
 
 // Asks our docshell whether we're active.
 void PresShell::QueryIsActive() {
   nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak();
   if (mDocument) {
     Document* displayDoc = mDocument->GetDisplayDocument();
     if (displayDoc) {
       // Ok, we're an external resource document -- we need to use our display
@@ -10405,22 +10425,22 @@ nsresult PresShell::SetIsActive(bool aIs
 
   // Propagate state-change to my resource documents' PresShells
   mDocument->EnumerateExternalResources(SetExternalResourceIsActive,
                                         &aIsActive);
   mDocument->EnumerateActivityObservers(SetPluginIsActive, &aIsActive);
   nsresult rv = UpdateImageLockingState();
 #ifdef ACCESSIBILITY
   if (aIsActive) {
-    nsAccessibilityService* accService = AccService();
-    if (accService) {
+    if (nsAccessibilityService* accService =
+            PresShell::GetAccessibilityService()) {
       accService->PresShellActivated(this);
     }
   }
-#endif
+#endif  // #ifdef ACCESSIBILITY
   return rv;
 }
 
 RefPtr<MobileViewportManager> PresShell::GetMobileViewportManager() const {
   return mMobileViewportManager;
 }
 
 void PresShell::UpdateViewportOverridden(bool aAfterInitialization) {
@@ -10544,66 +10564,66 @@ size_t PresShell::SizeOfTextRuns(MallocS
   nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame, nullptr,
                                          /* clear = */ true);
 
   // collect the total memory in use for textruns
   return nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame, aMallocSizeOf,
                                                 /* clear = */ false);
 }
 
-void nsIPresShell::MarkFixedFramesForReflow(IntrinsicDirty aIntrinsicDirty) {
+void PresShell::MarkFixedFramesForReflow(IntrinsicDirty aIntrinsicDirty) {
   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
   if (rootFrame) {
     const nsFrameList& childList =
         rootFrame->GetChildList(nsIFrame::kFixedList);
     for (nsIFrame* childFrame : childList) {
       FrameNeedsReflow(childFrame, aIntrinsicDirty, NS_FRAME_IS_DIRTY);
     }
   }
 }
 
-void nsIPresShell::CompleteChangeToVisualViewportSize() {
+void PresShell::CompleteChangeToVisualViewportSize() {
   if (nsIScrollableFrame* rootScrollFrame = GetRootScrollFrameAsScrollable()) {
     rootScrollFrame->MarkScrollbarsDirtyForReflow();
   }
   MarkFixedFramesForReflow(IntrinsicDirty::Resize);
 
   if (auto* window = nsGlobalWindowInner::Cast(mDocument->GetInnerWindow())) {
     window->VisualViewport()->PostResizeEvent();
   }
 
   if (nsIScrollableFrame* rootScrollFrame = GetRootScrollFrameAsScrollable()) {
     ScrollAnchorContainer* container = rootScrollFrame->Anchor();
     container->UserScrolled();
   }
 }
 
-void nsIPresShell::SetVisualViewportSize(nscoord aWidth, nscoord aHeight) {
+void PresShell::SetVisualViewportSize(nscoord aWidth, nscoord aHeight) {
   if (!mVisualViewportSizeSet || mVisualViewportSize.width != aWidth ||
       mVisualViewportSize.height != aHeight) {
     mVisualViewportSizeSet = true;
     mVisualViewportSize.width = aWidth;
     mVisualViewportSize.height = aHeight;
 
     CompleteChangeToVisualViewportSize();
   }
 }
 
-void nsIPresShell::ResetVisualViewportSize() {
+void PresShell::ResetVisualViewportSize() {
   if (mVisualViewportSizeSet) {
     mVisualViewportSizeSet = false;
     mVisualViewportSize.width = 0;
     mVisualViewportSize.height = 0;
 
     CompleteChangeToVisualViewportSize();
   }
 }
 
-bool nsIPresShell::SetVisualViewportOffset(
-    const nsPoint& aScrollOffset, const nsPoint& aPrevLayoutScrollPos) {
+bool PresShell::SetVisualViewportOffset(const nsPoint& aScrollOffset,
+                                        const nsPoint& aPrevLayoutScrollPos) {
   bool didChange = false;
   if (GetVisualViewportOffset() != aScrollOffset) {
     nsPoint prevOffset = GetVisualViewportOffset();
     mVisualViewportOffset = Some(aScrollOffset);
     didChange = true;
 
     if (auto* window = nsGlobalWindowInner::Cast(mDocument->GetInnerWindow())) {
       window->VisualViewport()->PostScrollEvent(prevOffset,
@@ -10656,17 +10676,17 @@ void nsIPresShell::ClearPendingVisualScr
   }
 }
 
 void nsIPresShell::AcknowledgePendingVisualScrollUpdate() {
   MOZ_ASSERT(mPendingVisualScrollUpdate);
   mPendingVisualScrollUpdate->mAcknowledged = true;
 }
 
-nsPoint nsIPresShell::GetVisualViewportOffsetRelativeToLayoutViewport() const {
+nsPoint PresShell::GetVisualViewportOffsetRelativeToLayoutViewport() const {
   return GetVisualViewportOffset() - GetLayoutViewportOffset();
 }
 
 nsPoint nsIPresShell::GetLayoutViewportOffset() const {
   nsPoint result;
   if (nsIScrollableFrame* sf = GetRootScrollFrameAsScrollable()) {
     result = sf->GetScrollPosition();
   }
@@ -10808,36 +10828,36 @@ static StyleOrigin ToOrigin(uint32_t aSe
 }
 
 nsresult nsIPresShell::HasRuleProcessorUsedByMultipleStyleSets(
     uint32_t aSheetType, bool* aRetVal) {
   *aRetVal = false;
   return NS_OK;
 }
 
-void nsIPresShell::NotifyStyleSheetServiceSheetAdded(StyleSheet* aSheet,
-                                                     uint32_t aSheetType) {
+void PresShell::NotifyStyleSheetServiceSheetAdded(StyleSheet* aSheet,
+                                                  uint32_t aSheetType) {
   switch (aSheetType) {
     case nsIStyleSheetService::AGENT_SHEET:
       AddAgentSheet(aSheet);
       break;
     case nsIStyleSheetService::USER_SHEET:
       AddUserSheet(aSheet);
       break;
     case nsIStyleSheetService::AUTHOR_SHEET:
       AddAuthorSheet(aSheet);
       break;
     default:
       MOZ_ASSERT_UNREACHABLE("unexpected aSheetType value");
       break;
   }
 }
 
-void nsIPresShell::NotifyStyleSheetServiceSheetRemoved(StyleSheet* aSheet,
-                                                       uint32_t aSheetType) {
+void PresShell::NotifyStyleSheetServiceSheetRemoved(StyleSheet* aSheet,
+                                                    uint32_t aSheetType) {
   RemoveSheet(ToOrigin(aSheetType), aSheet);
 }
 
 nsIContent* PresShell::EventHandler::GetOverrideClickTarget(
     WidgetGUIEvent* aGUIEvent, nsIFrame* aFrame) {
   if (aGUIEvent->mMessage != eMouseUp) {
     return nullptr;
   }
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -49,16 +49,24 @@ namespace dom {
 class Element;
 class Selection;
 }  // namespace dom
 
 class EventDispatchingCallback;
 class GeckoMVMContext;
 class OverflowChangedTracker;
 
+// 039d8ffc-fa55-42d7-a53a-388cb129b052
+#define NS_PRESSHELL_IID                             \
+  {                                                  \
+    0x039d8ffc, 0xfa55, 0x42d7, {                    \
+      0xa5, 0x3a, 0x38, 0x8c, 0xb1, 0x29, 0xb0, 0x52 \
+    }                                                \
+  }
+
 class PresShell final : public nsIPresShell,
                         public nsISelectionController,
                         public nsIObserver,
                         public nsSupportsWeakReference {
   typedef layers::FocusTarget FocusTarget;
   typedef dom::Element Element;
 
   // A set type for tracking visible frames, for use by the visibility code in
@@ -66,16 +74,18 @@ class PresShell final : public nsIPresSh
   typedef nsTHashtable<nsPtrHashKey<nsIFrame>> VisibleFrames;
 
  public:
   PresShell();
 
   // nsISupports
   NS_DECL_ISUPPORTS
 
+  NS_DECLARE_STATIC_IID_ACCESSOR(NS_PRESSHELL_IID)
+
   static bool AccessibleCaretEnabled(nsIDocShell* aDocShell);
 
   /**
    * Return the active content currently capturing the mouse if any.
    */
   static nsIContent* GetCapturingContent() {
     return sCapturingContentInfo.mContent;
   }
@@ -96,16 +106,40 @@ class PresShell final : public nsIPresSh
   }
 
   static void ClearMouseCaptureOnView(nsView* aView);
 
   // If a frame in the subtree rooted at aFrame is capturing the mouse then
   // clears that capture.
   static void ClearMouseCapture(nsIFrame* aFrame);
 
+#ifdef ACCESSIBILITY
+  /**
+   * Return the document accessible for this PresShell if there is one.
+   */
+  a11y::DocAccessible* GetDocAccessible() const { return mDocAccessible; }
+
+  /**
+   * Set the document accessible for this PresShell.
+   */
+  void SetDocAccessible(a11y::DocAccessible* aDocAccessible) {
+    mDocAccessible = aDocAccessible;
+  }
+
+  /**
+   * Return true if accessibility is active.
+   */
+  static bool IsAccessibilityActive();
+
+  /**
+   * Return accessibility service if accessibility is active.
+   */
+  static nsAccessibilityService* GetAccessibilityService();
+#endif  // #ifdef ACCESSIBILITY
+
   void Init(Document*, nsPresContext*, nsViewManager*);
   void Destroy() override;
 
   NS_IMETHOD GetSelectionFromScript(RawSelectionType aRawSelectionType,
                                     dom::Selection** aSelection) override;
   dom::Selection* GetSelection(RawSelectionType aRawSelectionType) override;
 
   dom::Selection* GetCurrentSelection(SelectionType aSelectionType) override;
@@ -125,21 +159,16 @@ class PresShell final : public nsIPresSh
   MOZ_CAN_RUN_SCRIPT nsresult ResizeReflow(
       nscoord aWidth, nscoord aHeight, nscoord aOldWidth = 0,
       nscoord aOldHeight = 0,
       ResizeReflowOptions aOptions = ResizeReflowOptions::NoOption) override;
   MOZ_CAN_RUN_SCRIPT nsresult ResizeReflowIgnoreOverride(
       nscoord aWidth, nscoord aHeight, nscoord aOldWidth, nscoord aOldHeight,
       ResizeReflowOptions aOptions = ResizeReflowOptions::NoOption) override;
 
-  MOZ_CAN_RUN_SCRIPT
-  void DoFlushPendingNotifications(FlushType aType) override;
-  MOZ_CAN_RUN_SCRIPT
-  void DoFlushPendingNotifications(ChangesToFlush aType) override;
-
   RectVisibility GetRectVisibility(nsIFrame* aFrame, const nsRect& aRect,
                                    nscoord aMinTwips) const override;
 
   nsresult CaptureHistoryState(
       nsILayoutHistoryState** aLayoutHistoryState) override;
 
   void UnsuppressPainting() override;
 
@@ -320,16 +349,159 @@ class PresShell final : public nsIPresSh
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
   NS_DECL_NSIOBSERVER
 
+  // Inline methods defined in PresShellInlines.h
+  inline void EnsureStyleFlush();
+  inline void SetNeedStyleFlush();
+  inline void SetNeedLayoutFlush();
+  inline void SetNeedThrottledAnimationFlush();
+  inline ServoStyleSet* StyleSet() const;
+
+  /**
+   * Whether we might need a flush for the given flush type.  If this
+   * function returns false, we definitely don't need to flush.
+   *
+   * @param aFlushType The flush type to check.  This must be
+   *   >= FlushType::Style.  This also returns true if a throttled
+   *   animation flush is required.
+   */
+  bool NeedFlush(FlushType aType) const {
+    // We check mInFlush to handle re-entrant calls to FlushPendingNotifications
+    // by reporting that we always need a flush in that case.  Otherwise,
+    // we could end up missing needed flushes, since we clear the mNeedXXXFlush
+    // flags at the top of FlushPendingNotifications.
+    MOZ_ASSERT(aType >= FlushType::Style);
+    return mNeedStyleFlush ||
+           (mNeedLayoutFlush && aType >= FlushType::InterruptibleLayout) ||
+           aType >= FlushType::Display || mNeedThrottledAnimationFlush ||
+           mInFlush;
+  }
+
+  /**
+   * Returns true if we might need to flush layout, even if we haven't scheduled
+   * one yet (as opposed to HasPendingReflow, which returns true if a flush is
+   * scheduled or will soon be scheduled).
+   */
+  bool NeedLayoutFlush() const { return mNeedLayoutFlush; }
+
+  bool NeedStyleFlush() const { return mNeedStyleFlush; }
+
+  /**
+   * Flush pending notifications of the type specified.  This method
+   * will not affect the content model; it'll just affect style and
+   * frames. Callers that actually want up-to-date presentation (other
+   * than the document itself) should probably be calling
+   * Document::FlushPendingNotifications.
+   *
+   * This method can execute script, which can destroy this presshell object
+   * unless someone is holding a reference to it on the stack.  The presshell
+   * itself will ensure it lives up until the method returns, but callers who
+   * plan to use the presshell after this call should hold a strong ref
+   * themselves!
+   *
+   * @param aType the type of notifications to flush
+   */
+  MOZ_CAN_RUN_SCRIPT
+  void FlushPendingNotifications(FlushType aType) {
+    if (!NeedFlush(aType)) {
+      return;
+    }
+
+    DoFlushPendingNotifications(aType);
+  }
+
+  MOZ_CAN_RUN_SCRIPT
+  void FlushPendingNotifications(ChangesToFlush aType) {
+    if (!NeedFlush(aType.mFlushType)) {
+      return;
+    }
+
+    DoFlushPendingNotifications(aType);
+  }
+
+  /**
+   * Tell the pres shell that a frame needs to be marked dirty and needs
+   * Reflow.  It's OK if this is an ancestor of the frame needing reflow as
+   * long as the ancestor chain between them doesn't cross a reflow root.
+   *
+   * The bit to add should be NS_FRAME_IS_DIRTY, NS_FRAME_HAS_DIRTY_CHILDREN
+   * or nsFrameState(0); passing 0 means that dirty bits won't be set on the
+   * frame or its ancestors/descendants, but that intrinsic widths will still
+   * be marked dirty.  Passing aIntrinsicDirty = eResize and aBitToAdd = 0
+   * would result in no work being done, so don't do that.
+   */
+  void FrameNeedsReflow(
+      nsIFrame* aFrame, IntrinsicDirty aIntrinsicDirty, nsFrameState aBitToAdd,
+      ReflowRootHandling aRootHandling = ReflowRootHandling::InferFromBitToAdd);
+
+  /**
+   * Calls FrameNeedsReflow on all fixed position children of the root frame.
+   */
+  void MarkFixedFramesForReflow(IntrinsicDirty aIntrinsicDirty);
+
+  // This function handles all the work after VisualViewportSize is set
+  // or reset.
+  void CompleteChangeToVisualViewportSize();
+
+  /**
+   * The return value indicates whether the offset actually changed.
+   */
+  bool SetVisualViewportOffset(const nsPoint& aScrollOffset,
+                               const nsPoint& aPrevLayoutScrollPos);
+
+  nsPoint GetVisualViewportOffset() const {
+    return mVisualViewportOffset.valueOr(nsPoint());
+  }
+  bool IsVisualViewportOffsetSet() const {
+    return mVisualViewportOffset.isSome();
+  }
+
+  void SetVisualViewportSize(nscoord aWidth, nscoord aHeight);
+  void ResetVisualViewportSize();
+  bool IsVisualViewportSizeSet() { return mVisualViewportSizeSet; }
+  nsSize GetVisualViewportSize() {
+    NS_ASSERTION(mVisualViewportSizeSet,
+                 "asking for visual viewport size when its not set?");
+    return mVisualViewportSize;
+  }
+
+  nsPoint GetVisualViewportOffsetRelativeToLayoutViewport() const;
+
+  /* Enable/disable author style level. Disabling author style disables the
+   * entire author level of the cascade, including the HTML preshint level.
+   */
+  // XXX these could easily be inlined, but there is a circular #include
+  // problem with nsStyleSet.
+  void SetAuthorStyleDisabled(bool aDisabled);
+  bool GetAuthorStyleDisabled() const;
+
+  /**
+   * Update the style set somehow to take into account changed prefs which
+   * affect document styling.
+   */
+  void UpdatePreferenceStyles();
+
+  // aSheetType is one of the nsIStyleSheetService *_SHEET constants.
+  void NotifyStyleSheetServiceSheetAdded(StyleSheet* aSheet,
+                                         uint32_t aSheetType);
+  void NotifyStyleSheetServiceSheetRemoved(StyleSheet* aSheet,
+                                           uint32_t aSheetType);
+
+  // DoReflow returns whether the reflow finished without interruption
+  // If aFrame is not the root frame, the caller must pass a non-null
+  // aOverflowTracker.
+  bool DoReflow(nsIFrame* aFrame, bool aInterruptible,
+                OverflowChangedTracker* aOverflowTracker);
+
 #ifdef MOZ_REFLOW_PERF
   void DumpReflows() override;
   void CountReflows(const char* aName, nsIFrame* aFrame) override;
   void PaintCount(const char* aName, gfxContext* aRenderingContext,
                   nsPresContext* aPresContext, nsIFrame* aFrame,
                   const nsPoint& aOffset, uint32_t aColor) override;
   void SetPaintFrameCount(bool aOn) override;
   bool IsPaintingFrameCounts() override;
@@ -526,16 +698,40 @@ class PresShell final : public nsIPresSh
     PresShell::SetCapturingContent(nullptr, CaptureFlags::None);
   }
 
   // Called at the end of nsLayoutUtils::PaintFrame().
   // This is used to clear any pending visual scroll updates that have been
   // acknowledged, to make sure they don't stick around for the next paint.
   void EndPaint();
 
+  /**
+   * Tell the presshell that the given frame's reflow was interrupted.  This
+   * will mark as having dirty children a path from the given frame (inclusive)
+   * to the nearest ancestor with a dirty subtree, or to the reflow root
+   * currently being reflowed if no such ancestor exists (inclusive).  This is
+   * to be done immediately after reflow of the current reflow root completes.
+   * This method must only be called during reflow, and the frame it's being
+   * called on must be in the process of being reflowed when it's called.  This
+   * method doesn't mark any intrinsic widths dirty and doesn't add any bits
+   * other than NS_FRAME_HAS_DIRTY_CHILDREN.
+   */
+  void FrameNeedsToContinueReflow(nsIFrame* aFrame);
+
+  /**
+   * Notification sent by a frame informing the pres shell that it is about to
+   * be destroyed.
+   * This allows any outstanding references to the frame to be cleaned up
+   */
+  void NotifyDestroyingFrame(nsIFrame* aFrame);
+
+#ifdef DEBUG
+  nsIFrame* GetDrawEventTargetFrame() { return mDrawEventTargetFrame; }
+#endif
+
  private:
   ~PresShell();
 
   friend class ::AutoPointerEventTargetUpdater;
 
   // ProcessReflowCommands returns whether we processed all our dirty roots
   // without interruptions.
   MOZ_CAN_RUN_SCRIPT bool ProcessReflowCommands(bool aInterruptible);
@@ -550,25 +746,41 @@ class PresShell final : public nsIPresSh
   MOZ_CAN_RUN_SCRIPT void HandlePostedReflowCallbacks(bool aInterruptible);
 
   /**
    * Helper for ScrollContentIntoView()
    */
   MOZ_CAN_RUN_SCRIPT void DoScrollContentIntoView();
 
   /**
+   * Methods to handle changes to user and UA sheet lists that we get
+   * notified about.
+   */
+  void AddUserSheet(StyleSheet*);
+  void AddAgentSheet(StyleSheet*);
+  void AddAuthorSheet(StyleSheet*);
+  void RemoveSheet(StyleOrigin, StyleSheet*);
+  void RemovePreferenceStyles();
+
+  /**
    * Initialize cached font inflation preference values and do an initial
    * computation to determine if font inflation is enabled.
    *
    * @see nsLayoutUtils::sFontSizeInflationEmPerLine
    * @see nsLayoutUtils::sFontSizeInflationMinTwips
    * @see nsLayoutUtils::sFontSizeInflationLineThreshold
    */
   void SetupFontInflation();
 
+  /**
+   * Implementation methods for FlushPendingNotifications.
+   */
+  MOZ_CAN_RUN_SCRIPT void DoFlushPendingNotifications(FlushType aType);
+  MOZ_CAN_RUN_SCRIPT void DoFlushPendingNotifications(ChangesToFlush aType);
+
   struct RenderingState {
     explicit RenderingState(PresShell* aPresShell)
         : mResolution(aPresShell->mResolution),
           mRenderFlags(aPresShell->mRenderFlags) {}
     Maybe<float> mResolution;
     RenderFlags mRenderFlags;
   };
 
@@ -1524,16 +1736,30 @@ class PresShell final : public nsIPresSh
 
   // A set of frames that were visible or could be visible soon at the time
   // that we last did an approximate frame visibility update.
   VisibleFrames mApproximatelyVisibleFrames;
 
   nsresult SetResolutionImpl(float aResolution, bool aScaleToResolution,
                              nsAtom* aOrigin);
 
+#ifdef DEBUG
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY bool VerifyIncrementalReflow();
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY void DoVerifyReflow();
+  void VerifyHasDirtyRootAncestor(nsIFrame* aFrame);
+  void ShowEventTargetDebug();
+
+  bool mInVerifyReflow = false;
+  // The reflow root under which we're currently reflowing.  Null when
+  // not in reflow.
+  nsIFrame* mCurrentReflowRoot = nullptr;
+
+  nsIFrame* mDrawEventTargetFrame = nullptr;
+#endif  // #ifdef DEBUG
+
   // This is used for synthetic mouse events that are sent when what is under
   // the mouse pointer may have changed without the mouse moving (eg scrolling,
   // change to the document contents).
   // It is set only on a presshell for a root document, this value represents
   // the last observed location of the mouse relative to that root document. It
   // is set to (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if the mouse isn't
   // over our window or there is no last observed mouse location for some
   // reason.
@@ -1572,27 +1798,47 @@ class PresShell final : public nsIPresSh
 
   // Information needed to properly handle scrolling content into view if the
   // pre-scroll reflow flush can be interrupted.  mContentToScrollTo is non-null
   // between the initial scroll attempt and the first time we finish processing
   // all our dirty roots.  mContentToScrollTo has a content property storing the
   // details for the scroll operation, see ScrollIntoViewData above.
   nsCOMPtr<nsIContent> mContentToScrollTo;
 
+#ifdef ACCESSIBILITY
+  a11y::DocAccessible* mDocAccessible;
+#endif  // #ifdef ACCESSIBILITY
+
+  nsSize mVisualViewportSize;
+
+  mozilla::Maybe<nsPoint> mVisualViewportOffset;
+
   TimeStamp mLastOSWake;
 
   // The focus sequence number of the last processed input event
   uint64_t mAPZFocusSequenceNumber;
   // The focus information needed for async keyboard scrolling
   FocusTarget mAPZFocusTarget;
 
   nscoord mLastAnchorScrollPositionY = 0;
 
   int32_t mActiveSuppressDisplayport;
 
+  // True if a layout flush might not be a no-op
+  bool mNeedLayoutFlush : 1;
+
+  // True if a style flush might not be a no-op
+  bool mNeedStyleFlush : 1;
+
+  // True if there are throttled animations that would be processed when
+  // performing a flush with mFlushAnimations == true.
+  bool mNeedThrottledAnimationFlush : 1;
+
+  bool mVisualViewportSizeSet : 1;
+
   bool mDocumentLoading : 1;
   bool mNoDelayedMouseEvents : 1;
   bool mNoDelayedKeyEvents : 1;
 
   bool mApproximateFrameVisibilityVisited : 1;
 
   bool mNextPaintCompressed : 1;
 
@@ -1642,11 +1888,13 @@ class PresShell final : public nsIPresSh
   };
   static CapturingContentInfo sCapturingContentInfo;
 
   static bool sDisableNonTestMouseEvents;
 
   static bool sProcessInteractable;
 };
 
+NS_DEFINE_STATIC_IID_ACCESSOR(PresShell, NS_PRESSHELL_IID)
+
 }  // namespace mozilla
 
 #endif  // mozilla_PresShell_h
rename from layout/base/nsIPresShellInlines.h
rename to layout/base/PresShellInlines.h
--- a/layout/base/nsIPresShellInlines.h
+++ b/layout/base/PresShellInlines.h
@@ -1,74 +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/. */
 
-#ifndef nsIPresShellInlines_h
-#define nsIPresShellInlines_h
+#ifndef mozilla_PresShellInlines_h
+#define mozilla_PresShellInlines_h
 
 #include "mozilla/PresShell.h"
 #include "mozilla/dom/Document.h"
 #include "mozilla/dom/Element.h"
 
-void nsIPresShell::SetNeedLayoutFlush() {
+namespace mozilla {
+
+void PresShell::SetNeedLayoutFlush() {
   mNeedLayoutFlush = true;
-  if (mozilla::dom::Document* doc = mDocument->GetDisplayDocument()) {
-    if (mozilla::PresShell* shell = doc->GetPresShell()) {
-      shell->mNeedLayoutFlush = true;
+  if (dom::Document* doc = mDocument->GetDisplayDocument()) {
+    if (PresShell* presShell = doc->GetPresShell()) {
+      presShell->mNeedLayoutFlush = true;
     }
   }
 
 #ifdef MOZ_GECKO_PROFILER
   if (!mReflowCause) {
     mReflowCause = profiler_get_backtrace();
   }
 #endif
 }
 
-void nsIPresShell::SetNeedStyleFlush() {
+void PresShell::SetNeedStyleFlush() {
   mNeedStyleFlush = true;
-  if (mozilla::dom::Document* doc = mDocument->GetDisplayDocument()) {
-    if (mozilla::PresShell* presShell = doc->GetPresShell()) {
+  if (dom::Document* doc = mDocument->GetDisplayDocument()) {
+    if (PresShell* presShell = doc->GetPresShell()) {
       presShell->mNeedStyleFlush = true;
     }
   }
 
 #ifdef MOZ_GECKO_PROFILER
   if (!mStyleCause) {
     mStyleCause = profiler_get_backtrace();
   }
 #endif
 }
 
-void nsIPresShell::EnsureStyleFlush() {
+void PresShell::EnsureStyleFlush() {
   SetNeedStyleFlush();
   ObserveStyleFlushes();
 }
 
-void nsIPresShell::SetNeedThrottledAnimationFlush() {
+void PresShell::SetNeedThrottledAnimationFlush() {
   mNeedThrottledAnimationFlush = true;
-  if (mozilla::dom::Document* doc = mDocument->GetDisplayDocument()) {
-    if (mozilla::PresShell* presShell = doc->GetPresShell()) {
+  if (dom::Document* doc = mDocument->GetDisplayDocument()) {
+    if (PresShell* presShell = doc->GetPresShell()) {
       presShell->mNeedThrottledAnimationFlush = true;
     }
   }
 }
 
-mozilla::ServoStyleSet* nsIPresShell::StyleSet() const {
+ServoStyleSet* PresShell::StyleSet() const {
   return mDocument->StyleSetForPresShellOrMediaQueryEvaluation();
 }
 
-namespace mozilla {
-
 /* static */
 inline void PresShell::EventHandler::OnPresShellDestroy(Document* aDocument) {
   if (sLastKeyDownEventTargetElement &&
       sLastKeyDownEventTargetElement->OwnerDoc() == aDocument) {
     sLastKeyDownEventTargetElement = nullptr;
   }
 }
 
 }  // namespace mozilla
 
-#endif  // nsIPresShellInlines_h
+#endif  // mozilla_PresShellInlines_h
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/ComputedStyle.h"
 #include "mozilla/ComputedStyleInlines.h"
 #include "mozilla/DocumentStyleRootIterator.h"
 #include "mozilla/GeckoBindings.h"
 #include "mozilla/LayerAnimationInfo.h"
 #include "mozilla/layers/AnimationInfo.h"
 #include "mozilla/layout/ScrollAnchorContainer.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/ServoStyleSetInlines.h"
 #include "mozilla/Unused.h"
 #include "mozilla/ViewportFrame.h"
 #include "mozilla/dom/ChildIterator.h"
 #include "mozilla/dom/DocumentInlines.h"
 #include "mozilla/dom/ElementInlines.h"
 #include "mozilla/dom/HTMLBodyElement.h"
@@ -30,17 +31,16 @@
 #include "nsBlockFrame.h"
 #include "nsBulletFrame.h"
 #include "nsContentUtils.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsCSSRendering.h"
 #include "nsIFrame.h"
 #include "nsIFrameInlines.h"
 #include "nsImageFrame.h"
-#include "nsIPresShellInlines.h"
 #include "nsPlaceholderFrame.h"
 #include "nsPrintfCString.h"
 #include "nsRefreshDriver.h"
 #include "nsStyleChangeList.h"
 #include "nsStyleUtil.h"
 #include "nsTransitionManager.h"
 #include "StickyScrollContainer.h"
 #include "mozilla/EffectSet.h"
--- a/layout/base/moz.build
+++ b/layout/base/moz.build
@@ -48,17 +48,16 @@ EXPORTS += [
     'nsCSSFrameConstructor.h',
     'nsFrameManager.h',
     'nsFrameTraversal.h',
     'nsGenConList.h',
     'nsIFrameTraversal.h',
     'nsILayoutDebugger.h',
     'nsIPercentBSizeObserver.h',
     'nsIPresShell.h',
-    'nsIPresShellInlines.h',
     'nsIReflowCallback.h',
     'nsLayoutUtils.h',
     'nsPresArena.h',
     'nsPresArenaObjectList.h',
     'nsPresContext.h',
     'nsPresContextInlines.h',
     'nsQuoteList.h',
     'nsRefreshDriver.h',
@@ -76,16 +75,17 @@ EXPORTS.mozilla += [
     'AccessibleCaretEventHub.h',
     'ArenaObjectID.h',
     'GeckoMVMContext.h',
     'GeometryUtils.h',
     'MVMContext.h',
     'OverflowChangedTracker.h',
     'PresShell.h',
     'PresShellForwards.h',
+    'PresShellInlines.h',
     'RestyleManager.h',
     'ScrollStyles.h',
     'ScrollTypes.h',
     'ShapeUtils.h',
     'StaticPresData.h',
 ]
 
 UNIFIED_SOURCES += [
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -20,16 +20,17 @@
 #include "mozilla/dom/HTMLSelectElement.h"
 #include "mozilla/dom/HTMLSharedListElement.h"
 #include "mozilla/dom/HTMLSummaryElement.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/Likely.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/ServoStyleSetInlines.h"
 #include "mozilla/StaticPrefs.h"
 #include "nsAbsoluteContainingBlock.h"
 #include "nsCSSPseudoElements.h"
 #include "nsAtom.h"
 #include "nsIFrameInlines.h"
 #include "nsGkAtoms.h"
@@ -118,17 +119,16 @@
 
 #include "nsMathMLParts.h"
 #include "mozilla/dom/SVGTests.h"
 #include "nsSVGUtils.h"
 
 #include "nsRefreshDriver.h"
 #include "nsTextNode.h"
 #include "ActiveLayerTracker.h"
-#include "nsIPresShellInlines.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 // An alias for convenience.
 static const nsIFrame::ChildListID kPrincipalList = nsIFrame::kPrincipalList;
 
 nsIFrame* NS_NewHTMLCanvasFrame(PresShell* aPresShell, ComputedStyle* aStyle);
@@ -6882,17 +6882,18 @@ void nsCSSFrameConstructor::ContentAppen
 #ifdef DEBUG
   if (gReallyNoisyContentUpdates) {
     printf("nsCSSFrameConstructor::ContentAppended: resulting frame model:\n");
     parentFrame->List(stdout);
   }
 #endif
 
 #ifdef ACCESSIBILITY
-  if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
+  if (nsAccessibilityService* accService =
+          PresShell::GetAccessibilityService()) {
     accService->ContentRangeInserted(mPresShell, aFirstNewContent, nullptr);
   }
 #endif
 }
 
 void nsCSSFrameConstructor::ContentInserted(nsIContent* aChild,
                                             nsILayoutHistoryState* aFrameState,
                                             InsertionKind aInsertionKind) {
@@ -6994,17 +6995,18 @@ void nsCSSFrameConstructor::ContentRange
     if (aFrameState) {
       // Restore frame state for the root scroll frame if there is one
       if (nsIFrame* rootScrollFrame = mPresShell->GetRootScrollFrame()) {
         RestoreFrameStateFor(rootScrollFrame, aFrameState);
       }
     }
 
 #ifdef ACCESSIBILITY
-    if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
+    if (nsAccessibilityService* accService =
+            PresShell::GetAccessibilityService()) {
       accService->ContentRangeInserted(mPresShell, aStartChild, aEndChild);
     }
 #endif
 
     return;
   }
 
   InsertionPoint insertion;
@@ -7360,17 +7362,18 @@ void nsCSSFrameConstructor::ContentRange
     printf(
         "nsCSSFrameConstructor::ContentRangeInserted: resulting frame "
         "model:\n");
     insertion.mParentFrame->List(stdout);
   }
 #endif
 
 #ifdef ACCESSIBILITY
-  if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
+  if (nsAccessibilityService* accService =
+          PresShell::GetAccessibilityService()) {
     accService->ContentRangeInserted(mPresShell, aStartChild, aEndChild);
   }
 #endif
 }
 
 bool nsCSSFrameConstructor::ContentRemoved(nsIContent* aChild,
                                            nsIContent* aOldNextSibling,
                                            RemoveFlags aFlags) {
@@ -7560,17 +7563,18 @@ bool nsCSSFrameConstructor::ContentRemov
       LAYOUT_PHASE_TEMP_EXIT();
       RecreateFramesForContent(grandparentFrame->GetContent(),
                                InsertionKind::Async);
       LAYOUT_PHASE_TEMP_REENTER();
       return true;
     }
 
 #ifdef ACCESSIBILITY
-    if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
+    if (nsAccessibilityService* accService =
+            PresShell::GetAccessibilityService()) {
       accService->ContentRemoved(mPresShell, aChild);
     }
 #endif
 
     // Examine the containing-block for the removed content and see if
     // :first-letter style applies.
     nsIFrame* inflowChild = childFrame;
     if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
@@ -11693,17 +11697,18 @@ void nsCSSFrameConstructor::GenerateChil
     // Pass null for the PendingBinding.
     ProcessChildren(state, aFrame->GetContent(), aFrame->Style(), aFrame, false,
                     childList, false, nullptr);
 
     aFrame->SetInitialChildList(kPrincipalList, childList);
   }
 
 #ifdef ACCESSIBILITY
-  if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
+  if (nsAccessibilityService* accService =
+          PresShell::GetAccessibilityService()) {
     if (nsIContent* child = aFrame->GetContent()->GetFirstChild()) {
       accService->ContentRangeInserted(mPresShell, child, nullptr);
     }
   }
 #endif
 
   // call XBL constructors after the frames are created
   mPresShell->GetDocument()->BindingManager()->ProcessAttachedQueue();
--- a/layout/base/nsCaret.cpp
+++ b/layout/base/nsCaret.cpp
@@ -577,17 +577,17 @@ void nsCaret::ResetBlinking() {
     return;
   }
   mBlinkRate = blinkRate;
 
   if (mBlinkTimer) {
     mBlinkTimer->Cancel();
   } else {
     nsIEventTarget* target = nullptr;
-    if (nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell)) {
+    if (RefPtr<PresShell> presShell = do_QueryReferent(mPresShell)) {
       if (nsCOMPtr<Document> doc = presShell->GetDocument()) {
         target = doc->EventTargetFor(TaskCategory::Other);
       }
     }
 
     mBlinkTimer = NS_NewTimer(target);
     if (!mBlinkTimer) {
       return;
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -217,52 +217,20 @@ class nsIPresShell : public nsStubDocume
   Document* GetDocument() const { return mDocument; }
 
   nsPresContext* GetPresContext() const { return mPresContext; }
 
   nsViewManager* GetViewManager() const { return mViewManager; }
 
   nsRefreshDriver* GetRefreshDriver() const;
 
-#ifdef ACCESSIBILITY
-  /**
-   * Return the document accessible for this pres shell if there is one.
-   */
-  mozilla::a11y::DocAccessible* GetDocAccessible() const {
-    return mDocAccessible;
-  }
-
-  /**
-   * Set the document accessible for this pres shell.
-   */
-  void SetDocAccessible(mozilla::a11y::DocAccessible* aDocAccessible) {
-    mDocAccessible = aDocAccessible;
-  }
-#endif
-
-  inline mozilla::ServoStyleSet* StyleSet() const;
-
   nsCSSFrameConstructor* FrameConstructor() const {
     return mFrameConstructor.get();
   }
 
-  /* Enable/disable author style level. Disabling author style disables the
-   * entire author level of the cascade, including the HTML preshint level.
-   */
-  // XXX these could easily be inlined, but there is a circular #include
-  // problem with nsStyleSet.
-  void SetAuthorStyleDisabled(bool aDisabled);
-  bool GetAuthorStyleDisabled() const;
-
-  /**
-   * Update the style set somehow to take into account changed prefs which
-   * affect document styling.
-   */
-  void UpdatePreferenceStyles();
-
   /**
    * FrameSelection will return the Frame based selection API.
    * You cannot go back and forth anymore with QI between nsIDOM sel and
    * nsIFrame sel.
    */
   already_AddRefed<nsFrameSelection> FrameSelection();
 
   /**
@@ -410,51 +378,16 @@ class nsIPresShell : public nsStubDocume
   nsCanvasFrame* GetCanvasFrame() const;
 
   void PostPendingScrollAnchorSelection(
       mozilla::layout::ScrollAnchorContainer* aContainer);
   void FlushPendingScrollAnchorSelections();
   void PostPendingScrollAnchorAdjustment(
       mozilla::layout::ScrollAnchorContainer* aContainer);
 
-  /**
-   * Tell the pres shell that a frame needs to be marked dirty and needs
-   * Reflow.  It's OK if this is an ancestor of the frame needing reflow as
-   * long as the ancestor chain between them doesn't cross a reflow root.
-   *
-   * The bit to add should be NS_FRAME_IS_DIRTY, NS_FRAME_HAS_DIRTY_CHILDREN
-   * or nsFrameState(0); passing 0 means that dirty bits won't be set on the
-   * frame or its ancestors/descendants, but that intrinsic widths will still
-   * be marked dirty.  Passing aIntrinsicDirty = eResize and aBitToAdd = 0
-   * would result in no work being done, so don't do that.
-   */
-  void FrameNeedsReflow(nsIFrame* aFrame,
-                        mozilla::IntrinsicDirty aIntrinsicDirty,
-                        nsFrameState aBitToAdd,
-                        mozilla::ReflowRootHandling aRootHandling =
-                            mozilla::ReflowRootHandling::InferFromBitToAdd);
-
-  /**
-   * Calls FrameNeedsReflow on all fixed position children of the root frame.
-   */
-  void MarkFixedFramesForReflow(mozilla::IntrinsicDirty aIntrinsicDirty);
-
-  /**
-   * Tell the presshell that the given frame's reflow was interrupted.  This
-   * will mark as having dirty children a path from the given frame (inclusive)
-   * to the nearest ancestor with a dirty subtree, or to the reflow root
-   * currently being reflowed if no such ancestor exists (inclusive).  This is
-   * to be done immediately after reflow of the current reflow root completes.
-   * This method must only be called during reflow, and the frame it's being
-   * called on must be in the process of being reflowed when it's called.  This
-   * method doesn't mark any intrinsic widths dirty and doesn't add any bits
-   * other than NS_FRAME_HAS_DIRTY_CHILDREN.
-   */
-  void FrameNeedsToContinueReflow(nsIFrame* aFrame);
-
   void CancelAllPendingReflows();
 
   void NotifyCounterStylesAreDirty();
 
   bool FrameIsAncestorOfDirtyRoot(nsIFrame* aFrame) const;
 
   /**
    * Destroy the frames for aElement, and reconstruct them asynchronously if
@@ -484,85 +417,16 @@ class nsIPresShell : public nsStubDocume
   bool IsSafeToFlush() const;
 
   /**
    * Informs the document's FontFaceSet that the refresh driver ticked,
    * flushing style and layout.
    */
   void NotifyFontFaceSetOnRefresh();
 
-  /**
-   * Flush pending notifications of the type specified.  This method
-   * will not affect the content model; it'll just affect style and
-   * frames. Callers that actually want up-to-date presentation (other
-   * than the document itself) should probably be calling
-   * Document::FlushPendingNotifications.
-   *
-   * This method can execute script, which can destroy this presshell object
-   * unless someone is holding a reference to it on the stack.  The presshell
-   * itself will ensure it lives up until the method returns, but callers who
-   * plan to use the presshell after this call should hold a strong ref
-   * themselves!
-   *
-   * @param aType the type of notifications to flush
-   */
-  MOZ_CAN_RUN_SCRIPT
-  void FlushPendingNotifications(mozilla::FlushType aType) {
-    if (!NeedFlush(aType)) {
-      return;
-    }
-
-    DoFlushPendingNotifications(aType);
-  }
-
-  MOZ_CAN_RUN_SCRIPT
-  void FlushPendingNotifications(mozilla::ChangesToFlush aType) {
-    if (!NeedFlush(aType.mFlushType)) {
-      return;
-    }
-
-    DoFlushPendingNotifications(aType);
-  }
-
- protected:
-  /**
-   * Implementation methods for FlushPendingNotifications.
-   */
-  MOZ_CAN_RUN_SCRIPT
-  virtual void DoFlushPendingNotifications(mozilla::FlushType aType) = 0;
-  MOZ_CAN_RUN_SCRIPT
-  virtual void DoFlushPendingNotifications(mozilla::ChangesToFlush aType) = 0;
-
- public:
-  /**
-   * Whether we might need a flush for the given flush type.  If this
-   * function returns false, we definitely don't need to flush.
-   *
-   * @param aFlushType The flush type to check.  This must be
-   *   >= FlushType::Style.  This also returns true if a throttled
-   *   animation flush is required.
-   */
-  bool NeedFlush(mozilla::FlushType aType) const {
-    // We check mInFlush to handle re-entrant calls to FlushPendingNotifications
-    // by reporting that we always need a flush in that case.  Otherwise,
-    // we could end up missing needed flushes, since we clear the mNeedXXXFlush
-    // flags at the top of FlushPendingNotifications.
-    MOZ_ASSERT(aType >= mozilla::FlushType::Style);
-    return mNeedStyleFlush ||
-           (mNeedLayoutFlush &&
-            aType >= mozilla::FlushType::InterruptibleLayout) ||
-           aType >= mozilla::FlushType::Display ||
-           mNeedThrottledAnimationFlush || mInFlush;
-  }
-
-  inline void EnsureStyleFlush();
-  inline void SetNeedStyleFlush();
-  inline void SetNeedLayoutFlush();
-  inline void SetNeedThrottledAnimationFlush();
-
   // Removes ourself from the list of layout / style / and resize refresh driver
   // observers.
   //
   // Right now this is only used for documents in the BFCache, so if you want to
   // use this for anything else you need to ensure we don't end up in those
   // lists after calling this, but before calling StartObservingRefreshDriver
   // again.
   //
@@ -577,24 +441,16 @@ class nsIPresShell : public nsStubDocume
 
   bool ObservingStyleFlushes() const { return mObservingStyleFlushes; }
   bool ObservingLayoutFlushes() const { return mObservingLayoutFlushes; }
 
   void ObserveStyleFlushes() {
     if (!ObservingStyleFlushes()) DoObserveStyleFlushes();
   }
 
-  bool NeedStyleFlush() const { return mNeedStyleFlush; }
-  /**
-   * Returns true if we might need to flush layout, even if we haven't scheduled
-   * one yet (as opposed to HasPendingReflow, which returns true if a flush is
-   * scheduled or will soon be scheduled).
-   */
-  bool NeedLayoutFlush() const { return mNeedLayoutFlush; }
-
   /**
    * Callbacks will be called even if reflow itself fails for
    * some reason.
    */
   nsresult PostReflowCallback(nsIReflowCallback* aCallback);
   void CancelReflowCallback(nsIReflowCallback* aCallback);
 
   void ScheduleBeforeFirstPaint();
@@ -662,23 +518,16 @@ class nsIPresShell : public nsStubDocume
 
   /**
    * Suppress notification of the frame manager that frames are
    * being destroyed.
    */
   void SetIgnoreFrameDestruction(bool aIgnore);
 
   /**
-   * Notification sent by a frame informing the pres shell that it is about to
-   * be destroyed.
-   * This allows any outstanding references to the frame to be cleaned up
-   */
-  void NotifyDestroyingFrame(nsIFrame* aFrame);
-
-  /**
    * Get the AccessibleCaretEventHub, if it exists. AddRefs it.
    */
   already_AddRefed<mozilla::AccessibleCaretEventHub>
   GetAccessibleCaretEventHub() const;
 
   /**
    * Get the caret, if it exists. AddRefs it.
    */
@@ -863,28 +712,16 @@ class nsIPresShell : public nsStubDocume
 
 #ifdef DEBUG
   // Debugging hooks
   virtual void ListComputedStyles(FILE* out, int32_t aIndent = 0) = 0;
 
   virtual void ListStyleSheets(FILE* out, int32_t aIndent = 0) = 0;
 #endif
 
-#ifdef ACCESSIBILITY
-  /**
-   * Return true if accessibility is active.
-   */
-  static bool IsAccessibilityActive();
-
-  /**
-   * Return accessibility service if accessibility is active.
-   */
-  static nsAccessibilityService* AccService();
-#endif
-
   /**
    * Stop all active elements (plugins and the caret) in this presentation and
    * in the presentations of subdocuments.  Resets painting to a suppressed
    * state.
    * XXX this should include image animations
    */
   virtual void Freeze() = 0;
   bool IsFrozen() { return mFrozen; }
@@ -985,20 +822,16 @@ class nsIPresShell : public nsStubDocume
       mozilla::RenderImageFlags aFlags) = 0;
 
   void AddAutoWeakFrame(AutoWeakFrame* aWeakFrame);
   void AddWeakFrame(WeakFrame* aWeakFrame);
 
   void RemoveAutoWeakFrame(AutoWeakFrame* aWeakFrame);
   void RemoveWeakFrame(WeakFrame* aWeakFrame);
 
-#ifdef DEBUG
-  nsIFrame* GetDrawEventTargetFrame() { return mDrawEventTargetFrame; }
-#endif
-
   /**
    * Stop or restart non synthetic test mouse event handling on *all*
    * presShells.
    *
    * @param aDisable If true, disable all non synthetic test mouse
    * events on all presShells.  Otherwise, enable them.
    */
   virtual void DisableNonTestMouseEvents(bool aDisable) = 0;
@@ -1323,44 +1156,16 @@ class nsIPresShell : public nsStubDocume
   bool AddRefreshObserver(nsARefreshObserver* aObserver,
                           mozilla::FlushType aFlushType);
   bool RemoveRefreshObserver(nsARefreshObserver* aObserver,
                              mozilla::FlushType aFlushType);
 
   bool AddPostRefreshObserver(nsAPostRefreshObserver* aObserver);
   bool RemovePostRefreshObserver(nsAPostRefreshObserver* aObserver);
 
-  void SetVisualViewportSize(nscoord aWidth, nscoord aHeight);
-  void ResetVisualViewportSize();
-  bool IsVisualViewportSizeSet() { return mVisualViewportSizeSet; }
-  nsSize GetVisualViewportSize() {
-    NS_ASSERTION(mVisualViewportSizeSet,
-                 "asking for visual viewport size when its not set?");
-    return mVisualViewportSize;
-  }
-
-  // This function handles all the work after VisualViewportSize is set
-  // or reset.
-  void CompleteChangeToVisualViewportSize();
-
-  /**
-   * The return value indicates whether the offset actually changed.
-   */
-  bool SetVisualViewportOffset(const nsPoint& aScrollOffset,
-                               const nsPoint& aPrevLayoutScrollPos);
-
-  nsPoint GetVisualViewportOffset() const {
-    return mVisualViewportOffset.valueOr(nsPoint());
-  }
-  bool IsVisualViewportOffsetSet() const {
-    return mVisualViewportOffset.isSome();
-  }
-
-  nsPoint GetVisualViewportOffsetRelativeToLayoutViewport() const;
-
   // Represents an update to the visual scroll offset that will be sent to APZ.
   // The update type is used to determine priority compared to other scroll
   // updates.
   struct VisualScrollUpdate {
     nsPoint mVisualScrollOffset;
     FrameMetrics::ScrollOffsetUpdateType mUpdateType;
     bool mAcknowledged = false;
   };
@@ -1409,22 +1214,16 @@ class nsIPresShell : public nsStubDocume
   bool HasPendingReflow() const {
     return mObservingLayoutFlushes || mReflowContinueTimer;
   }
 
   void SyncWindowProperties(nsView* aView);
 
   virtual Document* GetPrimaryContentDocument() = 0;
 
-  // aSheetType is one of the nsIStyleSheetService *_SHEET constants.
-  void NotifyStyleSheetServiceSheetAdded(mozilla::StyleSheet* aSheet,
-                                         uint32_t aSheetType);
-  void NotifyStyleSheetServiceSheetRemoved(mozilla::StyleSheet* aSheet,
-                                           uint32_t aSheetType);
-
   struct MOZ_RAII AutoAssertNoFlush {
     explicit AutoAssertNoFlush(nsIPresShell& aShell)
         : mShell(aShell), mOldForbidden(mShell.mForbiddenToFlush) {
       mShell.mForbiddenToFlush = true;
     }
 
     ~AutoAssertNoFlush() { mShell.mForbiddenToFlush = mOldForbidden; }
 
@@ -1441,42 +1240,20 @@ class nsIPresShell : public nsStubDocume
 
   void CancelPostedReflowCallbacks();
   void FlushPendingScrollAnchorAdjustments();
 
   void SetPendingVisualScrollUpdate(
       const nsPoint& aVisualViewportOffset,
       FrameMetrics::ScrollOffsetUpdateType aUpdateType);
 
-#ifdef DEBUG
-  MOZ_CAN_RUN_SCRIPT_BOUNDARY bool VerifyIncrementalReflow();
-  MOZ_CAN_RUN_SCRIPT_BOUNDARY void DoVerifyReflow();
-  void VerifyHasDirtyRootAncestor(nsIFrame* aFrame);
-  void ShowEventTargetDebug();
-
-  bool mInVerifyReflow = false;
-  // The reflow root under which we're currently reflowing.  Null when
-  // not in reflow.
-  nsIFrame* mCurrentReflowRoot = nullptr;
-#endif
-
 #ifdef MOZ_REFLOW_PERF
   mozilla::UniquePtr<ReflowCountMgr> mReflowCountMgr;
 #endif
 
-  /**
-   * Methods to handle changes to user and UA sheet lists that we get
-   * notified about.
-   */
-  void AddUserSheet(mozilla::StyleSheet*);
-  void AddAgentSheet(mozilla::StyleSheet*);
-  void AddAuthorSheet(mozilla::StyleSheet*);
-  void RemoveSheet(mozilla::StyleOrigin, mozilla::StyleSheet*);
-  void RemovePreferenceStyles();
-
   void WillDoReflow();
 
   // This data is stored as a content property (nsGkAtoms::scrolling) on
   // mContentToScrollTo when we have a pending ScrollIntoView.
   struct ScrollIntoViewData {
     mozilla::ScrollAxis mContentScrollVAxis;
     mozilla::ScrollAxis mContentScrollHAxis;
     mozilla::ScrollFlags mContentToScrollToFlags;
@@ -1493,22 +1270,16 @@ class nsIPresShell : public nsStubDocume
   // the last reflow was interrupted. In the interrupted case ScheduleReflow is
   // called off a timer, otherwise it is called directly.
   void MaybeScheduleReflow();
   // Actually schedules a reflow.  This should only be called by
   // MaybeScheduleReflow and the reflow timer ScheduleReflowOffTimer
   // sets up.
   void ScheduleReflow();
 
-  // DoReflow returns whether the reflow finished without interruption
-  // If aFrame is not the root frame, the caller must pass a non-null
-  // aOverflowTracker.
-  bool DoReflow(nsIFrame* aFrame, bool aInterruptible,
-                mozilla::OverflowChangedTracker* aOverflowTracker);
-
   // IMPORTANT: The ownership implicit in the following member variables
   // has been explicitly checked.  If you add any members to this class,
   // please make the ownership explicit (pinkerton, scc).
 
   // These are the same Document and PresContext owned by the DocViewer.
   // we must share ownership.
   RefPtr<Document> mDocument;
   RefPtr<nsPresContext> mPresContext;
@@ -1520,46 +1291,35 @@ class nsIPresShell : public nsStubDocume
   RefPtr<nsFrameSelection> mSelection;
   RefPtr<nsCaret> mCaret;
   RefPtr<nsCaret> mOriginalCaret;
   RefPtr<mozilla::AccessibleCaretEventHub> mAccessibleCaretEventHub;
   // Pointer into mFrameConstructor - this is purely so that GetRootFrame() can
   // be inlined:
   nsFrameManager* mFrameManager;
   mozilla::WeakPtr<nsDocShell> mForwardingContainer;
-#ifdef ACCESSIBILITY
-  mozilla::a11y::DocAccessible* mDocAccessible;
-#endif
 
   // The `performance.now()` value when we last started to process reflows.
   DOMHighResTimeStamp mLastReflowStart{0.0};
 
   // At least on Win32 and Mac after interupting a reflow we need to post
   // the resume reflow event off a timer to avoid event starvation because
   // posted messages are processed before other messages when the modal
   // moving/sizing loop is running, see bug 491700 for details.
   nsCOMPtr<nsITimer> mReflowContinueTimer;
 
-#ifdef DEBUG
-  nsIFrame* mDrawEventTargetFrame = nullptr;
-#endif
-
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   // We track allocated pointers in a debug-only hashtable to assert against
   // missing/double frees.
   nsTHashtable<nsPtrHashKey<void>> mAllocatedPointers;
 #endif
 
   // Count of the number of times this presshell has been painted to a window.
   uint64_t mPaintCount;
 
-  nsSize mVisualViewportSize;
-
-  mozilla::Maybe<nsPoint> mVisualViewportOffset;
-
   // A pending visual scroll offset that we will ask APZ to scroll to
   // during the next transaction. Cleared when we send the transaction.
   // Only applicable to the RCD pres shell.
   mozilla::Maybe<VisualScrollUpdate> mPendingVisualScrollUpdate;
 
   // A list of stack weak frames. This is a pointer to the last item in the
   // list.
   AutoWeakFrame* mAutoWeakFrames;
@@ -1668,39 +1428,28 @@ class nsIPresShell : public nsStubDocume
 
   bool mIsActive : 1;
   bool mFrozen : 1;
   bool mIsFirstPaint : 1;
   bool mObservesMutationsForPrint : 1;
 
   // Whether the most recent interruptible reflow was actually interrupted:
   bool mWasLastReflowInterrupted : 1;
-  bool mVisualViewportSizeSet : 1;
-
-  // True if a layout flush might not be a no-op
-  bool mNeedLayoutFlush : 1;
-
-  // True if a style flush might not be a no-op
-  bool mNeedStyleFlush : 1;
 
   // True if we're observing the refresh driver for style flushes.
   bool mObservingStyleFlushes : 1;
 
   // True if we're observing the refresh driver for layout flushes, that is, if
   // we have a reflow scheduled.
   //
   // Guaranteed to be false if mReflowContinueTimer is non-null.
   bool mObservingLayoutFlushes : 1;
 
   bool mResizeEventPending : 1;
 
-  // True if there are throttled animations that would be processed when
-  // performing a flush with mFlushAnimations == true.
-  bool mNeedThrottledAnimationFlush : 1;
-
   bool mFontSizeInflationForceEnabled : 1;
   bool mFontSizeInflationDisabledInMasterProcess : 1;
   bool mFontSizeInflationEnabled : 1;
 
   bool mPaintingIsFrozen : 1;
 
   // If a document belongs to an invisible DocShell, this flag must be set
   // to true, so we can avoid any paint calls for widget related to this
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -10,22 +10,22 @@
 #include "nsPresContextInlines.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Encoding.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 
 #include "base/basictypes.h"
 
 #include "nsCOMPtr.h"
 #include "nsCSSFrameConstructor.h"
-#include "nsIPresShellInlines.h"
 #include "nsDocShell.h"
 #include "nsIContentViewer.h"
 #include "nsPIDOMWindow.h"
 #include "mozilla/ServoStyleSet.h"
 #include "nsIContent.h"
 #include "nsIFrame.h"
 #include "mozilla/dom/Document.h"
 #include "mozilla/dom/DocumentInlines.h"
--- a/layout/base/nsStyleSheetService.cpp
+++ b/layout/base/nsStyleSheetService.cpp
@@ -5,32 +5,32 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* implementation of interface for managing user and user-agent style sheets */
 
 #include "nsStyleSheetService.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/PreloadedStyleSheet.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/Unused.h"
 #include "mozilla/css/Loader.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
 #include "nsICategoryManager.h"
 #include "nsISupportsPrimitives.h"
 #include "nsISimpleEnumerator.h"
 #include "nsNetUtil.h"
 #include "nsIConsoleService.h"
 #include "nsIObserverService.h"
-#include "nsIPresShellInlines.h"
 #include "nsLayoutStatics.h"
 #include "nsLayoutUtils.h"
 
 using namespace mozilla;
 
 nsStyleSheetService* nsStyleSheetService::gInstance = nullptr;
 
 nsStyleSheetService::nsStyleSheetService() {
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -12,17 +12,16 @@
 #include "mozilla/gfx/PathHelpers.h"
 #include "nsCOMPtr.h"
 #include "nsFocusManager.h"
 #include "nsCheckboxRadioFrame.h"
 #include "nsGkAtoms.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsHTMLParts.h"
 #include "nsIFormControl.h"
-#include "nsIPresShellInlines.h"
 #include "nsNameSpaceManager.h"
 #include "nsListControlFrame.h"
 #include "nsPIDOMWindow.h"
 #include "mozilla/PresState.h"
 #include "nsView.h"
 #include "nsViewManager.h"
 #include "nsIContentInlines.h"
 #include "nsIDOMEventListener.h"
@@ -42,16 +41,17 @@
 #include "mozilla/Likely.h"
 #include <algorithm>
 #include "nsTextNode.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/Unused.h"
 #include "gfx2DGlue.h"
 #include "mozilla/widget/nsAutoRollup.h"
 #include "nsILayoutHistoryState.h"
 
 #ifdef XP_WIN
 #  define COMBOBOX_ROLLUP_CONSUME_EVENT 0
 #else
--- a/layout/forms/nsRangeFrame.cpp
+++ b/layout/forms/nsRangeFrame.cpp
@@ -584,18 +584,18 @@ void nsRangeFrame::UpdateForValueChange(
   }
   if (IsThemed()) {
     // We don't know the exact dimensions or location of the thumb when native
     // theming is applied, so we just repaint the entire range.
     InvalidateFrame();
   }
 
 #ifdef ACCESSIBILITY
-  nsAccessibilityService* accService = nsIPresShell::AccService();
-  if (accService) {
+  if (nsAccessibilityService* accService =
+          PresShell::GetAccessibilityService()) {
     accService->RangeValueChanged(PresShell(), mContent);
   }
 #endif
 
   SchedulePaint();
 }
 
 void nsRangeFrame::DoUpdateThumbPosition(nsIFrame* aThumbFrame,
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -152,34 +152,34 @@ void nsBulletFrame::DidSetComputedStyle(
     // No image request on the new ComputedStyle.
     DeregisterAndCancelImageRequest();
   }
 
 #ifdef ACCESSIBILITY
   // Update the list bullet accessible. If old style list isn't available then
   // no need to update the accessible tree because it's not created yet.
   if (aOldComputedStyle) {
-    nsAccessibilityService* accService = nsIPresShell::AccService();
-    if (accService) {
+    if (nsAccessibilityService* accService =
+            PresShell::GetAccessibilityService()) {
       const nsStyleList* oldStyleList = aOldComputedStyle->StyleList();
       bool hadBullet = oldStyleList->GetListStyleImage() ||
                        !oldStyleList->mCounterStyle.IsNone();
 
       const nsStyleList* newStyleList = StyleList();
       bool hasBullet = newStyleList->GetListStyleImage() ||
                        !newStyleList->mCounterStyle.IsNone();
 
       if (hadBullet != hasBullet) {
         nsIContent* listItem = mContent->GetParent();
         accService->UpdateListBullet(PresContext()->GetPresShell(), listItem,
                                      hasBullet);
       }
     }
   }
-#endif
+#endif  // #ifdef ACCESSIBILITY
 }
 
 class nsDisplayBulletGeometry
     : public nsDisplayItemGenericGeometry,
       public nsImageGeometryMixin<nsDisplayBulletGeometry> {
  public:
   nsDisplayBulletGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
       : nsDisplayItemGenericGeometry(aItem, aBuilder),
--- a/layout/generic/nsFirstLetterFrame.cpp
+++ b/layout/generic/nsFirstLetterFrame.cpp
@@ -6,20 +6,20 @@
 
 /* rendering object for CSS :first-letter pseudo-element */
 
 #include "nsFirstLetterFrame.h"
 #include "nsPresContext.h"
 #include "nsPresContextInlines.h"
 #include "mozilla/ComputedStyle.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/RestyleManager.h"
 #include "mozilla/ServoStyleSet.h"
 #include "nsIContent.h"
-#include "nsIPresShellInlines.h"
 #include "nsLineLayout.h"
 #include "nsGkAtoms.h"
 #include "nsFrameManager.h"
 #include "nsPlaceholderFrame.h"
 #include "nsCSSFrameConstructor.h"
 
 using namespace mozilla;
 using namespace mozilla::layout;
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -17,16 +17,17 @@
 #include "mozilla/ComputedStyle.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/dom/ElementInlines.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/StaticPrefs.h"
 
 #include "nsCOMPtr.h"
 #include "nsFlexContainerFrame.h"
 #include "nsFrameList.h"
 #include "nsPlaceholderFrame.h"
 #include "nsPluginFrame.h"
@@ -39,17 +40,16 @@
 #include "nsCSSPseudoElements.h"
 #include "nsCSSRendering.h"
 #include "nsAtom.h"
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsTableWrapperFrame.h"
 #include "nsView.h"
 #include "nsViewManager.h"
-#include "nsIPresShellInlines.h"
 #include "nsIScrollableFrame.h"
 #include "nsPresContext.h"
 #include "nsPresContextInlines.h"
 #include "nsStyleConsts.h"
 #include "mozilla/Logging.h"
 #include "nsLayoutUtils.h"
 #include "LayoutLogging.h"
 #include "mozilla/RestyleManager.h"
--- a/layout/generic/nsFrameSetFrame.cpp
+++ b/layout/generic/nsFrameSetFrame.cpp
@@ -11,25 +11,25 @@
 #include "gfxContext.h"
 #include "gfxUtils.h"
 #include "mozilla/ComputedStyle.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Helpers.h"
 #include "mozilla/Likely.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 
 #include "nsGenericHTMLElement.h"
 #include "nsAttrValueInlines.h"
 #include "nsLeafFrame.h"
 #include "nsContainerFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsIContentInlines.h"
-#include "nsIPresShellInlines.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsHTMLParts.h"
 #include "nsNameSpaceManager.h"
 #include "nsCSSAnonBoxes.h"
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/ServoStyleSetInlines.h"
 #include "mozilla/dom/Element.h"
--- a/layout/generic/nsFrameStateBits.h
+++ b/layout/generic/nsFrameStateBits.h
@@ -112,17 +112,17 @@ FRAME_STATE_BIT(Generic, 8, NS_FRAME_OUT
 FRAME_STATE_BIT(Generic, 9, NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)
 
 // If this bit is set, then the frame and _all_ of its descendant frames need
 // to be reflowed.
 // This bit is set when the frame is first created.
 // This bit is cleared by DidReflow after the required call to Reflow has
 // finished.
 // Do not set this bit yourself if you plan to pass the frame to
-// nsIPresShell::FrameNeedsReflow.  Pass the right arguments instead.
+// PresShell::FrameNeedsReflow.  Pass the right arguments instead.
 FRAME_STATE_BIT(Generic, 10, NS_FRAME_IS_DIRTY)
 
 // If this bit is set then the frame is too deep in the frame tree, and
 // we'll stop updating it and its children, to prevent stack overflow
 // and the like.
 FRAME_STATE_BIT(Generic, 11, NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
 
 // If this bit is set, then either:
@@ -136,17 +136,17 @@ FRAME_STATE_BIT(Generic, 11, NS_FRAME_TO
 //     _actually_ need to be reflowed).
 // If this bit is set but the NS_FRAME_IS_DIRTY is not set, then Reflow still
 // needs to be called on the frame, but Reflow will likely not do as much work
 // as it would if NS_FRAME_IS_DIRTY were set. See the comment documenting
 // nsFrame::Reflow for more.
 // This bit is cleared by DidReflow after the required call to Reflow has
 // finished.
 // Do not set this bit yourself if you plan to pass the frame to
-// nsIPresShell::FrameNeedsReflow.  Pass the right arguments instead.
+// PresShell::FrameNeedsReflow.  Pass the right arguments instead.
 FRAME_STATE_BIT(Generic, 12, NS_FRAME_HAS_DIRTY_CHILDREN)
 
 // If this bit is set, the frame has an associated view
 FRAME_STATE_BIT(Generic, 13, NS_FRAME_HAS_VIEW)
 
 // If this bit is set, the frame was created from anonymous content.
 FRAME_STATE_BIT(Generic, 14, NS_FRAME_INDEPENDENT_SELECTION)
 
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -6158,18 +6158,18 @@ void ScrollFrameHelper::LayoutScrollbars
   if (!mPostedReflowCallback) {
     aState.PresShell()->PostReflowCallback(this);
     mPostedReflowCallback = true;
   }
 }
 
 #if DEBUG
 static bool ShellIsAlive(nsWeakPtr& aWeakPtr) {
-  nsCOMPtr<nsIPresShell> shell(do_QueryReferent(aWeakPtr));
-  return !!shell;
+  RefPtr<PresShell> presShell = do_QueryReferent(aWeakPtr);
+  return !!presShell;
 }
 #endif
 
 void ScrollFrameHelper::SetScrollbarEnabled(Element* aElement,
                                             nscoord aMaxPos) {
   DebugOnly<nsWeakPtr> weakShell(do_GetWeakReference(mOuter->PresShell()));
   if (aMaxPos) {
     aElement->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, true);
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -3806,30 +3806,29 @@ class nsIFrame : public nsQueryFrame {
   }
 
   /**
    * Increment the paint count of all child PresShells that were painted during
    * the last repaint.
    */
   void UpdatePaintCountForPaintedPresShells() {
     for (nsWeakPtr& item : *PaintedPresShellList()) {
-      nsCOMPtr<nsIPresShell> shell = do_QueryReferent(item);
-      if (shell) {
-        shell->IncrementPaintCount();
+      if (RefPtr<mozilla::PresShell> presShell = do_QueryReferent(item)) {
+        presShell->IncrementPaintCount();
       }
     }
   }
 
   /**
    * @return true if we painted @aPresShell during the last repaint.
    */
-  bool DidPaintPresShell(mozilla::PresShell* aShell) {
+  bool DidPaintPresShell(mozilla::PresShell* aPresShell) {
     for (nsWeakPtr& item : *PaintedPresShellList()) {
-      nsCOMPtr<nsIPresShell> shell = do_QueryReferent(item);
-      if (shell == aShell) {
+      RefPtr<mozilla::PresShell> presShell = do_QueryReferent(item);
+      if (presShell == aPresShell) {
         return true;
       }
     }
     return false;
   }
 
   /**
    * Accessors for the absolute containing block.
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -22,23 +22,23 @@
 #include "mozilla/dom/GeneratedImageContent.h"
 #include "mozilla/dom/HTMLAreaElement.h"
 #include "mozilla/dom/HTMLImageElement.h"
 #include "mozilla/dom/ResponsiveImageSelector.h"
 #include "mozilla/layers/RenderRootStateManager.h"
 #include "mozilla/layers/WebRenderLayerManager.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/Unused.h"
 
 #include "nsCOMPtr.h"
 #include "nsFontMetrics.h"
 #include "nsIImageLoadingContent.h"
 #include "nsImageLoadingContent.h"
-#include "nsIPresShellInlines.h"
 #include "nsString.h"
 #include "nsPrintfCString.h"
 #include "nsPresContext.h"
 #include "nsGkAtoms.h"
 #include "mozilla/dom/Document.h"
 #include "nsContentUtils.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsStyleConsts.h"
--- a/layout/generic/nsPlaceholderFrame.cpp
+++ b/layout/generic/nsPlaceholderFrame.cpp
@@ -11,24 +11,24 @@
 
 #include "nsPlaceholderFrame.h"
 
 #include "gfxContext.h"
 #include "gfxUtils.h"
 #include "mozilla/dom/ElementInlines.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/ServoStyleSetInlines.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsDisplayList.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsIFrameInlines.h"
 #include "nsIContentInlines.h"
-#include "nsIPresShellInlines.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 nsPlaceholderFrame* NS_NewPlaceholderFrame(PresShell* aPresShell,
                                            ComputedStyle* aStyle,
                                            nsFrameState aTypeBits) {
   return new (aPresShell)
--- a/layout/generic/nsPluginFrame.cpp
+++ b/layout/generic/nsPluginFrame.cpp
@@ -334,18 +334,19 @@ nsresult nsPluginFrame::PrepForDrawing(n
     RegisterPluginForGeometryUpdates();
   }
 
   if (!IsHidden()) {
     viewMan->SetViewVisibility(view, nsViewVisibility_kShow);
   }
 
 #ifdef ACCESSIBILITY
-  nsAccessibilityService* accService = nsIPresShell::AccService();
-  if (accService) {
+  ;
+  if (nsAccessibilityService* accService =
+          PresShell::GetAccessibilityService()) {
     accService->RecreateAccessible(PresShell(), mContent);
   }
 #endif
 
   return NS_OK;
 }
 
 #define EMBED_DEF_WIDTH 240
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -8656,18 +8656,18 @@ void nsTextFrame::Reflow(nsPresContext* 
 /**
  * Notifies accessibility about text reflow. Used by nsTextFrame::ReflowText.
  */
 class MOZ_STACK_CLASS ReflowTextA11yNotifier {
  public:
   ReflowTextA11yNotifier(nsPresContext* aPresContext, nsIContent* aContent)
       : mContent(aContent), mPresContext(aPresContext) {}
   ~ReflowTextA11yNotifier() {
-    nsAccessibilityService* accService = nsIPresShell::AccService();
-    if (accService) {
+    if (nsAccessibilityService* accService =
+            PresShell::GetAccessibilityService()) {
       accService->UpdateText(mPresContext->PresShell(), mContent);
     }
   }
 
  private:
   ReflowTextA11yNotifier();
   ReflowTextA11yNotifier(const ReflowTextA11yNotifier&);
   ReflowTextA11yNotifier& operator=(const ReflowTextA11yNotifier&);
--- a/layout/inspector/InspectorUtils.cpp
+++ b/layout/inspector/InspectorUtils.cpp
@@ -13,27 +13,27 @@
 #include "nsArray.h"
 #include "nsAutoPtr.h"
 #include "nsIServiceManager.h"
 #include "nsString.h"
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsIContentInlines.h"
 #include "mozilla/dom/Document.h"
 #include "nsIDOMWindow.h"
-#include "nsIPresShellInlines.h"
 #include "nsXBLBinding.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsIMutableArray.h"
 #include "nsBindingManager.h"
 #include "ChildIterator.h"
 #include "nsComputedDOMStyle.h"
 #include "mozilla/EventStateManager.h"
 #include "nsAtom.h"
 #include "nsRange.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/dom/CharacterData.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/CSSStyleRule.h"
 #include "mozilla/dom/InspectorUtilsBinding.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "nsCSSProps.h"
 #include "nsCSSValue.h"
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -18,16 +18,17 @@
 #include "mozilla/dom/FontFaceSetLoadEventBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/FontPropertyTypes.h"
 #include "mozilla/net/ReferrerPolicy.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/ServoCSSParser.h"
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/ServoUtils.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/LoadInfo.h"
@@ -38,17 +39,16 @@
 #include "nsIClassOfService.h"
 #include "nsIConsoleService.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIDocShell.h"
 #include "mozilla/dom/Document.h"
 #include "nsILoadContext.h"
 #include "nsINetworkPredictor.h"
-#include "nsIPresShellInlines.h"
 #include "nsIPrincipal.h"
 #include "nsISupportsPriority.h"
 #include "nsIWebNavigation.h"
 #include "nsNetUtil.h"
 #include "nsIProtocolHandler.h"
 #include "nsIInputStream.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -6,16 +6,17 @@
 
 /* Utilities for animation of computed style values */
 
 #include "mozilla/StyleAnimationValue.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/Tuple.h"
 #include "mozilla/UniquePtr.h"
 #include "nsAutoPtr.h"
 #include "nsCOMArray.h"
 #include "nsString.h"
 #include "mozilla/ComputedStyle.h"
 #include "nsComputedDOMStyle.h"
@@ -24,17 +25,16 @@
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Likely.h"
 #include "mozilla/ServoBindings.h"  // RawServoDeclarationBlock
 #include "mozilla/ServoCSSParser.h"
 #include "gfxMatrix.h"
 #include "gfxQuaternion.h"
 #include "mozilla/dom/Document.h"
 #include "nsIFrame.h"
-#include "nsIPresShellInlines.h"
 #include "gfx2DGlue.h"
 #include "mozilla/ComputedStyleInlines.h"
 #include "mozilla/layers/LayersMessages.h"
 
 using namespace mozilla;
 using namespace mozilla::css;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -8,22 +8,22 @@
 
 #include "nsComputedDOMStyle.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/FontPropertyTypes.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/StaticPtr.h"
 
 #include "nsError.h"
 #include "nsIFrame.h"
 #include "nsIFrameInlines.h"
-#include "nsIPresShellInlines.h"
 #include "mozilla/ComputedStyle.h"
 #include "nsIScrollableFrame.h"
 #include "nsContentUtils.h"
 #include "nsIContent.h"
 #include "nsStyleConsts.h"
 
 #include "nsDOMCSSValueList.h"
 #include "nsFlexContainerFrame.h"
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -7,24 +7,24 @@
 #include "nsTableFrame.h"
 
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Helpers.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/IntegerRange.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/WritingModes.h"
 
 #include "gfxContext.h"
 #include "nsCOMPtr.h"
 #include "mozilla/ComputedStyle.h"
 #include "nsStyleConsts.h"
 #include "nsIContent.h"
-#include "nsIPresShellInlines.h"
 #include "nsCellMap.h"
 #include "nsTableCellFrame.h"
 #include "nsHTMLParts.h"
 #include "nsTableColFrame.h"
 #include "nsTableColGroupFrame.h"
 #include "nsTableRowFrame.h"
 #include "nsTableRowGroupFrame.h"
 #include "nsTableWrapperFrame.h"
--- a/layout/xul/nsButtonBoxFrame.cpp
+++ b/layout/xul/nsButtonBoxFrame.cpp
@@ -194,17 +194,17 @@ void nsButtonBoxFrame::MouseClicked(Widg
   // Have the content handle the event, propagating it according to normal DOM
   // rules.
   RefPtr<mozilla::PresShell> presShell = PresContext()->GetPresShell();
   if (!presShell) {
     return;
   }
 
   // Execute the oncommand event handler.
+  nsCOMPtr<nsIContent> content = mContent;
   WidgetInputEvent* inputEvent = aEvent->AsInputEvent();
   WidgetMouseEventBase* mouseEvent = aEvent->AsMouseEventBase();
   nsContentUtils::DispatchXULCommand(
-      mContent, aEvent->IsTrusted(), nullptr, presShell,
-      inputEvent->IsControl(), inputEvent->IsAlt(), inputEvent->IsShift(),
-      inputEvent->IsMeta(),
+      content, aEvent->IsTrusted(), nullptr, presShell, inputEvent->IsControl(),
+      inputEvent->IsAlt(), inputEvent->IsShift(), inputEvent->IsMeta(),
       mouseEvent ? mouseEvent->mInputSource
                  : MouseEvent_Binding::MOZ_SOURCE_UNKNOWN);
 }
--- a/layout/xul/nsButtonBoxFrame.h
+++ b/layout/xul/nsButtonBoxFrame.h
@@ -30,16 +30,17 @@ class nsButtonBoxFrame : public nsBoxFra
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot,
                            PostDestroyData& aPostDestroyData) override;
 
   virtual nsresult HandleEvent(nsPresContext* aPresContext,
                                mozilla::WidgetGUIEvent* aEvent,
                                nsEventStatus* aEventStatus) override;
 
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   virtual void MouseClicked(mozilla::WidgetGUIEvent* aEvent);
 
   void Blurred();
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override {
     return MakeFrameName(NS_LITERAL_STRING("ButtonBoxFrame"), aResult);
   }
--- a/layout/xul/nsMenuPopupFrame.cpp
+++ b/layout/xul/nsMenuPopupFrame.cpp
@@ -1943,19 +1943,21 @@ nsMenuPopupFrame::ChangeMenuItem(nsMenuF
 
     // On Windows, a menulist should update its value whenever navigation was
     // done by the keyboard.
 #ifdef XP_WIN
     if (aFromKey && IsOpen() && IsMenuList()) {
       // Fire a command event as the new item, but we don't want to close
       // the menu, blink it, or update any other state of the menuitem. The
       // command event will cause the item to be selected.
-      nsContentUtils::DispatchXULCommand(
-          aMenuItem->GetContent(), /* aTrusted = */ true, nullptr, PresShell(),
-          false, false, false, false);
+      nsCOMPtr<nsIContent> menuItemContent = aMenuItem->GetContent();
+      RefPtr<mozilla::PresShell> presShell = PresShell();
+      nsContentUtils::DispatchXULCommand(menuItemContent, /* aTrusted = */ true,
+                                         nullptr, presShell, false, false,
+                                         false, false);
     }
 #endif
   }
 
   mCurrentMenu = aMenuItem;
 
   return NS_OK;
 }
--- a/layout/xul/nsMenuPopupFrame.h
+++ b/layout/xul/nsMenuPopupFrame.h
@@ -175,16 +175,17 @@ class nsMenuPopupFrame final : public ns
   NS_DECL_FRAMEARENA_HELPERS(nsMenuPopupFrame)
 
   explicit nsMenuPopupFrame(ComputedStyle* aStyle, nsPresContext* aPresContext);
 
   // nsMenuParent interface
   virtual nsMenuFrame* GetCurrentMenuItem() override;
   NS_IMETHOD SetCurrentMenuItem(nsMenuFrame* aMenuItem) override;
   virtual void CurrentMenuIsBeingDestroyed() override;
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   NS_IMETHOD ChangeMenuItem(nsMenuFrame* aMenuItem, bool aSelectFirstItem,
                             bool aFromKey) override;
 
   // as popups are opened asynchronously, the popup pending state is used to
   // prevent multiple requests from attempting to open the same popup twice
   nsPopupState PopupState() { return mPopupState; }
   void SetPopupState(nsPopupState aPopupState) { mPopupState = aPopupState; }
 
--- a/layout/xul/nsResizerFrame.cpp
+++ b/layout/xul/nsResizerFrame.cpp
@@ -523,12 +523,13 @@ nsResizerFrame::Direction nsResizerFrame
     }
   }
 
   return directions[index];
 }
 
 void nsResizerFrame::MouseClicked(WidgetMouseEvent* aEvent) {
   // Execute the oncommand event handler.
+  nsCOMPtr<nsIContent> content = mContent;
   nsContentUtils::DispatchXULCommand(
-      mContent, false, nullptr, nullptr, aEvent->IsControl(), aEvent->IsAlt(),
+      content, false, nullptr, nullptr, aEvent->IsControl(), aEvent->IsAlt(),
       aEvent->IsShift(), aEvent->IsMeta(), aEvent->mInputSource);
 }
--- a/layout/xul/nsResizerFrame.h
+++ b/layout/xul/nsResizerFrame.h
@@ -33,16 +33,17 @@ class nsResizerFrame final : public nsTi
                                       ComputedStyle* aStyle);
 
   explicit nsResizerFrame(ComputedStyle* aStyle, nsPresContext* aPresContext);
 
   virtual nsresult HandleEvent(nsPresContext* aPresContext,
                                mozilla::WidgetGUIEvent* aEvent,
                                nsEventStatus* aEventStatus) override;
 
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   virtual void MouseClicked(mozilla::WidgetMouseEvent* aEvent) override;
 
  protected:
   nsIContent* GetContentToResize(mozilla::PresShell* aPresShell,
                                  nsIBaseWindow** aWindow);
 
   Direction GetDirection();
 
--- a/layout/xul/nsTitleBarFrame.cpp
+++ b/layout/xul/nsTitleBarFrame.cpp
@@ -151,12 +151,13 @@ nsresult nsTitleBarFrame::HandleEvent(ns
   if (doDefault)
     return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
   else
     return NS_OK;
 }
 
 void nsTitleBarFrame::MouseClicked(WidgetMouseEvent* aEvent) {
   // Execute the oncommand event handler.
+  nsCOMPtr<nsIContent> content = mContent;
   nsContentUtils::DispatchXULCommand(
-      mContent, false, nullptr, nullptr, aEvent->IsControl(), aEvent->IsAlt(),
+      content, false, nullptr, nullptr, aEvent->IsControl(), aEvent->IsAlt(),
       aEvent->IsShift(), aEvent->IsMeta(), aEvent->mInputSource);
 }
--- a/layout/xul/nsTitleBarFrame.h
+++ b/layout/xul/nsTitleBarFrame.h
@@ -26,16 +26,17 @@ class nsTitleBarFrame : public nsBoxFram
 
   virtual void BuildDisplayListForChildren(
       nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) override;
 
   virtual nsresult HandleEvent(nsPresContext* aPresContext,
                                mozilla::WidgetGUIEvent* aEvent,
                                nsEventStatus* aEventStatus) override;
 
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   virtual void MouseClicked(mozilla::WidgetMouseEvent* aEvent);
 
   void UpdateMouseThrough() override {
     AddStateBits(NS_FRAME_MOUSE_THROUGH_NEVER);
   }
 
  protected:
   bool mTrackingMouseMove;
--- a/layout/xul/nsXULPopupManager.cpp
+++ b/layout/xul/nsXULPopupManager.cpp
@@ -2664,17 +2664,18 @@ nsXULMenuCommandEvent::Run() {
     mozilla::Unused
         << kungFuDeathGrip;  // Not referred to directly within this function
 
     // Deselect ourselves.
     if (mCloseMenuMode != CloseMenuMode_None) menuFrame->SelectMenu(false);
 
     AutoHandlingUserInputStatePusher userInpStatePusher(
         mUserInput, nullptr, presShell->GetDocument());
-    nsContentUtils::DispatchXULCommand(mMenu, mIsTrusted, nullptr, presShell,
+    RefPtr<Element> menu = mMenu;
+    nsContentUtils::DispatchXULCommand(menu, mIsTrusted, nullptr, presShell,
                                        mControl, mAlt, mShift, mMeta);
   }
 
   if (popup && mCloseMenuMode != CloseMenuMode_None)
     pm->HidePopup(popup, mCloseMenuMode == CloseMenuMode_Auto, true, false,
                   false);
 
   return NS_OK;
--- a/layout/xul/nsXULPopupManager.h
+++ b/layout/xul/nsXULPopupManager.h
@@ -295,17 +295,17 @@ class nsXULMenuCommandEvent : public moz
         mMeta(aMeta),
         mUserInput(aUserInput),
         mFlipChecked(aFlipChecked),
         mCloseMenuMode(CloseMenuMode_Auto) {
     NS_ASSERTION(aMenu,
                  "null menu supplied to nsXULMenuCommandEvent constructor");
   }
 
-  NS_IMETHOD Run() override;
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override;
 
   void SetCloseMenuMode(CloseMenuMode aCloseMenuMode) {
     mCloseMenuMode = aCloseMenuMode;
   }
 
  private:
   RefPtr<mozilla::dom::Element> mMenu;
   bool mIsTrusted;
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -395,21 +395,22 @@ nsresult nsTreeBodyFrame::SetView(nsITre
 
   // Changing the view causes us to refetch our data.  This will
   // necessarily entail a full invalidation of the tree.
   Invalidate();
 
   RefPtr<XULTreeElement> treeContent = GetBaseElement();
   if (treeContent) {
 #ifdef ACCESSIBILITY
-    nsAccessibilityService* accService = nsIPresShell::AccService();
-    if (accService)
+    if (nsAccessibilityService* accService =
+            PresShell::GetAccessibilityService()) {
       accService->TreeViewChanged(PresContext()->GetPresShell(), treeContent,
                                   mView);
-#endif
+    }
+#endif  // #ifdef ACCESSIBILITY
     FireDOMEvent(NS_LITERAL_STRING("TreeViewChanged"), treeContent);
   }
 
   if (mView) {
     // Give the view a new empty selection object to play with, but only if it
     // doesn't have one already.
     nsCOMPtr<nsITreeSelection> sel;
     mView->GetSelection(getter_AddRefs(sel));
@@ -517,56 +518,59 @@ nsresult nsTreeBodyFrame::Invalidate() {
 }
 
 nsresult nsTreeBodyFrame::InvalidateColumn(nsTreeColumn* aCol) {
   if (mUpdateBatchNest) return NS_OK;
 
   if (!aCol) return NS_ERROR_INVALID_ARG;
 
 #ifdef ACCESSIBILITY
-  if (nsIPresShell::IsAccessibilityActive())
+  if (PresShell::IsAccessibilityActive()) {
     FireInvalidateEvent(-1, -1, aCol, aCol);
-#endif
+  }
+#endif  // #ifdef ACCESSIBILITY
 
   nsRect columnRect;
   nsresult rv = aCol->GetRect(this, mInnerBox.y, mInnerBox.height, &columnRect);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // When false then column is out of view
   if (OffsetForHorzScroll(columnRect, true))
     InvalidateFrameWithRect(columnRect);
 
   return NS_OK;
 }
 
 nsresult nsTreeBodyFrame::InvalidateRow(int32_t aIndex) {
   if (mUpdateBatchNest) return NS_OK;
 
 #ifdef ACCESSIBILITY
-  if (nsIPresShell::IsAccessibilityActive())
+  if (PresShell::IsAccessibilityActive()) {
     FireInvalidateEvent(aIndex, aIndex, nullptr, nullptr);
-#endif
+  }
+#endif  // #ifdef ACCESSIBILITY
 
   aIndex -= mTopRowIndex;
   if (aIndex < 0 || aIndex > mPageLength) return NS_OK;
 
   nsRect rowRect(mInnerBox.x, mInnerBox.y + mRowHeight * aIndex,
                  mInnerBox.width, mRowHeight);
   InvalidateFrameWithRect(rowRect);
 
   return NS_OK;
 }
 
 nsresult nsTreeBodyFrame::InvalidateCell(int32_t aIndex, nsTreeColumn* aCol) {
   if (mUpdateBatchNest) return NS_OK;
 
 #ifdef ACCESSIBILITY
-  if (nsIPresShell::IsAccessibilityActive())
+  if (PresShell::IsAccessibilityActive()) {
     FireInvalidateEvent(aIndex, aIndex, aCol, aCol);
-#endif
+  }
+#endif  // #ifdef ACCESSIBILITY
 
   aIndex -= mTopRowIndex;
   if (aIndex < 0 || aIndex > mPageLength) return NS_OK;
 
   if (!aCol) return NS_ERROR_INVALID_ARG;
 
   nsRect cellRect;
   nsresult rv = aCol->GetRect(this, mInnerBox.y + mRowHeight * aIndex,
@@ -586,22 +590,22 @@ nsresult nsTreeBodyFrame::InvalidateRang
   int32_t last = LastVisibleRow();
   if (aStart > aEnd || aEnd < mTopRowIndex || aStart > last) return NS_OK;
 
   if (aStart < mTopRowIndex) aStart = mTopRowIndex;
 
   if (aEnd > last) aEnd = last;
 
 #ifdef ACCESSIBILITY
-  if (nsIPresShell::IsAccessibilityActive()) {
+  if (PresShell::IsAccessibilityActive()) {
     int32_t end =
         mRowCount > 0 ? ((mRowCount <= aEnd) ? mRowCount - 1 : aEnd) : 0;
     FireInvalidateEvent(aStart, end, nullptr, nullptr);
   }
-#endif
+#endif  // #ifdef ACCESSIBILITY
 
   nsRect rangeRect(mInnerBox.x,
                    mInnerBox.y + mRowHeight * (aStart - mTopRowIndex),
                    mInnerBox.width, mRowHeight * (aEnd - aStart + 1));
   InvalidateFrameWithRect(rangeRect);
 
   return NS_OK;
 }
@@ -1580,19 +1584,20 @@ nsresult nsTreeBodyFrame::CreateTimer(co
   timer.forget(aTimer);
   return NS_OK;
 }
 
 nsresult nsTreeBodyFrame::RowCountChanged(int32_t aIndex, int32_t aCount) {
   if (aCount == 0 || !mView) return NS_OK;  // Nothing to do.
 
 #ifdef ACCESSIBILITY
-  if (nsIPresShell::IsAccessibilityActive())
+  if (PresShell::IsAccessibilityActive()) {
     FireRowCountChangedEvent(aIndex, aCount);
-#endif
+  }
+#endif  // #ifdef ACCESSIBILITY
 
   // Adjust our selection.
   nsCOMPtr<nsITreeSelection> sel;
   mView->GetSelection(getter_AddRefs(sel));
   if (sel) sel->AdjustSelection(aIndex, aCount);
 
   if (mUpdateBatchNest) return NS_OK;
 
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/PanZoomController.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/PanZoomController.java
@@ -1,25 +1,20 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * 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/. */
 
 package org.mozilla.geckoview;
 
-import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.PrefsHelper;
 import org.mozilla.gecko.annotation.WrapForJNI;
 import org.mozilla.gecko.mozglue.JNIObject;
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.ThreadUtils;
 
-import android.app.UiModeManager;
-import android.content.Context;
-import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.SystemClock;
 import android.support.annotation.NonNull;
 import android.support.annotation.UiThread;
 import android.support.annotation.IntDef;
 import android.util.Log;
 import android.util.Pair;
 import android.view.MotionEvent;
@@ -31,24 +26,22 @@ import java.lang.annotation.RetentionPol
 import java.util.ArrayList;
 
 @UiThread
 public class PanZoomController {
     private static final String LOGTAG = "GeckoNPZC";
     private static final int EVENT_SOURCE_SCROLL = 0;
     private static final int EVENT_SOURCE_MOTION = 1;
     private static final int EVENT_SOURCE_MOUSE = 2;
-    private static final String PREF_MOUSE_AS_TOUCH = "ui.android.mouse_as_touch";
 
     private final GeckoSession mSession;
     private final Rect mTempRect = new Rect();
     private boolean mAttached;
     private float mPointerScrollFactor = 64.0f;
     private long mLastDownTime;
-    private boolean mTreatMouseAsTouch;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SCROLL_BEHAVIOR_SMOOTH, SCROLL_BEHAVIOR_AUTO})
     /* package */ @interface ScrollBehaviorType {}
 
     /**
      * Specifies smooth scrolling which animates content to the desired scroll position.
      */
@@ -230,42 +223,16 @@ public class PanZoomController {
 
         return mNative.handleMouseEvent(event.getActionMasked(), event.getEventTime(),
                                         event.getMetaState(), x, y, event.getButtonState());
     }
 
     protected PanZoomController(final GeckoSession session) {
         mSession = session;
         enableEventQueue();
-        initMouseAsTouch();
-    }
-
-    private void initMouseAsTouch() {
-        mTreatMouseAsTouch = true;
-
-        PrefsHelper.PrefHandler prefHandler = new PrefsHelper.PrefHandlerBase() {
-            @Override
-            public void prefValue(final String pref, final int value) {
-                if (!PREF_MOUSE_AS_TOUCH.equals(pref)) {
-                    return;
-                }
-                if (value == 0) {
-                    mTreatMouseAsTouch = false;
-                } else if (value == 1) {
-                    mTreatMouseAsTouch = true;
-                } else if (value == 2) {
-                    Context c = GeckoAppShell.getApplicationContext();
-                    UiModeManager m = (UiModeManager)c.getSystemService(Context.UI_MODE_SERVICE);
-                    // on TV devices, treat mouse as touch. everywhere else, don't
-                    mTreatMouseAsTouch = (m.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION);
-                }
-            }
-        };
-        PrefsHelper.addObserver(new String[] { PREF_MOUSE_AS_TOUCH }, prefHandler);
-        PrefsHelper.getPref(PREF_MOUSE_AS_TOUCH, prefHandler);
     }
 
     /**
      * Set the current scroll factor. The scroll factor is the maximum scroll amount that
      * one scroll event may generate, in device pixels.
      *
      * @param factor Scroll factor.
      */
@@ -289,20 +256,16 @@ public class PanZoomController {
      * "touch" rather than as "mouse". Pointer coordinates should be relative to the
      * display surface.
      *
      * @param event MotionEvent to process.
      * @return True if the event was handled.
      */
     public boolean onTouchEvent(final @NonNull MotionEvent event) {
         ThreadUtils.assertOnUiThread();
-
-        if (!mTreatMouseAsTouch && event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
-            return handleMouseEvent(event);
-        }
         return handleMotionEvent(event);
     }
 
     /**
      * Process a touch event through the pan-zoom controller. Treat any mouse events as
      * "mouse" rather than as "touch". Pointer coordinates should be relative to the
      * display surface.
      *
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -279,18 +279,16 @@ pref("dom.script_loader.binast_encoding.
 pref("dom.window.event.enabled", true);
 
 // Fastback caching - if this pref is negative, then we calculate the number
 // of content viewers to cache based on the amount of available memory.
 pref("browser.sessionhistory.max_total_viewers", -1);
 
 pref("ui.use_native_colors", true);
 pref("ui.click_hold_context_menus", false);
-// 0 = false, 1 = true, 2 = autodetect.
-pref("ui.android.mouse_as_touch", 1);
 
 // Pop up context menu on mouseup instead of mousedown, if that's the OS default.
 // Note: ignored on Windows (context menus always use mouseup)
 pref("ui.context_menus.after_mouseup", false);
 // Duration of timeout of incremental search in menus (ms).  0 means infinite.
 pref("ui.menu.incremental_search.timeout", 1000);
 // If true, all popups won't hide automatically on blur
 pref("ui.popup.disable_autohide", false);
--- a/mozglue/tests/interceptor/TestDllInterceptor.cpp
+++ b/mozglue/tests/interceptor/TestDllInterceptor.cpp
@@ -4,17 +4,19 @@
 
 #include <shlobj.h>
 #include <stdio.h>
 #include <commdlg.h>
 #define SECURITY_WIN32
 #include <security.h>
 #include <wininet.h>
 #include <schnlsp.h>
+#include <winternl.h>
 
+#include "mozilla/DynamicallyLinkedFunctionPtr.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WindowsVersion.h"
 #include "nsWindowsDllInterceptor.h"
 #include "nsWindowsHelpers.h"
 
 NTSTATUS NTAPI NtFlushBuffersFile(HANDLE, PIO_STATUS_BLOCK);
 NTSTATUS NTAPI NtReadFile(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID,
@@ -44,16 +46,18 @@ NTSTATUS NTAPI NtMapViewOfSection(
 
 // These pointers are disguised as PVOID to avoid pulling in obscure headers
 PVOID NTAPI LdrResolveDelayLoadedAPI(PVOID, PVOID, PVOID, PVOID, PVOID, ULONG);
 void CALLBACK ProcessCaretEvents(HWINEVENTHOOK, DWORD, HWND, LONG, LONG, DWORD,
                                  DWORD);
 void __fastcall BaseThreadInitThunk(BOOL aIsInitialThread, void* aStartAddress,
                                     void* aThreadParam);
 
+BOOL WINAPI ApiSetQueryApiSetPresence(PCUNICODE_STRING, PBOOLEAN);
+
 using namespace mozilla;
 
 struct payload {
   UINT64 a;
   UINT64 b;
   UINT64 c;
 
   bool operator==(const payload& other) const {
@@ -408,47 +412,58 @@ bool MaybeTestHook(const bool cond, cons
       reinterpret_cast<bool (*)(typename ReturnType<decltype(&func)>::Type)>( \
           NULL))
 
 bool ShouldTestTipTsf() {
   if (!IsWin8OrLater()) {
     return false;
   }
 
-  nsModuleHandle shell32(LoadLibraryW(L"shell32.dll"));
-  if (!shell32) {
-    return true;
-  }
-
-  auto pSHGetKnownFolderPath =
-      reinterpret_cast<decltype(&SHGetKnownFolderPath)>(
-          GetProcAddress(shell32, "SHGetKnownFolderPath"));
+  mozilla::DynamicallyLinkedFunctionPtr<decltype(&SHGetKnownFolderPath)>
+    pSHGetKnownFolderPath(L"shell32.dll", "SHGetKnownFolderPath");
   if (!pSHGetKnownFolderPath) {
-    return true;
+    return false;
   }
 
   PWSTR commonFilesPath = nullptr;
   if (FAILED(pSHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, nullptr,
                                    &commonFilesPath))) {
-    return true;
+    return false;
   }
 
   wchar_t fullPath[MAX_PATH + 1] = {};
   wcscpy(fullPath, commonFilesPath);
   wcscat(fullPath, L"\\Microsoft Shared\\Ink\\tiptsf.dll");
   CoTaskMemFree(commonFilesPath);
 
   if (!LoadLibraryW(fullPath)) {
     return false;
   }
 
   // Leak the module so that it's loaded for the interceptor test
   return true;
 }
 
+static const wchar_t gEmptyUnicodeStringLiteral[] = L"";
+static UNICODE_STRING gEmptyUnicodeString;
+static BOOLEAN gIsPresent;
+
+bool HasApiSetQueryApiSetPresence() {
+  mozilla::DynamicallyLinkedFunctionPtr<decltype(&ApiSetQueryApiSetPresence)>
+    func(L"Api-ms-win-core-apiquery-l1-1-0.dll", "ApiSetQueryApiSetPresence");
+  if (!func) {
+    return false;
+  }
+
+  // Prepare gEmptyUnicodeString for the test
+  ::RtlInitUnicodeString(&gEmptyUnicodeString, gEmptyUnicodeStringLiteral);
+
+  return true;
+}
+
 #if defined(_M_X64)
 
 // Use VMSharingPolicyUnique for the TenByteInterceptor, as it needs to
 // reserve its trampoline memory in a special location.
 using TenByteInterceptor = mozilla::interceptor::WindowsDllInterceptor<
     mozilla::interceptor::VMSharingPolicyUnique<
         mozilla::interceptor::MMPolicyInProcess,
         mozilla::interceptor::kDefaultTrampolineSize>>;
@@ -677,17 +692,19 @@ extern "C" int wmain(int argc, wchar_t* 
 
       TEST_HOOK(sspicli.dll, AcquireCredentialsHandleA, NotEquals, SEC_E_OK) &&
       TEST_HOOK(sspicli.dll, QueryCredentialsAttributesA, NotEquals,
                 SEC_E_OK) &&
 #if !defined(_M_ARM64)
       TEST_HOOK(sspicli.dll, FreeCredentialsHandle, NotEquals, SEC_E_OK) &&
 #endif
       TEST_DETOUR_SKIP_EXEC(kernel32.dll, BaseThreadInitThunk) &&
-      TEST_DETOUR_SKIP_EXEC(ntdll.dll, LdrLoadDll) && TestTenByteDetour()) {
+      TEST_DETOUR_SKIP_EXEC(ntdll.dll, LdrLoadDll) &&
+      MAYBE_TEST_HOOK_PARAMS(HasApiSetQueryApiSetPresence(), Api-ms-win-core-apiquery-l1-1-0.dll, ApiSetQueryApiSetPresence, Equals, FALSE, &gEmptyUnicodeString, &gIsPresent) &&
+      TestTenByteDetour()) {
     printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n");
 
     LARGE_INTEGER end, freq;
     QueryPerformanceCounter(&end);
 
     QueryPerformanceFrequency(&freq);
 
     LARGE_INTEGER result;
--- a/mozglue/tests/interceptor/moz.build
+++ b/mozglue/tests/interceptor/moz.build
@@ -16,16 +16,17 @@ if CONFIG['OS_TARGET'] == 'WINNT' and CO
     GeckoCppUnitTests(
         [
           'TestDllInterceptorCrossProcess',
         ],
         linkage=None
     )
 
 OS_LIBS += [
+    'ntdll',
     'ole32',
 ]
 
 if CONFIG['OS_TARGET'] == 'WINNT' and CONFIG['CC_TYPE'] in ('gcc', 'clang'):
     # This allows us to use wmain as the entry point on mingw
     LDFLAGS += [
         '-municode',
     ]
--- a/python/mozbuild/mozbuild/action/tooltool.py
+++ b/python/mozbuild/mozbuild/action/tooltool.py
@@ -17,39 +17,59 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 # 02110-1301, USA.
 
 # A manifest file specifies files in that directory that are stored
 # elsewhere. This file should only list files in the same directory
 # in which the manifest file resides and it should be called
 # 'manifest.tt'
 
+from __future__ import print_function
+
+import base64
+import calendar
 import hashlib
+import hmac
 import httplib
 import json
 import logging
+import math
 import optparse
 import os
+import pprint
+import re
 import shutil
 import sys
 import tarfile
 import tempfile
 import threading
 import time
 import urllib2
 import urlparse
 import zipfile
 
 from subprocess import PIPE
 from subprocess import Popen
 
 __version__ = '1'
 
+# Allowed request header characters:
+# !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9, \, "
+REQUEST_HEADER_ATTRIBUTE_CHARS = re.compile(
+    r"^[ a-zA-Z0-9_\!#\$%&'\(\)\*\+,\-\./\:;<\=>\?@\[\]\^`\{\|\}~]*$")
 DEFAULT_MANIFEST_NAME = 'manifest.tt'
 TOOLTOOL_PACKAGE_SUFFIX = '.TOOLTOOL-PACKAGE'
+HAWK_VER = 1
+PY3 = sys.version_info[0] == 3
+
+if PY3:
+    # TODO: py3 coverage
+    six_binary_type = bytes  # pragma: no cover
+else:
+    six_binary_type = str
 
 
 log = logging.getLogger(__name__)
 
 
 class FileRecordJSONEncoderException(Exception):
     pass
 
@@ -72,32 +92,231 @@ class BadFilenameException(ExceptionWith
 class DigestMismatchException(ExceptionWithFilename):
     pass
 
 
 class MissingFileException(ExceptionWithFilename):
     pass
 
 
+class InvalidCredentials(Exception):
+    pass
+
+
+class BadHeaderValue(Exception):
+    pass
+
+
+def parse_url(url):
+    url_parts = urlparse.urlparse(url)
+    url_dict = {
+        'scheme': url_parts.scheme,
+        'hostname': url_parts.hostname,
+        'port': url_parts.port,
+        'path': url_parts.path,
+        'resource': url_parts.path,
+        'query': url_parts.query,
+    }
+    if len(url_dict['query']) > 0:
+        url_dict['resource'] = '%s?%s' % (url_dict['resource'],  # pragma: no cover
+                                          url_dict['query'])
+
+    if url_parts.port is None:
+        if url_parts.scheme == 'http':
+            url_dict['port'] = 80
+        elif url_parts.scheme == 'https':  # pragma: no cover
+            url_dict['port'] = 443
+    return url_dict
+
+
+def utc_now(offset_in_seconds=0.0):
+    return int(math.floor(calendar.timegm(time.gmtime()) + float(offset_in_seconds)))
+
+
+def random_string(length):
+    return base64.urlsafe_b64encode(os.urandom(length))[:length]
+
+
+def prepare_header_val(val):
+    if isinstance(val, six_binary_type):
+        val = val.decode('utf-8')
+
+    if not REQUEST_HEADER_ATTRIBUTE_CHARS.match(val):
+        raise BadHeaderValue(  # pragma: no cover
+            'header value value={val} contained an illegal character'.format(val=repr(val)))
+
+    return val
+
+
+def parse_content_type(content_type):  # pragma: no cover
+    if content_type:
+        return content_type.split(';')[0].strip().lower()
+    else:
+        return ''
+
+
+def calculate_payload_hash(algorithm, payload, content_type):  # pragma: no cover
+    parts = [
+        part if isinstance(part, six_binary_type) else part.encode('utf8')
+        for part in ['hawk.' + str(HAWK_VER) + '.payload\n',
+                     parse_content_type(content_type) + '\n',
+                     payload or '',
+                     '\n',
+                     ]
+    ]
+
+    p_hash = hashlib.new(algorithm)
+    p_hash.update(''.join(parts))
+
+    log.debug('calculating payload hash from:\n{parts}'.format(parts=pprint.pformat(parts)))
+
+    return base64.b64encode(p_hash.digest())
+
+
+def validate_taskcluster_credentials(credentials):
+    if not hasattr(credentials, '__getitem__'):
+        raise InvalidCredentials('credentials must be a dict-like object')  # pragma: no cover
+    try:
+        credentials['clientId']
+        credentials['accessToken']
+    except KeyError:  # pragma: no cover
+        etype, val, tb = sys.exc_info()
+        raise InvalidCredentials('{etype}: {val}'.format(etype=etype, val=val))
+
+
+def normalize_header_attr(val):
+    if isinstance(val, six_binary_type):
+        return val.decode('utf-8')
+    return val  # pragma: no cover
+
+
+def normalize_string(mac_type,
+                     timestamp,
+                     nonce,
+                     method,
+                     name,
+                     host,
+                     port,
+                     content_hash,
+                     ):
+    return '\n'.join([
+        normalize_header_attr(header)
+        # The blank lines are important. They follow what the Node Hawk lib does.
+        for header in ['hawk.' + str(HAWK_VER) + '.' + mac_type,
+                       timestamp,
+                       nonce,
+                       method or '',
+                       name or '',
+                       host,
+                       port,
+                       content_hash or ''
+                       '',  # for ext which is empty in this case
+                       '',  # Add trailing new line.
+                       ]
+    ])
+
+
+def calculate_mac(mac_type,
+                  access_token,
+                  algorithm,
+                  timestamp,
+                  nonce,
+                  method,
+                  name,
+                  host,
+                  port,
+                  content_hash,
+                  ):
+    normalized = normalize_string(mac_type,
+                                  timestamp,
+                                  nonce,
+                                  method,
+                                  name,
+                                  host,
+                                  port,
+                                  content_hash)
+    log.debug(u'normalized resource for mac calc: {norm}'.format(norm=normalized))
+    digestmod = getattr(hashlib, algorithm)
+
+    # Make sure we are about to hash binary strings.
+
+    if not isinstance(normalized, six_binary_type):
+        normalized = normalized.encode('utf8')
+
+    if not isinstance(access_token, six_binary_type):
+        access_token = access_token.encode('ascii')
+
+    result = hmac.new(access_token, normalized, digestmod)
+    return base64.b64encode(result.digest())
+
+
+def make_taskcluster_header(credentials, req):
+    validate_taskcluster_credentials(credentials)
+
+    url = req.get_full_url()
+    method = req.get_method()
+    algorithm = 'sha256'
+    timestamp = str(utc_now())
+    nonce = random_string(6)
+    url_parts = parse_url(url)
+
+    content_hash = None
+    if req.has_data():
+        content_hash = calculate_payload_hash(  # pragma: no cover
+            algorithm,
+            req.get_data(),
+            req.get_method(),
+        )
+
+    mac = calculate_mac('header',
+                        credentials['accessToken'],
+                        algorithm,
+                        timestamp,
+                        nonce,
+                        method,
+                        url_parts['resource'],
+                        url_parts['hostname'],
+                        str(url_parts['port']),
+                        content_hash,
+                        )
+
+    header = u'Hawk mac="{}"'.format(prepare_header_val(mac))
+
+    if content_hash:  # pragma: no cover
+        header = u'{}, hash="{}"'.format(header, prepare_header_val(content_hash))
+
+    header = u'{header}, id="{id}", ts="{ts}", nonce="{nonce}"'.format(
+        header=header,
+        id=prepare_header_val(credentials['clientId']),
+        ts=prepare_header_val(timestamp),
+        nonce=prepare_header_val(nonce),
+    )
+
+    log.debug('Hawk header for URL={} method={}: {}'.format(url, method, header))
+
+    return header
+
+
 class FileRecord(object):
 
     def __init__(self, filename, size, digest, algorithm, unpack=False,
-                 version=None, visibility=None):
+                 version=None, visibility=None, setup=None):
         object.__init__(self)
         if '/' in filename or '\\' in filename:
             log.error(
                 "The filename provided contains path information and is, therefore, invalid.")
             raise BadFilenameException(filename=filename)
         self.filename = filename
         self.size = size
         self.digest = digest
         self.algorithm = algorithm
         self.unpack = unpack
         self.version = version
         self.visibility = visibility
+        self.setup = setup
 
     def __eq__(self, other):
         if self is other:
             return True
         if self.filename == other.filename and \
            self.size == other.size and \
            self.digest == other.digest and \
            self.algorithm == other.algorithm and \
@@ -179,16 +398,18 @@ class FileRecordJSONEncoder(json.JSONEnc
                 'digest': obj.digest,
             }
             if obj.unpack:
                 rv['unpack'] = True
             if obj.version:
                 rv['version'] = obj.version
             if obj.visibility is not None:
                 rv['visibility'] = obj.visibility
+            if obj.setup:
+                rv['setup'] = obj.setup
             return rv
 
     def default(self, f):
         if issubclass(type(f), list):
             record_list = []
             for i in f:
                 record_list.append(self.encode_file_record(i))
             return record_list
@@ -224,19 +445,20 @@ class FileRecordJSONDecoder(json.JSONDec
                 if req not in obj:
                     missing = True
                     break
 
             if not missing:
                 unpack = obj.get('unpack', False)
                 version = obj.get('version', None)
                 visibility = obj.get('visibility', None)
+                setup = obj.get('setup')
                 rv = FileRecord(
                     obj['filename'], obj['size'], obj['digest'], obj['algorithm'],
-                    unpack, version, visibility)
+                    unpack, version, visibility, setup)
                 log.debug("materialized %s" % rv)
                 return rv
         return obj
 
     def decode(self, s):
         decoded = json.JSONDecoder.decode(self, s)
         rv = self.process_file_records(decoded)
         return rv
@@ -329,17 +551,17 @@ def digest_file(f, a):
         data = f.read(chunk_size)
     name = repr(f.name) if hasattr(f, 'name') else 'a file'
     log.debug('hashed %s with %s to be %s', name, a, h.hexdigest())
     return h.hexdigest()
 
 
 def execute(cmd):
     """Execute CMD, logging its stdout at the info level"""
-    process = Popen(cmd, shell=True, stdout=PIPE)
+    process = Popen(cmd, shell=True, stdout=PIPE, bufsize=0)
     while True:
         line = process.stdout.readline()
         if not line:
             break
         log.info(line.replace('\n', ' '))
     return process.wait() == 0
 
 
@@ -530,17 +752,17 @@ def _cache_checksum_matches(base_file, c
         return False
 
 
 def _compute_cache_checksum(filename):
     with open(filename, "rb") as f:
         return digest_file(f, "sha256")
 
 
-def unpack_file(filename):
+def unpack_file(filename, setup=None):
     """Untar `filename`, assuming it is uncompressed or compressed with bzip2,
     xz, gzip, or unzip a zip file. The file is assumed to contain a single
     directory with a name matching the base of the given filename.
     Xz support is handled by shelling out to 'tar'."""
 
     checksum = _compute_cache_checksum(filename)
 
     if tarfile.is_tarfile(filename):
@@ -574,16 +796,19 @@ def unpack_file(filename):
         log.info('unzipping "%s"' % filename)
         z = zipfile.ZipFile(filename)
         z.extractall()
         z.close()
     else:
         log.error("Unknown archive extension for filename '%s'" % filename)
         return False
 
+    if setup and not execute(os.path.join(base_file, setup)):
+        return False
+
     with open(base_file + CHECKSUM_SUFFIX, "wb") as f:
         f.write(checksum)
 
     return True
 
 
 def fetch_files(manifest_file, base_urls, filenames=[], cache_folder=None,
                 auth_file=None, region=None):
@@ -604,16 +829,19 @@ def fetch_files(manifest_file, base_urls
     # We want to track files that fail to be fetched as well as
     # files that are fetched
     failed_files = []
     fetched_files = []
 
     # Files that we want to unpack.
     unpack_files = []
 
+    # Setup for unpacked files.
+    setup_files = {}
+
     # Lets go through the manifest and fetch the files that we want
     for f in manifest.file_records:
         # case 1: files are already present
         if f.present():
             if f.validate():
                 present_files.append(f.filename)
                 if f.unpack:
                     unpack_files.append(f.filename)
@@ -663,16 +891,23 @@ def fetch_files(manifest_file, base_urls
             temp_file_name = fetch_file(base_urls, f, auth_file=auth_file, region=region)
             if temp_file_name:
                 fetched_files.append((f, temp_file_name))
             else:
                 failed_files.append(f.filename)
         else:
             log.debug("skipping %s" % f.filename)
 
+        if f.setup:
+            if f.unpack:
+                setup_files[f.filename] = f.setup
+            else:
+                log.error("'setup' requires 'unpack' being set for %s" % f.filename)
+                failed_files.append(f.filename)
+
     # lets ensure that fetched files match what the manifest specified
     for localfile, temp_file_name in fetched_files:
         # since I downloaded to a temp file, I need to perform all validations on the temp file
         # this is why filerecord_for_validation is created
 
         filerecord_for_validation = FileRecord(
             temp_file_name, localfile.size, localfile.digest, localfile.algorithm)
 
@@ -705,17 +940,17 @@ def fetch_files(manifest_file, base_urls
                                 (localfile.filename, cache_folder), exc_info=True)
         else:
             failed_files.append(localfile.filename)
             log.error("'%s'" % filerecord_for_validation.describe())
             os.remove(temp_file_name)
 
     # Unpack files that need to be unpacked.
     for filename in unpack_files:
-        if not unpack_file(filename):
+        if not unpack_file(filename, setup_files.get(filename)):
             failed_files.append(filename)
 
     # If we failed to fetch or validate a file, we need to fail
     if len(failed_files) > 0:
         log.error("The following files failed: '%s'" %
                   "', ".join(failed_files))
         return False
     return True
@@ -773,20 +1008,35 @@ def _log_api_error(e):
         json_resp = json.load(e.fp)
         log.error("%s: %s" % (json_resp['error']['name'],
                               json_resp['error']['description']))
     else:
         log.exception("Error making RelengAPI request:")
 
 
 def _authorize(req, auth_file):
-    if auth_file:
-        log.debug("using bearer token in %s" % auth_file)
-        req.add_unredirected_header('Authorization',
-                                    'Bearer %s' % (open(auth_file, "rb").read().strip()))
+    if not auth_file:
+        return
+
+    is_taskcluster_auth = False
+    with open(auth_file) as f:
+        auth_file_content = f.read().strip()
+        try:
+            auth_file_content = json.loads(auth_file_content)
+            is_taskcluster_auth = True
+        except:
+            pass
+
+    if is_taskcluster_auth:
+        taskcluster_header = make_taskcluster_header(auth_file_content, req)
+        log.debug("Using taskcluster credentials in %s" % auth_file)
+        req.add_unredirected_header('Authorization', taskcluster_header)
+    else:
+        log.debug("Using Bearer token in %s" % auth_file)
+        req.add_unredirected_header('Authorization', 'Bearer %s' % auth_file_content)
 
 
 def _send_batch(base_url, auth_file, batch, region):
     url = urlparse.urljoin(base_url, 'upload')
     if region is not None:
         url += "?region=" + region
     req = urllib2.Request(url, json.dumps(batch), {'Content-Type': 'application/json'})
     _authorize(req, auth_file)
@@ -803,17 +1053,17 @@ def _s3_upload(filename, file):
     url = urlparse.urlparse(file['put_url'])
     cls = httplib.HTTPSConnection if url.scheme == 'https' else httplib.HTTPConnection
     host, port = url.netloc.split(':') if ':' in url.netloc else (url.netloc, 443)
     port = int(port)
     conn = cls(host, port)
     try:
         req_path = "%s?%s" % (url.path, url.query) if url.query else url.path
         conn.request('PUT', req_path, open(filename, "rb"),
-                     {'Content-type': 'application/octet-stream'})
+                     {'Content-Type': 'application/octet-stream'})
         resp = conn.getresponse()
         resp_body = resp.read()
         conn.close()
         if resp.status != 200:
             raise RuntimeError("Non-200 return from AWS: %s %s\n%s" %
                                (resp.status, resp.reason, resp_body))
     except Exception:
         file['upload_exception'] = sys.exc_info()
--- a/security/manager/ssl/nsNSSCallbacks.cpp
+++ b/security/manager/ssl/nsNSSCallbacks.cpp
@@ -257,17 +257,18 @@ OCSPRequest::Run() {
   // Security operations scheduled through normal HTTP channels are given
   // high priority to accommodate real time OCSP transactions.
   nsCOMPtr<nsISupportsPriority> priorityChannel = do_QueryInterface(channel);
   if (priorityChannel) {
     priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGHEST);
   }
 
   channel->SetLoadFlags(nsIRequest::LOAD_ANONYMOUS |
-                        nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
+                        nsIChannel::LOAD_BYPASS_SERVICE_WORKER |
+                        nsIChannel::LOAD_BYPASS_URL_CLASSIFIER);
 
   // For OCSP requests, only the first party domain and private browsing id
   // aspects of origin attributes are used. This means that:
   // a) if first party isolation is enabled, OCSP requests will be isolated
   // according to the first party domain of the original https request
   // b) OCSP requests are shared across different containers as long as first
   // party isolation is not enabled and none of the containers are in private
   // browsing mode.
--- a/security/sandbox/common/moz.build
+++ b/security/sandbox/common/moz.build
@@ -2,25 +2,27 @@
 # vim: set filetype=python:
 # 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/.
 
 with Files('**'):
     BUG_COMPONENT = ('Core', 'Security: Process Sandboxing')
 
-UNIFIED_SOURCES += ['SandboxSettings.cpp']
+UNIFIED_SOURCES += [
+    'SandboxSettings.cpp',
+]
 
 XPCOM_MANIFESTS += [
     'components.conf',
 ]
 
 XPIDL_SOURCES += [
     'mozISandboxSettings.idl',
 ]
 
 XPIDL_MODULE = 'sandbox'
 
 FINAL_LIBRARY = 'xul'
 
 EXPORTS.mozilla += [
-    'SandboxSettings.h'
+    'SandboxSettings.h',
 ]
--- a/security/sandbox/win/SandboxInitialization.cpp
+++ b/security/sandbox/win/SandboxInitialization.cpp
@@ -4,17 +4,19 @@
  * 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 "SandboxInitialization.h"
 
 #include "base/memory/ref_counted.h"
 #include "nsWindowsDllInterceptor.h"
 #include "sandbox/win/src/sandbox_factory.h"
+#include "mozilla/DebugOnly.h"
 #include "mozilla/sandboxing/permissionsService.h"
+#include "mozilla/WindowsProcessMitigations.h"
 
 namespace mozilla {
 namespace sandboxing {
 
 typedef BOOL(WINAPI* CloseHandle_func)(HANDLE hObject);
 static WindowsDllInterceptor::FuncHookType<CloseHandle_func> stub_CloseHandle;
 
 typedef BOOL(WINAPI* DuplicateHandle_func)(
@@ -41,17 +43,36 @@ static BOOL WINAPI patched_DuplicateHand
     base::win::OnHandleBeingClosed(hSourceHandle);
   }
 
   return stub_DuplicateHandle(hSourceProcessHandle, hSourceHandle,
                               hTargetProcessHandle, lpTargetHandle,
                               dwDesiredAccess, bInheritHandle, dwOptions);
 }
 
+typedef BOOL (WINAPI* ApiSetQueryApiSetPresence_func)(PCUNICODE_STRING, PBOOLEAN);
+static WindowsDllInterceptor::FuncHookType<ApiSetQueryApiSetPresence_func> stub_ApiSetQueryApiSetPresence;
+
+static const WCHAR gApiSetNtUserWindowStation[] =
+  L"ext-ms-win-ntuser-windowstation-l1-1-0";
+
+static BOOL WINAPI patched_ApiSetQueryApiSetPresence(
+    PCUNICODE_STRING aNamespace, PBOOLEAN aPresent) {
+  if (aNamespace && aPresent && !wcsncmp(aNamespace->Buffer,
+                                         gApiSetNtUserWindowStation,
+                                         aNamespace->Length / sizeof(WCHAR))) {
+    *aPresent = FALSE;
+    return TRUE;
+  }
+
+  return stub_ApiSetQueryApiSetPresence(aNamespace, aPresent);
+}
+
 static WindowsDllInterceptor Kernel32Intercept;
+static WindowsDllInterceptor gApiQueryIntercept;
 
 static bool EnableHandleCloseMonitoring() {
   Kernel32Intercept.Init("kernel32.dll");
   bool hooked = stub_CloseHandle.Set(Kernel32Intercept, "CloseHandle",
                                      &patched_CloseHandle);
   if (!hooked) {
     return false;
   }
@@ -60,16 +81,36 @@ static bool EnableHandleCloseMonitoring(
                                     &patched_DuplicateHandle);
   if (!hooked) {
     return false;
   }
 
   return true;
 }
 
+/**
+ * There is a bug in COM that causes its initialization to fail when user32.dll
+ * is loaded but Win32k lockdown is enabled. COM uses ApiSetQueryApiSetPresence
+ * to make this check. When we are under Win32k lockdown, we hook
+ * ApiSetQueryApiSetPresence and force it to tell the caller that the DLL of
+ * interest is not present.
+ */
+static void EnableApiQueryInterception() {
+  if (!IsWin32kLockedDown()) {
+    return;
+  }
+
+  gApiQueryIntercept.Init(L"Api-ms-win-core-apiquery-l1-1-0.dll");
+  DebugOnly<bool> hookSetOk =
+    stub_ApiSetQueryApiSetPresence.Set(gApiQueryIntercept,
+                                       "ApiSetQueryApiSetPresence",
+                                       &patched_ApiSetQueryApiSetPresence);
+  MOZ_ASSERT(hookSetOk);
+}
+
 static bool ShouldDisableHandleVerifier() {
 #if defined(_X86_) && (defined(EARLY_BETA_OR_EARLIER) || defined(DEBUG))
   // Chromium only has the verifier enabled for 32-bit and our close monitoring
   // hooks cause debug assertions for 64-bit anyway.
   // For x86 keep the verifier enabled by default only for Nightly or debug.
   return false;
 #else
   return !getenv("MOZ_ENABLE_HANDLE_VERIFIER");
@@ -83,16 +124,18 @@ static void InitializeHandleVerifier() {
     base::win::DisableHandleVerifier();
   }
 }
 
 static sandbox::TargetServices* InitializeTargetServices() {
   // This might disable the verifier, so we want to do it before it is used.
   InitializeHandleVerifier();
 
+  EnableApiQueryInterception();
+
   sandbox::TargetServices* targetServices =
       sandbox::SandboxFactory::GetTargetServices();
   if (!targetServices) {
     return nullptr;
   }
 
   if (targetServices->Init() != sandbox::SBOX_ALL_OK) {
     return nullptr;
--- a/security/sandbox/win/src/sandboxtarget/sandboxTarget.cpp
+++ b/security/sandbox/win/src/sandboxtarget/sandboxTarget.cpp
@@ -16,19 +16,32 @@ namespace mozilla {
 SandboxTarget* SandboxTarget::Instance() {
   static SandboxTarget sb;
   return &sb;
 }
 
 void SandboxTarget::StartSandbox() {
   if (mTargetServices) {
     mTargetServices->LowerToken();
+    NotifyStartObservers();
   }
 }
 
+void SandboxTarget::NotifyStartObservers() {
+  for (auto&& obs : mStartObservers) {
+    if (!obs) {
+      continue;
+    }
+
+    obs();
+  }
+
+  mStartObservers.clear();
+}
+
 bool SandboxTarget::BrokerDuplicateHandle(HANDLE aSourceHandle,
                                           DWORD aTargetProcessId,
                                           HANDLE* aTargetHandle,
                                           DWORD aDesiredAccess,
                                           DWORD aOptions) {
   if (!mTargetServices) {
     return false;
   }
--- a/security/sandbox/win/src/sandboxtarget/sandboxTarget.h
+++ b/security/sandbox/win/src/sandboxtarget/sandboxTarget.h
@@ -2,19 +2,23 @@
 /* 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 __SECURITY_SANDBOX_SANDBOXTARGET_H__
 #define __SECURITY_SANDBOX_SANDBOXTARGET_H__
 
+#include <functional>
+#include <list>
+
 #include <windows.h>
 
 #include "mozilla/Assertions.h"
+#include "mozilla/Move.h"
 
 namespace sandbox {
 class TargetServices;
 }
 
 namespace mozilla {
 
 class SandboxTarget {
@@ -34,16 +38,21 @@ class SandboxTarget {
   void SetTargetServices(sandbox::TargetServices* aTargetServices) {
     MOZ_ASSERT(aTargetServices);
     MOZ_ASSERT(!mTargetServices,
                "Sandbox TargetServices must only be set once.");
 
     mTargetServices = aTargetServices;
   }
 
+  template <typename CallbackT>
+  void RegisterSandboxStartCallback(CallbackT aCallback) {
+    mStartObservers.push_back(std::forward<CallbackT>(aCallback));
+  }
+
   /**
    * Called by the library that wants to "start" the sandbox, i.e. change to the
    * more secure delayed / lockdown policy.
    */
   void StartSandbox();
 
   /**
    * Used to duplicate handles via the broker process. The permission for the
@@ -52,13 +61,17 @@ class SandboxTarget {
   bool BrokerDuplicateHandle(HANDLE aSourceHandle, DWORD aTargetProcessId,
                              HANDLE* aTargetHandle, DWORD aDesiredAccess,
                              DWORD aOptions);
 
  protected:
   SandboxTarget() : mTargetServices(nullptr) {}
 
   sandbox::TargetServices* mTargetServices;
+
+ private:
+  void NotifyStartObservers();
+  std::list<std::function<void()>> mStartObservers;
 };
 
 }  // namespace mozilla
 
 #endif
--- a/testing/mozharness/external_tools/tooltool.py
+++ b/testing/mozharness/external_tools/tooltool.py
@@ -17,39 +17,59 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 # 02110-1301, USA.
 
 # A manifest file specifies files in that directory that are stored
 # elsewhere. This file should only list files in the same directory
 # in which the manifest file resides and it should be called
 # 'manifest.tt'
 
+from __future__ import print_function
+
+import base64
+import calendar
 import hashlib
+import hmac
 import httplib
 import json
 import logging
+import math
 import optparse
 import os
+import pprint
+import re
 import shutil
 import sys
 import tarfile
 import tempfile
 import threading
 import time
 import urllib2
 import urlparse
 import zipfile
 
 from subprocess import PIPE
 from subprocess import Popen
 
 __version__ = '1'
 
+# Allowed request header characters:
+# !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9, \, "
+REQUEST_HEADER_ATTRIBUTE_CHARS = re.compile(
+    r"^[ a-zA-Z0-9_\!#\$%&'\(\)\*\+,\-\./\:;<\=>\?@\[\]\^`\{\|\}~]*$")
 DEFAULT_MANIFEST_NAME = 'manifest.tt'
 TOOLTOOL_PACKAGE_SUFFIX = '.TOOLTOOL-PACKAGE'
+HAWK_VER = 1
+PY3 = sys.version_info[0] == 3
+
+if PY3:
+    # TODO: py3 coverage
+    six_binary_type = bytes  # pragma: no cover
+else:
+    six_binary_type = str
 
 
 log = logging.getLogger(__name__)
 
 
 class FileRecordJSONEncoderException(Exception):
     pass
 
@@ -72,16 +92,214 @@ class BadFilenameException(ExceptionWith
 class DigestMismatchException(ExceptionWithFilename):
     pass
 
 
 class MissingFileException(ExceptionWithFilename):
     pass
 
 
+class InvalidCredentials(Exception):
+    pass
+
+
+class BadHeaderValue(Exception):
+    pass
+
+
+def parse_url(url):
+    url_parts = urlparse.urlparse(url)
+    url_dict = {
+        'scheme': url_parts.scheme,
+        'hostname': url_parts.hostname,
+        'port': url_parts.port,
+        'path': url_parts.path,
+        'resource': url_parts.path,
+        'query': url_parts.query,
+    }
+    if len(url_dict['query']) > 0:
+        url_dict['resource'] = '%s?%s' % (url_dict['resource'],  # pragma: no cover
+                                          url_dict['query'])
+
+    if url_parts.port is None:
+        if url_parts.scheme == 'http':
+            url_dict['port'] = 80
+        elif url_parts.scheme == 'https':  # pragma: no cover
+            url_dict['port'] = 443
+    return url_dict
+
+
+def utc_now(offset_in_seconds=0.0):
+    return int(math.floor(calendar.timegm(time.gmtime()) + float(offset_in_seconds)))
+
+
+def random_string(length):
+    return base64.urlsafe_b64encode(os.urandom(length))[:length]
+
+
+def prepare_header_val(val):
+    if isinstance(val, six_binary_type):
+        val = val.decode('utf-8')
+
+    if not REQUEST_HEADER_ATTRIBUTE_CHARS.match(val):
+        raise BadHeaderValue(  # pragma: no cover
+            'header value value={val} contained an illegal character'.format(val=repr(val)))
+
+    return val
+
+
+def parse_content_type(content_type):  # pragma: no cover
+    if content_type:
+        return content_type.split(';')[0].strip().lower()
+    else:
+        return ''
+
+
+def calculate_payload_hash(algorithm, payload, content_type):  # pragma: no cover
+    parts = [
+        part if isinstance(part, six_binary_type) else part.encode('utf8')
+        for part in ['hawk.' + str(HAWK_VER) + '.payload\n',
+                     parse_content_type(content_type) + '\n',
+                     payload or '',
+                     '\n',
+                     ]
+    ]
+
+    p_hash = hashlib.new(algorithm)
+    p_hash.update(''.join(parts))
+
+    log.debug('calculating payload hash from:\n{parts}'.format(parts=pprint.pformat(parts)))
+
+    return base64.b64encode(p_hash.digest())
+
+
+def validate_taskcluster_credentials(credentials):
+    if not hasattr(credentials, '__getitem__'):
+        raise InvalidCredentials('credentials must be a dict-like object')  # pragma: no cover
+    try:
+        credentials['clientId']
+        credentials['accessToken']
+    except KeyError:  # pragma: no cover
+        etype, val, tb = sys.exc_info()
+        raise InvalidCredentials('{etype}: {val}'.format(etype=etype, val=val))
+
+
+def normalize_header_attr(val):
+    if isinstance(val, six_binary_type):
+        return val.decode('utf-8')
+    return val  # pragma: no cover
+
+
+def normalize_string(mac_type,
+                     timestamp,
+                     nonce,
+                     method,
+                     name,
+                     host,
+                     port,
+                     content_hash,
+                     ):
+    return '\n'.join([
+        normalize_header_attr(header)
+        # The blank lines are important. They follow what the Node Hawk lib does.
+        for header in ['hawk.' + str(HAWK_VER) + '.' + mac_type,
+                       timestamp,
+                       nonce,
+                       method or '',
+                       name or '',
+                       host,
+                       port,
+                       content_hash or ''
+                       '',  # for ext which is empty in this case
+                       '',  # Add trailing new line.
+                       ]
+    ])
+
+
+def calculate_mac(mac_type,
+                  access_token,
+                  algorithm,
+                  timestamp,
+                  nonce,
+                  method,
+                  name,
+                  host,
+                  port,
+                  content_hash,
+                  ):
+    normalized = normalize_string(mac_type,
+                                  timestamp,
+                                  nonce,
+                                  method,
+                                  name,
+                                  host,
+                                  port,
+                                  content_hash)
+    log.debug(u'normalized resource for mac calc: {norm}'.format(norm=normalized))
+    digestmod = getattr(hashlib, algorithm)
+
+    # Make sure we are about to hash binary strings.
+
+    if not isinstance(normalized, six_binary_type):
+        normalized = normalized.encode('utf8')
+
+    if not isinstance(access_token, six_binary_type):
+        access_token = access_token.encode('ascii')
+
+    result = hmac.new(access_token, normalized, digestmod)
+    return base64.b64encode(result.digest())
+
+
+def make_taskcluster_header(credentials, req):
+    validate_taskcluster_credentials(credentials)
+
+    url = req.get_full_url()
+    method = req.get_method()
+    algorithm = 'sha256'
+    timestamp = str(utc_now())
+    nonce = random_string(6)
+    url_parts = parse_url(url)
+
+    content_hash = None
+    if req.has_data():
+        content_hash = calculate_payload_hash(  # pragma: no cover
+            algorithm,
+            req.get_data(),
+            req.get_method(),
+        )
+
+    mac = calculate_mac('header',
+                        credentials['accessToken'],
+                        algorithm,
+                        timestamp,
+                        nonce,
+                        method,
+                        url_parts['resource'],
+                        url_parts['hostname'],
+                        str(url_parts['port']),
+                        content_hash,
+                        )
+
+    header = u'Hawk mac="{}"'.format(prepare_header_val(mac))
+
+    if content_hash:  # pragma: no cover
+        header = u'{}, hash="{}"'.format(header, prepare_header_val(content_hash))
+
+    header = u'{header}, id="{id}", ts="{ts}", nonce="{nonce}"'.format(
+        header=header,
+        id=prepare_header_val(credentials['clientId']),
+        ts=prepare_header_val(timestamp),
+        nonce=prepare_header_val(nonce),
+    )
+
+    log.debug('Hawk header for URL={} method={}: {}'.format(url, method, header))
+
+    return header
+
+
 class FileRecord(object):
 
     def __init__(self, filename, size, digest, algorithm, unpack=False,
                  version=None, visibility=None, setup=None):
         object.__init__(self)
         if '/' in filename or '\\' in filename:
             log.error(
                 "The filename provided contains path information and is, therefore, invalid.")
@@ -478,16 +696,18 @@ def fetch_file(base_urls, file_record, g
             req = urllib2.Request(url)
             _authorize(req, auth_file)
             f = urllib2.urlopen(req)
             log.debug("opened %s for reading" % url)
             with open(temp_path, 'wb') as out:
                 k = True
                 size = 0
                 while k:
+                    # TODO: print statistics as file transfers happen both for info and to stop
+                    # buildbot timeouts
                     indata = f.read(grabchunk)
                     out.write(indata)
                     size += len(indata)
                     if indata == '':
                         k = False
                 log.info("File %s fetched from %s as %s" %
                          (file_record.filename, base_url, temp_path))
                 fetched_path = temp_path
@@ -512,48 +732,81 @@ def fetch_file(base_urls, file_record, g
 
 def clean_path(dirname):
     """Remove a subtree if is exists. Helper for unpack_file()."""
     if os.path.exists(dirname):
         log.info('rm tree: %s' % dirname)
         shutil.rmtree(dirname)
 
 
+CHECKSUM_SUFFIX = ".checksum"
+
+
+def _cache_checksum_matches(base_file, checksum):
+    try:
+        with open(base_file + CHECKSUM_SUFFIX, "rb") as f:
+            prev_checksum = f.read().strip()
+            if prev_checksum == checksum:
+                log.info("Cache matches, avoiding extracting in '%s'" % base_file)
+                return True
+            return False
+    except IOError as e:
+        return False
+
+
+def _compute_cache_checksum(filename):
+    with open(filename, "rb") as f:
+        return digest_file(f, "sha256")
+
+
 def unpack_file(filename, setup=None):
     """Untar `filename`, assuming it is uncompressed or compressed with bzip2,
     xz, gzip, or unzip a zip file. The file is assumed to contain a single
     directory with a name matching the base of the given filename.
     Xz support is handled by shelling out to 'tar'."""
+
+    checksum = _compute_cache_checksum(filename)
+
     if tarfile.is_tarfile(filename):
         tar_file, zip_ext = os.path.splitext(filename)
         base_file, tar_ext = os.path.splitext(tar_file)
+        if _cache_checksum_matches(base_file, checksum):
+            return True
         clean_path(base_file)
         log.info('untarring "%s"' % filename)
         tar = tarfile.open(filename)
         tar.extractall()
         tar.close()
     elif filename.endswith('.tar.xz'):
         base_file = filename.replace('.tar.xz', '')
+        if _cache_checksum_matches(base_file, checksum):
+            return True
         clean_path(base_file)
         log.info('untarring "%s"' % filename)
         if not execute('tar -Jxf %s 2>&1' % filename):
             return False
     elif zipfile.is_zipfile(filename):
         base_file = filename.replace('.zip', '')
+        if _cache_checksum_matches(base_file, checksum):
+            return True
         clean_path(base_file)
         log.info('unzipping "%s"' % filename)
         z = zipfile.ZipFile(filename)
         z.extractall()
         z.close()
     else:
         log.error("Unknown archive extension for filename '%s'" % filename)
         return False
 
     if setup and not execute(os.path.join(base_file, setup)):
         return False
+
+    with open(base_file + CHECKSUM_SUFFIX, "wb") as f:
+        f.write(checksum)
+
     return True
 
 
 def fetch_files(manifest_file, base_urls, filenames=[], cache_folder=None,
                 auth_file=None, region=None):
     # Lets load the manifest file
     try:
         manifest = open_manifest(manifest_file)
@@ -750,20 +1003,35 @@ def _log_api_error(e):
         json_resp = json.load(e.fp)
         log.error("%s: %s" % (json_resp['error']['name'],
                               json_resp['error']['description']))
     else:
         log.exception("Error making RelengAPI request:")
 
 
 def _authorize(req, auth_file):
-    if auth_file:
-        log.debug("using bearer token in %s" % auth_file)
-        req.add_unredirected_header('Authorization',
-                                    'Bearer %s' % (open(auth_file, "rb").read().strip()))
+    if not auth_file:
+        return
+
+    is_taskcluster_auth = False
+    with open(auth_file) as f:
+        auth_file_content = f.read().strip()
+        try:
+            auth_file_content = json.loads(auth_file_content)
+            is_taskcluster_auth = True
+        except:
+            pass
+
+    if is_taskcluster_auth:
+        taskcluster_header = make_taskcluster_header(auth_file_content, req)
+        log.debug("Using taskcluster credentials in %s" % auth_file)
+        req.add_unredirected_header('Authorization', taskcluster_header)
+    else:
+        log.debug("Using Bearer token in %s" % auth_file)
+        req.add_unredirected_header('Authorization', 'Bearer %s' % auth_file_content)
 
 
 def _send_batch(base_url, auth_file, batch, region):
     url = urlparse.urljoin(base_url, 'upload')
     if region is not None:
         url += "?region=" + region
     req = urllib2.Request(url, json.dumps(batch), {'Content-Type': 'application/json'})
     _authorize(req, auth_file)
@@ -780,17 +1048,17 @@ def _s3_upload(filename, file):
     url = urlparse.urlparse(file['put_url'])
     cls = httplib.HTTPSConnection if url.scheme == 'https' else httplib.HTTPConnection
     host, port = url.netloc.split(':') if ':' in url.netloc else (url.netloc, 443)
     port = int(port)
     conn = cls(host, port)
     try:
         req_path = "%s?%s" % (url.path, url.query) if url.query else url.path
         conn.request('PUT', req_path, open(filename, "rb"),
-                     {'Content-type': 'application/octet-stream'})
+                     {'Content-Type': 'application/octet-stream'})
         resp = conn.getresponse()
         resp_body = resp.read()
         conn.close()
         if resp.status != 200:
             raise RuntimeError("Non-200 return from AWS: %s %s\n%s" %
                                (resp.status, resp.reason, resp_body))
     except Exception:
         file['upload_exception'] = sys.exc_info()
--- a/toolkit/components/reputationservice/ApplicationReputation.cpp
+++ b/toolkit/components/reputationservice/ApplicationReputation.cpp
@@ -1678,16 +1678,18 @@ nsresult PendingLookup::SendRemoteQueryI
   rv = ios->NewChannel(serviceUrl, nullptr, nullptr,
                        nullptr,  // aLoadingNode
                        nsContentUtils::GetSystemPrincipal(),
                        nullptr,  // aTriggeringPrincipal
                        nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
                        nsIContentPolicy::TYPE_OTHER, getter_AddRefs(mChannel));
   NS_ENSURE_SUCCESS(rv, rv);
 
+  mChannel->SetLoadFlags(nsIChannel::LOAD_BYPASS_URL_CLASSIFIER);
+
   nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
   mozilla::OriginAttributes attrs;
   attrs.mFirstPartyDomain.AssignLiteral(NECKO_SAFEBROWSING_FIRST_PARTY_DOMAIN);
   loadInfo->SetOriginAttributes(attrs);
 
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel, &rv));
   NS_ENSURE_SUCCESS(rv, rv);
   mozilla::Unused << httpChannel;
--- a/toolkit/components/typeaheadfind/nsTypeAheadFind.cpp
+++ b/toolkit/components/typeaheadfind/nsTypeAheadFind.cpp
@@ -1371,20 +1371,20 @@ bool nsTypeAheadFind::IsRangeRendered(Pr
 
     frames.ClearAndRetainStorage();
   }
 
   return false;
 }
 
 already_AddRefed<PresShell> nsTypeAheadFind::GetPresShell() {
-  if (!mPresShell) return nullptr;
-
-  nsCOMPtr<nsIPresShell> iPresShell = do_QueryReferent(mPresShell);
-  if (iPresShell) {
-    nsPresContext* pc = iPresShell->GetPresContext();
+  if (!mPresShell) {
+    return nullptr;
+  }
+  RefPtr<PresShell> presShell = do_QueryReferent(mPresShell);
+  if (presShell) {
+    nsPresContext* pc = presShell->GetPresContext();
     if (!pc || !pc->GetContainerWeak()) {
       return nullptr;
     }
   }
-  RefPtr<PresShell> presShell = static_cast<PresShell*>(iPresShell.get());
   return presShell.forget();
 }
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -190,16 +190,63 @@ class GeckoJavaSampler
     if (!profiler_is_active()) {
       return 0.0;
     }
     return profiler_time();
   };
 };
 #endif
 
+// Return all features that are available on this platform.
+static uint32_t AvailableFeatures() {
+  uint32_t features = 0;
+
+#define ADD_FEATURE(n_, str_, Name_, desc_) \
+  ProfilerFeature::Set##Name_(features);
+
+  // Add all the possible features.
+  PROFILER_FOR_EACH_FEATURE(ADD_FEATURE)
+
+#undef ADD_FEATURE
+
+  // Now remove features not supported on this platform/configuration.
+#if !defined(GP_OS_android)
+  ProfilerFeature::ClearJava(features);
+#endif
+#if !defined(HAVE_NATIVE_UNWIND)
+  ProfilerFeature::ClearStackWalk(features);
+#endif
+#if !defined(MOZ_TASK_TRACER)
+  ProfilerFeature::ClearTaskTracer(features);
+#endif
+#if !(defined(MOZ_REPLACE_MALLOC) && defined(MOZ_PROFILER_MEMORY))
+  ProfilerFeature::ClearMemory(features);
+#endif
+  if (!JS::TraceLoggerSupported()) {
+    ProfilerFeature::ClearJSTracer(features);
+  }
+
+  return features;
+}
+
+// Default features common to all contexts (even if not available).
+static uint32_t DefaultFeatures() {
+  return ProfilerFeature::Java | ProfilerFeature::JS | ProfilerFeature::Leaf |
+         ProfilerFeature::StackWalk | ProfilerFeature::Threads |
+         ProfilerFeature::Responsiveness;
+}
+
+// Extra default features when MOZ_PROFILER_STARTUP is set (even if not
+// available).
+static uint32_t StartupExtraDefaultFeatures() {
+  // Enable mainthreadio by default for startup profiles as startup is heavy on
+  // I/O operations, and main thread I/O is really important to see there.
+  return ProfilerFeature::MainThreadIO | ProfilerFeature::Memory;
+}
+
 class PSMutex : public StaticMutex {};
 
 typedef BaseAutoLock<PSMutex&> PSAutoLock;
 
 // Only functions that take a PSLockRef arg can access CorePS's and ActivePS's
 // fields.
 typedef const PSAutoLock& PSLockRef;
 
@@ -407,17 +454,17 @@ struct LiveProfiledThreadData {
 //
 // Accesses to ActivePS are guarded by gPSMutex, in much the same fashion as
 // CorePS.
 //
 class ActivePS {
  private:
   static uint32_t AdjustFeatures(uint32_t aFeatures, uint32_t aFilterCount) {
     // Filter out any features unavailable in this platform/configuration.
-    aFeatures &= profiler_get_available_features();
+    aFeatures &= AvailableFeatures();
 
 #if defined(GP_OS_android)
     if (!jni::IsFennec()) {
       aFeatures &= ~ProfilerFeature::Java;
     }
 #endif
 
     // Always enable ProfilerFeature::Threads if we have a filter, because
@@ -602,17 +649,17 @@ class ActivePS {
   PS_GET(uint32_t, Capacity)
 
   PS_GET(Maybe<double>, Duration)
 
   PS_GET(double, Interval)
 
   PS_GET(uint32_t, Features)
 
-#define PS_GET_FEATURE(n_, str_, Name_)                       \
+#define PS_GET_FEATURE(n_, str_, Name_, desc_)                \
   static bool Feature##Name_(PSLockRef) {                     \
     return ProfilerFeature::Has##Name_(sInstance->mFeatures); \
   }
 
   PROFILER_FOR_EACH_FEATURE(PS_GET_FEATURE)
 
 #undef PS_GET_FEATURE
 
@@ -2127,16 +2174,37 @@ bool profiler_stream_json_for_this_proce
 #endif
 
   return true;
 }
 
 // END saving/streaming code
 ////////////////////////////////////////////////////////////////////////
 
+static char FeatureCategory(uint32_t aFeature) {
+  if (aFeature & DefaultFeatures()) {
+    if (aFeature & AvailableFeatures()) {
+      return 'D';
+    }
+    return 'd';
+  }
+
+  if (aFeature & StartupExtraDefaultFeatures()) {
+    if (aFeature & AvailableFeatures()) {
+      return 'S';
+    }
+    return 's';
+  }
+
+  if (aFeature & AvailableFeatures()) {
+    return '-';
+  }
+  return 'x';
+}
+
 static void PrintUsageThenExit(int aExitCode) {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
 
   printf(
       "\n"
       "Profiler environment variable usage:\n"
       "\n"
       "  MOZ_PROFILER_HELP\n"
@@ -2148,17 +2216,18 @@ static void PrintUsageThenExit(int aExit
       "\n"
       "  MOZ_PROFILER_STARTUP\n"
       "  If set to any value, starts the profiler immediately on start-up.\n"
       "  Useful if you want profile code that runs very early.\n"
       "\n"
       "  MOZ_PROFILER_STARTUP_ENTRIES=<1..>\n"
       "  If MOZ_PROFILER_STARTUP is set, specifies the number of entries in\n"
       "  the profiler's circular buffer when the profiler is first started.\n"
-      "  If unset, the platform default is used.\n"
+      "  If unset, the platform default is used:\n"
+      "  %u, or %u when MOZ_PROFILER_STARTUP is set.\n"
       "\n"
       "  MOZ_PROFILER_STARTUP_DURATION=<1..>\n"
       "  If MOZ_PROFILER_STARTUP is set, specifies the maximum life time of\n"
       "  entries in the the profiler's circular buffer when the profiler is\n"
       "  first started, in seconds.\n"
       "  If unset, the life time of the entries will only be restricted by\n"
       "  MOZ_PROFILER_STARTUP_ENTRIES (or its default value), and no\n"
       "  additional time duration restriction will be applied.\n"
@@ -2174,16 +2243,32 @@ static void PrintUsageThenExit(int aExit
       "  If unset, the value from MOZ_PROFILER_STARTUP_FEATURES is used.\n"
       "\n"
       "  MOZ_PROFILER_STARTUP_FEATURES=<Features>\n"
       "  If MOZ_PROFILER_STARTUP is set, specifies the profiling features, as\n"
       "  a comma-separated list of strings.\n"
       "  Ignored if  MOZ_PROFILER_STARTUP_FEATURES_BITFIELD is set.\n"
       "  If unset, the platform default is used.\n"
       "\n"
+      "    Features: (x=unavailable, D/d=default/unavailable,\n"
+      "               S/s=MOZ_PROFILER_STARTUP extra default/unavailable)\n",
+      unsigned(PROFILER_DEFAULT_ENTRIES),
+      unsigned(PROFILER_DEFAULT_STARTUP_ENTRIES));
+
+#define PRINT_FEATURE(n_, str_, Name_, desc_)                                  \
+  printf("    %c %5u: \"%s\" (%s)\n", FeatureCategory(ProfilerFeature::Name_), \
+         ProfilerFeature::Name_, str_, desc_);
+
+  PROFILER_FOR_EACH_FEATURE(PRINT_FEATURE)
+
+#undef PRINT_FEATURE
+
+  printf(
+      "    -                \"default\" (All above D+S defaults)\n"
+      "\n"
       "  MOZ_PROFILER_STARTUP_FILTERS=<Filters>\n"
       "  If MOZ_PROFILER_STARTUP is set, specifies the thread filters, as a\n"
       "  comma-separated list of strings. A given thread will be sampled if\n"
       "  any of the filters is a case-insensitive substring of the thread\n"
       "  name. If unset, a default is used.\n"
       "\n"
       "  MOZ_PROFILER_SHUTDOWN\n"
       "  If set, the profiler saves a profile to the named file on shutdown.\n"
@@ -2545,38 +2630,44 @@ GeckoProfilerReporter::CollectReports(ns
       "Memory used by LUL, a stack unwinder used by the Gecko Profiler.");
 #endif
 
   return NS_OK;
 }
 
 NS_IMPL_ISUPPORTS(GeckoProfilerReporter, nsIMemoryReporter)
 
-static bool HasFeature(const char** aFeatures, uint32_t aFeatureCount,
-                       const char* aFeature) {
-  for (size_t i = 0; i < aFeatureCount; i++) {
-    if (strcmp(aFeatures[i], aFeature) == 0) {
-      return true;
-    }
+static uint32_t ParseFeature(const char* aFeature, bool aIsStartup) {
+  if (strcmp(aFeature, "default") == 0) {
+    return (aIsStartup ? (DefaultFeatures() | StartupExtraDefaultFeatures())
+                       : DefaultFeatures()) &
+           AvailableFeatures();
   }
-  return false;
+
+#define PARSE_FEATURE_BIT(n_, str_, Name_, desc_) \
+  if (strcmp(aFeature, str_) == 0) {              \
+    return ProfilerFeature::Name_;                \
+  }
+
+  PROFILER_FOR_EACH_FEATURE(PARSE_FEATURE_BIT)
+
+#undef PARSE_FEATURE_BIT
+
+  printf("\nUnrecognized feature \"%s\".\n\n", aFeature);
+  PrintUsageThenExit(1);
+  return 0;
 }
 
 uint32_t ParseFeaturesFromStringArray(const char** aFeatures,
-                                      uint32_t aFeatureCount) {
-#define ADD_FEATURE_BIT(n_, str_, Name_)            \
-  if (HasFeature(aFeatures, aFeatureCount, str_)) { \
-    features |= ProfilerFeature::Name_;             \
+                                      uint32_t aFeatureCount,
+                                      bool aIsStartup /* = false */) {
+  uint32_t features = 0;
+  for (size_t i = 0; i < aFeatureCount; i++) {
+    features |= ParseFeature(aFeatures[i], aIsStartup);
   }
-
-  uint32_t features = 0;
-  PROFILER_FOR_EACH_FEATURE(ADD_FEATURE_BIT)
-
-#undef ADD_FEATURE_BIT
-
   return features;
 }
 
 // Find the RegisteredThread for the current thread. This should only be called
 // in places where TLSRegisteredThread can't be used.
 static RegisteredThread* FindCurrentThreadRegisteredThread(PSLockRef aLock) {
   int id = Thread::GetCurrentId();
   const Vector<UniquePtr<RegisteredThread>>& registeredThreads =
@@ -2729,34 +2820,26 @@ void profiler_init(void* aStackTop) {
   MOZ_RELEASE_ASSERT(!CorePS::Exists());
 
   if (getenv("MOZ_PROFILER_HELP")) {
     PrintUsageThenExit(0);  // terminates execution
   }
 
   SharedLibraryInfo::Initialize();
 
-  uint32_t features =
-#if defined(GP_OS_android)
-      ProfilerFeature::Java |
-#endif
-      ProfilerFeature::JS | ProfilerFeature::Leaf |
-#if defined(HAVE_NATIVE_UNWIND)
-      ProfilerFeature::StackWalk |
-#endif
-      ProfilerFeature::Threads | ProfilerFeature::Responsiveness | 0;
+  uint32_t features = DefaultFeatures() & AvailableFeatures();
 
   UniquePtr<char[]> filterStorage;
 
   Vector<const char*> filters;
   MOZ_RELEASE_ASSERT(filters.append("GeckoMain"));
   MOZ_RELEASE_ASSERT(filters.append("Compositor"));
   MOZ_RELEASE_ASSERT(filters.append("DOM Worker"));
 
-  int capacity = PROFILER_DEFAULT_ENTRIES;
+  uint32_t capacity = PROFILER_DEFAULT_ENTRIES;
   Maybe<double> duration = Nothing();
   double interval = PROFILER_DEFAULT_INTERVAL;
 
   {
     PSAutoLock lock(gPSMutex);
 
     // We've passed the possible failure point. Instantiate CorePS, which
     // indicates that the profiler has initialized successfully.
@@ -2788,22 +2871,30 @@ void profiler_init(void* aStackTop) {
 
     const char* startupEnv = getenv("MOZ_PROFILER_STARTUP");
     if (!startupEnv || startupEnv[0] == '\0') {
       return;
     }
 
     LOG("- MOZ_PROFILER_STARTUP is set");
 
+    // Startup default capacity may be different.
+    capacity = PROFILER_DEFAULT_STARTUP_ENTRIES;
+
     const char* startupCapacity = getenv("MOZ_PROFILER_STARTUP_ENTRIES");
     if (startupCapacity && startupCapacity[0] != '\0') {
       errno = 0;
-      capacity = strtol(startupCapacity, nullptr, 10);
-      if (errno == 0 && capacity > 0) {
-        LOG("- MOZ_PROFILER_STARTUP_ENTRIES = %d", capacity);
+      long capacityLong = strtol(startupCapacity, nullptr, 10);
+      // `long` could be 32 or 64 bits, so we force a 64-bit comparison with
+      // the maximum 32-bit unsigned number.
+      if (errno == 0 && capacityLong > 0 &&
+          static_cast<uint64_t>(capacityLong) <=
+              static_cast<uint64_t>(UINT32_MAX)) {
+        capacity = static_cast<uint32_t>(capacityLong);
+        LOG("- MOZ_PROFILER_STARTUP_ENTRIES = %u", unsigned(capacity));
       } else {
         LOG("- MOZ_PROFILER_STARTUP_ENTRIES not a valid integer: %s",
             startupCapacity);
         PrintUsageThenExit(1);
       }
     }
 
     const char* startupDuration = getenv("MOZ_PROFILER_STARTUP_DURATION");
@@ -2830,20 +2921,17 @@ void profiler_init(void* aStackTop) {
         LOG("- MOZ_PROFILER_STARTUP_INTERVAL = %f", interval);
       } else {
         LOG("- MOZ_PROFILER_STARTUP_INTERVAL not a valid float: %s",
             startupInterval);
         PrintUsageThenExit(1);
       }
     }
 
-    // Enable mainthreadio by default for startup profiles as startup is
-    // heavy on I/O operations, and main thread I/O is really important to
-    // see there.
-    features |= ProfilerFeature::MainThreadIO;
+    features |= StartupExtraDefaultFeatures() & AvailableFeatures();
 
     const char* startupFeaturesBitfield =
         getenv("MOZ_PROFILER_STARTUP_FEATURES_BITFIELD");
     if (startupFeaturesBitfield && startupFeaturesBitfield[0] != '\0') {
       errno = 0;
       features = strtol(startupFeaturesBitfield, nullptr, 10);
       if (errno == 0 && features != 0) {
         LOG("- MOZ_PROFILER_STARTUP_FEATURES_BITFIELD = %d", features);
@@ -2856,31 +2944,40 @@ void profiler_init(void* aStackTop) {
       const char* startupFeatures = getenv("MOZ_PROFILER_STARTUP_FEATURES");
       if (startupFeatures && startupFeatures[0] != '\0') {
         // Interpret startupFeatures as a list of feature strings, separated by
         // commas.
         UniquePtr<char[]> featureStringStorage;
         Vector<const char*> featureStringArray =
             SplitAtCommas(startupFeatures, featureStringStorage);
         features = ParseFeaturesFromStringArray(featureStringArray.begin(),
-                                                featureStringArray.length());
+                                                featureStringArray.length(),
+                                                /* aIsStartup */ true);
         LOG("- MOZ_PROFILER_STARTUP_FEATURES = %d", features);
       }
     }
 
     const char* startupFilters = getenv("MOZ_PROFILER_STARTUP_FILTERS");
     if (startupFilters && startupFilters[0] != '\0') {
       filters = SplitAtCommas(startupFilters, filterStorage);
       LOG("- MOZ_PROFILER_STARTUP_FILTERS = %s", startupFilters);
     }
 
     locked_profiler_start(lock, capacity, interval, features, filters.begin(),
                           filters.length(), duration);
   }
 
+#if defined(MOZ_REPLACE_MALLOC) && defined(MOZ_PROFILER_MEMORY)
+  if (ProfilerFeature::HasMemory(features)) {
+    // start counting memory allocations (outside of lock because this may call
+    // profiler_add_sampled_counter which would attempt to take the lock.)
+    mozilla::profiler::install_memory_counter(true);
+  }
+#endif
+
   // We do this with gPSMutex unlocked. The comment in profiler_stop() explains
   // why.
   NotifyProfilerStarted(capacity, duration, interval, features, filters.begin(),
                         filters.length());
 }
 
 static void locked_profiler_save_profile_to_file(PSLockRef aLock,
                                                  const char* aFilename,
@@ -3126,41 +3223,17 @@ void profiler_save_profile_to_file(const
     return;
   }
 
   locked_profiler_save_profile_to_file(lock, aFilename);
 }
 
 uint32_t profiler_get_available_features() {
   MOZ_RELEASE_ASSERT(CorePS::Exists());
-
-  uint32_t features = 0;
-
-#define ADD_FEATURE(n_, str_, Name_) ProfilerFeature::Set##Name_(features);
-
-  // Add all the possible features.
-  PROFILER_FOR_EACH_FEATURE(ADD_FEATURE)
-
-#undef ADD_FEATURE
-
-  // Now remove features not supported on this platform/configuration.
-#if !defined(GP_OS_android)
-  ProfilerFeature::ClearJava(features);
-#endif
-#if !defined(HAVE_NATIVE_UNWIND)
-  ProfilerFeature::ClearStackWalk(features);
-#endif
-#if !defined(MOZ_TASK_TRACER)
-  ProfilerFeature::ClearTaskTracer(features);
-#endif
-  if (!JS::TraceLoggerSupported()) {
-    ProfilerFeature::ClearJSTracer(features);
-  }
-
-  return features;
+  return AvailableFeatures();
 }
 
 Maybe<ProfilerBufferInfo> profiler_get_buffer_info() {
   MOZ_RELEASE_ASSERT(CorePS::Exists());
 
   PSAutoLock lock(gPSMutex);
 
   if (!ActivePS::Exists(lock)) {
@@ -3213,17 +3286,17 @@ static void locked_profiler_start(PSLock
                                   const char** aFilters, uint32_t aFilterCount,
                                   const Maybe<double>& aDuration) {
   if (LOG_TEST) {
     LOG("locked_profiler_start");
     LOG("- capacity  = %d", aCapacity);
     LOG("- duration  = %.2f", aDuration ? *aDuration : -1);
     LOG("- interval = %.2f", aInterval);
 
-#define LOG_FEATURE(n_, str_, Name_)            \
+#define LOG_FEATURE(n_, str_, Name_, desc_)     \
   if (ProfilerFeature::Has##Name_(aFeatures)) { \
     LOG("- feature  = %s", str_);               \
   }
 
     PROFILER_FOR_EACH_FEATURE(LOG_FEATURE)
 
 #undef LOG_FEATURE
 
@@ -3324,18 +3397,21 @@ void profiler_start(uint32_t aCapacity, 
       samplerThread = locked_profiler_stop(lock);
     }
 
     locked_profiler_start(lock, aCapacity, aInterval, aFeatures, aFilters,
                           aFilterCount, aDuration);
   }
 
 #if defined(MOZ_REPLACE_MALLOC) && defined(MOZ_PROFILER_MEMORY)
-  // start counting memory allocations (outside of lock)
-  mozilla::profiler::install_memory_counter(true);
+  if (ProfilerFeature::HasMemory(aFeatures)) {
+    // start counting memory allocations (outside of lock because this may call
+    // profiler_add_sampled_counter which would attempt to take the lock.)
+    mozilla::profiler::install_memory_counter(true);
+  }
 #endif
 
   // We do these operations with gPSMutex unlocked. The comments in
   // profiler_stop() explain why.
   if (samplerThread) {
     ProfilerParent::ProfilerStopped();
     NotifyObservers("profiler-stopped");
     delete samplerThread;
@@ -3361,35 +3437,51 @@ void profiler_ensure_started(uint32_t aC
     }
 
     if (ActivePS::Exists(lock)) {
       // The profiler is active.
       if (!ActivePS::Equals(lock, aCapacity, aDuration, aInterval, aFeatures,
                             aFilters, aFilterCount)) {
         // Stop and restart with different settings.
         samplerThread = locked_profiler_stop(lock);
+#if defined(MOZ_REPLACE_MALLOC) && defined(MOZ_PROFILER_MEMORY)
+        if (!ProfilerFeature::HasMemory(aFeatures)) {
+          // Ensure we don't record memory measurements anymore (if we were).
+          mozilla::profiler::install_memory_counter(false);
+        }
+#endif
         locked_profiler_start(lock, aCapacity, aInterval, aFeatures, aFilters,
                               aFilterCount, aDuration);
         startedProfiler = true;
       }
     } else {
       // The profiler is stopped.
       locked_profiler_start(lock, aCapacity, aInterval, aFeatures, aFilters,
                             aFilterCount, aDuration);
       startedProfiler = true;
     }
   }
 
+#if defined(MOZ_REPLACE_MALLOC) && defined(MOZ_PROFILER_MEMORY)
+  if (startedProfiler && ProfilerFeature::HasMemory(aFeatures)) {
+    // start counting memory allocations (outside of lock because this may
+    // call profiler_add_sampled_counter which would attempt to take the
+    // lock.)
+    mozilla::profiler::install_memory_counter(true);
+  }
+#endif
+
   // We do these operations with gPSMutex unlocked. The comments in
   // profiler_stop() explain why.
   if (samplerThread) {
     ProfilerParent::ProfilerStopped();
     NotifyObservers("profiler-stopped");
     delete samplerThread;
   }
+
   if (startedProfiler) {
     NotifyProfilerStarted(aCapacity, aDuration, aInterval, aFeatures, aFilters,
                           aFilterCount);
   }
 }
 
 static MOZ_MUST_USE SamplerThread* locked_profiler_stop(PSLockRef aLock) {
   LOG("locked_profiler_stop");
--- a/tools/profiler/core/platform.h
+++ b/tools/profiler/core/platform.h
@@ -106,17 +106,18 @@ UniquePlatformData AllocPlatformData(int
 
 namespace mozilla {
 class JSONWriter;
 }
 void AppendSharedLibraries(mozilla::JSONWriter& aWriter);
 
 // Convert the array of strings to a bitfield.
 uint32_t ParseFeaturesFromStringArray(const char** aFeatures,
-                                      uint32_t aFeatureCount);
+                                      uint32_t aFeatureCount,
+                                      bool aIsStartup = false);
 
 void profiler_get_profile_json_into_lazily_allocated_buffer(
     const std::function<char*(size_t)>& aAllocator, double aSinceTime,
     bool aIsShuttingDown);
 
 // Flags to conveniently track various JS features.
 enum class JSSamplingFlags {
   StackSampling = 0x1,
--- a/tools/profiler/gecko/nsProfiler.cpp
+++ b/tools/profiler/gecko/nsProfiler.cpp
@@ -467,30 +467,30 @@ nsProfiler::GetElapsedTime(double* aElap
 NS_IMETHODIMP
 nsProfiler::IsActive(bool* aIsActive) {
   *aIsActive = profiler_is_active();
   return NS_OK;
 }
 
 static void GetArrayOfStringsForFeatures(uint32_t aFeatures, uint32_t* aCount,
                                          char*** aFeatureList) {
-#define COUNT_IF_SET(n_, str_, Name_)           \
+#define COUNT_IF_SET(n_, str_, Name_, desc_)    \
   if (ProfilerFeature::Has##Name_(aFeatures)) { \
     len++;                                      \
   }
 
   // Count the number of features in use.
   uint32_t len = 0;
   PROFILER_FOR_EACH_FEATURE(COUNT_IF_SET)
 
 #undef COUNT_IF_SET
 
   auto featureList = static_cast<char**>(moz_xmalloc(len * sizeof(char*)));
 
-#define DUP_IF_SET(n_, str_, Name_)             \
+#define DUP_IF_SET(n_, str_, Name_, desc_)      \
   if (ProfilerFeature::Has##Name_(aFeatures)) { \
     featureList[i] = moz_xstrdup(str_);         \
     i++;                                        \
   }
 
   // Insert the strings for the features in use.
   size_t i = 0;
   PROFILER_FOR_EACH_FEATURE(DUP_IF_SET)
--- a/tools/profiler/public/GeckoProfiler.h
+++ b/tools/profiler/public/GeckoProfiler.h
@@ -113,66 +113,67 @@ class Vector;
 // Profiler features
 //---------------------------------------------------------------------------
 
 // Higher-order macro containing all the feature info in one place. Define
 // |MACRO| appropriately to extract the relevant parts. Note that the number
 // values are used internally only and so can be changed without consequence.
 // Any changes to this list should also be applied to the feature list in
 // toolkit/components/extensions/schemas/geckoProfiler.json.
-#  define PROFILER_FOR_EACH_FEATURE(MACRO)                         \
-    /* Profile Java code (Android only). */                        \
-    MACRO(0, "java", Java)                                         \
-                                                                   \
-    /* Get the JS engine to expose the JS stack to the profiler */ \
-    MACRO(1, "js", JS)                                             \
-                                                                   \
-    /* Include the C++ leaf node if not stackwalking. */           \
-    /* The DevTools profiler doesn't want the native addresses. */ \
-    MACRO(2, "leaf", Leaf)                                         \
-                                                                   \
-    /* Add main thread I/O to the profile. */                      \
-    MACRO(3, "mainthreadio", MainThreadIO)                         \
-                                                                   \
-    /* Add memory measurements (e.g. RSS). */                      \
-    MACRO(4, "memory", Memory)                                     \
-                                                                   \
-    /* Do not include user-identifiable information. */            \
-    MACRO(5, "privacy", Privacy)                                   \
-                                                                   \
-    /* Collect thread responsiveness information. */               \
-    MACRO(6, "responsiveness", Responsiveness)                     \
-                                                                   \
-    /* Take a snapshot of the window on every composition. */      \
-    MACRO(7, "screenshots", Screenshots)                           \
-                                                                   \
-    /* Disable parallel traversal in styling. */                   \
-    MACRO(8, "seqstyle", SequentialStyle)                          \
-                                                                   \
-    /* Walk the C++ stack. Not available on all platforms. */      \
-    MACRO(9, "stackwalk", StackWalk)                               \
-                                                                   \
-    /* Start profiling with feature TaskTracer. */                 \
-    MACRO(10, "tasktracer", TaskTracer)                            \
-                                                                   \
-    /* Profile the registered secondary threads. */                \
-    MACRO(11, "threads", Threads)                                  \
-                                                                   \
-    /* Have the JavaScript engine track JIT optimizations. */      \
-    MACRO(12, "trackopts", TrackOptimizations)                     \
-                                                                   \
-    /* Enable tracing of the JavaScript engine. */                 \
-    MACRO(13, "jstracer", JSTracer)
+#  define PROFILER_FOR_EACH_FEATURE(MACRO)                                    \
+    MACRO(0, "java", Java, "Profile Java code, Android only")                 \
+                                                                              \
+    MACRO(1, "js", JS,                                                        \
+          "Get the JS engine to expose the JS stack to the profiler")         \
+                                                                              \
+    /* The DevTools profiler doesn't want the native addresses. */            \
+    MACRO(2, "leaf", Leaf, "Include the C++ leaf node if not stackwalking")   \
+                                                                              \
+    MACRO(3, "mainthreadio", MainThreadIO,                                    \
+          "Add main thread I/O to the profile")                               \
+                                                                              \
+    MACRO(4, "memory", Memory, "Add memory measurements")                     \
+                                                                              \
+    MACRO(5, "privacy", Privacy,                                              \
+          "Do not include user-identifiable information")                     \
+                                                                              \
+    MACRO(6, "responsiveness", Responsiveness,                                \
+          "Collect thread responsiveness information")                        \
+                                                                              \
+    MACRO(7, "screenshots", Screenshots,                                      \
+          "Take a snapshot of the window on every composition")               \
+                                                                              \
+    MACRO(8, "seqstyle", SequentialStyle,                                     \
+          "Disable parallel traversal in styling")                            \
+                                                                              \
+    MACRO(9, "stackwalk", StackWalk,                                          \
+          "Walk the C++ stack, not available on all platforms")               \
+                                                                              \
+    MACRO(10, "tasktracer", TaskTracer,                                       \
+          "Start profiling with feature TaskTracer")                          \
+                                                                              \
+    MACRO(11, "threads", Threads, "Profile the registered secondary threads") \
+                                                                              \
+    MACRO(12, "trackopts", TrackOptimizations,                                \
+          "Have the JavaScript engine track JIT optimizations")               \
+                                                                              \
+    MACRO(13, "jstracer", JSTracer, "Enable tracing of the JavaScript engine")
 
 struct ProfilerFeature {
-#  define DECLARE(n_, str_, Name_)                                           \
-    static const uint32_t Name_ = (1u << n_);                                \
-    static bool Has##Name_(uint32_t aFeatures) { return aFeatures & Name_; } \
-    static void Set##Name_(uint32_t& aFeatures) { aFeatures |= Name_; }      \
-    static void Clear##Name_(uint32_t& aFeatures) { aFeatures &= ~Name_; }
+#  define DECLARE(n_, str_, Name_, desc_)                     \
+    static constexpr uint32_t Name_ = (1u << n_);             \
+    static constexpr bool Has##Name_(uint32_t aFeatures) {    \
+      return aFeatures & Name_;                               \
+    }                                                         \
+    static constexpr void Set##Name_(uint32_t& aFeatures) {   \
+      aFeatures |= Name_;                                     \
+    }                                                         \
+    static constexpr void Clear##Name_(uint32_t& aFeatures) { \
+      aFeatures &= ~Name_;                                    \
+    }
 
   // Define a bitfield constant, a getter, and two setters for each feature.
   PROFILER_FOR_EACH_FEATURE(DECLARE)
 
 #  undef DECLARE
 };
 
 namespace mozilla {
@@ -206,17 +207,17 @@ class RacyFeatures {
     uint32_t af = sActiveAndFeatures;  // copy it first
     return (af & Active) && !(af & ProfilerFeature::Privacy);
   }
 
  private:
   static const uint32_t Active = 1u << 31;
 
 // Ensure Active doesn't overlap with any of the feature bits.
-#  define NO_OVERLAP(n_, str_, Name_) \
+#  define NO_OVERLAP(n_, str_, Name_, desc_) \
     static_assert(ProfilerFeature::Name_ != Active, "bad Active value");
 
   PROFILER_FOR_EACH_FEATURE(NO_OVERLAP);
 
 #  undef NO_OVERLAP
 
   // We combine the active bit with the feature bits so they can be read or
   // written in a single atomic operation. Accesses to this atomic are not
@@ -231,20 +232,30 @@ bool IsThreadBeingProfiled();
 }  // namespace detail
 }  // namespace profiler
 }  // namespace mozilla
 
 //---------------------------------------------------------------------------
 // Start and stop the profiler
 //---------------------------------------------------------------------------
 
+static constexpr uint32_t PROFILER_DEFAULT_ENTRIES =
 #  if !defined(ARCH_ARMV6)
-#    define PROFILER_DEFAULT_ENTRIES 1000000
+    1000000;
 #  else
-#    define PROFILER_DEFAULT_ENTRIES 100000
+    100000;
+#  endif
+
+// Startup profiling usually need to capture more data, especially on slow
+// systems.
+static constexpr uint32_t PROFILER_DEFAULT_STARTUP_ENTRIES =
+#  if !defined(ARCH_ARMV6)
+    10000000;
+#  else
+    100000;
 #  endif
 
 #  define PROFILER_DEFAULT_DURATION 20
 #  define PROFILER_DEFAULT_INTERVAL 1
 
 // Initialize the profiler. If MOZ_PROFILER_STARTUP is set the profiler will
 // also be started. This call must happen before any other profiler calls
 // (except profiler_start(), which will call profiler_init() if it hasn't
--- a/view/nsViewManager.cpp
+++ b/view/nsViewManager.cpp
@@ -2,28 +2,28 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsViewManager.h"
 
 #include "mozilla/MouseEvents.h"
 #include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/StartupTimeline.h"
 #include "mozilla/dom/Document.h"
 #include "nsAutoPtr.h"
 #include "nsGfxCIID.h"
 #include "nsView.h"
 #include "nsCOMPtr.h"
 #include "nsRegion.h"
 #include "nsCOMArray.h"
 #include "nsIPluginWidget.h"
 #include "nsXULPopupManager.h"
-#include "nsIPresShellInlines.h"
 #include "nsPresContext.h"
 #include "GeckoProfiler.h"
 #include "nsRefreshDriver.h"
 #include "nsContentUtils.h"  // for nsAutoScriptBlocker
 #include "nsLayoutUtils.h"
 #include "Layers.h"
 #include "gfxPlatform.h"
 #include "gfxPrefs.h"
--- a/widget/CommandList.h
+++ b/widget/CommandList.h
@@ -3,20 +3,32 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /**
  * Define NS_DEFINE_COMMAND(aName, aCommandStr) before including this.
  * @param aName          The name useful in C++ of the command.
  * @param aCommandStr    The command string in JS.
  *
+ * Define NS_DEFINE_COMMAND_WITH_PARAM(aName, aCommandStr, aParam) before
+ * including this.
+ * @param aName          The name useful in C++ of the command.
+ * @param aCommandStr    The command string in JS, but this may be shared with
+ *                       other aName values.  I.e., cannot map aName and
+ *                       aCommandStr 1:1.
+ * @param aParam         Additional param value.  When aCommandStr is executed,
+ *                       this value is also specified.  I.e., aName becomes
+ *                       unique when you look for with both aCommandStr and
+ *                       aParam.
+ *
  * Define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName) before including this.
  * @param aName          The name useful in C++ of the command.
  */
 
+// Mapped from commands of some platforms
 NS_DEFINE_COMMAND(BeginLine, cmd_beginLine)
 NS_DEFINE_COMMAND(CharNext, cmd_charNext)
 NS_DEFINE_COMMAND(CharPrevious, cmd_charPrevious)
 NS_DEFINE_COMMAND(Copy, cmd_copy)
 NS_DEFINE_COMMAND(Cut, cmd_cut)
 NS_DEFINE_COMMAND(Delete, cmd_delete)
 NS_DEFINE_COMMAND(DeleteCharBackward, cmd_deleteCharBackward)
 NS_DEFINE_COMMAND(DeleteCharForward, cmd_deleteCharForward)
@@ -51,12 +63,93 @@ NS_DEFINE_COMMAND(SelectLinePrevious, cm
 NS_DEFINE_COMMAND(SelectPageDown, cmd_selectPageDown)
 NS_DEFINE_COMMAND(SelectPageUp, cmd_selectPageUp)
 NS_DEFINE_COMMAND(SelectTop, cmd_selectTop)
 NS_DEFINE_COMMAND(SelectWordNext, cmd_selectWordNext)
 NS_DEFINE_COMMAND(SelectWordPrevious, cmd_selectWordPrevious)
 NS_DEFINE_COMMAND(WordNext, cmd_wordNext)
 NS_DEFINE_COMMAND(WordPrevious, cmd_wordPrevious)
 
+// We don't have corresponding commands for them, but some platforms have them.
 NS_DEFINE_COMMAND_NO_EXEC_COMMAND(CancelOperation)
 NS_DEFINE_COMMAND_NO_EXEC_COMMAND(Complete)
 NS_DEFINE_COMMAND_NO_EXEC_COMMAND(InsertBacktab)
 NS_DEFINE_COMMAND_NO_EXEC_COMMAND(InsertTab)
+
+// Commands mapped from HTMLDocument.execCommand()
+NS_DEFINE_COMMAND(FormatBold, cmd_bold)
+NS_DEFINE_COMMAND(FormatItalic, cmd_italic)
+NS_DEFINE_COMMAND(FormatUnderline, cmd_underline)
+NS_DEFINE_COMMAND(FormatStrikeThrough, cmd_strikethrough)
+NS_DEFINE_COMMAND(FormatSubscript, cmd_subscript)
+NS_DEFINE_COMMAND(FormatSuperscript, cmd_superscript)
+NS_DEFINE_COMMAND(HistoryUndo, cmd_undo)
+NS_DEFINE_COMMAND(HistoryRedo, cmd_redo)
+NS_DEFINE_COMMAND(FormatBlock, cmd_paragraphState)
+NS_DEFINE_COMMAND(FormatIndent, cmd_indent)
+NS_DEFINE_COMMAND(FormatOutdent, cmd_outdent)
+NS_DEFINE_COMMAND_WITH_PARAM(FormatJustifyLeft, cmd_align, left)
+NS_DEFINE_COMMAND_WITH_PARAM(FormatJustifyRight, cmd_align, right)
+NS_DEFINE_COMMAND_WITH_PARAM(FormatJustifyCenter, cmd_align, center)
+NS_DEFINE_COMMAND_WITH_PARAM(FormatJustifyFull, cmd_align, justify)
+NS_DEFINE_COMMAND(FormatBackColor, cmd_highlight)
+NS_DEFINE_COMMAND(FormatFontColor, cmd_fontColor)
+NS_DEFINE_COMMAND(FormatFontName, cmd_fontFace)
+NS_DEFINE_COMMAND(FormatFontSize, cmd_fontSize)
+NS_DEFINE_COMMAND(FormatIncreaseFontSize, cmd_increaseFont)
+NS_DEFINE_COMMAND(FormatDecreaseFontSize, cmd_decreaseFont)
+NS_DEFINE_COMMAND(InsertHorizontalRule, cmd_insertHR)
+NS_DEFINE_COMMAND(InsertLink, cmd_insertLinkNoUI)
+NS_DEFINE_COMMAND(InsertImage, cmd_insertImageNoUI)
+NS_DEFINE_COMMAND(InsertHTML, cmd_insertHTML)
+NS_DEFINE_COMMAND(InsertText, cmd_insertText)
+NS_DEFINE_COMMAND(InsertOrderedList, cmd_ol)
+NS_DEFINE_COMMAND(InsertUnorderedList, cmd_ul)
+NS_DEFINE_COMMAND(GetHTML, cmd_getContents)
+NS_DEFINE_COMMAND(FormatRemove, cmd_removeStyles)
+NS_DEFINE_COMMAND(FormatRemoveLink, cmd_removeLinks)
+NS_DEFINE_COMMAND(SetDocumentUseCSS, cmd_setDocumentUseCSS)
+NS_DEFINE_COMMAND(SetDocumentReadOnly, cmd_setDocumentReadOnly)
+NS_DEFINE_COMMAND(SetDocumentInsertBROnEnterKeyPress, cmd_insertBrOnReturn)
+NS_DEFINE_COMMAND(SetDocumentDefaultParagraphSeparator,
+                  cmd_defaultParagraphSeparator)
+NS_DEFINE_COMMAND(ToggleObjectResizers, cmd_enableObjectResizing)
+NS_DEFINE_COMMAND(ToggleInlineTableEditor, cmd_enableInlineTableEditing)
+NS_DEFINE_COMMAND(ToggleAbsolutePositionEditor,
+                  cmd_enableAbsolutePositionEditing)
+
+// Commands not mapped from HTMLDocument.execCommand() but available with
+// command dispatcher and handled in editor.
+NS_DEFINE_COMMAND(EditorObserverDocumentCreated, obs_documentCreated)
+NS_DEFINE_COMMAND(EditorObserverDocumentLocationChanged,
+                  obs_documentLocationChanged)
+NS_DEFINE_COMMAND(EditorObserverDocumentWillBeDestroyed,
+                  obs_documentWillBeDestroyed)
+NS_DEFINE_COMMAND(FormatAbbreviation, cmd_abbr)
+NS_DEFINE_COMMAND(FormatAbsolutePosition, cmd_absPos)
+NS_DEFINE_COMMAND(FormatAcronym, cmd_acronym)
+NS_DEFINE_COMMAND(FormatCitation, cmd_cite)
+NS_DEFINE_COMMAND(FormatCode, cmd_code)
+NS_DEFINE_COMMAND(FormatEmphasis, cmd_em)
+NS_DEFINE_COMMAND(FormatNoBreak, cmd_nobreak)
+NS_DEFINE_COMMAND(FormatSample, cmd_samp)
+NS_DEFINE_COMMAND(FormatStrong, cmd_strong)
+NS_DEFINE_COMMAND(FormatTeletypeText, cmd_tt)
+NS_DEFINE_COMMAND(FormatVariable, cmd_var)
+NS_DEFINE_COMMAND(InsertDefinitionDetails, cmd_dd)
+NS_DEFINE_COMMAND(InsertDefinitionTerm, cmd_dt)
+NS_DEFINE_COMMAND(MoveDown, cmd_moveDown)
+NS_DEFINE_COMMAND(MoveDown2, cmd_moveDown2)
+NS_DEFINE_COMMAND(MoveLeft, cmd_moveLeft)
+NS_DEFINE_COMMAND(MoveLeft2, cmd_moveLeft2)
+NS_DEFINE_COMMAND(MoveRight, cmd_moveRight)
+NS_DEFINE_COMMAND(MoveRight2, cmd_moveRight2)
+NS_DEFINE_COMMAND(MoveUp, cmd_moveUp)
+NS_DEFINE_COMMAND(MoveUp2, cmd_moveUp2)
+NS_DEFINE_COMMAND(SelectDown, cmd_selectDown)
+NS_DEFINE_COMMAND(SelectDown2, cmd_selectDown2)
+NS_DEFINE_COMMAND(SelectLeft, cmd_selectLeft)
+NS_DEFINE_COMMAND(SelectLeft2, cmd_selectLeft2)
+NS_DEFINE_COMMAND(SelectRight, cmd_selectRight)
+NS_DEFINE_COMMAND(SelectRight2, cmd_selectRight2)
+NS_DEFINE_COMMAND(SelectUp, cmd_selectUp)
+NS_DEFINE_COMMAND(SelectUp2, cmd_selectUp2)
+NS_DEFINE_COMMAND(SetDocumentModified, cmd_setDocumentModified)
--- a/widget/EventForwards.h
+++ b/widget/EventForwards.h
@@ -197,30 +197,50 @@ inline bool IsDataTransferAvailableOnHTM
     case EditorInputType::eInsertReplacementText:
     case EditorInputType::eInsertFromYank:
       return true;
     default:
       return false;
   }
 }
 
-#define NS_DEFINE_COMMAND(aName, aCommandStr) , Command##aName
-#define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName) , Command##aName
+#define NS_DEFINE_COMMAND(aName, aCommandStr) , aName
+#define NS_DEFINE_COMMAND_WITH_PARAM(aName, aCommandStr, aParam) , aName
+#define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName) , aName
 
 typedef int8_t CommandInt;
-enum Command : CommandInt {
-  CommandDoNothing
+enum class Command : CommandInt {
+  DoNothing
 
 #include "mozilla/CommandList.h"
 };
 #undef NS_DEFINE_COMMAND
+#undef NS_DEFINE_COMMAND_WITH_PARAM
 #undef NS_DEFINE_COMMAND_NO_EXEC_COMMAND
 
 const char* ToChar(Command aCommand);
 
+/**
+ * Return a command value for aCommandName.
+ * NOTE: We use overloads instead of default constructor with EmptyString()
+ *       because using it here requires to include another header file but
+ *       this header file shouldn't include other header files as far as
+ *       possible to avoid making rebuild time of them longer.
+ * XXX: Is there a better place to put `Command` related methods instead of
+ *      global scope in `mozilla` namespace?
+ *
+ * @param aCommandName  Should be a XUL command name like "cmd_bold" (case
+ *                      sensitive).
+ * @param aValue        Additional parameter value of aCommandName.
+ *                      It depends on the command whethere it's case sensitive
+ *                      or not.
+ */
+Command GetInternalCommand(const char* aCommandName);
+Command GetInternalCommand(const char* aCommandName, const nsAString& aValue);
+
 }  // namespace mozilla
 
 /**
  * All header files should include this header instead of *Events.h.
  */
 
 namespace mozilla {
 
--- a/widget/WidgetEventImpl.cpp
+++ b/widget/WidgetEventImpl.cpp
@@ -71,31 +71,35 @@ const nsCString ToString(CodeNameIndex a
     return NS_LITERAL_CSTRING("USE_STRING");
   }
   nsAutoString codeName;
   WidgetKeyboardEvent::GetDOMCodeName(aCodeNameIndex, codeName);
   return NS_ConvertUTF16toUTF8(codeName);
 }
 
 const char* ToChar(Command aCommand) {
-  if (aCommand == CommandDoNothing) {
+  if (aCommand == Command::DoNothing) {
     return "CommandDoNothing";
   }
 
   switch (aCommand) {
 #define NS_DEFINE_COMMAND(aName, aCommandStr) \
-  case Command##aName:                        \
-    return "Command" #aName;
+  case Command::aName:                        \
+    return "Command::" #aName;
+#define NS_DEFINE_COMMAND_WITH_PARAM(aName, aCommandStr, aParam) \
+  case Command::aName:                                           \
+    return "Command::" #aName;
 #define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName) \
-  case Command##aName:                           \
-    return "Command" #aName;
+  case Command::aName:                           \
+    return "Command::" #aName;
 
 #include "mozilla/CommandList.h"
 
 #undef NS_DEFINE_COMMAND
+#undef NS_DEFINE_COMMAND_WITH_PARAM
 #undef NS_DEFINE_COMMAND_NO_EXEC_COMMAND
 
     default:
       return "illegal command value";
   }
 }
 
 const nsCString GetDOMKeyCodeName(uint32_t aKeyCode) {
@@ -169,16 +173,71 @@ SelectionType ToSelectionType(TextRangeT
       return SelectionType::eIMESelectedClause;
     default:
       MOZ_CRASH("TextRangeType is invalid");
       return SelectionType::eNormal;
   }
 }
 
 /******************************************************************************
+ * non class method implementation
+ ******************************************************************************/
+
+static nsDataHashtable<nsDepCharHashKey, Command>* sCommandHashtable = nullptr;
+
+Command GetInternalCommand(const char* aCommandName) {
+  return GetInternalCommand(aCommandName, EmptyString());
+}
+
+Command GetInternalCommand(const char* aCommandName, const nsAString& aParam) {
+  if (!aCommandName) {
+    return Command::DoNothing;
+  }
+
+  // Special cases for "cmd_align".  It's mapped to multiple internal commands
+  // with additional param.  Therefore, we cannot handle it with the hashtable.
+  if (!strcmp(aCommandName, "cmd_align")) {
+    if (aParam.LowerCaseEqualsASCII("left")) {
+      return Command::FormatJustifyLeft;
+    }
+    if (aParam.LowerCaseEqualsASCII("right")) {
+      return Command::FormatJustifyRight;
+    }
+    if (aParam.LowerCaseEqualsASCII("center")) {
+      return Command::FormatJustifyCenter;
+    }
+    if (aParam.LowerCaseEqualsASCII("justify")) {
+      return Command::FormatJustifyFull;
+    }
+    return Command::DoNothing;
+  }
+
+  if (!sCommandHashtable) {
+    sCommandHashtable = new nsDataHashtable<nsDepCharHashKey, Command>();
+#define NS_DEFINE_COMMAND(aName, aCommandStr) \
+  sCommandHashtable->Put(#aCommandStr, Command::aName);
+
+#define NS_DEFINE_COMMAND_WITH_PARAM(aName, aCommandStr, aParam)
+
+#define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName)
+
+#include "mozilla/CommandList.h"
+
+#undef NS_DEFINE_COMMAND
+#undef NS_DEFINE_COMMAND_WITH_PARAM
+#undef NS_DEFINE_COMMAND_NO_EXEC_COMMAND
+  }
+  Command command = Command::DoNothing;
+  if (!sCommandHashtable->Get(aCommandName, &command)) {
+    return Command::DoNothing;
+  }
+  return command;
+}
+
+/******************************************************************************
  * As*Event() implementation
  ******************************************************************************/
 
 #define NS_ROOT_EVENT_CLASS(aPrefix, aName)
 #define NS_EVENT_CLASS(aPrefix, aName)                         \
   aPrefix##aName* WidgetEvent::As##aName() { return nullptr; } \
                                                                \
   const aPrefix##aName* WidgetEvent::As##aName() const {       \
@@ -996,16 +1055,20 @@ int32_t WidgetKeyboardEvent::ContentAcce
 }
 
 /* static */
 void WidgetKeyboardEvent::Shutdown() {
   delete sKeyNameIndexHashtable;
   sKeyNameIndexHashtable = nullptr;
   delete sCodeNameIndexHashtable;
   sCodeNameIndexHashtable = nullptr;
+  // Although sCommandHashtable is not a member of WidgetKeyboardEvent, but
+  // let's delete it here since we need to do it at same time.
+  delete sCommandHashtable;
+  sCommandHashtable = nullptr;
 }
 
 /* static */
 void WidgetKeyboardEvent::GetDOMKeyName(KeyNameIndex aKeyNameIndex,
                                         nsAString& aKeyName) {
   if (aKeyNameIndex >= KEY_NAME_INDEX_USE_STRING) {
     aKeyName.Truncate();
     return;
@@ -1093,27 +1156,29 @@ uint32_t WidgetKeyboardEvent::GetFallbac
       return dom::KeyboardEvent_Binding::DOM_VK_BACK_SLASH;
     default:
       return 0;
   }
 }
 
 /* static */ const char* WidgetKeyboardEvent::GetCommandStr(Command aCommand) {
 #define NS_DEFINE_COMMAND(aName, aCommandStr) , #aCommandStr
+#define NS_DEFINE_COMMAND_WITH_PARAM(aName, aCommandStr, aParam) , #aCommandStr
 #define NS_DEFINE_COMMAND_NO_EXEC_COMMAND(aName)
   static const char* const kCommands[] = {
-      ""  // CommandDoNothing
+      ""  // DoNothing
 #include "mozilla/CommandList.h"
   };
 #undef NS_DEFINE_COMMAND
+#undef NS_DEFINE_COMMAND_WITH_PARAM
 #undef NS_DEFINE_COMMAND_NO_EXEC_COMMAND
 
   MOZ_RELEASE_ASSERT(static_cast<size_t>(aCommand) < ArrayLength(kCommands),
                      "Illegal command enumeration value");
-  return kCommands[aCommand];
+  return kCommands[static_cast<CommandInt>(aCommand)];
 }
 
 /* static */
 uint32_t WidgetKeyboardEvent::ComputeLocationFromCodeValue(
     CodeNameIndex aCodeNameIndex) {
   // Following commented out cases are not defined in PhysicalKeyCodeNameList.h
   // but are defined by D3E spec.  So, they should be uncommented when the
   // code values are defined in the header.
--- a/widget/cocoa/NativeKeyBindings.h
+++ b/widget/cocoa/NativeKeyBindings.h
@@ -10,17 +10,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/EventForwards.h"
 #include "nsDataHashtable.h"
 #include "nsIWidget.h"
 
 namespace mozilla {
 namespace widget {
 
-typedef nsDataHashtable<nsPtrHashKey<struct objc_selector>, CommandInt>
+typedef nsDataHashtable<nsPtrHashKey<struct objc_selector>, Command>
     SelectorCommandHashtable;
 
 class NativeKeyBindings final {
   typedef nsIWidget::NativeKeyBindingsType NativeKeyBindingsType;
 
  public:
   static NativeKeyBindings* GetInstance(NativeKeyBindingsType aType);
   static void Shutdown();
--- a/widget/cocoa/NativeKeyBindings.mm
+++ b/widget/cocoa/NativeKeyBindings.mm
@@ -65,109 +65,109 @@ void NativeKeyBindings::Init(NativeKeyBi
   // TODO: Improves correctness of left / right meaning
   // TODO: Add real paragraph motions
 
   // SEL_TO_COMMAND(cancelOperation:, );
   // SEL_TO_COMMAND(capitalizeWord:, );
   // SEL_TO_COMMAND(centerSelectionInVisibleArea:, );
   // SEL_TO_COMMAND(changeCaseOfLetter:, );
   // SEL_TO_COMMAND(complete:, );
-  SEL_TO_COMMAND(copy:, CommandCopy);
+  SEL_TO_COMMAND(copy:, Command::Copy);
   // SEL_TO_COMMAND(copyFont:, );
   // SEL_TO_COMMAND(copyRuler:, );
-  SEL_TO_COMMAND(cut:, CommandCut);
-  SEL_TO_COMMAND(delete:, CommandDelete);
-  SEL_TO_COMMAND(deleteBackward:, CommandDeleteCharBackward);
+  SEL_TO_COMMAND(cut:, Command::Cut);
+  SEL_TO_COMMAND(delete:, Command::Delete);
+  SEL_TO_COMMAND(deleteBackward:, Command::DeleteCharBackward);
   // SEL_TO_COMMAND(deleteBackwardByDecomposingPreviousCharacter:, );
-  SEL_TO_COMMAND(deleteForward:, CommandDeleteCharForward);
+  SEL_TO_COMMAND(deleteForward:, Command::DeleteCharForward);
 
   // TODO: deleteTo* selectors are also supposed to add text to a kill buffer
-  SEL_TO_COMMAND(deleteToBeginningOfLine:, CommandDeleteToBeginningOfLine);
-  SEL_TO_COMMAND(deleteToBeginningOfParagraph:, CommandDeleteToBeginningOfLine);
-  SEL_TO_COMMAND(deleteToEndOfLine:, CommandDeleteToEndOfLine);
-  SEL_TO_COMMAND(deleteToEndOfParagraph:, CommandDeleteToEndOfLine);
+  SEL_TO_COMMAND(deleteToBeginningOfLine:, Command::DeleteToBeginningOfLine);
+  SEL_TO_COMMAND(deleteToBeginningOfParagraph:, Command::DeleteToBeginningOfLine);
+  SEL_TO_COMMAND(deleteToEndOfLine:, Command::DeleteToEndOfLine);
+  SEL_TO_COMMAND(deleteToEndOfParagraph:, Command::DeleteToEndOfLine);
   // SEL_TO_COMMAND(deleteToMark:, );
 
-  SEL_TO_COMMAND(deleteWordBackward:, CommandDeleteWordBackward);
-  SEL_TO_COMMAND(deleteWordForward:, CommandDeleteWordForward);
+  SEL_TO_COMMAND(deleteWordBackward:, Command::DeleteWordBackward);
+  SEL_TO_COMMAND(deleteWordForward:, Command::DeleteWordForward);
   // SEL_TO_COMMAND(indent:, );
   // SEL_TO_COMMAND(insertBacktab:, );
   // SEL_TO_COMMAND(insertContainerBreak:, );
   // SEL_TO_COMMAND(insertLineBreak:, );
   // SEL_TO_COMMAND(insertNewline:, );
   // SEL_TO_COMMAND(insertNewlineIgnoringFieldEditor:, );
   // SEL_TO_COMMAND(insertParagraphSeparator:, );
   // SEL_TO_COMMAND(insertTab:, );
   // SEL_TO_COMMAND(insertTabIgnoringFieldEditor:, );
   // SEL_TO_COMMAND(insertDoubleQuoteIgnoringSubstitution:, );
   // SEL_TO_COMMAND(insertSingleQuoteIgnoringSubstitution:, );
   // SEL_TO_COMMAND(lowercaseWord:, );
-  SEL_TO_COMMAND(moveBackward:, CommandCharPrevious);
-  SEL_TO_COMMAND(moveBackwardAndModifySelection:, CommandSelectCharPrevious);
+  SEL_TO_COMMAND(moveBackward:, Command::CharPrevious);
+  SEL_TO_COMMAND(moveBackwardAndModifySelection:, Command::SelectCharPrevious);
   if (aType == nsIWidget::NativeKeyBindingsForSingleLineEditor) {
-    SEL_TO_COMMAND(moveDown:, CommandEndLine);
+    SEL_TO_COMMAND(moveDown:, Command::EndLine);
   } else {
-    SEL_TO_COMMAND(moveDown:, CommandLineNext);
+    SEL_TO_COMMAND(moveDown:, Command::LineNext