Bug 1501180 - Make TextEditRules::Notify() hide input characters via editor instance r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 25 Oct 2018 03:35:26 +0000
changeset 499365 ca2018e79dc07aef83d62d70905e64895bc607a2
parent 499364 4560f9d969c02cd7648b1cd9fcb65222b0d5b501
child 499366 81d7102f5351cf4aa3c5b348b5820f3e499a4d60
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
bugs1501180, 1465702
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 1501180 - Make TextEditRules::Notify() hide input characters via editor instance r=m_kato TextEditRules::Notify() is callback of the timer. Therefore, this won't be in the stack while editor handles an edit action. Then, TextEditRules cannot access edit action data which will be put on the stack after fixing bug 1465702. So, it should do it after once calling a method of editor instance (and editor instance should call back proper TextEditRules method). Differential Revision: https://phabricator.services.mozilla.com/D9502
editor/libeditor/TextEditRules.cpp
editor/libeditor/TextEditRules.h
editor/libeditor/TextEditor.cpp
editor/libeditor/TextEditor.h
--- a/editor/libeditor/TextEditRules.cpp
+++ b/editor/libeditor/TextEditRules.cpp
@@ -777,17 +777,17 @@ TextEditRules::WillInsertText(EditSubAct
     outString->Assign(tString);
   }
 
   if (IsPasswordEditor()) {
     // manage the password buffer
     mPasswordText.Insert(*outString, start);
 
     if (LookAndFeel::GetEchoPassword() && !DontEchoPassword()) {
-      nsresult rv = HideLastPWInput();
+      nsresult rv = HideLastPasswordInputInternal();
       mLastStart = start;
       mLastLength = outString->Length();
       if (mTimer) {
         mTimer->Cancel();
       }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
@@ -1089,17 +1089,17 @@ TextEditRules::DeleteSelectionWithTransa
 
     // manage the password buffer
     uint32_t start, end;
     nsContentUtils::GetSelectionInTextControl(&SelectionRef(),
                                               TextEditorRef().GetRoot(),
                                               start, end);
 
     if (LookAndFeel::GetEchoPassword()) {
-      rv = HideLastPWInput();
+      rv = HideLastPasswordInputInternal();
       mLastStart = start;
       mLastLength = 0;
       if (mTimer) {
         mTimer->Cancel();
       }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
@@ -1699,41 +1699,57 @@ NS_IMETHODIMP
 TextEditRules::Notify(nsITimer* aTimer)
 {
   MOZ_ASSERT(mTimer);
 
   if (NS_WARN_IF(!mTextEditor)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  Selection* selection = mTextEditor->GetSelection();
-  if (NS_WARN_IF(!selection)) {
-    return NS_ERROR_FAILURE;
+  // Check whether our text editor's password flag was changed before this
+  // "hide password character" timer actually fires.
+  if (!IsPasswordEditor()) {
+    return NS_OK;
   }
 
-  AutoSafeEditorData setData(*this, *mTextEditor, *selection);
+  RefPtr<TextEditor> textEditor(mTextEditor);
+  nsresult rv = textEditor->HideLastPasswordInput();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
+}
+
+nsresult
+TextEditRules::HideLastPasswordInput(Selection& aSelection)
+{
+  MOZ_ASSERT(IsPasswordEditor());
+
+  AutoSafeEditorData setData(*this, *mTextEditor, aSelection);
 
   // Check whether our text editor's password flag was changed before this
   // "hide password character" timer actually fires.
-  nsresult rv = IsPasswordEditor() ? HideLastPWInput() : NS_OK;
-  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to hide last password input");
+  nsresult rv = HideLastPasswordInputInternal();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
   ASSERT_PASSWORD_LENGTHS_EQUAL();
   mLastLength = 0;
-  return rv;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 TextEditRules::GetName(nsACString& aName)
 {
   aName.AssignLiteral("TextEditRules");
   return NS_OK;
 }
 
 nsresult
-TextEditRules::HideLastPWInput()
+TextEditRules::HideLastPasswordInputInternal()
 {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   if (!mLastLength) {
     // Special case, we're trying to replace a range that no longer exists
     return NS_OK;
   }
 
--- a/editor/libeditor/TextEditRules.h
+++ b/editor/libeditor/TextEditRules.h
@@ -83,16 +83,17 @@ public:
 
   virtual nsresult Init(TextEditor* aTextEditor);
   virtual nsresult SetInitialValue(const nsAString& aValue);
   virtual nsresult DetachEditor();
   virtual nsresult BeforeEdit(EditSubAction aEditSubAction,
                               nsIEditor::EDirection aDirection);
   virtual nsresult AfterEdit(EditSubAction aEditSubAction,
                              nsIEditor::EDirection aDirection);
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   virtual nsresult WillDoAction(Selection* aSelection,
                                 EditSubActionInfo& aInfo,
                                 bool* aCancel,
                                 bool* aHandled);
   virtual nsresult DidDoAction(Selection* aSelection,
                                EditSubActionInfo& aInfo,
                                nsresult aResult);
 
@@ -145,16 +146,22 @@ public:
    */
   static void FillBufWithPWChars(nsAString* aOutString, int32_t aLength);
 
   bool HasBogusNode()
   {
     return !!mBogusNode;
   }
 
+  /**
+   * HideLastPasswordInput() is called while Nodify() is calling
+   * TextEditor::HideLastPasswordInput().
+   */
+  MOZ_CAN_RUN_SCRIPT nsresult HideLastPasswordInput(Selection& aSelection);
+
 protected:
 
   void InitFields();
 
   // TextEditRules implementation methods
 
   /**
    * Called before inserting text.
@@ -165,16 +172,17 @@ protected:
    *                            or EditSubAction::eInsertText.
    * @param aCancel             Returns true if the operation is canceled.
    * @param aHandled            Returns true if the edit action is handled.
    * @param inString            String to be inserted.
    * @param outString           String actually inserted.
    * @param aMaxLength          The maximum string length which the editor
    *                            allows to set.
    */
+  MOZ_CAN_RUN_SCRIPT
   MOZ_MUST_USE nsresult
   WillInsertText(EditSubAction aEditSubAction, bool* aCancel, bool* aHandled,
                  const nsAString* inString, nsAString* outString,
                  int32_t aMaxLength);
 
   /**
    * Called before inserting a line break into the editor.
    * This method removes selected text if selection isn't collapsed.
@@ -218,31 +226,33 @@ protected:
    * This method may actually remove the selected content with
    * DeleteSelectionWithTransaction().  So, this might cause destroying the
    * editor.
    *
    * @param aCaollapsedAction   Direction to extend the selection.
    * @param aCancel             Returns true if the operation is canceled.
    * @param aHandled            Returns true if the edit action is handled.
    */
+  MOZ_CAN_RUN_SCRIPT
   MOZ_MUST_USE nsresult
   WillDeleteSelection(nsIEditor::EDirection aCollapsedAction,
                       bool* aCancel, bool* aHandled);
 
   /**
    * DeleteSelectionWithTransaction() is internal method of
    * WillDeleteSelection() since it needs to create SelectionBatcher in
    * big scope and destroying it might causes destroying the editor.
    * So, after calling this method, callers need to check CanHandleEditAction()
    * manually.
    *
    * @param aCaollapsedAction   Direction to extend the selection.
    * @param aCancel             Returns true if the operation is canceled.
    * @param aHandled            Returns true if the edit action is handled.
    */
+  MOZ_CAN_RUN_SCRIPT
   MOZ_MUST_USE nsresult
   DeleteSelectionWithTransaction(nsIEditor::EDirection aCollapsedAction,
                                  bool* aCancel, bool* aHandled);
 
   /**
    * Called after deleted selected content.
    * This method may remove empty text node and makes guarantee that caret
    * is never at left of <br> element.
@@ -348,21 +358,22 @@ protected:
 
   void UndefineCaretBidiLevel();
 
   nsresult CheckBidiLevelForDeletion(const EditorRawDOMPoint& aSelectionPoint,
                                      nsIEditor::EDirection aAction,
                                      bool* aCancel);
 
   /**
-   * HideLastPWInput() replaces last password characters which have not
-   * been replaced with mask character like '*' with with the mask character.
-   * This method may cause destroying the editor.
+   * HideLastPasswordInputInternal() replaces last password characters which
+   * have not been replaced with mask character like '*' with with the mask
+   * character.  This method may cause destroying the editor.
    */
-  MOZ_MUST_USE nsresult HideLastPWInput();
+  MOZ_CAN_RUN_SCRIPT
+  MOZ_MUST_USE nsresult HideLastPasswordInputInternal();
 
   /**
    * CollapseSelectionToTrailingBRIfNeeded() collapses selection after the
    * text node if:
    * - the editor is text editor
    * - and Selection is collapsed at the end of the text node
    * - and the text node is followed by moz-<br>.
    */
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -2171,9 +2171,29 @@ TextEditor::RemoveAttributeOrEquivalent(
                                         bool aSuppressTransaction)
 {
   if (NS_WARN_IF(!aElement) || NS_WARN_IF(!aAttribute)) {
     return NS_ERROR_INVALID_ARG;
   }
   return RemoveAttributeWithTransaction(*aElement, *aAttribute);
 }
 
+nsresult
+TextEditor::HideLastPasswordInput()
+{
+  // This method should be called only by TextEditRules::Notify().
+  MOZ_ASSERT(mRules);
+  MOZ_ASSERT(IsPasswordEditor());
+
+  RefPtr<Selection> selection = GetSelection();
+  if (NS_WARN_IF(!selection)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  RefPtr<TextEditRules> rules(mRules);
+  nsresult rv = rules->HideLastPasswordInput(*selection);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
+}
+
 } // namespace mozilla
--- a/editor/libeditor/TextEditor.h
+++ b/editor/libeditor/TextEditor.h
@@ -331,16 +331,24 @@ protected: // May be called by friends.
   /**
    * Extends the selection for given deletion operation
    * If done, also update aAction to what's actually left to do after the
    * extension.
    */
   nsresult ExtendSelectionForDelete(Selection* aSelection,
                                     nsIEditor::EDirection* aAction);
 
+  /**
+   * HideLastPasswordInput() is called by timer callback of TextEditRules.
+   * This should be called only by TextEditRules::Notify().
+   * When this is called, the TextEditRules wants to call its
+   * HideLastPasswordInput().
+   */
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult HideLastPasswordInput();
+
   static void GetDefaultEditorPrefs(int32_t& aNewLineHandling,
                                     int32_t& aCaretStyle);
 
 protected: // Called by helper classes.
 
   virtual void
   OnStartToHandleTopLevelEditSubAction(
     EditSubAction aEditSubAction, nsIEditor::EDirection aDirection) override;