Bug 1619914 - part 2: Mark transaction class methods and their caller methods as `MOZ_CAN_RUN_SCRIPT r=m_kato
☠☠ backed out by efd779b64b3f ☠ ☠
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 03 Apr 2020 01:39:36 +0000
changeset 521962 d3816f82c0b9d4ceca0bb2ad177694164ed0921f
parent 521961 876b1031a6ae41a87ed146976f279b96bde9c7f6
child 521963 33fe9b3d615f088dff5217fa354d36a8b67c7c62
push id37280
push useropoprus@mozilla.com
push dateFri, 03 Apr 2020 21:40:10 +0000
treeherdermozilla-central@cf48e59e88de [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1619914
milestone76.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
Bug 1619914 - part 2: Mark transaction class methods and their caller methods as `MOZ_CAN_RUN_SCRIPT r=m_kato Differential Revision: https://phabricator.services.mozilla.com/D69303
editor/libeditor/ChangeAttributeTransaction.h
editor/libeditor/ChangeStyleTransaction.h
editor/libeditor/CompositionTransaction.cpp
editor/libeditor/CompositionTransaction.h
editor/libeditor/CreateElementTransaction.cpp
editor/libeditor/CreateElementTransaction.h
editor/libeditor/DeleteNodeTransaction.h
editor/libeditor/DeleteRangeTransaction.h
editor/libeditor/DeleteTextTransaction.cpp
editor/libeditor/EditAggregateTransaction.cpp
editor/libeditor/EditAggregateTransaction.h
editor/libeditor/EditTransactionBase.h
editor/libeditor/EditorBase.cpp
editor/libeditor/EditorBase.h
editor/libeditor/EditorEventListener.cpp
editor/libeditor/EditorEventListener.h
editor/libeditor/EditorUtils.h
editor/libeditor/HTMLEditor.cpp
editor/libeditor/InsertNodeTransaction.cpp
editor/libeditor/InsertTextTransaction.cpp
editor/libeditor/JoinNodeTransaction.cpp
editor/libeditor/PlaceholderTransaction.h
editor/libeditor/SplitNodeTransaction.cpp
editor/libeditor/SplitNodeTransaction.h
editor/nsIEditor.idl
editor/txmgr/TransactionItem.cpp
editor/txmgr/TransactionItem.h
editor/txmgr/TransactionManager.cpp
editor/txmgr/TransactionManager.h
editor/txmgr/nsITransaction.idl
editor/txmgr/nsITransactionManager.idl
editor/txmgr/tests/TestTXMgr.cpp
--- a/editor/libeditor/ChangeAttributeTransaction.h
+++ b/editor/libeditor/ChangeAttributeTransaction.h
@@ -53,17 +53,17 @@ class ChangeAttributeTransaction final :
       dom::Element& aElement, nsAtom& aAttribute);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ChangeAttributeTransaction,
                                            EditTransactionBase)
 
   NS_DECL_EDITTRANSACTIONBASE
 
-  NS_IMETHOD RedoTransaction() override;
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD RedoTransaction() override;
 
  private:
   virtual ~ChangeAttributeTransaction() = default;
 
   // The element to operate upon
   nsCOMPtr<dom::Element> mElement;
 
   // The attribute to change
--- a/editor/libeditor/ChangeStyleTransaction.h
+++ b/editor/libeditor/ChangeStyleTransaction.h
@@ -54,17 +54,17 @@ class ChangeStyleTransaction final : pub
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ChangeStyleTransaction,
                                            EditTransactionBase)
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_EDITTRANSACTIONBASE
 
-  NS_IMETHOD RedoTransaction() override;
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD RedoTransaction() override;
 
   /**
    * Returns true if the list of white-space separated values contains aValue
    *
    * @param aValueList      [IN] a list of white-space separated values
    * @param aValue          [IN] the value to look for in the list
    * @return                true if the value is in the list of values
    */
@@ -101,17 +101,18 @@ class ChangeStyleTransaction final : pub
                                    const nsAString& aRemoveValue);
 
   /**
    * If the boolean is true and if the value is not the empty string,
    * set the property in the transaction to that value; if the value
    * is empty, remove the property from element's styles. If the boolean
    * is false, just remove the style attribute.
    */
-  nsresult SetStyle(bool aAttributeWasSet, nsAString& aValue);
+  MOZ_CAN_RUN_SCRIPT nsresult SetStyle(bool aAttributeWasSet,
+                                       nsAString& aValue);
 
   // The element to operate upon.
   RefPtr<nsStyledElement> mStyledElement;
 
   // The CSS property to change.
   RefPtr<nsAtom> mProperty;
 
   // The value to set the property to (ignored if mRemoveProperty==true).
