Bug 1739545 - part 1: Get rid of mozInlineSpellChecker::DidJoinNodes() and mozInlineSpellChecker::DidSplitNode() r=m_kato

Currently, they do nothing because they specify empty range to
`SpellCheckBetweenNodes()`, and it makes the method does nothing.  This is
filed as bug 1581714.  However, they are not required because `HTMLEditor`
notifies `mozInlineSpellChecker` at ending handling the top level edit sub
action.
https://searchfox.org/mozilla-central/rev/a12c2c2e59c92d8f969d8f3f290ab16919449c9d/editor/libeditor/HTMLEditSubActionHandler.cpp#675

Therefore, these methods are not necessary anymore.

Differential Revision: https://phabricator.services.mozilla.com/D130457
This commit is contained in:
Masayuki Nakano 2021-11-09 01:09:20 +00:00
parent 1759f51cd0
commit 1034b36c49
7 changed files with 206 additions and 33 deletions

View File

@ -688,6 +688,7 @@ class EditorDOMPointBase final {
// We're already referring the start of the container or
// the offset is invalid since perhaps, the offset was set before
// the last DOM tree change.
NS_ASSERTION(false, "Failed to rewind offset");
return false;
}
mOffset = mozilla::Some(mOffset.value() - 1);

View File

@ -6370,7 +6370,9 @@ already_AddRefed<nsRange> HTMLEditor::CreateRangeIncludingAdjuscentWhiteSpaces(
}
}
EditorRawDOMPoint lastRawPoint(endPoint);
lastRawPoint.RewindOffset(); // XXX Fail if it's start of the container
if (!lastRawPoint.IsStartOfContainer()) {
lastRawPoint.RewindOffset();
}
if (!IsDescendantOfEditorRoot(lastRawPoint.GetChildOrContainerIfDataNode())) {
return nullptr;
}

View File

