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
--- 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()) {
@@ -2324,23 +2312,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