--- a/editor/libeditor/CompositionTransaction.cpp
+++ b/editor/libeditor/CompositionTransaction.cpp
@@ -74,18 +74,17 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(Compo
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CompositionTransaction)
   NS_INTERFACE_MAP_ENTRY_CONCRETE(CompositionTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
 NS_IMPL_ADDREF_INHERITED(CompositionTransaction, EditTransactionBase)
 NS_IMPL_RELEASE_INHERITED(CompositionTransaction, EditTransactionBase)
 
-MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
-CompositionTransaction::DoTransaction() {
+NS_IMETHODIMP CompositionTransaction::DoTransaction() {
   if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Fail before making any changes if there's no selection controller
   if (NS_WARN_IF(!mEditorBase->GetSelectionController())) {
     return NS_ERROR_NOT_AVAILABLE;
   }
@@ -147,18 +146,17 @@ CompositionTransaction::DoTransaction() 
 
   nsresult rv = SetSelectionForRanges();
   NS_WARNING_ASSERTION(
       NS_SUCCEEDED(rv),
       "CompositionTransaction::SetSelectionForRanges() failed");
   return rv;
 }
 
-MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
-CompositionTransaction::UndoTransaction() {
+NS_IMETHODIMP CompositionTransaction::UndoTransaction() {
   if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Get the selection first so we'll fail before making any changes if we
   // can't get it
   RefPtr<Selection> selection = mEditorBase->GetSelection();
   if (NS_WARN_IF(!selection)) {
--- a/editor/libeditor/CompositionTransaction.h
+++ b/editor/libeditor/CompositionTransaction.h
@@ -66,24 +66,24 @@ class CompositionTransaction final : pub
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_EDITTRANSACTIONBASE
 
   NS_IMETHOD Merge(nsITransaction* aTransaction, bool* aDidMerge) override;
 
   void MarkFixed();
 
-  MOZ_CAN_RUN_SCRIPT_BOUNDARY static nsresult SetIMESelection(
+  MOZ_CAN_RUN_SCRIPT static nsresult SetIMESelection(
       EditorBase& aEditorBase, dom::Text* aTextNode, uint32_t aOffsetInNode,
       uint32_t aLengthOfCompositionString, const TextRangeArray* aRanges);
 
  private:
   virtual ~CompositionTransaction() = default;
 
-  nsresult SetSelectionForRanges();
+  MOZ_CAN_RUN_SCRIPT nsresult SetSelectionForRanges();
 
   // The text element to operate upon.
   RefPtr<dom::Text> mTextNode;
 
   // The offsets into mTextNode where the insertion should be placed.
   uint32_t mOffset;
 
   uint32_t mReplaceLength;
--- a/editor/libeditor/CreateElementTransaction.cpp
+++ b/editor/libeditor/CreateElementTransaction.cpp
@@ -64,18 +64,17 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(Creat
                                    EditTransactionBase, mEditorBase,
                                    mPointToInsert, mNewElement)
 
 NS_IMPL_ADDREF_INHERITED(CreateElementTransaction, EditTransactionBase)
 NS_IMPL_RELEASE_INHERITED(CreateElementTransaction, EditTransactionBase)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CreateElementTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
-MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
-CreateElementTransaction::DoTransaction() {
+NS_IMETHODIMP CreateElementTransaction::DoTransaction() {
   if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTag) ||
       NS_WARN_IF(!mPointToInsert.IsSet())) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   OwningNonNull<EditorBase> editorBase = *mEditorBase;
 
   mNewElement = editorBase->CreateHTMLContent(mTag);
--- a/editor/libeditor/CreateElementTransaction.h
+++ b/editor/libeditor/CreateElementTransaction.h
@@ -46,27 +46,27 @@ class CreateElementTransaction final : p
       const EditorDOMPointBase<PT, CT>& aPointToInsert);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CreateElementTransaction,
                                            EditTransactionBase)
 
   NS_DECL_EDITTRANSACTIONBASE
 
-  NS_IMETHOD RedoTransaction() override;
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD RedoTransaction() override;
 
   dom::Element* GetNewElement() const { return mNewElement; }
 
  protected:
   virtual ~CreateElementTransaction() = default;
 
   /**
    * InsertNewNode() inserts mNewNode before the child node at mPointToInsert.
    */
-  void InsertNewNode(ErrorResult& aError);
+  MOZ_CAN_RUN_SCRIPT void InsertNewNode(ErrorResult& aError);
 
   // The document into which the new node will be inserted.
   RefPtr<EditorBase> mEditorBase;
 
   // The tag (mapping to object type) for the new element.
   RefPtr<nsAtom> mTag;
 
   // The DOM point we will insert mNewNode.
--- a/editor/libeditor/DeleteNodeTransaction.h
+++ b/editor/libeditor/DeleteNodeTransaction.h
@@ -43,17 +43,17 @@ class DeleteNodeTransaction final : publ
   bool CanDoIt() const;
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DeleteNodeTransaction,
                                            EditTransactionBase)
 
   NS_DECL_EDITTRANSACTIONBASE
 
-  NS_IMETHOD RedoTransaction() override;
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD RedoTransaction() override;
 
  protected:
   virtual ~DeleteNodeTransaction() = default;
 
   // The editor for this transaction.
   RefPtr<EditorBase> mEditorBase;
 
   // The element to delete.
--- a/editor/libeditor/DeleteRangeTransaction.h
+++ b/editor/libeditor/DeleteRangeTransaction.h
@@ -44,17 +44,17 @@ class DeleteRangeTransaction final : pub
   }
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DeleteRangeTransaction,
                                            EditAggregateTransaction)
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
 
   NS_DECL_EDITTRANSACTIONBASE
 
-  NS_IMETHOD RedoTransaction() override;
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD RedoTransaction() override;
 
  protected:
   /**
    * CreateTxnsToDeleteBetween() creates a DeleteTextTransaction or some
    * DeleteNodeTransactions to remove text or nodes between aStart and aEnd
    * and appends the created transactions to the array.
    *
    * @param aStart      Must be set and valid point.
--- a/editor/libeditor/DeleteTextTransaction.cpp
+++ b/editor/libeditor/DeleteTextTransaction.cpp
@@ -92,18 +92,17 @@ NS_INTERFACE_MAP_END_INHERITING(EditTran
 
 bool DeleteTextTransaction::CanDoIt() const {
   if (NS_WARN_IF(!mTextNode) || NS_WARN_IF(!mEditorBase)) {
     return false;
   }
   return mEditorBase->IsModifiableNode(*mTextNode);
 }
 
-MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
-DeleteTextTransaction::DoTransaction() {
+NS_IMETHODIMP DeleteTextTransaction::DoTransaction() {
   if (NS_WARN_IF(!CanDoIt())) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Get the text that we're about to delete
   ErrorResult error;
   mTextNode->SubstringData(mOffset, mLengthToDelete, mDeletedText, error);
   if (error.Failed()) {
@@ -135,18 +134,17 @@ DeleteTextTransaction::DoTransaction() {
   }
   selection->Collapse(EditorRawDOMPoint(textNode, mOffset), error);
   NS_WARNING_ASSERTION(!error.Failed(), "Selection::Collapse() failed");
   return error.StealNSResult();
 }
 
 // XXX: We may want to store the selection state and restore it properly.  Was
 //     it an insertion point or an extended selection?
-MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
-DeleteTextTransaction::UndoTransaction() {
+NS_IMETHODIMP DeleteTextTransaction::UndoTransaction() {
   if (NS_WARN_IF(!CanDoIt())) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   RefPtr<EditorBase> editorBase = mEditorBase;
   RefPtr<Text> textNode = mTextNode;
   ErrorResult error;
   editorBase->DoInsertText(*textNode, mOffset, mDeletedText, error);
   NS_WARNING_ASSERTION(!error.Failed(), "EditorBase::DoInsertText() failed");
--- a/editor/libeditor/EditAggregateTransaction.cpp
+++ b/editor/libeditor/EditAggregateTransaction.cpp
@@ -19,45 +19,46 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(EditA
 NS_IMPL_ADDREF_INHERITED(EditAggregateTransaction, EditTransactionBase)
 NS_IMPL_RELEASE_INHERITED(EditAggregateTransaction, EditTransactionBase)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EditAggregateTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
 NS_IMETHODIMP EditAggregateTransaction::DoTransaction() {
   // FYI: It's legal (but not very useful) to have an empty child list.
   AutoTArray<OwningNonNull<EditTransactionBase>, 10> children(mChildren);
-  for (auto& childTransaction : children) {
-    nsresult rv = childTransaction->DoTransaction();
+  for (OwningNonNull<EditTransactionBase>& childTransaction : children) {
+    nsresult rv = MOZ_KnownLive(childTransaction)->DoTransaction();
     if (NS_FAILED(rv)) {
       NS_WARNING("EditTransactionBase::DoTransaction() failed");
       return rv;
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP EditAggregateTransaction::UndoTransaction() {
   // FYI: It's legal (but not very useful) to have an empty child list.
   // Undo goes through children backwards.
   AutoTArray<OwningNonNull<EditTransactionBase>, 10> children(mChildren);
-  for (auto& childTransaction : Reversed(children)) {
-    nsresult rv = childTransaction->UndoTransaction();
+  for (OwningNonNull<EditTransactionBase>& childTransaction :
+       Reversed(children)) {
+    nsresult rv = MOZ_KnownLive(childTransaction)->UndoTransaction();
     if (NS_FAILED(rv)) {
       NS_WARNING("EditTransactionBase::UndoTransaction() failed");
       return rv;
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP EditAggregateTransaction::RedoTransaction() {
   // It's legal (but not very useful) to have an empty child list.
   AutoTArray<OwningNonNull<EditTransactionBase>, 10> children(mChildren);
-  for (auto& childTransaction : children) {
-    nsresult rv = childTransaction->RedoTransaction();
+  for (OwningNonNull<EditTransactionBase>& childTransaction : children) {
+    nsresult rv = MOZ_KnownLive(childTransaction)->RedoTransaction();
     if (NS_FAILED(rv)) {
       NS_WARNING("EditTransactionBase::RedoTransaction() failed");
       return rv;
     }
   }
   return NS_OK;
 }
 
--- a/editor/libeditor/EditAggregateTransaction.h
+++ b/editor/libeditor/EditAggregateTransaction.h
@@ -38,17 +38,17 @@ class EditAggregateTransaction : public 
   }
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(EditAggregateTransaction,
                                            EditTransactionBase)
 
   NS_DECL_EDITTRANSACTIONBASE
 
-  NS_IMETHOD RedoTransaction() override;
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD RedoTransaction() override;
   NS_IMETHOD Merge(nsITransaction* aTransaction, bool* aDidMerge) override;
 
   /**
    * Append a transaction to this aggregate.
    */
   NS_IMETHOD AppendChild(EditTransactionBase* aTransaction);
 
   /**
--- a/editor/libeditor/EditTransactionBase.h
+++ b/editor/libeditor/EditTransactionBase.h
@@ -16,23 +16,23 @@ namespace mozilla {
 /**
  * Base class for all document editing transactions.
  */
 class EditTransactionBase : public nsITransaction {
  public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(EditTransactionBase, nsITransaction)
 
-  NS_IMETHOD RedoTransaction(void) override;
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD RedoTransaction(void) override;
   NS_IMETHOD GetIsTransient(bool* aIsTransient) override;
   NS_IMETHOD Merge(nsITransaction* aTransaction, bool* aDidMerge) override;
 
  protected:
   virtual ~EditTransactionBase() = default;
 };
 
 }  // namespace mozilla
 