@ -4243,12 +4243,6 @@ already_AddRefed<nsIContent> HTMLEditor::SplitNodeWithTransaction(
*this, *aStartOfRightNode.GetContainerAsContent(), *newLeftContent);
}
if (mInlineSpellChecker) {
RefPtr<mozInlineSpellChecker> spellChecker = mInlineSpellChecker;
spellChecker->DidSplitNode(aStartOfRightNode.GetContainer(),
newLeftContent);
}
if (aError.Failed()) {
return nullptr;
}
@ -4631,11 +4625,6 @@ nsresult HTMLEditor::JoinNodesWithTransaction(nsIContent& aLeftContent,
TopLevelEditSubActionDataRef().DidJoinContents(
*this, EditorRawDOMPoint(&aRightContent, oldLeftNodeLen));
if (mInlineSpellChecker) {
RefPtr<mozInlineSpellChecker> spellChecker = mInlineSpellChecker;
spellChecker->DidJoinNodes(aLeftContent, aRightContent);
}
if (mTextServicesDocument && NS_SUCCEEDED(rv)) {
RefPtr<TextServicesDocument> textServicesDocument = mTextServicesDocument;
textServicesDocument->DidJoinNodes(aLeftContent, aRightContent);

View File

@ -40,5 +40,6 @@ skip-if = e10s
[test_bug1418629.html]
[test_bug1497480.html]
[test_bug1602526.html]
[test_spellcheck_after_edit.html]
[test_spellcheck_after_pressing_navigation_key.html]
[test_suggest.html]

View File

@ -0,0 +1,197 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Spellcheck result after edit</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<script>
let {onSpellCheck} =
SpecialPowers.Cu.import("resource://testing-common/AsyncSpellCheckTestHelper.jsm", {});
function waitForTick() {
return new Promise(resolve =>
SimpleTest.executeSoon(
() => requestAnimationFrame(
() => requestAnimationFrame(resolve)
)
)
);
}
async function waitForOnSpellCheck(
aSpellCheckSelection,
aEditingHost,
aWaitForNumberOfMisspelledWords,
aWhen
) {
info(`Waiting for onSpellCheck (${aWhen})...`);
for (let retry = 0; retry < 100; retry++) {
await waitForTick();
await new Promise(resolve => onSpellCheck(aEditingHost, resolve));
if (aWaitForNumberOfMisspelledWords === 0) {
if (aSpellCheckSelection.rangeCount === 0) {
break;
}
} else if (aSpellCheckSelection.rangeCount >= aWaitForNumberOfMisspelledWords) {
break;
}
}
}
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(async () => {
/**
* test object should have:
* init function
* @param normalSel The normal selection for the editing host
* @param editingHost The editing host of the editor
* @return Number of misspelled word in the editor
*
* run function
* @param editingHost The editing host of the editor
* @return Expected number of misspelled word in the editor
*
* check function
* @param spellCheckSel The spellcheck selection for the editing host
* @param editingHost The editing host of the editor
*/
for (const test of [
{
init: (normalSel, editingHost) => {
info("Staring to test spellcheck of misspelled word after joining paragraphs");
// eslint-disable-next-line no-unsanitized/property
editingHost.innerHTML = "<p>It is</p><p>what I want</p>";
normalSel.collapse(editingHost.querySelector("p + p").firstChild, 0);
return 0;
},
run: (editingHost) => {
document.execCommand("delete");
return 0;
},
check: (spellCheckSel, editingHost) => {
is(
spellCheckSel.rangeCount,
0,
"The joined misspelled word shouldn't be marked as misspelled word because caret is in the word"
);
},
},
{
init: (normalSel, editingHost) => {
info("Staring to test spellcheck of correct word after joining paragraphs");
// eslint-disable-next-line no-unsanitized/property
editingHost.innerHTML = "<p>It's beco</p><p>ming nicer</p>";
normalSel.collapse(editingHost.querySelector("p + p").firstChild, 0);
return 2;
},
run: (editingHost) => {
document.execCommand("delete");
return 0;
},
check: (spellCheckSel, editingHost) => {
is(
spellCheckSel.rangeCount,
0,
"There shouldn't be misspelled word after joining separated word anyway"
);
},
},
{
init: (normalSel, editingHost) => {
info("Staring to test spellcheck of correct words after splitting a paragraph");
// eslint-disable-next-line no-unsanitized/property
editingHost.innerHTML = "<p>It iswhat I want</p>";
normalSel.collapse(editingHost.querySelector("p").firstChild, "It is".length);
return 1;
},
run: (editingHost) => {
document.execCommand("insertParagraph");
return 0;
},
check: (spellCheckSel, editingHost) => {
is(
spellCheckSel.rangeCount,
0,
"No word should be marked as misspelled after split"
);
},
},
{
init: (normalSel, editingHost) => {
info("Staring to test spellcheck of misspelled words after splitting a paragraph");
// eslint-disable-next-line no-unsanitized/property
editingHost.innerHTML = "<p>It's becoming nicer</p>";
normalSel.collapse(editingHost.querySelector("p").firstChild, "It's beco".length);
return 0;
},
run: (editingHost) => {
document.execCommand("insertParagraph");
return 1;
},
check: (spellCheckSel, editingHost) => {
is(
spellCheckSel.rangeCount,
1,
"The split word in the first paragraph should be marked as misspelled, but the second paragraph's should be so because of caret is in it"
);
if (!spellCheckSel.rangeCount) {
return;
}
is(
SpecialPowers.unwrap(spellCheckSel.getRangeAt(0).startContainer),
editingHost.querySelector("p").firstChild,
"First misspelled word should start in the first child of the first <p>"
);
is(
SpecialPowers.unwrap(spellCheckSel.getRangeAt(0).endContainer),
editingHost.querySelector("p").firstChild,
"First misspelled word should end in the first child of the first <p>"
);
is(
spellCheckSel.getRangeAt(0).startOffset,
"It's ".length,
"First misspelled word should start after 'It '"
);
is(
spellCheckSel.getRangeAt(0).endOffset,
"It's beco".length,
"First misspelled word should end by after 'bec'"
);
},
},
]) {
const editingHost = document.createElement("div");
editingHost.setAttribute("contenteditable", "");
editingHost.setAttribute("spellcheck", "true");
document.body.appendChild(editingHost);
editingHost.focus();
const editor =
SpecialPowers.wrap(window).docShell.editingSession.getEditorForWindow(window);
const nsISelectionController = SpecialPowers.Ci.nsISelectionController;
const normalSel = editor.selectionController.getSelection(
nsISelectionController.SELECTION_NORMAL
);
const spellCheckSel = editor.selectionController.getSelection(
nsISelectionController.SELECTION_SPELLCHECK
);
const initialMisspelledWords = test.init(normalSel, editingHost);
await waitForOnSpellCheck(
spellCheckSel, editingHost, initialMisspelledWords, "before edit"
);
await waitForTick();
const expectedMisspelledWords = test.run(editingHost);
await waitForOnSpellCheck(
spellCheckSel, editingHost, expectedMisspelledWords, "after edit"
);
test.check(spellCheckSel, editingHost);
editingHost.remove();
await waitForTick();
}
SimpleTest.finish();
});
</script>
</body>
</html>

View File

@ -36,9 +36,11 @@
#include "mozilla/Attributes.h"
#include "mozilla/EditAction.h"
#include "mozilla/EditorBase.h"
#include "mozilla/EditorDOMPoint.h"
#include "mozilla/EditorSpellCheck.h"
#include "mozilla/EditorUtils.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/Logging.h"
#include "mozilla/RangeUtils.h"
#include "mozilla/Services.h"
@ -1012,22 +1014,6 @@ mozInlineSpellChecker::IgnoreWords(const nsTArray<nsString>& aWordsToIgnore) {
return ScheduleSpellCheck(std::move(status));
}
void mozInlineSpellChecker::DidSplitNode(nsINode* aExistingRightNode,
nsINode* aNewLeftNode) {
if (!mIsListeningToEditSubActions) {
return;
}
SpellCheckBetweenNodes(aNewLeftNode, 0, aNewLeftNode, 0);
}
void mozInlineSpellChecker::DidJoinNodes(nsINode& aLeftNode,
nsINode& aRightNode) {
if (!mIsListeningToEditSubActions) {
return;
}
SpellCheckBetweenNodes(&aRightNode, 0, &aRightNode, 0);
}
// mozInlineSpellChecker::MakeSpellCheckRange
//
// Given begin and end positions, this function constructs a range as

View File

@ -11,6 +11,7 @@
#include "nsIEditorSpellCheck.h"
#include "nsIInlineSpellChecker.h"
#include "mozInlineSpellWordUtil.h"
#include "mozilla/EditorDOMPoint.h"
#include "mozilla/Result.h"
#include "nsRange.h"
#include "nsWeakReference.h"
@ -24,6 +25,7 @@ namespace mozilla {
class EditorBase;
class EditorSpellCheck;
enum class EditSubAction : int32_t;
enum class JoinNodesDirection;
namespace dom {
class Event;
@ -283,11 +285,6 @@ class mozInlineSpellChecker final : public nsIInlineSpellChecker,
nsresult ResumeCheck(mozilla::UniquePtr<mozInlineSpellStatus>&& aStatus);
// Those methods are called when mEditorBase splits a node or joins the
// given nodes.
void DidSplitNode(nsINode* aExistingRightNode, nsINode* aNewLeftNode);
void DidJoinNodes(nsINode& aRightNode, nsINode& aLeftNode);
nsresult SpellCheckAfterEditorChange(mozilla::EditSubAction aEditSubAction,
mozilla::dom::Selection& aSelection,
nsINode* aPreviousSelectedNode,