Bug 1497746 - part 2: Move EditorBase::mDirection to EditorBase::AutoEditActionDataSetter r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Mon, 26 Nov 2018 06:30:29 +0000
changeset 507165 097a6db494774ab5b7311e10e40bd2948009e46e
parent 507164 6c108d9038c36d16fb6424a27054454110df7489
child 507166 465ebb044ee1494d7c2dca9ff04839cc45772b35
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [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 2: Move EditorBase::mDirection to EditorBase::AutoEditActionDataSetter r=m_kato EditorBase::mDirection is set and clear only when EditorBase::AutoEditActionDataSetter::SetTopLevelEditSubAction(). So, the direction is related to the top level edit sub action, and we can move it into AutoEditActionDataSetter. Note that except EditSubAction::eDeleteSelectedContent, the relation between sub-action and direction is fixed so that this patch checks the relation with MOZ_ASSERT. If we could replace EditSubAction::eDeleteSelectedContent with information of direction, we'd remove the new member of AutoEditActionDataSetter, though. Differential Revision: https://phabricator.services.mozilla.com/D12400
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)
-  , mDirection(eNone)
   , mDocDirtyState(-1)
   , mSpellcheckCheckboxState(eTriUnset)
   , mAllowsTransactionsToChangeSelection(true)
   , mDidPreDestroy(false)
   , mDidPostCreate(false)
   , mDispatchInputEvent(true)
   , mIsInEditSubAction(false)
   , mHidingCaret(false)
