From c5af04cf8aa7bf2fbeaaf2a40f169fe8c17239f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C5=82a=C5=BCej=20Szczygie=C5=82?= Date: Thu, 13 Jul 2017 20:02:58 +0200 Subject: HiDPI: Fix calculating window mask from pixmap on drag and drop Use platform window directly for setting a mask to prevent bitmap scaling if pixmap and window DPR are the same. Amends: 42f788ffe26d67864d569c3a3044619d49fc693a Task-number: QTBUG-61948 Change-Id: I5eec85c01f20bdefff7343e83ff10cbcb2c79508 Reviewed-by: Shawn Rutledge --- src/gui/kernel/qshapedpixmapdndwindow.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/gui') diff --git a/src/gui/kernel/qshapedpixmapdndwindow.cpp b/src/gui/kernel/qshapedpixmapdndwindow.cpp index b54c6b67a2..8509eb0961 100644 --- a/src/gui/kernel/qshapedpixmapdndwindow.cpp +++ b/src/gui/kernel/qshapedpixmapdndwindow.cpp @@ -39,6 +39,8 @@ #include "qshapedpixmapdndwindow_p.h" +#include "qplatformwindow.h" + #include #include #include @@ -70,7 +72,12 @@ void QShapedPixmapWindow::setPixmap(const QPixmap &pixmap) if (!mask.isNull()) { if (!handle()) create(); - setMask(mask); + if (auto platformWindow = handle()) { + const auto pixmapDpr = m_pixmap.devicePixelRatio(); + const auto winDpr = devicePixelRatio(); + const auto maskSize = (QSizeF(m_pixmap.size()) * winDpr / pixmapDpr).toSize(); + platformWindow->setMask(QBitmap(mask.scaled(maskSize))); + } } } } -- cgit v1.2.3 From 8c4207dddf9b2af0767de2ef0a10652612d462a5 Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Thu, 2 Aug 2018 13:11:20 +0200 Subject: Fix crash in qppmhandler for certain malformed image files The ppm format specifies that the maximum color value field must be less than 65536. The handler did not enforce this, leading to potentional overflow when the value was used in 16 bits context. Task-number: QTBUG-69449 Change-Id: Iea7a7e0f8953ec1ea8571e215687d12a9d77e11c Reviewed-by: Lars Knoll --- src/gui/image/qppmhandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/gui') diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp index e9f5a905f0..53e3fa293d 100644 --- a/src/gui/image/qppmhandler.cpp +++ b/src/gui/image/qppmhandler.cpp @@ -115,7 +115,7 @@ static bool read_pbm_header(QIODevice *device, char& type, int& w, int& h, int& else mcc = read_pbm_int(device); // get max color component - if (w <= 0 || w > 32767 || h <= 0 || h > 32767 || mcc <= 0) + if (w <= 0 || w > 32767 || h <= 0 || h > 32767 || mcc <= 0 || mcc > 0xffff) return false; // weird P.M image return true; -- cgit v1.2.3 From 1c8f9eb79da837db8e37cf6348de459088c3a20e Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 2 Aug 2018 18:05:51 +0200 Subject: Add missing optimization for loading RGB32 to RGBA64 using NEON The rest of the RGB64 routines were optimized, but the loading of RGB32 was not as it was originally not used much, but with ARGB32 using the RGB64 backend, it is essential for decent performance. Task-number: QTBUG-69724 Change-Id: I1c02411ed29d3d993427afde44dfa83689d117e0 Reviewed-by: Lars Knoll --- src/gui/painting/qdrawhelper.cpp | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'src/gui') diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 34847daf55..9bb1498ff0 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -618,6 +618,53 @@ static inline void qConvertARGB32PMToARGB64PM_sse2(QRgba64 *buffer, const uint * *buffer++ = QRgba64::fromArgb32(s); } } +#elif defined(__ARM_NEON__) +template +static inline void qConvertARGB32PMToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count) +{ + if (count <= 0) + return; + + const uint32x4_t amask = vdupq_n_u32(0xff000000); +#if defined(Q_PROCESSOR_ARM_64) + const uint8x16_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15}; +#else + const uint8x8_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7 }; +#endif + int i = 0; + for (; i < count-3; i += 4) { + uint32x4_t vs32 = vld1q_u32(src); + src += 4; + if (maskAlpha) + vs32 = vorrq_u32(vs32, amask); + uint8x16_t vs8 = vreinterpretq_u8_u32(vs32); + if (!RGBA) { +#if defined(Q_PROCESSOR_ARM_64) + vs8 = vqtbl1q_u8(vs8, rgbaMask); +#else + // no vqtbl1q_u8 + const uint8x8_t vlo = vtbl1_u8(vget_low_u8(vs8), rgbaMask); + const uint8x8_t vhi = vtbl1_u8(vget_high_u8(vs8), rgbaMask); + vs8 = vcombine_u8(vlo, vhi); +#endif + } + uint8x16x2_t v = vzipq_u8(vs8, vs8); + + vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[0])); + buffer += 2; + vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[1])); + buffer += 2; + } + + SIMD_EPILOGUE(i, count, 3) { + uint s = *src++; + if (maskAlpha) + s = s | 0xff000000; + if (RGBA) + s = RGBA2ARGB(s); + *buffer++ = QRgba64::fromArgb32(s); + } +} #endif static const QRgba64 *QT_FASTCALL convertRGB32ToRGB64(QRgba64 *buffer, const uint *src, int count, @@ -625,6 +672,8 @@ static const QRgba64 *QT_FASTCALL convertRGB32ToRGB64(QRgba64 *buffer, const uin { #ifdef __SSE2__ qConvertARGB32PMToARGB64PM_sse2(buffer, src, count); +#elif defined(__ARM_NEON__) + qConvertARGB32PMToRGBA64PM_neon(buffer, src, count); #else for (int i = 0; i < count; ++i) buffer[i] = QRgba64::fromArgb32(0xff000000 | src[i]); @@ -639,6 +688,10 @@ static const QRgba64 *QT_FASTCALL convertARGB32ToARGB64PM(QRgba64 *buffer, const qConvertARGB32PMToARGB64PM_sse2(buffer, src, count); for (int i = 0; i < count; ++i) buffer[i] = buffer[i].premultiplied(); +#elif defined(__ARM_NEON__) + qConvertARGB32PMToRGBA64PM_neon(buffer, src, count); + for (int i = 0; i < count; ++i) + buffer[i] = buffer[i].premultiplied(); #else for (int i = 0; i < count; ++i) buffer[i] = QRgba64::fromArgb32(src[i]).premultiplied(); @@ -651,6 +704,8 @@ static const QRgba64 *QT_FASTCALL convertARGB32PMToARGB64PM(QRgba64 *buffer, con { #ifdef __SSE2__ qConvertARGB32PMToARGB64PM_sse2(buffer, src, count); +#elif defined(__ARM_NEON__) + qConvertARGB32PMToRGBA64PM_neon(buffer, src, count); #else for (int i = 0; i < count; ++i) buffer[i] = QRgba64::fromArgb32(src[i]); @@ -665,6 +720,10 @@ static const QRgba64 *QT_FASTCALL convertRGBA8888ToARGB64PM(QRgba64 *buffer, con qConvertARGB32PMToARGB64PM_sse2(buffer, src, count); for (int i = 0; i < count; ++i) buffer[i] = buffer[i].premultiplied(); +#elif defined(__ARM_NEON__) + qConvertARGB32PMToRGBA64PM_neon(buffer, src, count); + for (int i = 0; i < count; ++i) + buffer[i] = buffer[i].premultiplied(); #else for (int i = 0; i < count; ++i) buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])).premultiplied(); @@ -677,6 +736,8 @@ static const QRgba64 *QT_FASTCALL convertRGBA8888PMToARGB64PM(QRgba64 *buffer, c { #ifdef __SSE2__ qConvertARGB32PMToARGB64PM_sse2(buffer, src, count); +#elif defined(__ARM_NEON__) + qConvertARGB32PMToRGBA64PM_neon(buffer, src, count); #else for (int i = 0; i < count; ++i) buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])); -- cgit v1.2.3 From cdf154e65a3137597f62880361c407e368aae0d6 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 2 Aug 2018 16:34:43 +0200 Subject: Optimize blits of any compatible formats The fast image blending is only used for SourceOver composition, but several of our embedded backends make heavy use of Source composition which doesn't have a short-cut. This patch adds a blitting short cut that works in those cases. Task-number: QTBUG-69724 Change-Id: Icc61a67cc27bc83863153d69cae60dd986d26f69 Reviewed-by: Lars Knoll --- src/gui/painting/qpaintengine_raster.cpp | 119 ++++++++++++++++++++++++++++++- src/gui/painting/qpaintengine_raster_p.h | 3 + 2 files changed, 120 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 6336b2943e..cade334ea6 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -1056,6 +1056,77 @@ void QRasterPaintEnginePrivate::drawImage(const QPointF &pt, alpha); } +void QRasterPaintEnginePrivate::blitImage(const QPointF &pt, + const QImage &img, + const QRect &clip, + const QRect &sr) +{ + if (!clip.isValid()) + return; + + Q_ASSERT(img.depth() >= 8); + + qsizetype srcBPL = img.bytesPerLine(); + const uchar *srcBits = img.bits(); + int srcSize = img.depth() >> 3; // This is the part that is incompatible with lower than 8-bit.. + int iw = img.width(); + int ih = img.height(); + + if (!sr.isEmpty()) { + iw = sr.width(); + ih = sr.height(); + // Adjust the image according to the source offset... + srcBits += ((sr.y() * srcBPL) + sr.x() * srcSize); + } + + // adapt the x parameters + int x = qRound(pt.x()); + int cx1 = clip.x(); + int cx2 = clip.x() + clip.width(); + if (x < cx1) { + int d = cx1 - x; + srcBits += srcSize * d; + iw -= d; + x = cx1; + } + if (x + iw > cx2) { + int d = x + iw - cx2; + iw -= d; + } + if (iw <= 0) + return; + + // adapt the y paremeters... + int cy1 = clip.y(); + int cy2 = clip.y() + clip.height(); + int y = qRound(pt.y()); + if (y < cy1) { + int d = cy1 - y; + srcBits += srcBPL * d; + ih -= d; + y = cy1; + } + if (y + ih > cy2) { + int d = y + ih - cy2; + ih -= d; + } + if (ih <= 0) + return; + + // blit.. + int dstSize = rasterBuffer->bytesPerPixel(); + qsizetype dstBPL = rasterBuffer->bytesPerLine(); + const uint *src = (const uint *) srcBits; + uint *dst = reinterpret_cast(rasterBuffer->buffer() + x * dstSize + y * dstBPL); + + const int len = iw * (qt_depthForFormat(rasterBuffer->format) >> 3); + for (int y = 0; y < ih; ++y) { + memcpy(dst, src, len); + dst = (quint32 *)(((uchar *) dst) + dstBPL); + src = (const quint32 *)(((const uchar *) src) + srcBPL); + } +} + void QRasterPaintEnginePrivate::systemStateChanged() { @@ -2160,7 +2231,15 @@ void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img) const QClipData *clip = d->clip(); QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy()); - if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) { + if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img)) { + if (!clip) { + d->blitImage(pt, img, d->deviceRect); + return; + } else if (clip->hasRectClip) { + d->blitImage(pt, img, clip->clipRect); + return; + } + } else if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) { SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()]; if (func) { if (!clip) { @@ -2445,7 +2524,16 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe fillPath(path, &d->image_filler_xform); s->matrix = m; } else { - if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) { + if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img)) { + QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy()); + if (!clip) { + d->blitImage(pt, img, d->deviceRect, sr.toRect()); + return; + } else if (clip->hasRectClip) { + d->blitImage(pt, img, clip->clipRect, sr.toRect()); + return; + } + } else if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) { SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()]; if (func) { QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy()); @@ -3665,6 +3753,33 @@ bool QRasterPaintEnginePrivate::canUseFastImageBlending(QPainter::CompositionMod && !image.hasAlphaChannel())); } +bool QRasterPaintEnginePrivate::canUseImageBlitting(QPainter::CompositionMode mode, const QImage &image) const +{ + Q_Q(const QRasterPaintEngine); + const QRasterPaintEngineState *s = q->state(); + + if (!s->flags.fast_images || s->intOpacity != 256 || qt_depthForFormat(rasterBuffer->format) < 8) + return false; + + QImage::Format dFormat = rasterBuffer->format; + QImage::Format sFormat = image.format(); + // Formats must match or source format must be a subset of destination format + if (dFormat != sFormat && image.pixelFormat().alphaUsage() == QPixelFormat::IgnoresAlpha) { + if ((sFormat == QImage::Format_RGB32 && dFormat == QImage::Format_ARGB32) + || (sFormat == QImage::Format_RGBX8888 && dFormat == QImage::Format_RGBA8888)) + sFormat = dFormat; + else + sFormat = qt_maybeAlphaVersionWithSameDepth(sFormat); // this returns premul formats + } + if (dFormat != sFormat) + return false; + + return s->matrix.type() <= QTransform::TxTranslate + && (mode == QPainter::CompositionMode_Source + || (mode == QPainter::CompositionMode_SourceOver + && !image.hasAlphaChannel())); +} + QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color) { Q_ASSERT(image.depth() == 1); diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h index 8c6f668d9d..14eddf07b1 100644 --- a/src/gui/painting/qpaintengine_raster_p.h +++ b/src/gui/painting/qpaintengine_raster_p.h @@ -291,6 +291,8 @@ public: void drawImage(const QPointF &pt, const QImage &img, SrcOverBlendFunc func, const QRect &clip, int alpha, const QRect &sr = QRect()); + void blitImage(const QPointF &pt, const QImage &img, + const QRect &clip, const QRect &sr = QRect()); QTransform brushMatrix() const { Q_Q(const QRasterPaintEngine); @@ -313,6 +315,7 @@ public: void recalculateFastImages(); bool canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const; + bool canUseImageBlitting(QPainter::CompositionMode mode, const QImage &image) const; QPaintDevice *device; QScopedPointer outlineMapper; -- cgit v1.2.3 From 65cd6f2e8271d070cd89da49d0993863e8836558 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Fri, 3 Aug 2018 11:31:42 +0200 Subject: Fix conversion from transparent indexed8 to RGB32 A typo meant the color-table was not fixed. For safety fallback colors are also made opaque. Change-Id: I3e609882177604910c4343c86f00221a89af9078 Reviewed-by: Eirik Aavitsland --- src/gui/image/qimage_conversions.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 1b4d3e63dd..d981c43711 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -1194,7 +1194,7 @@ static QVector fix_color_table(const QVector &ctbl, QImage::Format f if (format == QImage::Format_RGB32) { // check if the color table has alpha for (int i = 0; i < colorTable.size(); ++i) - if (qAlpha(colorTable.at(i) != 0xff)) + if (qAlpha(colorTable.at(i)) != 0xff) colorTable[i] = colorTable.at(i) | 0xff000000; } else if (format == QImage::Format_ARGB32_Premultiplied) { // check if the color table has alpha @@ -1796,8 +1796,9 @@ static void convert_Indexed8_to_X32(QImageData *dest, const QImageData *src, Qt: if (colorTable.size() < 256) { int tableSize = colorTable.size(); colorTable.resize(256); + QRgb fallbackColor = (dest->format == QImage::Format_RGB32) ? 0xff000000 : 0; for (int i=tableSize; i<256; ++i) - colorTable[i] = 0; + colorTable[i] = fallbackColor; } int w = src->width; -- cgit v1.2.3 From ae289884db05cbaac71156983974eebfb9b59730 Mon Sep 17 00:00:00 2001 From: Paul Wicking Date: Fri, 3 Aug 2018 14:09:52 +0200 Subject: Doc: Fix wrong link in QFont documentation Task-number: QTBUG-62072 Change-Id: I587534fc5723b3d198fe2065fbcf1bee4871a768 Reviewed-by: Mitch Curtis --- src/gui/text/qfont.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/gui') diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index c7fff266ad..f7462b65c8 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -1254,7 +1254,7 @@ QFont::StyleStrategy QFont::styleStrategy() const /*! Returns the StyleHint. - The style hint affects the \l{QFont}{font matching} algorithm. + The style hint affects the \l{#fontmatching}{font matching algorithm}. See \l QFont::StyleHint for the list of available hints. \sa setStyleHint(), QFont::StyleStrategy, QFontInfo::styleHint() -- cgit v1.2.3