-#define NS_DECL_EDITTRANSACTIONBASE    \
-  NS_IMETHOD DoTransaction() override; \
-  NS_IMETHOD UndoTransaction() override;
+#define NS_DECL_EDITTRANSACTIONBASE                       \
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD DoTransaction() override; \
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD UndoTransaction() override;
 
 #endif  // #ifndef mozilla_EditTransactionBase_h
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -355,17 +355,17 @@ nsresult EditorBase::PostCreate() {
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
                          "EditorBase::NotifyDocumentListeners("
                          "eDocumentStateChanged) failed, but ignored");
   }
 
   // update nsTextStateManager and caret if we have focus
   nsCOMPtr<nsIContent> focusedContent = GetFocusedContent();
   if (focusedContent) {
-    DebugOnly<nsresult> rvIgnored = InitializeSelection(focusedContent);
+    DebugOnly<nsresult> rvIgnored = InitializeSelection(*focusedContent);
     NS_WARNING_ASSERTION(
         NS_SUCCEEDED(rvIgnored),
         "EditorBase::InitializeSelection() failed, but ignored");
 
     // If the text control gets reframed during focus, Focus() would not be
     // called, so take a chance here to see if we need to spell check the text
     // control.
     mEventListener->SpellCheckIfNeeded();
@@ -5069,24 +5069,21 @@ Element* EditorBase::FindSelectionRoot(n
 }
 
 void EditorBase::InitializeSelectionAncestorLimit(nsIContent& aAncestorLimit) {
   MOZ_ASSERT(IsEditActionDataAvailable());
 
   SelectionRefPtr()->SetAncestorLimiter(&aAncestorLimit);
 }
 
-nsresult EditorBase::InitializeSelection(EventTarget* aFocusEventTarget) {
+nsresult EditorBase::InitializeSelection(nsINode& aFocusEventTargetNode) {
   MOZ_ASSERT(IsEditActionDataAvailable());
 
-  nsCOMPtr<nsINode> targetNode = do_QueryInterface(aFocusEventTarget);
-  if (NS_WARN_IF(!targetNode)) {
-    return NS_ERROR_INVALID_ARG;
-  }
-  nsCOMPtr<nsIContent> selectionRootContent = FindSelectionRoot(targetNode);
+  nsCOMPtr<nsIContent> selectionRootContent =
+      FindSelectionRoot(&aFocusEventTargetNode);
   if (!selectionRootContent) {
     return NS_OK;
   }
 
   nsCOMPtr<nsISelectionController> selectionController =
       GetSelectionController();
   if (NS_WARN_IF(!selectionController)) {
     return NS_ERROR_FAILURE;
@@ -5108,17 +5105,18 @@ nsresult EditorBase::InitializeSelection
       NS_SUCCEEDED(rvIgnored),
       "nsISelectionController::SetCaretEnabled() failed, but ignored");
   // NOTE(emilio): It's important for this call to be after
   // SetCaretEnabled(true), since that would override mIgnoreUserModify to true.
   //
   // Also, make sure to always ignore it for designMode, since that effectively
   // overrides everything and we allow to edit stuff with
   // contenteditable="false" subtrees in such a document.
-  caret->SetIgnoreUserModify(targetNode->OwnerDoc()->HasFlag(NODE_IS_EDITABLE));
+  caret->SetIgnoreUserModify(
+      aFocusEventTargetNode.OwnerDoc()->HasFlag(NODE_IS_EDITABLE));
 
   // Init selection
   rvIgnored =
       selectionController->SetSelectionFlags(nsISelectionDisplay::DISPLAY_ALL);
   NS_WARNING_ASSERTION(
       NS_SUCCEEDED(rvIgnored),
       "nsISelectionController::SetSelectionFlags() failed, but ignored");
 
@@ -5143,25 +5141,26 @@ nsresult EditorBase::InitializeSelection
     // XXX If selection is changed during reframe, this doesn't work well!
     nsRange* firstRange = SelectionRefPtr()->GetRangeAt(0);
     if (NS_WARN_IF(!firstRange)) {
       return NS_ERROR_FAILURE;
     }
     EditorRawDOMPoint atStartOfFirstRange(firstRange->StartRef());
     EditorRawDOMPoint betterInsertionPoint =
         FindBetterInsertionPoint(atStartOfFirstRange);
-    Text* textNode = betterInsertionPoint.GetContainerAsText();
+    RefPtr<Text> textNode = betterInsertionPoint.GetContainerAsText();
     MOZ_ASSERT(textNode,
                "There must be text node if composition string is not empty");
     if (textNode) {
       MOZ_ASSERT(textNode->Length() >= mComposition->XPEndOffsetInTextNode(),
                  "The text node must be different from the old text node");
+      RefPtr<TextRangeArray> ranges = mComposition->GetRanges();
       DebugOnly<nsresult> rvIgnored = CompositionTransaction::SetIMESelection(
           *this, textNode, mComposition->XPOffsetInTextNode(),
-          mComposition->XPLengthInTextNode(), mComposition->GetRanges());
+          mComposition->XPLengthInTextNode(), ranges);
       NS_WARNING_ASSERTION(
           NS_SUCCEEDED(rvIgnored),
           "CompositionTransaction::SetIMESelection() failed, but ignored");
     }
   }
 
   return NS_OK;
 }
@@ -5210,17 +5209,17 @@ void EditorBase::ReinitializeSelection(E
     return;
   }
 
   AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
   if (NS_WARN_IF(!editActionData.CanHandle())) {
     return;
   }
 
-  OnFocus(&aElement);
+  OnFocus(aElement);
 
   // If previous focused editor turn on spellcheck and this editor doesn't
   // turn on it, spellcheck state is mismatched.  So we need to re-sync it.
   SyncRealTimeSpell();
 
   nsPresContext* context = GetPresContext();
   if (NS_WARN_IF(!context)) {
     return;
@@ -5488,23 +5487,23 @@ bool EditorBase::IsAcceptableInputEvent(
     return false;
   }
 
   // Otherwise, we shouldn't handle any input events when we're not an active
   // element of the DOM window.
   return IsActiveInDOMWindow();
 }
 
