Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qandroidplatformiconengine.cpp
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include "androidjnimain.h"
6
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>
13
14#include <QtGui/qfontdatabase.h>
15#include <QtGui/qpainter.h>
16#include <QtGui/qpalette.h>
17
19
20using namespace Qt::StringLiterals;
21Q_LOGGING_CATEGORY(lcIconEngineFontDownload, "qt.qpa.iconengine.fontdownload")
22
23// the primary types to work with the FontRequest API
24Q_DECLARE_JNI_CLASS(FontRequest, "androidx/core/provider/FontRequest")
25Q_DECLARE_JNI_CLASS(FontsContractCompat, "androidx/core/provider/FontsContractCompat")
26Q_DECLARE_JNI_CLASS(FontFamilyResult, "androidx/core/provider/FontsContractCompat$FontFamilyResult")
27Q_DECLARE_JNI_CLASS(FontInfo, "androidx/core/provider/FontsContractCompat$FontInfo")
28
29// various utility types
30Q_DECLARE_JNI_CLASS(List, "java/util/List"); // List is just an Interface
31Q_DECLARE_JNI_CLASS(ArrayList, "java/util/ArrayList");
32Q_DECLARE_JNI_CLASS(HashSet, "java/util/HashSet");
33Q_DECLARE_JNI_CLASS(Uri, "android/net/Uri")
34Q_DECLARE_JNI_CLASS(CancellationSignal, "android/os/CancellationSignal")
35Q_DECLARE_JNI_CLASS(ParcelFileDescriptor, "android/os/ParcelFileDescriptor")
36Q_DECLARE_JNI_CLASS(ContentResolver, "android/content/ContentResolver")
37Q_DECLARE_JNI_CLASS(PackageManager, "android/content/pm/PackageManager")
38Q_DECLARE_JNI_CLASS(ProviderInfo, "android/content/pm/ProviderInfo")
39Q_DECLARE_JNI_CLASS(PackageInfo, "android/content/pm/PackageInfo")
40Q_DECLARE_JNI_CLASS(Signature, "android/content/pm/Signature")
41
42namespace FontProvider {
43
45{
46 using namespace QtJniTypes;
47
48 static QMap<QString, QString> triedFonts;
49 const auto it = triedFonts.find(query);
50 if (it != triedFonts.constEnd())
51 return it.value();
52
53 QString fontFamily;
54 triedFonts[query] = fontFamily; // mark as tried
55
56 QStringList loadedFamilies;
58 qCDebug(lcIconEngineFontDownload) << "Loading font from resource" << query;
61 loadedFamilies << QFontDatabase::applicationFontFamilies(fontId);
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;
65
66 // First we access the content provider to get the signatures of the authority for the package
68
69 auto packageManager = context.callMethod<PackageManager>("getPackageManager");
70 if (!packageManager.isValid()) {
71 qCWarning(lcIconEngineFontDownload, "Failed to instantiate PackageManager");
72 return fontFamily;
73 }
74 const int signaturesField = PackageManager::getStaticField<int>("GET_SIGNATURES");
75 auto providerInfo = packageManager.callMethod<ProviderInfo>("resolveContentProvider",
76 authority, 0);
77 if (!providerInfo.isValid()) {
78 qCWarning(lcIconEngineFontDownload, "Failed to resolve content provider");
79 return fontFamily;
80 }
81 const QString packageName = providerInfo.getField<QString>("packageName");
82 if (packageName != package) {
83 qCWarning(lcIconEngineFontDownload, "Mismatched provider package - expected '%s', got '%s'",
84 package.toUtf8().constData(), packageName.toUtf8().constData());
85 return fontFamily;
86 }
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",
91 signaturesField);
92 return fontFamily;
93 }
94 const auto signatures = packageInfo.getField<Signature[]>("signatures");
95 if (!signatures.isValid()) {
96 qCWarning(lcIconEngineFontDownload, "Failed to get signature array from package info");
97 return fontFamily;
98 }
99
100 // FontRequest wants a list of sets for the certificates
101 ArrayList outerList;
102 HashSet innerSet;
103 Q_ASSERT(outerList.isValid() && innerSet.isValid());
104
105 for (const auto &signature : signatures) {
106 const QJniArray<jbyte> byteArray = signature.callMethod<jbyte[]>("toByteArray");
107
108 // add takes an Object, not an Array
109 if (!innerSet.callMethod<jboolean>("add", byteArray.object<jobject>()))
110 qCWarning(lcIconEngineFontDownload, "Failed to add signature to set");
111 }
112 // Add the set to the list
113 if (!outerList.callMethod<jboolean>("add", innerSet.object()))
114 qCWarning(lcIconEngineFontDownload, "Failed to add set to certificate list");
115
116 // FontRequest constructor wants a List interface, not an ArrayList
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());
121 return fontFamily;
122 }
123
124 // Call FontsContractCompat::fetchFonts with the FontRequest object
125 auto fontFamilyResult = FontsContractCompat::callStaticMethod<FontFamilyResult>(
126 "fetchFonts",
127 context,
128 CancellationSignal(nullptr),
129 fontRequest);
130 if (!fontFamilyResult.isValid()) {
131 qCWarning(lcIconEngineFontDownload, "Failed to fetch fonts for query '%s'",
132 query.toUtf8().constData());
133 return fontFamily;
134 }
135
136 enum class StatusCode {
137 OK = 0,
138 UNEXPECTED_DATA_PROVIDED = 1,
139 WRONG_CERTIFICATES = 2,
140 };
141
142 const StatusCode statusCode = fontFamilyResult.callMethod<StatusCode>("getStatusCode");
143 switch (statusCode) {
144 case StatusCode::OK:
145 break;
146 case StatusCode::UNEXPECTED_DATA_PROVIDED:
147 qCWarning(lcIconEngineFontDownload, "Provider returned unexpected data for query '%s'",
148 query.toUtf8().constData());
149 return fontFamily;
150 case StatusCode::WRONG_CERTIFICATES:
151 qCWarning(lcIconEngineFontDownload, "Wrong Certificates provided in query '%s'",
152 query.toUtf8().constData());
153 return fontFamily;
154 }
155
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());
160 return fontFamily;
161 }
162
163 auto contentResolver = context.callMethod<ContentResolver>("getContentResolver");
164
165 for (QJniObject fontInfo : fontInfos) {
166 if (!fontInfo.isValid()) {
167 qCDebug(lcIconEngineFontDownload, "Received null-fontInfo object, skipping");
168 continue;
169 }
170 enum class ResultCode {
171 OK = 0,
172 FONT_NOT_FOUND = 1,
173 FONT_UNAVAILABLE = 2,
174 MALFORMED_QUERY = 3,
175 };
176 const ResultCode resultCode = fontInfo.callMethod<ResultCode>("getResultCode");
177 switch (resultCode) {
178 case ResultCode::OK:
179 break;
180 case ResultCode::FONT_NOT_FOUND:
181 qCWarning(lcIconEngineFontDownload, "Font '%s' could not be found",
182 query.toUtf8().constData());
183 return fontFamily;
184 case ResultCode::FONT_UNAVAILABLE:
185 qCWarning(lcIconEngineFontDownload, "Font '%s' is unavailable at",
186 query.toUtf8().constData());
187 return fontFamily;
188 case ResultCode::MALFORMED_QUERY:
189 qCWarning(lcIconEngineFontDownload, "Query string '%s' is malformed",
190 query.toUtf8().constData());
191 return fontFamily;
192 }
193 auto fontUri = fontInfo.callMethod<Uri>("getUri");
194 // in this case the Font URI is always a content scheme file, made
195 // so the app requesting it has permissions to open
196 auto fileDescriptor = contentResolver.callMethod<ParcelFileDescriptor>("openFileDescriptor",
197 fontUri, u"r"_s);
198 if (!fileDescriptor.isValid()) {
199 qCWarning(lcIconEngineFontDownload, "Font file '%s' not accessible",
200 fontUri.toString().toUtf8().constData());
201 continue;
202 }
203
204 int fd = fileDescriptor.callMethod<int>("detachFd");
205 QFile file;
208 qCDebug(lcIconEngineFontDownload) << "Font file read:" << fontData.size() << "bytes";
210 loadedFamilies << QFontDatabase::applicationFontFamilies(fontId);
211 }
212 }
213
214 qCDebug(lcIconEngineFontDownload) << "Query '" << query << "' added families" << loadedFamilies;
215 if (!loadedFamilies.isEmpty())
216 fontFamily = loadedFamilies.first();
217 triedFonts[query] = fontFamily;
218 return fontFamily;
219}
220}
221
222QString QAndroidPlatformIconEngine::glyphs() const
223{
224 if (!QFontInfo(m_iconFont).exactMatch())
225 return {};
226
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"},
283 //{"insert-object"_L1, u"\u"},
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"},
289 //{"mail-mark-junk"_L1, u"\u"},
290 //{"mail-mark-notjunk"_L1, u"\u"},
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"},
297 //{"mail-send-receive"_L1, u"\u"},
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"},
307 //{"object-flip-horizontal"_L1, u"\u"},
308 //{"object-flip-vertical"_L1, u"\u"},
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"},
314 //{"system-run"_L1, u"\u"},
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"},
340 //{"preferences-desktop-locale"_L1, u"\u"},
341 {"preferences-desktop-multimedia"_L1, u"\uea75"},
342 //{"preferences-desktop-screensaver"_L1, u"\u"},
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"},
350 //{"applications-accessories"_L1, u"\u"},
351 {"applications-development"_L1, u"\ue720"},
352 {"applications-engineering"_L1, u"\uea3d"},
353 {"applications-games"_L1, u"\uf135"},
354 //{"applications-graphics"_L1, u"\u"},
355 {"applications-internet"_L1, u"\ue80b"},
356 {"applications-multimedia"_L1, u"\uf06a"},
357 //{"applications-office"_L1, u"\u"},
358 //{"applications-other"_L1, u"\u"},
359 {"applications-science"_L1, u"\uea4b"},
360 //{"applications-system"_L1, u"\u"},
361 //{"applications-utilities"_L1, u"\u"},
362 {"preferences-desktop"_L1, u"\ueb97"},
363 //{"preferences-desktop-peripherals"_L1, u"\u"},
364 {"preferences-desktop-personal"_L1, u"\uf835"},
365 //{"preferences-other"_L1, u"\u"},
366 {"preferences-system"_L1, u"\ue8b8"},
367 {"preferences-system-network"_L1, u"\ue894"},
368 {"system-help"_L1, u"\ue887"},
369 //{"audio-card"_L1, u"\u"},
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"}, // same as media-optical
378 //{"drive-removable-media"_L1, u"\u"},
379 {"input-gaming"_L1, u"\uf5ee"},
380 {"input-keyboard"_L1, u"\ue312"},
381 {"input-mouse"_L1, u"\ue323"},
382 //{"input-tablet"_L1, u"\u"},
383 //{"media-flash"_L1, u"\u"},
384 //{"media-floppy"_L1, u"\u"},
385 {"media-optical"_L1, u"\ue019"},
386 //{"media-tape"_L1, u"\u"},
387 //{"modem"_L1, u"\u"},
388 //{"multimedia-player"_L1, u"\u"},
389 //{"network-wired"_L1, u"\u"},
390 {"network-wireless"_L1, u"\ue63e"},
391 //{"pda"_L1, u"\u"},
392 {"phone"_L1, u"\ue32c"},
393 {"printer"_L1, u"\ue8ad"},
394 {"scanner"_L1, u"\ue329"},
395 {"video-display"_L1, u"\uf06a"},
396 //{"emblem-default"_L1, u"\u"},
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"},
403 //{"emblem-readonly"_L1, u"\u"},
404 {"emblem-shared"_L1, u"\ue413"},
405 //{"emblem-symbolic-link"_L1, u"\u"},
406 //{"emblem-synchronized"_L1, u"\u"},
407 {"emblem-system"_L1, u"\ue8b8"},
408 //{"emblem-unreadable"_L1, u"\u"},
409 {"folder"_L1, u"\ue2c7"},
410 //{"folder-remote"_L1, u"\u"},
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"},
422 //{"audio-volume-medium"_L1, u"\u"},
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"},
439 //{"mail-replied"_L1, u"\u"},
440 //{"mail-signed"_L1, u"\u"},
441 //{"mail-signed-verified"_L1, u"\u"},
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"},
459 //{"task-due"_L1, u"\u"},
460 //{"task-past-due"_L1, u"\u"},
461 {"user-available"_L1, u"\uf565"},
462 {"user-away"_L1, u"\ue510"},
463 //{"user-idle"_L1, u"\u"},
464 {"user-offline"_L1, u"\uf7b3"},
465 {"user-trash-full"_L1, u"\ue872"}, //delete
466 //{"user-trash-full"_L1, u"\ue92b"}, //delete_forever
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"},
472 //{"weather-overcast"_L1, u"\u"},
473 {"weather-severe-alert"_L1, u"\ue002"}, //warning
474 //{"weather-severe-alert"_L1, u"\uebd3"},//severe_cold
475 {"weather-showers"_L1, u"\uf176"},
476 //{"weather-showers-scattered"_L1, u"\u"},
477 {"weather-snow"_L1, u"\ue80f"}, //snowing
478 //{"weather-snow"_L1, u"\ue2cd"}, //weather_snowy
479 //{"weather-snow"_L1, u"\ue810"},//cloudy_snowing
480 {"weather-storm"_L1, u"\uf070"},
481 };
482
483 const auto it = std::find_if(std::begin(glyphMap), std::end(glyphMap), [this](const auto &c){
484 return c.first == m_iconName;
485 });
486 return it != std::end(glyphMap) ? it->second.toString()
487 : (m_iconName.length() == 1 ? m_iconName : QString());
488}
489
491 : m_iconName(iconName)
492 , m_glyphs(glyphs())
493{
494 QString fontFamily;
495 // The MaterialIcons-*.ttf and MaterialSymbols* font files are available from
496 // https://github.com/google/material-design-icons/tree/master. If one of them is
497 // packaged as a resource with the application, then we use it. We prioritize
498 // a variable font.
499 const QStringList fontCandidates = {
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",
508 };
509 for (const auto &fontCandidate : fontCandidates) {
510 fontFamily = FontProvider::fetchFont(u":/qt-project.org/icons/%1"_s.arg(fontCandidate));
511 if (!fontFamily.isEmpty())
512 break;
513 }
514
515 // Otherwise we try to download the Outlined version of Material Symbols
516 const QString key = qEnvironmentVariable("QT_GOOGLE_FONTS_KEY");
517 if (fontFamily.isEmpty() && !key.isEmpty())
518 fontFamily = FontProvider::fetchFont(u"key=%1&name=Material+Symbols+Outlined"_s.arg(key));
519
520 // last resort - use any Material Icons
521 if (fontFamily.isEmpty())
522 fontFamily = u"Material Icons"_s;
523 m_iconFont = QFont(fontFamily);
524}
525
528
530{
531 return new QAndroidPlatformIconEngine(m_iconName);
532}
533
535{
536 return u"QAndroidPlatformIconEngine"_s;
537}
538
540{
541 return m_iconName;
542}
543
545{
546 if (m_glyphs.isEmpty())
547 return true;
548 const QChar c0 = m_glyphs.at(0);
549 const QFontMetrics fontMetrics(m_iconFont);
550 if (c0.category() == QChar::Other_Surrogate && m_glyphs.size() > 1)
551 return !fontMetrics.inFontUcs4(QChar::surrogateToUcs4(c0, m_glyphs.at(1)));
552 return !fontMetrics.inFont(c0);
553}
554
556{
557 return {{16, 16}, {24, 24}, {48, 48}, {128, 128}};
558}
559
564
569
571{
572 const quint64 cacheKey = calculateCacheKey(mode, state);
573 if (cacheKey != m_cacheKey || m_pixmap.size() != size || m_pixmap.devicePixelRatio() != scale) {
574 m_pixmap = QPixmap(size * scale);
575 m_pixmap.fill(Qt::transparent);
576 m_pixmap.setDevicePixelRatio(scale);
577
578 QPainter painter(&m_pixmap);
580
581 m_cacheKey = cacheKey;
582 }
583
584 return m_pixmap;
585}
586
588{
590
591 painter->save();
592 QFont renderFont(m_iconFont);
593 renderFont.setPixelSize(rect.height());
594 painter->setFont(renderFont);
595
597 switch (mode) {
598 case QIcon::Active:
600 break;
601 case QIcon::Normal:
603 break;
604 case QIcon::Disabled:
606 break;
607 case QIcon::Selected:
609 break;
610 }
611
613 painter->restore();
614}
615
QString key() const override
\variable QIconEngine::ScaledPixmapArgument::size
QPixmap scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale) override
QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override
Returns the actual size of the icon the engine provides for the requested size, mode and state.
QIconEngine * clone() const override
Reimplement this method to return a clone of this icon engine.
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override
Uses the given painter to paint the icon with the required mode and state into the rectangle rect.
QAndroidPlatformIconEngine(const QString &iconName)
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override
Returns the icon as a pixmap with the required size, mode, and state.
QList< QSize > availableSizes(QIcon::Mode, QIcon::State) override
\inmodule QtCore
Definition qbytearray.h:57
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
\inmodule QtCore
\inmodule QtCore
Definition qfile.h:93
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:904
static int addApplicationFontFromData(const QByteArray &fontData)
static QStringList applicationFontFamilies(int id)
\reentrant
Definition qfontinfo.h:16
\reentrant \inmodule QtGui
\reentrant
Definition qfont.h:22
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.
Definition qiconengine.h:15
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.
Definition qicon.h:22
@ Disabled
Definition qicon.h:22
@ Selected
Definition qicon.h:22
@ Normal
Definition qicon.h:22
@ Active
Definition qicon.h:22
State
This enum describes the state for which a pixmap is intended to be used.
Definition qicon.h:23
\inmodule QtCore
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
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.
Definition qpalette.h:19
@ Disabled
Definition qpalette.h:49
@ HighlightedText
Definition qpalette.h:53
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
QSize size() const
Returns the size of the pixmap.
Definition qpixmap.cpp:493
void setDevicePixelRatio(qreal scaleFactor)
Sets the device pixel ratio for the pixmap.
Definition qpixmap.cpp:604
void fill(const QColor &fillColor=Qt::white)
Fills the pixmap with the given color.
Definition qpixmap.cpp:850
qreal devicePixelRatio() const
Returns the device pixel ratio for the pixmap.
Definition qpixmap.cpp:576
\inmodule QtCore\reentrant
Definition qpoint.h:25
\inmodule QtCore\reentrant
Definition qrect.h:30
const_iterator constEnd() const noexcept
Definition qset.h:143
iterator find(const T &value)
Definition qset.h:159
\inmodule QtCore
Definition qsize.h:25
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
QString first(qsizetype n) const &
Definition qstring.h:390
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
QByteArray toUtf8() const &
Definition qstring.h:634
qsizetype length() const noexcept
Returns the number of characters in this string.
Definition qstring.h:191
QPainter paint
QSet< QString >::iterator it
rect
[4]
fontMetrics
else opt state
[0]
static QString fetchFont(const QString &query)
Combined button and popup list for selecting options.
Q_CORE_EXPORT QtJniTypes::Context context()
@ AlignCenter
Definition qnamespace.h:163
@ transparent
Definition qnamespace.h:47
static void * context
Q_DECLARE_JNI_CLASS(List, "java/util/List")
static QByteArray cacheKey(Args &&...args)
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
GLenum mode
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint64 GLenum GLint fd
GLenum GLsizeiptr const void * fontData
GLenum query
const GLubyte * c
GLenum GLenum GLenum GLenum GLenum scale
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QString qEnvironmentVariable(const char *varName, const QString &defaultValue)
#define Q_UNUSED(x)
unsigned long long quint64
Definition qtypes.h:61
double qreal
Definition qtypes.h:187
QFile file
[0]
QPainter painter(this)
[7]