Bug 1632021 - part 3: Get rid of `nsIAbsorbingTransaction` r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 23 Apr 2020 10:46:55 +0000
changeset 525736 946dc29651752566cd9332cc832e9b17d10ea99b
parent 525735 a4a7fce9f73e62f6125f4d2dcf6e3d03db7a4093
child 525737 55abc248f5249c13b2511bff48ecad5cfb365d5d
push id37343
push usercsabou@mozilla.com
push dateFri, 24 Apr 2020 09:51:27 +0000
treeherdermozilla-central@f3686ddab414 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1632021
milestone77.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 1632021 - part 3: Get rid of `nsIAbsorbingTransaction` r=m_kato It's inherited only by `PlaceholderTransaction` and used only for QI. Therefore, we can get rid of it. Additionally, this makes storing `PlaceholderTransaction` and `CompositionTransaction` in `PlaceholderTransaction` faster and safer with `WeakPtr`. Finally, this makes `PlaceholderTransaction` always have non-null name because it caused a lot of useless warnings in `EditAggregationTransaction::GetName()` and `PlaceholderTransaction::GetTxnName()`. Differential Revision: https://phabricator.services.mozilla.com/D71910
editor/libeditor/CompositionTransaction.h
editor/libeditor/EditorBase.cpp
editor/libeditor/EditorBase.h
editor/libeditor/PlaceholderTransaction.cpp
editor/libeditor/PlaceholderTransaction.h
editor/libeditor/TextEditor.cpp
editor/libeditor/nsIAbsorbingTransaction.h
--- a/editor/libeditor/CompositionTransaction.h
+++ b/editor/libeditor/CompositionTransaction.h
@@ -3,17 +3,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef CompositionTransaction_h
 #define CompositionTransaction_h
 
 #include "mozilla/EditTransactionBase.h"  // base class
 
-#include "mozilla/EditorDOMPoint.h"        // EditorDOMPointInText
+#include "mozilla/EditorDOMPoint.h"  // EditorDOMPointInText
+#include "mozilla/WeakPtr.h"
 #include "nsCycleCollectionParticipant.h"  // various macros
 #include "nsString.h"                      // mStringToInsert
 
 #define NS_IMETEXTTXN_IID                            \
   {                                                  \
     0xb391355d, 0x346c, 0x43d1, {                    \
       0x85, 0xed, 0x9e, 0x65, 0xbe, 0xe7, 0x7e, 0x48 \
     }                                                \
@@ -30,17 +31,19 @@ class Text;
 }  // namespace dom
 
 /**
  * CompositionTransaction stores all edit for a composition, i.e.,
  * from compositionstart event to compositionend event.  E.g., inserting a
  * composition string, modifying the composition string or its IME selection
  * ranges and commit or cancel the composition.
  */
-class CompositionTransaction final : public EditTransactionBase {
+class CompositionTransaction final
+    : public EditTransactionBase,
+      public SupportsWeakPtr<CompositionTransaction> {
  protected:
   CompositionTransaction(EditorBase& aEditorBase,
                          const nsAString& aStringToInsert,
                          const EditorDOMPointInText& aPointToInsert);
 
  public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMETEXTTXN_IID)
 
@@ -55,16 +58,18 @@ class CompositionTransaction final : pub
    *                            E.g., password editor can hide the character
    *                            with a different character.
    * @param aPointToInsert      The insertion point.
    */
   static already_AddRefed<CompositionTransaction> Create(
       EditorBase& aEditorBase, const nsAString& aStringToInsert,
       const EditorDOMPointInText& aPointToInsert);
 
+  MOZ_DECLARE_WEAKREFERENCE_TYPENAME(CompositionTransaction)
+
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CompositionTransaction,
                                            EditTransactionBase)
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_EDITTRANSACTIONBASE
   NS_DECL_EDITTRANSACTIONBASE_GETASMETHODS_OVERRIDE(CompositionTransaction)
 
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -78,18 +78,16 @@
 #include "nsContentUtils.h"            // for nsContentUtils
 #include "nsDOMString.h"               // for DOMStringIsNull
 #include "nsDebug.h"                   // for NS_WARNING, etc.
 #include "nsError.h"                   // for NS_OK, etc.
 #include "nsFocusManager.h"            // for nsFocusManager
 #include "nsFrameSelection.h"          // for nsFrameSelection
 #include "nsGenericHTMLElement.h"      // for nsGenericHTMLElement
 #include "nsGkAtoms.h"                 // for nsGkAtoms, nsGkAtoms::dir
