Bug 1497746 - part 1: Move EditorBase::mTopLevelEditSubAction to EditorBase::AutoEditActionDataSetter r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Mon, 26 Nov 2018 03:53:29 +0000
changeset 504384 6c108d9038c36d16fb6424a27054454110df7489
parent 504381 6ee93495fe0c47bdad591490f9a4439cbcb09be5
child 504385 097a6db494774ab5b7311e10e40bd2948009e46e
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1497746
milestone65.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 1497746 - part 1: Move EditorBase::mTopLevelEditSubAction to EditorBase::AutoEditActionDataSetter r=m_kato EditorBase::mTopLevelEditSubAction is set only by EditorBase::OnStartToHandleTopLevelEditSubAction() and EditorBase::OnEndToHandleTopLevelEditSubAction() and they are called only by AutoTopLevelEditSubActionNotifier(). So, this is used only in stack when a public method of editor is called. Therefore, we can move it into EditorBase::AutoEditActionDataSetter. Then, we can reduce heap allocation for editor instances. Differential Revision: https://phabricator.services.mozilla.com/D12399
editor/libeditor/EditorBase.cpp
editor/libeditor/EditorBase.h
editor/libeditor/HTMLEditor.cpp
editor/libeditor/TextEditor.cpp
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -156,17 +156,16 @@ EditorBase::MoveNodeWithTransaction(nsIC
 
 EditorBase::EditorBase()
   : mEditActionData(nullptr)
   , mPlaceholderName(nullptr)
   , mModCount(0)
   , mFlags(0)
   , mUpdateCount(0)
   , mPlaceholderBatch(0)
-  , mTopLevelEditSubAction(EditSubAction::eNone)
   , mDirection(eNone)
   , mDocDirtyState(-1)
   , mSpellcheckCheckboxState(eTriUnset)
   , mAllowsTransactionsToChangeSelection(true)
   , mDidPreDestroy(false)
   , mDidPostCreate(false)
   , mDispatchInputEvent(true)
   , mIsInEditSubAction(false)
@@ -255,17 +254,17 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(EditorB
 
 nsresult
 EditorBase::Init(nsIDocument& aDocument,
                  Element* aRoot,
                  nsISelectionController* aSelectionController,
                  uint32_t aFlags,
                  const nsAString& aValue)
 {
-  MOZ_ASSERT(mTopLevelEditSubAction == EditSubAction::eNone,
+  MOZ_ASSERT(GetTopLevelEditSubAction() == EditSubAction::eNone,
              "Initializing during an edit action is an error");
 
   // First only set flags, but other stuff shouldn't be initialized now.
   // Don't move this call after initializing mDocument.
   // SetFlags() can check whether it's called during initialization or not by
   // them.  Note that SetFlags() will be called by PostCreate().
 #ifdef DEBUG
   nsresult rv =
@@ -2405,24 +2404,28 @@ EditorBase::GetRootElement(Element** aRo
   return NS_OK;
 }
 
 void
 EditorBase::OnStartToHandleTopLevelEditSubAction(
               EditSubAction aEditSubAction,
               nsIEditor::EDirection aDirection)
 {
-  mTopLevelEditSubAction = aEditSubAction;
+  MOZ_ASSERT(IsEditActionDataAvailable());
+
+  mEditActionData->SetTopLevelEditSubAction(aEditSubAction);
   mDirection = aDirection;
 }
 
 void
 EditorBase::OnEndHandlingTopLevelEditSubAction()
 {
-  mTopLevelEditSubAction = EditSubAction::eNone;
+  MOZ_ASSERT(IsEditActionDataAvailable());
+
+  mEditActionData->SetTopLevelEditSubAction(EditSubAction::eNone);
   mDirection = eNone;
 }
 
 NS_IMETHODIMP
 EditorBase::CloneAttribute(const nsAString& aAttribute,
                            Element* aDestElement,
                            Element* aSourceElement)
 {
@@ -5218,26 +5221,28 @@ EditorBase::AutoSelectionRestorer::Abort
  * mozilla::EditorBase::AutoEditActionDataSetter
  *****************************************************************************/
 
 EditorBase::AutoEditActionDataSetter::AutoEditActionDataSetter(
                                         const EditorBase& aEditorBase,
                                         EditAction aEditAction)
   : mEditorBase(const_cast<EditorBase&>(aEditorBase))
   , mParentData(aEditorBase.mEditActionData)
+  , mTopLevelEditSubAction(EditSubAction::eNone)
 {
   // If we're nested edit action, copies necessary data from the parent.
   if (mParentData) {
     mSelection = mParentData->mSelection;
     // If we're eNotEditing, we should inherit the parent's edit action.
     // This may occur if creator or its callee use public methods which
     // just returns something.
     if (aEditAction != EditAction::eNotEditing) {
       mEditAction = aEditAction;
     }
+    mTopLevelEditSubAction = mParentData->mTopLevelEditSubAction;
   } else {
     mSelection = mEditorBase.GetSelection();
     if (NS_WARN_IF(!mSelection)) {
       return;
     }
     mEditAction = aEditAction;
   }
   mEditorBase.mEditActionData = this;
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -710,24 +710,35 @@ protected: // AutoEditActionDataSetter, 
     bool CanHandle() const
     {
       return mSelection && mEditorBase.IsInitialized();
     }
 
     const RefPtr<Selection>& SelectionRefPtr() const { return mSelection; }
     EditAction GetEditAction() const { return mEditAction; }
 
+    void SetTopLevelEditSubAction(EditSubAction aEditSubAction)
+    {
+      mTopLevelEditSubAction = aEditSubAction;
+    }
+    EditSubAction GetTopLevelEditSubAction() const
+    {
+      MOZ_ASSERT(CanHandle());
+      return mTopLevelEditSubAction;
+    }
+
   private:
     EditorBase& mEditorBase;
     RefPtr<Selection> mSelection;
     // EditAction may be nested, for example, a command may be executed
     // from mutation event listener which is run while editor changes
     // the DOM tree.  In such case, we need to handle edit action separately.
     AutoEditActionDataSetter* mParentData;
     EditAction mEditAction;
+    EditSubAction mTopLevelEditSubAction;
 
     AutoEditActionDataSetter() = delete;
     AutoEditActionDataSetter(const AutoEditActionDataSetter& aOther) = delete;
   };
 
 protected: // May be called by friends.
   /****************************************************************************
    * Some classes like TextEditRules, HTMLEditRules, WSRunObject which are
@@ -763,16 +774,33 @@ protected: // May be called by friends.
    */
   EditAction GetEditAction() const
   {
     return mEditActionData ? mEditActionData->GetEditAction() :
                              EditAction::eNone;
   }
 
   /**
+   * GetTopLevelEditSubAction() returns the top level edit sub-action.
+   * For example, if selected content is being replaced with inserted text,
+   * while removing selected content, the top level edit sub-action may be
+   * EditSubAction::eDeleteSelectedContent.  However, while inserting new
+   * text, the top level edit sub-action may be EditSubAction::eInsertText.
+   * So, this result means what we are doing right now unless you're looking
+   * for a case which the method is called via mutation event listener or
+   * selectionchange event listener which are fired while handling the edit
+   * sub-action.
+   */
+  EditSubAction GetTopLevelEditSubAction() const
+  {
+    return mEditActionData ? mEditActionData->GetTopLevelEditSubAction() :
+                             EditSubAction::eNone;
+  }
+
+  /**
    * InsertTextWithTransaction() inserts aStringToInsert to aPointToInsert or
    * better insertion point around it.  If aPointToInsert isn't in a text node,
    * this method looks for the nearest point in a text node with
    * FindBetterInsertionPoint().  If there is no text node, this creates
    * new text node and put aStringToInsert to it.
    *
    * @param aDocument       The document of this editor.
    * @param aStringToInsert The string to insert.
@@ -1694,30 +1722,30 @@ protected: // May be called by friends.
    * nsCaret.  Therefore, this is stateless.
    */
   void HideCaret(bool aHide);
 
 protected: // Called by helper classes.
 
   /**
    * OnStartToHandleTopLevelEditSubAction() is called when
-   * mTopLevelEditSubAction is EditSubAction::eNone and somebody starts to
+   * GetTopLevelEditSubAction() is EditSubAction::eNone and somebody starts to
    * handle aEditSubAction.
    *
    * @param aEditSubAction      Top level edit sub action which will be
    *                            handled soon.
    * @param aDirection          Direction of aEditSubAction.
    */
   virtual void
   OnStartToHandleTopLevelEditSubAction(EditSubAction aEditSubAction,
                                        nsIEditor::EDirection aDirection);
 
   /**
    * OnEndHandlingTopLevelEditSubAction() is called after
-   * mTopLevelEditSubAction is handled.
+   * SetTopLevelEditSubAction() is handled.
    */
   virtual void OnEndHandlingTopLevelEditSubAction();
 
   /**
    * Routines for managing the preservation of selection across
    * various editor actions.
    */
   bool ArePreservingSelection();
@@ -2071,21 +2099,21 @@ protected: // helper classes which may b
     AutoTopLevelEditSubActionNotifier(EditorBase& aEditorBase,
                                       EditSubAction aEditSubAction,
                                       nsIEditor::EDirection aDirection
                                       MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : mEditorBase(aEditorBase)
       , mDoNothing(false)
     {
       MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-      // mTopLevelEditSubAction will already be set if this is nested call
+      // The top level edit sub action has already be set if this is nested call
       // XXX Looks like that this is not aware of unexpected nested edit action
       //     handling via selectionchange event listener or mutation event
       //     listener.
-      if (!mEditorBase.mTopLevelEditSubAction) {
+      if (!mEditorBase.GetTopLevelEditSubAction()) {
         mEditorBase.OnStartToHandleTopLevelEditSubAction(aEditSubAction,
                                                          aDirection);
       } else {
         mDoNothing = true; // nested calls will end up here
       }
     }
 
     ~AutoTopLevelEditSubActionNotifier()
@@ -2213,18 +2241,16 @@ protected:
   uint32_t mModCount;
   // Behavior flags. See nsIPlaintextEditor.idl for the flags we use.
   uint32_t mFlags;
 
   int32_t mUpdateCount;
 
   // Nesting count for batching.
   int32_t mPlaceholderBatch;
-  // The top level edit sub-action.
-  EditSubAction mTopLevelEditSubAction;
 
   // The top level edit sub-action's direction.
   EDirection mDirection;
   // -1 = not initialized
   int8_t mDocDirtyState;
   // A Tristate value.
   uint8_t mSpellcheckCheckboxState;
 
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -3752,17 +3752,17 @@ HTMLEditor::DoContentInserted(nsIContent
   if (ShouldReplaceRootElement()) {
     UpdateRootElement();
     nsContentUtils::AddScriptRunner(
       NewRunnableMethod("HTMLEditor::NotifyRootChanged",
                         this,
                         &HTMLEditor::NotifyRootChanged));
   }
   // We don't need to handle our own modifications
-  else if (!mTopLevelEditSubAction && container->IsEditable()) {
+  else if (!GetTopLevelEditSubAction() && container->IsEditable()) {
     if (IsMozEditorBogusNode(aChild)) {
       // Ignore insertion of the bogus node
       return;
     }
     RefPtr<HTMLEditRules> htmlRules = mRules->AsHTMLEditRules();
     if (htmlRules) {
       htmlRules->DocumentModified();
     }
@@ -3801,17 +3801,18 @@ HTMLEditor::ContentRemoved(nsIContent* a
 
   if (SameCOMIdentity(aChild, mRootElement)) {
     mRootElement = nullptr;
     nsContentUtils::AddScriptRunner(
       NewRunnableMethod("HTMLEditor::NotifyRootChanged",
                         this,
                         &HTMLEditor::NotifyRootChanged));
   // We don't need to handle our own modifications
-  } else if (!mTopLevelEditSubAction && aChild->GetParentNode()->IsEditable()) {
+  } else if (!GetTopLevelEditSubAction() &&
+             aChild->GetParentNode()->IsEditable()) {
     if (aChild && IsMozEditorBogusNode(aChild)) {
       // Ignore removal of the bogus node
       return;
     }
 
     RefPtr<HTMLEditRules> htmlRules = mRules->AsHTMLEditRules();
     if (htmlRules) {
       htmlRules->DocumentModified();
@@ -3827,37 +3828,36 @@ HTMLEditor::OnStartToHandleTopLevelEditS
   // Protect the edit rules object from dying
   RefPtr<TextEditRules> rules(mRules);
 
   EditorBase::OnStartToHandleTopLevelEditSubAction(aEditSubAction, aDirection);
   if (!rules) {
     return;
   }
 
-  MOZ_ASSERT(mTopLevelEditSubAction == aEditSubAction);
+  MOZ_ASSERT(GetTopLevelEditSubAction() == aEditSubAction);
   MOZ_ASSERT(mDirection == aDirection);
-  DebugOnly<nsresult> rv =
-    rules->BeforeEdit(mTopLevelEditSubAction, mDirection);
+  DebugOnly<nsresult> rv = rules->BeforeEdit(aEditSubAction, mDirection);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
     "HTMLEditRules::BeforeEdit() failed to handle something");
 }
 
 void
 HTMLEditor::OnEndHandlingTopLevelEditSubAction()
 {
   // Protect the edit rules object from dying
   RefPtr<TextEditRules> rules(mRules);
 
   // post processing
   DebugOnly<nsresult> rv =
-    rules ? rules->AfterEdit(mTopLevelEditSubAction, mDirection) : NS_OK;
+    rules ? rules->AfterEdit(GetTopLevelEditSubAction(), mDirection) : NS_OK;
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
     "HTMLEditRules::AfterEdit() failed to handle something");
   EditorBase::OnEndHandlingTopLevelEditSubAction();
-  MOZ_ASSERT(!mTopLevelEditSubAction);
+  MOZ_ASSERT(!GetTopLevelEditSubAction());
   MOZ_ASSERT(mDirection == eNone);
 }
 
 bool
 HTMLEditor::TagCanContainTag(nsAtom& aParentTag,
                              nsAtom& aChildTag) const
 {
   int32_t childTagEnum;
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -2173,37 +2173,36 @@ TextEditor::OnStartToHandleTopLevelEditS
   // Protect the edit rules object from dying
   RefPtr<TextEditRules> rules(mRules);
 
   EditorBase::OnStartToHandleTopLevelEditSubAction(aEditSubAction, aDirection);
   if (!rules) {
     return;
   }
 
-  MOZ_ASSERT(mTopLevelEditSubAction == aEditSubAction);
+  MOZ_ASSERT(GetTopLevelEditSubAction() == aEditSubAction);
   MOZ_ASSERT(mDirection == aDirection);
-  DebugOnly<nsresult> rv =
-    rules->BeforeEdit(mTopLevelEditSubAction, mDirection);
+  DebugOnly<nsresult> rv = rules->BeforeEdit(aEditSubAction, mDirection);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
     "TextEditRules::BeforeEdit() failed to handle something");
 }
 
 void
 TextEditor::OnEndHandlingTopLevelEditSubAction()
 {
   // Protect the edit rules object from dying
   RefPtr<TextEditRules> rules(mRules);
 
   // post processing
   DebugOnly<nsresult> rv =
-    rules ? rules->AfterEdit(mTopLevelEditSubAction, mDirection) : NS_OK;
+    rules ? rules->AfterEdit(GetTopLevelEditSubAction(), mDirection) : NS_OK;
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
     "TextEditRules::AfterEdit() failed to handle something");
   EditorBase::OnEndHandlingTopLevelEditSubAction();
-  MOZ_ASSERT(!mTopLevelEditSubAction);
+  MOZ_ASSERT(!GetTopLevelEditSubAction());
   MOZ_ASSERT(mDirection == eNone);
 }
 
 nsresult
 TextEditor::SelectEntireDocument()
 {
   MOZ_ASSERT(IsEditActionDataAvailable());