QIcon: clean up Windows and Android icon engines

Use good old QString for the list of glyphs, and just render what we
get. The use case where we need to draw multiple symbols on top of
each other is (for now) academic, and we can support emojis just with
QString. Proof the latter point by mapping "banana" to the respective
emoji.

Change-Id: I8005a99f015e6eb2a2a635f9d892163f2008a673
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
bb10
Volker Hilsheimer 2023-12-06 18:10:43 +01:00
parent dcfd68c827
commit 12694cfc16
4 changed files with 54 additions and 70 deletions

View File

@ -219,29 +219,31 @@ static QString fetchFont(const QString &query)
}
}
QAndroidPlatformIconEngine::Glyphs QAndroidPlatformIconEngine::glyphs() const
QString QAndroidPlatformIconEngine::glyphs() const
{
if (!QFontInfo(m_iconFont).exactMatch())
return {};
static constexpr std::pair<QStringView, Glyphs> glyphMap[] = {
{u"edit-clear", 0xe872},
{u"edit-copy", 0xe14d},
{u"edit-cut", 0xe14e},
{u"edit-delete", 0xe14a},
{u"edit-find", 0xe8b6},
{u"edit-find-replace", 0xe881},
{u"edit-paste", 0xe14f},
{u"edit-redo", 0xe15a},
{u"edit-select-all", 0xe162},
{u"edit-undo", 0xe166},
{u"printer", 0xe8ad},
static constexpr std::pair<QLatin1StringView, QStringView> glyphMap[] = {
{QIcon::ThemeIcon::EditClear, u"\ue872"},
{QIcon::ThemeIcon::EditCopy, u"\ue14d"},
{QIcon::ThemeIcon::EditCut, u"\ue14e"},
{QIcon::ThemeIcon::EditDelete, u"\ue14a"},
{QIcon::ThemeIcon::EditFind, u"\ue8b6"},
{QIcon::ThemeIcon::EditFindReplace, u"\ue881"},
{QIcon::ThemeIcon::EditPaste, u"\ue14f"},
{QIcon::ThemeIcon::EditRedo, u"\ue15a"},
{QIcon::ThemeIcon::EditSelectAll, u"\ue162"},
{QIcon::ThemeIcon::EditUndo, u"\ue166"},
{QIcon::ThemeIcon::Printer, u"\ue8ad"},
{QLatin1StringView("banana"), u"🍌"},
};
const auto it = std::find_if(std::begin(glyphMap), std::end(glyphMap), [this](const auto &c){
return c.first == m_iconName;
});
return it != std::end(glyphMap) ? it->second : Glyphs();
return it != std::end(glyphMap) ? it->second.toString()
: (m_iconName.length() == 1 ? m_iconName : QString());
}
QAndroidPlatformIconEngine::QAndroidPlatformIconEngine(const QString &iconName)
@ -284,7 +286,13 @@ QString QAndroidPlatformIconEngine::iconName()
bool QAndroidPlatformIconEngine::isNull()
{
return m_glyphs.isNull() || !QFontMetrics(m_iconFont).inFont(m_glyphs.codepoints[0]);
if (m_glyphs.isEmpty())
return true;
const QChar c0 = m_glyphs.at(0);
const QFontMetrics fontMetrics(m_iconFont);
if (c0.category() == QChar::Other_Surrogate && m_glyphs.size() > 1)
return !fontMetrics.inFontUcs4(QChar::surrogateToUcs4(c0, m_glyphs.at(1)));
return !fontMetrics.inFont(c0);
}
QList<QSize> QAndroidPlatformIconEngine::availableSizes(QIcon::Mode, QIcon::State)
@ -332,15 +340,7 @@ QPixmap QAndroidPlatformIconEngine::scaledPixmap(const QSize &size, QIcon::Mode
}
const QRect rect({0, 0}, size);
if (m_glyphs.codepoints[0] == QChar(0xffff)) {
painter.drawText(rect, Qt::AlignCenter, QString(m_glyphs.codepoints + 1, 2));
} else {
for (const auto &glyph : m_glyphs.codepoints) {
if (glyph.isNull())
break;
painter.drawText(rect, glyph);
}
}
painter.drawText(rect, Qt::AlignCenter, m_glyphs);
m_cacheKey = cacheKey;
}

View File