@@ -1707,17 +1706,17 @@ EditorBase::DeleteNode(nsINode* aNode)
 }
 
 nsresult
 EditorBase::DeleteNodeWithTransaction(nsINode& aNode)
 {
   MOZ_ASSERT(IsEditActionDataAvailable());
 
   AutoTopLevelEditSubActionNotifier maybeTopLevelEditSubAction(
-                                      *this, EditSubAction::eCreateNode,
+                                      *this, EditSubAction::eDeleteNode,
                                       nsIEditor::ePrevious);
 
   if (mRules && mRules->AsHTMLEditRules()) {
     RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
     htmlEditRules->WillDeleteNode(aNode);
   }
 
   // FYI: DeleteNodeTransaction grabs aNode while it's alive.  So, it's safe
@@ -2405,28 +2404,24 @@ EditorBase::GetRootElement(Element** aRo
 }
 
 void
 EditorBase::OnStartToHandleTopLevelEditSubAction(
               EditSubAction aEditSubAction,
               nsIEditor::EDirection aDirection)
 {
   MOZ_ASSERT(IsEditActionDataAvailable());
-
-  mEditActionData->SetTopLevelEditSubAction(aEditSubAction);
-  mDirection = aDirection;
+  mEditActionData->SetTopLevelEditSubAction(aEditSubAction, aDirection);
 }
 
 void
 EditorBase::OnEndHandlingTopLevelEditSubAction()
 {
   MOZ_ASSERT(IsEditActionDataAvailable());
-
-  mEditActionData->SetTopLevelEditSubAction(EditSubAction::eNone);
-  mDirection = eNone;
+  mEditActionData->SetTopLevelEditSubAction(EditSubAction::eNone, eNone);
 }
 
 NS_IMETHODIMP
 EditorBase::CloneAttribute(const nsAString& aAttribute,
                            Element* aDestElement,
                            Element* aSourceElement)
 {
   NS_ENSURE_TRUE(aDestElement && aSourceElement, NS_ERROR_NULL_POINTER);
@@ -5233,22 +5228,25 @@ EditorBase::AutoEditActionDataSetter::Au
     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;
+    mDirectionOfTopLevelEditSubAction =
+      mParentData->mDirectionOfTopLevelEditSubAction;
   } else {
     mSelection = mEditorBase.GetSelection();
     if (NS_WARN_IF(!mSelection)) {
       return;
     }
     mEditAction = aEditAction;
+    mDirectionOfTopLevelEditSubAction = eNone;
   }
   mEditorBase.mEditActionData = this;
 }
 
 EditorBase::AutoEditActionDataSetter::~AutoEditActionDataSetter()
 {
   if (!mSelection || NS_WARN_IF(mEditorBase.mEditActionData != this)) {
     return;
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -710,35 +710,98 @@ 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)
+    void SetTopLevelEditSubAction(EditSubAction aEditSubAction,
+                                  EDirection aDirection = eNone)
     {
       mTopLevelEditSubAction = aEditSubAction;
+      switch (mTopLevelEditSubAction) {
+        case EditSubAction::eInsertNode:
+        case EditSubAction::eCreateNode:
+        case EditSubAction::eSplitNode:
+        case EditSubAction::eInsertText:
+        case EditSubAction::eInsertTextComingFromIME:
+        case EditSubAction::eSetTextProperty:
+        case EditSubAction::eRemoveTextProperty:
+        case EditSubAction::eRemoveAllTextProperties:
+        case EditSubAction::eSetText:
+        case EditSubAction::eInsertLineBreak:
+        case EditSubAction::eInsertParagraphSeparator:
+        case EditSubAction::eCreateOrChangeList:
+        case EditSubAction::eIndent:
+        case EditSubAction::eOutdent:
+        case EditSubAction::eSetOrClearAlignment:
+        case EditSubAction::eCreateOrRemoveBlock:
+        case EditSubAction::eRemoveList:
+        case EditSubAction::eCreateOrChangeDefinitionList:
+        case EditSubAction::eInsertElement:
+        case EditSubAction::eInsertQuotation:
+        case EditSubAction::ePasteHTMLContent:
+        case EditSubAction::eInsertHTMLSource:
+        case EditSubAction::eSetPositionToAbsolute:
+        case EditSubAction::eSetPositionToStatic:
+        case EditSubAction::eDecreaseZIndex:
+        case EditSubAction::eIncreaseZIndex:
+          MOZ_ASSERT(aDirection == eNext);
+          mDirectionOfTopLevelEditSubAction = eNext;
+          break;
+        case EditSubAction::eJoinNodes:
+        case EditSubAction::eDeleteText:
+          MOZ_ASSERT(aDirection == ePrevious);
+          mDirectionOfTopLevelEditSubAction = ePrevious;
+          break;
+        case EditSubAction::eUndo:
+        case EditSubAction::eRedo:
+        case EditSubAction::eComputeTextToOutput:
+        case EditSubAction::eCreateBogusNode:
+        case EditSubAction::eNone:
+          MOZ_ASSERT(aDirection == eNone);
+          mDirectionOfTopLevelEditSubAction = eNone;
+          break;
+        case EditSubAction::eReplaceHeadWithHTMLSource:
+          // NOTE: Not used with AutoTopLevelEditSubActionNotifier.
+          mDirectionOfTopLevelEditSubAction = eNone;
+          break;
+        case EditSubAction::eDeleteNode:
+        case EditSubAction::eDeleteSelectedContent:
+          // Unfortunately, eDeleteNode and eDeleteSelectedContent is used with
+          // any direction.  We might have specific sub-action for each
+          // direction, but there are some points referencing
+          // eDeleteSelectedContent so that we should keep storing direction
+          // as-is for now.
+          mDirectionOfTopLevelEditSubAction = aDirection;
+          break;
+      }
     }
     EditSubAction GetTopLevelEditSubAction() const
     {
       MOZ_ASSERT(CanHandle());
       return mTopLevelEditSubAction;
     }
+    EDirection GetDirectionOfTopLevelEditSubAction() const
+    {
+      return mDirectionOfTopLevelEditSubAction;
+    }
 
   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;
+    EDirection mDirectionOfTopLevelEditSubAction;
 
     AutoEditActionDataSetter() = delete;
     AutoEditActionDataSetter(const AutoEditActionDataSetter& aOther) = delete;
   };
 
 protected: // May be called by friends.
   /****************************************************************************
    * Some classes like TextEditRules, HTMLEditRules, WSRunObject which are
@@ -791,16 +854,26 @@ protected: // May be called by friends.
    */
   EditSubAction GetTopLevelEditSubAction() const
   {
     return mEditActionData ? mEditActionData->GetTopLevelEditSubAction() :
                              EditSubAction::eNone;
   }
 
   /**
+   * GetDirectionOfTopLevelEditSubAction() returns direction which user
+   * intended for doing the edit sub-action.
+   */
+  EDirection GetDirectionOfTopLevelEditSubAction() const
+  {
+    return mEditActionData ?
+       mEditActionData->GetDirectionOfTopLevelEditSubAction() : 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.
@@ -2242,18 +2315,16 @@ protected:
   // 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's direction.
-  EDirection mDirection;
   // -1 = not initialized
   int8_t mDocDirtyState;
   // A Tristate value.
   uint8_t mSpellcheckCheckboxState;
 
   // If false, transactions should not change Selection even after modifying
   // the DOM tree.
   bool mAllowsTransactionsToChangeSelection;
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -3829,36 +3829,37 @@ HTMLEditor::OnStartToHandleTopLevelEditS
   RefPtr<TextEditRules> rules(mRules);
 
   EditorBase::OnStartToHandleTopLevelEditSubAction(aEditSubAction, aDirection);
   if (!rules) {
     return;
   }
 
   MOZ_ASSERT(GetTopLevelEditSubAction() == aEditSubAction);
-  MOZ_ASSERT(mDirection == aDirection);
-  DebugOnly<nsresult> rv = rules->BeforeEdit(aEditSubAction, mDirection);
+  MOZ_ASSERT(GetDirectionOfTopLevelEditSubAction() == aDirection);
+  DebugOnly<nsresult> rv = rules->BeforeEdit(aEditSubAction, aDirection);
   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(GetTopLevelEditSubAction(), mDirection) : NS_OK;
+    rules ? rules->AfterEdit(GetTopLevelEditSubAction(),
+                             GetDirectionOfTopLevelEditSubAction()) : NS_OK;
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
     "HTMLEditRules::AfterEdit() failed to handle something");
   EditorBase::OnEndHandlingTopLevelEditSubAction();
   MOZ_ASSERT(!GetTopLevelEditSubAction());
