Commit 05f5948b authored by Masayuki Nakano's avatar Masayuki Nakano
Browse files

Bug 1767876 - part 2: Make `ComposerCommandsUpdater` stop inheriting...

Bug 1767876 - part 2: Make `ComposerCommandsUpdater` stop inheriting `nsITransactionListener` r=m_kato

This patch makes `TransactionManager` store `HTMLEditor`, and `HTMLEditor`
send notifications from `TransactionManager` to `ComposerCommandsUpdater`.

Depends on D145663

Differential Revision: https://phabricator.services.mozilla.com/D145664
parent 85750c7a
Loading
Loading
Loading
Loading
+12 −23
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@
#include "nsError.h"                     // for NS_OK, NS_ERROR_FAILURE, etc
#include "nsID.h"                        // for NS_GET_IID, etc
#include "nsIInterfaceRequestorUtils.h"  // for do_GetInterface
#include "nsITransactionManager.h"       // for nsITransactionManager
#include "nsLiteralString.h"             // for NS_LITERAL_STRING
#include "nsPIDOMWindow.h"               // for nsPIDOMWindow

@@ -40,10 +39,9 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(ComposerCommandsUpdater)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ComposerCommandsUpdater)

NS_INTERFACE_MAP_BEGIN(ComposerCommandsUpdater)
  NS_INTERFACE_MAP_ENTRY(nsITransactionListener)
  NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
  NS_INTERFACE_MAP_ENTRY(nsINamed)
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITransactionListener)
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITimerCallback)
  NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(ComposerCommandsUpdater)
NS_INTERFACE_MAP_END