-#include "nsIAbsorbingTransaction.h"   // for nsIAbsorbingTransaction
-#include "nsAtom.h"                    // for nsAtom
 #include "nsIContent.h"                // for nsIContent
 #include "mozilla/dom/Document.h"      // for Document
 #include "nsIDocumentStateListener.h"  // for nsIDocumentStateListener
 #include "nsIEditActionListener.h"     // for nsIEditActionListener
 #include "nsIEditorObserver.h"         // for nsIEditorObserver
 #include "nsIFrame.h"                  // for nsIFrame
 #include "nsIInlineSpellChecker.h"     // for nsIInlineSpellChecker, etc.
 #include "nsNameSpaceManager.h"        // for kNameSpaceID_None, etc.
@@ -769,18 +767,19 @@ NS_IMETHODIMP EditorBase::DoTransaction(
 }
 
 nsresult EditorBase::DoTransactionInternal(nsITransaction* aTransaction) {
   MOZ_ASSERT(IsEditActionDataAvailable());
   MOZ_ASSERT(!NeedsToDispatchBeforeInputEvent(),
              "beforeinput event hasn't been dispatched yet");
 
   if (mPlaceholderBatch && !mPlaceholderTransaction) {
+    MOZ_DIAGNOSTIC_ASSERT(mPlaceholderName);
     mPlaceholderTransaction = PlaceholderTransaction::Create(
-        *this, mPlaceholderName, std::move(mSelState));
+        *this, *mPlaceholderName, std::move(mSelState));
     MOZ_ASSERT(mSelState.isNothing());
 
     // We will recurse, but will not hit this case in the nested call
     RefPtr<PlaceholderTransaction> placeholderTransaction =
         mPlaceholderTransaction;
     DebugOnly<nsresult> rvIgnored =
         DoTransactionInternal(placeholderTransaction);
     NS_WARNING_ASSERTION(
@@ -945,26 +944,26 @@ void EditorBase::EndTransactionInternal(
     DebugOnly<nsresult> rvIgnored = transactionManager->EndBatch(false);
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
                          "TransactionManager::EndBatch() failed, but ignored");
   }
 
   EndUpdateViewBatch();
 }
 
