7#include <QtCore/qfile.h>
8#include <QtCore/private/qstdweb_p.h>
9#include <QtCore/private/qeventdispatcher_wasm_p.h>
10#include <QtGui/private/qguiapplication_p.h>
12#include <emscripten.h>
13#include <emscripten/val.h>
14#include <emscripten/bind.h>
21using namespace emscripten;
22using namespace Qt::StringLiterals;
30 FontData(val fontData)
31 :m_fontData(fontData) {}
33 QString family()
const
35 return QString::fromStdString(m_fontData[
"family"].as<std::string>());
38 QString fullName()
const
40 return QString::fromStdString(m_fontData[
"fullName"].as<std::string>());
43 QString postscriptName()
const
45 return QString::fromStdString(m_fontData[
"postscriptName"].as<std::string>());
50 return QString::fromStdString(m_fontData[
"style"].as<std::string>());
62val makeObject(
const char *key,
const char *value)
64 val obj = val::object();
65 obj.set(key, std::string(value));
69void printError(val err) {
71 << QString::fromStdString(err[
"name"].as<std::string>())
72 << QString::fromStdString(err[
"message"].as<std::string>());
73 QWasmFontDatabase::endAllFontFileLoading();
76void checkFontAccessPermitted(
std::function<
void(
bool)> callback)
78 const val permissions = val::global(
"navigator")[
"permissions"];
79 if (permissions.isUndefined()) {
84 qstdweb::Promise::make(permissions,
"query", {
85 .thenFunc = [callback](val status) {
86 callback(status[
"state"].as<std::string>() ==
"granted");
88 }, makeObject(
"name",
"local-fonts"));
91void queryLocalFonts(
std::function<
void(
const QList<FontData> &)> callback)
93 emscripten::val window = emscripten::val::global(
"window");
94 qstdweb::Promise::make(window,
"queryLocalFonts", {
95 .thenFunc = [callback](emscripten::val fontArray) {
96 QList<FontData> fonts;
97 const int count = fontArray[
"length"].as<
int>();
99 for (
int i = 0; i < count; ++i)
100 fonts.append(FontData(fontArray.call<emscripten::val>(
"at", i)));
103 .catchFunc = printError
107void readBlob(val blob,
std::function<
void(
const QByteArray &)> callback)
109 qstdweb::Promise::make(blob,
"arrayBuffer", {
110 .thenFunc = [callback](emscripten::val fontArrayBuffer) {
111 QByteArray fontData = qstdweb::Uint8Array(qstdweb::ArrayBuffer(fontArrayBuffer)).copyToQByteArray();
114 .catchFunc = printError
118void readFont(FontData font,
std::function<
void(
const QByteArray &)> callback)
120 qstdweb::Promise::make(font.value(),
"blob", {
121 .thenFunc = [callback](val blob) {
122 readBlob(blob, [callback](
const QByteArray &data) {
126 .catchFunc = printError
130emscripten::val getLocalFontsConfigProperty(
const char *name) {
131 emscripten::val qt = val::module_property(
"qt");
132 if (qt.isUndefined())
133 return emscripten::val();
134 emscripten::val localFonts = qt[
"localFonts"];
135 if (localFonts.isUndefined())
136 return emscripten::val();
137 return localFonts[name];
140bool getLocalFontsBoolConfigPropertyWithDefault(
const char *name,
bool defaultValue) {
141 emscripten::val prop = getLocalFontsConfigProperty(name);
142 if (prop.isUndefined())
144 return prop.as<
bool>();
147QString getLocalFontsStringConfigPropertyWithDefault(
const char *name, QString defaultValue) {
148 emscripten::val prop = getLocalFontsConfigProperty(name);
149 if (prop.isUndefined())
151 return QString::fromStdString(prop.as<std::string>());
154QStringList getLocalFontsStringListConfigPropertyWithDefault(
const char *name, QStringList defaultValue) {
155 emscripten::val array = getLocalFontsConfigProperty(name);
156 if (array.isUndefined())
160 int size = array[
"length"].as<
int>();
161 for (
int i = 0; i < size; ++i) {
162 emscripten::val element = array.call<emscripten::val>(
"at", i);
163 QString string = QString::fromStdString(element.as<std::string>());
164 if (!string.isEmpty())
172QWasmFontDatabase::QWasmFontDatabase()
173:QFreeTypeFontDatabase()
175 m_localFontsApiSupported = val::global(
"window")[
"queryLocalFonts"].isUndefined() ==
false;
176 if (m_localFontsApiSupported)
177 beginFontDatabaseStartupTask();
180QWasmFontDatabase *QWasmFontDatabase::get()
188void QWasmFontDatabase::populateLocalfonts()
191 QStringList selectedLocalFontFamilies;
192 bool allFamilies =
false;
194 switch (m_localFontFamilyLoadSet) {
199 case DefaultFontFamilies: {
200 const QStringList webSafeFontFamilies =
201 {
"Arial",
"Verdana",
"Tahoma",
"Trebuchet",
"Times New Roman",
202 "Georgia",
"Garamond",
"Courier New"};
203 selectedLocalFontFamilies = webSafeFontFamilies;
205 case AllFontFamilies:
210 selectedLocalFontFamilies += m_extraLocalFontFamilies;
212 if (selectedLocalFontFamilies.isEmpty() && !allFamilies) {
213 endAllFontFileLoading();
217 populateLocalFontFamilies(selectedLocalFontFamilies, allFamilies);
221 QStringList toStringList(
emscripten::val array)
224 int size = array[
"length"].as<
int>();
225 for (
int i = 0; i < size; ++i) {
226 emscripten::val element = array.call<emscripten::val>(
"at", i);
227 QString string = QString::fromStdString(element.as<std::string>());
228 if (!string.isEmpty())
235void QWasmFontDatabase::populateLocalFontFamilies(
emscripten::val families)
237 if (!m_localFontsApiSupported)
239 populateLocalFontFamilies(toStringList(families),
false);
242void QWasmFontDatabase::populateLocalFontFamilies(
const QStringList &fontFamilies,
bool allFamilies)
244 queryLocalFonts([fontFamilies, allFamilies](
const QList<FontData> &fonts) {
245 refFontFileLoading();
246 QList<FontData> filteredFonts;
247 std::copy_if(fonts.begin(), fonts.end(), std::back_inserter(filteredFonts),
248 [fontFamilies, allFamilies](FontData fontData) {
249 return allFamilies || fontFamilies.contains(fontData.family());
252 for (
const FontData &font: filteredFonts) {
253 refFontFileLoading();
254 readFont(font, [font](
const QByteArray &fontData){
255 QFreeTypeFontDatabase::registerFontFamily(font.family());
256 QFreeTypeFontDatabase::addTTFile(fontData, QByteArray());
257 derefFontFileLoading();
260 derefFontFileLoading();
265void QWasmFontDatabase::populateFontDatabase()
268 const QString fontFileNames[] = {
269 QStringLiteral(
":/fonts/DejaVuSansMono.ttf"),
270 QStringLiteral(
":/fonts/DejaVuSans.ttf"),
272 for (
const QString &fontFileName : fontFileNames) {
273 QFile theFont(fontFileName);
274 if (!theFont.open(QIODevice::ReadOnly))
277 QFreeTypeFontDatabase::addTTFile(theFont.readAll(), fontFileName.toLatin1());
281 m_queryLocalFontsPermission = getLocalFontsBoolConfigPropertyWithDefault(
"requestPermission",
false);
282 QString fontFamilyLoadSet = getLocalFontsStringConfigPropertyWithDefault(
"familiesCollection",
"DefaultFontFamilies");
283 m_extraLocalFontFamilies = getLocalFontsStringListConfigPropertyWithDefault(
"extraFamilies", QStringList());
285 if (fontFamilyLoadSet ==
"NoFontFamilies") {
286 m_localFontFamilyLoadSet = NoFontFamilies;
287 }
else if (fontFamilyLoadSet ==
"DefaultFontFamilies") {
288 m_localFontFamilyLoadSet = DefaultFontFamilies;
289 }
else if (fontFamilyLoadSet ==
"AllFontFamilies") {
290 m_localFontFamilyLoadSet = AllFontFamilies;
292 m_localFontFamilyLoadSet = NoFontFamilies;
293 qWarning() <<
"Unknown fontFamilyLoadSet value" << fontFamilyLoadSet;
296 if (!m_localFontsApiSupported)
302 if (m_queryLocalFontsPermission) {
303 populateLocalfonts();
305 checkFontAccessPermitted([
this](
bool granted) {
307 populateLocalfonts();
309 endAllFontFileLoading();
314QFontEngine *QWasmFontDatabase::fontEngine(
const QFontDef &fontDef,
void *handle)
316 QFontEngine *fontEngine = QFreeTypeFontDatabase::fontEngine(fontDef, handle);
320QStringList QWasmFontDatabase::fallbacksForFamily(
const QString &family, QFont::Style style,
321 QFont::StyleHint styleHint,
322 QFontDatabasePrivate::ExtendedScript script)
const
324 QStringList fallbacks
325 = QFreeTypeFontDatabase::fallbacksForFamily(family, style, styleHint, script);
329 static const QString wasmFallbackFonts[] = {
"DejaVu Sans" };
330 for (
auto wasmFallbackFont : wasmFallbackFonts) {
331 if (family != wasmFallbackFont && !fallbacks.contains(wasmFallbackFont))
332 fallbacks.append(wasmFallbackFont);
338void QWasmFontDatabase::releaseHandle(
void *handle)
340 QFreeTypeFontDatabase::releaseHandle(handle);
343QFont QWasmFontDatabase::defaultFont()
const
345 return QFont(
"DejaVu Sans"_L1);
349 int g_pendingFonts = 0;
350 bool g_fontStartupTaskCompleted =
false;
355void QWasmFontDatabase::beginFontDatabaseStartupTask()
357 g_fontStartupTaskCompleted =
false;
358 QEventDispatcherWasm::registerStartupTask();
362void QWasmFontDatabase::endFontDatabaseStartupTask()
364 if (!g_fontStartupTaskCompleted) {
365 g_fontStartupTaskCompleted =
true;
366 QEventDispatcherWasm::completeStarupTask();
371void QWasmFontDatabase::refFontFileLoading()
378void QWasmFontDatabase::derefFontFileLoading()
380 if (--g_pendingFonts <= 0) {
381 QFontCache::instance()->clear();
382 emit qGuiApp->fontDatabaseChanged();
383 endFontDatabaseStartupTask();
389void QWasmFontDatabase::endAllFontFileLoading()
391 bool hadPandingfonts = g_pendingFonts > 0;
392 if (hadPandingfonts) {
396 QFontCache::instance()->clear();
397 emit qGuiApp->fontDatabaseChanged();
400 endFontDatabaseStartupTask();
static QWasmIntegration * get()