-void EditorBase::OnFocus(EventTarget* aFocusEventTarget) {
+void EditorBase::OnFocus(nsINode& aFocusEventTargetNode) {
   AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
   if (NS_WARN_IF(!editActionData.CanHandle())) {
     return;
   }
 
-  InitializeSelection(aFocusEventTarget);
+  InitializeSelection(aFocusEventTargetNode);
   mSpellCheckerDictionaryUpdated = false;
   if (mInlineSpellChecker && CanEnableSpellCheck()) {
     DebugOnly<nsresult> rvIgnored =
         mInlineSpellChecker->UpdateCurrentDictionary();
     NS_WARNING_ASSERTION(
         NS_SUCCEEDED(rvIgnored),
         "mozInlineSpellCHecker::UpdateCurrentDictionary() failed, but ignored");
     mSpellCheckerDictionaryUpdated = true;
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -585,31 +585,31 @@ class EditorBase : public nsIEditor,
    */
   virtual Element* FindSelectionRoot(nsINode* aNode) const;
 
   /**
    * This method has to be called by EditorEventListener::Focus.
    * All actions that have to be done when the editor is focused needs to be
    * added here.
    */
-  void OnFocus(dom::EventTarget* aFocusEventTarget);
+  MOZ_CAN_RUN_SCRIPT void OnFocus(nsINode& aFocusEventTargetNode);
 
   /** Resyncs spellchecking state (enabled/disabled).  This should be called
    * when anything that affects spellchecking state changes, such as the
    * spellcheck attribute value.
    */
   void SyncRealTimeSpell();
 
   /**
    * This method re-initializes the selection and caret state that are for
    * current editor state. When editor session is destroyed, it always reset
    * selection state even if this has no focus.  So if destroying editor,
    * we have to call this method for focused editor to set selection state.
    */
-  void ReinitializeSelection(Element& aElement);
+  MOZ_CAN_RUN_SCRIPT void ReinitializeSelection(Element& aElement);
 
   /**
    * InsertTextAsAction() inserts aStringToInsert at selection.
    * Although this method is implementation of nsIEditor.insertText(),
    * this treats the input is an edit action.  If you'd like to insert text
    * as part of edit action, you probably should use InsertTextAsSubAction().
    *
    * @param aStringToInsert     The string to insert.
@@ -2356,17 +2356,17 @@ class EditorBase : public nsIEditor,
 
   /**
    * Used by AutoTransactionBatch.  After calling BeginTransactionInternal(),
    * all transactions will be treated as an atomic transaction.  I.e.,
    * two or more transactions are undid once.
    * XXX What's the difference with PlaceholderTransaction? Should we always
    *     use it instead?
    */
-  void BeginTransactionInternal();
+  MOZ_CAN_RUN_SCRIPT void BeginTransactionInternal();
   MOZ_CAN_RUN_SCRIPT void EndTransactionInternal();
 
  protected:  // Shouldn't be used by friend classes
   /**
    * The default destructor. This should suffice. Should this be pure virtual
    * for someone to derive from the EditorBase later? I don't believe so.
    */
   virtual ~EditorBase();
@@ -2578,17 +2578,17 @@ class EditorBase : public nsIEditor,
    */
   nsresult ClearSelection();
 
   /**
    * Initializes selection and caret for the editor.  If aEventTarget isn't
    * a host of the editor, i.e., the editor doesn't get focus, this does
    * nothing.
    */
-  nsresult InitializeSelection(dom::EventTarget* aFocusEventTarget);
+  MOZ_CAN_RUN_SCRIPT nsresult InitializeSelection(nsINode& aFocusEventTarget);
 
   enum NotificationForEditorObservers {
     eNotifyEditorObserversOfEnd,
     eNotifyEditorObserversOfBefore,
     eNotifyEditorObserversOfCancel
   };
   MOZ_CAN_RUN_SCRIPT void NotifyEditorObservers(
       NotificationForEditorObservers aNotification);
@@ -2633,17 +2633,17 @@ class EditorBase : public nsIEditor,
    *        AutoPlaceholderBatch instead.
    */
   class MOZ_RAII AutoTransactionBatch final {
    public:
     MOZ_CAN_RUN_SCRIPT explicit AutoTransactionBatch(
         EditorBase& aEditorBase MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
         : mEditorBase(aEditorBase) {
       MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-      mEditorBase.BeginTransactionInternal();
+      MOZ_KnownLive(mEditorBase).BeginTransactionInternal();
     }
 
     MOZ_CAN_RUN_SCRIPT ~AutoTransactionBatch() {
       MOZ_KnownLive(mEditorBase).EndTransactionInternal();
     }
 
    protected:
     EditorBase& mEditorBase;
--- a/editor/libeditor/EditorEventListener.cpp
+++ b/editor/libeditor/EditorEventListener.cpp
@@ -1170,17 +1170,17 @@ nsresult EditorEventListener::Focus(Inte
       if (!SameCOMIdentity(
               focusedContent->FindFirstNonChromeOnlyAccessContent(),
               originalTargetAsContent->FindFirstNonChromeOnlyAccessContent())) {
         return NS_OK;
       }
     }
   }
 
-  editorBase->OnFocus(target);
+  editorBase->OnFocus(*eventTargetNode);
   if (DetachedFromEditorOrDefaultPrevented(aFocusEvent)) {
     return NS_OK;
   }
 
   nsPresContext* presContext = GetPresContext();
   if (NS_WARN_IF(!presContext)) {
     return NS_OK;
   }
--- a/editor/libeditor/EditorEventListener.h
+++ b/editor/libeditor/EditorEventListener.h
@@ -70,17 +70,17 @@ class EditorEventListener : public nsIDO
   MOZ_CAN_RUN_SCRIPT void HandleEndComposition(
       WidgetCompositionEvent* aCompositionEvent);
   MOZ_CAN_RUN_SCRIPT virtual nsresult MouseDown(dom::MouseEvent* aMouseEvent);
   MOZ_CAN_RUN_SCRIPT virtual nsresult MouseUp(dom::MouseEvent* aMouseEvent) {
     return NS_OK;
   }
   MOZ_CAN_RUN_SCRIPT virtual nsresult MouseClick(
       WidgetMouseEvent* aMouseClickEvent);
-  nsresult Focus(InternalFocusEvent* aFocusEvent);
+  MOZ_CAN_RUN_SCRIPT nsresult Focus(InternalFocusEvent* aFocusEvent);
   nsresult Blur(InternalFocusEvent* aBlurEvent);
   MOZ_CAN_RUN_SCRIPT nsresult DragEnter(dom::DragEvent* aDragEvent);
   MOZ_CAN_RUN_SCRIPT nsresult DragOverOrDrop(dom::DragEvent* aDragEvent);
   nsresult DragExit(dom::DragEvent* aDragEvent);
 
   void RefuseToDropAndHideCaret(DragEvent* aDragEvent);
   bool DragEventHasSupportingData(DragEvent* aDragEvent) const;
   MOZ_CAN_RUN_SCRIPT bool CanInsertAtDropPosition(DragEvent* aDragEvent);
--- a/editor/libeditor/EditorUtils.h
+++ b/editor/libeditor/EditorUtils.h
@@ -695,17 +695,17 @@ class MOZ_STACK_CLASS SplitRangeOffResul
  * methods.
  ***************************************************************************/
 class MOZ_RAII AutoTransactionBatchExternal final {
  public:
   MOZ_CAN_RUN_SCRIPT explicit AutoTransactionBatchExternal(
       EditorBase& aEditorBase MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : mEditorBase(aEditorBase) {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    mEditorBase.BeginTransaction();
+    MOZ_KnownLive(mEditorBase).BeginTransaction();
   }
 
   MOZ_CAN_RUN_SCRIPT ~AutoTransactionBatchExternal() {
     MOZ_KnownLive(mEditorBase).EndTransaction();
   }
 
  private:
   EditorBase& mEditorBase;
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -5177,17 +5177,17 @@ void HTMLEditor::NotifyRootChanged() {
         "but ignored");
     return;
   }
 
   // When this editor has focus, we need to reset the selection limiter to
   // new root.  Otherwise, that is going to be done when this gets focus.
   nsCOMPtr<nsINode> node = GetFocusedNode();
   if (node) {
-    DebugOnly<nsresult> rvIgnored = InitializeSelection(node);
+    DebugOnly<nsresult> rvIgnored = InitializeSelection(*node);
     NS_WARNING_ASSERTION(
         NS_SUCCEEDED(rvIgnored),
         "EditorBase::InitializeSelection() failed, but ignored");
   }
 
   SyncRealTimeSpell();
 }
 
--- a/editor/libeditor/InsertNodeTransaction.cpp
+++ b/editor/libeditor/InsertNodeTransaction.cpp
@@ -55,18 +55,17 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(Inser
                                    mEditorBase, mContentToInsert,
                                    mPointToInsert)
 
 NS_IMPL_ADDREF_INHERITED(InsertNodeTransaction, EditTransactionBase)
 NS_IMPL_RELEASE_INHERITED(InsertNodeTransaction, EditTransactionBase)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InsertNodeTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
-MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
-InsertNodeTransaction::DoTransaction() {
+NS_IMETHODIMP InsertNodeTransaction::DoTransaction() {
   if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mContentToInsert) ||
       NS_WARN_IF(!mPointToInsert.IsSet())) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   if (!mPointToInsert.IsSetAndValid()) {
     // It seems that DOM tree has been changed after first DoTransaction()
     // and current RedoTranaction() call.
--- a/editor/libeditor/InsertTextTransaction.cpp
+++ b/editor/libeditor/InsertTextTransaction.cpp
@@ -40,18 +40,17 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(Inser
                                    mEditorBase, mTextNode)
 
 NS_IMPL_ADDREF_INHERITED(InsertTextTransaction, EditTransactionBase)
 NS_IMPL_RELEASE_INHERITED(InsertTextTransaction, EditTransactionBase)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InsertTextTransaction)
   NS_INTERFACE_MAP_ENTRY_CONCRETE(InsertTextTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
-MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
-InsertTextTransaction::DoTransaction() {
+NS_IMETHODIMP InsertTextTransaction::DoTransaction() {
   if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   OwningNonNull<EditorBase> editorBase = *mEditorBase;
   OwningNonNull<Text> textNode = *mTextNode;
 
   ErrorResult error;
@@ -77,18 +76,17 @@ InsertTextTransaction::DoTransaction() {
   // XXX Other transactions do not do this but its callers do.
   //     Why do this transaction do this by itself?
   editorBase->RangeUpdaterRef().SelAdjInsertText(textNode, mOffset,
                                                  mStringToInsert);
 
   return NS_OK;
 }
 
-MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
-InsertTextTransaction::UndoTransaction() {
+NS_IMETHODIMP InsertTextTransaction::UndoTransaction() {
   if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
     return NS_ERROR_NOT_INITIALIZED;
   }
   OwningNonNull<EditorBase> editorBase = *mEditorBase;
   OwningNonNull<Text> textNode = *mTextNode;
   ErrorResult error;
   editorBase->DoDeleteText(textNode, mOffset, mStringToInsert.Length(), error);
   NS_WARNING_ASSERTION(!error.Failed(), "EditorBase::DoDeleteText() failed");
--- a/editor/libeditor/JoinNodeTransaction.cpp
+++ b/editor/libeditor/JoinNodeTransaction.cpp
@@ -49,17 +49,17 @@ bool JoinNodeTransaction::CanDoIt() cons
       NS_WARN_IF(!mEditorBase) || !mLeftContent->GetParentNode()) {
     return false;
   }
   return mEditorBase->IsModifiableNode(*mLeftContent->GetParentNode());
 }
 
 // After DoTransaction() and RedoTransaction(), the left node is removed from
 // the content tree and right node remains.
-MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP JoinNodeTransaction::DoTransaction() {
+NS_IMETHODIMP JoinNodeTransaction::DoTransaction() {
   if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mLeftContent) ||
       NS_WARN_IF(!mRightContent)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Get the parent node
   nsCOMPtr<nsINode> leftContentParent = mLeftContent->GetParentNode();
   if (NS_WARN_IF(!leftContentParent)) {
@@ -82,18 +82,17 @@ MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIM
   OwningNonNull<nsINode> rightNode = *mRightContent;
   nsresult rv = editorBase->DoJoinNodes(rightNode, leftNode, leftContentParent);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "EditorBase::DoJoinNodes() failed");
   return rv;
 }
 
 // XXX: What if instead of split, we just deleted the unneeded children of
 //     mRight and re-inserted mLeft?
-MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
-JoinNodeTransaction::UndoTransaction() {
+NS_IMETHODIMP JoinNodeTransaction::UndoTransaction() {
   if (NS_WARN_IF(!mParentNode) || NS_WARN_IF(!mLeftContent) ||
       NS_WARN_IF(!mRightContent) || NS_WARN_IF(!mEditorBase)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   OwningNonNull<nsIContent> leftContent = *mLeftContent;
   OwningNonNull<nsIContent> rightContent = *mRightContent;
   OwningNonNull<nsINode> parentNode = *mParentNode;
--- a/editor/libeditor/PlaceholderTransaction.h
+++ b/editor/libeditor/PlaceholderTransaction.h
@@ -50,17 +50,17 @@ class PlaceholderTransaction final : pub
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PlaceholderTransaction,
                                            EditAggregateTransaction)
   // ------------ EditAggregateTransaction -----------------------
 
   NS_DECL_EDITTRANSACTIONBASE
 
-  NS_IMETHOD RedoTransaction() override;
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD RedoTransaction() override;
   NS_IMETHOD Merge(nsITransaction* aTransaction, bool* aDidMerge) override;
 
   // ------------ nsIAbsorbingTransaction -----------------------
 
   NS_IMETHOD GetTxnName(nsAtom** aName) override;
 
   NS_IMETHOD_(bool) StartSelectionEquals(SelectionState& aSelState) override;
 
--- a/editor/libeditor/SplitNodeTransaction.cpp
+++ b/editor/libeditor/SplitNodeTransaction.cpp
@@ -45,18 +45,17 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(Split
                                    mEditorBase, mStartOfRightContent,
                                    mContainerParentNode, mNewLeftContent)
 
 NS_IMPL_ADDREF_INHERITED(SplitNodeTransaction, EditTransactionBase)
 NS_IMPL_RELEASE_INHERITED(SplitNodeTransaction, EditTransactionBase)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SplitNodeTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
 
-MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
-SplitNodeTransaction::DoTransaction() {
+NS_IMETHODIMP SplitNodeTransaction::DoTransaction() {
   if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mStartOfRightContent.IsSet())) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   MOZ_ASSERT(mStartOfRightContent.IsSetAndValid());
 
   // Create a new node
   ErrorResult error;
   // Don't use .downcast directly because AsContent has an assertion we want
@@ -113,18 +112,17 @@ SplitNodeTransaction::DoTransaction() {
     return NS_ERROR_FAILURE;
   }
   EditorRawDOMPoint atEndOfLeftNode(EditorRawDOMPoint::AtEndOf(newLeftContent));
   selection->Collapse(atEndOfLeftNode, error);
   NS_WARNING_ASSERTION(!error.Failed(), "Selection::Collapse() failed");
   return error.StealNSResult();
 }
 
-MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
-SplitNodeTransaction::UndoTransaction() {
+NS_IMETHODIMP SplitNodeTransaction::UndoTransaction() {
   if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mNewLeftContent) ||
       NS_WARN_IF(!mContainerParentNode) ||
       NS_WARN_IF(!mStartOfRightContent.IsSet())) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // This assumes Do inserted the new node in front of the prior existing node
   // XXX Perhaps, we should reset mStartOfRightNode with current first child
@@ -138,18 +136,17 @@ SplitNodeTransaction::UndoTransaction() 
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "EditorBase::DoJoinNodes() failed");
   return rv;
 }
 
 /* Redo cannot simply resplit the right node, because subsequent transactions
  * on the redo stack may depend on the left node existing in its previous
  * state.
  */
-MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
-SplitNodeTransaction::RedoTransaction() {
+NS_IMETHODIMP SplitNodeTransaction::RedoTransaction() {
   if (NS_WARN_IF(!mNewLeftContent) || NS_WARN_IF(!mContainerParentNode) ||
       NS_WARN_IF(!mStartOfRightContent.IsSet()) || NS_WARN_IF(!mEditorBase)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   OwningNonNull<EditorBase> editorBase = *mEditorBase;
   OwningNonNull<nsINode> newLeftContent = *mNewLeftContent;
   OwningNonNull<nsINode> containerParentNode = *mContainerParentNode;
--- a/editor/libeditor/SplitNodeTransaction.h
+++ b/editor/libeditor/SplitNodeTransaction.h
@@ -46,17 +46,17 @@ class SplitNodeTransaction final : publi
       const EditorDOMPointBase<PT, CT>& aStartOfRightContent);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SplitNodeTransaction,
                                            EditTransactionBase)
 
   NS_DECL_EDITTRANSACTIONBASE
 
-  NS_IMETHOD RedoTransaction() override;
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD RedoTransaction() override;
 
   nsIContent* GetNewLeftContent() const { return mNewLeftContent; }
 
  protected:
   virtual ~SplitNodeTransaction() = default;
 
   RefPtr<EditorBase> mEditorBase;
 
--- a/editor/nsIEditor.idl
+++ b/editor/nsIEditor.idl
@@ -256,16 +256,17 @@ interface nsIEditor  : nsISupports
     * that should be treated as a single logical operation,
     * in the most efficient way possible.<br>
     * All transactions executed between a call to beginTransaction and
     * endTransaction will be undoable as an atomic action.<br>
     * endTransaction must be called after beginTransaction.<br>
     * Calls to beginTransaction can be nested, as long as endTransaction
     * is called once per beginUpdate.
     */
+  [can_run_script]
   void beginTransaction();
 
   /** endTransaction is a signal to the editor that the caller is
     * finished updating the content model.<br>
     * beginUpdate must be called before endTransaction is called.<br>
     * Calls to beginTransaction can be nested, as long as endTransaction
     * is called once per beginTransaction.
     */
--- a/editor/txmgr/TransactionItem.cpp
+++ b/editor/txmgr/TransactionItem.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TransactionItem.h"
 
 #include "mozilla/mozalloc.h"
+#include "mozilla/OwningNonNull.h"
 #include "mozilla/TransactionManager.h"
 #include "mozilla/TransactionStack.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsISupportsImpl.h"
 #include "nsITransaction.h"
 
@@ -71,17 +72,18 @@ nsresult TransactionItem::AddChild(Trans
 already_AddRefed<nsITransaction> TransactionItem::GetTransaction() {
   return do_AddRef(mTransaction);
 }
 
 nsresult TransactionItem::DoTransaction() {
   if (!mTransaction) {
     return NS_OK;
   }
-  nsresult rv = mTransaction->DoTransaction();
+  OwningNonNull<nsITransaction> transaction = *mTransaction;
+  nsresult rv = transaction->DoTransaction();
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                        "nsITransaction::DoTransaction() failed");
   return rv;
 }
 
 nsresult TransactionItem::UndoTransaction(
     TransactionManager* aTransactionManager) {
   nsresult rv = UndoChildren(aTransactionManager);
@@ -92,17 +94,18 @@ nsresult TransactionItem::UndoTransactio
                          "TransactionItem::RecoverFromUndoError() failed");
     return rv;
   }
 
   if (!mTransaction) {
     return NS_OK;
   }
 
-  rv = mTransaction->UndoTransaction();
+  OwningNonNull<nsITransaction> transaction = *mTransaction;
+  rv = transaction->UndoTransaction();
   if (NS_SUCCEEDED(rv)) {
     return NS_OK;
   }
 
   NS_WARNING("TransactionItem::UndoTransaction() failed");
   DebugOnly<nsresult> rvIgnored = RecoverFromUndoError(aTransactionManager);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
                        "TransactionItem::RecoverFromUndoError() failed");
@@ -252,29 +255,31 @@ nsresult TransactionItem::RecoverFromUnd
   nsresult rv = RedoChildren(aTransactionManager);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                        "TransactionItem::RedoChildren() failed");
   return rv;
 }
 
 nsresult TransactionItem::RecoverFromRedoError(
     TransactionManager* aTransactionManager) {
+  OwningNonNull<nsITransaction> transaction = *mTransaction;
+
   // If this method gets called, we already successfully called
   // RedoTransaction() for the transaction item itself. Undo all
   // the children that successfully called RedoTransaction(),
   // then undo the transaction item itself.
   nsresult rv = UndoChildren(aTransactionManager);
   if (NS_FAILED(rv)) {
     NS_WARNING("TransactionItem::UndoChildren() failed");
     return rv;
   }
 
   if (!mTransaction) {
     return NS_OK;
   }
 
-  rv = mTransaction->UndoTransaction();
+  rv = transaction->UndoTransaction();
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                        "nsITransaction::UndoTransaction() failed");
   return rv;
 }
 
 }  // namespace mozilla