-void EditorBase::BeginPlaceholderTransaction(nsAtom* aTransactionName) {
+void EditorBase::BeginPlaceholderTransaction(nsStaticAtom& aTransactionName) {
   MOZ_ASSERT(IsEditActionDataAvailable());
   MOZ_ASSERT(mPlaceholderBatch >= 0, "negative placeholder batch count!");
 
   if (!mPlaceholderBatch) {
     NotifyEditorObservers(eNotifyEditorObserversOfBefore);
     // time to turn on the batch
     BeginUpdateViewBatch();
     mPlaceholderTransaction = nullptr;
-    mPlaceholderName = aTransactionName;
+    mPlaceholderName = &aTransactionName;
     mSelState.emplace();
     mSelState->SaveSelection(*SelectionRefPtr());
     // Composition transaction can modify multiple nodes and it merges text
     // node for ime into single text node.
     // So if current selection is into IME text node, it might be failed
     // to restore selection by UndoTransaction.
     // So we need update selection by range updater.
     if (mPlaceholderName == nsGkAtoms::IMETxnName) {
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -18,16 +18,17 @@
 #include "mozilla/SelectionState.h"      // for RangeUpdater, etc.
 #include "mozilla/StyleSheet.h"          // for StyleSheet
 #include "mozilla/TransactionManager.h"  // for TransactionManager
 #include "mozilla/WeakPtr.h"             // for WeakPtr
 #include "mozilla/dom/DataTransfer.h"    // for dom::DataTransfer
 #include "mozilla/dom/HTMLBRElement.h"   // for dom::HTMLBRElement
 #include "mozilla/dom/Selection.h"
 #include "mozilla/dom/Text.h"
+#include "nsAtom.h"    // for nsAtom, nsStaticAtom
 #include "nsCOMPtr.h"  // for already_AddRefed, nsCOMPtr
 #include "nsCycleCollectionParticipant.h"
 #include "nsGkAtoms.h"
 #include "mozilla/dom/Document.h"
 #include "nsIContentInlines.h"       // for nsINode::IsEditable()
 #include "nsIEditor.h"               // for nsIEditor, etc.
 #include "nsISelectionController.h"  // for nsISelectionController constants
 #include "nsISelectionListener.h"    // for nsISelectionListener
@@ -2231,20 +2232,19 @@ class EditorBase : public nsIEditor,
    * (Begin|End)PlaceholderTransaction() are called by AutoPlaceholderBatch.
    * This set of methods are similar to the (Begin|End)Transaction(), but do
    * not use the transaction managers batching feature.  Instead we use a
    * placeholder transaction to wrap up any further transaction while the
    * batch is open.  The advantage of this is that placeholder transactions
    * can later merge, if needed.  Merging is unavailable between transaction
    * manager batches.
    */
-  MOZ_CAN_RUN_SCRIPT_BOUNDARY
-  void BeginPlaceholderTransaction(nsAtom* aTransactionName);
-  MOZ_CAN_RUN_SCRIPT_BOUNDARY
-  void EndPlaceholderTransaction();
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY void BeginPlaceholderTransaction(
+      nsStaticAtom& aTransactionName);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY void EndPlaceholderTransaction();
 
   void BeginUpdateViewBatch();
   MOZ_CAN_RUN_SCRIPT void EndUpdateViewBatch();
 
   /**
    * Used by AutoTransactionBatch.  After calling BeginTransactionInternal(),
    * all transactions will be treated as an atomic transaction.  I.e.,
    * two or more transactions are undid once.
@@ -2542,25 +2542,25 @@ class EditorBase : public nsIEditor,
    * dispatches "input" event if it's necessary.
    */
   class MOZ_RAII AutoPlaceholderBatch final {
    public:
     explicit AutoPlaceholderBatch(
         EditorBase& aEditorBase MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
         : mEditorBase(aEditorBase) {
       MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-      mEditorBase->BeginPlaceholderTransaction(nullptr);
+      mEditorBase->BeginPlaceholderTransaction(*nsGkAtoms::_empty);
     }
 
     AutoPlaceholderBatch(EditorBase& aEditorBase,
-                         nsAtom& aTransactionName
+                         nsStaticAtom& aTransactionName
                              MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
         : mEditorBase(aEditorBase) {
       MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-      mEditorBase->BeginPlaceholderTransaction(&aTransactionName);
+      mEditorBase->BeginPlaceholderTransaction(aTransactionName);
     }
 
     ~AutoPlaceholderBatch() { mEditorBase->EndPlaceholderTransaction(); }
 
    protected:
     OwningNonNull<EditorBase> mEditorBase;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   };
@@ -2698,17 +2698,17 @@ class EditorBase : public nsIEditor,
   RefPtr<dom::HTMLBRElement> mPaddingBRElementForEmptyEditor;
 
   // The form field as an event receiver.
   nsCOMPtr<dom::EventTarget> mEventTarget;
   RefPtr<EditorEventListener> mEventListener;
   // Strong reference to placeholder for begin/end batch purposes.
   RefPtr<PlaceholderTransaction> mPlaceholderTransaction;
   // Name of placeholder transaction.
-  nsAtom* mPlaceholderName;
+  nsStaticAtom* mPlaceholderName;
   // Saved selection state for placeholder transaction batching.
   mozilla::Maybe<SelectionState> mSelState;
   // IME composition this is not null between compositionstart and
   // compositionend.
   RefPtr<TextComposition> mComposition;
 
   RefPtr<TextInputListener> mTextInputListener;
 
--- a/editor/libeditor/PlaceholderTransaction.cpp
+++ b/editor/libeditor/PlaceholderTransaction.cpp
@@ -13,24 +13,24 @@
 #include "nsGkAtoms.h"
 #include "nsQueryObject.h"
 
 namespace mozilla {
 
 using namespace dom;
 
 PlaceholderTransaction::PlaceholderTransaction(
-    EditorBase& aEditorBase, nsAtom* aName, Maybe<SelectionState>&& aSelState)
+    EditorBase& aEditorBase, nsStaticAtom& aName,
+    Maybe<SelectionState>&& aSelState)
     : mEditorBase(&aEditorBase),
-      mForwarding(nullptr),
       mCompositionTransaction(nullptr),
       mStartSel(*std::move(aSelState)),
       mAbsorb(true),
       mCommitted(false) {
-  mName = aName;
+  mName = &aName;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(PlaceholderTransaction)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PlaceholderTransaction,
                                                 EditAggregateTransaction)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditorBase);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mStartSel);
@@ -40,17 +40,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PlaceholderTransaction,
                                                   EditAggregateTransaction)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEditorBase);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStartSel);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEndSel);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PlaceholderTransaction)
