From aa4734b714baee2546d0519058f42c7c8b9ef080 Mon Sep 17 00:00:00 2001 From: Michael Bragg Date: Tue, 18 Mar 2025 12:08:47 -0400 Subject: [PATCH] alloy: win: Add spelling suggestions in context menu (fixes #3055) --- libcef/browser/menu_manager.cc | 43 ++++++++++++++++++++++++++++++++-- libcef/browser/menu_manager.h | 13 +++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/libcef/browser/menu_manager.cc b/libcef/browser/menu_manager.cc index f4e65137a..e6413862b 100644 --- a/libcef/browser/menu_manager.cc +++ b/libcef/browser/menu_manager.cc @@ -20,6 +20,12 @@ #include "content/public/browser/render_widget_host_view.h" #include "third_party/blink/public/mojom/context_menu/context_menu.mojom.h" +#if BUILDFLAG(IS_WIN) +#include "chrome/browser/spellchecker/spellcheck_factory.h" +#include "chrome/browser/spellchecker/spellcheck_service.h" +#include "components/spellcheck/browser/spellcheck_platform.h" +#endif + namespace { CefString GetLabel(int message_id) { @@ -120,8 +126,8 @@ bool CefMenuManager::IsShowingContextMenu() { return web_contents()->IsShowingContextMenu(); } -bool CefMenuManager::CreateContextMenu( - const content::ContextMenuParams& params) { +bool CefMenuManager::CreateContextMenu(const content::ContextMenuParams& params, + bool query_spellcheck) { // The renderer may send the "show context menu" message multiple times, one // for each right click mouse event it receives. Normally, this doesn't happen // because mouse events are not forwarded once the context menu is showing. @@ -134,6 +140,24 @@ bool CefMenuManager::CreateContextMenu( } params_ = params; + +#if BUILDFLAG(IS_WIN) + // System spellcheck suggestions need to be queried asynchronously. + if (query_spellcheck && !params_.misspelled_word.empty() && + params_.dictionary_suggestions.empty()) { + SpellcheckService* spellcheck_service = + SpellcheckServiceFactory::GetForContext( + browser_->web_contents()->GetBrowserContext()); + if (spellcheck_service) { + spellcheck_platform::GetPerLanguageSuggestions( + spellcheck_service->platform_spell_checker(), params_.misspelled_word, + base::BindOnce(&CefMenuManager::OnGetPlatformSuggestionsComplete, + weak_ptr_factory_.GetWeakPtr())); + } + return true; + } +#endif + model_->Clear(); // Create the default menu model. @@ -511,3 +535,18 @@ bool CefMenuManager::IsCustomContextMenuCommand(int command_id) { } return false; } + +#if BUILDFLAG(IS_WIN) +void CefMenuManager::OnGetPlatformSuggestionsComplete( + const spellcheck::PerLanguageSuggestions& + platform_per_language_suggestions) { + std::vector combined_suggestions; + spellcheck::FillSuggestions(platform_per_language_suggestions, + &combined_suggestions); + + params_.dictionary_suggestions = combined_suggestions; + + // Now that we have spelling suggestions, call CreateContextMenu again. + CreateContextMenu(params_, /*query_spellcheck=*/false); +} +#endif diff --git a/libcef/browser/menu_manager.h b/libcef/browser/menu_manager.h index e49234147..3479d4923 100644 --- a/libcef/browser/menu_manager.h +++ b/libcef/browser/menu_manager.h @@ -13,6 +13,10 @@ #include "content/public/browser/context_menu_params.h" #include "content/public/browser/web_contents_observer.h" +#if BUILDFLAG(IS_WIN) +#include "components/spellcheck/common/spellcheck_common.h" +#endif + namespace content { class RenderFrameHost; class WebContents; @@ -39,7 +43,8 @@ class CefMenuManager : public CefMenuModelImpl::Delegate, bool IsShowingContextMenu(); // Create the context menu. - bool CreateContextMenu(const content::ContextMenuParams& params); + bool CreateContextMenu(const content::ContextMenuParams& params, + bool query_spellcheck = true); void CancelContextMenu(); private: @@ -62,6 +67,12 @@ class CefMenuManager : public CefMenuModelImpl::Delegate, // Returns true if the specified id is a custom context menu command. bool IsCustomContextMenuCommand(int command_id); +#if BUILDFLAG(IS_WIN) + void OnGetPlatformSuggestionsComplete( + const spellcheck::PerLanguageSuggestions& + platform_per_language_suggestions); +#endif + // AlloyBrowserHostImpl pointer is guaranteed to outlive this object. raw_ptr browser_;