--- a/editor/txmgr/TransactionItem.h
+++ b/editor/txmgr/TransactionItem.h
@@ -29,28 +29,34 @@ class TransactionItem final {
 
   nsresult AddChild(TransactionItem& aTransactionItem);
   already_AddRefed<nsITransaction> GetTransaction();
   size_t NumberOfChildren() const {
     return NumberOfUndoItems() + NumberOfRedoItems();
   }
   nsresult GetChild(size_t aIndex, TransactionItem** aChild);
 
-  nsresult DoTransaction();
-  nsresult UndoTransaction(TransactionManager* aTransactionManager);
-  nsresult RedoTransaction(TransactionManager* aTransactionManager);
+  MOZ_CAN_RUN_SCRIPT nsresult DoTransaction();
+  MOZ_CAN_RUN_SCRIPT nsresult
+  UndoTransaction(TransactionManager* aTransactionManager);
+  MOZ_CAN_RUN_SCRIPT nsresult
+  RedoTransaction(TransactionManager* aTransactionManager);
 
   nsCOMArray<nsISupports>& GetData() { return mData; }
 
  private:
-  nsresult UndoChildren(TransactionManager* aTransactionManager);
-  nsresult RedoChildren(TransactionManager* aTransactionManager);
+  MOZ_CAN_RUN_SCRIPT nsresult
+  UndoChildren(TransactionManager* aTransactionManager);
+  MOZ_CAN_RUN_SCRIPT nsresult
+  RedoChildren(TransactionManager* aTransactionManager);
 
-  nsresult RecoverFromUndoError(TransactionManager* aTransactionManager);
-  nsresult RecoverFromRedoError(TransactionManager* aTransactionManager);
+  MOZ_CAN_RUN_SCRIPT nsresult
+  RecoverFromUndoError(TransactionManager* aTransactionManager);
+  MOZ_CAN_RUN_SCRIPT nsresult
+  RecoverFromRedoError(TransactionManager* aTransactionManager);
 
   size_t NumberOfUndoItems() const;
   size_t NumberOfRedoItems() const;
 
   void CleanUp();
 
   ~TransactionItem();
 
--- a/editor/txmgr/TransactionManager.cpp
+++ b/editor/txmgr/TransactionManager.cpp
@@ -206,17 +206,17 @@ nsresult TransactionManager::BeginBatchI
   if (NS_FAILED(rv)) {
     NS_WARNING("TransactionManager::WillBeginBatchNotify() failed");
     return rv;
   }
   if (doInterrupt) {
     return NS_OK;
   }
 
-  rv = BeginTransaction(0, aData);
+  rv = BeginTransaction(nullptr, aData);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                        "TransactionManager::BeginTransaction() failed");
 
   nsresult rv2 = DidBeginBatchNotify(rv);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv2),
                        "TransactionManager::DidBeginBatchNotify() failed");
 
   // XXX The result of BeginTransaction() or DidBeginBatchNotify() if
