diff options
Diffstat (limited to 'src/gui/image')
-rw-r--r-- | src/gui/image/qiconloader.cpp | 5 | ||||
-rw-r--r-- | src/gui/image/qimage.cpp | 47 | ||||
-rw-r--r-- | src/gui/image/qimage.h | 4 | ||||
-rw-r--r-- | src/gui/image/qimage_neon.cpp | 66 | ||||
-rw-r--r-- | src/gui/image/qimage_p.h | 6 | ||||
-rw-r--r-- | src/gui/image/qpixmap.cpp | 15 | ||||
-rw-r--r-- | src/gui/image/qplatformpixmap.cpp | 1 |
7 files changed, 87 insertions, 57 deletions
diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp index a9adde8c8d..1d0c93f26f 100644 --- a/src/gui/image/qiconloader.cpp +++ b/src/gui/image/qiconloader.cpp @@ -629,7 +629,10 @@ void QIconLoaderEngine::ensureLoaded() void QIconLoaderEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) { - QSize pixmapSize = rect.size(); + const qreal dpr = !qApp->testAttribute(Qt::AA_UseHighDpiPixmaps) ? + qreal(1.0) : painter->device()->devicePixelRatioF(); + + QSize pixmapSize = rect.size() * dpr; painter->drawPixmap(rect, pixmap(pixmapSize, mode, state)); } diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 18125460c7..8b2db6d346 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -127,7 +127,7 @@ QImageData * QImageData::create(const QSize &size, QImage::Format format) int height = size.height(); int depth = qt_depthForFormat(format); auto params = calculateImageParameters(width, height, depth); - if (params.bytesPerLine < 0) + if (!params.isValid()) return nullptr; QScopedPointer<QImageData> d(new QImageData); @@ -786,7 +786,7 @@ QImageData *QImageData::create(uchar *data, int width, int height, int bpl, QIm const int depth = qt_depthForFormat(format); auto params = calculateImageParameters(width, height, depth); - if (params.totalSize < 0) + if (!params.isValid()) return nullptr; if (bpl > 0) { @@ -1094,16 +1094,32 @@ void QImage::detach() } -static void copyMetadata(QImageData *dst, const QImageData *src) +static void copyPhysicalMetadata(QImageData *dst, const QImageData *src) { - // Doesn't copy colortable and alpha_clut, or offset. dst->dpmx = src->dpmx; dst->dpmy = src->dpmy; dst->devicePixelRatio = src->devicePixelRatio; +} + +static void copyMetadata(QImageData *dst, const QImageData *src) +{ + // Doesn't copy colortable and alpha_clut, or offset. + copyPhysicalMetadata(dst, src); dst->text = src->text; dst->colorSpace = src->colorSpace; } +static void copyMetadata(QImage *dst, const QImage &src) +{ + dst->setDotsPerMeterX(src.dotsPerMeterX()); + dst->setDotsPerMeterY(src.dotsPerMeterY()); + dst->setDevicePixelRatio(src.devicePixelRatio()); + const auto textKeys = src.textKeys(); + for (const auto &key: textKeys) + dst->setText(key, src.text(key)); + +} + /*! \fn QImage QImage::copy(int x, int y, int width, int height) const \overload @@ -1492,10 +1508,17 @@ qsizetype QImage::sizeInBytes() const \sa scanLine() */ +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) +qsizetype QImage::bytesPerLine() const +{ + return d ? d->bytes_per_line : 0; +} +#else int QImage::bytesPerLine() const { return d ? d->bytes_per_line : 0; } +#endif /*! @@ -2948,8 +2971,10 @@ QImage QImage::createAlphaMask(Qt::ImageConversionFlags flags) const } QImage mask(d->width, d->height, Format_MonoLSB); - if (!mask.isNull()) + if (!mask.isNull()) { dither_to_Mono(mask.d, d, flags, true); + copyPhysicalMetadata(mask.d, d); + } return mask; } @@ -3067,6 +3092,7 @@ QImage QImage::createHeuristicMask(bool clipTight) const #undef PIX + copyPhysicalMetadata(m.d, d); return m; } #endif //QT_NO_IMAGE_HEURISTIC_MASK @@ -3110,6 +3136,8 @@ QImage QImage::createMaskFromColor(QRgb color, Qt::MaskMode mode) const } if (mode == Qt::MaskOutColor) maskImage.invertPixels(); + + copyPhysicalMetadata(maskImage.d, d); return maskImage; } @@ -4681,8 +4709,7 @@ QImage QImage::smoothScaled(int w, int h) const { static QImage rotated90(const QImage &image) { QImage out(image.height(), image.width(), image.format()); - out.setDotsPerMeterX(image.dotsPerMeterY()); - out.setDotsPerMeterY(image.dotsPerMeterX()); + copyMetadata(&out, image); if (image.colorCount() > 0) out.setColorTable(image.colorTable()); int w = image.width(); @@ -4710,8 +4737,7 @@ static QImage rotated180(const QImage &image) return image.mirrored(true, true); QImage out(image.width(), image.height(), image.format()); - out.setDotsPerMeterX(image.dotsPerMeterY()); - out.setDotsPerMeterY(image.dotsPerMeterX()); + copyMetadata(&out, image); if (image.colorCount() > 0) out.setColorTable(image.colorTable()); int w = image.width(); @@ -4723,8 +4749,7 @@ static QImage rotated180(const QImage &image) static QImage rotated270(const QImage &image) { QImage out(image.height(), image.width(), image.format()); - out.setDotsPerMeterX(image.dotsPerMeterY()); - out.setDotsPerMeterY(image.dotsPerMeterX()); + copyMetadata(&out, image); if (image.colorCount() > 0) out.setColorTable(image.colorTable()); int w = image.width(); diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index b09e69c839..af7e6988cb 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -228,7 +228,11 @@ public: uchar *scanLine(int); const uchar *scanLine(int) const; const uchar *constScanLine(int) const; +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + qsizetype bytesPerLine() const; +#else int bytesPerLine() const; +#endif bool valid(int x, int y) const; bool valid(const QPoint &pt) const; diff --git a/src/gui/image/qimage_neon.cpp b/src/gui/image/qimage_neon.cpp index 57a24edeca..9dbcb11db5 100644 --- a/src/gui/image/qimage_neon.cpp +++ b/src/gui/image/qimage_neon.cpp @@ -52,65 +52,41 @@ Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_neon(quint32 *dst, cons const quint32 *const end = dst + len; - // align dst on 64 bits - const int offsetToAlignOn8Bytes = (reinterpret_cast<quintptr>(dst) >> 2) & 0x1; - for (int i = 0; i < offsetToAlignOn8Bytes; ++i) { + // align dst on 128 bits + const int offsetToAlignOn16Bytes = (reinterpret_cast<quintptr>(dst) >> 2) & 0x3; + for (int i = 0; i < offsetToAlignOn16Bytes; ++i) { *dst++ = qRgb(src[0], src[1], src[2]); src += 3; } - if ((len - offsetToAlignOn8Bytes) >= 8) { - const quint32 *const simdEnd = end - 7; -#if !defined(Q_PROCESSOR_ARM_64) - register uint8x8_t fullVector asm ("d3") = vdup_n_u8(0xff); - do { + if ((len - offsetToAlignOn16Bytes) >= 16) { + const quint32 *const simdEnd = end - 15; + uint8x16x4_t dstVector; #if Q_BYTE_ORDER == Q_BIG_ENDIAN - asm volatile ( - "vld3.8 { d4, d5, d6 }, [%[SRC]] !\n\t" - "vst4.8 { d3, d4, d5, d6 }, [%[DST],:64] !\n\t" - : [DST]"+r" (dst), [SRC]"+r" (src) - : "w"(fullVector) - : "memory", "d4", "d5", "d6" - ); + dstVector.val[0] = vdupq_n_u8(0xff); #else - asm volatile ( - "vld3.8 { d0, d1, d2 }, [%[SRC]] !\n\t" - "vswp d0, d2\n\t" - "vst4.8 { d0, d1, d2, d3 }, [%[DST],:64] !\n\t" - : [DST]"+r" (dst), [SRC]"+r" (src) - : "w"(fullVector) - : "memory", "d0", "d1", "d2" - ); + dstVector.val[3] = vdupq_n_u8(0xff); #endif - } while (dst < simdEnd); -#else - register uint8x8_t fullVector asm ("v3") = vdup_n_u8(0xff); do { + uint8x16x3_t srcVector = vld3q_u8(src); + src += 3 * 16; #if Q_BYTE_ORDER == Q_BIG_ENDIAN - asm volatile ( - "ld3 { v4.8b, v5.8b, v6.8b }, [%[SRC]], #24 \n\t" - "st4 { v3.8b, v4.8b, v5.8b, v6.8b }, [%[DST]], #32 \n\t" - : [DST]"+r" (dst), [SRC]"+r" (src) - : "w"(fullVector) - : "memory", "v4", "v5", "v6" - ); + dstVector.val[1] = srcVector.val[0]; + dstVector.val[2] = srcVector.val[1]; + dstVector.val[3] = srcVector.val[2]; #else - asm volatile ( - "ld3 { v0.8b, v1.8b, v2.8b }, [%[SRC]], #24 \n\t" - "mov v4.8b, v2.8b\n\t" - "mov v2.8b, v0.8b\n\t" - "mov v0.8b, v4.8b\n\t" - "st4 { v0.8b, v1.8b, v2.8b, v3.8b }, [%[DST]], #32 \n\t" - : [DST]"+r" (dst), [SRC]"+r" (src) - : "w"(fullVector) - : "memory", "v0", "v1", "v2", "v4" - ); + dstVector.val[0] = srcVector.val[2]; + dstVector.val[1] = srcVector.val[1]; + dstVector.val[2] = srcVector.val[0]; #endif + vst4q_u8(reinterpret_cast<uint8_t*>(dst), dstVector); + dst += 16; } while (dst < simdEnd); -#endif } - while (dst != end) { + int i = 0; + int length = end - dst; + SIMD_EPILOGUE(i, length, 15) { *dst++ = qRgb(src[0], src[1], src[2]); src += 3; } diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h index 1e0578a0f4..9da6acd0a7 100644 --- a/src/gui/image/qimage_p.h +++ b/src/gui/image/qimage_p.h @@ -113,6 +113,7 @@ struct Q_GUI_EXPORT QImageData { // internal image data struct ImageSizeParameters { qsizetype bytesPerLine; qsizetype totalSize; + bool isValid() const { return bytesPerLine > 0 && totalSize > 0; } }; static ImageSizeParameters calculateImageParameters(qsizetype width, qsizetype height, qsizetype depth); }; @@ -139,6 +140,11 @@ QImageData::calculateImageParameters(qsizetype width, qsizetype height, qsizetyp qsizetype dummy; if (mul_overflow(height, qsizetype(sizeof(uchar *)), &dummy)) return invalid; // why is this here? +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) + // Disallow images where width * depth calculations might overflow + if (width > (INT_MAX - 31) / depth) + return invalid; +#endif return { bytes_per_line, total_size }; } diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 2ef1d09422..5b4d218603 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -1552,6 +1552,11 @@ QPixmap QPixmap::fromImage(const QImage &image, Qt::ImageConversionFlags flags) if (image.isNull()) return QPixmap(); + if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(QCoreApplication::instance()))) { + qWarning("QPixmap::fromImage: QPixmap cannot be created without a QGuiApplication"); + return QPixmap(); + } + QScopedPointer<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::PixmapType)); data->fromImage(image, flags); return QPixmap(data.take()); @@ -1574,6 +1579,11 @@ QPixmap QPixmap::fromImageInPlace(QImage &image, Qt::ImageConversionFlags flags) if (image.isNull()) return QPixmap(); + if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(QCoreApplication::instance()))) { + qWarning("QPixmap::fromImageInPlace: QPixmap cannot be created without a QGuiApplication"); + return QPixmap(); + } + QScopedPointer<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::PixmapType)); data->fromImageInPlace(image, flags); return QPixmap(data.take()); @@ -1593,6 +1603,11 @@ QPixmap QPixmap::fromImageInPlace(QImage &image, Qt::ImageConversionFlags flags) */ QPixmap QPixmap::fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags) { + if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(QCoreApplication::instance()))) { + qWarning("QPixmap::fromImageReader: QPixmap cannot be created without a QGuiApplication"); + return QPixmap(); + } + QScopedPointer<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::PixmapType)); data->fromImageReader(imageReader, flags); return QPixmap(data.take()); diff --git a/src/gui/image/qplatformpixmap.cpp b/src/gui/image/qplatformpixmap.cpp index 2209c3de4d..a2e01147c4 100644 --- a/src/gui/image/qplatformpixmap.cpp +++ b/src/gui/image/qplatformpixmap.cpp @@ -178,6 +178,7 @@ QBitmap QPlatformPixmap::mask() const if (mask.isNull()) // allocation failed return QBitmap(); + mask.setDevicePixelRatio(devicePixelRatio()); mask.setColorCount(2); mask.setColor(0, QColor(Qt::color0).rgba()); mask.setColor(1, QColor(Qt::color1).rgba()); |