Bug 1451672 - part 21: Refine TextEditor::TypedText() r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Mon, 16 Apr 2018 23:43:36 +0900
changeset 468374 ec93f6db7e4b525495c549916a878972dfcda34d
parent 468373 5726deba80285b649b0f19c190a9b9275282eff1
child 468375 7b6165489943f380905a61ecc882b7d22dc04ce4
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1451672
milestone61.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 1451672 - part 21: Refine TextEditor::TypedText() r=m_kato According to existing comments, TextEditor::TypedText() and HTMLEditor::TypedText() are intentional bottleneck to debug. However, only for that purpose, it and its internal methods are made virtual. This really doesn't make sense. So, this patch creates TextEditor::OnInputText() for callers of TypedText() with non-empty string, TextEditor::OnInputParagraphSeparator() for callers of TypedText() with eTypeBreak (Enter key or insertParagraphSeparator), HTMLEditor::OnInputLineBreak() for callers of TypedText() with eTypeBR (Shift + Enter or insertLineBreak). Additionally, this creates internal non-virtual methods for XPCOM methods which are used as internal methods of TypedText(). One is InsertTextAsAction() for nsIPlatintextEditor.insertText(). the other is InsertParagraphSeparator() for nsIPlaintextEditor.insertLineBreak(). Although those new methods are not have "WithTransaction" postfix, they must be clearer they'll use transactions since user input and actions should be undo-able. MozReview-Commit-ID: AmOkMqovIKA
accessible/generic/HyperTextAccessible-inl.h
dom/html/nsTextEditorState.cpp
editor/libeditor/EditorCommands.cpp
editor/libeditor/HTMLEditor.cpp
editor/libeditor/HTMLEditor.h
editor/libeditor/HTMLEditorDataTransfer.cpp
editor/libeditor/TextEditor.cpp
editor/libeditor/TextEditor.h
editor/libeditor/TextEditorDataTransfer.cpp
editor/spellchecker/TextServicesDocument.cpp
extensions/spellcheck/src/mozInlineSpellChecker.cpp
--- a/accessible/generic/HyperTextAccessible-inl.h
+++ b/accessible/generic/HyperTextAccessible-inl.h
@@ -65,26 +65,28 @@ HyperTextAccessible::ReplaceText(const n
   if (!textEditor) {
     return;
   }
 
   // DeleteText() may cause inserting <br> element in some cases. Let's
   // select all again and replace whole contents.
   textEditor->SelectAll();
 
-  textEditor->InsertText(aText);
+  DebugOnly<nsresult> rv = textEditor->InsertTextAsAction(aText);
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert the new text");
 }
 
 inline void
 HyperTextAccessible::InsertText(const nsAString& aText, int32_t aPosition)
 {
   RefPtr<TextEditor> textEditor = GetEditor();
   if (textEditor) {
     SetSelectionRange(aPosition, aPosition);
-    textEditor->InsertText(aText);
+    DebugOnly<nsresult> rv = textEditor->InsertTextAsAction(aText);
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert the text");
   }
 }
 
 inline void
 HyperTextAccessible::CopyText(int32_t aStartPos, int32_t aEndPos)
   {
     RefPtr<TextEditor> textEditor = GetEditor();
     if (textEditor) {
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -2423,17 +2423,20 @@ nsTextEditorState::SetValue(const nsAStr
 
             if (insertValue.IsEmpty()) {
               DebugOnly<nsresult> rv =
                 textEditor->DeleteSelectionAsAction(nsIEditor::eNone,
                                                     nsIEditor::eStrip);
               NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
                 "Failed to remove the text");
             } else {
-              textEditor->InsertText(insertValue);
+              DebugOnly<nsresult> rv =
+                textEditor->InsertTextAsAction(insertValue);
+              NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+                "Failed to insert the new value");
             }
           } else {
             AutoDisableUndo disableUndo(textEditor);
             if (selection) {
               // Since we don't use undo transaction, we don't need to store
               // selection state.  SetText will set selection to tail.
               // Note that textEditor will collapse selection to the end.
               // Therefore, it's safe to use RemoveAllRangesTemporarily() here.
--- a/editor/libeditor/EditorCommands.cpp
+++ b/editor/libeditor/EditorCommands.cpp
@@ -1086,17 +1086,25 @@ InsertPlaintextCommand::DoCommand(const 
 {
   // No value is equivalent to empty string
   nsCOMPtr<nsIEditor> editor = do_QueryInterface(aCommandRefCon);
   if (NS_WARN_IF(!editor)) {
     return NS_ERROR_FAILURE;
   }
   TextEditor* textEditor = editor->AsTextEditor();
   MOZ_ASSERT(textEditor);
-  return textEditor->InsertText(EmptyString());
+  // XXX InsertTextAsAction() is not same as OnInputText().  However, other
+  //     commands to insert line break or paragraph separator use OnInput*().
+  //     According to the semantics of those methods, using *AsAction() is
+  //     better, however, this may not cause two or more placeholder
+  //     transactions to the top transaction since its name may not be
+  //     nsGkAtoms::TypingTxnName.
+  DebugOnly<nsresult> rv = textEditor->InsertTextAsAction(EmptyString());
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert empty string");
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 InsertPlaintextCommand::DoCommandParams(const char* aCommandName,
                                         nsICommandParams* aParams,
                                         nsISupports* aCommandRefCon)
 {
   if (NS_WARN_IF(!aParams)) {
@@ -1112,17 +1120,25 @@ InsertPlaintextCommand::DoCommandParams(
   nsAutoString text;
   nsresult rv = aParams->GetStringValue(STATE_DATA, text);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   TextEditor* textEditor = editor->AsTextEditor();
   MOZ_ASSERT(textEditor);
-  return textEditor->InsertText(text);
+  // XXX InsertTextAsAction() is not same as OnInputText().  However, other
+  //     commands to insert line break or paragraph separator use OnInput*().
+  //     According to the semantics of those methods, using *AsAction() is
+  //     better, however, this may not cause two or more placeholder
+  //     transactions to the top transaction since its name may not be
+  //     nsGkAtoms::TypingTxnName.
+  rv = textEditor->InsertTextAsAction(text);
+  NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert the text");
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 InsertPlaintextCommand::GetCommandStateParams(const char* aCommandName,
                                               nsICommandParams* aParams,
                                               nsISupports* aCommandRefCon)
 {
   if (NS_WARN_IF(!aParams)) {
@@ -1164,17 +1180,19 @@ InsertParagraphCommand::DoCommand(const 
 {
   nsCOMPtr<nsIEditor> editor = do_QueryInterface(aCommandRefCon);
   if (NS_WARN_IF(!editor)) {
     return NS_ERROR_FAILURE;
   }
 
   TextEditor* textEditor = editor->AsTextEditor();
   MOZ_ASSERT(textEditor);
-  return textEditor->TypedText(EmptyString(), TextEditor::eTypedBreak);
+  // XXX OnInputParagraphSeparator() is a handler of user input.  So, this
+  //     call may not be expected.
+  return textEditor->OnInputParagraphSeparator();
 }
 
 NS_IMETHODIMP
 InsertParagraphCommand::DoCommandParams(const char* aCommandName,
                                         nsICommandParams* aParams,
                                         nsISupports* aCommandRefCon)
 {
   return DoCommand(aCommandName, aCommandRefCon);
@@ -1222,19 +1240,23 @@ NS_IMETHODIMP
 InsertLineBreakCommand::DoCommand(const char* aCommandName,
                                   nsISupports* aCommandRefCon)
 {
   nsCOMPtr<nsIEditor> editor = do_QueryInterface(aCommandRefCon);
   if (NS_WARN_IF(!editor)) {
     return NS_ERROR_FAILURE;
   }
 
-  TextEditor* textEditor = editor->AsTextEditor();
-  MOZ_ASSERT(textEditor);
-  return textEditor->TypedText(EmptyString(), TextEditor::eTypedBR);
+  HTMLEditor* htmlEditor = editor->AsHTMLEditor();
+  if (!htmlEditor) {
+    return NS_ERROR_FAILURE;
+  }
+  // XXX OnInputLineBreak() is a handler of user input.  So, this call may not
+  //     be expected.
+  return htmlEditor->OnInputLineBreak();
 }
 
 NS_IMETHODIMP
 InsertLineBreakCommand::DoCommandParams(const char* aCommandName,
                                         nsICommandParams* aParams,
                                         nsISupports* aCommandRefCon)
 {
   return DoCommand(aCommandName, aCommandRefCon);
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -768,38 +768,38 @@ HTMLEditor::HandleKeyPressEvent(WidgetKe
       if (handled) {
         aKeyboardEvent->PreventDefault(); // consumed
         return NS_OK;
       }
       if (aKeyboardEvent->IsShift()) {
         return NS_OK; // don't type text for shift tabs
       }
       aKeyboardEvent->PreventDefault();
-      return TypedText(NS_LITERAL_STRING("\t"), eTypedText);
+      return OnInputText(NS_LITERAL_STRING("\t"));
     }
     case NS_VK_RETURN:
       if (!aKeyboardEvent->IsInputtingLineBreak()) {
         return NS_OK;
       }
       aKeyboardEvent->PreventDefault(); // consumed
       if (aKeyboardEvent->IsShift()) {
-        // only inserts a br node
-        return TypedText(EmptyString(), eTypedBR);
+        // Only inserts a <br> element.
+        return OnInputLineBreak();
       }
       // uses rules to figure out what to insert
-      return TypedText(EmptyString(), eTypedBreak);
+      return OnInputParagraphSeparator();
   }
 
   if (!aKeyboardEvent->IsInputtingText()) {
     // we don't PreventDefault() here or keybindings like control-x won't work
     return NS_OK;
   }
   aKeyboardEvent->PreventDefault();
   nsAutoString str(aKeyboardEvent->mCharCode);
-  return TypedText(str, eTypedText);
+  return OnInputText(str);
 }
 
 /**
  * Returns true if the id represents an element of block type.
  * Can be used to determine if a new paragraph should be started.
  */
 bool
 HTMLEditor::NodeIsBlockStatic(const nsINode* aElement)
@@ -1032,37 +1032,25 @@ HTMLEditor::UpdateBaseURL()
   // If no base tag, then set baseURL to the document's URL.  This is very
   // important, else relative URLs for links and images are wrong
   if (!nodeList || !nodeList->Item(0)) {
     doc->SetBaseURI(doc->GetDocumentURI());
   }
   return NS_OK;
 }
 
-/**
- * This routine is needed to provide a bottleneck for typing for logging
- * purposes.  Can't use HandleKeyPress() (above) for that since it takes
- * a WidgetKeyboardEvent* parameter.  So instead we pass enough info through
- * to TypedText() to determine what action to take, but without passing
- * an event.
- */
-NS_IMETHODIMP
-HTMLEditor::TypedText(const nsAString& aString,
-                      ETypingAction aAction)
+nsresult
+HTMLEditor::OnInputLineBreak()
 {
-  MOZ_ASSERT(!aString.IsEmpty() || aAction != eTypedText);
-
   AutoPlaceholderBatch batch(this, nsGkAtoms::TypingTxnName);
-
-  if (aAction == eTypedBR) {
-    // only inserts a br node
-    return InsertBR();
-  }
-
-  return TextEditor::TypedText(aString, aAction);
+  nsresult rv = InsertBrElementAtSelectionWithTransaction();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
 }
 
 nsresult
 HTMLEditor::TabInTable(bool inIsShift,
                        bool* outHandled)
 {
   NS_ENSURE_TRUE(outHandled, NS_ERROR_NULL_POINTER);
   *outHandled = false;
@@ -1131,17 +1119,17 @@ HTMLEditor::TabInTable(bool inIsShift,
       selection->Collapse(cell, 0);
     }
   }
 
   return NS_OK;
 }
 
 nsresult
-HTMLEditor::InsertBR()
+HTMLEditor::InsertBrElementAtSelectionWithTransaction()
 {
   // calling it text insertion to trigger moz br treatment by rules
   AutoRules beginRulesSniffing(this, EditAction::insertText, nsIEditor::eNext);
 
   RefPtr<Selection> selection = GetSelection();
   NS_ENSURE_STATE(selection);
 
   if (!selection->Collapsed()) {
@@ -2318,23 +2306,30 @@ HTMLEditor::Indent(const nsAString& aInd
       return NS_ERROR_FAILURE;
     }
     // put a space in it so layout will draw the list item
     ErrorResult error;
     selection->Collapse(RawRangeBoundary(newBQ, 0), error);
     if (NS_WARN_IF(error.Failed())) {
       return error.StealNSResult();
     }
-    rv = InsertText(NS_LITERAL_STRING(" "));
-    NS_ENSURE_SUCCESS(rv, rv);
-    // reposition selection to before the space character
-    NS_ENSURE_STATE(selection->GetRangeAt(0));
-    rv = selection->Collapse(selection->GetRangeAt(0)->GetStartContainer(),
-                             0);
-    NS_ENSURE_SUCCESS(rv, rv);
+    rv = InsertTextAsAction(NS_LITERAL_STRING(" "));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    // Reposition selection to before the space character.
+    firstRange = selection->GetRangeAt(0);
+    if (NS_WARN_IF(!firstRange)) {
+      return NS_ERROR_FAILURE;
+    }
+    selection->Collapse(RawRangeBoundary(firstRange->GetStartContainer(), 0),
+                        error);
+    if (NS_WARN_IF(error.Failed())) {
+      return error.StealNSResult();
+    }
   }
   return rules->DidDoAction(selection, &ruleInfo, rv);
 }
 
 //TODO: IMPLEMENT ALIGNMENT!
 
 NS_IMETHODIMP
 HTMLEditor::Align(const nsAString& aAlignType)
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -431,19 +431,21 @@ public:
   virtual bool IsModifiableNode(nsINode* aNode) override;
 
   NS_IMETHOD SelectAll() override;
 
   // nsICSSLoaderObserver
   NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet,
                               bool aWasAlternate, nsresult aStatus) override;
 
-  // Utility Routines, not part of public API
-  NS_IMETHOD TypedText(const nsAString& aString,
-                       ETypingAction aAction) override;
+  /**
+   * OnInputLineBreak() is called when user inputs a line break with
+   * Shift + Enter or something.
+   */
+  nsresult OnInputLineBreak();
 
   /**
    * InsertNodeIntoProperAncestor() attempts to insert aNode into the document,
    * at aPointToInsert.  Checks with strict dtd to see if containment is
    * allowed.  If not allowed, will attempt to find a parent in the parent
    * hierarchy of aPointToInsert.GetContainer() that will accept aNode as a
    * child.  If such a parent is found, will split the document tree from
    * aPointToInsert up to parent, and then insert aNode. aPointToInsert is then
@@ -649,20 +651,21 @@ protected:
   /**
    * Return TRUE if aElement is a table-related elemet and caret was set.
    */
   bool SetCaretInTableCell(nsIDOMElement* aElement);
 
   nsresult TabInTable(bool inIsShift, bool* outHandled);
 
   /**
-   * InsertBR() inserts a new <br> element at selection.  If there is
-   * non-collapsed selection ranges, the selected ranges is deleted first.
+   * InsertBrElementAtSelectionWithTransaction() inserts a new <br> element at
+   * selection.  If there is non-collapsed selection ranges, the selected
+   * ranges is deleted first.
    */
-  nsresult InsertBR();
+  nsresult InsertBrElementAtSelectionWithTransaction();
 
   // Table Editing (implemented in nsTableEditor.cpp)
 
   /**
    * Insert a new cell after or before supplied aCell.
    * Optional: If aNewCell supplied, returns the newly-created cell (addref'd,
    * of course)
    * This doesn't change or use the current selection.
--- a/editor/libeditor/HTMLEditorDataTransfer.cpp
+++ b/editor/libeditor/HTMLEditorDataTransfer.cpp
@@ -1751,17 +1751,19 @@ HTMLEditor::InsertTextWithQuotations(con
     // If no newline found, lineStart is now strEnd and we can finish up,
     // inserting from curHunk to lineStart then returning.
     const nsAString &curHunk = Substring(hunkStart, lineStart);
     nsCOMPtr<nsIDOMNode> dummyNode;
     if (curHunkIsQuoted) {
       rv = InsertAsPlaintextQuotation(curHunk, false,
                                       getter_AddRefs(dummyNode));
     } else {
-      rv = InsertText(curHunk);
+      rv = InsertTextAsAction(curHunk);
+      NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+        "Failed to insert a line of the quoted text");
     }
     if (!found) {
       break;
     }
     curHunkIsQuoted = quoted;
     hunkStart = lineStart;
   }
 
@@ -1841,17 +1843,19 @@ HTMLEditor::InsertAsPlaintextQuotation(c
 
     // and set the selection inside it:
     selection->Collapse(newNode, 0);
   }
 
   if (aAddCites) {
     rv = TextEditor::InsertAsQuotation(aQuotedText, aNodeInserted);
   } else {
-    rv = TextEditor::InsertText(aQuotedText);
+    rv = InsertTextAsAction(aQuotedText);
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+      "Failed to insert the quoted text as plain text");
   }
   // Note that if !aAddCites, aNodeInserted isn't set.
   // That's okay because the routines that use aAddCites
   // don't need to know the inserted node.
 
   if (aNodeInserted && NS_SUCCEEDED(rv)) {
     *aNodeInserted = GetAsDOMNode(newNode);
     NS_IF_ADDREF(*aNodeInserted);
@@ -1923,17 +1927,18 @@ HTMLEditor::InsertAsCitedQuotation(const
   }
 
   // Set the selection inside the blockquote so aQuotedText will go there:
   selection->Collapse(newNode, 0);
 
   if (aInsertHTML) {
     rv = LoadHTML(aQuotedText);
   } else {
-    rv = InsertText(aQuotedText);  // XXX ignore charset
+    rv = InsertTextAsAction(aQuotedText);  // XXX ignore charset
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert the quoted text");
   }
 
   if (aNodeInserted && NS_SUCCEEDED(rv)) {
     *aNodeInserted = GetAsDOMNode(newNode);
     NS_IF_ADDREF(*aNodeInserted);
   }
 
   // Set the selection to just after the inserted node:
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -393,55 +393,55 @@ TextEditor::HandleKeyPressEvent(WidgetKe
       if (aKeyboardEvent->IsShift() || aKeyboardEvent->IsControl() ||
           aKeyboardEvent->IsAlt() || aKeyboardEvent->IsMeta() ||
           aKeyboardEvent->IsOS()) {
         return NS_OK;
       }
 
       // else we insert the tab straight through
       aKeyboardEvent->PreventDefault();
-      return TypedText(NS_LITERAL_STRING("\t"), eTypedText);
+      return OnInputText(NS_LITERAL_STRING("\t"));
     }
     case NS_VK_RETURN:
       if (IsSingleLineEditor() || !aKeyboardEvent->IsInputtingLineBreak()) {
         return NS_OK;
       }
       aKeyboardEvent->PreventDefault();
-      return TypedText(EmptyString(), eTypedBreak);
+      return OnInputParagraphSeparator();
   }
 
   if (!aKeyboardEvent->IsInputtingText()) {
     // we don't PreventDefault() here or keybindings like control-x won't work
     return NS_OK;
   }
   aKeyboardEvent->PreventDefault();
   nsAutoString str(aKeyboardEvent->mCharCode);
-  return TypedText(str, eTypedText);
+  return OnInputText(str);
 }
 
-/* This routine is needed to provide a bottleneck for typing for logging
-   purposes.  Can't use HandleKeyPress() (above) for that since it takes
-   a WidgetKeyboardEvent* parameter.  So instead we pass enough info through
-   to TypedText() to determine what action to take, but without passing
-   an event.
-   */
-NS_IMETHODIMP
-TextEditor::TypedText(const nsAString& aString, ETypingAction aAction)
+nsresult
+TextEditor::OnInputText(const nsAString& aStringToInsert)
 {
   AutoPlaceholderBatch batch(this, nsGkAtoms::TypingTxnName);
+  nsresult rv = InsertTextAsAction(aStringToInsert);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
+}
 
-  switch (aAction) {
-    case eTypedText:
-      return InsertText(aString);
-    case eTypedBreak:
-      return InsertLineBreak();
-    default:
-      // eTypedBR is only for HTML
-      return NS_ERROR_FAILURE;
+nsresult
+TextEditor::OnInputParagraphSeparator()
+{
+  AutoPlaceholderBatch batch(this, nsGkAtoms::TypingTxnName);
+  nsresult rv = InsertParagraphSeparatorAsAction();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
   }
+  return NS_OK;
 }
 
 template<typename PT, typename CT>
 already_AddRefed<Element>
 TextEditor::InsertBrElementWithTransaction(
               Selection& aSelection,
               const EditorDOMPointBase<PT, CT>& aPointToInsert,
               EDirection aSelect /* = eNone */)
@@ -917,81 +917,106 @@ TextEditor::DeleteSelectionAndPrepareToC
     return error.StealNSResult();
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TextEditor::InsertText(const nsAString& aStringToInsert)
 {
+  nsresult rv = InsertTextAsAction(aStringToInsert);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
+}
+
+nsresult
+TextEditor::InsertTextAsAction(const nsAString& aStringToInsert)
+{
   if (!mRules) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   // Protect the edit rules object from dying
   RefPtr<TextEditRules> rules(mRules);
 
   EditAction opID = EditAction::insertText;
   if (ShouldHandleIMEComposition()) {
     opID = EditAction::insertIMEText;
   }
+
   AutoPlaceholderBatch batch(this, nullptr);
   AutoRules beginRulesSniffing(this, opID, nsIEditor::eNext);
 
-  // pre-process
   RefPtr<Selection> selection = GetSelection();
-  NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
+  if (NS_WARN_IF(!selection)) {
+    return NS_ERROR_FAILURE;
+  }
+
   nsAutoString resultString;
   // XXX can we trust instring to outlive ruleInfo,
   // XXX and ruleInfo not to refer to instring in its dtor?
   //nsAutoString instring(aStringToInsert);
   RulesInfo ruleInfo(opID);
   ruleInfo.inString = &aStringToInsert;
   ruleInfo.outString = &resultString;
   ruleInfo.maxLength = mMaxTextLength;
 
   bool cancel, handled;
   nsresult rv = rules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
   if (!cancel && !handled) {
     // we rely on rules code for now - no default implementation
   }
   if (cancel) {
     return NS_OK;
   }
   // post-process
-  return rules->DidDoAction(selection, &ruleInfo, rv);
+  return rules->DidDoAction(selection, &ruleInfo, NS_OK);
 }
 
 NS_IMETHODIMP
 TextEditor::InsertLineBreak()
 {
+  return InsertParagraphSeparatorAsAction();
+}
+
+nsresult
+TextEditor::InsertParagraphSeparatorAsAction()
+{
   if (!mRules) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   // Protect the edit rules object from dying
   RefPtr<TextEditRules> rules(mRules);
 
   AutoPlaceholderBatch beginBatching(this);
   AutoRules beginRulesSniffing(this, EditAction::insertBreak, nsIEditor::eNext);
 
-  // pre-process
   RefPtr<Selection> selection = GetSelection();
-  NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
+  if (NS_WARN_IF(!selection)) {
+    return NS_ERROR_FAILURE;
+  }
 
   RulesInfo ruleInfo(EditAction::insertBreak);
   ruleInfo.maxLength = mMaxTextLength;
   bool cancel, handled;
-  // XXX DidDoAction() won't be called when this returns error.  Perhaps,
-  //     we should move the code between WillDoAction() and DidDoAction()
-  //     to a new method and guarantee that DidDoAction() is always called
-  //     after WillDoAction().
   nsresult rv = rules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    // XXX DidDoAction() won't be called when WillDoAction() returns error.
+    //     Perhaps, we should move the code between WillDoAction() and
+    //     DidDoAction() to a new method and guarantee that DidDoAction() is
+    //     always called after WillDoAction().
+    return rv;
+  }
+
   if (!cancel && !handled) {
     // get the (collapsed) selection location
     nsRange* firstRange = selection->GetRangeAt(0);
     if (NS_WARN_IF(!firstRange)) {
       return NS_ERROR_FAILURE;
     }
 
     EditorRawDOMPoint pointToInsert(firstRange->StartRef());
@@ -1004,17 +1029,19 @@ TextEditor::InsertLineBreak()
     if (!pointToInsert.IsInTextNode() &&
         !CanContainTag(*pointToInsert.GetContainer(),
                        *nsGkAtoms::textTagName)) {
       return NS_ERROR_FAILURE;
     }
 
     // we need to get the doc
     nsCOMPtr<nsIDocument> doc = GetDocument();
-    NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
+    if (NS_WARN_IF(!doc)) {
+      return NS_ERROR_NOT_INITIALIZED;
+    }
 
     // don't change my selection in subtransactions
     AutoTransactionsConserveSelection dontChangeMySelection(this);
 
     // insert a linefeed character
     EditorRawDOMPoint pointAfterInsertedLineBreak;
     rv = InsertTextWithTransaction(*doc, NS_LITERAL_STRING("\n"), pointToInsert,
                                    &pointAfterInsertedLineBreak);
@@ -1094,17 +1121,18 @@ TextEditor::SetText(const nsAString& aSt
     } else {
       rv = EditorBase::SelectEntireDocument(selection);
     }
     if (NS_SUCCEEDED(rv)) {
       if (aString.IsEmpty()) {
         rv = DeleteSelectionAsAction(eNone, eStrip);
         NS_WARNING_ASSERTION(NS_FAILED(rv), "Failed to remove all text");
       } else {
-        rv = InsertText(aString);
+        rv = InsertTextAsAction(aString);
+        NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert the new text");
       }
     }
   }
   // post-process
   return rules->DidDoAction(selection, &ruleInfo, rv);
 }
 
 nsresult
@@ -1161,17 +1189,19 @@ TextEditor::UpdateIMEComposition(WidgetC
   RefPtr<nsCaret> caretP = ps->GetCaret();
 
   nsresult rv;
   {
     AutoPlaceholderBatch batch(this, nsGkAtoms::IMETxnName);
 
     MOZ_ASSERT(mIsInEditAction,
       "AutoPlaceholderBatch should've notified the observes of before-edit");
-    rv = InsertText(aCompsitionChangeEvent->mData);
+    rv = InsertTextAsAction(aCompsitionChangeEvent->mData);
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+      "Failed to insert new composition string");
 
     if (caretP) {
       caretP->SetSelection(selection);
     }
   }
 
   // If still composing, we should fire input event via observer.
   // Note that if the composition will be committed by the following
@@ -1711,17 +1741,21 @@ TextEditor::OutputToStream(nsIOutputStre
   }
 
   return encoder->EncodeToStream(aOutputStream);
 }
 
 NS_IMETHODIMP
 TextEditor::InsertTextWithQuotations(const nsAString& aStringToInsert)
 {
-  return InsertText(aStringToInsert);
+  nsresult rv = InsertTextAsAction(aStringToInsert);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 TextEditor::PasteAsQuotation(int32_t aSelectionType)
 {
   // Get Clipboard Service
   nsresult rv;
   nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1", &rv));
@@ -1790,17 +1824,18 @@ TextEditor::InsertAsQuotation(const nsAS
   RulesInfo ruleInfo(EditAction::insertElement);
   bool cancel, handled;
   rv = rules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
   NS_ENSURE_SUCCESS(rv, rv);
   if (cancel) {
     return NS_OK; // Rules canceled the operation.
   }
   if (!handled) {
-    rv = InsertText(quotedStuff);
+    rv = InsertTextAsAction(quotedStuff);
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert quoted text");
 
     // XXX Should set *aNodeInserted to the first node inserted
     if (aNodeInserted && NS_SUCCEEDED(rv)) {
       *aNodeInserted = nullptr;
     }
   }
   return rv;
 }
@@ -1884,17 +1919,21 @@ TextEditor::StripCites()
   rv = InternetCiter::StripCites(current, stripped);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (isCollapsed) {
     rv = SelectAll();
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  return InsertText(stripped);
+  rv = InsertTextAsAction(stripped);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 TextEditor::GetEmbeddedObjects(nsIArray** aNodeList)
 {
   if (NS_WARN_IF(!aNodeList)) {
     return NS_ERROR_INVALID_ARG;
   }
--- a/editor/libeditor/TextEditor.h
+++ b/editor/libeditor/TextEditor.h
@@ -39,23 +39,16 @@ class Selection;
 class TextEditor : public EditorBase
                  , public nsIPlaintextEditor
                  , public nsIEditorMailSupport
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(TextEditor, EditorBase)
 
-  enum ETypingAction
-  {
-    eTypedText,  /* user typed text */
-    eTypedBR,    /* user typed shift-enter to get a br */
-    eTypedBreak  /* user typed enter */
-  };
-
   TextEditor();
 
   // nsIPlaintextEditor methods
   NS_DECL_NSIPLAINTEXTEDITOR
 
   // nsIEditorMailSupport overrides
   NS_DECL_NSIEDITORMAILSUPPORT
 
@@ -158,18 +151,46 @@ public:
    * @param aDirection          How much range should be removed.
    * @param aStripWrappers      Whether the parent blocks should be removed
    *                            when they become empty.
    */
   virtual nsresult
   DeleteSelectionWithTransaction(EDirection aAction,
                                  EStripWrappers aStripWrappers);
 
-  // Utility Routines, not part of public API
-  NS_IMETHOD TypedText(const nsAString& aString, ETypingAction aAction);
+  /**
+   * OnInputText() is called when user inputs text with keyboard or something.
+   *
+   * @param aStringToInsert     The string to insert.
+   */
+  nsresult OnInputText(const nsAString& aStringToInsert);
+
+  /**
+   * OnInputParagraphSeparator() is called when user tries to separate current
+   * paragraph with Enter key press or something.
+   */
+  nsresult OnInputParagraphSeparator();
+
+  /**
+   * InsertTextAsAction() inserts aStringToInsert at selection.
+   * Although this method is implementation of nsIPlaintextEditor.insertText(),
+   * this treats the input is an edit action.
+   *
+   * @param aStringToInsert     The string to insert.
+   */
+  nsresult InsertTextAsAction(const nsAString& aStringToInsert);
+
+  /**
+   * InsertParagraphSeparatorAsAction() inserts a line break if it's TextEditor
+   * or inserts new paragraph if it's HTMLEditor and it's possible.
+   * Although, this method is implementation of
+   * nsIPlaintextEditor.insertLineBreak(), this treats the input is an edit
+   * action.
+   */
+  nsresult InsertParagraphSeparatorAsAction();
 
   nsresult InsertTextAt(const nsAString& aStringToInsert,
                         nsINode* aDestinationNode,
                         int32_t aDestOffset,
                         bool aDoDeleteSelection);
 
   virtual nsresult InsertFromDataTransfer(dom::DataTransfer* aDataTransfer,
                                           int32_t aIndex,
--- a/editor/libeditor/TextEditorDataTransfer.cpp
+++ b/editor/libeditor/TextEditorDataTransfer.cpp
@@ -90,17 +90,21 @@ TextEditor::InsertTextAt(const nsAString
 
     ErrorResult error;
     selection->Collapse(RawRangeBoundary(targetNode, targetOffset), error);
     if (NS_WARN_IF(error.Failed())) {
       return error.StealNSResult();
     }
   }
 
-  return InsertText(aStringToInsert);
+  nsresult rv = InsertTextAsAction(aStringToInsert);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
 }
 
 nsresult
 TextEditor::InsertTextFromTransferable(nsITransferable* aTransferable)
 {
   nsresult rv = NS_OK;
   nsAutoCString bestFlavor;
   nsCOMPtr<nsISupports> genericDataObj;
--- a/editor/spellchecker/TextServicesDocument.cpp
+++ b/editor/spellchecker/TextServicesDocument.cpp
@@ -1254,17 +1254,17 @@ TextServicesDocument::InsertText(const n
 
   RefPtr<TextEditor> textEditor = mTextEditor;
   nsresult rv = textEditor->BeginTransaction();
   if (NS_FAILED(rv)) {
     UNLOCK_DOC(this);
     return rv;
   }
 
-  rv = textEditor->InsertText(*aText);
+  rv = textEditor->InsertTextAsAction(*aText);
   if (NS_FAILED(rv)) {
     textEditor->EndTransaction();
     UNLOCK_DOC(this);
     return rv;
   }
 
   int32_t strLength = aText->Length();
 
--- a/extensions/spellcheck/src/mozInlineSpellChecker.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp
@@ -964,17 +964,18 @@ mozInlineSpellChecker::ReplaceWord(nsIDO
     AutoPlaceholderBatch phb(mTextEditor, nullptr);
 
     RefPtr<Selection> selection = mTextEditor->GetSelection();
     NS_ENSURE_TRUE(selection, NS_ERROR_UNEXPECTED);
     selection->RemoveAllRanges(IgnoreErrors());
     selection->AddRange(*editorRange, IgnoreErrors());
 
     MOZ_ASSERT(mTextEditor);
-    mTextEditor->InsertText(newword);
+    DebugOnly<nsresult> rv = mTextEditor->InsertTextAsAction(newword);
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert the new word");
   }
 
   return NS_OK;
 }
 
 // mozInlineSpellChecker::AddWordToDictionary
 
 NS_IMETHODIMP