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

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

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

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

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

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

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

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

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

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

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

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

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

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

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