@ -30,19 +30,11 @@ private:
{
return (quint64(mode) << 32) | state;
}
struct Glyphs
{
constexpr Glyphs(char16_t g1 = 0, char16_t g2 = 0, char16_t g3 = 0) noexcept
: codepoints{g1, g2, g3}
{}
constexpr bool isNull() const noexcept { return codepoints[0].isNull(); }
const QChar codepoints[3] = {};
};
Glyphs glyphs() const;
QString glyphs() const;
const QString m_iconName;
QFont m_iconFont;
const Glyphs m_glyphs;
const QString m_glyphs;
mutable QPixmap m_pixmap;
mutable quint64 m_cacheKey = {};
};

View File

@ -12,31 +12,31 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
QWindowsIconEngine::Glyphs QWindowsIconEngine::glyphs() const
QString QWindowsIconEngine::glyphs() const
{
if (!QFontInfo(m_iconFont).exactMatch())
return {};
static constexpr std::pair<QStringView, Glyphs> glyphMap[] = {
{u"edit-clear", 0xe894},
{u"edit-copy", 0xe8c8},
{u"edit-cut", 0xe8c6},
{u"edit-delete", 0xe74d},
{u"edit-find", 0xe721},
{u"edit-find-replace", Glyphs(0xeb51, 0xeb52)},
{u"edit-paste", 0xe77f},
{u"edit-redo", 0xe7a6},
{u"edit-select-all", 0xe8b3},
{u"edit-undo", 0xe7a7},
{u"printer", 0xe749},
{u"red-heart", Glyphs(0x2764, 0xFE0F)},
{u"banana", Glyphs(0xffff, 0xD83C, 0xDF4C)},
static constexpr std::pair<QLatin1StringView, QStringView> glyphMap[] = {
{QIcon::ThemeIcon::EditClear, u"\ue894"},
{QIcon::ThemeIcon::EditCopy, u"\ue8c8"},
{QIcon::ThemeIcon::EditCut, u"\ue8c6"},
{QIcon::ThemeIcon::EditDelete, u"\ue74d"},
{QIcon::ThemeIcon::EditFind, u"\ue721"},
{QIcon::ThemeIcon::EditPaste, u"\ue77f"},
{QIcon::ThemeIcon::EditRedo, u"\ue7a6"},
{QIcon::ThemeIcon::EditSelectAll, u"\ue8b3"},
{QIcon::ThemeIcon::EditUndo, u"\ue7a7"},
{QIcon::ThemeIcon::Printer, u"\ue749"},
{QLatin1StringView("banana"), u"🍌"},
};
const auto it = std::find_if(std::begin(glyphMap), std::end(glyphMap), [this](const auto &c){
return c.first == m_iconName;
});
return it != std::end(glyphMap) ? it->second : Glyphs();
return it != std::end(glyphMap) ? it->second.toString()
: (m_iconName.length() == 1 ? m_iconName : QString());
}
namespace {
@ -74,7 +74,14 @@ QString QWindowsIconEngine::iconName()
bool QWindowsIconEngine::isNull()
{
return m_glyphs.isNull();
if (m_glyphs.isEmpty())
return true;
const QChar c0 = m_glyphs.at(0);
const QFontMetrics fontMetrics(m_iconFont);
if (c0.category() == QChar::Other_Surrogate && m_glyphs.size() > 1)
return !fontMetrics.inFontUcs4(QChar::surrogateToUcs4(c0, m_glyphs.at(1)));
return !fontMetrics.inFont(c0);
}
QList<QSize> QWindowsIconEngine::availableSizes(QIcon::Mode, QIcon::State)
@ -122,15 +129,7 @@ QPixmap QWindowsIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QI
}
const QRect rect({0, 0}, size);
if (m_glyphs.codepoints[0] == QChar(0xffff)) {
painter.drawText(rect, Qt::AlignCenter, QString(m_glyphs.codepoints + 1, 2));
} else {
for (const auto &glyph : m_glyphs.codepoints) {
if (glyph.isNull())
break;
painter.drawText(rect, glyph);
}
}
painter.drawText(rect, Qt::AlignCenter, m_glyphs);
m_cacheKey = cacheKey;
}

View File

@ -32,19 +32,12 @@ private:
{
return (quint64(mode) << 32) | state;
}
struct Glyphs
{
constexpr Glyphs(char16_t g1 = 0, char16_t g2 = 0, char16_t g3 = 0) noexcept
: codepoints{g1, g2, g3}
{}
constexpr bool isNull() const noexcept { return codepoints[0].isNull(); }
const QChar codepoints[3] = {};
};
Glyphs glyphs() const;
QString glyphs() const;
const QString m_iconName;
const QFont m_iconFont;
const Glyphs m_glyphs;
const QString m_glyphs;
mutable QPixmap m_pixmap;
mutable quint64 m_cacheKey = {};
};