@@ -54,40 +52,31 @@ NS_IMPL_CYCLE_COLLECTION(ComposerCommandsUpdater, mUpdateTimer, mDOMWindow,
#  pragma mark -
#endif

MOZ_CAN_RUN_SCRIPT_BOUNDARY
NS_IMETHODIMP ComposerCommandsUpdater::DidDo(nsITransactionManager* aManager,
                                             nsITransaction* aTransaction,
                                             nsresult aDoResult) {
void ComposerCommandsUpdater::DidDoTransaction(
    TransactionManager& aTransactionManager, nsITransaction* aTransaction,
    nsresult aDoTransactionResult) {
  // only need to update if the status of the Undo menu item changes.
  size_t undoCount = aManager->AsTransactionManager()->NumberOfUndoItems();
  if (undoCount == 1) {
  if (aTransactionManager.NumberOfUndoItems() == 1) {
    if (mFirstDoOfFirstUndo) {
      UpdateCommandGroup(CommandGroup::Undo);
    }
    mFirstDoOfFirstUndo = false;
  }

  return NS_OK;
}

MOZ_CAN_RUN_SCRIPT_BOUNDARY
NS_IMETHODIMP ComposerCommandsUpdater::DidUndo(nsITransactionManager* aManager,
                                               nsITransaction* aTransaction,
                                               nsresult aUndoResult) {
  size_t undoCount = aManager->AsTransactionManager()->NumberOfUndoItems();
  if (!undoCount) {
void ComposerCommandsUpdater::DidUndoTransaction(
    TransactionManager& aTransactionManager, nsITransaction* aTransaction,
    nsresult aUndoTransactionResult) {
  if (!aTransactionManager.NumberOfUndoItems()) {
    mFirstDoOfFirstUndo = true;  // reset the state for the next do
  }
  UpdateCommandGroup(CommandGroup::Undo);
  return NS_OK;
}

MOZ_CAN_RUN_SCRIPT_BOUNDARY
NS_IMETHODIMP ComposerCommandsUpdater::DidRedo(nsITransactionManager* aManager,
                                               nsITransaction* aTransaction,
                                               nsresult aRedoResult) {
void ComposerCommandsUpdater::DidRedoTransaction(
    TransactionManager& aTransactionManager, nsITransaction* aTransaction,
    nsresult aRedoTransactionResult) {
  UpdateCommandGroup(CommandGroup::Undo);
  return NS_OK;
}

#if 0
+21 −11
Original line number Diff line number Diff line
@@ -12,7 +12,6 @@
#include "nsINamed.h"
#include "nsISupportsImpl.h"  // for NS_DECL_ISUPPORTS
#include "nsITimer.h"         // for NS_DECL_NSITIMERCALLBACK, etc
#include "nsITransactionListener.h"  // for nsITransactionListener
#include "nscore.h"           // for NS_IMETHOD, nsresult, etc

class nsCommandManager;
@@ -23,16 +22,16 @@ class nsPIDOMWindowOuter;

namespace mozilla {

class ComposerCommandsUpdater final : public nsITransactionListener,
                                      public nsITimerCallback,
                                      public nsINamed {
class TransactionManager;

class ComposerCommandsUpdater final : public nsITimerCallback, public nsINamed {
 public:
  ComposerCommandsUpdater();

  // nsISupports
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ComposerCommandsUpdater,
                                           nsITransactionListener)
                                           nsITimerCallback)

  // nsITimerCallback
  NS_DECL_NSITIMERCALLBACK
@@ -40,9 +39,6 @@ class ComposerCommandsUpdater final : public nsITransactionListener,
  // nsINamed
  NS_DECL_NSINAMED

  // nsITransactionListener
  NS_DECL_NSITRANSACTIONLISTENER

  void Init(nsPIDOMWindowOuter& aDOMWindow);

  /**
@@ -87,6 +83,20 @@ class ComposerCommandsUpdater final : public nsITransactionListener,
    mDirtyState = aNowDirty;
  }

  /**
   * The following methods are called when aTransactionManager did
   * `DoTransaction`, `UndoTransaction` or `RedoTransaction` of aTransaction.
   */
  MOZ_CAN_RUN_SCRIPT void DidDoTransaction(
      TransactionManager& aTransactionManager, nsITransaction* aTransaction,
      nsresult aDoTransactionResult);
  MOZ_CAN_RUN_SCRIPT void DidUndoTransaction(
      TransactionManager& aTransactionManager, nsITransaction* aTransaction,
      nsresult aUndoTransactionResult);
  MOZ_CAN_RUN_SCRIPT void DidRedoTransaction(
      TransactionManager& aTransactionManager, nsITransaction* aTransaction,
      nsresult aRedoTransactionResult);

 protected:
  virtual ~ComposerCommandsUpdater();

+11 −20
Original line number Diff line number Diff line
@@ -320,16 +320,17 @@ nsresult nsEditingSession::SetupEditorOnWindow(nsPIDOMWindowOuter& aWindow) {
  }

  // make the UI state maintainer
  mComposerCommandsUpdater = new ComposerCommandsUpdater();
  RefPtr<ComposerCommandsUpdater> commandsUpdater =
      new ComposerCommandsUpdater();
  mComposerCommandsUpdater = commandsUpdater;

  // now init the state maintainer
  // This allows notification of error state
  //  even if we don't create an editor
  mComposerCommandsUpdater->Init(aWindow);
  commandsUpdater->Init(aWindow);

  if (mEditorStatus != eEditorCreationInProgress) {
    RefPtr<ComposerCommandsUpdater> updater = mComposerCommandsUpdater;
    updater->OnHTMLEditorCreated();
    commandsUpdater->OnHTMLEditorCreated();

    // At this point we have made a final decision that we don't support
    // editing the current document.  This is an internal failure state, but
@@ -403,11 +404,11 @@ nsresult nsEditingSession::SetupEditorOnWindow(nsPIDOMWindowOuter& aWindow) {
    return NS_ERROR_FAILURE;
  }

  // Set up as a doc state listener
  // Important! We must have this to broadcast the "obs_documentCreated" message
  htmlEditor->SetComposerCommandsUpdater(mComposerCommandsUpdater);

  rv = htmlEditor->Init(*doc, mEditorFlags);
  MOZ_DIAGNOSTIC_ASSERT(commandsUpdater == mComposerCommandsUpdater);
  if (MOZ_UNLIKELY(commandsUpdater != mComposerCommandsUpdater)) {
    commandsUpdater = mComposerCommandsUpdater;
  }
  rv = htmlEditor->Init(*doc, *commandsUpdater, mEditorFlags);
  NS_ENSURE_SUCCESS(rv, rv);

  RefPtr<Selection> selection = htmlEditor->GetSelection();
@@ -415,13 +416,6 @@ nsresult nsEditingSession::SetupEditorOnWindow(nsPIDOMWindowOuter& aWindow) {
    return NS_ERROR_FAILURE;
  }

  // and as a transaction listener
  MOZ_ASSERT(mComposerCommandsUpdater);
  DebugOnly<bool> addedTransactionListener =
      htmlEditor->AddTransactionListener(*mComposerCommandsUpdater);
  NS_WARNING_ASSERTION(addedTransactionListener,
                       "Failed to add transaction listener to the editor");

  // Set context on all controllers to be the editor
  rv = SetEditorOnControllers(aWindow, htmlEditor);
  NS_ENSURE_SUCCESS(rv, rv);
@@ -444,10 +438,7 @@ void nsEditingSession::RemoveListenersAndControllers(
  RefPtr<ComposerCommandsUpdater> composertCommandsUpdater =
      std::move(mComposerCommandsUpdater);
  MOZ_ASSERT(!mComposerCommandsUpdater);
  aHTMLEditor->SetComposerCommandsUpdater(nullptr);
  if (!aHTMLEditor->RemoveTransactionListener(*composertCommandsUpdater)) {
    NS_WARNING("Failed to remove transaction listener from the editor");
  }
  aHTMLEditor->Detach(*composertCommandsUpdater);

  // Remove editor controllers from the window now that we're not
  // editing in that window any more.
+26 −2
Original line number Diff line number Diff line
@@ -295,10 +295,16 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HTMLEditor)
  NS_INTERFACE_MAP_ENTRY(nsIEditorMailSupport)
NS_INTERFACE_MAP_END_INHERITING(EditorBase)

nsresult HTMLEditor::Init(Document& aDocument, uint32_t aFlags) {
nsresult HTMLEditor::Init(Document& aDocument,
                          ComposerCommandsUpdater& aComposerCommandsUpdater,
                          uint32_t aFlags) {
  MOZ_ASSERT(!mInitSucceeded,
             "HTMLEditor::Init() called again without calling PreDestroy()?");

  MOZ_DIAGNOSTIC_ASSERT(!mComposerCommandsUpdater ||
                        mComposerCommandsUpdater == &aComposerCommandsUpdater);
  mComposerCommandsUpdater = &aComposerCommandsUpdater;

  RefPtr<PresShell> presShell = aDocument.GetPresShell();
  if (NS_WARN_IF(!presShell)) {
    return NS_ERROR_FAILURE;
@@ -371,7 +377,12 @@ nsresult HTMLEditor::Init(Document& aDocument, uint32_t aFlags) {
  // Throw away the old transaction manager if this is not the first time that
  // we're initializing the editor.
  ClearUndoRedo();
  EnableUndoRedo();
  EnableUndoRedo();  // FYI: Creating mTransactionManager in this call

  if (mTransactionManager) {
    mTransactionManager->Attach(*this);
  }

  MOZ_ASSERT(!mInitSucceeded, "HTMLEditor::Init() shouldn't be nested");
  mInitSucceeded = true;
  return NS_OK;
@@ -716,6 +727,19 @@ void HTMLEditor::RemoveEventListeners() {
  EditorBase::RemoveEventListeners();
}

void HTMLEditor::Detach(
    const ComposerCommandsUpdater& aComposerCommandsUpdater) {
  MOZ_DIAGNOSTIC_ASSERT_IF(
      mComposerCommandsUpdater,
      &aComposerCommandsUpdater == mComposerCommandsUpdater);
  if (mComposerCommandsUpdater == &aComposerCommandsUpdater) {
    mComposerCommandsUpdater = nullptr;
    if (mTransactionManager) {
      mTransactionManager->Detach(*this);
    }
  }
}

NS_IMETHODIMP HTMLEditor::BeginningOfDocument() {
  AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
  if (NS_WARN_IF(!editActionData.CanHandle())) {
+38 −29
Original line number Diff line number Diff line
@@ -127,9 +127,12 @@ class HTMLEditor final : public EditorBase,

  /**
   * @param aDocument   The document whose content will be editable.
   * @param aComposerCommandsUpdater     The composer command updater.
   * @param aFlags      Some of nsIEditor::eEditor*Mask flags.
   */
  MOZ_CAN_RUN_SCRIPT nsresult Init(Document& aDocument, uint32_t aFlags);
  MOZ_CAN_RUN_SCRIPT nsresult
  Init(Document& aDocument, ComposerCommandsUpdater& aComposerCommandsUpdater,
       uint32_t aFlags);

  /**
   * PostCreate() should be called after Init, and is the time that the editor
@@ -150,25 +153,6 @@ class HTMLEditor final : public EditorBase,
    return aEditor ? aEditor->GetAsHTMLEditor() : nullptr;
  }

  /**
   * Adds or removes transaction listener to or from the transaction manager.
   * Note that TransactionManager does not check if the listener is in the
   * array.  So, caller of AddTransactionListener() needs to manage if it's
   * already been registered to the transaction manager.
   */
  bool AddTransactionListener(nsITransactionListener& aListener) {
    if (!mTransactionManager) {
      return false;
    }
    return mTransactionManager->AddTransactionListener(aListener);
  }
  bool RemoveTransactionListener(nsITransactionListener& aListener) {
    if (!mTransactionManager) {
      return false;
    }
    return mTransactionManager->RemoveTransactionListener(aListener);
  }

  bool GetReturnInParagraphCreatesNewParagraph();

  // EditorBase overrides
@@ -590,16 +574,9 @@ class HTMLEditor final : public EditorBase,
  GetFontColorState(bool* aIsMixed, nsAString& aColor);

  /**
   * SetComposerCommandsUpdater() sets or unsets mComposerCommandsUpdater.
   * This will crash in debug build if the editor already has an instance
   * but called with another instance.
   * Detach aComposerCommandsUpdater from this.
   */
  void SetComposerCommandsUpdater(
      ComposerCommandsUpdater* aComposerCommandsUpdater) {
    MOZ_ASSERT(!aComposerCommandsUpdater || !mComposerCommandsUpdater ||
               aComposerCommandsUpdater == mComposerCommandsUpdater);
    mComposerCommandsUpdater = aComposerCommandsUpdater;
  }
  void Detach(const ComposerCommandsUpdater& aComposerCommandsUpdater);

  nsStaticAtom& DefaultParagraphSeparatorTagName() const {
    return HTMLEditor::ToParagraphSeparatorTagName(mDefaultParagraphSeparator);
@@ -4447,6 +4424,36 @@ class HTMLEditor final : public EditorBase,
    return do_AddRef(mChangedRangeForTopLevelEditSubAction);
  }

  MOZ_CAN_RUN_SCRIPT void DidDoTransaction(
      TransactionManager& aTransactionManager, nsITransaction* aTransaction,
      nsresult aDoTransactionResult) {
    if (mComposerCommandsUpdater) {
      RefPtr<ComposerCommandsUpdater> updater(mComposerCommandsUpdater);
      updater->DidDoTransaction(aTransactionManager, aTransaction,
                                aDoTransactionResult);
    }
  }

  MOZ_CAN_RUN_SCRIPT void DidUndoTransaction(
      TransactionManager& aTransactionManager, nsITransaction* aTransaction,
      nsresult aUndoTransactionResult) {
    if (mComposerCommandsUpdater) {
      RefPtr<ComposerCommandsUpdater> updater(mComposerCommandsUpdater);
      updater->DidUndoTransaction(aTransactionManager, aTransaction,
                                  aUndoTransactionResult);
    }
  }

  MOZ_CAN_RUN_SCRIPT void DidRedoTransaction(
      TransactionManager& aTransactionManager, nsITransaction* aTransaction,
      nsresult aRedoTransactionResult) {
    if (mComposerCommandsUpdater) {
      RefPtr<ComposerCommandsUpdater> updater(mComposerCommandsUpdater);
      updater->DidRedoTransaction(aTransactionManager, aTransaction,
                                  aRedoTransactionResult);
    }
  }

 protected:
  // Helper for Handle[CSS|HTML]IndentAtSelectionInternal
  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
@@ -4668,6 +4675,8 @@ class HTMLEditor final : public EditorBase,
  friend class SlurpBlobEventListener;  // BlobReader
  friend class SplitNodeResult;         // CollapseSelectionTo
  friend class SplitNodeTransaction;    // DoJoinNodes, DoSplitNode
  friend class TransactionManager;      // DidDoTransaction, DidRedoTransaction,
                                        // DidUndoTransaction
  friend class
      WhiteSpaceVisibilityKeeper;  // CanMoveChildren,
                                   // CanMoveOrDeleteSomethingInHardLine,
Loading