-  NS_INTERFACE_MAP_ENTRY(nsIAbsorbingTransaction)
 NS_INTERFACE_MAP_END_INHERITING(EditAggregateTransaction)
 
 NS_IMPL_ADDREF_INHERITED(PlaceholderTransaction, EditAggregateTransaction)
 NS_IMPL_RELEASE_INHERITED(PlaceholderTransaction, EditAggregateTransaction)
 
 NS_IMETHODIMP PlaceholderTransaction::DoTransaction() { return NS_OK; }
 
 NS_IMETHODIMP PlaceholderTransaction::UndoTransaction() {
@@ -103,34 +102,33 @@ NS_IMETHODIMP PlaceholderTransaction::Me
                                             bool* aDidMerge) {
   if (NS_WARN_IF(!aDidMerge) || NS_WARN_IF(!aOtherTransaction)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   // set out param default value
   *aDidMerge = false;
 
-  if (mForwarding) {
+  if (mForwardingTransaction) {
     MOZ_ASSERT_UNREACHABLE(
         "tried to merge into a placeholder that was in "
         "forwarding mode!");
     return NS_ERROR_FAILURE;
   }
 
   RefPtr<EditTransactionBase> otherTransactionBase =
       aOtherTransaction->GetAsEditTransactionBase();
   if (!otherTransactionBase) {
     return NS_OK;
   }
 
   // We are absorbing all transactions if mAbsorb is lit.
   if (mAbsorb) {
-    CompositionTransaction* otherCompositionTransaction =
-        otherTransactionBase->GetAsCompositionTransaction();
-    if (otherCompositionTransaction) {
+    if (CompositionTransaction* otherCompositionTransaction =
+            otherTransactionBase->GetAsCompositionTransaction()) {
       // special handling for CompositionTransaction's: they need to merge with
       // any previous CompositionTransaction in this placeholder, if possible.
       if (!mCompositionTransaction) {
         // this is the first IME txn in the placeholder
         mCompositionTransaction = otherCompositionTransaction;
         DebugOnly<nsresult> rvIgnored =
             AppendChild(otherCompositionTransaction);
         NS_WARNING_ASSERTION(
@@ -147,19 +145,19 @@ NS_IMETHODIMP PlaceholderTransaction::Me
           DebugOnly<nsresult> rvIgnored =
               AppendChild(otherCompositionTransaction);
           NS_WARNING_ASSERTION(
               NS_SUCCEEDED(rvIgnored),
               "EditAggregateTransaction::AppendChild() failed, but ignored");
         }
       }
     } else {
-      nsCOMPtr<nsIAbsorbingTransaction> otherAbsorbingTransaction =
-          do_QueryInterface(otherTransactionBase);
-      if (!otherAbsorbingTransaction) {
+      PlaceholderTransaction* otherPlaceholderTransaction =
+          otherTransactionBase->GetAsPlaceholderTransaction();
+      if (!otherPlaceholderTransaction) {
         // See bug 171243: just drop incoming placeholders on the floor.
         // Their children will be swallowed by this preexisting one.
         DebugOnly<nsresult> rvIgnored = AppendChild(otherTransactionBase);
         NS_WARNING_ASSERTION(
             NS_SUCCEEDED(rvIgnored),
             "EditAggregateTransaction::AppendChild() failed, but ignored");
       }
     }
@@ -167,104 +165,87 @@ NS_IMETHODIMP PlaceholderTransaction::Me
     //  RememberEndingSelection();
     //  efficiency hack: no need to remember selection here, as we haven't yet
     //  finished the initial batch and we know we will be told when the batch
     //  ends. we can remeber the selection then.
     return NS_OK;
   }
 
   // merge typing or IME or deletion transactions if the selection matches
-  if (mCommitted || (mName.get() != nsGkAtoms::TypingTxnName &&
-                     mName.get() != nsGkAtoms::IMETxnName &&
-                     mName.get() != nsGkAtoms::DeleteTxnName)) {
+  if (mCommitted ||
+      (mName != nsGkAtoms::TypingTxnName && mName != nsGkAtoms::IMETxnName &&
+       mName != nsGkAtoms::DeleteTxnName)) {
     return NS_OK;
   }
 
-  nsCOMPtr<nsIAbsorbingTransaction> otherAbsorbingTransaction =
-      do_QueryInterface(otherTransactionBase);
-  if (!otherAbsorbingTransaction) {
+  PlaceholderTransaction* otherPlaceholderTransaction =
+      otherTransactionBase->GetAsPlaceholderTransaction();
+  if (!otherPlaceholderTransaction) {
     return NS_OK;
   }
 
   RefPtr<nsAtom> otherTransactionName;
-  DebugOnly<nsresult> rvIgnored = otherAbsorbingTransaction->GetTxnName(
+  DebugOnly<nsresult> rvIgnored = otherPlaceholderTransaction->GetName(
       getter_AddRefs(otherTransactionName));
-  NS_WARNING_ASSERTION(
-      NS_SUCCEEDED(rvIgnored),
-      "nsIAbsorbingTransaction::GetTxnName() failed, but ignored");
-  if (!otherTransactionName || otherTransactionName != mName) {
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
+                       "PlaceholderTransaction::GetName() failed, but ignored");
+  if (!otherTransactionName || otherTransactionName == nsGkAtoms::_empty ||
+      otherTransactionName != mName) {
     return NS_OK;
   }
   // check if start selection of next placeholder matches
   // end selection of this placeholder
-  if (!otherAbsorbingTransaction->StartSelectionEquals(mEndSel)) {
+  if (!otherPlaceholderTransaction->StartSelectionEquals(mEndSel)) {
     return NS_OK;
   }
   mAbsorb = true;  // we need to start absorbing again
-  otherAbsorbingTransaction->ForwardEndBatchTo(this);
+  otherPlaceholderTransaction->ForwardEndBatchTo(*this);
   // AppendChild(editTransactionBase);
   // see bug 171243: we don't need to merge placeholders
   // into placeholders.  We just reactivate merging in the
   // pre-existing placeholder and drop the new one on the floor.  The
   // EndPlaceHolderBatch() call on the new placeholder will be
   // forwarded to this older one.
   rvIgnored = RememberEndingSelection();
   NS_WARNING_ASSERTION(
       NS_SUCCEEDED(rvIgnored),
       "PlaceholderTransaction::RememberEndingSelection() failed, but "
       "ignored");
   *aDidMerge = true;
   return NS_OK;
 }
 
-NS_IMETHODIMP PlaceholderTransaction::GetTxnName(nsAtom** aName) {
-  nsresult rv = GetName(aName);
-  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
-                       "EditAggregationTransaction::GetName() failed");
-  return rv;
-}
-
-NS_IMETHODIMP_(bool)
-PlaceholderTransaction::StartSelectionEquals(SelectionState& aSelectionState) {
+bool PlaceholderTransaction::StartSelectionEquals(
+    SelectionState& aSelectionState) {
   // determine if starting selection matches the given selection state.
   // note that we only care about collapsed selections.
   return mStartSel.IsCollapsed() && aSelectionState.IsCollapsed() &&
          mStartSel.Equals(aSelectionState);
 }
 
-NS_IMETHODIMP PlaceholderTransaction::EndPlaceHolderBatch() {
+nsresult PlaceholderTransaction::EndPlaceHolderBatch() {
   mAbsorb = false;
 
-  if (mForwarding) {
-    nsCOMPtr<nsIAbsorbingTransaction> forwardingTransaction =
-        do_QueryReferent(mForwarding);
-    if (forwardingTransaction) {
+  if (mForwardingTransaction) {
+    if (mForwardingTransaction) {
       DebugOnly<nsresult> rvIgnored =
-          forwardingTransaction->EndPlaceHolderBatch();
+          mForwardingTransaction->EndPlaceHolderBatch();
       NS_WARNING_ASSERTION(
           NS_SUCCEEDED(rvIgnored),
-          "nsIAbsorbingTransaction::EndPlaceHolderBatch() failed, but ignored");
+          "PlaceholderTransaction::EndPlaceHolderBatch() failed, but ignored");
     }
   }
   // remember our selection state.
   nsresult rv = RememberEndingSelection();
   NS_WARNING_ASSERTION(
       NS_SUCCEEDED(rv),
       "PlaceholderTransaction::RememberEndingSelection() failed");
   return rv;
 }
 
-NS_IMETHODIMP_(void)
-PlaceholderTransaction::ForwardEndBatchTo(
-    nsIAbsorbingTransaction* aForwardingAddress) {
-  mForwarding = do_GetWeakReference(aForwardingAddress);
-}
-
-NS_IMETHODIMP_(void) PlaceholderTransaction::Commit() { mCommitted = true; }
-
 nsresult PlaceholderTransaction::RememberEndingSelection() {
   if (NS_WARN_IF(!mEditorBase)) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   RefPtr<Selection> selection = mEditorBase->GetSelection();
   if (NS_WARN_IF(!selection)) {
     return NS_ERROR_FAILURE;
--- a/editor/libeditor/PlaceholderTransaction.h
+++ b/editor/libeditor/PlaceholderTransaction.h
@@ -3,95 +3,89 @@
  * 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 PlaceholderTransaction_h
 #define PlaceholderTransaction_h
 
 #include "EditAggregateTransaction.h"
 #include "mozilla/Maybe.h"
-#include "nsIAbsorbingTransaction.h"
-#include "nsIWeakReferenceUtils.h"
+#include "mozilla/WeakPtr.h"
 
 namespace mozilla {
 
-class CompositionTransaction;
-
 /**
  * An aggregate transaction that knows how to absorb all subsequent
  * transactions with the same name.  This transaction does not "Do" anything.
  * But it absorbs other transactions via merge, and can undo/redo the
  * transactions it has absorbed.
  */
 
-class PlaceholderTransaction final : public EditAggregateTransaction,
-                                     public nsIAbsorbingTransaction {
+class PlaceholderTransaction final
+    : public EditAggregateTransaction,
+      public SupportsWeakPtr<PlaceholderTransaction> {
  protected:
-  PlaceholderTransaction(EditorBase& aEditorBase, nsAtom* aName,
+  PlaceholderTransaction(EditorBase& aEditorBase, nsStaticAtom& aName,
                          Maybe<SelectionState>&& aSelState);
 
  public:
   /**
    * Creates a placeholder transaction.  This never returns nullptr.
    *
    * @param aEditorBase     The editor.
    * @param aName           The name of creating transaction.
    * @param aSelState       The selection state of aEditorBase.
    */
   static already_AddRefed<PlaceholderTransaction> Create(
-      EditorBase& aEditorBase, nsAtom* aName,
+      EditorBase& aEditorBase, nsStaticAtom& aName,
       Maybe<SelectionState>&& aSelState) {
     // Make sure to move aSelState into a local variable to null out the
     // original Maybe<SelectionState> variable.
     Maybe<SelectionState> selState(std::move(aSelState));
     RefPtr<PlaceholderTransaction> transaction =
         new PlaceholderTransaction(aEditorBase, aName, std::move(selState));
     return transaction.forget();
   }
 
+  MOZ_DECLARE_WEAKREFERENCE_TYPENAME(PlaceholderTransaction)
+
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PlaceholderTransaction,
                                            EditAggregateTransaction)
   // ------------ EditAggregateTransaction -----------------------
 
   NS_DECL_EDITTRANSACTIONBASE
   NS_DECL_EDITTRANSACTIONBASE_GETASMETHODS_OVERRIDE(PlaceholderTransaction)
 
   MOZ_CAN_RUN_SCRIPT NS_IMETHOD RedoTransaction() override;
   NS_IMETHOD Merge(nsITransaction* aTransaction, bool* aDidMerge) override;
 
-  // ------------ nsIAbsorbingTransaction -----------------------
-
-  NS_IMETHOD GetTxnName(nsAtom** aName) override;
+  bool StartSelectionEquals(SelectionState& aSelectionState);
 
-  NS_IMETHOD_(bool) StartSelectionEquals(SelectionState& aSelState) override;
-
-  NS_IMETHOD EndPlaceHolderBatch() override;
+  nsresult EndPlaceHolderBatch();
 
-  NS_IMETHOD_(void)
-  ForwardEndBatchTo(nsIAbsorbingTransaction* aForwardingAddress) override;
+  void ForwardEndBatchTo(PlaceholderTransaction& aForwardingTransaction) {
+    mForwardingTransaction = &aForwardingTransaction;
+  }
 
-  NS_IMETHOD_(void) Commit() override;
-
-  NS_IMETHOD_(PlaceholderTransaction*) AsPlaceholderTransaction() override {
-    return this;
-  }
+  void Commit() { mCommitted = true; }
 
   nsresult RememberEndingSelection();
 
  protected:
   virtual ~PlaceholderTransaction() = default;
 
   // The editor for this transaction.
   RefPtr<EditorBase> mEditorBase;
 
-  nsWeakPtr mForwarding;
+  WeakPtr<PlaceholderTransaction> mForwardingTransaction;
+
   // First IME txn in this placeholder - used for IME merging.
-  mozilla::CompositionTransaction* mCompositionTransaction;
+  WeakPtr<CompositionTransaction> mCompositionTransaction;
 
   // These next two members store the state of the selection in a safe way.
   // Selection at the start of the transaction is stored, as is the selection
   // at the end.  This is so that UndoTransaction() and RedoTransaction() can
   // restore the selection properly.
 
   SelectionState mStartSel;
   SelectionState mEndSel;
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -36,17 +36,16 @@
 #include "nsComponentManagerUtils.h"
 #include "nsContentCID.h"
 #include "nsContentList.h"
 #include "nsCopySupport.h"
 #include "nsDebug.h"
 #include "nsDependentSubstring.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
-#include "nsIAbsorbingTransaction.h"
 #include "nsIClipboard.h"
 #include "nsIContent.h"
 #include "nsIDocumentEncoder.h"
 #include "nsINode.h"
 #include "nsIPrincipal.h"
 #include "nsISelectionController.h"
 #include "nsISupportsPrimitives.h"
 #include "nsITransferable.h"
@@ -1390,21 +1389,25 @@ void TextEditor::OnCompositionEnd(
         ToInputType(editAction) == EditorInputType::eInsertFromComposition);
     MOZ_ASSERT(!aCompositionEndEvent.mData.IsVoid());
     editActionData.SetData(aCompositionEndEvent.mData);
   }
 
   // commit the IME transaction..we can get at it via the transaction mgr.
   // Note that this means IME won't work without an undo stack!
   if (mTransactionManager) {
-    nsCOMPtr<nsITransaction> transaction = mTransactionManager->PeekUndoStack();
-    nsCOMPtr<nsIAbsorbingTransaction> absorbingTransaction =
-        do_QueryInterface(transaction);
-    if (absorbingTransaction) {
-      absorbingTransaction->Commit();
+    if (nsCOMPtr<nsITransaction> transaction =
+            mTransactionManager->PeekUndoStack()) {
+      if (RefPtr<EditTransactionBase> transactionBase =
+              transaction->GetAsEditTransactionBase()) {
+        if (PlaceholderTransaction* placeholderTransaction =
+                transactionBase->GetAsPlaceholderTransaction()) {
+          placeholderTransaction->Commit();
+        }
+      }
     }
   }
 
   // Note that this just marks as that we've already handled "beforeinput" for
   // preventing assertions in FireInputEvent().  Note that corresponding
   // "beforeinput" event for the following "input" event should've already
   // been dispatched from `OnCompositionChange()`.
   DebugOnly<nsresult> rvIgnored =
deleted file mode 100644
--- a/editor/libeditor/nsIAbsorbingTransaction.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* -*- 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/. */
-
-#ifndef nsIAbsorbingTransaction_h__
-#define nsIAbsorbingTransaction_h__
-
-#include "nsISupports.h"
-
-/*
-Transaction interface to outside world
-*/
-
-#define NS_IABSORBINGTRANSACTION_IID                 \
-  { /* a6cf9116-15b3-11d2-932e-00805f8add32 */       \
-    0xa6cf9116, 0x15b3, 0x11d2, {                    \
-      0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32 \
-    }                                                \
-  }
-
-class nsAtom;
-
-namespace mozilla {
-class EditorBase;
-class PlaceholderTransaction;
-class SelectionState;
-}  // namespace mozilla
-
-/**
- * A transaction interface mixin - for transactions that can support.
- * the placeholder absorbtion idiom.
- */
-class nsIAbsorbingTransaction : public nsISupports {
- public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IABSORBINGTRANSACTION_IID)
-
-  NS_IMETHOD EndPlaceHolderBatch() = 0;
-
-  NS_IMETHOD GetTxnName(nsAtom** aName) = 0;
-
-  NS_IMETHOD_(bool)
-  StartSelectionEquals(mozilla::SelectionState& aSelState) = 0;
-
-  NS_IMETHOD_(void)
-  ForwardEndBatchTo(nsIAbsorbingTransaction* aForwardingAddress) = 0;
-
-  NS_IMETHOD_(void) Commit() = 0;
-
-  NS_IMETHOD_(mozilla::PlaceholderTransaction*)
-  AsPlaceholderTransaction() = 0;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(nsIAbsorbingTransaction,
-                              NS_IABSORBINGTRANSACTION_IID)
-
-#endif  // nsIAbsorbingTransaction_h__