8#include <QtCore/qfile.h>
9#include <QtCore/private/qstdweb_p.h>
10#include <QtCore/private/qeventdispatcher_wasm_p.h>
11#include <QtGui/private/qguiapplication_p.h>
13#include <emscripten.h>
14#include <emscripten/val.h>
15#include <emscripten/bind.h>
22using namespace emscripten;
23using namespace Qt::StringLiterals;
31 FontData(val fontData)
32 :m_fontData(fontData) {}
34 QString family()
const
36 return QString::fromStdString(m_fontData[
"family"].as<std::string>());
39 QString fullName()
const
41 return QString::fromStdString(m_fontData[
"fullName"].as<std::string>());
44 QString postscriptName()
const
46 return QString::fromStdString(m_fontData[
"postscriptName"].as<std::string>());
51 return QString::fromStdString(m_fontData[
"style"].as<std::string>());
63val makeObject(
const char *key,
const char *value)
65 val obj = val::object();
66 obj.set(key, std::string(value));
70void printError(val err) {
72 << QString::fromStdString(err[
"name"].as<std::string>())
73 << QString::fromStdString(err[
"message"].as<std::string>());
74 QWasmFontDatabase::endAllFontFileLoading();
77void checkFontAccessPermitted(
std::function<
void(
bool)> callback)
79 const val permissions = val::global(
"navigator")[
"permissions"];
80 if (permissions.isUndefined()) {
85 qstdweb::Promise::make(permissions,
"query", {
86 .thenFunc = [callback](val status) {
87 callback(status[
"state"].as<std::string>() ==
"granted");
89 }, makeObject(
"name",
"local-fonts"));
92void queryLocalFonts(
std::function<
void(
const QList<FontData> &)> callback)
94 emscripten::val window = emscripten::val::global(
"window");
95 qstdweb::Promise::make(window,
"queryLocalFonts", {
96 .thenFunc = [callback](emscripten::val fontArray) {
97 QList<FontData> fonts;
98 const int count = fontArray[
"length"].as<
int>();
100 for (
int i = 0; i < count; ++i)
101 fonts.append(FontData(fontArray.call<emscripten::val>(
"at", i)));
104 .catchFunc = printError
108void readBlob(val blob,
std::function<
void(
const QByteArray &)> callback)
110 qstdweb::Promise::make(blob,
"arrayBuffer", {
111 .thenFunc = [callback](emscripten::val fontArrayBuffer) {
112 QByteArray fontData = qstdweb::Uint8Array(qstdweb::ArrayBuffer(fontArrayBuffer)).copyToQByteArray();
115 .catchFunc = printError
119void readFont(FontData font,
std::function<
void(
const QByteArray &)> callback)
121 qstdweb::Promise::make(font.value(),
"blob", {
122 .thenFunc = [callback](val blob) {
123 readBlob(blob, [callback](
const QByteArray &data) {
127 .catchFunc = printError
131emscripten::val getLocalFontsConfigProperty(
const char *name) {
132 emscripten::val qt = val::module_property(
"qt");
133 if (qt.isUndefined())
134 return emscripten::val();
135 emscripten::val localFonts = qt[
"localFonts"];
136 if (localFonts.isUndefined())
137 return emscripten::val();
138 return localFonts[name];
141bool getLocalFontsBoolConfigPropertyWithDefault(
const char *name,
bool defaultValue) {
142 emscripten::val prop = getLocalFontsConfigProperty(name);
143 if (prop.isUndefined())
145 return prop.as<
bool>();
148QString getLocalFontsStringConfigPropertyWithDefault(
const char *name, QString defaultValue) {
149 emscripten::val prop = getLocalFontsConfigProperty(name);
150 if (prop.isUndefined())
152 return QString::fromStdString(prop.as<std::string>());
155QStringList getLocalFontsStringListConfigPropertyWithDefault(
const char *name, QStringList defaultValue) {
156 emscripten::val array = getLocalFontsConfigProperty(name);
157 if (array.isUndefined())
161 int size = array[
"length"].as<
int>();
162 for (
int i = 0; i < size; ++i) {
163 emscripten::val element = array.call<emscripten::val>(
"at", i);
164 QString string = QString::fromStdString(element.as<std::string>());
165 if (!string.isEmpty())
173QWasmFontDatabase::QWasmFontDatabase()
174:QFreeTypeFontDatabase()
176 m_localFontsApiSupported = val::global(
"window")[
"queryLocalFonts"].isUndefined() ==
false;
179QWasmFontDatabase *QWasmFontDatabase::get()
187void QWasmFontDatabase::populateLocalfonts()
190 QStringList selectedLocalFontFamilies;
191 bool allFamilies =
false;
193 switch (m_localFontFamilyLoadSet) {
198 case DefaultFontFamilies: {
199 const QStringList webSafeFontFamilies =
200 {
"Arial",
"Verdana",
"Tahoma",
"Trebuchet",
"Times New Roman",
201 "Georgia",
"Garamond",
"Courier New"};
202 selectedLocalFontFamilies = webSafeFontFamilies;
204 case AllFontFamilies:
209 selectedLocalFontFamilies += m_extraLocalFontFamilies;
211 if (selectedLocalFontFamilies.isEmpty() && !allFamilies) {
212 endAllFontFileLoading();
216 populateLocalFontFamilies(selectedLocalFontFamilies, allFamilies);
220 QStringList toStringList(
emscripten::val array)
223 int size = array[
"length"].as<
int>();
224 for (
int i = 0; i < size; ++i) {
225 emscripten::val element = array.call<emscripten::val>(
"at", i);
226 QString string = QString::fromStdString(element.as<std::string>());
227 if (!string.isEmpty())
234void QWasmFontDatabase::populateLocalFontFamilies(
emscripten::val families)
236 if (!m_localFontsApiSupported)
238 populateLocalFontFamilies(toStringList(families),
false);
241void QWasmFontDatabase::populateLocalFontFamilies(
const QStringList &fontFamilies,
bool allFamilies)
243 queryLocalFonts([fontFamilies, allFamilies](
const QList<FontData> &fonts) {
244 refFontFileLoading();
245 QList<FontData> filteredFonts;
246 std::copy_if(fonts.begin(), fonts.end(), std::back_inserter(filteredFonts),
247 [fontFamilies, allFamilies](FontData fontData) {
248 return allFamilies || fontFamilies.contains(fontData.family());
251 for (
const FontData &font: filteredFonts) {
252 refFontFileLoading();
253 readFont(font, [font](
const QByteArray &fontData){
254 QFreeTypeFontDatabase::registerFontFamily(font.family());
255 QFreeTypeFontDatabase::addTTFile(fontData, QByteArray());
256 derefFontFileLoading();
259 derefFontFileLoading();
264void QWasmFontDatabase::populateFontDatabase()
267 const QString fontFileNames[] = {
268 QStringLiteral(
":/fonts/DejaVuSansMono.ttf"),
269 QStringLiteral(
":/fonts/DejaVuSans.ttf"),
271 for (
const QString &fontFileName : fontFileNames) {
272 QFile theFont(fontFileName);
273 if (!theFont.open(QIODevice::ReadOnly))
276 QFreeTypeFontDatabase::addTTFile(theFont.readAll(), fontFileName.toLatin1());
280 m_queryLocalFontsPermission = getLocalFontsBoolConfigPropertyWithDefault(
"requestPermission",
false);
281 QString fontFamilyLoadSet = getLocalFontsStringConfigPropertyWithDefault(
"familiesCollection",
"DefaultFontFamilies");
282 m_extraLocalFontFamilies = getLocalFontsStringListConfigPropertyWithDefault(
"extraFamilies", QStringList());
284 if (fontFamilyLoadSet ==
"NoFontFamilies") {
285 m_localFontFamilyLoadSet = NoFontFamilies;
286 }
else if (fontFamilyLoadSet ==
"DefaultFontFamilies") {
287 m_localFontFamilyLoadSet = DefaultFontFamilies;
288 }
else if (fontFamilyLoadSet ==
"AllFontFamilies") {
289 m_localFontFamilyLoadSet = AllFontFamilies;
291 m_localFontFamilyLoadSet = NoFontFamilies;
292 qWarning() <<
"Unknown fontFamilyLoadSet value" << fontFamilyLoadSet;
295 if (!m_localFontsApiSupported)
301 if (m_queryLocalFontsPermission) {
302 populateLocalfonts();
304 checkFontAccessPermitted([
this](
bool granted) {
306 populateLocalfonts();
308 endAllFontFileLoading();
313QFontEngine *QWasmFontDatabase::fontEngine(
const QFontDef &fontDef,
void *handle)
315 QFontEngine *fontEngine = QFreeTypeFontDatabase::fontEngine(fontDef, handle);
319QStringList QWasmFontDatabase::fallbacksForFamily(
const QString &family, QFont::Style style,
320 QFont::StyleHint styleHint,
321 QFontDatabasePrivate::ExtendedScript script)
const
323 QStringList fallbacks
324 = QFreeTypeFontDatabase::fallbacksForFamily(family, style, styleHint, script);
328 static const QString wasmFallbackFonts[] = {
"DejaVu Sans" };
329 for (
auto wasmFallbackFont : wasmFallbackFonts) {
330 if (family != wasmFallbackFont && !fallbacks.contains(wasmFallbackFont))
331 fallbacks.append(wasmFallbackFont);
337void QWasmFontDatabase::releaseHandle(
void *handle)
339 QFreeTypeFontDatabase::releaseHandle(handle);
342QFont QWasmFontDatabase::defaultFont()
const
344 return QFont(
"DejaVu Sans"_L1);
348 int g_pendingFonts = 0;
352void QWasmFontDatabase::refFontFileLoading()
359void QWasmFontDatabase::derefFontFileLoading()
361 if (--g_pendingFonts <= 0) {
362 QFontCache::instance()->clear();
363 emit qGuiApp->fontDatabaseChanged();
369void QWasmFontDatabase::endAllFontFileLoading()
371 bool hadPandingfonts = g_pendingFonts > 0;
372 if (hadPandingfonts) {
376 QFontCache::instance()->clear();
377 emit qGuiApp->fontDatabaseChanged();
static QWasmIntegration * get()