Bug 1719110 - Don't use sync IPC to show suggestion by spellchecker. r=Gijs

CheckCurrentWord on content process causes sync IPC, so I would like to remove
this call on content process. New nsIEditorSpellChecker.suggest method can
avoid it.

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

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

@ -507,7 +507,7 @@ class ContextMenuChild extends JSWindowActorChild {
return false;
}
handleEvent(aEvent) {
async handleEvent(aEvent) {
contextMenus.set(this.browsingContext, this);
let defaultPrevented = aEvent.defaultPrevented;
@ -645,7 +645,6 @@ class ContextMenuChild extends JSWindowActorChild {
referrerInfo,
editFlags,
principal,
spellInfo,
contentType,
docLocation,
loginFillInfo,
@ -692,6 +691,15 @@ class ContextMenuChild extends JSWindowActorChild {
// instead.
aEvent.stopPropagation();
data.spellInfo = null;
if (!spellInfo) {
this.sendAsyncMessage("contextmenu", data);
return;
}
try {
data.spellInfo = await spellInfo;
} catch (ex) {}
this.sendAsyncMessage("contextmenu", data);
}

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

@ -284,6 +284,10 @@ class nsContextMenu {
);
}
if (this.contentData.spellInfo) {
this.spellSuggesions = this.contentData.spellInfo.spellSuggestions;
}
if (context.shouldInitInlineSpellCheckerUIWithChildren) {
InlineSpellCheckerUI.initFromRemote(
this.contentData.spellInfo,
@ -769,7 +773,7 @@ class nsContextMenu {
var numsug = InlineSpellCheckerUI.addSuggestionsToMenu(
suggestionsSeparator.parentNode,
suggestionsSeparator,
5
this.spellSuggesions
);
this.showItem("spell-no-suggestions", numsug == 0);
} else {

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

@ -35,13 +35,22 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1272623
// Perform the spelling correction
let mm = SpecialPowers.loadChromeScript(function() {
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const {BrowserTestUtils} = ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
// Chrome scripts are run with synchronous messages, so make sure we're completely
// decoupled from the content process before doing this work.
Cu.dispatch(function() {
Cu.dispatch(async function() {
let chromeWin = Services.ww.activeWindow;
let contextMenu = chromeWin.document.getElementById("contentAreaContextMenu");
let suggestion = contextMenu.querySelector(".spell-suggestion");
if (!suggestion) {
await BrowserTestUtils.waitForMutationCondition(
contextMenu,
{ childList: true },
() => contextMenu.querySelector(".spell-suggestion")
);
suggestion = contextMenu.querySelector(".spell-suggestion");
}
suggestion.doCommand();
contextMenu.hidePopup();
sendAsyncMessage("spellingCorrected");

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

@ -22,7 +22,7 @@ class InlineSpellCheckerChild extends JSWindowActorChild {
break;
case "InlineSpellChecker:replaceMisspelling":
InlineSpellCheckerContent.replaceMisspelling(msg.data.index);
InlineSpellCheckerContent.replaceMisspelling(msg.data.suggestion);
break;
case "InlineSpellChecker:toggleEnabled":

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

@ -15,8 +15,10 @@ class InlineSpellCheckerParent extends JSWindowActorParent {
});
}
replaceMisspelling({ index }) {
this.sendAsyncMessage("InlineSpellChecker:replaceMisspelling", { index });
replaceMisspelling({ suggestion }) {
this.sendAsyncMessage("InlineSpellChecker:replaceMisspelling", {
suggestion,
});
}
toggleEnabled() {

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

@ -144,7 +144,7 @@
// suggestion list
var suggestionsSeparator = this.getMenuItem("spell-no-suggestions");
var numsug = spellui.addSuggestionsToMenu(
var numsug = spellui.addSuggestionsToMenuOnParent(
event.target,
suggestionsSeparator,
5

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

@ -62,7 +62,6 @@ InlineSpellChecker.prototype = {
this.mOverMisspelling = false;
this.mMisspelling = "";
this.mMenu = null;
this.mSpellSuggestions = [];
this.mSuggestionItems = [];
this.mDictionaryMenu = null;
this.mDictionaryItems = [];
@ -144,7 +143,40 @@ InlineSpellChecker.prototype = {
// this prepends up to "maxNumber" suggestions at the given menu position
// for the word under the cursor. Returns the number of suggestions inserted.
addSuggestionsToMenu(menu, insertBefore, maxNumber) {
addSuggestionsToMenuOnParent(menu, insertBefore, maxNumber) {
if (this.mRemote) {
// This is used on parent process only.
// If you want to add suggestions to context menu, get suggestions then
// use addSuggestionsToMenu instead.
return 0;
}
if (!this.mInlineSpellChecker || !this.mOverMisspelling) {
return 0;
}
let spellchecker = this.mInlineSpellChecker.spellChecker;
let spellSuggestions = [];
try {
if (!spellchecker.CheckCurrentWord(this.mMisspelling)) {
return 0;
}
for (let i = 0; i < maxNumber; i++) {
let suggestion = spellchecker.GetSuggestedWord();
if (!suggestion.length) {
// no more data
break;
}
spellSuggestions.push(suggestion);
}
} catch (e) {
return 0;
}
return this._addSuggestionsToMenu(menu, insertBefore, spellSuggestions);
},
addSuggestionsToMenu(menu, insertBefore, spellSuggestions) {
if (
!this.mRemote &&
(!this.mInlineSpellChecker || !this.mOverMisspelling)
@ -152,41 +184,31 @@ InlineSpellChecker.prototype = {
return 0;
} // nothing to do
var spellchecker = this.mRemote || this.mInlineSpellChecker.spellChecker;
try {
if (!this.mRemote && !spellchecker.CheckCurrentWord(this.mMisspelling)) {
return 0;
} // word seems not misspelled after all (?)
} catch (e) {
if (!spellSuggestions?.length) {
return 0;
}
return this._addSuggestionsToMenu(menu, insertBefore, spellSuggestions);
},
_addSuggestionsToMenu(menu, insertBefore, spellSuggestions) {
this.mMenu = menu;
this.mSpellSuggestions = [];
this.mSuggestionItems = [];
for (var i = 0; i < maxNumber; i++) {
var suggestion = spellchecker.GetSuggestedWord();
if (!suggestion.length) {
break;
}
this.mSpellSuggestions.push(suggestion);
for (let suggestion of spellSuggestions) {
var item = menu.ownerDocument.createXULElement("menuitem");
this.mSuggestionItems.push(item);
item.setAttribute("label", suggestion);
item.setAttribute("value", suggestion);
// this function thing is necessary to generate a callback with the
// correct binding of "val" (the index in this loop).
var callback = function(me, val) {
return function(evt) {
me.replaceMisspelling(val);
};
};
item.addEventListener("command", callback(this, i), true);
item.addEventListener(
"command",
this.replaceMisspelling.bind(this, suggestion),
true
);
item.setAttribute("class", "spell-suggestion");
menu.insertBefore(item, insertBefore);
}
return this.mSpellSuggestions.length;
return spellSuggestions.length;
},
// undoes the work of addSuggestionsToMenu for the same menu
@ -301,21 +323,18 @@ InlineSpellChecker.prototype = {
},
// callback for selecting a suggested replacement
replaceMisspelling(index) {
replaceMisspelling(suggestion) {
if (this.mRemote) {
this.mRemote.replaceMisspelling(index);
this.mRemote.replaceMisspelling(suggestion);
return;
}
if (!this.mInlineSpellChecker || !this.mOverMisspelling) {
return;
}
if (index < 0 || index >= this.mSpellSuggestions.length) {
return;
}
this.mInlineSpellChecker.replaceWord(
this.mWordNode,
this.mWordOffset,
this.mSpellSuggestions[index]
suggestion
);
},
@ -514,22 +533,8 @@ RemoteSpellChecker.prototype = {
get enableRealTimeSpell() {
return this._spellInfo.enableRealTimeSpell;
},
GetSuggestedWord() {
if (!this._suggestionGenerator) {
this._suggestionGenerator = (function*(spellInfo) {
for (let i of spellInfo.spellSuggestions) {
yield i;
}
})(this._spellInfo);
}
let next = this._suggestionGenerator.next();
if (next.done) {
this._suggestionGenerator = null;
return "";
}
return next.value;
get suggestions() {
return this._spellInfo.spellSuggestions;
},
get currentDictionary() {
@ -543,8 +548,8 @@ RemoteSpellChecker.prototype = {
this._actor.selectDictionary({ localeCode });
},
replaceMisspelling(index) {
this._actor.replaceMisspelling({ index });
replaceMisspelling(suggestion) {
this._actor.replaceMisspelling({ suggestion });
},
toggleEnabled() {

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

@ -15,7 +15,7 @@ var InlineSpellCheckerContent = {
_spellChecker: null,
_actor: null,
initContextMenu(event, editFlags, actor) {
async initContextMenu(event, editFlags, actor) {
this._actor = actor;
this._actor.registerDestructionObserver(this);
@ -62,6 +62,7 @@ var InlineSpellCheckerContent = {
let realSpellChecker = spellChecker.mInlineSpellChecker.spellChecker;
let dictionaryList = realSpellChecker.GetDictionaryList();
let spellSuggestions = await this._generateSpellSuggestions();
return {
canSpellCheck: spellChecker.canSpellCheck,
@ -69,7 +70,7 @@ var InlineSpellCheckerContent = {
enableRealTimeSpell: spellChecker.enabled,
overMisspelling: spellChecker.overMisspelling,
misspelling: spellChecker.mMisspelling,
spellSuggestions: this._generateSpellSuggestions(),
spellSuggestions,
currentDictionary: spellChecker.mInlineSpellChecker.spellChecker.GetCurrentDictionary(),
dictionaryList,
};
@ -87,24 +88,18 @@ var InlineSpellCheckerContent = {
this.uninitContextMenu();
},
_generateSpellSuggestions() {
async _generateSpellSuggestions() {
let spellChecker = this._spellChecker.mInlineSpellChecker.spellChecker;
let suggestions = null;
try {
spellChecker.CheckCurrentWord(this._spellChecker.mMisspelling);
suggestions = await spellChecker.suggest(
this._spellChecker.mMisspelling,
5
);
} catch (e) {
return [];
}
let suggestions = new Array(5);
for (let i = 0; i < 5; ++i) {
suggestions[i] = spellChecker.GetSuggestedWord();
if (suggestions[i].length === 0) {
suggestions.length = i;
break;
}
}
this._spellChecker.mSpellSuggestions = suggestions;
return suggestions;
},
@ -112,8 +107,8 @@ var InlineSpellCheckerContent = {
this._spellChecker.selectDictionary(localeCode);
},
replaceMisspelling(index) {
this._spellChecker.replaceMisspelling(index);
replaceMisspelling(suggestion) {
this._spellChecker.replaceMisspelling(suggestion);
},
toggleEnabled() {