summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/platforms/wasm/qwasmfontdatabase.cpp278
-rw-r--r--src/plugins/platforms/wasm/qwasmfontdatabase.h24
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.cpp11
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.h3
4 files changed, 257 insertions, 59 deletions
diff --git a/src/plugins/platforms/wasm/qwasmfontdatabase.cpp b/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
index 83eee06ac0..1e166fa6ff 100644
--- a/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
+++ b/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
@@ -6,6 +6,7 @@
#include <QtCore/qfile.h>
#include <QtCore/private/qstdweb_p.h>
+#include <QtCore/private/qeventdispatcher_wasm_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <emscripten.h>
@@ -58,11 +59,6 @@ private:
val m_fontData;
};
-bool isLocalFontsAPISupported()
-{
- return val::global("window")["queryLocalFonts"].isUndefined() == false;
-}
-
val makeObject(const char *key, const char *value)
{
val obj = val::object();
@@ -70,37 +66,25 @@ val makeObject(const char *key, const char *value)
return obj;
}
-std::multimap<QString, FontData> makeFontFamilyMap(const QList<FontData> &fonts)
-{
- std::multimap<QString, FontData> fontFamilies;
- for (auto font : fonts)
- fontFamilies.insert(std::make_pair(font.family(), font));
- return fontFamilies;
-}
-
void printError(val err) {
qCWarning(lcQpaFonts)
<< QString::fromStdString(err["name"].as<std::string>())
<< QString::fromStdString(err["message"].as<std::string>());
+ QWasmFontDatabase::endAllFontFileLoading();
}
-std::array<const char *, 8> webSafeFontFamilies()
-{
- return {"Arial", "Verdana", "Tahoma", "Trebuchet", "Times New Roman",
- "Georgia", "Garamond", "Courier New"};
-}
-
-void checkFontAccessPermitted(std::function<void()> callback)
+void checkFontAccessPermitted(std::function<void(bool)> callback)
{
const val permissions = val::global("navigator")["permissions"];
- if (permissions.isUndefined())
+ if (permissions.isUndefined()) {
+ callback(false);
return;
+ }
qstdweb::Promise::make(permissions, "query", {
.thenFunc = [callback](val status) {
- if (status["state"].as<std::string>() == "granted")
- callback();
- }
+ callback(status["state"].as<std::string>() == "granted");
+ },
}, makeObject("name", "local-fonts"));
}
@@ -143,46 +127,144 @@ void readFont(FontData font, std::function<void(const QByteArray &)> callback)
});
}
+emscripten::val getLocalFontsConfigProperty(const char *name) {
+ emscripten::val qt = val::module_property("qt");
+ if (qt.isUndefined())
+ return emscripten::val();
+ emscripten::val localFonts = qt["localFonts"];
+ if (localFonts.isUndefined())
+ return emscripten::val();
+ return localFonts[name];
+};
+
+bool getLocalFontsBoolConfigPropertyWithDefault(const char *name, bool defaultValue) {
+ emscripten::val prop = getLocalFontsConfigProperty(name);
+ if (prop.isUndefined())
+ return defaultValue;
+ return prop.as<bool>();
+};
+
+QString getLocalFontsStringConfigPropertyWithDefault(const char *name, QString defaultValue) {
+ emscripten::val prop = getLocalFontsConfigProperty(name);
+ if (prop.isUndefined())
+ return defaultValue;
+ return QString::fromStdString(prop.as<std::string>());
+};
+
+QStringList getLocalFontsStringListConfigPropertyWithDefault(const char *name, QStringList defaultValue) {
+ emscripten::val array = getLocalFontsConfigProperty(name);
+ if (array.isUndefined())
+ return defaultValue;
+
+ QStringList list;
+ int size = array["length"].as<int>();
+ for (int i = 0; i < size; ++i) {
+ emscripten::val element = array.call<emscripten::val>("at", i);
+ QString string = QString::fromStdString(element.as<std::string>());
+ if (!string.isEmpty())
+ list.append(string);
+ }
+ return list;
+};
+
} // namespace
+QWasmFontDatabase::QWasmFontDatabase()
+:QFreeTypeFontDatabase()
+{
+ m_localFontsApiSupported = val::global("window")["queryLocalFonts"].isUndefined() == false;
+ if (m_localFontsApiSupported)
+ beginFontDatabaseStartupTask();
+}
+
+QWasmFontDatabase *QWasmFontDatabase::get()
+{
+ return static_cast<QWasmFontDatabase *>(QWasmIntegration::get()->fontDatabase());
+}
+
+// Populates the font database with local fonts. Will make the browser ask
+// the user for permission if needed. Does nothing if the Local Font Access API
+// is not supported.
void QWasmFontDatabase::populateLocalfonts()
{
- if (!isLocalFontsAPISupported())
+ // Decide which font families to populate based on user preferences
+ QStringList selectedLocalFontFamilies;
+ bool allFamilies = false;
+
+ switch (m_localFontFamilyLoadSet) {
+ case NoFontFamilies:
+ default:
+ // keep empty selectedLocalFontFamilies
+ break;
+ case DefaultFontFamilies: {
+ const QStringList webSafeFontFamilies =
+ {"Arial", "Verdana", "Tahoma", "Trebuchet", "Times New Roman",
+ "Georgia", "Garamond", "Courier New"};
+ selectedLocalFontFamilies = webSafeFontFamilies;
+ } break;
+ case AllFontFamilies:
+ allFamilies = true;
+ break;
+ }
+
+ selectedLocalFontFamilies += m_extraLocalFontFamilies;
+
+ if (selectedLocalFontFamilies.isEmpty() && !allFamilies) {
+ endAllFontFileLoading();
return;
+ }
- // Run the font population code if local font access has been
- // permitted. This does not request permission, since we are currently
- // starting up and should not display a permission request dialog at
- // this point.
- checkFontAccessPermitted([](){
- queryLocalFonts([](const QList<FontData> &fonts){
- auto fontFamilies = makeFontFamilyMap(fonts);
- // Populate some font families. We can't populate _all_ fonts as in-memory fonts,
- // since that would require several gigabytes of memory. Instead, populate
- // a subset of the available fonts.
- for (const QString &family: webSafeFontFamilies()) {
- auto fontsRange = fontFamilies.equal_range(family);
- if (fontsRange.first != fontsRange.second)
- QFreeTypeFontDatabase::registerFontFamily(family);
-
- for (auto it = fontsRange.first; it != fontsRange.second; ++it) {
- const FontData &font = it->second;
- readFont(font, [](const QByteArray &fontData){
- QFreeTypeFontDatabase::addTTFile(fontData, QByteArray());
- QWasmFontDatabase::notifyFontsChanged();
- });
- }
- }
+ populateLocalFontFamilies(selectedLocalFontFamilies, allFamilies);
+}
+
+namespace {
+ QStringList toStringList(emscripten::val array)
+ {
+ QStringList list;
+ int size = array["length"].as<int>();
+ for (int i = 0; i < size; ++i) {
+ emscripten::val element = array.call<emscripten::val>("at", i);
+ QString string = QString::fromStdString(element.as<std::string>());
+ if (!string.isEmpty())
+ list.append(string);
+ }
+ return list;
+ }
+}
+
+void QWasmFontDatabase::populateLocalFontFamilies(emscripten::val families)
+{
+ if (!m_localFontsApiSupported)
+ return;
+ populateLocalFontFamilies(toStringList(families), false);
+}
+
+void QWasmFontDatabase::populateLocalFontFamilies(const QStringList &fontFamilies, bool allFamilies)
+{
+ queryLocalFonts([fontFamilies, allFamilies](const QList<FontData> &fonts) {
+ refFontFileLoading();
+ QList<FontData> filteredFonts;
+ std::copy_if(fonts.begin(), fonts.end(), std::back_inserter(filteredFonts),
+ [fontFamilies, allFamilies](FontData fontData) {
+ return allFamilies || fontFamilies.contains(fontData.family());
});
+
+ for (const FontData &font: filteredFonts) {
+ refFontFileLoading();
+ readFont(font, [font](const QByteArray &fontData){
+ QFreeTypeFontDatabase::registerFontFamily(font.family());
+ QFreeTypeFontDatabase::addTTFile(fontData, QByteArray());
+ derefFontFileLoading();
+ });
+ }
+ derefFontFileLoading();
});
+
}
void QWasmFontDatabase::populateFontDatabase()
{
- // Load font file from resources. Currently
- // all fonts needs to be bundled with the nexe
- // as Qt resources.
-
+ // Load bundled font file from resources.
const QString fontFileNames[] = {
QStringLiteral(":/fonts/DejaVuSansMono.ttf"),
QStringLiteral(":/fonts/Vera.ttf"),
@@ -196,12 +278,44 @@ void QWasmFontDatabase::populateFontDatabase()
QFreeTypeFontDatabase::addTTFile(theFont.readAll(), fontFileName.toLatin1());
}
- populateLocalfonts();
+ // Get config options for controlling local fonts usage
+ m_queryLocalFontsPermission = getLocalFontsBoolConfigPropertyWithDefault("requestPermission", false);
+ QString fontFamilyLoadSet = getLocalFontsStringConfigPropertyWithDefault("familiesCollection", "DefaultFontFamilies");
+ m_extraLocalFontFamilies = getLocalFontsStringListConfigPropertyWithDefault("extraFamilies", QStringList());
+
+ if (fontFamilyLoadSet == "NoFontFamilies") {
+ m_localFontFamilyLoadSet = NoFontFamilies;
+ } else if (fontFamilyLoadSet == "DefaultFontFamilies") {
+ m_localFontFamilyLoadSet = DefaultFontFamilies;
+ } else if (fontFamilyLoadSet == "AllFontFamilies") {
+ m_localFontFamilyLoadSet = AllFontFamilies;
+ } else {
+ m_localFontFamilyLoadSet = NoFontFamilies;
+ qWarning() << "Unknown fontFamilyLoadSet value" << fontFamilyLoadSet;
+ }
+
+ if (!m_localFontsApiSupported)
+ return;
+
+ // Populate the font database with local fonts. Either try unconditianlly
+ // if displyaing a fonts permissions dialog at startup is allowed, or else
+ // only if we already have permission.
+ if (m_queryLocalFontsPermission) {
+ populateLocalfonts();
+ } else {
+ checkFontAccessPermitted([this](bool granted) {
+ if (granted)
+ populateLocalfonts();
+ else
+ endAllFontFileLoading();
+ });
+ }
}
QFontEngine *QWasmFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
{
- return QFreeTypeFontDatabase::fontEngine(fontDef, handle);
+ QFontEngine *fontEngine = QFreeTypeFontDatabase::fontEngine(fontDef, handle);
+ return fontEngine;
}
QStringList QWasmFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style,
@@ -232,10 +346,60 @@ QFont QWasmFontDatabase::defaultFont() const
return QFont("Bitstream Vera Sans"_L1);
}
-void QWasmFontDatabase::notifyFontsChanged()
+namespace {
+ int g_pendingFonts = 0;
+ bool g_fontStartupTaskCompleted = false;
+}
+
+// Registers font loading as a startup task, which makes Qt delay
+// sending onLoaded event until font loading has completed.
+void QWasmFontDatabase::beginFontDatabaseStartupTask()
+{
+ g_fontStartupTaskCompleted = false;
+ QEventDispatcherWasm::registerStartupTask();
+}
+
+// Ends the font loading startup task.
+void QWasmFontDatabase::endFontDatabaseStartupTask()
+{
+ if (!g_fontStartupTaskCompleted) {
+ g_fontStartupTaskCompleted = true;
+ QEventDispatcherWasm::completeStarupTask();
+ }
+}
+
+// Registers that a font file will be loaded.
+void QWasmFontDatabase::refFontFileLoading()
+{
+ g_pendingFonts += 1;
+}
+
+// Registers that one font file has been loaded, and sends notifactions
+// when all pending font files have been loaded.
+void QWasmFontDatabase::derefFontFileLoading()
{
- QFontCache::instance()->clear();
- emit qGuiApp->fontDatabaseChanged();
+ if (--g_pendingFonts <= 0) {
+ QFontCache::instance()->clear();
+ emit qGuiApp->fontDatabaseChanged();
+ endFontDatabaseStartupTask();
+ }
}
+// Unconditionally ends local font loading, for instance if there
+// are no fonts to load or if there was an unexpected error.
+void QWasmFontDatabase::endAllFontFileLoading()
+{
+ bool hadPandingfonts = g_pendingFonts > 0;
+ if (hadPandingfonts) {
+ // The hadPandingfonts counter might no longer be correct; disable counting
+ // and send notifications unconditionally.
+ g_pendingFonts = 0;
+ QFontCache::instance()->clear();
+ emit qGuiApp->fontDatabaseChanged();
+ }
+
+ endFontDatabaseStartupTask();
+}
+
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmfontdatabase.h b/src/plugins/platforms/wasm/qwasmfontdatabase.h
index 8a2936cb1d..a1c8f1ff48 100644
--- a/src/plugins/platforms/wasm/qwasmfontdatabase.h
+++ b/src/plugins/platforms/wasm/qwasmfontdatabase.h
@@ -6,11 +6,16 @@
#include <QtGui/private/qfreetypefontdatabase_p.h>
+#include <emscripten/val.h>
+
QT_BEGIN_NAMESPACE
class QWasmFontDatabase : public QFreeTypeFontDatabase
{
public:
+ QWasmFontDatabase();
+ static QWasmFontDatabase *get();
+
void populateFontDatabase() override;
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override;
QStringList fallbacksForFamily(const QString &family, QFont::Style style,
@@ -20,8 +25,25 @@ public:
QFont defaultFont() const override;
void populateLocalfonts();
+ void populateLocalFontFamilies(emscripten::val families);
+ void populateLocalFontFamilies(const QStringList &famliies, bool allFamilies);
+
+ static void beginFontDatabaseStartupTask();
+ static void endFontDatabaseStartupTask();
+ static void refFontFileLoading();
+ static void derefFontFileLoading();
+ static void endAllFontFileLoading();
- static void notifyFontsChanged();
+private:
+ bool m_localFontsApiSupported = false;
+ bool m_queryLocalFontsPermission = false;
+ enum FontFamilyLoadSet {
+ NoFontFamilies,
+ DefaultFontFamilies,
+ AllFontFamilies,
+ };
+ FontFamilyLoadSet m_localFontFamilyLoadSet;
+ QStringList m_extraLocalFontFamilies;
};
QT_END_NAMESPACE
#endif
diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp
index 778c769ae1..2fbb33eb2d 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.cpp
+++ b/src/plugins/platforms/wasm/qwasmintegration.cpp
@@ -66,6 +66,11 @@ static void resizeAllScreens(emscripten::val event)
QWasmIntegration::get()->resizeAllScreens();
}
+static void loadLocalFontFamilies(emscripten::val event)
+{
+ QWasmIntegration::get()->loadLocalFontFamilies(event);
+}
+
EMSCRIPTEN_BINDINGS(qtQWasmIntegraton)
{
function("qtSetContainerElements", &setContainerElements);
@@ -74,6 +79,7 @@ EMSCRIPTEN_BINDINGS(qtQWasmIntegraton)
function("qtResizeContainerElement", &resizeContainerElement);
function("qtUpdateDpi", &qtUpdateDpi);
function("qtResizeAllScreens", &resizeAllScreens);
+ function("qtLoadLocalFontFamilies", &loadLocalFontFamilies);
}
QWasmIntegration *QWasmIntegration::s_instance;
@@ -395,6 +401,11 @@ void QWasmIntegration::resizeAllScreens()
elementAndScreen.wasmScreen->updateQScreenAndCanvasRenderSize();
}
+void QWasmIntegration::loadLocalFontFamilies(emscripten::val families)
+{
+ m_fontDb->populateLocalFontFamilies(families);
+}
+
quint64 QWasmIntegration::getTimestamp()
{
return emscripten_performance_now();
diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h
index 8dfa065d9c..b966487760 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.h
+++ b/src/plugins/platforms/wasm/qwasmintegration.h
@@ -74,8 +74,9 @@ public:
void addContainerElement(emscripten::val elementArray);
void removeContainerElement(emscripten::val elementArray);
void resizeScreen(const emscripten::val &canvas);
- void resizeAllScreens();
void updateDpi();
+ void resizeAllScreens();
+ void loadLocalFontFamilies(emscripten::val families);
void removeBackingStore(QWindow* window);
static quint64 getTimestamp();