mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-12 00:50:40 +00:00
Backed out 2 changesets (bug 1574852) for assertion failures at TextEditRules.cpp
Backed out changeset f54f6af6359d (bug 1574852) Backed out changeset 2b6968592570 (bug 1574852)
This commit is contained in:
parent
bf1c1cfd11
commit
ba23dcf114
@ -2910,23 +2910,19 @@ nsresult EditorBase::NotifyDocumentListeners(
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult EditorBase::SetTextNodeWithoutTransaction(const nsAString& aString,
|
||||
Text& aTextNode) {
|
||||
nsresult EditorBase::SetTextImpl(const nsAString& aString, Text& aTextNode) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
MOZ_ASSERT(!AsHTMLEditor());
|
||||
MOZ_ASSERT(IsPlaintextEditor());
|
||||
MOZ_ASSERT(!IsUndoRedoEnabled());
|
||||
|
||||
const uint32_t length = aTextNode.Length();
|
||||
|
||||
AutoEditSubActionNotifier startToHandleEditSubAction(
|
||||
*this, EditSubAction::eSetText, nsIEditor::eNext);
|
||||
|
||||
// Let listeners know what's up
|
||||
if (!mActionListeners.IsEmpty() && length) {
|
||||
AutoActionListenerArray listeners(mActionListeners);
|
||||
for (auto& listener : listeners) {
|
||||
listener->WillDeleteText(&aTextNode, 0, length);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2940,13 +2936,13 @@ nsresult EditorBase::SetTextNodeWithoutTransaction(const nsAString& aString,
|
||||
return rv;
|
||||
}
|
||||
|
||||
DebugOnly<nsresult> rvIgnored =
|
||||
SelectionRefPtr()->Collapse(&aTextNode, aString.Length());
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
{
|
||||
// Create a nested scope to not overwrite rv from the outer scope.
|
||||
DebugOnly<nsresult> rv =
|
||||
SelectionRefPtr()->Collapse(&aTextNode, aString.Length());
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Selection could not be collapsed after insert");
|
||||
}
|
||||
NS_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"Selection::Collapse() failed, but ignored");
|
||||
|
||||
RangeUpdaterRef().SelAdjDeleteText(&aTextNode, 0, length);
|
||||
RangeUpdaterRef().SelAdjInsertText(aTextNode, 0, aString);
|
||||
@ -2955,11 +2951,9 @@ nsresult EditorBase::SetTextNodeWithoutTransaction(const nsAString& aString,
|
||||
RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
|
||||
if (length) {
|
||||
htmlEditRules->DidDeleteText(aTextNode, 0, length);
|
||||
MOZ_ASSERT(!Destroyed());
|
||||
}
|
||||
if (!aString.IsEmpty()) {
|
||||
htmlEditRules->DidInsertText(aTextNode, 0, aString);
|
||||
MOZ_ASSERT(!Destroyed());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2969,20 +2963,14 @@ nsresult EditorBase::SetTextNodeWithoutTransaction(const nsAString& aString,
|
||||
for (auto& listener : listeners) {
|
||||
if (length) {
|
||||
listener->DidDeleteText(&aTextNode, 0, length, rv);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
}
|
||||
if (!aString.IsEmpty()) {
|
||||
listener->DidInsertText(&aTextNode, 0, aString, rv);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult EditorBase::DeleteTextWithTransaction(Text& aTextNode,
|
||||
|
@ -1144,13 +1144,8 @@ class EditorBase : public nsIEditor,
|
||||
const nsAString& aStringToInsert, Text& aTextNode, int32_t aOffset,
|
||||
bool aSuppressIME = false);
|
||||
|
||||
/**
|
||||
* SetTextNodeWithoutTransaction() is optimized path to set new value to
|
||||
* the text node directly and without transaction. This is used when
|
||||
* setting `<input>.value` and `<textarea>.value`.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
|
||||
SetTextNodeWithoutTransaction(const nsAString& aString, Text& aTextNode);
|
||||
MOZ_CAN_RUN_SCRIPT nsresult SetTextImpl(const nsAString& aString,
|
||||
Text& aTextNode);
|
||||
|
||||
/**
|
||||
* DeleteNodeWithTransaction() removes aNode from the DOM tree.
|
||||
|
@ -773,34 +773,11 @@ nsresult HTMLEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel,
|
||||
switch (aInfo.mEditSubAction) {
|
||||
case EditSubAction::eInsertElement:
|
||||
case EditSubAction::eInsertQuotedText: {
|
||||
*aCancel = IsReadonly() || IsDisabled();
|
||||
nsresult rv = MOZ_KnownLive(HTMLEditorRef())
|
||||
.EnsureNoPaddingBRElementForEmptyEditor();
|
||||
nsresult rv = MOZ_KnownLive(HTMLEditorRef()).WillInsert(aCancel);
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING(
|
||||
"EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
|
||||
return NS_OK;
|
||||
}
|
||||
if (!SelectionRefPtr()->IsCollapsed()) {
|
||||
return NS_OK;
|
||||
}
|
||||
rv = MOZ_KnownLive(HTMLEditorRef()).EnsureCaretNotAfterPaddingBRElement();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
|
||||
return NS_OK;
|
||||
}
|
||||
rv = MOZ_KnownLive(HTMLEditorRef()).PrepareInlineStylesForCaret();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"PrepareInlineStylesForCaret() failed, but ignored");
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
|
||||
return NS_OK;
|
||||
}
|
||||
case EditSubAction::eComputeTextToOutput:
|
||||
@ -1306,64 +1283,66 @@ nsresult HTMLEditRules::GetFormatString(nsINode* aNode, nsAString& outFormat) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult HTMLEditor::EnsureCaretNotAfterPaddingBRElement() {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
MOZ_ASSERT(SelectionRefPtr()->IsCollapsed());
|
||||
nsresult HTMLEditor::WillInsert(bool* aCancel) {
|
||||
MOZ_ASSERT(IsTopLevelEditSubActionDataAvailable());
|
||||
|
||||
// If we are after a padding `<br>` element for empty last line in the same
|
||||
// XXX Why don't we stop handling this call if we're readonly or disabled?
|
||||
if (aCancel && (IsReadonly() || IsDisabled())) {
|
||||
*aCancel = true;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Adjust selection to prevent insertion after a padding <br> element for
|
||||
// empty last line. This next only works for collapsed selections right
|
||||
// now, because selection is a pain to work with when not collapsed. (no
|
||||
// good way to extend start or end of selection), so we ignore those types
|
||||
// of selections.
|
||||
if (!SelectionRefPtr()->IsCollapsed()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If we are after a padding <br> element for empty last line in the same
|
||||
// block, then move selection to be before it
|
||||
nsRange* firstRange = SelectionRefPtr()->GetRangeAt(0);
|
||||
if (NS_WARN_IF(!firstRange)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
EditorRawDOMPoint atSelectionStart(firstRange->StartRef());
|
||||
if (NS_WARN_IF(!atSelectionStart.IsSet())) {
|
||||
EditorRawDOMPoint atStartOfSelection(firstRange->StartRef());
|
||||
if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
MOZ_ASSERT(atSelectionStart.IsSetAndValid());
|
||||
MOZ_ASSERT(atStartOfSelection.IsSetAndValid());
|
||||
|
||||
nsCOMPtr<nsIContent> previousEditableContent =
|
||||
GetPreviousEditableHTMLNode(atSelectionStart);
|
||||
if (!previousEditableContent ||
|
||||
!EditorBase::IsPaddingBRElementForEmptyLastLine(
|
||||
*previousEditableContent)) {
|
||||
return NS_OK;
|
||||
// Get prior node
|
||||
nsCOMPtr<nsIContent> priorNode =
|
||||
GetPreviousEditableHTMLNode(atStartOfSelection);
|
||||
if (priorNode && EditorBase::IsPaddingBRElementForEmptyLastLine(*priorNode)) {
|
||||
RefPtr<Element> block1 = GetBlock(*atStartOfSelection.GetContainer());
|
||||
RefPtr<Element> block2 = GetBlockNodeParent(priorNode);
|
||||
|
||||
if (block1 && block1 == block2) {
|
||||
// If we are here then the selection is right after a padding <br>
|
||||
// element for empty last line that is in the same block as the
|
||||
// selection. We need to move the selection start to be before the
|
||||
// padding <br> element.
|
||||
EditorRawDOMPoint point(priorNode);
|
||||
ErrorResult error;
|
||||
SelectionRefPtr()->Collapse(point, error);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
error.SuppressException();
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<Element> blockElementAtSelectionStart =
|
||||
GetBlock(*atSelectionStart.GetContainer());
|
||||
RefPtr<Element> parentBlockElementOfPreviousEditableContent =
|
||||
GetBlockNodeParent(previousEditableContent);
|
||||
|
||||
if (!blockElementAtSelectionStart ||
|
||||
blockElementAtSelectionStart !=
|
||||
parentBlockElementOfPreviousEditableContent) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If we are here then the selection is right after a padding <br>
|
||||
// element for empty last line that is in the same block as the
|
||||
// selection. We need to move the selection start to be before the
|
||||
// padding <br> element.
|
||||
EditorRawDOMPoint atPreviousEditableContent(previousEditableContent);
|
||||
ErrorResult error;
|
||||
SelectionRefPtr()->Collapse(atPreviousEditableContent, error);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
error.SuppressException();
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(!error.Failed(), "Selection::Collapse() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
nsresult HTMLEditor::PrepareInlineStylesForCaret() {
|
||||
MOZ_ASSERT(IsTopLevelEditSubActionDataAvailable());
|
||||
MOZ_ASSERT(SelectionRefPtr()->IsCollapsed());
|
||||
|
||||
// XXX This method works with the top level edit sub-action, but this
|
||||
// must be wrong if we are handling nested edit action.
|
||||
|
||||
if (TopLevelEditSubActionDataRef().mDidDeleteSelection) {
|
||||
switch (GetTopLevelEditSubAction()) {
|
||||
case EditSubAction::eInsertText:
|
||||
@ -1410,31 +1389,12 @@ EditActionResult HTMLEditor::HandleInsertText(
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
|
||||
// FYI: Ignore cancel result of WillInsert().
|
||||
nsresult rv = WillInsert();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
|
||||
|
||||
if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
|
||||
nsresult rv = EnsureCaretNotAfterPaddingBRElement();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsresult rv = PrepareInlineStylesForCaret();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"PrepareInlineStylesForCaret() failed, but ignored");
|
||||
}
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
|
||||
|
||||
RefPtr<Document> document = GetDocument();
|
||||
if (NS_WARN_IF(!document)) {
|
||||
@ -1778,31 +1738,12 @@ EditActionResult HTMLEditor::InsertParagraphSeparatorAsSubAction() {
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
|
||||
// FYI: Ignore cancel result of WillInsert().
|
||||
nsresult rv = WillInsert();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
|
||||
|
||||
if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
|
||||
nsresult rv = EnsureCaretNotAfterPaddingBRElement();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsresult rv = PrepareInlineStylesForCaret();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"PrepareInlineStylesForCaret() failed, but ignored");
|
||||
}
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
|
||||
|
||||
// Split any mailcites in the way. Should we abort this if we encounter
|
||||
// table cell boundaries?
|
||||
@ -2020,8 +1961,7 @@ EditActionResult HTMLEditor::InsertParagraphSeparatorAsSubAction() {
|
||||
// Fall through, if HandleInsertParagraphInParagraph() didn't handle it.
|
||||
MOZ_ASSERT(!result.Canceled(),
|
||||
"HandleInsertParagraphInParagraph() canceled this edit action, "
|
||||
"InsertParagraphSeparatorAsSubAction() needs to handle this "
|
||||
"action instead");
|
||||
"WillInsertBreak() needs to handle such case");
|
||||
}
|
||||
|
||||
// If nobody handles this edit action, let's insert new <br> at the selection.
|
||||
@ -4232,31 +4172,12 @@ EditActionResult HTMLEditor::MakeOrChangeListAndListItemAsSubAction(
|
||||
: EditSubAction::eCreateOrChangeList,
|
||||
nsIEditor::eNext);
|
||||
|
||||
nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
|
||||
// FYI: Ignore cancel result of WillInsert().
|
||||
nsresult rv = WillInsert();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
|
||||
|
||||
if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
|
||||
nsresult rv = EnsureCaretNotAfterPaddingBRElement();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsresult rv = PrepareInlineStylesForCaret();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"PrepareInlineStylesForCaret() failed, but ignored");
|
||||
}
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
|
||||
|
||||
nsAtom* listTagName = nullptr;
|
||||
nsAtom* listItemTagName = nullptr;
|
||||
@ -5037,31 +4958,12 @@ EditActionResult HTMLEditor::IndentAsSubAction() {
|
||||
EditActionResult HTMLEditor::HandleIndentAtSelection() {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
|
||||
nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
|
||||
// FYI: Ignore cancel result of WillInsert().
|
||||
nsresult rv = WillInsert();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
|
||||
|
||||
if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
|
||||
nsresult rv = EnsureCaretNotAfterPaddingBRElement();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsresult rv = PrepareInlineStylesForCaret();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"PrepareInlineStylesForCaret() failed, but ignored");
|
||||
}
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed, but ignored");
|
||||
|
||||
if (IsCSSEnabled()) {
|
||||
nsresult rv = HandleCSSIndentAtSelection();
|
||||
@ -6389,31 +6291,12 @@ EditActionResult HTMLEditor::AlignAsSubAction(const nsAString& aAlignType) {
|
||||
return result;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
|
||||
// FYI: Ignore cancel result of WillInsert().
|
||||
nsresult rv = WillInsert();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
|
||||
|
||||
if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
|
||||
nsresult rv = EnsureCaretNotAfterPaddingBRElement();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsresult rv = PrepareInlineStylesForCaret();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"PrepareInlineStylesForCaret() failed, but ignored");
|
||||
}
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed, but ignored");
|
||||
|
||||
if (!SelectionRefPtr()->IsCollapsed()) {
|
||||
nsresult rv = MaybeExtendSelectionToHardLineEdgesForBlockEditAction();
|
||||
@ -11018,31 +10901,12 @@ EditActionResult HTMLEditor::SetSelectionToAbsoluteAsSubAction() {
|
||||
return result;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
|
||||
// FYI: Ignore cancel result of WillInsert().
|
||||
nsresult rv = WillInsert();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
|
||||
|
||||
if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
|
||||
nsresult rv = EnsureCaretNotAfterPaddingBRElement();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsresult rv = PrepareInlineStylesForCaret();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"PrepareInlineStylesForCaret() failed, but ignored");
|
||||
}
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
|
||||
|
||||
RefPtr<Element> focusElement = GetSelectionContainerElement();
|
||||
if (focusElement && HTMLEditUtils::IsImage(focusElement)) {
|
||||
@ -11367,31 +11231,12 @@ EditActionResult HTMLEditor::SetSelectionToStaticAsSubAction() {
|
||||
return result;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
|
||||
// FYI: Ignore cancel result of WillInsert().
|
||||
nsresult rv = WillInsert();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
|
||||
|
||||
if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
|
||||
nsresult rv = EnsureCaretNotAfterPaddingBRElement();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsresult rv = PrepareInlineStylesForCaret();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"PrepareInlineStylesForCaret() failed, but ignored");
|
||||
}
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed, but ignored");
|
||||
|
||||
RefPtr<Element> element = GetAbsolutelyPositionedSelectionContainer();
|
||||
if (NS_WARN_IF(!element)) {
|
||||
@ -11430,31 +11275,12 @@ EditActionResult HTMLEditor::AddZIndexAsSubAction(int32_t aChange) {
|
||||
return result;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
|
||||
// FYI: Ignore cancel result of WillInsert().
|
||||
nsresult rv = WillInsert();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
|
||||
|
||||
if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
|
||||
nsresult rv = EnsureCaretNotAfterPaddingBRElement();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsresult rv = PrepareInlineStylesForCaret();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"PrepareInlineStylesForCaret() failed, but ignored");
|
||||
}
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed, but ignored");
|
||||
|
||||
RefPtr<Element> absolutelyPositionedElement =
|
||||
GetAbsolutelyPositionedSelectionContainer();
|
||||
|
@ -2115,31 +2115,13 @@ nsresult HTMLEditor::FormatBlockContainerAsSubAction(nsAtom& aTagName) {
|
||||
return result.Rv();
|
||||
}
|
||||
|
||||
nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
|
||||
// FYI: Ignore cancel result of WillInsert() since we've already checked
|
||||
// whether we can or cannot edit current selection range.
|
||||
nsresult rv = WillInsert();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureNoPaddingBRElementForEmptyEditor() failed, but ignored");
|
||||
|
||||
if (NS_SUCCEEDED(rv) && SelectionRefPtr()->IsCollapsed()) {
|
||||
nsresult rv = EnsureCaretNotAfterPaddingBRElement();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EnsureCaretNotAfterPaddingBRElement() failed, but ignored");
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsresult rv = PrepareInlineStylesForCaret();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"PrepareInlineStylesForCaret() failed, but ignored");
|
||||
}
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed, but ignored");
|
||||
|
||||
// FormatBlockContainerWithTransaction() creates AutoSelectionRestorer.
|
||||
// Therefore, even if it returns NS_OK, editor might have been destroyed
|
||||
|
@ -1156,24 +1156,14 @@ class HTMLEditor final : public TextEditor,
|
||||
EditActionResult CanHandleHTMLEditSubAction() const;
|
||||
|
||||
/**
|
||||
* EnsureCaretNotAfterPaddingBRElement() makes sure that caret is NOT after
|
||||
* padding `<br>` element for preventing insertion after padding `<br>`
|
||||
* element at empty last line.
|
||||
* NOTE: This method should be called only when `Selection` is collapsed
|
||||
* because `Selection` is a pain to work with when not collapsed.
|
||||
* (no good way to extend start or end of selection), so we need to
|
||||
* ignore those types of selections.
|
||||
* Called before inserting something into the editor.
|
||||
* This method may removes mPaddingBRElementForEmptyEditor if there is.
|
||||
* Therefore, this method might cause destroying the editor.
|
||||
*
|
||||
* @param aCancel Returns true if the operation is canceled.
|
||||
* This can be nullptr.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
|
||||
EnsureCaretNotAfterPaddingBRElement();
|
||||
|
||||
/**
|
||||
* PrepareInlineStylesForCaret() consider inline styles from top level edit
|
||||
* sub-action and setting it to `mTypeInState` and clear inline style cache
|
||||
* if necessary.
|
||||
* NOTE: This method should be called only when `Selection` is collapsed.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult PrepareInlineStylesForCaret();
|
||||
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult WillInsert(bool* aCancel = nullptr);
|
||||
|
||||
/**
|
||||
* HandleInsertText() handles inserting text at selection.
|
||||
|
@ -202,6 +202,9 @@ nsresult TextEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel,
|
||||
|
||||
// my kingdom for dynamic cast
|
||||
switch (aInfo.mEditSubAction) {
|
||||
case EditSubAction::eSetText:
|
||||
TextEditorRef().UndefineCaretBidiLevel();
|
||||
return WillSetText(aCancel, aHandled, aInfo.inString, aInfo.maxLength);
|
||||
case EditSubAction::eInsertQuotedText: {
|
||||
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
|
||||
|
||||
@ -221,7 +224,6 @@ nsresult TextEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel,
|
||||
case EditSubAction::eInsertLineBreak:
|
||||
case EditSubAction::eInsertText:
|
||||
case EditSubAction::eInsertTextComingFromIME:
|
||||
case EditSubAction::eSetText:
|
||||
case EditSubAction::eUndo:
|
||||
case EditSubAction::eRedo:
|
||||
MOZ_ASSERT_UNREACHABLE("This path should've been dead code");
|
||||
@ -244,7 +246,6 @@ nsresult TextEditRules::DidDoAction(EditSubActionInfo& aInfo,
|
||||
case EditSubAction::eInsertLineBreak:
|
||||
case EditSubAction::eInsertText:
|
||||
case EditSubAction::eInsertTextComingFromIME:
|
||||
case EditSubAction::eSetText:
|
||||
case EditSubAction::eUndo:
|
||||
case EditSubAction::eRedo:
|
||||
MOZ_ASSERT_UNREACHABLE("This path should've been dead code");
|
||||
@ -678,31 +679,41 @@ EditActionResult TextEditor::HandleInsertText(
|
||||
return EditActionHandled();
|
||||
}
|
||||
|
||||
EditActionResult TextEditor::SetTextWithoutTransaction(
|
||||
const nsAString& aValue) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
MOZ_ASSERT(!AsTextEditor());
|
||||
MOZ_ASSERT(IsPlaintextEditor());
|
||||
MOZ_ASSERT(!IsIMEComposing());
|
||||
MOZ_ASSERT(!IsUndoRedoEnabled());
|
||||
MOZ_ASSERT(GetEditAction() != EditAction::eReplaceText);
|
||||
MOZ_ASSERT(mMaxTextLength < 0);
|
||||
MOZ_ASSERT(aValue.FindChar(static_cast<char16_t>('\r')) == kNotFound);
|
||||
|
||||
UndefineCaretBidiLevel();
|
||||
nsresult TextEditRules::WillSetText(bool* aCancel, bool* aHandled,
|
||||
const nsAString* aString,
|
||||
int32_t aMaxLength) {
|
||||
MOZ_ASSERT(IsEditorDataAvailable());
|
||||
MOZ_ASSERT(!mIsHTMLEditRules);
|
||||
MOZ_ASSERT(aCancel);
|
||||
MOZ_ASSERT(aHandled);
|
||||
MOZ_ASSERT(aString);
|
||||
MOZ_ASSERT(aString->FindChar(static_cast<char16_t>('\r')) == kNotFound);
|
||||
|
||||
// XXX If we're setting value, shouldn't we keep setting the new value here?
|
||||
CANCEL_OPERATION_AND_RETURN_EDIT_ACTION_RESULT_IF_READONLY_OF_DISABLED
|
||||
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
|
||||
|
||||
MaybeDoAutoPasswordMasking();
|
||||
*aHandled = false;
|
||||
*aCancel = false;
|
||||
|
||||
nsresult rv = EnsureNoPaddingBRElementForEmptyEditor();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return EditActionResult(rv);
|
||||
if (!IsPlaintextEditor() || TextEditorRef().IsIMEComposing() ||
|
||||
TextEditorRef().IsUndoRedoEnabled() ||
|
||||
TextEditorRef().GetEditAction() == EditAction::eReplaceText ||
|
||||
aMaxLength != -1) {
|
||||
// SetTextImpl only supports plain text editor without IME and
|
||||
// when we don't need to make it undoable.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<Element> anonymousDivElement = GetRoot();
|
||||
nsIContent* firstChild = anonymousDivElement->GetFirstChild();
|
||||
TextEditorRef().MaybeDoAutoPasswordMasking();
|
||||
|
||||
nsresult rv =
|
||||
MOZ_KnownLive(TextEditorRef()).EnsureNoPaddingBRElementForEmptyEditor();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
RefPtr<Element> rootElement = TextEditorRef().GetRoot();
|
||||
nsIContent* firstChild = rootElement->GetFirstChild();
|
||||
|
||||
// We can use this fast path only when:
|
||||
// - we need to insert a text node.
|
||||
@ -715,73 +726,82 @@ EditActionResult TextEditor::SetTextWithoutTransaction(
|
||||
// that even if there is a padding <br> element for empty editor, it's
|
||||
// already been removed by `EnsureNoPaddingBRElementForEmptyEditor()`. So,
|
||||
// at here, there should be only one text node or no children.
|
||||
if (firstChild && (!firstChild->IsText() || firstChild->GetNextSibling())) {
|
||||
return EditActionIgnored();
|
||||
if (firstChild &&
|
||||
(!EditorBase::IsTextNode(firstChild) || firstChild->GetNextSibling())) {
|
||||
return NS_OK;
|
||||
}
|
||||
} else {
|
||||
// If we're a multiline text editor, i.e., <textarea>, there is a padding
|
||||
// <br> element for empty last line followed by scrollbar/resizer elements.
|
||||
// Otherwise, a text node is followed by them.
|
||||
if (!firstChild) {
|
||||
return EditActionIgnored();
|
||||
return NS_OK;
|
||||
}
|
||||
if (firstChild->IsText()) {
|
||||
if (EditorBase::IsTextNode(firstChild)) {
|
||||
if (!firstChild->GetNextSibling() ||
|
||||
!EditorBase::IsPaddingBRElementForEmptyLastLine(
|
||||
*firstChild->GetNextSibling())) {
|
||||
return EditActionIgnored();
|
||||
return NS_OK;
|
||||
}
|
||||
} else if (!EditorBase::IsPaddingBRElementForEmptyLastLine(*firstChild)) {
|
||||
return EditActionIgnored();
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// XXX Password fields accept line breaks as normal characters with this code.
|
||||
// Is this intentional?
|
||||
nsAutoString sanitizedValue(aValue);
|
||||
nsAutoString tString(*aString);
|
||||
if (IsSingleLineEditor() && !IsPasswordEditor()) {
|
||||
HandleNewLinesInStringForSingleLineEditor(sanitizedValue);
|
||||
TextEditorRef().HandleNewLinesInStringForSingleLineEditor(tString);
|
||||
}
|
||||
|
||||
if (!firstChild || !firstChild->IsText()) {
|
||||
if (sanitizedValue.IsEmpty()) {
|
||||
return EditActionHandled();
|
||||
if (!firstChild || !EditorBase::IsTextNode(firstChild)) {
|
||||
if (tString.IsEmpty()) {
|
||||
*aHandled = true;
|
||||
return NS_OK;
|
||||
}
|
||||
RefPtr<Document> document = GetDocument();
|
||||
if (NS_WARN_IF(!document)) {
|
||||
return EditActionIgnored();
|
||||
RefPtr<Document> doc = TextEditorRef().GetDocument();
|
||||
if (NS_WARN_IF(!doc)) {
|
||||
return NS_OK;
|
||||
}
|
||||
RefPtr<nsTextNode> newTextNode = CreateTextNode(sanitizedValue);
|
||||
if (NS_WARN_IF(!newTextNode)) {
|
||||
return EditActionIgnored();
|
||||
RefPtr<nsTextNode> newNode = TextEditorRef().CreateTextNode(tString);
|
||||
if (NS_WARN_IF(!newNode)) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsresult rv = InsertNodeWithTransaction(
|
||||
*newTextNode, EditorDOMPoint(anonymousDivElement, 0));
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
nsresult rv = MOZ_KnownLive(TextEditorRef())
|
||||
.InsertNodeWithTransaction(
|
||||
*newNode, EditorDOMPoint(rootElement, 0));
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return EditActionResult(rv);
|
||||
return rv;
|
||||
}
|
||||
return EditActionHandled();
|
||||
*aHandled = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// TODO: If new value is empty string, we should only remove it.
|
||||
// Even if empty text, we don't remove text node and set empty text
|
||||
// for performance
|
||||
RefPtr<Text> textNode = firstChild->GetAsText();
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(!textNode))) {
|
||||
return EditActionIgnored();
|
||||
return NS_OK;
|
||||
}
|
||||
rv = MOZ_KnownLive(TextEditorRef()).SetTextImpl(tString, *textNode);
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
rv = SetTextNodeWithoutTransaction(sanitizedValue, *textNode);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return EditActionResult(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// If we replaced non-empty value with empty string, we need to delete the
|
||||
// text node.
|
||||
if (sanitizedValue.IsEmpty() && !textNode->Length()) {
|
||||
nsresult rv = DeleteNodeWithTransaction(*textNode);
|
||||
if (tString.IsEmpty() && !textNode->Length()) {
|
||||
nsresult rv =
|
||||
MOZ_KnownLive(TextEditorRef()).DeleteNodeWithTransaction(*textNode);
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"DeleteNodeWithTransaction() failed, but ignored");
|
||||
@ -794,7 +814,8 @@ EditActionResult TextEditor::SetTextWithoutTransaction(
|
||||
"Selection::SetInterlinePoisition() failed");
|
||||
}
|
||||
|
||||
return EditActionHandled();
|
||||
*aHandled = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
EditActionResult TextEditor::HandleDeleteSelection(
|
||||
|
@ -106,6 +106,22 @@ class TextEditRules {
|
||||
|
||||
// TextEditRules implementation methods
|
||||
|
||||
/**
|
||||
* Called before setting text to the text editor.
|
||||
* This method may actually set text to it. Therefore, this might cause
|
||||
* destroying the text editor.
|
||||
*
|
||||
* @param aCancel Returns true if the operation is canceled.
|
||||
* @param aHandled Returns true if the edit action is handled.
|
||||
* @param inString String to be set.
|
||||
* @param aMaxLength The maximum string length which the text editor
|
||||
* allows to set.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
MOZ_MUST_USE nsresult WillSetText(bool* aCancel, bool* aHandled,
|
||||
const nsAString* inString,
|
||||
int32_t aMaxLength);
|
||||
|
||||
/**
|
||||
* Creates a trailing break in the text doc if there is not one already.
|
||||
*/
|
||||
|
@ -991,8 +991,10 @@ nsresult TextEditor::SetTextAsAction(const nsAString& aString,
|
||||
|
||||
AutoPlaceholderBatch treatAsOneTransaction(*this);
|
||||
nsresult rv = SetTextAsSubAction(aString);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetTextAsSubAction() failed");
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult TextEditor::ReplaceTextAsAction(const nsAString& aString,
|
||||
@ -1017,8 +1019,10 @@ nsresult TextEditor::ReplaceTextAsAction(const nsAString& aString,
|
||||
|
||||
if (!aReplaceRange) {
|
||||
nsresult rv = SetTextAsSubAction(aString);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetTextAsSubAction() failed");
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(aString.IsEmpty() && aReplaceRange->Collapsed())) {
|
||||
@ -1058,18 +1062,26 @@ nsresult TextEditor::SetTextAsSubAction(const nsAString& aString) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
// Protect the edit rules object from dying
|
||||
RefPtr<TextEditRules> rules(mRules);
|
||||
|
||||
AutoEditSubActionNotifier startToHandleEditSubAction(
|
||||
*this, EditSubAction::eSetText, nsIEditor::eNext);
|
||||
|
||||
if (IsPlaintextEditor() && !IsIMEComposing() && !IsUndoRedoEnabled() &&
|
||||
GetEditAction() != EditAction::eReplaceText && mMaxTextLength < 0) {
|
||||
EditActionResult result = SetTextWithoutTransaction(aString);
|
||||
if (NS_WARN_IF(result.Failed()) || result.Canceled() || result.Handled()) {
|
||||
return result.Rv();
|
||||
}
|
||||
}
|
||||
EditSubActionInfo subActionInfo(EditSubAction::eSetText);
|
||||
subActionInfo.inString = &aString;
|
||||
subActionInfo.maxLength = mMaxTextLength;
|
||||
|
||||
{
|
||||
bool cancel;
|
||||
bool handled;
|
||||
nsresult rv = rules->WillDoAction(subActionInfo, &cancel, &handled);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
if (cancel) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (!handled) {
|
||||
// Note that do not notify selectionchange caused by selecting all text
|
||||
// because it's preparation of our delete implementation so web apps
|
||||
// shouldn't receive such selectionchange before the first mutation.
|
||||
@ -1080,34 +1092,31 @@ nsresult TextEditor::SetTextAsSubAction(const nsAString& aString) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// We want to select trailing `<br>` element to remove all nodes to replace
|
||||
// all, but TextEditor::SelectEntireDocument() doesn't select such `<br>`
|
||||
// elements.
|
||||
// XXX We should make ReplaceSelectionAsSubAction() take range. Then,
|
||||
// we can saving the expensive cost of modifying `Selection` here.
|
||||
nsresult rv;
|
||||
if (mRules && mRules->DocumentIsEmpty()) {
|
||||
// We want to select trailing BR node to remove all nodes to replace all,
|
||||
// but TextEditor::SelectEntireDocument doesn't select that BR node.
|
||||
if (rules->DocumentIsEmpty()) {
|
||||
rv = SelectionRefPtr()->Collapse(rootElement, 0);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Selection::Collapse() failed, but ignored");
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"Failed to move caret to start of the editor root element");
|
||||
} else {
|
||||
ErrorResult error;
|
||||
SelectionRefPtr()->SelectAllChildren(*rootElement, error);
|
||||
NS_WARNING_ASSERTION(
|
||||
!error.Failed(),
|
||||
"Selection::SelectAllChildren() failed, but ignored");
|
||||
"Failed to select all children of the editor root element");
|
||||
rv = error.StealNSResult();
|
||||
}
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
DebugOnly<nsresult> rvIgnored = ReplaceSelectionAsSubAction(aString);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"ReplaceSelectionAsSubAction() failed, but ignored");
|
||||
rv = ReplaceSelectionAsSubAction(aString);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Failed to replace selection with new string");
|
||||
}
|
||||
}
|
||||
|
||||
// Destroying AutoUpdateViewBatch may cause destroying us.
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
// post-process
|
||||
rv = rules->DidDoAction(subActionInfo, rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -457,8 +457,7 @@ class TextEditor : public EditorBase,
|
||||
*
|
||||
* @ param aString The string to be set.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
|
||||
SetTextAsSubAction(const nsAString& aString);
|
||||
MOZ_CAN_RUN_SCRIPT nsresult SetTextAsSubAction(const nsAString& aString);
|
||||
|
||||
/**
|
||||
* ReplaceSelectionAsSubAction() replaces selection with aString.
|
||||
@ -661,14 +660,6 @@ class TextEditor : public EditorBase,
|
||||
EditActionResult ComputeValueFromTextNodeAndPaddingBRElement(
|
||||
nsAString& aValue) const;
|
||||
|
||||
/**
|
||||
* SetTextWithoutTransaction() is optimized method to set `<input>.value`
|
||||
* and `<textarea>.value` to aValue without transaction. This must be
|
||||
* called only when it's not `HTMLEditor` and undo/redo is disabled.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE EditActionResult
|
||||
SetTextWithoutTransaction(const nsAString& aValue);
|
||||
|
||||
protected: // Called by helper classes.
|
||||
virtual void OnStartToHandleTopLevelEditSubAction(
|
||||
EditSubAction aEditSubAction, nsIEditor::EDirection aDirection) override;
|
||||
|
Loading…
Reference in New Issue
Block a user