From 9451ceee24e832d32a86ae6a2f37eea781acaa2f Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Fri, 28 May 2021 19:59:48 +0200 Subject: Add spellchecker support and qwebengine_covert_dict to cmake Add spellchecker dictionary conversion tool. Change scope of gn object imported variables to function scope. Pick-to: 6.2 Change-Id: Ice579a89e20b80034b675e7f767a774100478472 Reviewed-by: Allan Sandfeld Jensen --- CMakeLists.txt | 1 + cmake/Functions.cmake | 34 +++ .../webenginewidgets/spellchecker/CMakeLists.txt | 34 +++ src/core/CMakeLists.txt | 45 ++-- src/core/api/configure.cmake | 1 - src/core/configure/BUILD.root.gn.in | 16 +- src/core/tools/CMakeLists.txt | 21 ++ src/core/tools/main.cpp | 248 +++++++++++++++++++++ src/tools/qwebengine_convert_dict/main.cpp | 248 --------------------- tests/auto/widgets/CMakeLists.txt | 2 +- tests/auto/widgets/spellchecking/CMakeLists.txt | 49 ++++ .../widgets/spellchecking/tst_spellchecking.cpp | 4 +- 12 files changed, 426 insertions(+), 277 deletions(-) create mode 100644 src/core/tools/CMakeLists.txt create mode 100644 src/core/tools/main.cpp delete mode 100644 src/tools/qwebengine_convert_dict/main.cpp create mode 100644 tests/auto/widgets/spellchecking/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 08d900d20..31ebb8687 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,7 @@ if(NOT QT_FEATURE_qtwebengine_build AND NOT QT_FEATURE_qtpdf_build) endif() add_subdirectory(src/core/api) +add_subdirectory(src/core/tools) add_subdirectory(src/process) add_subdirectory(src/webenginewidgets) add_subdirectory(src/webenginequick) diff --git a/cmake/Functions.cmake b/cmake/Functions.cmake index 2cd81554e..c61e403be 100644 --- a/cmake/Functions.cmake +++ b/cmake/Functions.cmake @@ -294,3 +294,37 @@ function(get_darwin_sdk_version result) endif() endfunction() +function(extend_target_with_gn_objects target config cmakeFile stampFile) + + include(${buildDir}/${config}/${cmakeFile}) + + string(TOUPPER ${config} cfg) + add_library(GnObjects_${target}_${config} OBJECT IMPORTED GLOBAL) + target_link_libraries(${target} PRIVATE $<$:GnObjects_${target}_${config}>) + add_custom_target(ninja_${target}_${config} DEPENDS ${buildDir}/${config}/${stampFile}) + add_dependencies(GnObjects_${target}_${config} ninja_${target}_${config}) + #TODO: remove GnObjects_${target}_${config} with CMAKE 3.20 + set_property(TARGET GnObjects_${target}_${config} + PROPERTY IMPORTED_OBJECTS_${cfg} ${${cfg}_NINJA_OBJECTS} + ) + set_source_files_properties(${${cfg}_NINJA_OBJECTS} PROPERTIES GENERATED TRUE) + + if(LINUX) + target_link_libraries(${target} + PRIVATE "-Wl,--start-group" "$<$:${${cfg}_NINJA_ARCHIVES}>" "-Wl,--end-group") + else() + target_link_libraries(${target} PRIVATE "$<$:${${cfg}_NINJA_ARCHIVES}>") + endif() + + target_link_libraries(${target} PUBLIC "$<$:${${cfg}_NINJA_LIBS}>") + + # we depend on stampFile, but ninja backend generator needs more (create once) + if(stampFile) + add_custom_command(OUTPUT ${${cfg}_NINJA_OBJECTS} ${${cfg}_NINJA_ARCHIVES} + DEPENDS ${buildDir}/${config}/${stampFile} + ) + add_custom_target(generate_${target}_${cfg} + DEPENDS ${${cfg}_NINJA_OBJECTS} ${${cfg}_NINJA_ARCHIVES} + ) + endif() +endfunction() diff --git a/examples/webenginewidgets/spellchecker/CMakeLists.txt b/examples/webenginewidgets/spellchecker/CMakeLists.txt index b8e17b1ac..f05cd74fe 100644 --- a/examples/webenginewidgets/spellchecker/CMakeLists.txt +++ b/examples/webenginewidgets/spellchecker/CMakeLists.txt @@ -53,3 +53,37 @@ install(TARGETS spellchecker BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" ) + +file(GLOB_RECURSE dicts + RELATIVE ${CMAKE_CURRENT_LIST_DIR}/dict + */*.dic +) + +if(QT_GENERATOR_IS_MULTI_CONFIG) + set(spellcheckerDir ${CMAKE_CURRENT_BINARY_DIR}/dict/qtwebengine_dictionaries) +else() + set(spellcheckerDir ${CMAKE_CURRENT_BINARY_DIR}/qtwebengine_dictionaries) +endif() + +foreach(dictFile ${dicts}) + get_filename_component(dictName ${dictFile} NAME_WE) + add_custom_command(TARGET spellchecker + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${spellcheckerDir} + COMMAND $ + ${CMAKE_CURRENT_SOURCE_DIR}/dict/${dictFile} + ${spellcheckerDir}/${dictName}.bdic + COMMENT "Running qwebengine_convert_dict" + ) +endforeach() + +# copy dictionaries to $ build dir +if(QT_GENERATOR_IS_MULTI_CONFIG) + add_custom_command(TARGET spellchecker + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo Copying dictionares + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/dict + ${CMAKE_CURRENT_BINARY_DIR}/$ + ) +endif() + diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index faf69327c..3f95156bd 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -14,6 +14,7 @@ include(${WEBENGINE_ROOT_SOURCE_DIR}/cmake/Functions.cmake) assertRunAsTopLevelBuild(TRUE) add_subdirectory(api) +add_subdirectory(tools) find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals Core) find_package(Gn ${QT_REPO_MODULE_VERSION} EXACT REQUIRED) @@ -522,7 +523,6 @@ foreach(config ${configs}) string(REGEX REPLACE "\n$" "" gnOutput "${gnOutput}") message("-- GN ${gnOutput}") endif() - include(${buildDir}/${config}/QtWebEngineCore.cmake) ## @@ -571,30 +571,10 @@ endif() foreach(config ${configs}) - string(TOUPPER ${config} cfg) - - add_library(GnObjects_${config} OBJECT IMPORTED GLOBAL) - target_link_libraries(WebEngineCore PRIVATE $<$:GnObjects_${config}>) - add_dependencies(GnObjects_${config} ninja_${config}) - #TODO: remove GnObjects_${config} with CMAKE 3.20 - set_property(TARGET GnObjects_${config} PROPERTY IMPORTED_OBJECTS_${cfg} ${${cfg}_NINJA_OBJECTS}) - set_source_files_properties(${${cfg}_NINJA_OBJECTS} PROPERTIES GENERATED TRUE) - - if(LINUX) - target_link_libraries(WebEngineCore - PRIVATE "-Wl,--start-group" "$<$:${${cfg}_NINJA_ARCHIVES}>" "-Wl,--end-group") - else() - target_link_libraries(WebEngineCore PRIVATE "$<$:${${cfg}_NINJA_ARCHIVES}>") - endif() - - target_link_libraries(WebEngineCore PUBLIC "$<$:${${cfg}_NINJA_LIBS}>") - - # we depend on WebEnigneCore stamp, but ninja backend generator needs more - add_custom_command(OUTPUT ${${cfg}_NINJA_OBJECTS} ${${cfg}_NINJA_ARCHIVES} - DEPENDS ${buildDir}/${config}/QtWebEngineCore.stamp) - add_custom_target(generate_${cfg} DEPENDS ${${cfg}_NINJA_OBJECTS} ${${cfg}_NINJA_ARCHIVES}) + extend_target_with_gn_objects(WebEngineCore ${config} QtWebEngineCore.cmake QtWebEngineCore.stamp) if(WIN32) + string(TOUPPER ${config} cfg) set(sandboxLibraryPath ${buildDir}/${config}/QtWebEngineCoreSandbox.lib) set_property(TARGET WebEngineCoreSandbox PROPERTY IMPORTED_LOCATION_${cfg} ${sandboxLibraryPath}) @@ -606,7 +586,7 @@ foreach(config ${configs}) endforeach() ## -# RESOURCES +# WEBENGINECORE RESOURCES ## #TODO: use simply filter / globbing-expressions @@ -706,3 +686,20 @@ else() ${CMAKE_INSTALL_PREFIX}/translations/qtwebengine_locales) endif() endif() + +## +# WEBENGINECORE DICT TOOL SETUP +## + +if(QT_FEATURE_webengine_spellchecker) + qt_get_tool_target_name(dict_target_name qwebengine_convert_dict) + target_include_directories(${dict_target_name} PRIVATE + ../3rdparty/chromium + ../3rdparty/chromium/third_party/boringssl/src/include + ${buildDir}/${config}/gen + ) + foreach(config ${configs}) + extend_target_with_gn_objects(${dict_target_name} ${config} convert_dict.cmake "") + endforeach() +endif() + diff --git a/src/core/api/configure.cmake b/src/core/api/configure.cmake index 8e8b6044e..35d28e87f 100644 --- a/src/core/api/configure.cmake +++ b/src/core/api/configure.cmake @@ -81,7 +81,6 @@ qt_feature("webengine-kerberos" PRIVATE qt_feature("webengine-spellchecker" PUBLIC LABEL "Spellchecker" PURPOSE "Provides a spellchecker." - AUTODETECT OFF ) qt_feature("webengine-native-spellchecker" PUBLIC LABEL "Native Spellchecker" diff --git a/src/core/configure/BUILD.root.gn.in b/src/core/configure/BUILD.root.gn.in index 28882050f..b0e52511c 100644 --- a/src/core/configure/BUILD.root.gn.in +++ b/src/core/configure/BUILD.root.gn.in @@ -258,7 +258,8 @@ source_set("qtwebengine_sources") { if (enable_spellcheck) { deps += [ ":qtwebengine_spellcheck_sources", - "//chrome/tools/convert_dict", + "//chrome/tools/convert_dict:lib", + "//third_party/hunspell", ] } if (enable_plugins) { @@ -530,3 +531,16 @@ if (enable_extensions) { ] } } + +if (enable_spellcheck) { + shared_library("convert_dict") { + cmake_config = "@GN_CONFIG@" + configs += [ "//build/config/compiler:wexit_time_destructors" ] + deps = [ + "//chrome/tools/convert_dict:lib", + "//base", + "//base:i18n", + "//third_party/hunspell", + ] + } +} diff --git a/src/core/tools/CMakeLists.txt b/src/core/tools/CMakeLists.txt new file mode 100644 index 000000000..d191f57b9 --- /dev/null +++ b/src/core/tools/CMakeLists.txt @@ -0,0 +1,21 @@ + +## +# WEBENGINECORE DICT CONVERT TOOL +## + +if(QT_FEATURE_webengine_spellchecker) + qt_get_tool_target_name(dict_target_name qwebengine_convert_dict) + qt_internal_add_tool(${dict_target_name} + TARGET_DESCRIPTION "QtWebEngine Dictionary Conversion Tool" + INSTALL_DIR ${INSTALL_LIBEXECDIR} + TOOLS_TARGET WebEngineCore + SOURCES main.cpp + ) + qt_skip_warnings_are_errors(${dict_target_name}) + make_install_only(${dict_target_name}) + add_dependencies(${dict_target_name} WebEngineCore) + qt_internal_extend_target(${dict_target_name} CONDITION WIN32 + DEFINES WIN32_LEAN_AND_MEAN NOMINMAX + ) +endif() + diff --git a/src/core/tools/main.cpp b/src/core/tools/main.cpp new file mode 100644 index 000000000..d79132510 --- /dev/null +++ b/src/core/tools/main.cpp @@ -0,0 +1,248 @@ +/****************************************************************************** +** This is just slightly modified version of convert_dict.cc +** chromium/chrome/tools/convert_dict/convert_dict.cc +** +** Original work: +** Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +** Modified work: +** Copyright (C) 2016 The Qt Company Ltd. +** +** Use of this source code is governed by a BSD-style license that can be +** found in the LICENSE.Chromium file. +** +** This tool converts Hunspell .aff/.dic pairs to a combined binary dictionary +** format (.bdic). This format is more compact, and can be more efficiently +** read by the client application. +** +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// see also src/core/type_conversion.h +inline base::FilePath::StringType toFilePathString(const QString &str) +{ +#if defined(Q_OS_WIN) + return QDir::toNativeSeparators(str).toStdWString(); +#else + return str.toStdString(); +#endif +} + +inline base::FilePath toFilePath(const QString &str) +{ + return base::FilePath(toFilePathString(str)); +} + +inline QString toQt(const base::string16 &string) +{ +#if defined(OS_WIN) + return QString::fromStdWString(string); +#else + return QString::fromUtf16(reinterpret_cast(string.data()), string.size()); +#endif +} + +inline QString toQt(const std::string &string) +{ + return QString::fromStdString(string); +} + +template +QTextStream &operator<<(QTextStream &out, base::span span) +{ + out << '['; + QString prefix; + for (const auto &element : span) { + out << prefix; + out << element; + prefix = QStringLiteral(","); + } + out << ']'; + return out; +} + +// Compares the given word list with the serialized trie to make sure they +// are the same. +inline bool VerifyWords(const convert_dict::DicReader::WordList& org_words, + const std::string& serialized, QTextStream& out) +{ + hunspell::BDictReader reader; + if (!reader.Init(reinterpret_cast(serialized.data()), + serialized.size())) { + out << "BDict is invalid\n"; + return false; + } + hunspell::WordIterator iter = reader.GetAllWordIterator(); + + int affix_ids[hunspell::BDict::MAX_AFFIXES_PER_WORD]; + + static const int buf_size = 128; + char buf[buf_size]; + for (size_t i = 0; i < org_words.size(); i++) { + int affix_matches = iter.Advance(buf, buf_size, affix_ids); + if (affix_matches == 0) { + out << "Found the end before we expected\n"; + return false; + } + + if (org_words[i].first != buf) { + out << "Word does not match!\n" + << " Index: " << i << "\n" + << " Expected: " << QString::fromStdString(org_words[i].first) << "\n" + << " Actual: " << QString::fromUtf8(buf) << "\n"; + return false; + } + + base::span expectedAffixes(org_words[i].second); + base::span actualAffixes(affix_ids, affix_matches); + + if (!std::equal(expectedAffixes.begin(), expectedAffixes.end(), + actualAffixes.begin(), actualAffixes.end(), + [](int a, int b) { return a == b; })) { + out << "Affixes do not match!\n" + << " Index: " << i << "\n" + << " Word: " << QString::fromUtf8(buf) << "\n" + << " Expected: " << expectedAffixes << "\n" + << " Actual: " << actualAffixes << "\n"; + return false; + } + } + + return true; +} + +#if defined(OS_MAC) && defined(QT_MAC_FRAMEWORK_BUILD) +QString frameworkIcuDataPath() +{ + return QLibraryInfo::location(QLibraryInfo::LibrariesPath) + + QStringLiteral("/QtWebEngineCore.framework/Resources/"); +} +#endif + +int main(int argc, char *argv[]) +{ + // Required only for making QLibraryInfo::location() return a valid path, when the application + // picks up a qt.conf file (which is the case for official Qt packages). + QCoreApplication app(argc, argv); + Q_UNUSED(app); + + QTextStream out(stdout); + + if (argc != 3) { + QTextStream out(stdout); + out << "Usage: qwebengine_convert_dict \n\nExample:\n" + "qwebengine_convert_dict ./en-US.dic ./en-US.bdic\nwill read en-US.dic, " + "en-US.dic_delta, and en-US.aff from the current directory and generate " + "en-US.bdic\n\n"; + return 1; + } + + bool icuDataDirFound = false; + QString icuDataDir = QLibraryInfo::path(QLibraryInfo::DataPath) + % QLatin1String("/resources"); + + // Try to look up the path to the ICU data directory via an environment variable + // (e.g. for the case when the tool is ran during build phase, and regular installed + // ICU data file is not available). + const QString icuPossibleEnvDataDir = qEnvironmentVariable("QT_WEBENGINE_ICU_DATA_DIR"); + if (!icuPossibleEnvDataDir.isEmpty() && QFileInfo::exists(icuPossibleEnvDataDir)) { + icuDataDir = icuPossibleEnvDataDir; + icuDataDirFound = true; + } +#if defined(OS_MAC) && defined(QT_MAC_FRAMEWORK_BUILD) + // In a macOS Qt framework build, the resources are inside the QtWebEngineCore framework + // Resources directory, rather than in the Qt install location. + else if (QFileInfo::exists(frameworkIcuDataPath())) { + icuDataDir = frameworkIcuDataPath(); + icuDataDirFound = true; + } +#endif + // Try to find the ICU data directory in the installed Qt location. + else if (QFileInfo::exists(icuDataDir)) { + icuDataDirFound = true; + } + + if (icuDataDirFound) { + base::PathService::Override(base::DIR_QT_LIBRARY_DATA, toFilePath(icuDataDir)); + } else { + QTextStream out(stdout); + out << "Couldn't find ICU data directory. Please check that the following path exists: " + << icuDataDir + << "\nAlternatively provide the directory path via the QT_WEBENGINE_ICU_DAT_DIR " + "environment variable.\n\n"; + return 1; + } + + + base::AtExitManager exit_manager; + base::i18n::InitializeICU(); + + base::FilePath file_in_path = toFilePath(argv[1]); + base::FilePath file_out_path = toFilePath(argv[2]); + base::FilePath aff_path = file_in_path.ReplaceExtension(FILE_PATH_LITERAL(".aff")); + + out << "Reading " << toQt(aff_path.value()) << "\n"; + convert_dict::AffReader aff_reader(aff_path); + + if (!aff_reader.Read()) { + out << "Unable to read the aff file.\n"; + return 1; + } + + base::FilePath dic_path = file_in_path.ReplaceExtension(FILE_PATH_LITERAL(".dic")); + out << "Reading " << toQt(dic_path.value()) << "\n"; + + // DicReader will also read the .dic_delta file. + convert_dict::DicReader dic_reader(dic_path); + if (!dic_reader.Read(&aff_reader)) { + out << "Unable to read the dic file.\n"; + return 1; + } + + hunspell::BDictWriter writer; + writer.SetComment(aff_reader.comments()); + writer.SetAffixRules(aff_reader.affix_rules()); + writer.SetAffixGroups(aff_reader.GetAffixGroups()); + writer.SetReplacements(aff_reader.replacements()); + writer.SetOtherCommands(aff_reader.other_commands()); + writer.SetWords(dic_reader.words()); + + out << "Serializing...\n"; + + std::string serialized = writer.GetBDict(); + + out << "Verifying...\n"; + + if (!VerifyWords(dic_reader.words(), serialized, out)) { + out << "ERROR converting, the dictionary does not check out OK.\n"; + return 1; + } + + out << "Writing " << toQt(file_out_path.value()) << "\n"; + FILE *out_file = base::OpenFile(file_out_path, "wb"); + if (!out_file) { + out << "ERROR writing file\n"; + return 1; + } + size_t written = fwrite(&serialized[0], 1, serialized.size(), out_file); + Q_ASSERT(written == serialized.size()); + base::CloseFile(out_file); + out << "Success. Dictionary converted.\n"; + return 0; +} + diff --git a/src/tools/qwebengine_convert_dict/main.cpp b/src/tools/qwebengine_convert_dict/main.cpp deleted file mode 100644 index d79132510..000000000 --- a/src/tools/qwebengine_convert_dict/main.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/****************************************************************************** -** This is just slightly modified version of convert_dict.cc -** chromium/chrome/tools/convert_dict/convert_dict.cc -** -** Original work: -** Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -** Modified work: -** Copyright (C) 2016 The Qt Company Ltd. -** -** Use of this source code is governed by a BSD-style license that can be -** found in the LICENSE.Chromium file. -** -** This tool converts Hunspell .aff/.dic pairs to a combined binary dictionary -** format (.bdic). This format is more compact, and can be more efficiently -** read by the client application. -** -******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -// see also src/core/type_conversion.h -inline base::FilePath::StringType toFilePathString(const QString &str) -{ -#if defined(Q_OS_WIN) - return QDir::toNativeSeparators(str).toStdWString(); -#else - return str.toStdString(); -#endif -} - -inline base::FilePath toFilePath(const QString &str) -{ - return base::FilePath(toFilePathString(str)); -} - -inline QString toQt(const base::string16 &string) -{ -#if defined(OS_WIN) - return QString::fromStdWString(string); -#else - return QString::fromUtf16(reinterpret_cast(string.data()), string.size()); -#endif -} - -inline QString toQt(const std::string &string) -{ - return QString::fromStdString(string); -} - -template -QTextStream &operator<<(QTextStream &out, base::span span) -{ - out << '['; - QString prefix; - for (const auto &element : span) { - out << prefix; - out << element; - prefix = QStringLiteral(","); - } - out << ']'; - return out; -} - -// Compares the given word list with the serialized trie to make sure they -// are the same. -inline bool VerifyWords(const convert_dict::DicReader::WordList& org_words, - const std::string& serialized, QTextStream& out) -{ - hunspell::BDictReader reader; - if (!reader.Init(reinterpret_cast(serialized.data()), - serialized.size())) { - out << "BDict is invalid\n"; - return false; - } - hunspell::WordIterator iter = reader.GetAllWordIterator(); - - int affix_ids[hunspell::BDict::MAX_AFFIXES_PER_WORD]; - - static const int buf_size = 128; - char buf[buf_size]; - for (size_t i = 0; i < org_words.size(); i++) { - int affix_matches = iter.Advance(buf, buf_size, affix_ids); - if (affix_matches == 0) { - out << "Found the end before we expected\n"; - return false; - } - - if (org_words[i].first != buf) { - out << "Word does not match!\n" - << " Index: " << i << "\n" - << " Expected: " << QString::fromStdString(org_words[i].first) << "\n" - << " Actual: " << QString::fromUtf8(buf) << "\n"; - return false; - } - - base::span expectedAffixes(org_words[i].second); - base::span actualAffixes(affix_ids, affix_matches); - - if (!std::equal(expectedAffixes.begin(), expectedAffixes.end(), - actualAffixes.begin(), actualAffixes.end(), - [](int a, int b) { return a == b; })) { - out << "Affixes do not match!\n" - << " Index: " << i << "\n" - << " Word: " << QString::fromUtf8(buf) << "\n" - << " Expected: " << expectedAffixes << "\n" - << " Actual: " << actualAffixes << "\n"; - return false; - } - } - - return true; -} - -#if defined(OS_MAC) && defined(QT_MAC_FRAMEWORK_BUILD) -QString frameworkIcuDataPath() -{ - return QLibraryInfo::location(QLibraryInfo::LibrariesPath) + - QStringLiteral("/QtWebEngineCore.framework/Resources/"); -} -#endif - -int main(int argc, char *argv[]) -{ - // Required only for making QLibraryInfo::location() return a valid path, when the application - // picks up a qt.conf file (which is the case for official Qt packages). - QCoreApplication app(argc, argv); - Q_UNUSED(app); - - QTextStream out(stdout); - - if (argc != 3) { - QTextStream out(stdout); - out << "Usage: qwebengine_convert_dict \n\nExample:\n" - "qwebengine_convert_dict ./en-US.dic ./en-US.bdic\nwill read en-US.dic, " - "en-US.dic_delta, and en-US.aff from the current directory and generate " - "en-US.bdic\n\n"; - return 1; - } - - bool icuDataDirFound = false; - QString icuDataDir = QLibraryInfo::path(QLibraryInfo::DataPath) - % QLatin1String("/resources"); - - // Try to look up the path to the ICU data directory via an environment variable - // (e.g. for the case when the tool is ran during build phase, and regular installed - // ICU data file is not available). - const QString icuPossibleEnvDataDir = qEnvironmentVariable("QT_WEBENGINE_ICU_DATA_DIR"); - if (!icuPossibleEnvDataDir.isEmpty() && QFileInfo::exists(icuPossibleEnvDataDir)) { - icuDataDir = icuPossibleEnvDataDir; - icuDataDirFound = true; - } -#if defined(OS_MAC) && defined(QT_MAC_FRAMEWORK_BUILD) - // In a macOS Qt framework build, the resources are inside the QtWebEngineCore framework - // Resources directory, rather than in the Qt install location. - else if (QFileInfo::exists(frameworkIcuDataPath())) { - icuDataDir = frameworkIcuDataPath(); - icuDataDirFound = true; - } -#endif - // Try to find the ICU data directory in the installed Qt location. - else if (QFileInfo::exists(icuDataDir)) { - icuDataDirFound = true; - } - - if (icuDataDirFound) { - base::PathService::Override(base::DIR_QT_LIBRARY_DATA, toFilePath(icuDataDir)); - } else { - QTextStream out(stdout); - out << "Couldn't find ICU data directory. Please check that the following path exists: " - << icuDataDir - << "\nAlternatively provide the directory path via the QT_WEBENGINE_ICU_DAT_DIR " - "environment variable.\n\n"; - return 1; - } - - - base::AtExitManager exit_manager; - base::i18n::InitializeICU(); - - base::FilePath file_in_path = toFilePath(argv[1]); - base::FilePath file_out_path = toFilePath(argv[2]); - base::FilePath aff_path = file_in_path.ReplaceExtension(FILE_PATH_LITERAL(".aff")); - - out << "Reading " << toQt(aff_path.value()) << "\n"; - convert_dict::AffReader aff_reader(aff_path); - - if (!aff_reader.Read()) { - out << "Unable to read the aff file.\n"; - return 1; - } - - base::FilePath dic_path = file_in_path.ReplaceExtension(FILE_PATH_LITERAL(".dic")); - out << "Reading " << toQt(dic_path.value()) << "\n"; - - // DicReader will also read the .dic_delta file. - convert_dict::DicReader dic_reader(dic_path); - if (!dic_reader.Read(&aff_reader)) { - out << "Unable to read the dic file.\n"; - return 1; - } - - hunspell::BDictWriter writer; - writer.SetComment(aff_reader.comments()); - writer.SetAffixRules(aff_reader.affix_rules()); - writer.SetAffixGroups(aff_reader.GetAffixGroups()); - writer.SetReplacements(aff_reader.replacements()); - writer.SetOtherCommands(aff_reader.other_commands()); - writer.SetWords(dic_reader.words()); - - out << "Serializing...\n"; - - std::string serialized = writer.GetBDict(); - - out << "Verifying...\n"; - - if (!VerifyWords(dic_reader.words(), serialized, out)) { - out << "ERROR converting, the dictionary does not check out OK.\n"; - return 1; - } - - out << "Writing " << toQt(file_out_path.value()) << "\n"; - FILE *out_file = base::OpenFile(file_out_path, "wb"); - if (!out_file) { - out << "ERROR writing file\n"; - return 1; - } - size_t written = fwrite(&serialized[0], 1, serialized.size(), out_file); - Q_ASSERT(written == serialized.size()); - base::CloseFile(out_file); - out << "Success. Dictionary converted.\n"; - return 0; -} - diff --git a/tests/auto/widgets/CMakeLists.txt b/tests/auto/widgets/CMakeLists.txt index f7955b1f8..a6e8d7c35 100644 --- a/tests/auto/widgets/CMakeLists.txt +++ b/tests/auto/widgets/CMakeLists.txt @@ -32,5 +32,5 @@ if(QT_FEATURE_ssl) add_subdirectory(certificateerror) endif() if(QT_FEATURE_webengine_spellchecker AND NOT CMAKE_CROSSCOMPILING AND NOT QT_FEATURE_webengine_native_spellchecker) -# add_subdirectory(spellchecking) + add_subdirectory(spellchecking) endif() diff --git a/tests/auto/widgets/spellchecking/CMakeLists.txt b/tests/auto/widgets/spellchecking/CMakeLists.txt new file mode 100644 index 000000000..afed7e28b --- /dev/null +++ b/tests/auto/widgets/spellchecking/CMakeLists.txt @@ -0,0 +1,49 @@ +include(../../util/util.cmake) + +qt_internal_add_test(tst_spellchecking + SOURCES + tst_spellchecking.cpp + LIBRARIES + Qt::WebEngineWidgets + Test::Util +) + +qt_internal_add_resource(tst_spellchecking "tst_spellchecking" + PREFIX + "/" + FILES + "resources/index.html" +) + +file(GLOB_RECURSE dicts + RELATIVE ${CMAKE_CURRENT_LIST_DIR}/dict + *.dic +) + +if(QT_GENERATOR_IS_MULTI_CONFIG) + set(spellcheckerDir ${CMAKE_CURRENT_BINARY_DIR}/dict/qtwebengine_dictionaries) +else() + set(spellcheckerDir ${CMAKE_CURRENT_BINARY_DIR}/qtwebengine_dictionaries) +endif() + +foreach(dictFile ${dicts}) + get_filename_component(dictName ${dictFile} NAME_WE) + add_custom_command(TARGET tst_spellchecking + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${spellcheckerDir} + COMMAND $ + ${CMAKE_CURRENT_SOURCE_DIR}/dict/${dictFile} + ${spellcheckerDir}/${dictName}.bdic + COMMENT "Running qwebengine_convert_dict" + ) +endforeach() + +# copy dictionaries to $ build dir +if(QT_GENERATOR_IS_MULTI_CONFIG) + add_custom_command(TARGET tst_spellchecking + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo Copying dictionares + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/dict + ${CMAKE_CURRENT_BINARY_DIR}/$ + ) +endif() diff --git a/tests/auto/widgets/spellchecking/tst_spellchecking.cpp b/tests/auto/widgets/spellchecking/tst_spellchecking.cpp index 258071559..ab79ff6cb 100644 --- a/tests/auto/widgets/spellchecking/tst_spellchecking.cpp +++ b/tests/auto/widgets/spellchecking/tst_spellchecking.cpp @@ -26,12 +26,12 @@ ** ****************************************************************************/ -#include "util.h" +#include #include #include #include +#include #include -#include class WebView : public QWebEngineView { -- cgit v1.2.3