Bug 1719110 - Add nsIEditorSpellCheck.suggest to get rid of PRemoteSpellcheckEngine.CheckAndSuggest. r=masayuki

When getting suggestions from spellchecker's result, we use sync IPC
(`PRemoteSpellcheckEngine.CheckAndSuggest`). This is used by showing context
menu only on Gecko. So I think that we can remove this IPC if we add async API
to get spellchecker suggestions.

And in comm-central's code, `CheckCurrentWord` and `GetSuggestedWord` seems to
use on spellchecker dialog (content/dialogs/EdSpellCheck.js in mail and suite)
that runs on parent process. So c-c won't use this IPC method.

So I would like to add the promise version of getting spellchecker's
suggestion.

Differential Revision: https://phabricator.services.mozilla.com/D119936
This commit is contained in:
Makoto Kato 2021-08-10 03:55:25 +00:00
Родитель ace90e9307
Коммит a6944a1428
9 изменённых файлов: 152 добавлений и 0 удалений

Просмотреть файл

@ -60,6 +60,13 @@ interface nsIEditorSpellCheck : nsISupports
*/
boolean CheckCurrentWord(in AString suggestedWord);
/**
* Check a given word then returns suggestion words via Promise if a given
* word is misspelled. If not misspelled, returns empty string array.
*/
[implicit_jscontext]
Promise suggest(in AString aCheckingWorkd, in unsigned long aMaxCount);
/**
* Use when modally checking the document to replace a word.
*

Просмотреть файл

@ -10,6 +10,7 @@
#include "mozilla/EditorBase.h" // for EditorBase
#include "mozilla/HTMLEditor.h" // for HTMLEditor
#include "mozilla/dom/Element.h" // for Element
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/dom/StaticRange.h"
#include "mozilla/intl/LocaleService.h" // for retrieving app locale
@ -448,6 +449,36 @@ EditorSpellCheck::CheckCurrentWord(const nsAString& aSuggestedWord,
&mSuggestedWordList);
}
NS_IMETHODIMP
EditorSpellCheck::Suggest(const nsAString& aSuggestedWord, uint32_t aCount,
JSContext* aCx, Promise** aPromise) {
NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(aCx);
if (NS_WARN_IF(!globalObject)) {
return NS_ERROR_UNEXPECTED;
}
ErrorResult result;
RefPtr<Promise> promise = Promise::Create(globalObject, result);
if (NS_WARN_IF(result.Failed())) {
return result.StealNSResult();
}
mSpellChecker->Suggest(aSuggestedWord, aCount)
->Then(
GetMainThreadSerialEventTarget(), __func__,
[promise](const CopyableTArray<nsString>& aSuggestions) {
promise->MaybeResolve(aSuggestions);
},
[promise](nsresult aError) {
promise->MaybeReject(NS_ERROR_FAILURE);
});
promise.forget(aPromise);
return NS_OK;
}
RefPtr<CheckWordPromise> EditorSpellCheck::CheckCurrentWordsNoSuggest(
const nsTArray<nsString>& aSuggestedWords) {
if (NS_WARN_IF(!mSpellChecker)) {

Просмотреть файл

@ -40,3 +40,4 @@ skip-if = e10s
[test_bug1418629.html]
[test_bug1497480.html]
[test_bug1602526.html]
[test_suggest.html]

Просмотреть файл

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<title>Test for nsIEditorSpellChecfker.sugget</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div contenteditable id="en-US" lang="en-US">missspelled</div>
<pre id="test">
<script class="testbody" type="text/javascript">
add_task(async function() {
await new Promise(resolve => SimpleTest.waitForFocus(resolve));
let { onSpellCheck } =
SpecialPowers.Cu.import(
"resource://testing-common/AsyncSpellCheckTestHelper.jsm", null);
let element = document.getElementById("en-US");
element.focus();
await new Promise(resolve => onSpellCheck(element, resolve));
let editingSession = SpecialPowers.wrap(window).docShell.editingSession;
let editor = editingSession.getEditorForWindow(window);
let spellchecker = SpecialPowers.Cu.createSpellChecker();
spellchecker.setFilterType(spellchecker.FILTERTYPE_NORMAL);
await new Promise(resolve => spellchecker.InitSpellChecker(editor, false, resolve));
let suggestions = await spellchecker.suggest("misspelled", 5);
is(suggestions.length, 0, "\"misspelled\" is correct word");
suggestions = await spellchecker.suggest("missspelled", 5);
is(suggestions.length, 5, "\"missspelled\" isn't correct word");
});
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -18,6 +18,8 @@ parent:
sync SetDictionary(nsCString aDictionary) returns (bool success);
async Suggest(nsString aWord, uint32_t aCount) returns (nsString[] aSuggestions);
/*
* Set current dictionary from list of dictionary name.
*

Просмотреть файл

@ -64,6 +64,23 @@ mozilla::ipc::IPCResult RemoteSpellcheckEngineParent::RecvCheckAndSuggest(
return IPC_OK();
}
mozilla::ipc::IPCResult RemoteSpellcheckEngineParent::RecvSuggest(
const nsString& aWord, uint32_t aCount, SuggestResolver&& aResolve) {
nsTArray<nsString> suggestions;
mSpellChecker->Suggest(aWord, aCount)
->Then(
GetMainThreadSerialEventTarget(), __func__,
[aResolve](CopyableTArray<nsString> aSuggestions) {
aResolve(std::move(aSuggestions));
},
[aResolve](nsresult aError) {
// No suggestions due to error
nsTArray<nsString> suggestions;
aResolve(std::move(suggestions));
});
return IPC_OK();
}
void RemoteSpellcheckEngineParent::ActorDestroy(ActorDestroyReason aWhy) {}
} // namespace mozilla

Просмотреть файл

@ -33,6 +33,10 @@ class RemoteSpellcheckEngineParent : public PRemoteSpellcheckEngineParent {
const nsString& aWord, bool* aIsMisspelled,
nsTArray<nsString>* aSuggestions);
virtual mozilla::ipc::IPCResult RecvSuggest(const nsString& aWord,
uint32_t aCount,
SuggestResolver&& aResolve);
private:
RefPtr<mozSpellChecker> mSpellChecker;
};

Просмотреть файл

@ -172,6 +172,46 @@ nsresult mozSpellChecker::CheckWord(const nsAString& aWord, bool* aIsMisspelled,
return NS_OK;
}
RefPtr<mozilla::SuggestionsPromise> mozSpellChecker::Suggest(
const nsAString& aWord, uint32_t aMaxCount) {
if (XRE_IsContentProcess()) {
return mEngine->SendSuggest(nsString(aWord), aMaxCount)
->Then(
mozilla::GetCurrentSerialEventTarget(), __func__,
[](nsTArray<nsString>&& aSuggestions) {
return mozilla::SuggestionsPromise::CreateAndResolve(
std::move(aSuggestions), __func__);
},
[](mozilla::ipc::ResponseRejectReason&& aReason) {
return mozilla::SuggestionsPromise::CreateAndReject(
NS_ERROR_NOT_AVAILABLE, __func__);
});
}
if (!mSpellCheckingEngine) {
return mozilla::SuggestionsPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE,
__func__);
}
bool correct;
nsresult rv = mSpellCheckingEngine->Check(aWord, &correct);
if (NS_FAILED(rv)) {
return mozilla::SuggestionsPromise::CreateAndReject(rv, __func__);
}
nsTArray<nsString> suggestions;
if (!correct) {
rv = mSpellCheckingEngine->Suggest(aWord, suggestions);
if (NS_FAILED(rv)) {
return mozilla::SuggestionsPromise::CreateAndReject(rv, __func__);
}
if (suggestions.Length() > aMaxCount) {
suggestions.TruncateLength(aMaxCount);
}
}
return mozilla::SuggestionsPromise::CreateAndResolve(std::move(suggestions),
__func__);
}
nsresult mozSpellChecker::Replace(const nsAString& aOldWord,
const nsAString& aNewWord,
bool aAllOccurrences) {

Просмотреть файл

@ -22,6 +22,8 @@ namespace mozilla {
class RemoteSpellcheckEngineChild;
class TextServicesDocument;
typedef MozPromise<CopyableTArray<bool>, nsresult, false> CheckWordPromise;
typedef MozPromise<CopyableTArray<nsString>, nsresult, false>
SuggestionsPromise;
} // namespace mozilla
class mozSpellChecker final {
@ -74,6 +76,12 @@ class mozSpellChecker final {
RefPtr<mozilla::CheckWordPromise> CheckWords(
const nsTArray<nsString>& aWords);
/*
* Checks if a word is misspelled, then get suggestion words if existed.
*/
RefPtr<mozilla::SuggestionsPromise> Suggest(const nsAString& aWord,
uint32_t aMaxCount);
/**
* Replaces the old word with the specified new word.
* @param aOldWord is the word to be replaced.