Bug 1574852 - part 104: Move TextEditRules::WillInsertText() to TextEditor and make HTMLEditor::WillInsertText() override it r=m_kato

And also this patch moves `TextEditRules::HandleNewLines()` and
`TextEditRules::DontEchoPassword()` to `TextEditor`.

Differential Revision: https://phabricator.services.mozilla.com/D45298

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Masayuki Nakano 2019-09-13 02:40:09 +00:00
parent 1a291f1700
commit f521a40385
9 changed files with 226 additions and 291 deletions

View File

@ -401,8 +401,9 @@ class HyperTextAccessible : public AccessibleWrap {
//////////////////////////////////////////////////////////////////////////////
// EditableTextAccessible
void ReplaceText(const nsAString& aText);
void InsertText(const nsAString& aText, int32_t aPosition);
MOZ_CAN_RUN_SCRIPT_BOUNDARY void ReplaceText(const nsAString& aText);
MOZ_CAN_RUN_SCRIPT_BOUNDARY void InsertText(const nsAString& aText,
int32_t aPosition);
void CopyText(int32_t aStartPos, int32_t aEndPos);
MOZ_CAN_RUN_SCRIPT_BOUNDARY void CutText(int32_t aStartPos, int32_t aEndPos);
MOZ_CAN_RUN_SCRIPT_BOUNDARY void DeleteText(int32_t aStartPos,

View File

@ -507,10 +507,6 @@ class EditorBase : public nsIEditor,
return (mFlags & nsIPlaintextEditor::eEditorAllowInteraction) != 0;
}
bool DontEchoPassword() const {
return (mFlags & nsIPlaintextEditor::eEditorDontEchoPassword) != 0;
}
bool ShouldSkipSpellCheck() const {
return (mFlags & nsIPlaintextEditor::eEditorSkipSpellCheck) != 0;
}

View File

@ -777,12 +777,6 @@ nsresult HTMLEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel,
}
switch (aInfo.mEditSubAction) {
case EditSubAction::eInsertText:
case EditSubAction::eInsertTextComingFromIME:
TextEditorRef().UndefineCaretBidiLevel();
return MOZ_KnownLive(HTMLEditorRef())
.WillInsertText(aInfo.mEditSubAction, aCancel, aHandled,
aInfo.inString, aInfo.outString, aInfo.maxLength);
case EditSubAction::eDeleteSelectedContent:
result = MOZ_KnownLive(HTMLEditorRef())
.HandleDeleteSelection(aInfo.collapsedAction,
@ -809,6 +803,8 @@ nsresult HTMLEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel,
case EditSubAction::eIndent:
case EditSubAction::eInsertHTMLSource:
case EditSubAction::eInsertParagraphSeparator:
case EditSubAction::eInsertText:
case EditSubAction::eInsertTextComingFromIME:
case EditSubAction::eOutdent:
case EditSubAction::eUndo:
case EditSubAction::eRedo:
@ -832,9 +828,6 @@ nsresult HTMLEditRules::DidDoAction(EditSubActionInfo& aInfo,
AutoSafeEditorData setData(*this, *mHTMLEditor);
switch (aInfo.mEditSubAction) {
case EditSubAction::eInsertText:
case EditSubAction::eInsertTextComingFromIME:
return NS_OK;
case EditSubAction::eInsertElement:
case EditSubAction::eInsertQuotedText:
return NS_OK;
@ -848,6 +841,8 @@ nsresult HTMLEditRules::DidDoAction(EditSubActionInfo& aInfo,
case EditSubAction::eInsertHTMLSource:
case EditSubAction::eInsertLineBreak:
case EditSubAction::eInsertParagraphSeparator:
case EditSubAction::eInsertText:
case EditSubAction::eInsertTextComingFromIME:
case EditSubAction::eOutdent:
case EditSubAction::eUndo:
case EditSubAction::eRedo:
@ -1379,47 +1374,47 @@ nsresult HTMLEditor::WillInsert(bool* aCancel) {
return NS_OK;
}
nsresult HTMLEditor::WillInsertText(EditSubAction aEditSubAction, bool* aCancel,
bool* aHandled, const nsAString* inString,
nsAString* outString, int32_t aMaxLength) {
EditActionResult HTMLEditor::HandleInsertText(
EditSubAction aEditSubAction, const nsAString& aInsertionString) {
MOZ_ASSERT(IsTopLevelEditSubActionDataAvailable());
MOZ_ASSERT(aEditSubAction == EditSubAction::eInsertText ||
aEditSubAction == EditSubAction::eInsertTextComingFromIME);
if (NS_WARN_IF(!aCancel) || NS_WARN_IF(!aHandled)) {
return NS_ERROR_NULL_POINTER;
EditActionResult result = CanHandleHTMLEditSubAction();
if (NS_WARN_IF(result.Failed()) || result.Canceled()) {
return result;
}
// initialize out param
*aCancel = false;
*aHandled = true;
UndefineCaretBidiLevel();
// If the selection isn't collapsed, delete it. Don't delete existing inline
// tags, because we're hopefully going to insert text (bug 787432).
if (!SelectionRefPtr()->IsCollapsed()) {
nsresult rv =
DeleteSelectionAsSubAction(nsIEditor::eNone, nsIEditor::eNoStrip);
if (NS_WARN_IF(Destroyed())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionHandled(rv);
}
}
// FYI: Ignore cancel result of WillInsert().
nsresult rv = WillInsert();
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
// we need to get the doc
RefPtr<Document> doc = GetDocument();
if (NS_WARN_IF(!doc)) {
return NS_ERROR_FAILURE;
RefPtr<Document> document = GetDocument();
if (NS_WARN_IF(!document)) {
return EditActionHandled(NS_ERROR_FAILURE);
}
RefPtr<nsRange> firstRange = SelectionRefPtr()->GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
return NS_ERROR_FAILURE;
return EditActionHandled(NS_ERROR_FAILURE);
}
// for every property that is set, insert a new inline style node
@ -1427,24 +1422,24 @@ nsresult HTMLEditor::WillInsertText(EditSubAction aEditSubAction, bool* aCancel,
// it should just return the insertion point instead.
rv = CreateStyleForInsertText(*firstRange);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionHandled(rv);
}
firstRange = SelectionRefPtr()->GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
return NS_ERROR_FAILURE;
return EditActionHandled(NS_ERROR_FAILURE);
}
EditorDOMPoint pointToInsert(firstRange->StartRef());
if (NS_WARN_IF(!pointToInsert.IsSet())) {
return NS_ERROR_FAILURE;
return EditActionHandled(NS_ERROR_FAILURE);
}
MOZ_ASSERT(pointToInsert.IsSetAndValid());
// dont put text in places that can't have it
if (!EditorBase::IsTextNode(pointToInsert.GetContainer()) &&
!CanContainTag(*pointToInsert.GetContainer(), *nsGkAtoms::textTagName)) {
return NS_ERROR_FAILURE;
return EditActionHandled(NS_ERROR_FAILURE);
}
if (aEditSubAction == EditSubAction::eInsertTextComingFromIME) {
@ -1453,17 +1448,18 @@ nsresult HTMLEditor::WillInsertText(EditSubAction aEditSubAction, bool* aCancel,
compositionStartPoint = pointToInsert;
}
if (inString->IsEmpty()) {
if (aInsertionString.IsEmpty()) {
// Right now the WSRunObject code bails on empty strings, but IME needs
// the InsertTextWithTransaction() call to still happen since empty
// strings are meaningful there.
rv = InsertTextWithTransaction(*doc, *inString, compositionStartPoint);
nsresult rv = InsertTextWithTransaction(*document, aInsertionString,
compositionStartPoint);
if (NS_WARN_IF(Destroyed())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"InsertTextWithTransaction() failed");
return rv;
return EditActionHandled(rv);
}
EditorRawDOMPoint compositionEndPoint = GetCompositionEndPoint();
@ -1471,12 +1467,12 @@ nsresult HTMLEditor::WillInsertText(EditSubAction aEditSubAction, bool* aCancel,
compositionEndPoint = compositionStartPoint;
}
WSRunObject wsObj(this, compositionStartPoint, compositionEndPoint);
rv = wsObj.InsertText(*doc, *inString);
nsresult rv = wsObj.InsertText(*document, aInsertionString);
if (NS_WARN_IF(Destroyed())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionHandled(rv);
}
compositionStartPoint = GetCompositionStartPoint();
@ -1484,14 +1480,14 @@ nsresult HTMLEditor::WillInsertText(EditSubAction aEditSubAction, bool* aCancel,
if (NS_WARN_IF(!compositionStartPoint.IsSet()) ||
NS_WARN_IF(!compositionEndPoint.IsSet())) {
// Mutation event listener has changed the DOM tree...
return NS_OK;
return EditActionHandled();
}
rv = TopLevelEditSubActionDataRef().mChangedRange->SetStartAndEnd(
compositionStartPoint.ToRawRangeBoundary(),
compositionEndPoint.ToRawRangeBoundary());
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"Faliled to set mChangedRange to composing range");
return rv;
return EditActionHandled(rv);
}
MOZ_ASSERT(aEditSubAction == EditSubAction::eInsertText);
@ -1513,8 +1509,6 @@ nsresult HTMLEditor::WillInsertText(EditSubAction aEditSubAction, bool* aCancel,
// don't change my selection in subtransactions
AutoTransactionsConserveSelection dontChangeMySelection(*this);
nsAutoString tString(*inString);
const char16_t* unicodeBuf = tString.get();
int32_t pos = 0;
NS_NAMED_LITERAL_STRING(newlineStr, LFSTR);
@ -1525,11 +1519,11 @@ nsresult HTMLEditor::WillInsertText(EditSubAction aEditSubAction, bool* aCancel,
// its a lot cheaper to search the input string for only newlines than
// it is to search for both tabs and newlines.
if (isPRE || IsPlaintextEditor()) {
while (unicodeBuf && pos != -1 &&
pos < static_cast<int32_t>(inString->Length())) {
while (pos != -1 &&
pos < static_cast<int32_t>(aInsertionString.Length())) {
int32_t oldPos = pos;
int32_t subStrLen;
pos = tString.FindChar(nsCRT::LF, oldPos);
pos = aInsertionString.FindChar(nsCRT::LF, oldPos);
if (pos != -1) {
subStrLen = pos - oldPos;
@ -1538,21 +1532,21 @@ nsresult HTMLEditor::WillInsertText(EditSubAction aEditSubAction, bool* aCancel,
subStrLen = 1;
}
} else {
subStrLen = tString.Length() - oldPos;
pos = tString.Length();
subStrLen = aInsertionString.Length() - oldPos;
pos = aInsertionString.Length();
}
nsDependentSubstring subStr(tString, oldPos, subStrLen);
nsDependentSubstring subStr(aInsertionString, oldPos, subStrLen);
// is it a return?
if (subStr.Equals(newlineStr)) {
RefPtr<Element> brElement =
InsertBRElementWithTransaction(currentPoint, nsIEditor::eNone);
if (NS_WARN_IF(Destroyed())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(!brElement)) {
return NS_ERROR_FAILURE;
return EditActionHandled(NS_ERROR_FAILURE);
}
pos++;
if (brElement->GetNextSibling()) {
@ -1573,14 +1567,14 @@ nsresult HTMLEditor::WillInsertText(EditSubAction aEditSubAction, bool* aCancel,
"by mutation observer");
} else {
EditorRawDOMPoint pointAfterInsertedString;
rv = InsertTextWithTransaction(*doc, subStr,
EditorRawDOMPoint(currentPoint),
&pointAfterInsertedString);
nsresult rv = InsertTextWithTransaction(
*document, subStr, EditorRawDOMPoint(currentPoint),
&pointAfterInsertedString);
if (NS_WARN_IF(Destroyed())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionHandled(rv);
}
currentPoint = pointAfterInsertedString;
pointToInsert = pointAfterInsertedString;
@ -1590,11 +1584,12 @@ nsresult HTMLEditor::WillInsertText(EditSubAction aEditSubAction, bool* aCancel,
NS_NAMED_LITERAL_STRING(tabStr, "\t");
NS_NAMED_LITERAL_STRING(spacesStr, " ");
char specialChars[] = {TAB, nsCRT::LF, 0};
while (unicodeBuf && pos != -1 &&
pos < static_cast<int32_t>(inString->Length())) {
nsAutoString insertionString(aInsertionString); // For FindCharInSet().
while (pos != -1 &&
pos < static_cast<int32_t>(insertionString.Length())) {
int32_t oldPos = pos;
int32_t subStrLen;
pos = tString.FindCharInSet(specialChars, oldPos);
pos = insertionString.FindCharInSet(specialChars, oldPos);
if (pos != -1) {
subStrLen = pos - oldPos;
@ -1603,22 +1598,23 @@ nsresult HTMLEditor::WillInsertText(EditSubAction aEditSubAction, bool* aCancel,
subStrLen = 1;
}
} else {
subStrLen = tString.Length() - oldPos;
pos = tString.Length();
subStrLen = insertionString.Length() - oldPos;
pos = insertionString.Length();
}
nsDependentSubstring subStr(tString, oldPos, subStrLen);
nsDependentSubstring subStr(insertionString, oldPos, subStrLen);
WSRunObject wsObj(this, currentPoint);
// is it a tab?
if (subStr.Equals(tabStr)) {
EditorRawDOMPoint pointAfterInsertedSpaces;
rv = wsObj.InsertText(*doc, spacesStr, &pointAfterInsertedSpaces);
nsresult rv =
wsObj.InsertText(*document, spacesStr, &pointAfterInsertedSpaces);
if (NS_WARN_IF(Destroyed())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionHandled(rv);
}
pos++;
MOZ_ASSERT(pointAfterInsertedSpaces.IsSet());
@ -1631,10 +1627,10 @@ nsresult HTMLEditor::WillInsertText(EditSubAction aEditSubAction, bool* aCancel,
wsObj.InsertBreak(MOZ_KnownLive(*SelectionRefPtr()), currentPoint,
nsIEditor::eNone);
if (NS_WARN_IF(Destroyed())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(!newBRElement)) {
return NS_ERROR_FAILURE;
return EditActionHandled(NS_ERROR_FAILURE);
}
pos++;
if (newBRElement->GetNextSibling()) {
@ -1655,12 +1651,13 @@ nsresult HTMLEditor::WillInsertText(EditSubAction aEditSubAction, bool* aCancel,
"Perhaps, newBRElement has been moved or removed unexpectedly");
} else {
EditorRawDOMPoint pointAfterInsertedString;
rv = wsObj.InsertText(*doc, subStr, &pointAfterInsertedString);
nsresult rv =
wsObj.InsertText(*document, subStr, &pointAfterInsertedString);
if (NS_WARN_IF(Destroyed())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionHandled(rv);
}
MOZ_ASSERT(pointAfterInsertedString.IsSet());
currentPoint = pointAfterInsertedString;
@ -1681,7 +1678,7 @@ nsresult HTMLEditor::WillInsertText(EditSubAction aEditSubAction, bool* aCancel,
IgnoredErrorResult ignoredError;
SelectionRefPtr()->Collapse(currentPoint, ignoredError);
if (NS_WARN_IF(Destroyed())) {
return NS_ERROR_EDITOR_DESTROYED;
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
NS_WARNING_ASSERTION(!ignoredError.Failed(),
"Failed to collapse at current point");
@ -1690,15 +1687,15 @@ nsresult HTMLEditor::WillInsertText(EditSubAction aEditSubAction, bool* aCancel,
// manually update the doc changed range so that AfterEdit will clean up
// the correct portion of the document.
if (currentPoint.IsSet()) {
rv = TopLevelEditSubActionDataRef().mChangedRange->SetStartAndEnd(
nsresult rv = TopLevelEditSubActionDataRef().mChangedRange->SetStartAndEnd(
pointToInsert.ToRawRangeBoundary(), currentPoint.ToRawRangeBoundary());
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to set mChangedRange");
return rv;
return EditActionHandled(rv);
}
rv = TopLevelEditSubActionDataRef().mChangedRange->CollapseTo(pointToInsert);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to collapse mChangedRange");
return rv;
return EditActionHandled(rv);
}
bool HTMLEditor::CanContainParagraph(Element& aElement) const {

View File

@ -1166,22 +1166,14 @@ class HTMLEditor final : public TextEditor,
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult WillInsert(bool* aCancel = nullptr);
/**
* Called before inserting text.
* This method may actually inserts text into the editor. Therefore, this
* might cause destroying the editor.
* HandleInsertText() handles inserting text at selection.
*
* @param aEditSubAction Must be EditSubAction::eInsertTextComingFromIME
* 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.
* @param aEditSubAction Must be EditSubAction::eInsertText or
* EditSubAction::eInsertTextComingFromIME.
* @param aInsertionString String to be inserted at selection.
*/
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult WillInsertText(
EditSubAction aEditSubAction, bool* aCancel, bool* aHandled,
const nsAString* inString, nsAString* outString, int32_t aMaxLength);
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE virtual EditActionResult HandleInsertText(
EditSubAction aEditSubAction, const nsAString& aInsertionString) final;
/**
* GetInlineStyles() retrieves the style of aNode and modifies each item of

View File

@ -202,11 +202,6 @@ nsresult TextEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel,
// my kingdom for dynamic cast
switch (aInfo.mEditSubAction) {
case EditSubAction::eInsertText:
case EditSubAction::eInsertTextComingFromIME:
TextEditorRef().UndefineCaretBidiLevel();
return WillInsertText(aInfo.mEditSubAction, aCancel, aHandled,
aInfo.inString, aInfo.outString, aInfo.maxLength);
case EditSubAction::eSetText:
TextEditorRef().UndefineCaretBidiLevel();
return WillSetText(aCancel, aHandled, aInfo.inString, aInfo.maxLength);
@ -234,6 +229,8 @@ nsresult TextEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel,
}
case EditSubAction::eInsertElement:
case EditSubAction::eInsertLineBreak:
case EditSubAction::eInsertText:
case EditSubAction::eInsertTextComingFromIME:
case EditSubAction::eUndo:
case EditSubAction::eRedo:
MOZ_ASSERT_UNREACHABLE("This path should've been dead code");
@ -253,6 +250,8 @@ nsresult TextEditRules::DidDoAction(EditSubActionInfo& aInfo,
case EditSubAction::eDeleteSelectedContent:
case EditSubAction::eInsertElement:
case EditSubAction::eInsertLineBreak:
case EditSubAction::eInsertText:
case EditSubAction::eInsertTextComingFromIME:
case EditSubAction::eUndo:
case EditSubAction::eRedo:
MOZ_ASSERT_UNREACHABLE("This path should've been dead code");
@ -284,7 +283,7 @@ EditActionResult TextEditor::InsertLineFeedCharacterAtSelection() {
if (mMaxTextLength >= 0) {
nsAutoString insertionString(NS_LITERAL_STRING("\n"));
EditActionResult result =
TruncateInsertionStringForMaxLength(insertionString, mMaxTextLength);
TruncateInsertionStringForMaxLength(insertionString);
if (NS_WARN_IF(result.Failed())) {
return result;
}
@ -467,9 +466,11 @@ TextEditRules::GetTextNodeAroundSelectionStartContainer() {
return node.forget();
}
void TextEditRules::HandleNewLines(nsString& aString) {
void TextEditor::HandleNewLinesInStringForSingleLineEditor(
nsString& aString) const {
static const char16_t kLF = static_cast<char16_t>('\n');
MOZ_ASSERT(IsEditorDataAvailable());
MOZ_ASSERT(IsEditActionDataAvailable());
MOZ_ASSERT(IsPlaintextEditor());
MOZ_ASSERT(aString.FindChar(static_cast<uint16_t>('\r')) == kNotFound);
// First of all, check if aString contains '\n' since if the string
@ -479,7 +480,7 @@ void TextEditRules::HandleNewLines(nsString& aString) {
return;
}
switch (TextEditorRef().mNewlineHandling) {
switch (mNewlineHandling) {
case nsIPlaintextEditor::eNewlinesReplaceWithSpaces:
// Default of Firefox:
// Strip trailing newlines first so we don't wind up with trailing spaces
@ -540,84 +541,70 @@ void TextEditRules::HandleNewLines(nsString& aString) {
}
}
nsresult TextEditRules::WillInsertText(EditSubAction aEditSubAction,
bool* aCancel, bool* aHandled,
const nsAString* inString,
nsAString* outString,
int32_t aMaxLength) {
MOZ_ASSERT(IsEditorDataAvailable());
EditActionResult TextEditor::HandleInsertText(
EditSubAction aEditSubAction, const nsAString& aInsertionString) {
MOZ_ASSERT(IsEditActionDataAvailable());
MOZ_ASSERT(aEditSubAction == EditSubAction::eInsertText ||
aEditSubAction == EditSubAction::eInsertTextComingFromIME);
if (NS_WARN_IF(!aCancel) || NS_WARN_IF(!aHandled)) {
return NS_ERROR_INVALID_ARG;
}
UndefineCaretBidiLevel();
if (inString->IsEmpty() &&
if (aInsertionString.IsEmpty() &&
aEditSubAction != EditSubAction::eInsertTextComingFromIME) {
// HACK: this is a fix for bug 19395
// I can't outlaw all empty insertions
// because IME transaction depend on them
// There is more work to do to make the
// world safe for IME.
*aCancel = true;
*aHandled = false;
return NS_OK;
return EditActionCanceled();
}
// initialize out param
*aCancel = false;
*aHandled = true;
outString->Assign(*inString);
if (aMaxLength >= 0) {
nsAutoString insertionString(aInsertionString);
if (mMaxTextLength >= 0) {
EditActionResult result =
TextEditorRef().TruncateInsertionStringForMaxLength(*outString,
aMaxLength);
TruncateInsertionStringForMaxLength(insertionString);
if (NS_WARN_IF(result.Failed())) {
return result.Rv();
return result.MarkAsHandled();
}
// If we're exceeding the maxlength when composing IME, we need to clean up
// the composing text, so we shouldn't return early.
if (result.Handled() && outString->IsEmpty() &&
if (result.Handled() && insertionString.IsEmpty() &&
aEditSubAction != EditSubAction::eInsertTextComingFromIME) {
*aCancel = true;
return NS_OK;
return EditActionCanceled();
}
}
uint32_t start = 0;
if (IsPasswordEditor()) {
if (TextEditorRef().GetComposition() &&
!TextEditorRef().GetComposition()->String().IsEmpty()) {
start = TextEditorRef().GetComposition()->XPOffsetInTextNode();
if (GetComposition() && !GetComposition()->String().IsEmpty()) {
start = GetComposition()->XPOffsetInTextNode();
} else {
uint32_t end = 0;
nsContentUtils::GetSelectionInTextControl(
SelectionRefPtr(), TextEditorRef().GetRoot(), start, end);
nsContentUtils::GetSelectionInTextControl(SelectionRefPtr(), GetRoot(),
start, end);
}
}
// if the selection isn't collapsed, delete it.
if (!SelectionRefPtr()->IsCollapsed()) {
nsresult rv =
MOZ_KnownLive(TextEditorRef())
.DeleteSelectionAsSubAction(nsIEditor::eNone, nsIEditor::eStrip);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
DeleteSelectionAsSubAction(nsIEditor::eNone, nsIEditor::eStrip);
if (NS_WARN_IF(Destroyed())) {
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionHandled(rv);
}
}
// XXX Why do we set `aCancel` here, but ignore it?
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
// XXX Why don't we cancel here? Shouldn't we do this first?
CANCEL_OPERATION_AND_RETURN_EDIT_ACTION_RESULT_IF_READONLY_OF_DISABLED
TextEditorRef().MaybeDoAutoPasswordMasking();
MaybeDoAutoPasswordMasking();
nsresult rv =
MOZ_KnownLive(TextEditorRef()).EnsureNoPaddingBRElementForEmptyEditor();
nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionHandled(rv);
}
// People have lots of different ideas about what text fields
@ -631,7 +618,6 @@ nsresult TextEditRules::WillInsertText(EditSubAction aEditSubAction,
// 5. strip newlines and surrounding whitespace
// So find out what we're expected to do:
if (IsSingleLineEditor()) {
nsAutoString tString(*outString);
// XXX Some callers of TextEditor::InsertTextAsAction() already make the
// string use only \n as a linebreaker. However, they are not hot
// path and nsContentUtils::PlatformToDOMLineBreaks() does nothing
@ -639,104 +625,98 @@ nsresult TextEditRules::WillInsertText(EditSubAction aEditSubAction,
// here. Note that there are too many callers of
// TextEditor::InsertTextAsAction(). So, it's difficult to keep
// maintaining all of them won't reach here without \r nor \r\n.
nsContentUtils::PlatformToDOMLineBreaks(tString);
HandleNewLines(tString);
outString->Assign(tString);
// XXX Should we handle do this before truncating the string for
// `maxlength`?
nsContentUtils::PlatformToDOMLineBreaks(insertionString);
HandleNewLinesInStringForSingleLineEditor(insertionString);
}
// get the (collapsed) selection location
nsRange* firstRange = SelectionRefPtr()->GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
return NS_ERROR_FAILURE;
return EditActionHandled(NS_ERROR_FAILURE);
}
EditorRawDOMPoint atStartOfSelection(firstRange->StartRef());
if (NS_WARN_IF(!atStartOfSelection.IsSetAndValid())) {
return NS_ERROR_FAILURE;
return EditActionHandled(NS_ERROR_FAILURE);
}
// don't put text in places that can't have it
if (!atStartOfSelection.IsInTextNode() &&
!TextEditorRef().CanContainTag(*atStartOfSelection.GetContainer(),
*nsGkAtoms::textTagName)) {
return NS_ERROR_FAILURE;
!CanContainTag(*atStartOfSelection.GetContainer(),
*nsGkAtoms::textTagName)) {
return EditActionHandled(NS_ERROR_FAILURE);
}
// we need to get the doc
RefPtr<Document> doc = TextEditorRef().GetDocument();
if (NS_WARN_IF(!doc)) {
return NS_ERROR_NOT_INITIALIZED;
RefPtr<Document> document = GetDocument();
if (NS_WARN_IF(!document)) {
return EditActionHandled(NS_ERROR_NOT_INITIALIZED);
}
if (aEditSubAction == EditSubAction::eInsertTextComingFromIME) {
EditorRawDOMPoint compositionStartPoint =
TextEditorRef().GetCompositionStartPoint();
EditorRawDOMPoint compositionStartPoint = GetCompositionStartPoint();
if (!compositionStartPoint.IsSet()) {
compositionStartPoint =
TextEditorRef().FindBetterInsertionPoint(atStartOfSelection);
compositionStartPoint = FindBetterInsertionPoint(atStartOfSelection);
}
nsresult rv =
MOZ_KnownLive(TextEditorRef())
.InsertTextWithTransaction(*doc, *outString, compositionStartPoint);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
nsresult rv = InsertTextWithTransaction(*document, insertionString,
compositionStartPoint);
if (NS_WARN_IF(Destroyed())) {
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionHandled(rv);
}
} else {
// aEditSubAction == EditSubAction::eInsertText
MOZ_ASSERT(aEditSubAction == EditSubAction::eInsertText);
// don't change my selection in subtransactions
AutoTransactionsConserveSelection dontChangeMySelection(TextEditorRef());
AutoTransactionsConserveSelection dontChangeMySelection(*this);
EditorRawDOMPoint pointAfterStringInserted;
nsresult rv =
MOZ_KnownLive(TextEditorRef())
.InsertTextWithTransaction(*doc, *outString, atStartOfSelection,
&pointAfterStringInserted);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
nsresult rv = InsertTextWithTransaction(*document, insertionString,
atStartOfSelection,
&pointAfterStringInserted);
if (NS_WARN_IF(Destroyed())) {
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
return EditActionHandled(rv);
}
if (pointAfterStringInserted.IsSet()) {
// Make the caret attach to the inserted text, unless this text ends with
// a LF, in which case make the caret attach to the next line.
bool endsWithLF = !outString->IsEmpty() && outString->Last() == nsCRT::LF;
IgnoredErrorResult error;
SelectionRefPtr()->SetInterlinePosition(endsWithLF, error);
NS_WARNING_ASSERTION(!error.Failed(),
"Failed to set or unset interline position");
bool endsWithLF =
!insertionString.IsEmpty() && insertionString.Last() == nsCRT::LF;
IgnoredErrorResult ignoredError;
SelectionRefPtr()->SetInterlinePosition(endsWithLF, ignoredError);
NS_WARNING_ASSERTION(
!ignoredError.Failed(),
"Selection::SetInterlinePosition() failed, but ignored");
MOZ_ASSERT(
!pointAfterStringInserted.GetChild(),
"After inserting text into a text node, pointAfterStringInserted."
"GetChild() should be nullptr");
error = IgnoredErrorResult();
SelectionRefPtr()->Collapse(pointAfterStringInserted, error);
if (NS_WARN_IF(!CanHandleEditAction())) {
return NS_ERROR_EDITOR_DESTROYED;
ignoredError = IgnoredErrorResult();
SelectionRefPtr()->Collapse(pointAfterStringInserted, ignoredError);
if (NS_WARN_IF(Destroyed())) {
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
}
NS_WARNING_ASSERTION(
!error.Failed(),
"Failed to collapse selection after inserting string");
NS_WARNING_ASSERTION(!ignoredError.Failed(),
"Selection::Collapse() failed, but ignored");
}
}
// Unmask inputted character(s) if necessary.
if (IsPasswordEditor() && IsMaskingPassword() && !DontEchoPassword()) {
nsresult rv =
MOZ_KnownLive(TextEditorRef())
.SetUnmaskRangeAndNotify(start, outString->Length(),
LookAndFeel::GetPasswordMaskDelay());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (IsPasswordEditor() && IsMaskingPassword() && CanEchoPasswordNow()) {
nsresult rv = SetUnmaskRangeAndNotify(start, insertionString.Length(),
LookAndFeel::GetPasswordMaskDelay());
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetUnmaskRangeAndNotify() failed");
return EditActionHandled(rv);
}
return NS_OK;
return EditActionHandled();
}
nsresult TextEditRules::WillSetText(bool* aCancel, bool* aHandled,
@ -812,7 +792,7 @@ nsresult TextEditRules::WillSetText(bool* aCancel, bool* aHandled,
// Is this intentional?
nsAutoString tString(*aString);
if (IsSingleLineEditor() && !IsPasswordEditor()) {
HandleNewLines(tString);
TextEditorRef().HandleNewLinesInStringForSingleLineEditor(tString);
}
if (!firstChild || !EditorBase::IsTextNode(firstChild)) {
@ -1148,8 +1128,9 @@ nsresult TextEditRules::CreateTrailingBRIfNeeded() {
}
EditActionResult TextEditor::TruncateInsertionStringForMaxLength(
nsAString& aInsertionString, uint32_t aMaxLength) {
nsAString& aInsertionString) {
MOZ_ASSERT(IsEditActionDataAvailable());
MOZ_ASSERT(mMaxTextLength >= 0);
if (!IsPlaintextEditor() || IsIMEComposing()) {
return EditActionIgnored();
@ -1175,16 +1156,17 @@ EditActionResult TextEditor::TruncateInsertionStringForMaxLength(
// is part of kOldCompositionStringLength.
const uint32_t kNewLength =
currentLength - kSelectionLength - kOldCompositionStringLength;
if (kNewLength >= aMaxLength) {
if (kNewLength >= static_cast<uint32_t>(mMaxTextLength)) {
aInsertionString.Truncate(); // Too long, we cannot accept new character.
return EditActionHandled();
}
if (aInsertionString.Length() + kNewLength <= aMaxLength) {
if (aInsertionString.Length() + kNewLength <=
static_cast<uint32_t>(mMaxTextLength)) {
return EditActionIgnored(); // Enough short string.
}
int32_t newInsertionStringLength = aMaxLength - kNewLength;
int32_t newInsertionStringLength = mMaxTextLength - kNewLength;
MOZ_ASSERT(newInsertionStringLength > 0);
char16_t maybeHighSurrogate =
aInsertionString.CharAt(newInsertionStringLength - 1);
@ -1229,20 +1211,14 @@ bool TextEditRules::IsMailEditor() const {
return mTextEditor ? mTextEditor->IsMailEditor() : false;
}
bool TextEditRules::DontEchoPassword() const {
if (!mTextEditor) {
// XXX Why do we use echo password if editor is null?
bool TextEditor::CanEchoPasswordNow() const {
if (!LookAndFeel::GetEchoPassword() ||
(mFlags & nsIPlaintextEditor::eEditorDontEchoPassword)) {
return false;
}
if (!LookAndFeel::GetEchoPassword() || mTextEditor->DontEchoPassword()) {
return true;
}
if (mTextEditor->GetEditAction() != EditAction::eDrop &&
mTextEditor->GetEditAction() != EditAction::ePaste) {
return false;
}
return true;
return GetEditAction() != EditAction::eDrop &&
GetEditAction() != EditAction::ePaste;
}
} // namespace mozilla

View File

@ -102,55 +102,10 @@ class TextEditRules {
protected:
virtual ~TextEditRules() = default;
public:
/**
* Handles the newline characters according to the default system prefs
* (editor.singleLine.pasteNewlines).
* Each value means:
* nsIPlaintextEditor::eNewlinesReplaceWithSpaces (2, Firefox default):
* replace newlines with spaces.
* nsIPlaintextEditor::eNewlinesStrip (3):
* remove newlines from the string.
* nsIPlaintextEditor::eNewlinesReplaceWithCommas (4, Thunderbird default):
* replace newlines with commas.
* nsIPlaintextEditor::eNewlinesStripSurroundingWhitespace (5):
* collapse newlines and surrounding whitespace characters and
* remove them from the string.
* nsIPlaintextEditor::eNewlinesPasteIntact (0):
* only remove the leading and trailing newlines.
* nsIPlaintextEditor::eNewlinesPasteToFirst (1) or any other value:
* remove the first newline and all characters following it.
*
* @param aString the string to be modified in place.
*/
void HandleNewLines(nsString& aString);
protected:
void InitFields();
// TextEditRules implementation methods
/**
* Called before inserting text.
* This method may actually inserts text into the editor. Therefore, this
* might cause destroying the editor.
*
* @param aEditSubAction Must be EditSubAction::eInsertTextComingFromIME
* 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 setting text to the text editor.
* This method may actually set text to it. Therefore, this might cause

View File

@ -954,9 +954,6 @@ nsresult TextEditor::InsertTextAsSubAction(const nsAString& aStringToInsert) {
return NS_ERROR_NOT_INITIALIZED;
}
// Protect the edit rules object from dying.
RefPtr<TextEditRules> rules(mRules);
EditSubAction editSubAction = ShouldHandleIMEComposition()
? EditSubAction::eInsertTextComingFromIME
: EditSubAction::eInsertText;
@ -964,32 +961,9 @@ nsresult TextEditor::InsertTextAsSubAction(const nsAString& aStringToInsert) {
AutoEditSubActionNotifier startToHandleEditSubAction(*this, editSubAction,
nsIEditor::eNext);
nsAutoString resultString;
// XXX can we trust instring to outlive subActionInfo,
// XXX and subActionInfo not to refer to instring in its dtor?
// nsAutoString instring(aStringToInsert);
EditSubActionInfo subActionInfo(editSubAction);
subActionInfo.inString = &aStringToInsert;
subActionInfo.outString = &resultString;
subActionInfo.maxLength = mMaxTextLength;
bool cancel, handled;
nsresult rv = rules->WillDoAction(subActionInfo, &cancel, &handled);
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
rv = rules->DidDoAction(subActionInfo, NS_OK);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
EditActionResult result = HandleInsertText(editSubAction, aStringToInsert);
NS_WARNING_ASSERTION(result.Succeeded(), "HandleInsertText() failed");
return result.Rv();
}
NS_IMETHODIMP

View File

@ -214,8 +214,8 @@ class TextEditor : public EditorBase,
* JS. If set to nullptr, will be treated as
* called by system.
*/
nsresult InsertTextAsAction(const nsAString& aStringToInsert,
nsIPrincipal* aPrincipal = nullptr);
MOZ_CAN_RUN_SCRIPT nsresult InsertTextAsAction(
const nsAString& aStringToInsert, nsIPrincipal* aPrincipal = nullptr);
/**
* PasteAsQuotationAsAction() pastes content in clipboard as quotation.
@ -423,7 +423,8 @@ class TextEditor : public EditorBase,
*
* @param aStringToInsert The string to insert.
*/
nsresult InsertTextAsSubAction(const nsAString& aStringToInsert);
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
InsertTextAsSubAction(const nsAString& aStringToInsert);
/**
* DeleteSelectionAsSubAction() removes selection content or content around
@ -586,7 +587,7 @@ class TextEditor : public EditorBase,
* more characters, returns "as handled".
*/
EditActionResult TruncateInsertionStringForMaxLength(
nsAString& aInsertionString, uint32_t aMaxLength);
nsAString& aInsertionString);
/**
* InsertLineFeedCharacterAtSelection() inserts a linefeed character at
@ -595,6 +596,38 @@ class TextEditor : public EditorBase,
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE EditActionResult
InsertLineFeedCharacterAtSelection();
/**
* Handles the newline characters according to the default system prefs
* (editor.singleLine.pasteNewlines).
* Each value means:
* nsIPlaintextEditor::eNewlinesReplaceWithSpaces (2, Firefox default):
* replace newlines with spaces.
* nsIPlaintextEditor::eNewlinesStrip (3):
* remove newlines from the string.
* nsIPlaintextEditor::eNewlinesReplaceWithCommas (4, Thunderbird default):
* replace newlines with commas.
* nsIPlaintextEditor::eNewlinesStripSurroundingWhitespace (5):
* collapse newlines and surrounding whitespace characters and
* remove them from the string.
* nsIPlaintextEditor::eNewlinesPasteIntact (0):
* only remove the leading and trailing newlines.
* nsIPlaintextEditor::eNewlinesPasteToFirst (1) or any other value:
* remove the first newline and all characters following it.
*
* @param aString the string to be modified in place.
*/
void HandleNewLinesInStringForSingleLineEditor(nsString& aString) const;
/**
* HandleInsertText() handles inserting text at selection.
*
* @param aEditSubAction Must be EditSubAction::eInsertText or
* EditSubAction::eInsertTextComingFromIME.
* @param aInsertionString String to be inserted at selection.
*/
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE virtual EditActionResult HandleInsertText(
EditSubAction aEditSubAction, const nsAString& aInsertionString);
protected: // Called by helper classes.
virtual void OnStartToHandleTopLevelEditSubAction(
EditSubAction aEditSubAction, nsIEditor::EDirection aDirection) override;
@ -632,6 +665,13 @@ class TextEditor : public EditorBase,
int32_t WrapWidth() const { return mWrapColumn; }
/**
* CanEchoPasswordNow() returns true if currently we can echo password.
* If it's direct user input such as pasting or dropping text, this
* returns false even if we may echo password.
*/
bool CanEchoPasswordNow() const;
/**
* Make the given selection span the entire document.
*/
@ -643,7 +683,8 @@ class TextEditor : public EditorBase,
*
* @param aStringToInsert The string to insert.
*/
nsresult OnInputText(const nsAString& aStringToInsert);
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
OnInputText(const nsAString& aStringToInsert);
/**
* InsertLineBreakAsSubAction() inserts a line break, i.e., \n if it's
@ -687,7 +728,8 @@ class TextEditor : public EditorBase,
* @param aQuotedText String to insert. This will be quoted by ">"
* automatically.
*/
nsresult InsertWithQuotationsAsSubAction(const nsAString& aQuotedText);
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
InsertWithQuotationsAsSubAction(const nsAString& aQuotedText);
/**
* Return true if the data is safe to insert as the source and destination
@ -730,7 +772,8 @@ class TextEditor : public EditorBase,
*/
virtual nsresult PrepareTransferable(nsITransferable** transferable);
nsresult InsertTextFromTransferable(nsITransferable* transferable);
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
InsertTextFromTransferable(nsITransferable* transferable);
/**
* DeleteSelectionAndCreateElement() creates a element whose name is aTag.

View File

@ -86,6 +86,7 @@ interface nsIPlaintextEditor : nsISupports
*
* @param aString the string to be inserted
*/
[can_run_script]
void insertText(in AString aStringToInsert);
/**