Apple icon engine: reverse implementation to avoid pixmaps
Instead of implementing scaledPixmap() to rasterize the vector image we get from App/UIKit, and calling that from paint, implement paint() to draw the vector image directly through the painter, and use that in scaledPixmap. Change-Id: I2c62826f29406543bc8d8c7fa71199e91586d83b Reviewed-by: Amr Elsayed <amr.elsayed@qt.io> Reviewed-by: Doris Verria <doris.verria@qt.io> Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io> (cherry picked from commit 9d8c5bc7186b0553c47ddabc9ad6c9d509b35f81) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
c198f7124c
commit
2a1bdbf730
@ -395,21 +395,32 @@ auto *configuredImage(const UIImage *image, const QColor &color)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
template <typename Image>
|
|
||||||
QPixmap imageToPixmap(const Image *image, QSizeF renderSize)
|
|
||||||
{
|
|
||||||
if constexpr (std::is_same_v<Image, NSImage>)
|
|
||||||
return qt_mac_toQPixmap(image, renderSize.toSize());
|
|
||||||
else
|
|
||||||
return QPixmap::fromImage(qt_mac_toQImage(image, renderSize.toSize()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QPixmap QAppleIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
|
QPixmap QAppleIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
|
||||||
{
|
{
|
||||||
const quint64 cacheKey = calculateCacheKey(mode, state);
|
const quint64 cacheKey = calculateCacheKey(mode, state);
|
||||||
if (cacheKey != m_cacheKey || m_pixmap.size() != size || m_pixmap.devicePixelRatio() != scale) {
|
if (cacheKey != m_cacheKey || m_pixmap.size() != size || m_pixmap.devicePixelRatio() != scale) {
|
||||||
|
const QSize paintSize = actualSize(size, mode, state);
|
||||||
|
const QSize paintOffset = paintSize != size
|
||||||
|
? (QSizeF(size - paintSize) * 0.5).toSize()
|
||||||
|
: QSize();
|
||||||
|
|
||||||
|
m_pixmap = QPixmap(size * scale);
|
||||||
|
m_pixmap.setDevicePixelRatio(scale);
|
||||||
|
m_pixmap.fill(Qt::transparent);
|
||||||
|
|
||||||
|
QPainter painter(&m_pixmap);
|
||||||
|
paint(&painter, QRect(paintOffset.width(), paintOffset.height(),
|
||||||
|
paintSize.width(), paintSize.height()), mode, state);
|
||||||
|
|
||||||
|
m_cacheKey = cacheKey;
|
||||||
|
}
|
||||||
|
return m_pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QAppleIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
|
||||||
|
{
|
||||||
|
Q_UNUSED(state);
|
||||||
|
|
||||||
QColor color;
|
QColor color;
|
||||||
const QPalette palette;
|
const QPalette palette;
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
@ -428,36 +439,26 @@ QPixmap QAppleIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIco
|
|||||||
}
|
}
|
||||||
const auto *image = configuredImage(m_image, color);
|
const auto *image = configuredImage(m_image, color);
|
||||||
|
|
||||||
// The size we want might have a different aspect ratio than the icon we have.
|
QMacCGContext ctx(painter);
|
||||||
// So ask for a pixmap with the same aspect ratio as the icon, constrained to the
|
|
||||||
// size we want, and then center that within a pixmap of the requested size.
|
|
||||||
const QSize requestedSize = size * scale;
|
|
||||||
const QSizeF renderSize = actualSize(requestedSize, mode, state);
|
|
||||||
QPixmap iconPixmap = imageToPixmap(image, renderSize);
|
|
||||||
iconPixmap.setDevicePixelRatio(scale);
|
|
||||||
|
|
||||||
if (renderSize != requestedSize) {
|
#if defined(Q_OS_MACOS)
|
||||||
m_pixmap = QPixmap(requestedSize);
|
NSGraphicsContext *gc = [NSGraphicsContext graphicsContextWithCGContext:ctx flipped:YES];
|
||||||
m_pixmap.fill(Qt::transparent);
|
[NSGraphicsContext saveGraphicsState];
|
||||||
m_pixmap.setDevicePixelRatio(scale);
|
[NSGraphicsContext setCurrentContext:gc];
|
||||||
|
|
||||||
QPainter painter(&m_pixmap);
|
const NSSize pixmapSize = NSMakeSize(rect.width(), rect.height());
|
||||||
const QSize offset = ((m_pixmap.deviceIndependentSize()
|
[image setSize:pixmapSize];
|
||||||
- iconPixmap.deviceIndependentSize()) / 2).toSize();
|
const NSRect sourceRect = NSMakeRect(0, 0, pixmapSize.width, pixmapSize.height);
|
||||||
painter.drawPixmap(offset.width(), offset.height(), iconPixmap);
|
const NSRect iconRect = NSMakeRect(rect.x(), rect.y(), pixmapSize.width, pixmapSize.height);
|
||||||
} else {
|
|
||||||
m_pixmap = iconPixmap;
|
|
||||||
}
|
|
||||||
m_cacheKey = cacheKey;
|
|
||||||
}
|
|
||||||
return m_pixmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QAppleIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
|
[image drawInRect:iconRect fromRect:sourceRect operation:NSCompositingOperationSourceOver fraction:1.0 respectFlipped:YES hints:nil];
|
||||||
{
|
[NSGraphicsContext restoreGraphicsState];
|
||||||
const qreal scale = painter->device()->devicePixelRatio();
|
#elif defined(Q_OS_IOS)
|
||||||
// TODO: render the image directly if we don't have the pixmap yet and paint on an image
|
UIGraphicsPushContext(ctx);
|
||||||
painter->drawPixmap(rect, scaledPixmap(rect.size(), mode, state, scale));
|
const CGRect cgrect = CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
|
||||||
|
[image drawInRect:cgrect];
|
||||||
|
UIGraphicsPopContext();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
Loading…
x
Reference in New Issue
Block a user