Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qohosplatformfontdatabase.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QDir>
5
7#include <QtCore/private/qnapi_p.h>
8#include <fontconfig/fontconfig.h>
9#include <qohosplugincore.h>
10
11using namespace std::string_literals;
12
14
15// Defined in gui/text/qfontdatabase.cpp
16Q_GUI_EXPORT QFontDatabase::WritingSystem qt_writing_system_for_script(int script);
17
18namespace {
19
20enum class JsSystemFontType {
21 ALL = 1 << 0,
22 GENERIC = 1 << 1,
23 STYLISH = 1 << 2,
24 INSTALLED = 1 << 3,
25};
26
27bool ohosNoUiChildMode = false;
28
29QStringList getSystemFontPaths(QtOhos::JsState &jsState)
30{
31 if (ohosNoUiChildMode)
32 return {};
33
34 auto fontModule = jsState.eval<QNapi::Object>("@ohos.font");
35
36 auto systemFontPaths = QNapi::getArrayElements<QStringList, QNapi::String>(
37 fontModule.call<QNapi::Array>("getSystemFontList"),
38 [&](QNapi::String fontName) {
39 auto fontInfo = fontModule.call("getFontByName", {fontName});
40 return fontInfo.IsObject()
41 ? QString::fromStdString(
42 QNapi::checkedCast<QNapi::Object>(fontInfo).get<QNapi::String>("path"))
43 : QString();
44 });
45
46 systemFontPaths.removeAll(QString());
47
48 return systemFontPaths;
49}
50
51QStringList getUIFontPaths(QtOhos::JsState &jsState)
52{
53 if (ohosNoUiChildMode)
54 return {};
55
56 auto uiFontDirs = QNapi::getArrayElements<QStringList, QNapi::String>(
57 jsState.eval<QNapi::Array>("@ohos.font.getUIFontConfig().fontDir"),
58 &QString::fromStdString);
59
60 QStringList nameFilters;
61 nameFilters << QLatin1String("*.ttf")
62 << QLatin1String("*.otf")
63 << QLatin1String("*.ttc");
64
65 QStringList result;
66 for (const auto &fontDir : uiFontDirs) {
67 for (const QFileInfo &fileInfo : QDir(fontDir).entryInfoList(nameFilters, QDir::Files))
68 result.append(fileInfo.absoluteFilePath());
69 }
70
71 return result;
72}
73
74QStringList getInstalledFontPaths()
75{
76 if (ohosNoUiChildMode)
77 return {};
78
79 auto fontsPaths = QtOhos::evalInJsThreadWithConsumer<std::vector<std::string>>(
80 [](QtOhos::JsState &jsState, QOhosConsumer<std::vector<std::string>> resultConsumer) {
81 jsState.eval<QNapi::Promise>(
82 "@ohos.graphics.text.getSystemFontFullNamesByType(*)",
83 {static_cast<int>(JsSystemFontType::INSTALLED)})
84 .withContext(std::move(resultConsumer))
85 .onThenWithContext(
86 [](const QtOhos::CallbackInfo &cbInfo, auto &resultConsumer) {
87 auto fontsNamesArray = cbInfo.getFirstArg<QNapi::Array>(Q_FUNC_INFO);
88
89 if (fontsNamesArray.Length() == 0) {
90 resultConsumer({});
91 return;
92 }
93
94 auto fontsNames = QNapi::getArrayElements<std::vector<std::string>, QNapi::String>(fontsNamesArray);
95 auto pathsCollector = std::make_shared<QOhosConsumer<std::string>>(
96 [resultConsumer = std::move(resultConsumer), pushSize = fontsNames.size(), result = std::vector<std::string>()](auto element) mutable {
97 result.push_back(std::move(element));
98 if (result.size() == pushSize)
99 resultConsumer(std::move(result));
100 });
101
102 for (const auto &fontName : fontsNames) {
103 cbInfo.jsState().eval<QNapi::Promise>(
104 "@ohos.graphics.text.getFontDescriptorByFullName(*)",
105 {fontName, static_cast<int>(JsSystemFontType::INSTALLED)})
106 .onThen(
107 [pathsCollector](const QtOhos::CallbackInfo &cbInfo) {
108 auto fontDescriptor = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
109 auto optFontPath = QNapi::getOptionalPropOrEmpty<QNapi::String>(fontDescriptor, "path");
110 (*pathsCollector)(!optFontPath.IsEmpty() ? optFontPath.Utf8Value() : ""s);
111 })
112 .onCatch(
113 [pathsCollector, fontName](const QtOhos::CallbackInfo &cbInfo) {
114 QtOhos::logJsCallbackError(
115 cbInfo, ("getFontDescriptorByFullName("s + fontName + ") failed"s).c_str());
116 (*pathsCollector)(""s);
117 });
118 }
119 })
120 .onCatchWithContext(
121 [](const QtOhos::CallbackInfo &cbInfo, auto &resultConsumer) {
122 QtOhos::logJsCallbackError(cbInfo, "getSystemFontFullNamesByType() failed");
123 resultConsumer({});
124 });
125 });
126
127 QStringList result;
128 std::transform(
129 fontsPaths.begin(), fontsPaths.end(),
130 std::back_inserter(result), QString::fromStdString);
131 result.removeAll(QString());
132 result.sort();
133
134 return result;
135}
136
137std::string getDefaultFontFamily(QtOhos::JsState &jsState)
138{
139 if (ohosNoUiChildMode)
140 return "";
141
142 std::string defaultFontFamily;
143 auto genericFonts = jsState.eval<QNapi::Array>("@ohos.font.getUIFontConfig().generic");
144 if (genericFonts.Length() > 0) {
145 auto firstFont = QNapi::checkedCast<QNapi::Object>(genericFonts.Get(0U));
146 defaultFontFamily = firstFont.get<QNapi::String>("family");
147 } else {
148 qFatal("Failed to get system default font family name."
149 " The reason is: empty `@ohos.font.getUIFontConfig().generic` array.");
150 }
151
152 return defaultFontFamily;
153}
154
155void registerSystemFonts()
156{
157 QStringList fontPaths;
159 [&](auto &jsState) {
160 fontPaths.append(getSystemFontPaths(jsState));
161 fontPaths.append(getUIFontPaths(jsState));
162 });
163 fontPaths.append(getInstalledFontPaths());
164 fontPaths.removeDuplicates();
165
166 QSet<QString> uniqueFontDirs;
167 for (const QString &fontPath : fontPaths)
168 uniqueFontDirs.insert(QFileInfo(fontPath).absolutePath());
169
170 FcConfig *config = FcConfigGetCurrent();
171 if (config != nullptr) {
172 for (const QString &dir : uniqueFontDirs)
173 FcConfigAppFontAddDir(config, reinterpret_cast<const FcChar8 *>(dir.toUtf8().constData()));
174 FcConfigBuildFonts(config);
175 } else {
176 qOhosPrintfError("Failed to get fontconfig current configuration.");
177 std::abort();
178 }
179}
180
181}
182
184{
185 ohosNoUiChildMode = true;
186}
187
189{
190 FcInit();
191
192 registerSystemFonts();
193
194 QFontconfigDatabase::populateFontDatabase();
195}
196
198 QFont::Style style,
199 QFont::StyleHint styleHint,
200 QFontDatabasePrivate::ExtendedScript script) const
201{
202 QStringList result;
203
204 const QFontDatabase::WritingSystem ws = qt_writing_system_for_script(script);
205 const bool defaultFontSupportsScript =
206 ws == QFontDatabase::Any ||
207 QFontDatabase::writingSystems(defaultFont().family()).contains(ws);
208
209 if (defaultFontSupportsScript)
210 result.append(defaultFont().family());
211
212 if (styleHint == QFont::Monospace || styleHint == QFont::Courier)
213 result.append(QString::fromUtf8(qgetenv("Droid Sans Mono;Droid Sans;Noto Sans")).split(QLatin1Char(';')));
214 else if (styleHint == QFont::Serif)
215 result.append(QString::fromUtf8(qgetenv("Noto Serif")).split(QLatin1Char(';')));
216 else
217 result.append(QString::fromUtf8(qgetenv("Roboto;Droid Sans")).split(QLatin1Char(';')));
218 result.append(QFontconfigDatabase::fallbacksForFamily(family, style, styleHint, script));
219
220 return result;
221}
222
224{
225 static const char * const preferredDefaultFontFamily = "HarmonyOS Sans SC";
226 static const QString defaultFontFamily =
227 QFontDatabase::families().contains(QLatin1String(preferredDefaultFontFamily))
228 ? QString::fromStdString(preferredDefaultFontFamily)
229 : QtOhos::evalInJsThread(
230 [&](auto &jsState) {
231 return QString::fromStdString(getDefaultFontFamily(jsState));
232 });
233 return QFont(defaultFontFamily);
234}
235
236QT_END_NAMESPACE
QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QFontDatabasePrivate::ExtendedScript script) const override
Returns a list of alternative fonts for the specified family and style and script using the styleHint...
QFont defaultFont() const override
Returns the default system font.
void populateFontDatabase() override
This function is called once at startup by Qt's internal font database.
void runInJsThreadAndWait(const std::function< void(JsState &)> &task)
QDebug Q_GUI_EXPORT & operator<<(QDebug &s, const QVectorPath &path)