Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qwasmfontdatabase.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qwasmfontdatabase.h"
5#include "qwasmintegration.h"
6
7#include <QtCore/qfile.h>
8#include <QtCore/private/qstdweb_p.h>
9#include <QtGui/private/qguiapplication_p.h>
10
11#include <emscripten.h>
12#include <emscripten/val.h>
13#include <emscripten/bind.h>
14
15#include <map>
16#include <array>
17
19
20using namespace emscripten;
21using namespace Qt::StringLiterals;
22
23
24namespace {
25
26bool isLocalFontsAPISupported()
27{
28 return val::global("window")["queryLocalFonts"].isUndefined() == false;
29}
30
31val makeObject(const char *key, const char *value)
32{
33 val obj = val::object();
34 obj.set(key, std::string(value));
35 return obj;
36}
37
38std::multimap<QString, emscripten::val> makeFontFamilyMap(const QList<val> &fonts)
39{
40 std::multimap<QString, emscripten::val> fontFamilies;
41 for (auto font : fonts) {
42 QString family = QString::fromStdString(font["family"].as<std::string>());
43 fontFamilies.insert(std::make_pair(family, font));
44 }
45 return fontFamilies;
46}
47
48void printError(val err) {
49 qCWarning(lcQpaFonts)
50 << QString::fromStdString(err["name"].as<std::string>())
51 << QString::fromStdString(err["message"].as<std::string>());
52}
53
54std::array<const char *, 8> webSafeFontFamilies()
55{
56 return {"Arial", "Verdana", "Tahoma", "Trebuchet", "Times New Roman",
57 "Georgia", "Garamond", "Courier New"};
58}
59
60void checkFontAccessPermitted(std::function<void()> callback)
61{
62 const val permissions = val::global("navigator")["permissions"];
63 if (permissions.isUndefined())
64 return;
65
66 qstdweb::Promise::make(permissions, "query", {
67 .thenFunc = [callback](val status) {
68 if (status["state"].as<std::string>() == "granted")
69 callback();
70 }
71 }, makeObject("name", "local-fonts"));
72}
73
74void queryLocalFonts(std::function<void(const QList<val> &)> callback)
75{
76 emscripten::val window = emscripten::val::global("window");
77 qstdweb::Promise::make(window, "queryLocalFonts", {
78 .thenFunc = [callback](emscripten::val fontArray) {
79 QList<val> fonts;
80 const int count = fontArray["length"].as<int>();
81 fonts.reserve(count);
82 for (int i = 0; i < count; ++i)
83 fonts.append(fontArray.call<emscripten::val>("at", i));
84 callback(fonts);
85 },
86 .catchFunc = printError
87 });
88}
89
90void readBlob(val blob, std::function<void(const QByteArray &)> callback)
91{
92 qstdweb::Promise::make(blob, "arrayBuffer", {
93 .thenFunc = [callback](emscripten::val fontArrayBuffer) {
95 callback(fontData);
96 },
97 .catchFunc = printError
98 });
99}
100
101void readFont(val font, std::function<void(const QByteArray &)> callback)
102{
104 .thenFunc = [callback](val blob) {
105 readBlob(blob, [callback](const QByteArray &data) {
106 callback(data);
107 });
108 },
109 .catchFunc = printError
110 });
111}
112
113} // namespace
114
116{
117 if (!isLocalFontsAPISupported())
118 return;
119
120 // Run the font population code if local font access has been
121 // permitted. This does not request permission, since we are currently
122 // starting up and should not display a permission request dialog at
123 // this point.
124 checkFontAccessPermitted([](){
125 queryLocalFonts([](const QList<val> &fonts){
126 auto fontFamilies = makeFontFamilyMap(fonts);
127 // Populate some font families. We can't populate _all_ fonts as in-memory fonts,
128 // since that would require several gigabytes of memory. Instead, populate
129 // a subset of the available fonts.
130 for (const QString &family: webSafeFontFamilies()) {
131 auto fontsRange = fontFamilies.equal_range(family);
132 if (fontsRange.first != fontsRange.second)
134
135 for (auto it = fontsRange.first; it != fontsRange.second; ++it) {
136 const val font = it->second;
137 readFont(font, [](const QByteArray &fontData){
140 });
141 }
142 }
143 });
144 });
145}
146
148{
149 // Load font file from resources. Currently
150 // all fonts needs to be bundled with the nexe
151 // as Qt resources.
152
153 const QString fontFileNames[] = {
154 QStringLiteral(":/fonts/DejaVuSansMono.ttf"),
155 QStringLiteral(":/fonts/Vera.ttf"),
156 QStringLiteral(":/fonts/DejaVuSans.ttf"),
157 };
158 for (const QString &fontFileName : fontFileNames) {
159 QFile theFont(fontFileName);
160 if (!theFont.open(QIODevice::ReadOnly))
161 break;
162
163 QFreeTypeFontDatabase::addTTFile(theFont.readAll(), fontFileName.toLatin1());
164 }
165
167}
168
170{
172}
173
175 QFont::StyleHint styleHint,
176 QChar::Script script) const
177{
178 QStringList fallbacks
179 = QFreeTypeFontDatabase::fallbacksForFamily(family, style, styleHint, script);
180
181 // Add the vera.ttf and DejaVuSans.ttf fonts (loaded in populateFontDatabase above) as falback fonts
182 // to all other fonts (except itself).
183 static const QString wasmFallbackFonts[] = { "Bitstream Vera Sans", "DejaVu Sans" };
184 for (auto wasmFallbackFont : wasmFallbackFonts) {
185 if (family != wasmFallbackFont && !fallbacks.contains(wasmFallbackFont))
186 fallbacks.append(wasmFallbackFont);
187 }
188
189 return fallbacks;
190}
191
193{
195}
196
198{
199 return QFont("Bitstream Vera Sans"_L1);
200}
201
203{
205 emit qGuiApp->fontDatabaseChanged();
206}
207
\inmodule QtCore
Definition qbytearray.h:57
Script
Definition qchar.h:144
\inmodule QtCore
Definition qfile.h:93
bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:881
void clear()
Definition qfont.cpp:3089
static QFontCache * instance()
Definition qfont.cpp:3052
\reentrant
Definition qfont.h:20
StyleHint
Style hints are used by the \l{QFont}{font matching} algorithm to find an appropriate default family ...
Definition qfont.h:23
Style
This enum describes the different styles of glyphs that are used to display text.
Definition qfont.h:73
QFontEngine * fontEngine(const QFontDef &fontDef, void *handle) override
Returns the font engine that can be used to render the font described by the font definition,...
static QStringList addTTFile(const QByteArray &fontData, const QByteArray &file, QFontDatabasePrivate::ApplicationFont *applicationFont=nullptr)
void releaseHandle(void *handle) override
Releases the specified font handle.
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
Definition qlist.h:74
void reserve(qsizetype size)
Definition qlist.h:746
void append(parameter_type t)
Definition qlist.h:441
virtual QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
Returns a list of alternative fonts for the specified family and style and script using the styleHint...
static void registerFontFamily(const QString &familyName)
Registers a font family with the font database.
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString fromStdString(const std::string &s)
Definition qstring.h:1322
void populateFontDatabase() override
This function is called once at startup by Qt's internal font database.
QFont defaultFont() const override
Returns the default system font.
QFontEngine * fontEngine(const QFontDef &fontDef, void *handle) override
Returns the font engine that can be used to render the font described by the font definition,...
static void notifyFontsChanged()
void releaseHandle(void *handle) override
Releases the specified font handle.
QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const override
Returns a list of alternative fonts for the specified family and style and script using the styleHint...
QByteArray copyToQByteArray() const
Definition qstdweb.cpp:712
QSet< QString >::iterator it
Combined button and popup list for selecting options.
void make(emscripten::val target, QString methodName, PromiseCallbacks callbacks, Args... args)
Definition qstdweb_p.h:182
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qGuiApp
#define qCWarning(category,...)
GLuint64 GLenum void * handle
GLuint64 key
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLsizeiptr const void * fontData
GLhandleARB obj
[2]
GLuint GLfloat * val
#define QStringLiteral(str)
#define emit
void printError(const char *msg)
[0]
aWidget window() -> setWindowTitle("New Window Title")
[2]