--- a/editor/txmgr/TransactionManager.h
+++ b/editor/txmgr/TransactionManager.h
@@ -30,18 +30,18 @@ class TransactionManager final : public 
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(TransactionManager,
                                            nsITransactionManager)
 
   NS_DECL_NSITRANSACTIONMANAGER
 
   already_AddRefed<nsITransaction> PeekUndoStack();
   already_AddRefed<nsITransaction> PeekRedoStack();
 
-  nsresult Undo();
-  nsresult Redo();
+  MOZ_CAN_RUN_SCRIPT nsresult Undo();
+  MOZ_CAN_RUN_SCRIPT nsresult Redo();
 
   size_t NumberOfUndoItems() const { return mUndoStack.GetSize(); }
   size_t NumberOfRedoItems() const { return mRedoStack.GetSize(); }
 
   int32_t NumberOfMaximumTransactions() const { return mMaxTransactionCount; }
 
   bool EnableUndoRedo(int32_t aMaxTransactionCount = -1);
   bool DisableUndoRedo() { return EnableUndoRedo(0); }
@@ -57,41 +57,52 @@ class TransactionManager final : public 
   bool AddTransactionListener(nsITransactionListener& aListener) {
     // XXX Shouldn't we check if aListener has already been in mListeners?
     return mListeners.AppendObject(&aListener);
   }
   bool RemoveTransactionListener(nsITransactionListener& aListener) {
     return mListeners.RemoveObject(&aListener);
   }
 
