Bug 1837268, update inline spellchecker when text data is modified, r=masayuki
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Thu, 03 Aug 2023 09:25:44 +0000 (23 months ago)
changeset 674007 01837134e47e1685a64e399acb9ef435e1b3a65d
parent 674006 ebc036450b323fadbab0feb654346cf19d5720a2
child 674008 6f55c55c40c70eff3b82d3129f516257598ea115
push id41076
push userimoraru@mozilla.com
push dateThu, 03 Aug 2023 15:59:35 +0000 (23 months ago)
treeherdermozilla-central@6f55c55c40c7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmasayuki
bugs1837268, 1602526
milestone118.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1837268, update inline spellchecker when text data is modified, r=masayuki Using the test for bug 1602526 as the basis for the new test but tweaking it by adding the event listener used in the first testcase of the bug. Differential Revision: https://phabricator.services.mozilla.com/D184987
editor/libeditor/HTMLEditor.cpp
editor/libeditor/HTMLEditor.h
editor/spellchecker/tests/mochitest.ini
editor/spellchecker/tests/test_bug1837268.html
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -4542,16 +4542,34 @@ MOZ_CAN_RUN_SCRIPT_BOUNDARY void HTMLEdi
       return;
     }
     NS_WARNING_ASSERTION(
         NS_SUCCEEDED(rv),
         "HTMLEditor::OnDocumentModified() failed, but ignored");
   }
 }
 
+MOZ_CAN_RUN_SCRIPT_BOUNDARY void HTMLEditor::CharacterDataChanged(
+    nsIContent* aContent, const CharacterDataChangeInfo& aInfo) {
+  if (!mInlineSpellChecker || !aContent->IsEditable() ||
+      !IsInObservedSubtree(aContent) ||
+      GetTopLevelEditSubAction() != EditSubAction::eNone) {
+    return;
+  }
+
+  nsIContent* parent = aContent->GetParent();
+  if (!parent || !parent->InclusiveDescendantMayNeedSpellchecking(this)) {
+    return;
+  }
+
+  RefPtr<nsRange> range = nsRange::Create(aContent);
+  range->SelectNodesInContainer(parent, aContent, aContent);
+  DebugOnly<nsresult> rvIgnored = mInlineSpellChecker->SpellCheckRange(range);
+}
+
 nsresult HTMLEditor::SelectEntireDocument() {
   MOZ_ASSERT(IsEditActionDataAvailable());
 
   if (!mInitSucceeded) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   // XXX It's odd to select all of the document body if an contenteditable
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -97,16 +97,17 @@ class HTMLEditor final : public EditorBa
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLEditor, EditorBase)
 
   // nsStubMutationObserver overrides
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
+  NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
 
   // nsIHTMLEditor methods
   NS_DECL_NSIHTMLEDITOR
 
   // nsIHTMLObjectResizer methods (implemented in HTMLObjectResizer.cpp)
   NS_DECL_NSIHTMLOBJECTRESIZER
 
   // nsIHTMLAbsPosEditor methods (implemented in HTMLAbsPositionEditor.cpp)
--- a/editor/spellchecker/tests/mochitest.ini
+++ b/editor/spellchecker/tests/mochitest.ini
@@ -37,16 +37,17 @@ skip-if = true
 [test_bug1365383.html]
 [test_bug1368544.html]
 [test_bug1402822.html]
 [test_bug1418629.html]
 [test_bug1497480.html]
 [test_bug1602526.html]
 [test_bug1761273.html]
 [test_bug1773802.html]
+[test_bug1837268.html]
 [test_bug366682.html]
 [test_bug432225.html]
 [test_bug484181.html]
 [test_bug596333.html]
 [test_bug636465.html]
 [test_bug678842.html]
 skip-if =
   http3
new file mode 100644
--- /dev/null
+++ b/editor/spellchecker/tests/test_bug1837268.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Mozilla bug 1837268</title>
+  <link rel=stylesheet href="/tests/SimpleTest/test.css">
+  <script src="/tests/SimpleTest/EventUtils.js"></script>
+  <script src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script src="/tests/editor/spellchecker/tests/spellcheck.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1837268">Mozilla Bug 1837268</a>
+<p id="display"></p>
+<div id="content" style="display: none;">
+
+</div>
+
+<div id="contenteditable" contenteditable=true>aabbcc</div>
+
+<script>
+const { maybeOnSpellCheck } = SpecialPowers.ChromeUtils.importESModule(
+  "resource://testing-common/AsyncSpellCheckTestHelper.sys.mjs"
+);
+
+SimpleTest.waitForExplicitFinish();
+
+function getEditor() {
+  return SpecialPowers.wrap(window).docShell.editor;
+}
+
+SimpleTest.waitForFocus(async () => {
+  let contenteditable = document.getElementById("contenteditable");
+  contenteditable.addEventListener("beforeinput", (ev) => {
+    ev.preventDefault();
+    let text = contenteditable.textContent;
+    const sel = window.getSelection();
+    let offset = sel.anchorOffset;
+    switch (ev.inputType) {
+      case "insertText":
+        text = text.substring(0, offset) + ev.data + text.substring(offset);
+        offset += 1;
+        break;
+      case "deleteContentBackward":
+        text = text.substring(0, offset - 1) + text.substring(offset);
+        offset -= 1;
+        break;
+      default:
+        return;
+    }
+    if (contenteditable.firstChild) {
+      contenteditable.firstChild.nodeValue = text;
+    } else {
+      contenteditable.textContent = text;
+    }
+    sel.collapse(contenteditable.firstChild ?? contenteditable, offset);
+  });
+
+  let misspelledWords = [];
+  misspelledWords.push("aabbc"); // One c removed.
+
+  contenteditable.focus();
+  window.getSelection().collapse(contenteditable.firstChild, contenteditable.firstChild.length);
+
+  // Run spell checker
+  await new Promise((resolve) => { maybeOnSpellCheck(contenteditable, resolve); });
+
+  synthesizeKey("KEY_Backspace");
+  synthesizeKey(" ");
+
+  await new Promise((resolve) => { maybeOnSpellCheck(contenteditable, resolve); });
+  let editor = getEditor();
+  // isSpellingCheckOk is defined in spellcheck.js
+  // eslint-disable-next-line no-undef
+  ok(isSpellingCheckOk(editor, misspelledWords), "correct word is selected as misspelled");
+
+  SimpleTest.finish();
+});
+</script>
+</body>
+</html>