-  MOZ_ASSERT(mDirection == eNone);
+  MOZ_ASSERT(GetDirectionOfTopLevelEditSubAction() == eNone);
 }
 
 bool
 HTMLEditor::TagCanContainTag(nsAtom& aParentTag,
                              nsAtom& aChildTag) const
 {
   int32_t childTagEnum;
   // XXX Should this handle #cdata-section too?
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -2174,36 +2174,37 @@ TextEditor::OnStartToHandleTopLevelEditS
   RefPtr<TextEditRules> rules(mRules);
 
   EditorBase::OnStartToHandleTopLevelEditSubAction(aEditSubAction, aDirection);
   if (!rules) {
     return;
   }
 
   MOZ_ASSERT(GetTopLevelEditSubAction() == aEditSubAction);
-  MOZ_ASSERT(mDirection == aDirection);
-  DebugOnly<nsresult> rv = rules->BeforeEdit(aEditSubAction, mDirection);
+  MOZ_ASSERT(GetDirectionOfTopLevelEditSubAction() == aDirection);
+  DebugOnly<nsresult> rv = rules->BeforeEdit(aEditSubAction, aDirection);
   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(GetTopLevelEditSubAction(), mDirection) : NS_OK;
+    rules ? rules->AfterEdit(GetTopLevelEditSubAction(),
+                             GetDirectionOfTopLevelEditSubAction()) : NS_OK;
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
     "TextEditRules::AfterEdit() failed to handle something");
   EditorBase::OnEndHandlingTopLevelEditSubAction();
   MOZ_ASSERT(!GetTopLevelEditSubAction());
-  MOZ_ASSERT(mDirection == eNone);
+  MOZ_ASSERT(GetDirectionOfTopLevelEditSubAction() == eNone);
 }
 
 nsresult
 TextEditor::SelectEntireDocument()
 {
   MOZ_ASSERT(IsEditActionDataAvailable());
 
   if (!mRules) {