7#include <QtCore/qdebug.h>
8#include <QtCore/qjniarray.h>
9#include <QtCore/qjniobject.h>
10#include <QtCore/qloggingcategory.h>
11#include <QtCore/qfile.h>
12#include <QtCore/qset.h>
14#include <QtGui/qfontdatabase.h>
15#include <QtGui/qpainter.h>
16#include <QtGui/qpalette.h>
26Q_DECLARE_JNI_CLASS(FontFamilyResult, "androidx/core/provider/FontsContractCompat$FontFamilyResult")
46 using namespace QtJniTypes;
48 static QMap<QString, QString> triedFonts;
54 triedFonts[
query] = fontFamily;
58 qCDebug(lcIconEngineFontDownload) <<
"Loading font from resource" <<
query;
62 }
else if (!
query.startsWith(u
":/"_s)) {
63 const QString package = u"com.google.android.gms"_s;
64 const QString authority = u
"com.google.android.gms.fonts"_s;
69 auto packageManager =
context.callMethod<PackageManager>(
"getPackageManager");
70 if (!packageManager.isValid()) {
71 qCWarning(lcIconEngineFontDownload,
"Failed to instantiate PackageManager");
74 const int signaturesField = PackageManager::getStaticField<int>(
"GET_SIGNATURES");
75 auto providerInfo = packageManager.callMethod<ProviderInfo>(
"resolveContentProvider",
77 if (!providerInfo.isValid()) {
78 qCWarning(lcIconEngineFontDownload,
"Failed to resolve content provider");
81 const QString packageName = providerInfo.getField<
QString>(
"packageName");
82 if (packageName != package) {
83 qCWarning(lcIconEngineFontDownload,
"Mismatched provider package - expected '%s', got '%s'",
87 auto packageInfo = packageManager.callMethod<PackageInfo>(
"getPackageInfo",
88 package, signaturesField);
89 if (!packageInfo.isValid()) {
90 qCWarning(lcIconEngineFontDownload,
"Failed to get package info with signature field %d",
94 const auto signatures = packageInfo.getField<
Signature[]>(
"signatures");
95 if (!signatures.isValid()) {
96 qCWarning(lcIconEngineFontDownload,
"Failed to get signature array from package info");
103 Q_ASSERT(outerList.isValid() && innerSet.isValid());
105 for (
const auto &signature : signatures) {
106 const QJniArray<jbyte> byteArray = signature.callMethod<jbyte[]>(
"toByteArray");
109 if (!innerSet.callMethod<jboolean>(
"add", byteArray.object<jobject>()))
110 qCWarning(lcIconEngineFontDownload,
"Failed to add signature to set");
113 if (!outerList.callMethod<jboolean>(
"add", innerSet.object()))
114 qCWarning(lcIconEngineFontDownload,
"Failed to add set to certificate list");
117 FontRequest fontRequest(authority, package,
query, outerList.object<List>());
118 if (!fontRequest.isValid()) {
119 qCWarning(lcIconEngineFontDownload,
"Failed to create font request for '%s'",
120 query.toUtf8().constData());
125 auto fontFamilyResult = FontsContractCompat::callStaticMethod<FontFamilyResult>(
128 CancellationSignal(
nullptr),
130 if (!fontFamilyResult.isValid()) {
131 qCWarning(lcIconEngineFontDownload,
"Failed to fetch fonts for query '%s'",
132 query.toUtf8().constData());
136 enum class StatusCode {
138 UNEXPECTED_DATA_PROVIDED = 1,
139 WRONG_CERTIFICATES = 2,
142 const StatusCode statusCode = fontFamilyResult.callMethod<StatusCode>(
"getStatusCode");
143 switch (statusCode) {
146 case StatusCode::UNEXPECTED_DATA_PROVIDED:
147 qCWarning(lcIconEngineFontDownload,
"Provider returned unexpected data for query '%s'",
148 query.toUtf8().constData());
150 case StatusCode::WRONG_CERTIFICATES:
151 qCWarning(lcIconEngineFontDownload,
"Wrong Certificates provided in query '%s'",
152 query.toUtf8().constData());
156 const auto fontInfos = fontFamilyResult.callMethod<FontInfo[]>(
"getFonts");
157 if (!fontInfos.isValid()) {
158 qCWarning(lcIconEngineFontDownload,
"FontFamilyResult::getFonts returned null object for '%s'",
159 query.toUtf8().constData());
163 auto contentResolver =
context.callMethod<ContentResolver>(
"getContentResolver");
166 if (!fontInfo.isValid()) {
167 qCDebug(lcIconEngineFontDownload,
"Received null-fontInfo object, skipping");
170 enum class ResultCode {
173 FONT_UNAVAILABLE = 2,
176 const ResultCode resultCode = fontInfo.callMethod<ResultCode>(
"getResultCode");
177 switch (resultCode) {
180 case ResultCode::FONT_NOT_FOUND:
181 qCWarning(lcIconEngineFontDownload,
"Font '%s' could not be found",
182 query.toUtf8().constData());
184 case ResultCode::FONT_UNAVAILABLE:
185 qCWarning(lcIconEngineFontDownload,
"Font '%s' is unavailable at",
186 query.toUtf8().constData());
188 case ResultCode::MALFORMED_QUERY:
189 qCWarning(lcIconEngineFontDownload,
"Query string '%s' is malformed",
190 query.toUtf8().constData());
193 auto fontUri = fontInfo.callMethod<Uri>(
"getUri");
196 auto fileDescriptor = contentResolver.callMethod<ParcelFileDescriptor>(
"openFileDescriptor",
198 if (!fileDescriptor.isValid()) {
199 qCWarning(lcIconEngineFontDownload,
"Font file '%s' not accessible",
200 fontUri.toString().toUtf8().constData());
204 int fd = fileDescriptor.callMethod<
int>(
"detachFd");
208 qCDebug(lcIconEngineFontDownload) <<
"Font file read:" <<
fontData.size() <<
"bytes";
214 qCDebug(lcIconEngineFontDownload) <<
"Query '" <<
query <<
"' added families" << loadedFamilies;
215 if (!loadedFamilies.isEmpty())
216 fontFamily = loadedFamilies.
first();
217 triedFonts[
query] = fontFamily;
222QString QAndroidPlatformIconEngine::glyphs()
const
227 static constexpr std::pair<QLatin1StringView, QStringView> glyphMap[] = {
228 {
"address-book-new"_L1, u
"\ue0e0"},
229 {
"application-exit"_L1, u
"\ue5cd"},
230 {
"appointment-new"_L1, u
"\ue878"},
231 {
"call-start"_L1, u
"\ue0b0"},
232 {
"call-stop"_L1, u
"\ue0b1"},
233 {
"contact-new"_L1, u
"\uf22e"},
234 {
"document-new"_L1, u
"\ue89c"},
235 {
"document-open"_L1, u
"\ue2c8"},
236 {
"document-open-recent"_L1, u
"\ue4a7"},
237 {
"document-page-setup"_L1, u
"\uf88c"},
238 {
"document-print"_L1, u
"\ue8ad"},
239 {
"document-print-preview"_L1, u
"\uefb2"},
240 {
"document-properties"_L1, u
"\uf775"},
241 {
"document-revert"_L1, u
"\ue929"},
242 {
"document-save"_L1, u
"\ue161"},
243 {
"document-save-as"_L1, u
"\ueb60"},
244 {
"document-send"_L1, u
"\uf09b"},
245 {
"edit-clear"_L1, u
"\ue872"},
246 {
"edit-copy"_L1, u
"\ue14d"},
247 {
"edit-cut"_L1, u
"\ue14e"},
248 {
"edit-delete"_L1, u
"\ue14a"},
249 {
"edit-find"_L1, u
"\ue8b6"},
250 {
"edit-find-replace"_L1, u
"\ue881"},
251 {
"edit-paste"_L1, u
"\ue14f"},
252 {
"edit-redo"_L1, u
"\ue15a"},
253 {
"edit-select-all"_L1, u
"\ue162"},
254 {
"edit-undo"_L1, u
"\ue166"},
255 {
"folder-new"_L1, u
"\ue2cc"},
256 {
"format-indent-less"_L1, u
"\ue23d"},
257 {
"format-indent-more"_L1, u
"\ue23e"},
258 {
"format-justify-center"_L1, u
"\ue234"},
259 {
"format-justify-fill"_L1, u
"\ue235"},
260 {
"format-justify-left"_L1, u
"\ue236"},
261 {
"format-justify-right"_L1, u
"\ue237"},
262 {
"format-text-direction-ltr"_L1, u
"\ue247"},
263 {
"format-text-direction-rtl"_L1, u
"\ue248"},
264 {
"format-text-bold"_L1, u
"\ue238"},
265 {
"format-text-italic"_L1, u
"\ue23f"},
266 {
"format-text-underline"_L1, u
"\ue249"},
267 {
"format-text-strikethrough"_L1, u
"\ue246"},
268 {
"go-bottom"_L1,u
"\ue258"},
269 {
"go-down"_L1,u
"\uf1e3"},
270 {
"go-first"_L1, u
"\ue5dc"},
271 {
"go-home"_L1, u
"\ue88a"},
272 {
"go-jump"_L1, u
"\uf719"},
273 {
"go-last"_L1, u
"\ue5dd"},
274 {
"go-next"_L1, u
"\ue5c8"},
275 {
"go-previous"_L1, u
"\ue5c4"},
276 {
"go-top"_L1, u
"\ue25a"},
277 {
"go-up"_L1, u
"\uf1e0"},
278 {
"help-about"_L1, u
"\ue88e"},
279 {
"help-contents"_L1, u
"\ue8de"},
280 {
"help-faq"_L1, u
"\uf04c"},
281 {
"insert-image"_L1, u
"\ue43e"},
282 {
"insert-link"_L1, u
"\ue178"},
284 {
"insert-text"_L1, u
"\uf827"},
285 {
"list-add"_L1, u
"\ue145"},
286 {
"list-remove"_L1, u
"\ue15b"},
287 {
"mail-forward"_L1, u
"\ue154"},
288 {
"mail-mark-important"_L1, u
"\ue937"},
291 {
"mail-mark-read"_L1, u
"\uf18c"},
292 {
"mail-mark-unread"_L1, u
"\ue9bc"},
293 {
"mail-message-new"_L1, u
"\ue3c9"},
294 {
"mail-reply-all"_L1, u
"\ue15f"},
295 {
"mail-reply-sender"_L1, u
"\ue15e"},
296 {
"mail-send"_L1, u
"\ue163"},
298 {
"media-eject"_L1, u
"\ue8fb"},
299 {
"media-playback-pause"_L1, u
"\ue034"},
300 {
"media-playback-start"_L1, u
"\ue037"},
301 {
"media-playback-stop"_L1, u
"\ue047"},
302 {
"media-record"_L1, u
"\uf679"},
303 {
"media-seek-backward"_L1, u
"\ue020"},
304 {
"media-seek-forward"_L1, u
"\ue01f"},
305 {
"media-skip-backward"_L1, u
"\ue045"},
306 {
"media-skip-forward"_L1, u
"\ue044"},
309 {
"object-rotate-left"_L1, u
"\ue419"},
310 {
"object-rotate-right"_L1, u
"\ue41a"},
311 {
"process-stop"_L1, u
"\ue5c9"},
312 {
"system-lock-screen"_L1, u
"\ue897"},
313 {
"system-log-out"_L1, u
"\ue9ba"},
315 {
"system-search"_L1, u
"\uef70"},
316 {
"system-reboot"_L1, u
"\uf053"},
317 {
"system-shutdown"_L1, u
"\ue8ac"},
318 {
"tools-check-spelling"_L1, u
"\ue8ce"},
319 {
"view-fullscreen"_L1, u
"\ue5d0"},
320 {
"view-refresh"_L1, u
"\ue5d5"},
321 {
"view-restore"_L1, u
"\uf1cf"},
322 {
"view-sort-ascending"_L1, u
"\ue25a"},
323 {
"view-sort-descending"_L1, u
"\ue258"},
324 {
"window-close"_L1, u
"\ue5cd"},
325 {
"window-new"_L1, u
"\uf710"},
326 {
"zoom-fit-best"_L1, u
"\uea10"},
327 {
"zoom-in"_L1, u
"\ue8ff"},
328 {
"zoom-original"_L1, u
"\ue5d1"},
329 {
"zoom-out"_L1, u
"\ue900"},
330 {
"process-working"_L1, u
"\uef64"},
331 {
"accessories-calculator"_L1, u
"\uea5f"},
332 {
"accessories-character-map"_L1, u
"\uf8a3"},
333 {
"accessories-dictionary"_L1, u
"\uf539"},
334 {
"accessories-text-editor"_L1, u
"\ue262"},
335 {
"help-browser"_L1, u
"\ue887"},
336 {
"multimedia-volume-control"_L1, u
"\ue050"},
337 {
"preferences-desktop-accessibility"_L1, u
"\uf05d"},
338 {
"preferences-desktop-font"_L1, u
"\ue165"},
339 {
"preferences-desktop-keyboard"_L1, u
"\ue312"},
341 {
"preferences-desktop-multimedia"_L1, u
"\uea75"},
343 {
"preferences-desktop-theme"_L1, u
"\uf560"},
344 {
"preferences-desktop-wallpaper"_L1, u
"\ue1bc"},
345 {
"system-file-manager"_L1, u
"\ue2c7"},
346 {
"system-software-install"_L1, u
"\ueb71"},
347 {
"system-software-update"_L1, u
"\ue8d7"},
348 {
"utilities-system-monitor"_L1, u
"\uef5b"},
349 {
"utilities-terminal"_L1, u
"\ueb8e"},
351 {
"applications-development"_L1, u
"\ue720"},
352 {
"applications-engineering"_L1, u
"\uea3d"},
353 {
"applications-games"_L1, u
"\uf135"},
355 {
"applications-internet"_L1, u
"\ue80b"},
356 {
"applications-multimedia"_L1, u
"\uf06a"},
359 {
"applications-science"_L1, u
"\uea4b"},
362 {
"preferences-desktop"_L1, u
"\ueb97"},
364 {
"preferences-desktop-personal"_L1, u
"\uf835"},
366 {
"preferences-system"_L1, u
"\ue8b8"},
367 {
"preferences-system-network"_L1, u
"\ue894"},
368 {
"system-help"_L1, u
"\ue887"},
370 {
"audio-input-microphone"_L1, u
"\ue029"},
371 {
"battery"_L1, u
"\ue1a4"},
372 {
"camera-photo"_L1, u
"\ue412"},
373 {
"camera-video"_L1, u
"\ue04b"},
374 {
"camera-web"_L1, u
"\uf7a6"},
375 {
"computer"_L1, u
"\ue30a"},
376 {
"drive-harddisk"_L1, u
"\uf80e"},
377 {
"drive-optical"_L1, u
"\ue019"},
379 {
"input-gaming"_L1, u
"\uf5ee"},
380 {
"input-keyboard"_L1, u
"\ue312"},
381 {
"input-mouse"_L1, u
"\ue323"},
385 {
"media-optical"_L1, u
"\ue019"},
390 {
"network-wireless"_L1, u
"\ue63e"},
392 {
"phone"_L1, u
"\ue32c"},
393 {
"printer"_L1, u
"\ue8ad"},
394 {
"scanner"_L1, u
"\ue329"},
395 {
"video-display"_L1, u
"\uf06a"},
397 {
"emblem-documents"_L1, u
"\ue873"},
398 {
"emblem-downloads"_L1, u
"\uf090"},
399 {
"emblem-favorite"_L1, u
"\uf090"},
400 {
"emblem-important"_L1, u
"\ue645"},
401 {
"emblem-mail"_L1, u
"\ue158"},
402 {
"emblem-photos"_L1, u
"\ue413"},
404 {
"emblem-shared"_L1, u
"\ue413"},
407 {
"emblem-system"_L1, u
"\ue8b8"},
409 {
"folder"_L1, u
"\ue2c7"},
411 {
"network-server"_L1, u
"\ue875"},
412 {
"network-workgroup"_L1, u
"\ue1a0"},
413 {
"start-here"_L1, u
"\ue089"},
414 {
"user-bookmarks"_L1, u
"\ue98b"},
415 {
"user-desktop"_L1, u
"\ue30a"},
416 {
"user-home"_L1, u
"\ue88a"},
417 {
"user-trash"_L1, u
"\ue872"},
418 {
"appointment-missed"_L1, u
"\ue615"},
419 {
"appointment-soon"_L1, u
"\uf540"},
420 {
"audio-volume-high"_L1, u
"\ue050"},
421 {
"audio-volume-low"_L1, u
"\ue04d"},
423 {
"audio-volume-muted"_L1, u
"\ue04e"},
424 {
"battery-caution"_L1, u
"\ue19c"},
425 {
"battery-low"_L1, u
"\uf147"},
426 {
"dialog-error"_L1, u
"\ue000"},
427 {
"dialog-information"_L1, u
"\ue88e"},
428 {
"dialog-password"_L1, u
"\uf042"},
429 {
"dialog-question"_L1, u
"\ueb8b"},
430 {
"dialog-warning"_L1, u
"\ue002"},
431 {
"folder-drag-accept"_L1, u
"\ue9a3"},
432 {
"folder-open"_L1, u
"\ue2c8"},
433 {
"folder-visiting"_L1, u
"\ue8a7"},
434 {
"image-loading"_L1, u
"\ue41a"},
435 {
"image-missing"_L1, u
"\ue3ad"},
436 {
"mail-attachment"_L1, u
"\ue2bc"},
437 {
"mail-unread"_L1, u
"\uf18a"},
438 {
"mail-read"_L1, u
"\uf18c"},
442 {
"media-playlist-repeat"_L1, u
"\ue040"},
443 {
"media-playlist-shuffle"_L1, u
"\ue043"},
444 {
"network-error"_L1, u
"\uead9"},
445 {
"network-idle"_L1, u
"\ue51f"},
446 {
"network-offline"_L1, u
"\uf239"},
447 {
"network-receive"_L1, u
"\ue2c0"},
448 {
"network-transmit"_L1, u
"\ue2c3"},
449 {
"network-transmit-receive"_L1, u
"\uea18"},
450 {
"printer-error"_L1, u
"\uf7a0"},
451 {
"printer-printing"_L1, u
"\uf7a1"},
452 {
"security-high"_L1, u
"\ue32a"},
453 {
"security-medium"_L1, u
"\ue9e0"},
454 {
"security-low"_L1, u
"\uf012"},
455 {
"software-update-available"_L1, u
"\ue923"},
456 {
"software-update-urgent"_L1, u
"\uf05a"},
457 {
"sync-error"_L1, u
"\ue629"},
458 {
"sync-synchronizing"_L1, u
"\ue627"},
461 {
"user-available"_L1, u
"\uf565"},
462 {
"user-away"_L1, u
"\ue510"},
464 {
"user-offline"_L1, u
"\uf7b3"},
465 {
"user-trash-full"_L1, u
"\ue872"},
467 {
"weather-clear"_L1, u
"\uf157"},
468 {
"weather-clear-night"_L1, u
"\uf159"},
469 {
"weather-few-clouds"_L1, u
"\uf172"},
470 {
"weather-few-clouds-night"_L1, u
"\uf174"},
471 {
"weather-fog"_L1, u
"\ue818"},
473 {
"weather-severe-alert"_L1, u
"\ue002"},
475 {
"weather-showers"_L1, u
"\uf176"},
477 {
"weather-snow"_L1, u
"\ue80f"},
480 {
"weather-storm"_L1, u
"\uf070"},
483 const auto it = std::find_if(std::begin(glyphMap), std::end(glyphMap), [
this](
const auto &
c){
484 return c.first == m_iconName;
486 return it != std::end(glyphMap) ?
it->second.toString()
491 : m_iconName(iconName)
500 "MaterialSymbolsOutlined[FILL,GRAD,opsz,wght].ttf",
501 "MaterialSymbolsRounded[FILL,GRAD,opsz,wght].ttf",
502 "MaterialSymbolsSharp[FILL,GRAD,opsz,wght].ttf",
503 "MaterialIcons-Regular.ttf",
504 "MaterialIconsOutlined-Regular.otf",
505 "MaterialIconsRound-Regular.otf",
506 "MaterialIconsSharp-Regular.otf",
507 "MaterialIconsTwoTone-Regular.otf",
509 for (
const auto &fontCandidate : fontCandidates) {
522 fontFamily = u
"Material Icons"_s;
523 m_iconFont =
QFont(fontFamily);
536 return u
"QAndroidPlatformIconEngine"_s;
548 const QChar c0 = m_glyphs.
at(0);
550 if (c0.category() == QChar::Other_Surrogate && m_glyphs.
size() > 1)
551 return !
fontMetrics.inFontUcs4(QChar::surrogateToUcs4(c0, m_glyphs.
at(1)));
557 return {{16, 16}, {24, 24}, {48, 48}, {128, 128}};
592 QFont renderFont(m_iconFont);
593 renderFont.setPixelSize(
rect.height());
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
static int addApplicationFontFromData(const QByteArray &fontData)
static QStringList applicationFontFamilies(int id)
\reentrant \inmodule QtGui
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
The QIconEngine class provides an abstract base class for QIcon renderers.
virtual QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
Returns the actual size of the icon the engine provides for the requested size, mode and state.
Mode
This enum type describes the mode for which a pixmap is intended to be used.
State
This enum describes the state for which a pixmap is intended to be used.
The QPainter class performs low-level painting on widgets and other paint devices.
void setPen(const QColor &color)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void restore()
Restores the current painter state (pops a saved state off the stack).
void save()
Saves the current painter state (pushes the state onto a stack).
void setFont(const QFont &f)
Sets the painter's font to the given font.
void drawText(const QPointF &p, const QString &s)
Draws the given text with the currently defined text direction, beginning at the given position.
The QPalette class contains color groups for each widget state.
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
QSize size() const
Returns the size of the pixmap.
void setDevicePixelRatio(qreal scaleFactor)
Sets the device pixel ratio for the pixmap.
void fill(const QColor &fillColor=Qt::white)
Fills the pixmap with the given color.
qreal devicePixelRatio() const
Returns the device pixel ratio for the pixmap.
\inmodule QtCore\reentrant
\inmodule QtCore\reentrant
const_iterator constEnd() const noexcept
iterator find(const T &value)
\macro QT_RESTRICTED_CAST_FROM_ASCII
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
qsizetype size() const noexcept
Returns the number of characters in this string.
QString first(qsizetype n) const &
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
QByteArray toUtf8() const &
qsizetype length() const noexcept
Returns the number of characters in this string.
QSet< QString >::iterator it
static QString fetchFont(const QString &query)
Combined button and popup list for selecting options.
Q_CORE_EXPORT QtJniTypes::Context context()
static QByteArray cacheKey(Args &&...args)
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLsizeiptr const void * fontData
GLenum GLenum GLenum GLenum GLenum scale
QString qEnvironmentVariable(const char *varName, const QString &defaultValue)
unsigned long long quint64