-  nsresult WillDoNotify(nsITransaction* aTransaction, bool* aInterrupt);
-  nsresult DidDoNotify(nsITransaction* aTransaction, nsresult aExecuteResult);
-  nsresult WillUndoNotify(nsITransaction* aTransaction, bool* aInterrupt);
-  nsresult DidUndoNotify(nsITransaction* aTransaction, nsresult aUndoResult);
-  nsresult WillRedoNotify(nsITransaction* aTransaction, bool* aInterrupt);
-  nsresult DidRedoNotify(nsITransaction* aTransaction, nsresult aRedoResult);
-  nsresult WillBeginBatchNotify(bool* aInterrupt);
-  nsresult DidBeginBatchNotify(nsresult aResult);
-  nsresult WillEndBatchNotify(bool* aInterrupt);
-  nsresult DidEndBatchNotify(nsresult aResult);
-  nsresult WillMergeNotify(nsITransaction* aTop, nsITransaction* aTransaction,
-                           bool* aInterrupt);
-  nsresult DidMergeNotify(nsITransaction* aTop, nsITransaction* aTransaction,
-                          bool aDidMerge, nsresult aMergeResult);
+  // FYI: We don't need to treat the following methods as `MOZ_CAN_RUN_SCRIPT`
+  //      for now because only ComposerCommandUpdater is the listener and it
+  //      does not do something dangerous synchronously.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
+  WillDoNotify(nsITransaction* aTransaction, bool* aInterrupt);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult DidDoNotify(nsITransaction* aTransaction,
+                                                   nsresult aExecuteResult);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
+  WillUndoNotify(nsITransaction* aTransaction, bool* aInterrupt);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
+  DidUndoNotify(nsITransaction* aTransaction, nsresult aUndoResult);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
+  WillRedoNotify(nsITransaction* aTransaction, bool* aInterrupt);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
+  DidRedoNotify(nsITransaction* aTransaction, nsresult aRedoResult);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult WillBeginBatchNotify(bool* aInterrupt);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult DidBeginBatchNotify(nsresult aResult);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult WillEndBatchNotify(bool* aInterrupt);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult DidEndBatchNotify(nsresult aResult);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult WillMergeNotify(
+      nsITransaction* aTop, nsITransaction* aTransaction, bool* aInterrupt);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
+  DidMergeNotify(nsITransaction* aTop, nsITransaction* aTransaction,
+                 bool aDidMerge, nsresult aMergeResult);
 
   /**
    * Exposing non-virtual methods of nsITransactionManager methods.
    */
-  nsresult BeginBatchInternal(nsISupports* aData);
+  MOZ_CAN_RUN_SCRIPT nsresult BeginBatchInternal(nsISupports* aData);
   nsresult EndBatchInternal(bool aAllowEmpty);
 
  private:
   virtual ~TransactionManager() = default;
 
-  nsresult BeginTransaction(nsITransaction* aTransaction, nsISupports* aData);
+  MOZ_CAN_RUN_SCRIPT nsresult BeginTransaction(nsITransaction* aTransaction,
+                                               nsISupports* aData);
   nsresult EndTransaction(bool aAllowEmpty);
 
   int32_t mMaxTransactionCount;
   TransactionStack mDoStack;
   TransactionStack mUndoStack;
   TransactionStack mRedoStack;
   nsCOMArray<nsITransactionListener> mListeners;
 };
