summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/plugins/platforms/wasm/qwasmfontdatabase.cpp218
-rw-r--r--src/plugins/platforms/wasm/qwasmfontdatabase.h3
2 files changed, 127 insertions, 94 deletions
diff --git a/src/plugins/platforms/wasm/qwasmfontdatabase.cpp b/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
index 5fdaae8f84a..c0833a65ca2 100644
--- a/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
+++ b/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
@@ -12,126 +12,158 @@
#include <emscripten/val.h>
#include <emscripten/bind.h>
+#include <map>
+#include <array>
+
QT_BEGIN_NAMESPACE
using namespace emscripten;
using namespace Qt::StringLiterals;
-void QWasmFontDatabase::populateFontDatabase()
+
+namespace {
+
+bool isLocalFontsAPISupported()
{
- // Load font file from resources. Currently
- // all fonts needs to be bundled with the nexe
- // as Qt resources.
+ return val::global("window")["queryLocalFonts"].isUndefined() == false;
+}
- const QString fontFileNames[] = {
- QStringLiteral(":/fonts/DejaVuSansMono.ttf"),
- QStringLiteral(":/fonts/Vera.ttf"),
- QStringLiteral(":/fonts/DejaVuSans.ttf"),
- };
- for (const QString &fontFileName : fontFileNames) {
- QFile theFont(fontFileName);
- if (!theFont.open(QIODevice::ReadOnly))
- break;
+val makeObject(const char *key, const char *value)
+{
+ val obj = val::object();
+ obj.set(key, std::string(value));
+ return obj;
+}
- QFreeTypeFontDatabase::addTTFile(theFont.readAll(), fontFileName.toLatin1());
+std::multimap<QString, emscripten::val> makeFontFamilyMap(const QList<val> &fonts)
+{
+ std::multimap<QString, emscripten::val> fontFamilies;
+ for (auto font : fonts) {
+ QString family = QString::fromStdString(font["family"].as<std::string>());
+ fontFamilies.insert(std::make_pair(family, font));
}
+ return fontFamilies;
+}
- // check if local-fonts API is available in the browser
- val window = val::global("window");
- val fonts = window["queryLocalFonts"];
+void printError(val err) {
+ qCWarning(lcQpaFonts)
+ << QString::fromStdString(err["name"].as<std::string>())
+ << QString::fromStdString(err["message"].as<std::string>());
+}
- if (fonts.isUndefined())
- return;
+std::array<const char *, 8> webSafeFontFamilies()
+{
+ return {"Arial", "Verdana", "Tahoma", "Trebuchet", "Times New Roman",
+ "Georgia", "Garamond", "Courier New"};
+}
- val permissions = val::global("navigator")["permissions"];
- if (permissions["request"].isUndefined())
+void checkFontAccessPermitted(std::function<void()> callback)
+{
+ const val permissions = val::global("navigator")["permissions"];
+ if (permissions.isUndefined())
return;
- val requestLocalFontsPermission = val::object();
- requestLocalFontsPermission.set("name", std::string("local-fonts"));
-
- qstdweb::PromiseCallbacks permissionRequestCallbacks {
- .thenFunc = [window](val status) {
- qCDebug(lcQpaFonts) << "onFontPermissionSuccess:"
- << QString::fromStdString(status["state"].as<std::string>());
-
- // query all available local fonts and call registerFontFamily for each of them
- qstdweb::Promise::make(window, "queryLocalFonts", {
- .thenFunc = [](val status) {
- const int count = status["length"].as<int>();
- for (int i = 0; i < count; ++i) {
- val font = status.call<val>("at", i);
- const std::string family = font["family"].as<std::string>();
- QFreeTypeFontDatabase::registerFontFamily(QString::fromStdString(family));
- }
- QWasmFontDatabase::notifyFontsChanged();
- },
- .catchFunc = [](val) {
- qCWarning(lcQpaFonts)
- << "Error while trying to query local-fonts API";
- }
- });
- },
- .catchFunc = [](val error) {
- qCWarning(lcQpaFonts)
- << "Error while requesting local-fonts API permission: "
- << QString::fromStdString(error["name"].as<std::string>());
+ qstdweb::Promise::make(permissions, "query", {
+ .thenFunc = [callback](val status) {
+ if (status["state"].as<std::string>() == "granted")
+ callback();
}
- };
-
- // request local fonts permission (currently supported only by Chrome 103+)
- qstdweb::Promise::make(permissions, "request", std::move(permissionRequestCallbacks), std::move(requestLocalFontsPermission));
+ }, makeObject("name", "local-fonts"));
}
-void QWasmFontDatabase::populateFamily(const QString &familyName)
+void queryLocalFonts(std::function<void(const QList<val> &)> callback)
{
- val window = val::global("window");
-
- auto queryFontsArgument = val::array(std::vector<val>({ val(familyName.toStdString()) }));
- val queryFont = val::object();
- queryFont.set("postscriptNames", std::move(queryFontsArgument));
-
- qstdweb::PromiseCallbacks localFontsQueryCallback {
- .thenFunc = [](val status) {
- val font = status.call<val>("at", 0);
-
- if (font.isUndefined())
- return;
-
- qstdweb::PromiseCallbacks blobQueryCallback {
- .thenFunc = [](val status) {
- qCDebug(lcQpaFonts) << "onBlobQuerySuccess";
+ emscripten::val window = emscripten::val::global("window");
+ qstdweb::Promise::make(window, "queryLocalFonts", {
+ .thenFunc = [callback](emscripten::val fontArray) {
+ QList<val> fonts;
+ const int count = fontArray["length"].as<int>();
+ fonts.reserve(count);
+ for (int i = 0; i < count; ++i)
+ fonts.append(fontArray.call<emscripten::val>("at", i));
+ callback(fonts);
+ },
+ .catchFunc = printError
+ });
+}
- qstdweb::PromiseCallbacks arrayBufferCallback {
- .thenFunc = [](val status) {
- qCDebug(lcQpaFonts) << "onArrayBuffer" ;
+void readBlob(val blob, std::function<void(const QByteArray &)> callback)
+{
+ qstdweb::Promise::make(blob, "arrayBuffer", {
+ .thenFunc = [callback](emscripten::val fontArrayBuffer) {
+ QByteArray fontData = qstdweb::Uint8Array(qstdweb::ArrayBuffer(fontArrayBuffer)).copyToQByteArray();
+ callback(fontData);
+ },
+ .catchFunc = printError
+ });
+}
- QByteArray fontByteArray = QByteArray::fromEcmaUint8Array(status);
+void readFont(val font, std::function<void(const QByteArray &)> callback)
+{
+ qstdweb::Promise::make(font, "blob", {
+ .thenFunc = [callback](val blob) {
+ readBlob(blob, [callback](const QByteArray &data) {
+ callback(data);
+ });
+ },
+ .catchFunc = printError
+ });
+}
- QFreeTypeFontDatabase::addTTFile(fontByteArray, QByteArray());
+} // namespace
- QWasmFontDatabase::notifyFontsChanged();
- },
- .catchFunc = [](val) {
- qCWarning(lcQpaFonts) << "onArrayBufferError";
- }
- };
+void QWasmFontDatabase::populateLocalfonts()
+{
+ if (!isLocalFontsAPISupported())
+ return;
- qstdweb::Promise::make(status, "arrayBuffer", std::move(arrayBufferCallback));
- },
- .catchFunc = [](val) {
- qCWarning(lcQpaFonts) << "onBlobQueryError";
+ // 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<val> &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 val font = it->second;
+ readFont(font, [](const QByteArray &fontData){
+ QFreeTypeFontDatabase::addTTFile(fontData, QByteArray());
+ QWasmFontDatabase::notifyFontsChanged();
+ });
}
- };
+ }
+ });
+ });
+}
- qstdweb::Promise::make(font, "blob", std::move(blobQueryCallback));
- },
- .catchFunc = [](val) {
- qCWarning(lcQpaFonts) << "onLocalFontsQueryError";
- }
+void QWasmFontDatabase::populateFontDatabase()
+{
+ // Load font file from resources. Currently
+ // all fonts needs to be bundled with the nexe
+ // as Qt resources.
+
+ const QString fontFileNames[] = {
+ QStringLiteral(":/fonts/DejaVuSansMono.ttf"),
+ QStringLiteral(":/fonts/Vera.ttf"),
+ QStringLiteral(":/fonts/DejaVuSans.ttf"),
};
+ for (const QString &fontFileName : fontFileNames) {
+ QFile theFont(fontFileName);
+ if (!theFont.open(QIODevice::ReadOnly))
+ break;
+
+ QFreeTypeFontDatabase::addTTFile(theFont.readAll(), fontFileName.toLatin1());
+ }
- qstdweb::Promise::make(window, "queryLocalFonts", std::move(localFontsQueryCallback), std::move(queryFont));
+ populateLocalfonts();
}
QFontEngine *QWasmFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
diff --git a/src/plugins/platforms/wasm/qwasmfontdatabase.h b/src/plugins/platforms/wasm/qwasmfontdatabase.h
index 22c550f2445..8a2936cb1d7 100644
--- a/src/plugins/platforms/wasm/qwasmfontdatabase.h
+++ b/src/plugins/platforms/wasm/qwasmfontdatabase.h
@@ -12,7 +12,6 @@ class QWasmFontDatabase : public QFreeTypeFontDatabase
{
public:
void populateFontDatabase() override;
- void populateFamily(const QString &familyName) override;
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override;
QStringList fallbacksForFamily(const QString &family, QFont::Style style,
QFont::StyleHint styleHint,
@@ -20,6 +19,8 @@ public:
void releaseHandle(void *handle) override;
QFont defaultFont() const override;
+ void populateLocalfonts();
+
static void notifyFontsChanged();
};
QT_END_NAMESPACE