From 4713387c052d54e0f5ea02efaeaa25931d1cd7ee Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Thu, 8 Oct 2015 23:49:26 +0200 Subject: Add spell checker support Integrate chromium spell checker: * add spellchecker and dependencies to build * underline misspelled words in html text areas * right-click context menu shows up to 4 options to correct the misspelled word * toggle spell check from context menu * add new qml and widget api calls to qwebengineprofile to enable/disable spell check, select spell check language, get list of supported languages/dictionaries * register new qml spell check properties for QtWebEngine 1.3 * CONFIG+="no_spellcheck" to remove spellcheck support Change-Id: Ie61434ab9493597d7759a6f33794f6859c4e3a4c Reviewed-by: Allan Sandfeld Jensen --- src/core/browser_context_adapter.cpp | 27 ++++++ src/core/browser_context_adapter.h | 7 ++ src/core/browser_context_qt.cpp | 79 ++++++++++++++++++ src/core/browser_context_qt.h | 20 +++++ src/core/chrome_qt.gyp | 95 +++++++++++++++++++++- src/core/config/embedded_linux.pri | 1 - src/core/config/linux.pri | 3 + src/core/config/mac_osx.pri | 3 + src/core/config/windows.pri | 3 + src/core/content_browser_client_qt.cpp | 11 ++- src/core/content_main_delegate_qt.cpp | 4 +- src/core/renderer/content_renderer_client_qt.cpp | 11 +++ src/core/renderer/content_renderer_client_qt.h | 5 ++ src/core/type_conversion.h | 11 +++ src/core/web_contents_adapter.cpp | 13 +++ src/core/web_contents_adapter.h | 4 + src/core/web_contents_adapter_client.h | 13 ++- src/core/web_contents_view_qt.cpp | 17 +++- src/core/web_engine_library_info.cpp | 30 +++++++ src/webengine/api/qquickwebengineprofile.cpp | 90 ++++++++++++++++++++ src/webengine/api/qquickwebengineprofile.h | 17 ++++ src/webengine/api/qquickwebengineview.cpp | 37 ++++++++- src/webengine/api/qquickwebengineview_p.h | 8 +- src/webengine/plugin/plugin.cpp | 1 + src/webengine/ui_delegates_manager.cpp | 5 +- src/webengine/ui_delegates_manager.h | 3 +- src/webengine/webengine.pro | 7 ++ src/webenginewidgets/api/qwebenginepage.cpp | 38 +++++++++ src/webenginewidgets/api/qwebenginepage.h | 8 +- src/webenginewidgets/api/qwebengineprofile.cpp | 64 +++++++++++++++ src/webenginewidgets/api/qwebengineprofile.h | 8 ++ .../doc/src/qwebenginepage_lgpl.qdoc | 5 ++ src/webenginewidgets/webenginewidgets.pro | 7 ++ 33 files changed, 640 insertions(+), 15 deletions(-) diff --git a/src/core/browser_context_adapter.cpp b/src/core/browser_context_adapter.cpp index 0b9c4f3f2..94770f0bb 100644 --- a/src/core/browser_context_adapter.cpp +++ b/src/core/browser_context_adapter.cpp @@ -431,4 +431,31 @@ void BrowserContextAdapter::clearHttpCache() m_browserContext->url_request_getter_->clearHttpCache(); } +#if defined(ENABLE_SPELLCHECK) +QStringList BrowserContextAdapter::spellCheckLanguages(const QStringList &acceptLanguages) +{ + return m_browserContext->spellCheckLanguages(acceptLanguages); +} + +void BrowserContextAdapter::setSpellCheckLanguage(const QString &language) +{ + m_browserContext->setSpellCheckLanguage(language); +} + +QString BrowserContextAdapter::spellCheckLanguage() const +{ + return m_browserContext->spellCheckLanguage(); +} + +void BrowserContextAdapter::setSpellCheckEnabled(bool enabled) +{ + m_browserContext->setSpellCheckEnabled(enabled); +} + +bool BrowserContextAdapter::isSpellCheckEnabled() const +{ + return m_browserContext->isSpellCheckEnabled(); +} +#endif + } // namespace QtWebEngineCore diff --git a/src/core/browser_context_adapter.h b/src/core/browser_context_adapter.h index 393107940..8eb7631f7 100644 --- a/src/core/browser_context_adapter.h +++ b/src/core/browser_context_adapter.h @@ -107,6 +107,13 @@ public: QString httpUserAgent() const; void setHttpUserAgent(const QString &userAgent); +#if defined(ENABLE_SPELLCHECK) + QStringList spellCheckLanguages(const QStringList &acceptLanguages); + void setSpellCheckLanguage(const QString &language); + QString spellCheckLanguage() const; + void setSpellCheckEnabled(bool enabled); + bool isSpellCheckEnabled() const; +#endif // KEEP IN SYNC with API or add mapping layer enum HttpCacheType { MemoryHttpCache = 0, diff --git a/src/core/browser_context_qt.cpp b/src/core/browser_context_qt.cpp index 15c73180b..ca772c169 100644 --- a/src/core/browser_context_qt.cpp +++ b/src/core/browser_context_qt.cpp @@ -52,12 +52,49 @@ #include "content/public/browser/storage_partition.h" #include "net/proxy/proxy_config_service.h" +#if defined(ENABLE_SPELLCHECK) +#include "base/prefs/pref_member.h" +#include "base/prefs/pref_service.h" +#include "base/prefs/testing_pref_store.h" +#include "base/prefs/pref_service.h" +#include "base/prefs/pref_service_factory.h" +#include "base/prefs/pref_registry_simple.h" +#include "components/user_prefs/user_prefs.h" +#include "chrome/common/pref_names.h" +#include "chrome/browser/spellchecker/spellcheck_service.h" +#endif + namespace QtWebEngineCore { +#if defined(ENABLE_SPELLCHECK) +BrowserContextQt::BrowserContextQt(BrowserContextAdapter *adapter) + : m_adapter(adapter), + m_prefStore(new TestingPrefStore()) +{ + m_prefStore->SetInitializationCompleted(); + base::PrefServiceFactory factory; + factory.set_user_prefs(m_prefStore); + scoped_refptr registry(new PrefRegistrySimple()); + + // Initial spellcheck settings + std::string spellcheckLang("en-US"); + base::ListValue *dictionaries = new base::ListValue; + dictionaries->AppendString(spellcheckLang); + registry->RegisterListPref(prefs::kSpellCheckDictionaries, dictionaries); + registry->RegisterStringPref(prefs::kAcceptLanguages, spellcheckLang); + registry->RegisterStringPref(prefs::kSpellCheckDictionary, spellcheckLang); + registry->RegisterBooleanPref(prefs::kSpellCheckUseSpellingService, false); + registry->RegisterBooleanPref(prefs::kEnableContinuousSpellcheck, false); + registry->RegisterBooleanPref(prefs::kEnableAutoSpellCorrect, false); + m_prefService = factory.Create(registry.get()).Pass(); + user_prefs::UserPrefs::Set(this, m_prefService.get()); +} +#else BrowserContextQt::BrowserContextQt(BrowserContextAdapter *adapter) : m_adapter(adapter) { } +#endif //ENABLE_SPELLCHECK BrowserContextQt::~BrowserContextQt() { @@ -156,4 +193,46 @@ net::URLRequestContextGetter *BrowserContextQt::CreateRequestContext(content::Pr return url_request_getter_.get(); } + +#if defined(ENABLE_SPELLCHECK) +QStringList BrowserContextQt::spellCheckLanguages(const QStringList& acceptedLanguages) +{ + QStringList result; +#if !defined(OS_MACOSX) // no SpellcheckService::GetSpellCheckLanguages + m_prefService->SetString(prefs::kAcceptLanguages,acceptedLanguages.join(",").toStdString()); + + std::vector vec; + SpellcheckService::GetSpellCheckLanguages(this, &vec); + + for (std::vector::iterator it = vec.begin(); it != vec.end(); ++it) { + result << QString::fromStdString(*it); + } +#endif + return result; +} + +void BrowserContextQt::setSpellCheckLanguage(const QString &language) +{ + base::ListValue dictionaries; + dictionaries.AppendString(language.toStdString()); + m_prefService->Set(prefs::kSpellCheckDictionaries, dictionaries); +} + +QString BrowserContextQt::spellCheckLanguage() const +{ + std::string dictionary; + m_prefService->GetList(prefs::kSpellCheckDictionaries)->GetString(0, &dictionary); + return QString::fromStdString(dictionary); +} + +void BrowserContextQt::setSpellCheckEnabled(bool enabled) +{ + m_prefService->SetBoolean(prefs::kEnableContinuousSpellcheck, enabled); +} + +bool BrowserContextQt::isSpellCheckEnabled() const +{ + return m_prefService->GetBoolean(prefs::kEnableContinuousSpellcheck); +} +#endif //ENABLE_SPELLCHECK } // namespace QtWebEngineCore diff --git a/src/core/browser_context_qt.h b/src/core/browser_context_qt.h index 1513bf4bc..6a4b65b6b 100644 --- a/src/core/browser_context_qt.h +++ b/src/core/browser_context_qt.h @@ -47,6 +47,14 @@ #include // Needed for Q_DECL_OVERRIDE +#if defined(ENABLE_SPELLCHECK) +QT_BEGIN_NAMESPACE +class QStringList; +QT_END_NAMESPACE +class TestingPrefStore; +class PrefService; +#endif + namespace QtWebEngineCore { class BrowserContextAdapter; @@ -81,6 +89,14 @@ public: BrowserContextAdapter *adapter() { return m_adapter; } +#if defined(ENABLE_SPELLCHECK) + QStringList spellCheckLanguages(const QStringList &acceptLanguages); + void setSpellCheckLanguage(const QString &language); + QString spellCheckLanguage() const; + void setSpellCheckEnabled(bool enabled); + bool isSpellCheckEnabled() const; +#endif + private: friend class ContentBrowserClientQt; friend class WebContentsAdapter; @@ -88,6 +104,10 @@ private: scoped_refptr url_request_getter_; scoped_ptr permissionManager; BrowserContextAdapter *m_adapter; +#if defined(ENABLE_SPELLCHECK) + scoped_refptr m_prefStore; + scoped_ptr m_prefService; +#endif friend class BrowserContextAdapter; DISALLOW_COPY_AND_ASSIGN(BrowserContextQt); diff --git a/src/core/chrome_qt.gyp b/src/core/chrome_qt.gyp index 6c8e0d4d6..626691db4 100644 --- a/src/core/chrome_qt.gyp +++ b/src/core/chrome_qt.gyp @@ -1,6 +1,61 @@ { 'variables': { 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/chrome', + 'chrome_spellchecker_sources': [ + '<(DEPTH)/base/prefs/testing_pref_store.cc', + '<(DEPTH)/base/prefs/testing_pref_store.h', + '<(DEPTH)/chrome/browser/spellchecker/feedback.cc', + '<(DEPTH)/chrome/browser/spellchecker/feedback.h', + '<(DEPTH)/chrome/browser/spellchecker/feedback_sender.cc', + '<(DEPTH)/chrome/browser/spellchecker/feedback_sender.h', + '<(DEPTH)/chrome/browser/spellchecker/misspelling.cc', + '<(DEPTH)/chrome/browser/spellchecker/misspelling.h', + '<(DEPTH)/chrome/browser/spellchecker/spellcheck_action.cc', + '<(DEPTH)/chrome/browser/spellchecker/spellcheck_action.h', + '<(DEPTH)/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc', + '<(DEPTH)/chrome/browser/spellchecker/spellcheck_custom_dictionary.h', + '<(DEPTH)/chrome/browser/spellchecker/spellcheck_factory.cc', + '<(DEPTH)/chrome/browser/spellchecker/spellcheck_factory.h', + '<(DEPTH)/chrome/browser/spellchecker/spellcheck_host_metrics.cc', + '<(DEPTH)/chrome/browser/spellchecker/spellcheck_host_metrics.h', + '<(DEPTH)/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc', + '<(DEPTH)/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h', + '<(DEPTH)/chrome/browser/spellchecker/spellcheck_message_filter.cc', + '<(DEPTH)/chrome/browser/spellchecker/spellcheck_message_filter.h', + '<(DEPTH)/chrome/browser/spellchecker/spellcheck_message_filter_platform.h', + '<(DEPTH)/chrome/browser/spellchecker/spellcheck_message_filter_platform_mac.cc', + '<(DEPTH)/chrome/browser/spellchecker/spellcheck_platform_mac.mm', + '<(DEPTH)/chrome/browser/spellchecker/spellcheck_service.cc', + '<(DEPTH)/chrome/browser/spellchecker/spellcheck_service.h', + '<(DEPTH)/chrome/browser/spellchecker/spelling_service_client.cc', + '<(DEPTH)/chrome/browser/spellchecker/spelling_service_client.h', + '<(DEPTH)/chrome/browser/spellchecker/word_trimmer.cc', + '<(DEPTH)/chrome/browser/spellchecker/word_trimmer.h', + '<(DEPTH)/chrome/common/common_message_generator.cc', + '<(DEPTH)/chrome/common/pref_names.cc', + '<(DEPTH)/chrome/common/pref_names.h', + '<(DEPTH)/chrome/common/spellcheck_bdict_language.h', + '<(DEPTH)/chrome/common/spellcheck_common.cc', + '<(DEPTH)/chrome/common/spellcheck_common.h', + '<(DEPTH)/chrome/common/spellcheck_marker.h', + '<(DEPTH)/chrome/common/spellcheck_messages.h', + '<(DEPTH)/chrome/common/spellcheck_result.h', + '<(DEPTH)/chrome/renderer/spellchecker/custom_dictionary_engine.cc', + '<(DEPTH)/chrome/renderer/spellchecker/custom_dictionary_engine.h', + '<(DEPTH)/chrome/renderer/spellchecker/hunspell_engine.cc', + '<(DEPTH)/chrome/renderer/spellchecker/hunspell_engine.h', + '<(DEPTH)/chrome/renderer/spellchecker/platform_spelling_engine.cc', + '<(DEPTH)/chrome/renderer/spellchecker/platform_spelling_engine.h', + '<(DEPTH)/chrome/renderer/spellchecker/spellcheck.cc', + '<(DEPTH)/chrome/renderer/spellchecker/spellcheck.h', + '<(DEPTH)/chrome/renderer/spellchecker/spellcheck_language.cc', + '<(DEPTH)/chrome/renderer/spellchecker/spellcheck_language.h', + '<(DEPTH)/chrome/renderer/spellchecker/spellcheck_provider.cc', + '<(DEPTH)/chrome/renderer/spellchecker/spellcheck_provider.h', + '<(DEPTH)/chrome/renderer/spellchecker/spellcheck_worditerator.cc', + '<(DEPTH)/chrome/renderer/spellchecker/spellcheck_worditerator.h', + '<(DEPTH)/chrome/renderer/spellchecker/spelling_engine.h', + ] }, 'targets': [ { @@ -20,14 +75,52 @@ '<(SHARED_INTERMEDIATE_DIR)/components/strings', ], 'sources': [ + '<(DEPTH)/chrome/browser/media/desktop_media_list.h', '<(DEPTH)/chrome/browser/media/desktop_streams_registry.cc', '<(DEPTH)/chrome/browser/media/desktop_streams_registry.h', - '<(DEPTH)/chrome/browser/media/desktop_media_list.h', '<(DEPTH)/chrome/common/chrome_switches.cc', '<(DEPTH)/chrome/common/chrome_switches.h', '<(DEPTH)/chrome/common/localized_error.cc', '<(DEPTH)/chrome/common/localized_error.h', ], + 'conditions': [ + ['enable_spellcheck==1', { + 'sources': [ '<@(chrome_spellchecker_sources)' ], + 'include_dirs': [ + '<(chromium_src_dir)/third_party/WebKit', + ], + 'dependencies': [ + '<(chromium_src_dir)/components/components.gyp:keyed_service_content', + '<(chromium_src_dir)/components/components.gyp:keyed_service_core', + '<(chromium_src_dir)/components/components.gyp:pref_registry', + '<(chromium_src_dir)/components/components.gyp:user_prefs', + '<(chromium_src_dir)/third_party/hunspell/hunspell.gyp:hunspell', + '<(chromium_src_dir)/third_party/icu/icu.gyp:icui18n', + '<(chromium_src_dir)/third_party/icu/icu.gyp:icuuc', + ], + 'defines': [ + '__STDC_CONSTANT_MACROS', + '__STDC_FORMAT_MACROS', + ], + 'conditions': [ + ['OS == "win"', { + # crbug.com/167187 fix size_t to int truncations + 'msvs_disabled_warnings': [4267, ], + }], + [ 'OS != "mac"', { + 'sources/': [ + ['exclude', '_mac\\.(cc|cpp|mm?)$'], + ], + }], + ['use_browser_spellchecker==0', { + 'sources!': [ + '<(DEPTH)/chrome/renderer/spellchecker/platform_spelling_engine.cc', + '<(DEPTH)/chrome/renderer/spellchecker/platform_spelling_engine.h', + ], + }], + ] + }], + ], }, { 'target_name': 'chrome_resources', diff --git a/src/core/config/embedded_linux.pri b/src/core/config/embedded_linux.pri index 50f94147e..84db049cb 100644 --- a/src/core/config/embedded_linux.pri +++ b/src/core/config/embedded_linux.pri @@ -18,7 +18,6 @@ GYP_CONFIG += \ enable_plugins=0 \ enable_printing=0 \ enable_session_service=0 \ - enable_spellcheck=0 \ enable_task_manager=0 \ enable_themes=0 \ enable_webrtc=0 \ diff --git a/src/core/config/linux.pri b/src/core/config/linux.pri index c3398757e..f2883bc32 100644 --- a/src/core/config/linux.pri +++ b/src/core/config/linux.pri @@ -24,6 +24,9 @@ GYP_CONFIG += \ use_openssl_certs=1 } +no_spellcheck: GYP_CONFIG += enable_spellcheck=0 +else: GYP_CONFIG += enable_spellcheck=1 + contains(QT_CONFIG, system-zlib): use?(system_minizip): GYP_CONFIG += use_system_zlib=1 contains(QT_CONFIG, system-png): GYP_CONFIG += use_system_libpng=1 contains(QT_CONFIG, system-jpeg): GYP_CONFIG += use_system_libjpeg=1 diff --git a/src/core/config/mac_osx.pri b/src/core/config/mac_osx.pri index 6532077de..f11dba1b7 100644 --- a/src/core/config/mac_osx.pri +++ b/src/core/config/mac_osx.pri @@ -17,5 +17,8 @@ GYP_CONFIG += \ clang_use_chrome_plugins=0 \ enable_widevine=1 +no_spellcheck: GYP_CONFIG += enable_spellcheck=0 use_browser_spellchecker=0 +else: GYP_CONFIG += enable_spellcheck=1 use_browser_spellchecker=1 + QMAKE_MAC_SDK_PATH = "$$eval(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.path)" exists($$QMAKE_MAC_SDK_PATH): GYP_CONFIG += mac_sdk_path=\"$${QMAKE_MAC_SDK_PATH}\" diff --git a/src/core/config/windows.pri b/src/core/config/windows.pri index 92e193422..153a4fe72 100644 --- a/src/core/config/windows.pri +++ b/src/core/config/windows.pri @@ -6,6 +6,9 @@ GYP_CONFIG += \ use_ash=0 \ enable_widevine=1 +no_spellcheck: GYP_CONFIG += enable_spellcheck=0 +else: GYP_CONFIG += enable_spellcheck=1 + # Chromium builds with debug info in release by default but Qt doesn't CONFIG(release, debug|release):!force_debug_info: GYP_CONFIG += fastbuild=1 diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index 25cac53aa..54430b81c 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -41,6 +41,9 @@ #include "base/message_loop/message_loop.h" #include "base/threading/thread_restrictions.h" +#if defined(ENABLE_SPELLCHECK) +#include "chrome/browser/spellchecker/spellcheck_message_filter.h" +#endif #include "content/browser/renderer_host/render_view_host_delegate.h" #include "content/public/browser/browser_main_parts.h" #include "content/public/browser/child_process_security_policy.h" @@ -352,10 +355,14 @@ content::BrowserMainParts *ContentBrowserClientQt::CreateBrowserMainParts(const void ContentBrowserClientQt::RenderProcessWillLaunch(content::RenderProcessHost* host) { // FIXME: Add a settings variable to enable/disable the file scheme. - content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme(host->GetID(), url::kFileScheme); + const int id = host->GetID(); + content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme(id, url::kFileScheme); static_cast(host->GetBrowserContext())->m_adapter->userScriptController()->renderProcessStartedWithHost(host); #if defined(ENABLE_PEPPER_CDMS) - host->AddFilter(new BrowserMessageFilterQt(host->GetID())); + host->AddFilter(new BrowserMessageFilterQt(id)); +#endif +#if defined(ENABLE_SPELLCHECK) + host->AddFilter(new SpellCheckMessageFilter(id)); #endif } diff --git a/src/core/content_main_delegate_qt.cpp b/src/core/content_main_delegate_qt.cpp index 3c633600a..2f61e1e5e 100644 --- a/src/core/content_main_delegate_qt.cpp +++ b/src/core/content_main_delegate_qt.cpp @@ -103,7 +103,9 @@ bool ContentMainDelegateQt::BasicStartupComplete(int *exit_code) PathService::Override(base::DIR_QT_LIBRARY_DATA, WebEngineLibraryInfo::getPath(base::DIR_QT_LIBRARY_DATA)); PathService::Override(content::DIR_MEDIA_LIBS, WebEngineLibraryInfo::getPath(content::DIR_MEDIA_LIBS)); PathService::Override(ui::DIR_LOCALES, WebEngineLibraryInfo::getPath(ui::DIR_LOCALES)); - +#if defined(ENABLE_SPELLCHECK) + PathService::Override(base::DIR_APP_DICTIONARIES, WebEngineLibraryInfo::getPath(base::DIR_APP_DICTIONARIES)); +#endif SetContentClient(new ContentClientQt); return false; } diff --git a/src/core/renderer/content_renderer_client_qt.cpp b/src/core/renderer/content_renderer_client_qt.cpp index 5d2882020..36e4f83f1 100644 --- a/src/core/renderer/content_renderer_client_qt.cpp +++ b/src/core/renderer/content_renderer_client_qt.cpp @@ -44,6 +44,10 @@ #include "base/strings/string_split.h" #include "base/strings/utf_string_conversions.h" #include "chrome/common/localized_error.h" +#if defined(ENABLE_SPELLCHECK) +#include "chrome/renderer/spellchecker/spellcheck.h" +#include "chrome/renderer/spellchecker/spellcheck_provider.h" +#endif #include "components/cdm/renderer/widevine_key_systems.h" #include "components/error_page/common/error_page_params.h" #include "components/visitedlink/renderer/visitedlink_slave.h" @@ -93,6 +97,10 @@ void ContentRendererClientQt::RenderThreadStarted() // mark qrc as a secure scheme (avoids deprecation warnings) blink::WebSecurityPolicy::registerURLSchemeAsSecure(blink::WebString::fromLatin1(kQrcSchemeQt)); +#if defined(ENABLE_SPELLCHECK) + m_spellCheck.reset(new SpellCheck()); + renderThread->AddObserver(m_spellCheck.data()); +#endif } void ContentRendererClientQt::RenderViewCreated(content::RenderView* render_view) @@ -101,6 +109,9 @@ void ContentRendererClientQt::RenderViewCreated(content::RenderView* render_view new RenderViewObserverQt(render_view, m_webCacheObserver.data()); new WebChannelIPCTransport(render_view); UserScriptController::instance()->renderViewCreated(render_view); +#if defined(ENABLE_SPELLCHECK) + new SpellCheckProvider(render_view, m_spellCheck.data()); +#endif } void ContentRendererClientQt::RenderFrameCreated(content::RenderFrame* render_frame) diff --git a/src/core/renderer/content_renderer_client_qt.h b/src/core/renderer/content_renderer_client_qt.h index ca4bebe94..c80395140 100644 --- a/src/core/renderer/content_renderer_client_qt.h +++ b/src/core/renderer/content_renderer_client_qt.h @@ -52,6 +52,8 @@ namespace web_cache { class WebCacheRenderProcessObserver; } +class SpellCheck; + namespace QtWebEngineCore { class ContentRendererClientQt : public content::ContentRendererClient { @@ -73,6 +75,9 @@ public: private: QScopedPointer m_visitedLinkSlave; QScopedPointer m_webCacheObserver; +#if defined(ENABLE_SPELLCHECK) + QScopedPointer m_spellCheck; +#endif }; } // namespace diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h index e203697c0..0f3357948 100644 --- a/src/core/type_conversion.h +++ b/src/core/type_conversion.h @@ -250,6 +250,17 @@ inline std::vector toVector(const QStringList &fileList) int flagsFromModifiers(Qt::KeyboardModifiers modifiers); +#if defined(ENABLE_SPELLCHECK) +inline QStringList fromVector(const std::vector &vector) +{ + QStringList result; + for (auto s: vector) { + result.append(toQt(s)); + } + return result; +} +#endif + } // namespace QtWebEngineCore #endif // TYPE_CONVERSION_H diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 497221861..bf36a771c 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -1162,6 +1162,19 @@ void WebContentsAdapter::initUpdateDragCursorMessagePollingTimer() }); } +#if defined(ENABLE_SPELLCHECK) +void WebContentsAdapter::replaceMisspelling(const QString &word) +{ + Q_D(WebContentsAdapter); + d->webContents->ReplaceMisspelling(toString16(word)); +} + +void WebContentsAdapter::toogleSpellCheckEnabled() +{ + browserContext()->setSpellCheckEnabled(!browserContext()->isSpellCheckEnabled()); +} +#endif + WebContentsAdapterClient::RenderProcessTerminationStatus WebContentsAdapterClient::renderProcessExitStatus(int terminationStatus) { auto status = WebContentsAdapterClient::RenderProcessTerminationStatus(-1); diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index cbc7c34fb..e6aef23ec 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -170,6 +170,10 @@ public: // meant to be used within WebEngineCore only content::WebContents *webContents() const; +#if defined(ENABLE_SPELLCHECK) + void replaceMisspelling(const QString &word); + void toogleSpellCheckEnabled(); +#endif private: Q_DISABLE_COPY(WebContentsAdapter) diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index c29abe53f..5e6335584 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -79,6 +79,10 @@ public: : mediaType(MediaTypeNone) , hasImageContent(false) , mediaFlags(0) +#if defined(ENABLE_SPELLCHECK) + , isEditable(false) + , isSpellCheckerEnabled(false) +#endif { } @@ -124,11 +128,14 @@ public: bool hasImageContent; uint mediaFlags; QString suggestedFileName; +#if defined(ENABLE_SPELLCHECK) + bool isEditable; + bool isSpellCheckerEnabled; + QString misspelledWord; + QStringList spellCheckerSuggestions; +#endif // Some likely candidates for future additions as we add support for the related actions: // bool isImageBlocked; -// bool isEditable; -// bool isSpellCheckingEnabled; -// QStringList spellCheckingSuggestions; // mediaType; // ... }; diff --git a/src/core/web_contents_view_qt.cpp b/src/core/web_contents_view_qt.cpp index 926e159df..9614aa0f8 100644 --- a/src/core/web_contents_view_qt.cpp +++ b/src/core/web_contents_view_qt.cpp @@ -39,7 +39,7 @@ #include "web_contents_view_qt.h" -#include "browser_context_qt.h" +#include "browser_context_adapter.h" #include "content_browser_client_qt.h" #include "render_widget_host_view_qt_delegate.h" #include "type_conversion.h" @@ -162,12 +162,27 @@ static WebEngineContextMenuData fromParams(const content::ContextMenuParams &par ret.hasImageContent = params.has_image_contents; ret.mediaFlags = params.media_flags; ret.suggestedFileName = toQt(params.suggested_filename.data()); +#if defined(ENABLE_SPELLCHECK) + ret.isEditable = params.is_editable; + ret.misspelledWord = toQt(params.misspelled_word); + ret.spellCheckerSuggestions = fromVector(params.dictionary_suggestions); +#endif return ret; } void WebContentsViewQt::ShowContextMenu(content::RenderFrameHost *, const content::ContextMenuParams ¶ms) { WebEngineContextMenuData contextMenuData(fromParams(params)); +#if defined(ENABLE_SPELLCHECK) + // Do not use params.spellcheck_enabled, since it is never + // correctly initialized for chrome asynchronous spellchecking. + // Even fixing the initialization in ContextMenuClientImpl::showContextMenu + // will not work. By default SpellCheck::spellcheck_enabled_ + // must be initialized to true due to the way how the initialization sequence + // in SpellCheck works ie. typing the first word triggers the creation + // of the SpellcheckService. Use user preference store instead. + contextMenuData.isSpellCheckerEnabled = m_client->browserContextAdapter()->isSpellCheckEnabled(); +#endif m_client->contextMenuRequested(contextMenuData); } diff --git a/src/core/web_engine_library_info.cpp b/src/core/web_engine_library_info.cpp index aae86dce8..ee8174af7 100644 --- a/src/core/web_engine_library_info.cpp +++ b/src/core/web_engine_library_info.cpp @@ -205,6 +205,32 @@ QString localesPath() #endif } +#if defined(ENABLE_SPELLCHECK) +QString dictionariesPath() +{ +#if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) + return getResourcesPath(frameworkBundle()) % QLatin1String("/qtwebengine_dictionaries"); +#else + static bool initialized = false; + static QString potentialDictionariesPath = QLibraryInfo::location(QLibraryInfo::DataPath) % QDir::separator() % QLatin1String("qtwebengine_dictionaries"); + + if (!initialized) { + initialized = true; + if (!QFileInfo::exists(potentialDictionariesPath)) { + qWarning("Installed Qt WebEngine dictionaries directory not found at location %s. Trying application directory...", qPrintable(potentialDictionariesPath)); + potentialDictionariesPath = QCoreApplication::applicationDirPath() % QDir::separator() % QLatin1String("qtwebengine_dictionaries"); + } + if (!QFileInfo::exists(potentialDictionariesPath)) { + qWarning("Qt WebEngine dictionaries directory not found at location %s. Trying fallback directory... Spellcheck MAY NOT work.", qPrintable(potentialDictionariesPath)); + potentialDictionariesPath = fallbackDir(); + } + } + + return potentialDictionariesPath; +#endif +} +#endif // ENABLE_SPELLCHECK + QString icuDataPath() { #if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) @@ -292,6 +318,10 @@ base::FilePath WebEngineLibraryInfo::getPath(int key) return toFilePath(pluginsPath()); case ui::DIR_LOCALES: return toFilePath(localesPath()); +#if defined(ENABLE_SPELLCHECK) + case base::DIR_APP_DICTIONARIES: + return toFilePath(dictionariesPath()); +#endif default: // Note: the path system expects this function to override the default // behavior. So no need to log an error if we don't support a given diff --git a/src/webengine/api/qquickwebengineprofile.cpp b/src/webengine/api/qquickwebengineprofile.cpp index 1cf3d8922..14405251e 100644 --- a/src/webengine/api/qquickwebengineprofile.cpp +++ b/src/webengine/api/qquickwebengineprofile.cpp @@ -592,7 +592,97 @@ QQuickWebEngineProfile *QQuickWebEngineProfile::defaultProfile() return profile; } +#if !defined(QT_NO_SPELLCHECK) /*! + \qmlmethod void QQuickWebEngineProfile::spellCheckLanguages() + + Returns the subset of \a acceptLanguages supported by the spell checker. + Checks whether the spell checker dictionary is installed for the specified + language from the \a acceptLanguages list. If the dictionary file is missing + or corrupted, the language is removed from the returned list. + + \since QtWebEngine 1.3 +*/ + +/*! + Returns the subset of \a acceptLanguages supported by the spell checker. + Checks whether the spell checker dictionary is installed for the specified + language from the \a acceptLanguages list. If the dictionary file is missing + or corrupted, the language is removed from the returned list. + + \since QtWebEngine 1.3 +*/ +QStringList QQuickWebEngineProfile::spellCheckLanguages(const QStringList &acceptLanguages) +{ + const Q_D(QQuickWebEngineProfile); + return d->browserContext()->spellCheckLanguages(acceptLanguages); +} + +/*! + \property QQuickWebEngineProfile::spellCheckLanguage + \brief the language used by the spell checker. + + \since QtWebEngine 1.3 +*/ + +/*! + \qmlproperty QString WebEngineProfile::spellCheckLanguage + + This property holds the language used by the spell checker. + + \since QtWebEngine 1.3 +*/ +void QQuickWebEngineProfile::setSpellCheckLanguage(const QString &language) +{ + Q_D(QQuickWebEngineProfile); + if (language != d->browserContext()->spellCheckLanguage()) { + d->browserContext()->setSpellCheckLanguage(language); + emit spellCheckLanguageChanged(); + } +} + +/*! + \since 5.7 + + Returns the language used by the spell checker. +*/ +QString QQuickWebEngineProfile::spellCheckLanguage() const +{ + const Q_D(QQuickWebEngineProfile); + return d->browserContext()->spellCheckLanguage(); +} + +/*! + \property QQuickWebEngineProfile::spellCheckEnabled + \brief whether the web engine spell checker is enabled. + + \since QtWebEngine 1.3 +*/ + +/*! + \qmlproperty QString WebEngineProfile::spellCheckEnabled + + This property holds whether the web engine spell checker is enabled. + + \since QtWebEngine 1.3 +*/ +void QQuickWebEngineProfile::setSpellCheckEnabled(bool enable) +{ + Q_D(QQuickWebEngineProfile); + if (enable != isSpellCheckEnabled()) { + d->browserContext()->setSpellCheckEnabled(enable); + emit spellCheckEnabledChanged(); + } +} + +bool QQuickWebEngineProfile::isSpellCheckEnabled() const +{ + const Q_D(QQuickWebEngineProfile); + return d->browserContext()->isSpellCheckEnabled(); +} +#endif +/*! + Returns the cookie store singleton, if one has been set. */ QWebEngineCookieStore *QQuickWebEngineProfile::cookieStore() const diff --git a/src/webengine/api/qquickwebengineprofile.h b/src/webengine/api/qquickwebengineprofile.h index ba0126eaa..cf4334126 100644 --- a/src/webengine/api/qquickwebengineprofile.h +++ b/src/webengine/api/qquickwebengineprofile.h @@ -71,6 +71,11 @@ class Q_WEBENGINE_EXPORT QQuickWebEngineProfile : public QObject { Q_PROPERTY(QString httpAcceptLanguage READ httpAcceptLanguage WRITE setHttpAcceptLanguage NOTIFY httpAcceptLanguageChanged FINAL REVISION 1) Q_PROPERTY(PersistentCookiesPolicy persistentCookiesPolicy READ persistentCookiesPolicy WRITE setPersistentCookiesPolicy NOTIFY persistentCookiesPolicyChanged FINAL) Q_PROPERTY(int httpCacheMaximumSize READ httpCacheMaximumSize WRITE setHttpCacheMaximumSize NOTIFY httpCacheMaximumSizeChanged FINAL) +#if !defined(QT_NO_SPELLCHECK) + Q_PROPERTY(QString spellCheckLanguage READ spellCheckLanguage WRITE setSpellCheckLanguage NOTIFY spellCheckLanguageChanged REVISION 2) + Q_PROPERTY(bool spellCheckEnabled READ isSpellCheckEnabled WRITE setSpellCheckEnabled NOTIFY spellCheckEnabledChanged REVISION 2) +# endif + public: QQuickWebEngineProfile(QObject *parent = Q_NULLPTR); ~QQuickWebEngineProfile(); @@ -128,6 +133,14 @@ public: void clearHttpCache(); +#if !defined(QT_NO_SPELLCHECK) + Q_REVISION(2) Q_INVOKABLE QStringList spellCheckLanguages(const QStringList &acceptLanguages); + Q_REVISION(2) void setSpellCheckLanguage(const QString &language); + Q_REVISION(2) QString spellCheckLanguage() const; + Q_REVISION(2) void setSpellCheckEnabled(bool enabled); + Q_REVISION(2) bool isSpellCheckEnabled() const; +# endif + static QQuickWebEngineProfile *defaultProfile(); Q_SIGNALS: @@ -140,6 +153,10 @@ Q_SIGNALS: void persistentCookiesPolicyChanged(); void httpCacheMaximumSizeChanged(); Q_REVISION(1) void httpAcceptLanguageChanged(); +#if !defined(QT_NO_SPELLCHECK) + Q_REVISION(2) void spellCheckLanguageChanged(); + Q_REVISION(2) void spellCheckEnabledChanged(); +#endif void downloadRequested(QQuickWebEngineDownloadItem *download); void downloadFinished(QQuickWebEngineDownloadItem *download); diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 20264c7f7..17710b5cc 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -193,7 +193,17 @@ bool QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu // Populate our menu MenuItemHandler *item = 0; - +#if !defined(QT_NO_SPELLCHECK) + if (contextMenuData.isEditable && !contextMenuData.spellCheckerSuggestions.isEmpty()) { + for (int i=0; i < contextMenuData.spellCheckerSuggestions.count() && i < 4; i++) { + item = new MenuItemHandler(menu); + int index = QQuickWebEngineView::ReplaceMisspelledWord_1 + i; + QObject::connect(item, &MenuItemHandler::triggered, [q,index] { q->triggerWebAction(static_cast(index)); }); + ui()->addMenuItem(item, contextMenuData.spellCheckerSuggestions.at(i)); + } + ui()->addMenuSeparator(menu); + } +#endif if (!data.linkText.isEmpty() && data.linkUrl.isValid()) { item = new MenuItemHandler(menu); QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::OpenLinkInThisWindow); }); @@ -296,7 +306,13 @@ bool QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::ExitFullScreen); }); ui()->addMenuItem(item, QQuickWebEngineView::tr("Exit Full Screen Mode")); } - +#if !defined(QT_NO_SPELLCHECK) + if (contextMenuData.isEditable) { + item = new MenuItemHandler(menu); + QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::ToggleSpellcheck); }); + ui()->addMenuItem(item, QQuickWebEngineView::tr("Check Spelling"), QString(), true, true, contextMenuData.isSpellCheckerEnabled); + } +#endif // FIXME: expose the context menu data as an attached property to make this more useful if (contextMenuExtraItems) { ui()->addMenuSeparator(menu); @@ -1525,6 +1541,23 @@ void QQuickWebEngineView::triggerWebAction(WebAction action) case SavePage: d->adapter->save(); break; +#if !defined(QT_NO_SPELLCHECK) + case ToggleSpellcheck: + d->adapter->toogleSpellCheckEnabled(); + break; + case ReplaceMisspelledWord_1: + d->adapter->replaceMisspelling(d->contextMenuData.spellCheckerSuggestions.at(0)); + break; + case ReplaceMisspelledWord_2: + d->adapter->replaceMisspelling(d->contextMenuData.spellCheckerSuggestions.at(1)); + break; + case ReplaceMisspelledWord_3: + d->adapter->replaceMisspelling(d->contextMenuData.spellCheckerSuggestions.at(2)); + break; + case ReplaceMisspelledWord_4: + d->adapter->replaceMisspelling(d->contextMenuData.spellCheckerSuggestions.at(3)); + break; +#endif default: Q_UNREACHABLE(); } diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h index 3aace7563..4c6cbbaff 100644 --- a/src/webengine/api/qquickwebengineview_p.h +++ b/src/webengine/api/qquickwebengineview_p.h @@ -239,7 +239,13 @@ public: RequestClose, Unselect, SavePage, - +#if !defined(QT_NO_SPELLCHECK) + ToggleSpellcheck, + ReplaceMisspelledWord_1, + ReplaceMisspelledWord_2, + ReplaceMisspelledWord_3, + ReplaceMisspelledWord_4, +#endif WebActionCount }; Q_ENUM(WebAction) diff --git a/src/webengine/plugin/plugin.cpp b/src/webengine/plugin/plugin.cpp index c41bacf08..2feb3d195 100644 --- a/src/webengine/plugin/plugin.cpp +++ b/src/webengine/plugin/plugin.cpp @@ -76,6 +76,7 @@ public: qmlRegisterType(uri, 1, 3, "WebEngineView"); qmlRegisterType(uri, 1, 1, "WebEngineProfile"); qmlRegisterType(uri, 1, 2, "WebEngineProfile"); + qmlRegisterType(uri, 1, 3, "WebEngineProfile"); qmlRegisterType(uri, 1, 1, "WebEngineScript"); qmlRegisterUncreatableType(uri, 1, 1, "WebEngineCertificateError", tr("Cannot create separate instance of WebEngineCertificateError")); qmlRegisterUncreatableType(uri, 1, 1, "WebEngineDownloadItem", diff --git a/src/webengine/ui_delegates_manager.cpp b/src/webengine/ui_delegates_manager.cpp index d819c3321..a82ed0f2e 100644 --- a/src/webengine/ui_delegates_manager.cpp +++ b/src/webengine/ui_delegates_manager.cpp @@ -166,7 +166,8 @@ bool UIDelegatesManager::ensureComponentLoaded(ComponentType type) if (!prop.isSignalProperty()) \ qWarning("%s is missing %s signal property.\n", qPrintable(location.toString()), qPrintable(prop.name())); -void UIDelegatesManager::addMenuItem(MenuItemHandler *menuItemHandler, const QString &text, const QString &iconName, bool enabled) +void UIDelegatesManager::addMenuItem(MenuItemHandler *menuItemHandler, const QString &text, const QString &iconName, bool enabled, + bool checkable, bool checked) { Q_ASSERT(menuItemHandler); if (!ensureComponentLoaded(MenuItem)) @@ -176,6 +177,8 @@ void UIDelegatesManager::addMenuItem(MenuItemHandler *menuItemHandler, const QSt QQmlProperty(it, QStringLiteral("text")).write(text); QQmlProperty(it, QStringLiteral("iconName")).write(iconName); QQmlProperty(it, QStringLiteral("enabled")).write(enabled); + QQmlProperty(it, QStringLiteral("checkable")).write(checkable); + QQmlProperty(it, QStringLiteral("checked")).write(checked); QQmlProperty signal(it, QStringLiteral("onTriggered")); CHECK_QML_SIGNAL_PROPERTY(signal, menuItemComponent->url()); diff --git a/src/webengine/ui_delegates_manager.h b/src/webengine/ui_delegates_manager.h index ba3e0ff60..b63aa91f1 100644 --- a/src/webengine/ui_delegates_manager.h +++ b/src/webengine/ui_delegates_manager.h @@ -103,7 +103,8 @@ public: UIDelegatesManager(QQuickWebEngineView *); - void addMenuItem(MenuItemHandler *menuItemHandler, const QString &text, const QString &iconName = QString(), bool enabled = true); + void addMenuItem(MenuItemHandler *menuItemHandler, const QString &text, const QString &iconName = QString(), + bool enabled = true, bool checkable = false, bool checked = true); void addMenuSeparator(QObject *menu); QObject *addMenu(QObject *parentMenu, const QString &title, const QPoint &pos = QPoint()); QQmlContext *creationContextForComponent(QQmlComponent *); diff --git a/src/webengine/webengine.pro b/src/webengine/webengine.pro index 8f802d5c4..10353107a 100644 --- a/src/webengine/webengine.pro +++ b/src/webengine/webengine.pro @@ -55,4 +55,11 @@ isQMLTestSupportApiEnabled() { DEFINES += ENABLE_QML_TESTSUPPORT_API } +no_spellcheck { + DEFINES += QT_NO_SPELLCHECK + MODULE_DEFINES += QT_NO_SPELLCHECK +} else { + DEFINES += ENABLE_SPELLCHECK +} + load(qt_module) diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index d68f364e4..62c1adee6 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -835,6 +835,11 @@ QAction *QWebEnginePage::action(WebAction action) const case SavePage: text = tr("Save &Page"); break; +#if !defined(QT_NO_SPELLCHECK) + case ToggleSpellcheck: + text = tr("Check Spelling"); + break; +#endif default: break; } @@ -1015,6 +1020,17 @@ void QWebEnginePage::triggerAction(WebAction action, bool) case SavePage: d->adapter->save(); break; +#if !defined(QT_NO_SPELLCHECK) + case ToggleSpellcheck: + d->adapter->toogleSpellCheckEnabled(); + break; + case ReplaceMisspelledWord_1: + case ReplaceMisspelledWord_2: + case ReplaceMisspelledWord_3: + case ReplaceMisspelledWord_4: + d->adapter->replaceMisspelling(d->actions[action]->text()); + break; +#endif default: Q_UNREACHABLE(); } @@ -1194,6 +1210,19 @@ QMenu *QWebEnginePage::createStandardContextMenu() QMenu *menu = new QMenu(d->view); QAction *action = 0; WebEngineContextMenuData contextMenuData(d->m_menuData); + +#if !defined(QT_NO_SPELLCHECK) + if (contextMenuData.isEditable && !contextMenuData.spellCheckerSuggestions.isEmpty()) { + for (int i=0; i < contextMenuData.spellCheckerSuggestions.count() && i < 4; i++) { + int index = ReplaceMisspelledWord_1 + i; + QAction *action(QWebEnginePage::action(static_cast(index))); + action->setText(contextMenuData.spellCheckerSuggestions.at(i)); + menu->addAction(action); + } + menu->addSeparator(); + } +#endif + if (!contextMenuData.linkText.isEmpty() && contextMenuData.linkUrl.isValid()) { action = QWebEnginePage::action(OpenLinkInThisWindow); action->setText(tr("Follow Link")); @@ -1259,6 +1288,15 @@ QMenu *QWebEnginePage::createStandardContextMenu() if (d->isFullScreenMode()) menu->addAction(QWebEnginePage::action(ExitFullScreen)); +#if !defined(QT_NO_SPELLCHECK) + if (contextMenuData.isEditable) { + QAction* spellcheckAction(QWebEnginePage::action(ToggleSpellcheck)); + menu->addAction(spellcheckAction); + spellcheckAction->setCheckable(true); + spellcheckAction->setChecked(contextMenuData.isSpellCheckerEnabled); + } +#endif + return menu; } diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h index d8bdec303..be9f08ad1 100644 --- a/src/webenginewidgets/api/qwebenginepage.h +++ b/src/webenginewidgets/api/qwebenginepage.h @@ -118,7 +118,13 @@ public: RequestClose, Unselect, SavePage, - +#if !defined(QT_NO_SPELLCHECK) + ToggleSpellcheck, + ReplaceMisspelledWord_1, + ReplaceMisspelledWord_2, + ReplaceMisspelledWord_3, + ReplaceMisspelledWord_4, +#endif WebActionCount }; diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp index 69d96f925..8a6523a1b 100644 --- a/src/webenginewidgets/api/qwebengineprofile.cpp +++ b/src/webenginewidgets/api/qwebengineprofile.cpp @@ -530,6 +530,70 @@ QWebEngineProfile *QWebEngineProfile::defaultProfile() return profile; } +#if !defined(QT_NO_SPELLCHECK) +/*! + \since 5.7 + + Returns the subset of \a acceptLanguages supported by the spell checker. + + Checks whether the spell checker dictionary is installed for the specified + language from the \a acceptLanguages list. If the dictionary file is missing + or corrupted, the language is removed from the returned list. + + \sa setSpellCheckLanguage() +*/ +QStringList QWebEngineProfile::spellCheckLanguages(const QStringList &acceptLanguages) +{ + const Q_D(QWebEngineProfile); + return d->browserContext()->spellCheckLanguages(acceptLanguages); +} + +/*! + \since 5.7 + + Sets the current \a language for the spell checker. +*/ +void QWebEngineProfile::setSpellCheckLanguage(const QString &language) +{ + Q_D(QWebEngineProfile); + d->browserContext()->setSpellCheckLanguage(language); +} + +/*! + \since 5.7 + + Returns the language used by the spell checker. +*/ +QString QWebEngineProfile::spellCheckLanguage() const +{ + const Q_D(QWebEngineProfile); + return d->browserContext()->spellCheckLanguage(); +} + +/*! + \since 5.7 + + Enables spell checker if \a enable is \c true, otherwise disables it. + \sa isSpellCheckEnabled() + */ +void QWebEngineProfile::setSpellCheckEnabled(bool enable) +{ + Q_D(QWebEngineProfile); + d->browserContext()->setSpellCheckEnabled(enable); +} +/*! + \since 5.7 + + Returns \c true if the spell checker is enabled; otherwise returns \c false. + \sa setSpellCheckEnabled() + */ +bool QWebEngineProfile::isSpellCheckEnabled() const +{ + const Q_D(QWebEngineProfile); + return d->browserContext()->isSpellCheckEnabled(); +} +#endif + /*! Returns the default settings for all pages in this profile. */ diff --git a/src/webenginewidgets/api/qwebengineprofile.h b/src/webenginewidgets/api/qwebengineprofile.h index 22a913fb2..1a9bfe43a 100644 --- a/src/webenginewidgets/api/qwebengineprofile.h +++ b/src/webenginewidgets/api/qwebengineprofile.h @@ -121,6 +121,14 @@ public: void clearHttpCache(); +#if !defined(QT_NO_SPELLCHECK) + QStringList spellCheckLanguages(const QStringList &acceptLanguages); + void setSpellCheckLanguage(const QString &language); + QString spellCheckLanguage() const; + void setSpellCheckEnabled(bool enabled); + bool isSpellCheckEnabled() const; +#endif + static QWebEngineProfile *defaultProfile(); Q_SIGNALS: diff --git a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc index d3c540016..3b25bac76 100644 --- a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc @@ -125,6 +125,11 @@ \value Unselect Clear the current selection. (Added in Qt 5.7) \value SavePage Save the current page to disk. MHTML is the default format that is used to store the web page on disk. (Added in Qt 5.7) + \value ToggleSpellcheck Enable or disable the spell checker. (Added in Qt 5.7) + \value ReplaceMisspelledWord_1 Replace a misspelled word. (Added in Qt 5.7) + \value ReplaceMisspelledWord_2 Replace a misspelled word. (Added in Qt 5.7) + \value ReplaceMisspelledWord_3 Replace a misspelled word. (Added in Qt 5.7) + \value ReplaceMisspelledWord_4 Replace a misspelled word. (Added in Qt 5.7) \omitvalue WebActionCount diff --git a/src/webenginewidgets/webenginewidgets.pro b/src/webenginewidgets/webenginewidgets.pro index 5687bffaf..3b6b843b6 100644 --- a/src/webenginewidgets/webenginewidgets.pro +++ b/src/webenginewidgets/webenginewidgets.pro @@ -46,4 +46,11 @@ HEADERS = \ DEFINES += QT_UI_DELEGATES } +no_spellcheck { + DEFINES += QT_NO_SPELLCHECK + MODULE_DEFINES += QT_NO_SPELLCHECK +} else { + DEFINES += ENABLE_SPELLCHECK +} + load(qt_module) -- cgit v1.2.3