--- a/editor/txmgr/nsITransaction.idl
+++ b/editor/txmgr/nsITransaction.idl
@@ -12,30 +12,33 @@
  * execute some behavior that must be tracked by the transaction manager.
  */
 [scriptable, uuid(58e330c1-7b48-11d2-98b9-00805f297d89)]
 interface nsITransaction : nsISupports
 {
   /**
    * Executes the transaction.
    */
+  [can_run_script]
   void doTransaction();
 
   /**
    * Restores the state to what it was before the transaction was executed.
    */
+  [can_run_script]
   void undoTransaction();
 
   /**
    * Executes the transaction again. Can only be called on a transaction that
    * was previously undone.
    * <P>
    * In most cases, the redoTransaction() method will actually call the
    * doTransaction() method to execute the transaction again.
    */
+  [can_run_script]
   void redoTransaction();
 
   /**
    * The transaction's transient state. This attribute is checked by
    * the transaction manager after the transaction's Execute() method is called.
    * If the transient state is false, a reference to the transaction is
    * held by the transaction manager so that the transactions' undoTransaction()
    * and redoTransaction() methods can be called. If the transient state is
--- a/editor/txmgr/nsITransactionManager.idl
+++ b/editor/txmgr/nsITransactionManager.idl
@@ -26,28 +26,31 @@ interface nsITransactionManager : nsISup
    * Calls a transaction's doTransaction() method, then pushes it on the
    * undo stack.
    * <P>
    * This method calls the transaction's AddRef() method.
    * The transaction's Release() method will be called when the undo or redo
    * stack is pruned or when the transaction manager is destroyed.
    * @param aTransaction the transaction to do.
    */
+  [can_run_script]
   void doTransaction(in nsITransaction aTransaction);
 
   /**
    * Pops the topmost transaction on the undo stack, calls its
    * undoTransaction() method, then pushes it on the redo stack.
    */
+  [can_run_script]
   void undoTransaction();
 
   /**
    * Pops the topmost transaction on the redo stack, calls its
    * redoTransaction() method, then pushes it on the undo stack.
    */
+  [can_run_script]
   void redoTransaction();
 
   /**
    * Clears the undo and redo stacks.
    */
   void clear();
 
   /**
@@ -64,16 +67,17 @@ interface nsITransactionManager : nsISup
    * Turns on the transaction manager's batch mode, forcing all transactions
    * executed by the transaction manager's doTransaction() method to be
    * aggregated together until EndBatch() is called.  This mode allows an
    * application to execute and group together several independent transactions
    * so they can be undone with a single call to undoTransaction().
    * @param aData An arbitrary nsISupports object that is associated with the
    * batch. Can be retrieved from the undo or redo stacks.
    */
+  [can_run_script]
   void beginBatch(in nsISupports aData);
 
   /**
    * Turns off the transaction manager's batch mode.
    * @param aAllowEmpty If true, a batch containing no children will be
    * pushed onto the undo stack. Otherwise, ending a batch with no
    * children will result in no transactions being pushed on the undo stack.
    */
--- a/editor/txmgr/tests/TestTXMgr.cpp
+++ b/editor/txmgr/tests/TestTXMgr.cpp
@@ -265,49 +265,49 @@ class SimpleTransaction : public TestTra
   int32_t mFlags;
 
  public:
   explicit SimpleTransaction(int32_t aFlags = NONE_FLAG)
       : mVal(++sConstructorCount), mFlags(aFlags) {}
 
   ~SimpleTransaction() override = default;
 
-  NS_IMETHOD DoTransaction() override {
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD DoTransaction() override {
     //
     // Make sure DoTransaction() is called in the order we expect!
     // Notice that we don't check to see if we go past the end of the array.
     // This is done on purpose since we want to crash if the order array is out
     // of date.
     //
     if (sDoOrderArr) {
       EXPECT_EQ(mVal, sDoOrderArr[sDoCount]);
     }
 
     ++sDoCount;
 
     return (mFlags & THROWS_DO_ERROR_FLAG) ? NS_ERROR_FAILURE : NS_OK;
   }
 
-  NS_IMETHOD UndoTransaction() override {
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD UndoTransaction() override {
     //
     // Make sure UndoTransaction() is called in the order we expect!
     // Notice that we don't check to see if we go past the end of the array.
     // This is done on purpose since we want to crash if the order array is out
     // of date.
     //
     if (sUndoOrderArr) {
       EXPECT_EQ(mVal, sUndoOrderArr[sUndoCount]);
     }
 
     ++sUndoCount;
 
     return (mFlags & THROWS_UNDO_ERROR_FLAG) ? NS_ERROR_FAILURE : NS_OK;
   }
 
-  NS_IMETHOD RedoTransaction() override {
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD RedoTransaction() override {
     //
     // Make sure RedoTransaction() is called in the order we expect!
     // Notice that we don't check to see if we go past the end of the array.
     // This is done on purpose since we want to crash if the order array is out
     // of date.
     //
     if (sRedoOrderArr) {
       EXPECT_EQ(mVal, sRedoOrderArr[sRedoCount]);
@@ -367,17 +367,17 @@ class AggregateTransaction : public Simp
     mErrorFlags = aFlags & ALL_ERROR_FLAGS;
     mTXMgr = aTXMgr;
     mMaxLevel = aMaxLevel;
     mNumChildrenPerNode = aNumChildrenPerNode;
   }
 
   ~AggregateTransaction() override = default;
 
-  NS_IMETHOD DoTransaction() override {
+  MOZ_CAN_RUN_SCRIPT NS_IMETHOD DoTransaction() override {
     if (mLevel >= mMaxLevel) {
       // Only leaf nodes can throw errors!
       mFlags |= mErrorFlags;
     }
 
     nsresult rv = SimpleTransaction::DoTransaction();
     if (NS_FAILED(rv)) {
       // fail("QueryInterface() failed for transaction level %d. (%d)\n",
@@ -385,17 +385,17 @@ class AggregateTransaction : public Simp
       return rv;
     }
 
     if (mLevel >= mMaxLevel) {
       return NS_OK;
     }
 
     if (mFlags & BATCH_FLAG) {
-      rv = mTXMgr->BeginBatch(nullptr);
+      rv = MOZ_KnownLive(mTXMgr)->BeginBatch(nullptr);
       if (NS_FAILED(rv)) {
         return rv;
       }
     }
 
     int32_t cLevel = mLevel + 1;
 
     for (int i = 1; i <= mNumChildrenPerNode; i++) {
@@ -411,17 +411,17 @@ class AggregateTransaction : public Simp
         mErrorFlags = mErrorFlags & (~THROWS_UNDO_ERROR_FLAG);
       }
 
       flags |= mFlags & BATCH_FLAG;
 
       RefPtr<AggregateTransaction> tximpl = new AggregateTransaction(
           mTXMgr, cLevel, i, mMaxLevel, mNumChildrenPerNode, flags);
 
-      rv = mTXMgr->DoTransaction(tximpl);
+      rv = MOZ_KnownLive(mTXMgr)->DoTransaction(tximpl);
       if (NS_FAILED(rv)) {
         if (mFlags & BATCH_FLAG) {
           mTXMgr->EndBatch(false);
         }
         return rv;
       }
     }
 
@@ -477,32 +477,32 @@ void reset_globals() {
 
   sRedoCount = 0;
   sRedoOrderArr = 0;
 }
 
 /**
  * Test behaviors in non-batch mode.
  **/
-void quick_test(TestTransactionFactory* factory) {
+MOZ_CAN_RUN_SCRIPT_BOUNDARY void quick_test(TestTransactionFactory* factory) {
   /*******************************************************************
    *
    * Create a transaction manager implementation:
    *
    *******************************************************************/
 
   nsCOMPtr<nsITransactionManager> mgr = new TransactionManager();
 
   /*******************************************************************
    *
    * Call DoTransaction() with a null transaction:
    *
    *******************************************************************/
 
-  nsresult rv = mgr->DoTransaction(0);
+  nsresult rv = mgr->DoTransaction(nullptr);
   EXPECT_EQ(rv, NS_ERROR_NULL_POINTER);
 
   /*******************************************************************
    *
    * Call UndoTransaction() with an empty undo stack:
    *
    *******************************************************************/
 
@@ -1224,17 +1224,18 @@ TEST(TestTXMgr, AggregationTest)
   AggregateTransactionFactory factory(3, 2);
 
   quick_test(&factory);
 }
 
 /**
  * Test behaviors in batch mode.
  **/
-void quick_batch_test(TestTransactionFactory* factory) {
+MOZ_CAN_RUN_SCRIPT_BOUNDARY void quick_batch_test(
+    TestTransactionFactory* factory) {
   /*******************************************************************
    *
    * Create a transaction manager implementation:
    *
    *******************************************************************/
 
   nsCOMPtr<nsITransactionManager> mgr = new TransactionManager();
 
@@ -1853,17 +1854,18 @@ TEST(TestTXMgr, AggregationBatchTest)
 
   quick_batch_test(&factory);
 }
 
 /**
  * Create 'iterations * (iterations + 1) / 2' transactions;
  * do/undo/redo/undo them.
  **/
-void stress_test(TestTransactionFactory* factory, int32_t iterations) {
+MOZ_CAN_RUN_SCRIPT_BOUNDARY void stress_test(TestTransactionFactory* factory,
+                                             int32_t iterations) {
   /*******************************************************************
    *
    * Create a transaction manager:
    *
    *******************************************************************/
 
   nsCOMPtr<nsITransactionManager> mgr = new TransactionManager();