Bug 1418629 - Single quotation mark shouldn't always separator. r=Ehsan
authorMakoto Kato <m_kato@ga2.so-net.ne.jp>
Wed, 08 May 2019 09:36:05 +0000
changeset 531855 5822c9d23ff717f637b5cd9c2c24a8e2d223fcb8
parent 531854 80c8ca102b81ddccf720129381d8669b88f61a17
child 531856 2bea789487b771c178585c365496b61d51fbaa6e
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersEhsan
bugs1418629, 1362858, 1462858
milestone68.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 1418629 - Single quotation mark shouldn't always separator. r=Ehsan This seems to be regression by bug 1362858. Actually, single quotation mark is always separator for spellchecker after landing bug 1462858. When user tries to input "doesn't", "'" becomes separator for spellchecker. Then "doesn" will be misspell word. So we shouldn't mark single quotation mark as separator if user is inputting word. Differential Revision: https://phabricator.services.mozilla.com/D29153
editor/spellchecker/tests/mochitest.ini
editor/spellchecker/tests/test_bug1418629.html
extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
--- a/editor/spellchecker/tests/mochitest.ini
+++ b/editor/spellchecker/tests/mochitest.ini
@@ -7,20 +7,22 @@ support-files =
   bug1204147_subframe.html
   bug1204147_subframe2.html
   en-GB/en_GB.dic
   en-GB/en_GB.aff
   en-AU/en_AU.dic
   en-AU/en_AU.aff
   de-DE/de_DE.dic
   de-DE/de_DE.aff
+  !/editor/libeditor/tests/spellcheck.js
 
 [test_async_UpdateCurrentDictionary.html]
 [test_bug678842.html]
 [test_bug697981.html]
 [test_bug717433.html]
 [test_bug1200533.html]
 [test_bug1204147.html]
 [test_bug1205983.html]
 [test_bug1209414.html]
 [test_bug1219928.html]
 skip-if = e10s
 [test_bug1365383.html]
+[test_bug1418629.html]
new file mode 100644
--- /dev/null
+++ b/editor/spellchecker/tests/test_bug1418629.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Mozilla bug 1418629</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/SimpleTest/AddTask.js"></script>
+  <script src="/tests/editor/libeditor/tests/spellcheck.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1418629">Mozilla Bug 1418629</a>
+<p id="display"></p>
+<div id="content" style="display: none;">
+
+</div>
+
+<input id="input1" autofocus spellcheck="true">
+
+<script>
+const {onSpellCheck} = SpecialPowers.Cu.import("resource://testing-common/AsyncSpellCheckTestHelper.jsm", {});
+
+SimpleTest.waitForExplicitFinish();
+
+add_task(async function() {
+  await new Promise((resolve) => {
+    SimpleTest.waitForFocus(() => {
+      SimpleTest.executeSoon(resolve);
+    }, window);
+  });
+
+  let misspeltWords = [];
+  let input = document.getElementById("input1");
+
+  input.focus();
+  input.value = "";
+  synthesizeKey("d");
+  synthesizeKey("o");
+  synthesizeKey("e");
+  synthesizeKey("s");
+
+  await new Promise((resolve) => { onSpellCheck(input, resolve); });
+  // isSpellingCheckOk is defined in spellcheck.js
+  // eslint-disable-next-line no-undef
+  ok(isSpellingCheckOk(SpecialPowers.wrap(input).editor, misspeltWords),
+     "no misspelt words");
+
+  synthesizeKey("n");
+  synthesizeKey("\'");
+  is(input.value, "doesn\'", "");
+
+  await new Promise((resolve) => { onSpellCheck(input, resolve); });
+  // isSpellingCheckOk is defined in spellcheck.js
+  // eslint-disable-next-line no-undef
+  ok(isSpellingCheckOk(SpecialPowers.wrap(input).editor, misspeltWords),
+     "don't run spellchecker during inputting word");
+
+  synthesizeKey(" ");
+  is(input.value, "doesn\' ", "");
+
+  await new Promise((resolve) => { onSpellCheck(input, resolve); });
+  misspeltWords.push("doesn\'");
+  // isSpellingCheckOk is defined in spellcheck.js
+  // eslint-disable-next-line no-undef
+  ok(isSpellingCheckOk(SpecialPowers.wrap(input).editor, misspeltWords),
+     "should run spellchecker");
+});
+
+async function test_with_twice_characters(ch) {
+  let misspeltWords = [];
+  let input = document.getElementById("input1");
+
+  input.focus();
+  input.value = "";
+  synthesizeKey("d");
+  synthesizeKey("o");
+  synthesizeKey("e");
+  synthesizeKey("s");
+  synthesizeKey("n");
+  synthesizeKey(ch);
+  synthesizeKey(ch);
+  is(input.value, "doesn" + ch + ch, "");
+
+  await new Promise((resolve) => { onSpellCheck(input, resolve); });
+  misspeltWords.push("doesn");
+  // isSpellingCheckOk is defined in spellcheck.js
+  // eslint-disable-next-line no-undef
+  ok(isSpellingCheckOk(SpecialPowers.wrap(input).editor, misspeltWords),
+     "should run spellchecker");
+}
+
+add_task(test_with_twice_characters.bind(null, "\'"));
+add_task(test_with_twice_characters.bind(null, String.fromCharCode(0x2019)));
+</script>
+</body>
+</html>
--- a/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
@@ -413,18 +413,29 @@ CharClass WordSplitState::ClassifyCharac
     if (aIndex == 0) return CHAR_CLASS_SEPARATOR;
     if (ClassifyCharacter(aIndex - 1, false) != CHAR_CLASS_WORD)
       return CHAR_CLASS_SEPARATOR;
     // If the previous charatcer is a word-char, make sure that it's not a
     // special dot character.
     if (mDOMWordText[aIndex - 1] == '.') return CHAR_CLASS_SEPARATOR;
 
     // now we know left char is a word-char, check the right-hand character
-    if (aIndex == int32_t(mDOMWordText.Length()) - 1)
+    if (aIndex == int32_t(mDOMWordText.Length() - 1)) {
+      if (mDOMWordText[aIndex] == '\'' || mDOMWordText[aIndex] == 0x2019) {
+        nsUGenCategory prevCategory =
+            mozilla::unicode::GetGenCategory(mDOMWordText[aIndex - 1]);
+        if (prevCategory == nsUGenCategory::kLetter ||
+            prevCategory == nsUGenCategory::kNumber) {
+          // If single quotation mark is last, we don't return separator yet.
+          return CHAR_CLASS_WORD;
+        }
+      }
       return CHAR_CLASS_SEPARATOR;
+    }
+
     if (ClassifyCharacter(aIndex + 1, false) != CHAR_CLASS_WORD)
       return CHAR_CLASS_SEPARATOR;
     // If the next charatcer is a word-char, make sure that it's not a
     // special dot character.
     if (mDOMWordText[aIndex + 1] == '.') return CHAR_CLASS_SEPARATOR;
 
     // char on either side is a word, this counts as a word
     return CHAR_CLASS_WORD;