diff options
Diffstat (limited to 'src/gui')
47 files changed, 1055 insertions, 957 deletions
diff --git a/src/gui/configure.json b/src/gui/configure.json index 220662ea8e..aac70a16a3 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -661,6 +661,26 @@ "fxc.exe" ] }, + "drm_atomic": { + "label": "DRM Atomic API", + "type": "compile", + "test": { + "head": [ + "#include <stdlib.h>", + "#include <stdint.h>", + "extern \"C\" {" + ], + "include": [ + "xf86drmMode.h", + "xf86drm.h" + ], + "tail": [ + "}" + ], + "main": "drmModeAtomicReq *request;" + }, + "use": "drm" + }, "egl-x11": { "label": "EGL on X11", "type": "compile", @@ -1010,6 +1030,11 @@ "condition": "libs.drm", "output": [ "publicQtConfig", "privateFeature" ] }, + "drm_atomic": { + "label": "DRM Atomic API", + "condition": "libs.drm && tests.drm_atomic", + "output": [ "privateFeature" ] + }, "libinput": { "label": "libinput", "condition": "features.libudev && libs.libinput", diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index 76aba944b2..b4942f06d4 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -9,6 +9,7 @@ HEADERS += \ image/qimage_p.h \ image/qimageiohandler.h \ image/qimagereader.h \ + image/qimagereaderwriterhelpers_p.h \ image/qimagewriter.h \ image/qpaintengine_pic_p.h \ image/qpicture.h \ @@ -33,6 +34,7 @@ SOURCES += \ image/qimage_conversions.cpp \ image/qimageiohandler.cpp \ image/qimagereader.cpp \ + image/qimagereaderwriterhelpers.cpp \ image/qimagewriter.cpp \ image/qpaintengine_pic.cpp \ image/qpicture.cpp \ diff --git a/src/gui/image/qbitmap.cpp b/src/gui/image/qbitmap.cpp index e8405a6d11..2453242fa8 100644 --- a/src/gui/image/qbitmap.cpp +++ b/src/gui/image/qbitmap.cpp @@ -189,9 +189,7 @@ QBitmap &QBitmap::operator=(const QPixmap &pixmap) } else if (pixmap.depth() == 1) { // 1-bit pixmap QPixmap::operator=(pixmap); // shallow assignment } else { // n-bit depth pixmap - QImage image; - image = pixmap.toImage(); // convert pixmap to image - *this = fromImage(image); // will dither image + *this = fromImage(pixmap.toImage()); // will dither image } return *this; } @@ -223,6 +221,24 @@ QBitmap::operator QVariant() const return QVariant(QVariant::Bitmap, this); } +static QBitmap makeBitmap(QImage &&image, Qt::ImageConversionFlags flags) +{ + // make sure image.color(0) == Qt::color0 (white) + // and image.color(1) == Qt::color1 (black) + const QRgb c0 = QColor(Qt::black).rgb(); + const QRgb c1 = QColor(Qt::white).rgb(); + if (image.color(0) == c0 && image.color(1) == c1) { + image.invertPixels(); + image.setColor(0, c1); + image.setColor(1, c0); + } + + QScopedPointer<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::BitmapType)); + + data->fromImageInPlace(image, flags | Qt::MonoOnly); + return QPixmap(data.take()); +} + /*! Returns a copy of the given \a image converted to a bitmap using the specified image conversion \a flags. @@ -234,22 +250,24 @@ QBitmap QBitmap::fromImage(const QImage &image, Qt::ImageConversionFlags flags) if (image.isNull()) return QBitmap(); - QImage img = image.convertToFormat(QImage::Format_MonoLSB, flags); + return makeBitmap(image.convertToFormat(QImage::Format_MonoLSB, flags), flags); +} - // make sure image.color(0) == Qt::color0 (white) - // and image.color(1) == Qt::color1 (black) - const QRgb c0 = QColor(Qt::black).rgb(); - const QRgb c1 = QColor(Qt::white).rgb(); - if (img.color(0) == c0 && img.color(1) == c1) { - img.invertPixels(); - img.setColor(0, c1); - img.setColor(1, c0); - } +/*! + \since 5.12 + \overload - QScopedPointer<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::BitmapType)); + Returns a copy of the given \a image converted to a bitmap using + the specified image conversion \a flags. - data->fromImage(img, flags | Qt::MonoOnly); - return QPixmap(data.take()); + \sa fromData() +*/ +QBitmap QBitmap::fromImage(QImage &&image, Qt::ImageConversionFlags flags) +{ + if (image.isNull()) + return QBitmap(); + + return makeBitmap(std::move(image).convertToFormat(QImage::Format_MonoLSB, flags), flags); } /*! @@ -277,7 +295,7 @@ QBitmap QBitmap::fromData(const QSize &size, const uchar *bits, QImage::Format m int bytesPerLine = (size.width() + 7) / 8; for (int y = 0; y < size.height(); ++y) memcpy(image.scanLine(y), bits + bytesPerLine * y, bytesPerLine); - return QBitmap::fromImage(image); + return QBitmap::fromImage(std::move(image)); } /*! diff --git a/src/gui/image/qbitmap.h b/src/gui/image/qbitmap.h index 6a8c8b3457..188064fccf 100644 --- a/src/gui/image/qbitmap.h +++ b/src/gui/image/qbitmap.h @@ -72,6 +72,7 @@ public: inline void clear() { fill(Qt::color0); } static QBitmap fromImage(const QImage &image, Qt::ImageConversionFlags flags = Qt::AutoColor); + static QBitmap fromImage(QImage &&image, Qt::ImageConversionFlags flags = Qt::AutoColor); static QBitmap fromData(const QSize &size, const uchar *bits, QImage::Format monoFormat = QImage::Format_MonoLSB); diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 7fcae12cbd..469ae8b97e 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -2582,15 +2582,14 @@ bool QImage::allGray() const break; } - const int buffer_size = 2048; - uint buffer[buffer_size]; + uint buffer[BufferSize]; const QPixelLayout *layout = &qPixelLayouts[d->format]; FetchPixelsFunc fetch = qFetchPixels[layout->bpp]; for (int j = 0; j < d->height; ++j) { const uchar *b = constScanLine(j); int x = 0; while (x < d->width) { - int l = qMin(d->width - x, buffer_size); + int l = qMin(d->width - x, BufferSize); const uint *ptr = fetch(buffer, b, x, l); ptr = layout->convertToARGB32PM(buffer, ptr, l, 0, 0); for (int i = 0; i < l; ++i) { @@ -3218,14 +3217,13 @@ inline void rgbSwapped_generic(int width, int height, const QImage *src, QImage const uint alphaGreenMask = (((1 << layout->alphaWidth) - 1) << layout->alphaShift) | (((1 << layout->greenWidth) - 1) << layout->greenShift); - const int buffer_size = 2048; - uint buffer[buffer_size]; + uint buffer[BufferSize]; for (int i = 0; i < height; ++i) { uchar *q = dst->scanLine(i); const uchar *p = src->constScanLine(i); int x = 0; while (x < width) { - int l = qMin(width - x, buffer_size); + int l = qMin(width - x, BufferSize); const uint *ptr = fetch(buffer, p, x, l); for (int j = 0; j < l; ++j) { uint red = (ptr[j] >> layout->redShift) & redBlueMask; @@ -3457,8 +3455,7 @@ void QImage::rgbSwapped_inplace() bool QImage::load(const QString &fileName, const char* format) { - QImage image = QImageReader(fileName, format).read(); - operator=(image); + *this = QImageReader(fileName, format).read(); return !isNull(); } @@ -3471,8 +3468,7 @@ bool QImage::load(const QString &fileName, const char* format) bool QImage::load(QIODevice* device, const char* format) { - QImage image = QImageReader(device, format).read(); - operator=(image); + *this = QImageReader(device, format).read(); return !isNull(); } @@ -3492,8 +3488,7 @@ bool QImage::load(QIODevice* device, const char* format) bool QImage::loadFromData(const uchar *data, int len, const char *format) { - QImage image = fromData(data, len, format); - operator=(image); + *this = fromData(data, len, format); return !isNull(); } diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 4eef617336..9a8cbf43c9 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -145,8 +145,7 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio // Cannot be used with indexed formats. Q_ASSERT(dest->format > QImage::Format_Indexed8); Q_ASSERT(src->format > QImage::Format_Indexed8); - const int buffer_size = 2048; - uint buf[buffer_size]; + uint buf[BufferSize]; uint *buffer = buf; const QPixelLayout *srcLayout = &qPixelLayouts[src->format]; const QPixelLayout *destLayout = &qPixelLayouts[dest->format]; @@ -196,7 +195,7 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio if (destLayout->bpp == QPixelLayout::BPP32) buffer = reinterpret_cast<uint *>(destData) + x; else - l = qMin(l, buffer_size); + l = qMin(l, BufferSize); const uint *ptr = fetch(buffer, srcData, x, l); ptr = convertToARGB32PM(buffer, ptr, l, 0, ditherPtr); ptr = convertFromARGB32PM(buffer, ptr, l, 0, ditherPtr); @@ -217,8 +216,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im if (data->depth != qt_depthForFormat(dst_format)) return false; - const int buffer_size = 2048; - uint buffer[buffer_size]; + uint buffer[BufferSize]; const QPixelLayout *srcLayout = &qPixelLayouts[data->format]; const QPixelLayout *destLayout = &qPixelLayouts[dst_format]; uchar *srcData = data->data; @@ -261,7 +259,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im int x = 0; while (x < data->width) { dither.x = x; - int l = qMin(data->width - x, buffer_size); + int l = qMin(data->width - x, BufferSize); const uint *ptr = fetch(buffer, srcData, x, l); ptr = convertToARGB32PM(buffer, ptr, l, 0, ditherPtr); ptr = convertFromARGB32PM(buffer, ptr, l, 0, ditherPtr); diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index 7086e102ea..e77c6f019c 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -164,73 +164,13 @@ #include <private/qpnghandler_p.h> #endif +#include <private/qimagereaderwriterhelpers_p.h> + #include <algorithm> QT_BEGIN_NAMESPACE -#ifndef QT_NO_IMAGEFORMATPLUGIN -Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, - (QImageIOHandlerFactoryInterface_iid, QLatin1String("/imageformats"))) -#endif - -enum _qt_BuiltInFormatType { -#ifndef QT_NO_IMAGEFORMAT_PNG - _qt_PngFormat, -#endif -#ifndef QT_NO_IMAGEFORMAT_BMP - _qt_BmpFormat, -#endif -#ifndef QT_NO_IMAGEFORMAT_PPM - _qt_PpmFormat, - _qt_PgmFormat, - _qt_PbmFormat, -#endif -#ifndef QT_NO_IMAGEFORMAT_XBM - _qt_XbmFormat, -#endif -#ifndef QT_NO_IMAGEFORMAT_XPM - _qt_XpmFormat, -#endif - _qt_NumFormats, - _qt_NoFormat = -1 -}; - -#if !defined(QT_NO_IMAGEFORMAT_PPM) -# define MAX_MT_SIZE 20 -#elif !defined(QT_NO_IMAGEFORMAT_XBM) || !defined(QT_NO_IMAGEFORMAT_XPM) -# define MAX_MT_SIZE 10 -#else -# define MAX_MT_SIZE 4 -#endif - -struct _qt_BuiltInFormatStruct -{ - char extension[4]; - char mimeType[MAX_MT_SIZE]; -}; - -#undef MAX_MT_SIZE - -static const _qt_BuiltInFormatStruct _qt_BuiltInFormats[] = { -#ifndef QT_NO_IMAGEFORMAT_PNG - {"png", "png"}, -#endif -#ifndef QT_NO_IMAGEFORMAT_BMP - {"bmp", "bmp"}, -#endif -#ifndef QT_NO_IMAGEFORMAT_PPM - {"ppm", "x-portable-pixmap"}, - {"pgm", "x-portable-graymap"}, - {"pbm", "x-portable-bitmap"}, -#endif -#ifndef QT_NO_IMAGEFORMAT_XBM - {"xbm", "x-xbitmap"}, -#endif -#ifndef QT_NO_IMAGEFORMAT_XPM - {"xpm", "x-xpixmap"}, -#endif -}; -Q_STATIC_ASSERT(_qt_NumFormats == sizeof _qt_BuiltInFormats / sizeof *_qt_BuiltInFormats); +using namespace QImageReaderWriterHelpers; static QImageIOHandler *createReadHandlerHelper(QIODevice *device, const QByteArray &format, @@ -251,7 +191,7 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device, typedef QMultiMap<int, QString> PluginKeyMap; // check if we have plugins that support the image format - QFactoryLoader *l = loader(); + auto l = QImageReaderWriterHelpers::pluginLoader(); const PluginKeyMap keyMap = l->keyMap(); #ifdef QIMAGEREADER_DEBUG @@ -1565,16 +1505,6 @@ QByteArray QImageReader::imageFormat(QIODevice *device) return format; } -#ifndef QT_NO_IMAGEFORMATPLUGIN -void supportedImageHandlerFormats(QFactoryLoader *loader, - QImageIOPlugin::Capability cap, - QList<QByteArray> *result); - -void supportedImageHandlerMimeTypes(QFactoryLoader *loader, - QImageIOPlugin::Capability cap, - QList<QByteArray> *result); -#endif - /*! Returns the list of image formats supported by QImageReader. @@ -1605,18 +1535,7 @@ void supportedImageHandlerMimeTypes(QFactoryLoader *loader, QList<QByteArray> QImageReader::supportedImageFormats() { - QList<QByteArray> formats; - formats.reserve(_qt_NumFormats); - for (int i = 0; i < _qt_NumFormats; ++i) - formats << _qt_BuiltInFormats[i].extension; - -#ifndef QT_NO_IMAGEFORMATPLUGIN - supportedImageHandlerFormats(loader(), QImageIOPlugin::CanRead, &formats); -#endif // QT_NO_IMAGEFORMATPLUGIN - - std::sort(formats.begin(), formats.end()); - formats.erase(std::unique(formats.begin(), formats.end()), formats.end()); - return formats; + return QImageReaderWriterHelpers::supportedImageFormats(QImageReaderWriterHelpers::CanRead); } /*! @@ -1630,18 +1549,24 @@ QList<QByteArray> QImageReader::supportedImageFormats() QList<QByteArray> QImageReader::supportedMimeTypes() { - QList<QByteArray> mimeTypes; - mimeTypes.reserve(_qt_NumFormats); - for (const auto &fmt : _qt_BuiltInFormats) - mimeTypes.append(QByteArrayLiteral("image/") + fmt.mimeType); + return QImageReaderWriterHelpers::supportedMimeTypes(QImageReaderWriterHelpers::CanRead); +} -#ifndef QT_NO_IMAGEFORMATPLUGIN - supportedImageHandlerMimeTypes(loader(), QImageIOPlugin::CanRead, &mimeTypes); -#endif // QT_NO_IMAGEFORMATPLUGIN +/*! + \since 5.12 - std::sort(mimeTypes.begin(), mimeTypes.end()); - mimeTypes.erase(std::unique(mimeTypes.begin(), mimeTypes.end()), mimeTypes.end()); - return mimeTypes; + Returns the list of image formats corresponding to \mimeType. + + Note that the QGuiApplication instance must be created before this function is + called. + + \sa supportedImageFormats(), supportedMimeTypes() +*/ + +QList<QByteArray> QImageReader::imageFormatsForMimeType(const QByteArray &mimeType) +{ + return QImageReaderWriterHelpers::imageFormatsForMimeType(mimeType, + QImageReaderWriterHelpers::CanRead); } QT_END_NAMESPACE diff --git a/src/gui/image/qimagereader.h b/src/gui/image/qimagereader.h index 9d6c1e0b1e..4e9a08b6e6 100644 --- a/src/gui/image/qimagereader.h +++ b/src/gui/image/qimagereader.h @@ -144,6 +144,7 @@ public: static QByteArray imageFormat(QIODevice *device); static QList<QByteArray> supportedImageFormats(); static QList<QByteArray> supportedMimeTypes(); + static QList<QByteArray> imageFormatsForMimeType(const QByteArray &mimeType); private: Q_DISABLE_COPY(QImageReader) diff --git a/src/gui/image/qimagereaderwriterhelpers.cpp b/src/gui/image/qimagereaderwriterhelpers.cpp new file mode 100644 index 0000000000..a5b7fb6449 --- /dev/null +++ b/src/gui/image/qimagereaderwriterhelpers.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qimagereaderwriterhelpers_p.h" + +#include <qjsonarray.h> +#include <qmutex.h> +#include <private/qfactoryloader_p.h> + +QT_BEGIN_NAMESPACE + +namespace QImageReaderWriterHelpers { + +#ifndef QT_NO_IMAGEFORMATPLUGIN + +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, + (QImageIOHandlerFactoryInterface_iid, QLatin1String("/imageformats"))) +Q_GLOBAL_STATIC(QMutex, loaderMutex) + +static void appendImagePluginFormats(QFactoryLoader *loader, + QImageIOPlugin::Capability cap, + QList<QByteArray> *result) +{ + typedef QMultiMap<int, QString> PluginKeyMap; + typedef PluginKeyMap::const_iterator PluginKeyMapConstIterator; + + const PluginKeyMap keyMap = loader->keyMap(); + const PluginKeyMapConstIterator cend = keyMap.constEnd(); + int i = -1; + QImageIOPlugin *plugin = 0; + result->reserve(result->size() + keyMap.size()); + for (PluginKeyMapConstIterator it = keyMap.constBegin(); it != cend; ++it) { + if (it.key() != i) { + i = it.key(); + plugin = qobject_cast<QImageIOPlugin *>(loader->instance(i)); + } + const QByteArray key = it.value().toLatin1(); + if (plugin && (plugin->capabilities(0, key) & cap) != 0) + result->append(key); + } +} + +static void appendImagePluginMimeTypes(QFactoryLoader *loader, + QImageIOPlugin::Capability cap, + QList<QByteArray> *result, + QList<QByteArray> *resultKeys = nullptr) +{ + QList<QJsonObject> metaDataList = loader->metaData(); + + const int pluginCount = metaDataList.size(); + for (int i = 0; i < pluginCount; ++i) { + const QJsonObject metaData = metaDataList.at(i).value(QLatin1String("MetaData")).toObject(); + const QJsonArray keys = metaData.value(QLatin1String("Keys")).toArray(); + const QJsonArray mimeTypes = metaData.value(QLatin1String("MimeTypes")).toArray(); + QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(loader->instance(i)); + const int keyCount = keys.size(); + for (int k = 0; k < keyCount; ++k) { + const QByteArray key = keys.at(k).toString().toLatin1(); + if (plugin && (plugin->capabilities(0, key) & cap) != 0) { + result->append(mimeTypes.at(k).toString().toLatin1()); + if (resultKeys) + resultKeys->append(key); + } + } + } +} + +QSharedPointer<QFactoryLoader> pluginLoader() +{ + loaderMutex()->lock(); + return QSharedPointer<QFactoryLoader>(loader(), [](QFactoryLoader *) { + loaderMutex()->unlock(); + }); +} + +static inline QImageIOPlugin::Capability pluginCapability(Capability cap) +{ + return cap == CanRead ? QImageIOPlugin::CanRead : QImageIOPlugin::CanWrite; +} + +#endif // QT_NO_IMAGEFORMATPLUGIN + +QList<QByteArray> supportedImageFormats(Capability cap) +{ + QList<QByteArray> formats; + formats.reserve(_qt_NumFormats); + for (int i = 0; i < _qt_NumFormats; ++i) + formats << _qt_BuiltInFormats[i].extension; + +#ifndef QT_NO_IMAGEFORMATPLUGIN + appendImagePluginFormats(loader(), pluginCapability(cap), &formats); +#endif // QT_NO_IMAGEFORMATPLUGIN + + std::sort(formats.begin(), formats.end()); + formats.erase(std::unique(formats.begin(), formats.end()), formats.end()); + return formats; +} + +QList<QByteArray> supportedMimeTypes(Capability cap) +{ + QList<QByteArray> mimeTypes; + mimeTypes.reserve(_qt_NumFormats); + for (const auto &fmt : _qt_BuiltInFormats) + mimeTypes.append(QByteArrayLiteral("image/") + fmt.mimeType); + +#ifndef QT_NO_IMAGEFORMATPLUGIN + appendImagePluginMimeTypes(loader(), pluginCapability(cap), &mimeTypes); +#endif // QT_NO_IMAGEFORMATPLUGIN + + std::sort(mimeTypes.begin(), mimeTypes.end()); + mimeTypes.erase(std::unique(mimeTypes.begin(), mimeTypes.end()), mimeTypes.end()); + return mimeTypes; +} + +QList<QByteArray> imageFormatsForMimeType(const QByteArray &mimeType, Capability cap) +{ + QList<QByteArray> formats; + if (mimeType.startsWith("image/")) { + const QByteArray type = mimeType.mid(sizeof("image/") - 1); + for (const auto &fmt : _qt_BuiltInFormats) { + if (fmt.mimeType == type && !formats.contains(fmt.extension)) + formats << fmt.extension; + } + } + +#ifndef QT_NO_IMAGEFORMATPLUGIN + QList<QByteArray> mimeTypes; + QList<QByteArray> keys; + appendImagePluginMimeTypes(loader(), pluginCapability(cap), &mimeTypes, &keys); + for (int i = 0; i < mimeTypes.size(); ++i) { + if (mimeTypes.at(i) == mimeType) { + const auto &key = keys.at(i); + if (!formats.contains(key)) + formats << key; + } + } +#endif // QT_NO_IMAGEFORMATPLUGIN + + return formats; +} + +} // QImageReaderWriterHelpers + +QT_END_NAMESPACE diff --git a/src/gui/image/qimagereaderwriterhelpers_p.h b/src/gui/image/qimagereaderwriterhelpers_p.h new file mode 100644 index 0000000000..6fe418a8ab --- /dev/null +++ b/src/gui/image/qimagereaderwriterhelpers_p.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QIMAGEREADERWRITERHELPERS_P_H +#define QIMAGEREADERWRITERHELPERS_P_H + +#include <QtGui/private/qtguiglobal_p.h> +#include <qsharedpointer.h> +#include "qimageiohandler.h" + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +class QFactoryLoader; + +namespace QImageReaderWriterHelpers { + +enum _qt_BuiltInFormatType { +#ifndef QT_NO_IMAGEFORMAT_PNG + _qt_PngFormat, +#endif +#ifndef QT_NO_IMAGEFORMAT_BMP + _qt_BmpFormat, +#endif +#ifndef QT_NO_IMAGEFORMAT_PPM + _qt_PpmFormat, + _qt_PgmFormat, + _qt_PbmFormat, +#endif +#ifndef QT_NO_IMAGEFORMAT_XBM + _qt_XbmFormat, +#endif +#ifndef QT_NO_IMAGEFORMAT_XPM + _qt_XpmFormat, +#endif + _qt_NumFormats, + _qt_NoFormat = -1 +}; + +#if !defined(QT_NO_IMAGEFORMAT_PPM) +# define MAX_MT_SIZE 20 +#elif !defined(QT_NO_IMAGEFORMAT_XBM) || !defined(QT_NO_IMAGEFORMAT_XPM) +# define MAX_MT_SIZE 10 +#else +# define MAX_MT_SIZE 4 +#endif + +struct _qt_BuiltInFormatStruct +{ + char extension[4]; + char mimeType[MAX_MT_SIZE]; +}; + +#undef MAX_MT_SIZE + +static const _qt_BuiltInFormatStruct _qt_BuiltInFormats[] = { +#ifndef QT_NO_IMAGEFORMAT_PNG + {"png", "png"}, +#endif +#ifndef QT_NO_IMAGEFORMAT_BMP + {"bmp", "bmp"}, +#endif +#ifndef QT_NO_IMAGEFORMAT_PPM + {"ppm", "x-portable-pixmap"}, + {"pgm", "x-portable-graymap"}, + {"pbm", "x-portable-bitmap"}, +#endif +#ifndef QT_NO_IMAGEFORMAT_XBM + {"xbm", "x-xbitmap"}, +#endif +#ifndef QT_NO_IMAGEFORMAT_XPM + {"xpm", "x-xpixmap"}, +#endif +}; +Q_STATIC_ASSERT(_qt_NumFormats == sizeof _qt_BuiltInFormats / sizeof *_qt_BuiltInFormats); + +#ifndef QT_NO_IMAGEFORMATPLUGIN +QSharedPointer<QFactoryLoader> pluginLoader(); +#endif + +enum Capability { + CanRead, + CanWrite +}; +QList<QByteArray> supportedImageFormats(Capability cap); +QList<QByteArray> supportedMimeTypes(Capability cap); +QList<QByteArray> imageFormatsForMimeType(const QByteArray &mimeType, Capability cap); + +} + +QT_END_NAMESPACE + +#endif // QIMAGEREADERWRITERHELPERS_P_H diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp index a39d204677..30ec224158 100644 --- a/src/gui/image/qimagewriter.cpp +++ b/src/gui/image/qimagewriter.cpp @@ -102,7 +102,6 @@ #include <qfileinfo.h> #include <qimage.h> #include <qimageiohandler.h> -#include <qjsonarray.h> #include <qset.h> #include <qvariant.h> @@ -119,15 +118,12 @@ #include <private/qpnghandler_p.h> #endif +#include <private/qimagereaderwriterhelpers_p.h> + #include <algorithm> QT_BEGIN_NAMESPACE -#ifndef QT_NO_IMAGEFORMATPLUGIN -Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, - (QImageIOHandlerFactoryInterface_iid, QLatin1String("/imageformats"))) -#endif - static QImageIOHandler *createWriteHandlerHelper(QIODevice *device, const QByteArray &format) { @@ -139,7 +135,7 @@ static QImageIOHandler *createWriteHandlerHelper(QIODevice *device, typedef QMultiMap<int, QString> PluginKeyMap; // check if any plugins can write the image - QFactoryLoader *l = loader(); + auto l = QImageReaderWriterHelpers::pluginLoader(); const PluginKeyMap keyMap = l->keyMap(); int suffixPluginIndex = -1; #endif @@ -824,52 +820,6 @@ bool QImageWriter::supportsOption(QImageIOHandler::ImageOption option) const return d->handler->supportsOption(option); } - -#ifndef QT_NO_IMAGEFORMATPLUGIN -void supportedImageHandlerFormats(QFactoryLoader *loader, - QImageIOPlugin::Capability cap, - QList<QByteArray> *result) -{ - typedef QMultiMap<int, QString> PluginKeyMap; - typedef PluginKeyMap::const_iterator PluginKeyMapConstIterator; - - const PluginKeyMap keyMap = loader->keyMap(); - const PluginKeyMapConstIterator cend = keyMap.constEnd(); - int i = -1; - QImageIOPlugin *plugin = 0; - result->reserve(result->size() + keyMap.size()); - for (PluginKeyMapConstIterator it = keyMap.constBegin(); it != cend; ++it) { - if (it.key() != i) { - i = it.key(); - plugin = qobject_cast<QImageIOPlugin *>(loader->instance(i)); - } - const QByteArray key = it.value().toLatin1(); - if (plugin && (plugin->capabilities(0, key) & cap) != 0) - result->append(key); - } -} - -void supportedImageHandlerMimeTypes(QFactoryLoader *loader, - QImageIOPlugin::Capability cap, - QList<QByteArray> *result) -{ - QList<QJsonObject> metaDataList = loader->metaData(); - - const int pluginCount = metaDataList.size(); - for (int i = 0; i < pluginCount; ++i) { - const QJsonObject metaData = metaDataList.at(i).value(QLatin1String("MetaData")).toObject(); - const QJsonArray keys = metaData.value(QLatin1String("Keys")).toArray(); - const QJsonArray mimeTypes = metaData.value(QLatin1String("MimeTypes")).toArray(); - QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(loader->instance(i)); - const int keyCount = keys.size(); - for (int k = 0; k < keyCount; ++k) { - if (plugin && (plugin->capabilities(0, keys.at(k).toString().toLatin1()) & cap) != 0) - result->append(mimeTypes.at(k).toString().toLatin1()); - } - } -} -#endif // QT_NO_IMAGEFORMATPLUGIN - /*! Returns the list of image formats supported by QImageWriter. @@ -897,30 +847,7 @@ void supportedImageHandlerMimeTypes(QFactoryLoader *loader, */ QList<QByteArray> QImageWriter::supportedImageFormats() { - QList<QByteArray> formats; -#ifndef QT_NO_IMAGEFORMAT_BMP - formats << "bmp"; -#endif -#ifndef QT_NO_IMAGEFORMAT_PPM - formats << "pbm" << "pgm" << "ppm"; -#endif -#ifndef QT_NO_IMAGEFORMAT_XBM - formats << "xbm"; -#endif -#ifndef QT_NO_IMAGEFORMAT_XPM - formats << "xpm"; -#endif -#ifndef QT_NO_IMAGEFORMAT_PNG - formats << "png"; -#endif - -#ifndef QT_NO_IMAGEFORMATPLUGIN - supportedImageHandlerFormats(loader(), QImageIOPlugin::CanWrite, &formats); -#endif // QT_NO_IMAGEFORMATPLUGIN - - std::sort(formats.begin(), formats.end()); - formats.erase(std::unique(formats.begin(), formats.end()), formats.end()); - return formats; + return QImageReaderWriterHelpers::supportedImageFormats(QImageReaderWriterHelpers::CanWrite); } /*! @@ -933,32 +860,24 @@ QList<QByteArray> QImageWriter::supportedImageFormats() */ QList<QByteArray> QImageWriter::supportedMimeTypes() { - QList<QByteArray> mimeTypes; -#ifndef QT_NO_IMAGEFORMAT_BMP - mimeTypes << "image/bmp"; -#endif -#ifndef QT_NO_IMAGEFORMAT_PPM - mimeTypes << "image/x-portable-bitmap"; - mimeTypes << "image/x-portable-graymap"; - mimeTypes << "image/x-portable-pixmap"; -#endif -#ifndef QT_NO_IMAGEFORMAT_XBM - mimeTypes << "image/x-xbitmap"; -#endif -#ifndef QT_NO_IMAGEFORMAT_XPM - mimeTypes << "image/x-xpixmap"; -#endif -#ifndef QT_NO_IMAGEFORMAT_PNG - mimeTypes << "image/png"; -#endif + return QImageReaderWriterHelpers::supportedMimeTypes(QImageReaderWriterHelpers::CanWrite); +} -#ifndef QT_NO_IMAGEFORMATPLUGIN - supportedImageHandlerMimeTypes(loader(), QImageIOPlugin::CanWrite, &mimeTypes); -#endif // QT_NO_IMAGEFORMATPLUGIN +/*! + \since 5.12 - std::sort(mimeTypes.begin(), mimeTypes.end()); - mimeTypes.erase(std::unique(mimeTypes.begin(), mimeTypes.end()), mimeTypes.end()); - return mimeTypes; + Returns the list of image formats corresponding to \mimeType. + + Note that the QGuiApplication instance must be created before this function is + called. + + \sa supportedImageFormats(), supportedMimeTypes() +*/ + +QList<QByteArray> QImageWriter::imageFormatsForMimeType(const QByteArray &mimeType) +{ + return QImageReaderWriterHelpers::imageFormatsForMimeType(mimeType, + QImageReaderWriterHelpers::CanWrite); } QT_END_NAMESPACE diff --git a/src/gui/image/qimagewriter.h b/src/gui/image/qimagewriter.h index fd1fdd07e8..29c06ccdd2 100644 --- a/src/gui/image/qimagewriter.h +++ b/src/gui/image/qimagewriter.h @@ -116,6 +116,7 @@ public: static QList<QByteArray> supportedImageFormats(); static QList<QByteArray> supportedMimeTypes(); + static QList<QByteArray> imageFormatsForMimeType(const QByteArray &mimeType); private: Q_DISABLE_COPY(QImageWriter) diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 5b3e3985a7..4cd8befc1b 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -248,9 +248,9 @@ QPixmap::QPixmap(const char * const xpm[]) QImage image(xpm); if (!image.isNull()) { if (data && data->pixelType() == QPlatformPixmap::BitmapType) - *this = QBitmap::fromImage(image); + *this = QBitmap::fromImage(std::move(image)); else - *this = fromImage(image); + *this = fromImage(std::move(image)); } } #endif @@ -691,7 +691,7 @@ QBitmap QPixmap::createHeuristicMask(bool clipTight) const QBitmap QPixmap::createMaskFromColor(const QColor &maskColor, Qt::MaskMode mode) const { QImage image = toImage().convertToFormat(QImage::Format_ARGB32); - return QBitmap::fromImage(image.createMaskFromColor(maskColor.rgba(), mode)); + return QBitmap::fromImage(std::move(image).createMaskFromColor(maskColor.rgba(), mode)); } /*! @@ -1018,9 +1018,9 @@ QDataStream &operator>>(QDataStream &stream, QPixmap &pixmap) if (image.isNull()) { pixmap = QPixmap(); } else if (image.depth() == 1) { - pixmap = QBitmap::fromImage(image); + pixmap = QBitmap::fromImage(std::move(image)); } else { - pixmap = QPixmap::fromImage(image); + pixmap = QPixmap::fromImage(std::move(image)); } return stream; } diff --git a/src/gui/image/qxbmhandler.cpp b/src/gui/image/qxbmhandler.cpp index 155a4f88b4..24d86e116d 100644 --- a/src/gui/image/qxbmhandler.cpp +++ b/src/gui/image/qxbmhandler.cpp @@ -241,7 +241,7 @@ static bool write_xbm_image(const QImage &sourceImage, QIODevice *device, const } } } -#if defined(_MSC_VER) && _MSC_VER >= 1400 +#ifdef Q_CC_MSVC strcpy_s(p, sizeof(" };\n"), " };\n"); #else strcpy(p, " };\n"); diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp index 9c54b9ada4..17272ffe69 100644 --- a/src/gui/image/qxpmhandler.cpp +++ b/src/gui/image/qxpmhandler.cpp @@ -741,10 +741,6 @@ static const struct XPMRGBData { { QRGB(139,139, 0), "yellow4" }, { QRGB(154,205, 50), "yellowgreen" } }; -#if defined(Q_CC_MSVC) && _MSC_VER < 1600 -inline bool operator<(const XPMRGBData &data1, const XPMRGBData &data2) -{ return qstrcmp(data1.name, data2.name) < 0; } -#endif inline bool operator<(const char *name, const XPMRGBData &data) { return qstrcmp(name, data.name) < 0; } diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h index f58dcf17f0..64b703e524 100644 --- a/src/gui/kernel/qplatformdialoghelper.h +++ b/src/gui/kernel/qplatformdialoghelper.h @@ -150,6 +150,7 @@ public: MacModelessLayout, AndroidLayout }; + Q_ENUM(ButtonLayout) QPlatformDialogHelper(); virtual ~QPlatformDialogHelper(); diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp index a66420c364..a3046a9b44 100644 --- a/src/gui/kernel/qplatformwindow.cpp +++ b/src/gui/kernel/qplatformwindow.cpp @@ -340,6 +340,20 @@ void QPlatformWindow::setWindowFilePath(const QString &filePath) { Q_UNUSED(file void QPlatformWindow::setWindowIcon(const QIcon &icon) { Q_UNUSED(icon); } /*! + Reimplement to let the platform handle non-spontaneous window close. + + When reimplementing make sure to call the base class implementation + or QWindowSystemInterface::handleCloseEvent(), which will prompt the + user to accept the window close (if needed) and then close the QWindow. +*/ +bool QPlatformWindow::close() +{ + bool accepted = false; + QWindowSystemInterface::handleCloseEvent<QWindowSystemInterface::SynchronousDelivery>(window(), &accepted); + return accepted; +} + +/*! Reimplement to be able to let Qt raise windows to the top of the desktop */ void QPlatformWindow::raise() { qWarning("This plugin does not support raise()"); } diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h index 84dff681d5..bba6390694 100644 --- a/src/gui/kernel/qplatformwindow.h +++ b/src/gui/kernel/qplatformwindow.h @@ -100,6 +100,7 @@ public: virtual void setWindowTitle(const QString &title); virtual void setWindowFilePath(const QString &title); virtual void setWindowIcon(const QIcon &icon); + virtual bool close(); virtual void raise(); virtual void lower(); diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 2c7e061bcf..5db740acb9 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -2144,10 +2144,7 @@ bool QWindow::close() if (!d->platformWindow) return true; - bool accepted = false; - QWindowSystemInterface::handleCloseEvent(this, &accepted); - QWindowSystemInterface::flushWindowSystemEvents(); - return accepted; + return d->platformWindow->close(); } /*! diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 5243ae66a2..1b964ba913 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -335,12 +335,12 @@ QT_DEFINE_QPA_EVENT_HANDLER(void, handleExposeEvent, QWindow *window, const QReg QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e); } -void QWindowSystemInterface::handleCloseEvent(QWindow *window, bool *accepted) +QT_DEFINE_QPA_EVENT_HANDLER(void, handleCloseEvent, QWindow *window, bool *accepted) { if (window) { QWindowSystemInterfacePrivate::CloseEvent *e = new QWindowSystemInterfacePrivate::CloseEvent(window, accepted); - QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); + QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e); } } diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index b22495f9d0..d584374fca 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -193,6 +193,7 @@ public: template<typename Delivery = QWindowSystemInterface::DefaultDelivery> static void handleExposeEvent(QWindow *window, const QRegion ®ion); + template<typename Delivery = QWindowSystemInterface::DefaultDelivery> static void handleCloseEvent(QWindow *window, bool *accepted = nullptr); template<typename Delivery = QWindowSystemInterface::DefaultDelivery> diff --git a/src/gui/opengl/qopengl.h b/src/gui/opengl/qopengl.h index b4657fa118..3a2393ea58 100644 --- a/src/gui/opengl/qopengl.h +++ b/src/gui/opengl/qopengl.h @@ -239,7 +239,7 @@ typedef unsigned long long int uint64_t; typedef long int int32_t; typedef long long int int64_t; typedef unsigned long long int uint64_t; -#elif defined(_WIN32) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1600)) +#elif defined(_WIN32) && (defined(__GNUC__) || defined(_MSC_VER)) #include <stdint.h> #elif defined(_WIN32) typedef __int32 int32_t; diff --git a/src/gui/opengl/qopenglengineshadermanager.cpp b/src/gui/opengl/qopenglengineshadermanager.cpp index 2f7afa4a66..f66193cb01 100644 --- a/src/gui/opengl/qopenglengineshadermanager.cpp +++ b/src/gui/opengl/qopenglengineshadermanager.cpp @@ -153,12 +153,8 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context) code[AffinePositionWithRadialGradientBrushVertexShader] = qopenglslAffinePositionWithRadialGradientBrushVertexShader_core; code[AffinePositionWithTextureBrushVertexShader] = qopenglslAffinePositionWithTextureBrushVertexShader_core; - code[MainFragmentShader_CMO] = qopenglslMainFragmentShader_CMO_core; - code[MainFragmentShader_CM] = qopenglslMainFragmentShader_CM_core; code[MainFragmentShader_MO] = qopenglslMainFragmentShader_MO_core; code[MainFragmentShader_M] = qopenglslMainFragmentShader_M_core; - code[MainFragmentShader_CO] = qopenglslMainFragmentShader_CO_core; - code[MainFragmentShader_C] = qopenglslMainFragmentShader_C_core; code[MainFragmentShader_O] = qopenglslMainFragmentShader_O_core; code[MainFragmentShader] = qopenglslMainFragmentShader_core; code[MainFragmentShader_ImageArrays] = qopenglslMainFragmentShader_ImageArrays_core; @@ -203,12 +199,8 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context) code[AffinePositionWithRadialGradientBrushVertexShader] = qopenglslAffinePositionWithRadialGradientBrushVertexShader; code[AffinePositionWithTextureBrushVertexShader] = qopenglslAffinePositionWithTextureBrushVertexShader; - code[MainFragmentShader_CMO] = qopenglslMainFragmentShader_CMO; - code[MainFragmentShader_CM] = qopenglslMainFragmentShader_CM; code[MainFragmentShader_MO] = qopenglslMainFragmentShader_MO; code[MainFragmentShader_M] = qopenglslMainFragmentShader_M; - code[MainFragmentShader_CO] = qopenglslMainFragmentShader_CO; - code[MainFragmentShader_C] = qopenglslMainFragmentShader_C; code[MainFragmentShader_O] = qopenglslMainFragmentShader_O; code[MainFragmentShader] = qopenglslMainFragmentShader; code[MainFragmentShader_ImageArrays] = qopenglslMainFragmentShader_ImageArrays; @@ -238,21 +230,20 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context) code[RgbMaskWithGammaFragmentShader] = ""; //### } - // These shaders are not implemented yet and therefore are the same - // for all profiles. Implementations should make a version for both - // profiles and put the appropriate lines in the if-statement above. + // The composition shaders are just layout qualifiers and the same + // for all profiles that support them. code[NoCompositionModeFragmentShader] = ""; - code[MultiplyCompositionModeFragmentShader] = ""; //### - code[ScreenCompositionModeFragmentShader] = ""; //### - code[OverlayCompositionModeFragmentShader] = ""; //### - code[DarkenCompositionModeFragmentShader] = ""; //### - code[LightenCompositionModeFragmentShader] = ""; //### - code[ColorDodgeCompositionModeFragmentShader] = ""; //### - code[ColorBurnCompositionModeFragmentShader] = ""; //### - code[HardLightCompositionModeFragmentShader] = ""; //### - code[SoftLightCompositionModeFragmentShader] = ""; //### - code[DifferenceCompositionModeFragmentShader] = ""; //### - code[ExclusionCompositionModeFragmentShader] = ""; //### + code[MultiplyCompositionModeFragmentShader] = qopenglslMultiplyCompositionModeFragmentShader; + code[ScreenCompositionModeFragmentShader] = qopenglslScreenCompositionModeFragmentShader; + code[OverlayCompositionModeFragmentShader] = qopenglslOverlayCompositionModeFragmentShader; + code[DarkenCompositionModeFragmentShader] = qopenglslDarkenCompositionModeFragmentShader; + code[LightenCompositionModeFragmentShader] = qopenglslLightenCompositionModeFragmentShader; + code[ColorDodgeCompositionModeFragmentShader] = qopenglslColorDodgeCompositionModeFragmentShader; + code[ColorBurnCompositionModeFragmentShader] = qopenglslColorBurnCompositionModeFragmentShader; + code[HardLightCompositionModeFragmentShader] = qopenglslHardLightCompositionModeFragmentShader; + code[SoftLightCompositionModeFragmentShader] = qopenglslSoftLightCompositionModeFragmentShader; + code[DifferenceCompositionModeFragmentShader] = qopenglslDifferenceCompositionModeFragmentShader; + code[ExclusionCompositionModeFragmentShader] = qopenglslExclusionCompositionModeFragmentShader; #if defined(QT_DEBUG) // Check that all the elements have been filled: @@ -612,8 +603,11 @@ void QOpenGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mo if (compositionMode == mode) return; + bool wasAdvanced = compositionMode > QPainter::CompositionMode_Plus; + bool isAdvanced = mode > QPainter::CompositionMode_Plus; + compositionMode = mode; - shaderProgNeedsChanging = true; //### + shaderProgNeedsChanging = shaderProgNeedsChanging || wasAdvanced || isAdvanced; } void QOpenGLEngineShaderManager::setCustomStage(QOpenGLCustomShaderStage* stage) @@ -783,21 +777,13 @@ bool QOpenGLEngineShaderManager::useCorrectShaderProg() requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_ImageArrays; } else { bool useGlobalOpacity = (opacityMode == UniformOpacity); - if (hasCompose && hasMask && useGlobalOpacity) - requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_CMO; - if (hasCompose && hasMask && !useGlobalOpacity) - requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_CM; - if (!hasCompose && hasMask && useGlobalOpacity) + if (hasMask && useGlobalOpacity) requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_MO; - if (!hasCompose && hasMask && !useGlobalOpacity) + if (hasMask && !useGlobalOpacity) requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_M; - if (hasCompose && !hasMask && useGlobalOpacity) - requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_CO; - if (hasCompose && !hasMask && !useGlobalOpacity) - requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_C; - if (!hasCompose && !hasMask && useGlobalOpacity) + if (!hasMask && useGlobalOpacity) requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_O; - if (!hasCompose && !hasMask && !useGlobalOpacity) + if (!hasMask && !useGlobalOpacity) requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader; } diff --git a/src/gui/opengl/qopenglengineshadermanager_p.h b/src/gui/opengl/qopenglengineshadermanager_p.h index 377501457d..d43788d777 100644 --- a/src/gui/opengl/qopenglengineshadermanager_p.h +++ b/src/gui/opengl/qopenglengineshadermanager_p.h @@ -281,12 +281,8 @@ public: AffinePositionWithTextureBrushVertexShader, // MainFragmentShader_CMO must be first in the list: - MainFragmentShader_CMO, - MainFragmentShader_CM, MainFragmentShader_MO, MainFragmentShader_M, - MainFragmentShader_CO, - MainFragmentShader_C, MainFragmentShader_O, MainFragmentShader, MainFragmentShader_ImageArrays, diff --git a/src/gui/opengl/qopenglengineshadersource_p.h b/src/gui/opengl/qopenglengineshadersource_p.h index a165643839..5d9ee8110b 100644 --- a/src/gui/opengl/qopenglengineshadersource_p.h +++ b/src/gui/opengl/qopenglengineshadersource_p.h @@ -403,25 +403,6 @@ static const char* const qopenglslMainFragmentShader_ImageArrays = "\n\ gl_FragColor = srcPixel() * opacity; \n\ }\n"; -static const char* const qopenglslMainFragmentShader_CMO = "\n\ - uniform lowp float globalOpacity; \n\ - lowp vec4 srcPixel(); \n\ - lowp vec4 applyMask(lowp vec4); \n\ - lowp vec4 compose(lowp vec4); \n\ - void main() \n\ - { \n\ - gl_FragColor = applyMask(compose(srcPixel()*globalOpacity))); \n\ - }\n"; - -static const char* const qopenglslMainFragmentShader_CM = "\n\ - lowp vec4 srcPixel(); \n\ - lowp vec4 applyMask(lowp vec4); \n\ - lowp vec4 compose(lowp vec4); \n\ - void main() \n\ - { \n\ - gl_FragColor = applyMask(compose(srcPixel())); \n\ - }\n"; - static const char* const qopenglslMainFragmentShader_MO = "\n\ uniform lowp float globalOpacity; \n\ lowp vec4 srcPixel(); \n\ @@ -439,23 +420,6 @@ static const char* const qopenglslMainFragmentShader_M = "\n\ gl_FragColor = applyMask(srcPixel()); \n\ }\n"; -static const char* const qopenglslMainFragmentShader_CO = "\n\ - uniform lowp float globalOpacity; \n\ - lowp vec4 srcPixel(); \n\ - lowp vec4 compose(lowp vec4); \n\ - void main() \n\ - { \n\ - gl_FragColor = compose(srcPixel()*globalOpacity); \n\ - }\n"; - -static const char* const qopenglslMainFragmentShader_C = "\n\ - lowp vec4 srcPixel(); \n\ - lowp vec4 compose(lowp vec4); \n\ - void main() \n\ - { \n\ - gl_FragColor = compose(srcPixel()); \n\ - }\n"; - static const char* const qopenglslMainFragmentShader_O = "\n\ uniform lowp float globalOpacity; \n\ lowp vec4 srcPixel(); \n\ @@ -513,22 +477,65 @@ static const char* const qopenglslRgbMaskFragmentShaderPass2 = "\n\ return src * mask; \n\ }\n"; +static const char* const qopenglslMultiplyCompositionModeFragmentShader = "\n\ + #ifdef GL_KHR_blend_equation_advanced\n\ + layout(blend_support_multiply) out;\n\ + #endif\n"; + +static const char* const qopenglslScreenCompositionModeFragmentShader = "\n\ + #ifdef GL_KHR_blend_equation_advanced\n\ + layout(blend_support_screen) out;\n\ + #endif\n"; + +static const char* const qopenglslOverlayCompositionModeFragmentShader = "\n\ + #ifdef GL_KHR_blend_equation_advanced\n\ + layout(blend_support_overlay) out;\n\ + #endif\n"; + +static const char* const qopenglslDarkenCompositionModeFragmentShader = "\n\ + #ifdef GL_KHR_blend_equation_advanced\n\ + layout(blend_support_darken) out;\n\ + #endif\n"; + +static const char* const qopenglslLightenCompositionModeFragmentShader = "\n\ + #ifdef GL_KHR_blend_equation_advanced\n\ + layout(blend_support_lighten) out;\n\ + #endif\n"; + +static const char* const qopenglslColorDodgeCompositionModeFragmentShader = "\n\ + #ifdef GL_KHR_blend_equation_advanced\n\ + layout(blend_support_colordodge) out;\n\ + #endif\n"; + +static const char* const qopenglslColorBurnCompositionModeFragmentShader = "\n\ + #ifdef GL_KHR_blend_equation_advanced\n\ + layout(blend_support_colorburn) out;\n\ + #endif\n"; + +static const char* const qopenglslHardLightCompositionModeFragmentShader = "\n\ + #ifdef GL_KHR_blend_equation_advanced\n\ + layout(blend_support_hardlight) out;\n\ + #endif\n"; + +static const char* const qopenglslSoftLightCompositionModeFragmentShader = "\n\ + #ifdef GL_KHR_blend_equation_advanced\n\ + layout(blend_support_softlight) out;\n\ + #endif\n"; + +static const char* const qopenglslDifferenceCompositionModeFragmentShader = "\n\ + #ifdef GL_KHR_blend_equation_advanced\n\ + layout(blend_support_difference) out;\n\ + #endif\n"; + +static const char* const qopenglslExclusionCompositionModeFragmentShader = "\n\ + #ifdef GL_KHR_blend_equation_advanced\n\ + layout(blend_support_exclusion) out;\n\ + #endif\n"; + /* Left to implement: RgbMaskFragmentShader, RgbMaskWithGammaFragmentShader, - - MultiplyCompositionModeFragmentShader, - ScreenCompositionModeFragmentShader, - OverlayCompositionModeFragmentShader, - DarkenCompositionModeFragmentShader, - LightenCompositionModeFragmentShader, - ColorDodgeCompositionModeFragmentShader, - ColorBurnCompositionModeFragmentShader, - HardLightCompositionModeFragmentShader, - SoftLightCompositionModeFragmentShader, - DifferenceCompositionModeFragmentShader, - ExclusionCompositionModeFragmentShader, */ /* @@ -880,29 +887,6 @@ static const char* const qopenglslMainFragmentShader_ImageArrays_core = fragColor = srcPixel() * opacity; \n\ }\n"; -static const char* const qopenglslMainFragmentShader_CMO_core = - "#version 150 core\n\ - out vec4 fragColor; \n\ - uniform float globalOpacity; \n\ - vec4 srcPixel(); \n\ - vec4 applyMask(vec4); \n\ - vec4 compose(vec4); \n\ - void main() \n\ - { \n\ - fragColor = applyMask(compose(srcPixel()*globalOpacity))); \n\ - }\n"; - -static const char* const qopenglslMainFragmentShader_CM_core = - "#version 150 core\n\ - out vec4 fragColor; \n\ - vec4 srcPixel(); \n\ - vec4 applyMask(vec4); \n\ - vec4 compose(vec4); \n\ - void main() \n\ - { \n\ - fragColor = applyMask(compose(srcPixel())); \n\ - }\n"; - static const char* const qopenglslMainFragmentShader_MO_core = "#version 150 core\n\ out vec4 fragColor; \n\ @@ -924,27 +908,6 @@ static const char* const qopenglslMainFragmentShader_M_core = fragColor = applyMask(srcPixel()); \n\ }\n"; -static const char* const qopenglslMainFragmentShader_CO_core = - "#version 150 core\n\ - out vec4 fragColor; \n\ - uniform float globalOpacity; \n\ - vec4 srcPixel(); \n\ - vec4 compose(vec4); \n\ - void main() \n\ - { \n\ - fragColor = compose(srcPixel()*globalOpacity); \n\ - }\n"; - -static const char* const qopenglslMainFragmentShader_C_core = - "#version 150 core\n\ - out vec4 fragColor; \n\ - vec4 srcPixel(); \n\ - vec4 compose(vec4); \n\ - void main() \n\ - { \n\ - fragColor = compose(srcPixel()); \n\ - }\n"; - static const char* const qopenglslMainFragmentShader_O_core = "#version 150 core\n\ out vec4 fragColor; \n\ @@ -1010,18 +973,6 @@ static const char* const qopenglslRgbMaskFragmentShaderPass2_core = "\n\ Left to implement: RgbMaskFragmentShader_core, RgbMaskWithGammaFragmentShader_core, - - MultiplyCompositionModeFragmentShader_core, - ScreenCompositionModeFragmentShader_core, - OverlayCompositionModeFragmentShader_core, - DarkenCompositionModeFragmentShader_core, - LightenCompositionModeFragmentShader_core, - ColorDodgeCompositionModeFragmentShader_core, - ColorBurnCompositionModeFragmentShader_core, - HardLightCompositionModeFragmentShader_core, - SoftLightCompositionModeFragmentShader_core, - DifferenceCompositionModeFragmentShader_core, - ExclusionCompositionModeFragmentShader_core, */ QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp index ff044a91da..236c81ac93 100644 --- a/src/gui/opengl/qopenglfunctions.cpp +++ b/src/gui/opengl/qopenglfunctions.cpp @@ -294,9 +294,19 @@ QOpenGLExtensions::QOpenGLExtensions(QOpenGLContext *context) static int qt_gl_resolve_features() { QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QOpenGLExtensionMatcher extensions; + int features = 0; + if ((extensions.match("GL_KHR_blend_equation_advanced") + || extensions.match("GL_NV_blend_equation_advanced")) && + (extensions.match("GL_KHR_blend_equation_advanced_coherent") + || extensions.match("GL_NV_blend_equation_advanced_coherent"))) { + // We need both the advanced equations and the coherency for us + // to be able to easily use the new blend equations + features |= QOpenGLFunctions::BlendEquationAdvanced; + } if (ctx->isOpenGLES()) { // OpenGL ES - int features = QOpenGLFunctions::Multitexture | + features |= QOpenGLFunctions::Multitexture | QOpenGLFunctions::Shaders | QOpenGLFunctions::Buffers | QOpenGLFunctions::Framebuffers | @@ -308,7 +318,6 @@ static int qt_gl_resolve_features() QOpenGLFunctions::CompressedTextures | QOpenGLFunctions::Multisample | QOpenGLFunctions::StencilSeparate; - QOpenGLExtensionMatcher extensions; if (extensions.match("GL_IMG_texture_npot")) features |= QOpenGLFunctions::NPOTTextures; if (extensions.match("GL_OES_texture_npot")) @@ -320,14 +329,18 @@ static int qt_gl_resolve_features() if (!(renderer && strstr(renderer, "Mesa"))) features |= QOpenGLFunctions::TextureRGFormats; } - if (ctx->format().majorVersion() >= 3) + if (ctx->format().majorVersion() >= 3) { features |= QOpenGLFunctions::MultipleRenderTargets; + if (ctx->format().minorVersion() >= 2 && extensions.match("GL_KHR_blend_equation_advanced_coherent")) { + // GL_KHR_blend_equation_advanced is included in OpenGL ES/3.2 + features |= QOpenGLFunctions::BlendEquationAdvanced; + } + } return features; } else { // OpenGL - int features = QOpenGLFunctions::TextureRGFormats; + features |= QOpenGLFunctions::TextureRGFormats; QSurfaceFormat format = QOpenGLContext::currentContext()->format(); - QOpenGLExtensionMatcher extensions; if (format.majorVersion() >= 3) features |= QOpenGLFunctions::Framebuffers | QOpenGLFunctions::MultipleRenderTargets; diff --git a/src/gui/opengl/qopenglfunctions.h b/src/gui/opengl/qopenglfunctions.h index 1a43f13d9b..00287b0665 100644 --- a/src/gui/opengl/qopenglfunctions.h +++ b/src/gui/opengl/qopenglfunctions.h @@ -277,7 +277,8 @@ public: NPOTTextureRepeat = 0x2000, FixedFunctionPipeline = 0x4000, TextureRGFormats = 0x8000, - MultipleRenderTargets = 0x10000 + MultipleRenderTargets = 0x10000, + BlendEquationAdvanced = 0x20000, }; Q_DECLARE_FLAGS(OpenGLFeatures, OpenGLFeature) diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index 17dc9df619..fb7e6fce97 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -87,8 +87,27 @@ #include <QDebug> -QT_BEGIN_NAMESPACE +#ifndef GL_KHR_blend_equation_advanced +#define GL_KHR_blend_equation_advanced 1 +#define GL_MULTIPLY_KHR 0x9294 +#define GL_SCREEN_KHR 0x9295 +#define GL_OVERLAY_KHR 0x9296 +#define GL_DARKEN_KHR 0x9297 +#define GL_LIGHTEN_KHR 0x9298 +#define GL_COLORDODGE_KHR 0x9299 +#define GL_COLORBURN_KHR 0x929A +#define GL_HARDLIGHT_KHR 0x929B +#define GL_SOFTLIGHT_KHR 0x929C +#define GL_DIFFERENCE_KHR 0x929E +#define GL_EXCLUSION_KHR 0x92A0 +#endif /* GL_KHR_blend_equation_advanced */ + +#ifndef GL_KHR_blend_equation_advanced_coherent +#define GL_KHR_blend_equation_advanced_coherent 1 +#define GL_BLEND_ADVANCED_COHERENT_KHR 0x9285 +#endif /* GL_KHR_blend_equation_advanced_coherent */ +QT_BEGIN_NAMESPACE Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert); @@ -498,6 +517,21 @@ void QOpenGL2PaintEngineExPrivate::updateCompositionMode() // NOTE: The entire paint engine works on pre-multiplied data - which is why some of these // composition modes look odd. // qDebug() << "QOpenGL2PaintEngineExPrivate::updateCompositionMode() - Setting GL composition mode for " << q->state()->composition_mode; + if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::BlendEquationAdvanced)) { + if (q->state()->composition_mode <= QPainter::CompositionMode_Plus) { + funcs.glDisable(GL_BLEND_ADVANCED_COHERENT_KHR); + funcs.glBlendEquation(GL_FUNC_ADD); + } else { + funcs.glEnable(GL_BLEND_ADVANCED_COHERENT_KHR); + } + shaderManager->setCompositionMode(q->state()->composition_mode); + } else { + if (q->state()->composition_mode > QPainter::CompositionMode_Plus) { + qWarning("Unsupported composition mode"); + compositionModeDirty = false; + return; + } + } switch(q->state()->composition_mode) { case QPainter::CompositionMode_SourceOver: funcs.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); @@ -538,6 +572,39 @@ void QOpenGL2PaintEngineExPrivate::updateCompositionMode() case QPainter::CompositionMode_Plus: funcs.glBlendFunc(GL_ONE, GL_ONE); break; + case QPainter::CompositionMode_Multiply: + funcs.glBlendEquation(GL_MULTIPLY_KHR); + break; + case QPainter::CompositionMode_Screen: + funcs.glBlendEquation(GL_SCREEN_KHR); + break; + case QPainter::CompositionMode_Overlay: + funcs.glBlendEquation(GL_OVERLAY_KHR); + break; + case QPainter::CompositionMode_Darken: + funcs.glBlendEquation(GL_DARKEN_KHR); + break; + case QPainter::CompositionMode_Lighten: + funcs.glBlendEquation(GL_LIGHTEN_KHR); + break; + case QPainter::CompositionMode_ColorDodge: + funcs.glBlendEquation(GL_COLORDODGE_KHR); + break; + case QPainter::CompositionMode_ColorBurn: + funcs.glBlendEquation(GL_COLORBURN_KHR); + break; + case QPainter::CompositionMode_HardLight: + funcs.glBlendEquation(GL_HARDLIGHT_KHR); + break; + case QPainter::CompositionMode_SoftLight: + funcs.glBlendEquation(GL_SOFTLIGHT_KHR); + break; + case QPainter::CompositionMode_Difference: + funcs.glBlendEquation(GL_DIFFERENCE_KHR); + break; + case QPainter::CompositionMode_Exclusion: + funcs.glBlendEquation(GL_EXCLUSION_KHR); + break; default: qWarning("Unsupported composition mode"); break; diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp index 1fe30f7e0e..46963f0dbf 100644 --- a/src/gui/opengl/qopenglshaderprogram.cpp +++ b/src/gui/opengl/qopenglshaderprogram.cpp @@ -497,6 +497,13 @@ static const char redefineHighp[] = "#endif\n"; #endif +// Boiler-plate header to have the layout attributes available we need later +static const char blendEquationAdvancedHeader[] = + "#ifdef GL_KHR_blend_equation_advanced\n" + "#extension GL_ARB_fragment_coord_conventions : enable\n" + "#extension GL_KHR_blend_equation_advanced : enable\n" + "#endif\n"; + struct QVersionDirectivePosition { Q_DECL_CONSTEXPR QVersionDirectivePosition(int position = 0, int line = -1) @@ -637,6 +644,10 @@ bool QOpenGLShader::compileSourceCode(const char *source) } } } + if (d->shaderType == Fragment) { + sourceChunks.append(blendEquationAdvancedHeader); + sourceChunkLengths.append(GLint(sizeof(blendEquationAdvancedHeader) - 1)); + } // The precision qualifiers are useful on OpenGL/ES systems, // but usually not present on desktop systems. diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index c55bcb12c9..1d7375d1df 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -304,11 +304,6 @@ static const int rgbTblSize = sizeof(rgbTbl) / sizeof(RGBData); #undef rgb -#if defined(Q_CC_MSVC) && _MSC_VER < 1600 -inline bool operator<(const RGBData &data1, const RGBData &data2) -{ return qstrcmp(data1.name, data2.name) < 0; } -#endif - inline bool operator<(const char *name, const RGBData &data) { return qstrcmp(name, data.name) < 0; } inline bool operator<(const RGBData &data, const char *name) diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index f08038e34b..efd9b0c146 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -73,9 +73,6 @@ enum { half_point = 1 << 15 }; -// must be multiple of 4 for easier SIMD implementations -static const int buffer_size = 2048; - template<QImage::Format> Q_DECL_CONSTEXPR uint redWidth(); template<QImage::Format> Q_DECL_CONSTEXPR uint redShift(); template<QImage::Format> Q_DECL_CONSTEXPR uint greenWidth(); @@ -1131,7 +1128,7 @@ static uint *QT_FASTCALL destFetch(uint *buffer, QRasterBuffer *rasterBuffer, in static QRgba64 *QT_FASTCALL destFetch64(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length) { const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format]; - uint buffer32[buffer_size]; + uint buffer32[BufferSize]; const uint *ptr = qFetchPixels[layout->bpp](buffer32, rasterBuffer->scanLine(y), x, length); return const_cast<QRgba64 *>(layout->convertToARGB64PM(buffer, ptr, length, 0, 0)); } @@ -1304,12 +1301,12 @@ static void QT_FASTCALL destStoreRGB16(QRasterBuffer *rasterBuffer, int x, int y static void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length) { - uint buf[buffer_size]; + uint buf[BufferSize]; const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format]; StorePixelsFunc store = qStorePixels[layout->bpp]; uchar *dest = rasterBuffer->scanLine(y); while (length) { - int l = qMin(length, buffer_size); + int l = qMin(length, BufferSize); const uint *ptr = 0; if (!layout->premultiplied && !layout->alphaWidth) ptr = layout->convertFromRGB32(buf, buffer, l, 0, 0); @@ -1331,12 +1328,12 @@ static void QT_FASTCALL convertFromRgb64(uint *dest, const QRgba64 *src, int len static void QT_FASTCALL destStore64(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) { - uint buf[buffer_size]; + uint buf[BufferSize]; const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format]; StorePixelsFunc store = qStorePixels[layout->bpp]; uchar *dest = rasterBuffer->scanLine(y); while (length) { - int l = qMin(length, buffer_size); + int l = qMin(length, BufferSize); const uint *ptr = 0; convertFromRgb64(buf, buffer, l); if (!layout->premultiplied && !layout->alphaWidth) @@ -1554,7 +1551,7 @@ static const QRgba64 *QT_FASTCALL fetchUntransformed64(QRgba64 *buffer, const Op { const QPixelLayout *layout = &qPixelLayouts[data->texture.format]; if (layout->bpp != QPixelLayout::BPP32) { - uint buffer32[buffer_size]; + uint buffer32[BufferSize]; const uint *ptr = qFetchPixels[layout->bpp](buffer32, data->texture.scanLine(y), x, length); return layout->convertToARGB64PM(buffer, ptr, length, data->texture.colorTable, 0); } else { @@ -1673,7 +1670,7 @@ static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Oper FetchPixelFunc fetch = qFetchPixel[layout->bpp]; const QVector<QRgb> *clut = data->texture.colorTable; - uint buffer32[buffer_size]; + uint buffer32[BufferSize]; QRgba64 *b = buffer; if (data->fast_matrix) { // The increment pr x in the scanline @@ -1687,9 +1684,9 @@ static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Oper int i = 0, j = 0; while (i < length) { - if (j == buffer_size) { - layout->convertToARGB64PM(b, buffer32, buffer_size, clut, 0); - b += buffer_size; + if (j == BufferSize) { + layout->convertToARGB64PM(b, buffer32, BufferSize, clut, 0); + b += BufferSize; j = 0; } int px = fx >> 16; @@ -1725,9 +1722,9 @@ static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Oper int i = 0, j = 0; while (i < length) { - if (j == buffer_size) { - layout->convertToARGB64PM(b, buffer32, buffer_size, clut, 0); - b += buffer_size; + if (j == BufferSize) { + layout->convertToARGB64PM(b, buffer32, BufferSize, clut, 0); + b += BufferSize; j = 0; } const qreal iw = fw == 0 ? 1 : 1 / fw; @@ -1921,7 +1918,7 @@ inline void fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(int, } enum FastTransformTypes { - SimpleUpscaleTransform, + SimpleScaleTransform, UpscaleTransform, DownscaleTransform, RotateTransform, @@ -1929,11 +1926,38 @@ enum FastTransformTypes { NFastTransformTypes }; +// Completes the partial interpolation stored in IntermediateBuffer. +// by performing the x-axis interpolation and joining the RB and AG buffers. +static void QT_FASTCALL intermediate_adder(uint *b, uint *end, const IntermediateBuffer &intermediate, int offset, int &fx, int fdx) +{ +#if defined(QT_COMPILER_SUPPORTS_AVX2) + extern void QT_FASTCALL intermediate_adder_avx2(uint *b, uint *end, const IntermediateBuffer &intermediate, int offset, int &fx, int fdx); + if (qCpuHasFeature(AVX2)) + return intermediate_adder_avx2(b, end, intermediate, offset, fx, fdx); +#endif + + // Switch to intermediate buffer coordinates + fx -= offset * fixed_scale; + + while (b < end) { + const int x = (fx >> 16); + + const uint distx = (fx & 0x0000ffff) >> 8; + const uint idistx = 256 - distx; + const uint rb = (intermediate.buffer_rb[x] * idistx + intermediate.buffer_rb[x + 1] * distx) & 0xff00ff00; + const uint ag = (intermediate.buffer_ag[x] * idistx + intermediate.buffer_ag[x + 1] * distx) & 0xff00ff00; + *b = (rb >> 8) | ag; + b++; + fx += fdx; + } + fx += offset * fixed_scale; +} + typedef void (QT_FASTCALL *BilinearFastTransformHelper)(uint *b, uint *end, const QTextureData &image, int &fx, int &fy, int fdx, int fdy); template<TextureBlendType blendType> -static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(uint *b, uint *end, const QTextureData &image, - int &fx, int &fy, int fdx, int /*fdy*/) +static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_scale_helper(uint *b, uint *end, const QTextureData &image, + int &fx, int &fy, int fdx, int /*fdy*/) { int y1 = (fy >> 16); int y2; @@ -1950,16 +1974,12 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u const int offset = (fx + adjust) >> 16; int x = offset; - // The idea is first to do the interpolation between the row s1 and the row s2 - // into an intermediate buffer, then we interpolate between two pixel of this buffer. - - // intermediate_buffer[0] is a buffer of red-blue component of the pixel, in the form 0x00RR00BB - // intermediate_buffer[1] is the alpha-green component of the pixel, in the form 0x00AA00GG - // +1 for the last pixel to interpolate with, and +1 for rounding errors. - quint32 intermediate_buffer[2][buffer_size + 2]; - // count is the size used in the intermediate_buffer. + IntermediateBuffer intermediate; + // count is the size used in the intermediate.buffer. int count = (qint64(length) * qAbs(fdx) + fixed_scale - 1) / fixed_scale + 2; - Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case + // length is supposed to be <= BufferSize either because data->m11 < 1 or + // data->m11 < 2, and any larger buffers split + Q_ASSERT(count <= BufferSize + 2); int f = 0; int lim = count; if (blendType == BlendTransformedBilinearTiled) { @@ -1974,8 +1994,8 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u quint32 rb = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff; quint32 ag = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff; do { - intermediate_buffer[0][f] = rb; - intermediate_buffer[1][f] = ag; + intermediate.buffer_rb[f] = rb; + intermediate.buffer_ag[f] = ag; f++; x++; } while (x < image.x1 && f < lim); @@ -2008,10 +2028,10 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u // Add the values, and shift to only keep 8 significant bits per colors __m128i rAG =_mm_add_epi16(topAG, bottomAG); rAG = _mm_srli_epi16(rAG, 8); - _mm_storeu_si128((__m128i*)(&intermediate_buffer[1][f]), rAG); + _mm_storeu_si128((__m128i*)(&intermediate.buffer_ag[f]), rAG); __m128i rRB =_mm_add_epi16(topRB, bottomRB); rRB = _mm_srli_epi16(rRB, 8); - _mm_storeu_si128((__m128i*)(&intermediate_buffer[0][f]), rRB); + _mm_storeu_si128((__m128i*)(&intermediate.buffer_rb[f]), rRB); } #elif defined(__ARM_NEON__) const int16x8_t disty_ = vdupq_n_s16(disty); @@ -2038,10 +2058,10 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u // Add the values, and shift to only keep 8 significant bits per colors int16x8_t rAG = vaddq_s16(topAG, bottomAG); rAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rAG), 8)); - vst1q_s16((int16_t*)(&intermediate_buffer[1][f]), rAG); + vst1q_s16((int16_t*)(&intermediate.buffer_ag[f]), rAG); int16x8_t rRB = vaddq_s16(topRB, bottomRB); rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8)); - vst1q_s16((int16_t*)(&intermediate_buffer[0][f]), rRB); + vst1q_s16((int16_t*)(&intermediate.buffer_rb[f]), rRB); } #endif } @@ -2055,28 +2075,13 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u uint t = s1[x]; uint b = s2[x]; - intermediate_buffer[0][f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff; - intermediate_buffer[1][f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff; + intermediate.buffer_rb[f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff; + intermediate.buffer_ag[f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff; x++; } - // Now interpolate the values from the intermediate_buffer to get the final result. - fx -= offset * fixed_scale; // Switch to intermediate buffer coordinates - - while (b < end) { - int x1 = (fx >> 16); - int x2 = x1 + 1; - Q_ASSERT(x1 >= 0); - Q_ASSERT(x2 < count); - - int distx = (fx & 0x0000ffff) >> 8; - int idistx = 256 - distx; - int rb = ((intermediate_buffer[0][x1] * idistx + intermediate_buffer[0][x2] * distx) >> 8) & 0xff00ff; - int ag = (intermediate_buffer[1][x1] * idistx + intermediate_buffer[1][x2] * distx) & 0xff00ff00; - *b = rb | ag; - b++; - fx += fdx; - } + // Now interpolate the values from the intermediate.buffer to get the final result. + intermediate_adder(b, end, intermediate, offset, fx, fdx); } template<TextureBlendType blendType> @@ -2552,14 +2557,14 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_fast_rotate_helper(uint static BilinearFastTransformHelper bilinearFastTransformHelperARGB32PM[2][NFastTransformTypes] = { { - fetchTransformedBilinearARGB32PM_simple_upscale_helper<BlendTransformedBilinear>, + fetchTransformedBilinearARGB32PM_simple_scale_helper<BlendTransformedBilinear>, fetchTransformedBilinearARGB32PM_upscale_helper<BlendTransformedBilinear>, fetchTransformedBilinearARGB32PM_downscale_helper<BlendTransformedBilinear>, fetchTransformedBilinearARGB32PM_rotate_helper<BlendTransformedBilinear>, fetchTransformedBilinearARGB32PM_fast_rotate_helper<BlendTransformedBilinear> }, { - fetchTransformedBilinearARGB32PM_simple_upscale_helper<BlendTransformedBilinearTiled>, + fetchTransformedBilinearARGB32PM_simple_scale_helper<BlendTransformedBilinearTiled>, fetchTransformedBilinearARGB32PM_upscale_helper<BlendTransformedBilinearTiled>, fetchTransformedBilinearARGB32PM_downscale_helper<BlendTransformedBilinearTiled>, fetchTransformedBilinearARGB32PM_rotate_helper<BlendTransformedBilinearTiled>, @@ -2594,7 +2599,13 @@ static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, c if (fdy == 0) { // simple scale, no rotation or shear if (qAbs(fdx) <= fixed_scale) { // simple scale up on X - bilinearFastTransformHelperARGB32PM[tiled][SimpleUpscaleTransform](b, end, data->texture, fx, fy, fdx, fdy); + bilinearFastTransformHelperARGB32PM[tiled][SimpleScaleTransform](b, end, data->texture, fx, fy, fdx, fdy); + } else if (qAbs(fdx) <= 2 * fixed_scale) { + // simple scale down on X, less than 2x + const int mid = (length * 2 < BufferSize) ? length : ((length + 1) / 2); + bilinearFastTransformHelperARGB32PM[tiled][SimpleScaleTransform](buffer, buffer + mid, data->texture, fx, fy, fdx, fdy); + if (mid != length) + bilinearFastTransformHelperARGB32PM[tiled][SimpleScaleTransform](buffer + mid, buffer + length, data->texture, fx, fy, fdx, fdy); } else if (qAbs(data->m22) < qreal(1./8.)) { // scale up more than 8x (on Y) bilinearFastTransformHelperARGB32PM[tiled][UpscaleTransform](b, end, data->texture, fx, fy, fdx, fdy); @@ -2663,8 +2674,8 @@ static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, c } template<TextureBlendType blendType, QPixelLayout::BPP bpp> -static void QT_FASTCALL fetchTransformedBilinear_simple_upscale_helper(uint *b, uint *end, const QTextureData &image, - int &fx, int &fy, int fdx, int /*fdy*/) +static void QT_FASTCALL fetchTransformedBilinear_simple_scale_helper(uint *b, uint *end, const QTextureData &image, + int &fx, int &fy, int fdx, int /*fdy*/) { const QPixelLayout *layout = &qPixelLayouts[image.format]; const QVector<QRgb> *clut = image.colorTable; @@ -2688,16 +2699,14 @@ static void QT_FASTCALL fetchTransformedBilinear_simple_upscale_helper(uint *b, const int offset = (fx + adjust) >> 16; int x = offset; - // The idea is first to do the interpolation between the row s1 and the row s2 - // into an intermediate buffer, then we interpolate between two pixel of this buffer. - // +1 for the last pixel to interpolate with, and +1 for rounding errors. - uint buf1[buffer_size + 2]; - uint buf2[buffer_size + 2]; + IntermediateBuffer intermediate; + uint *buf1 = intermediate.buffer_rb; + uint *buf2 = intermediate.buffer_ag; const uint *ptr1; const uint *ptr2; int count = (qint64(length) * qAbs(fdx) + fixed_scale - 1) / fixed_scale + 2; - Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case + Q_ASSERT(count <= BufferSize + 2); if (blendType == BlendTransformedBilinearTiled) { x %= image.width; @@ -2729,6 +2738,7 @@ static void QT_FASTCALL fetchTransformedBilinear_simple_upscale_helper(uint *b, buf2[i + len1] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff; } } + // Generate the rest by repeatedly repeating the previous set of pixels for (int i = image.width; i < count; ++i) { buf1[i] = buf1[i - image.width]; buf2[i] = buf2[i - image.width]; @@ -2761,22 +2771,8 @@ static void QT_FASTCALL fetchTransformedBilinear_simple_upscale_helper(uint *b, } } - // Now interpolate the values from the intermediate_buffer to get the final result. - fx -= offset * fixed_scale; // Switch to intermediate buffer coordinates - - while (b < end) { - int x1 = (fx >> 16); - int x2 = x1 + 1; - Q_ASSERT(x1 >= 0); - Q_ASSERT(x2 < count); - - int distx = (fx & 0x0000ffff) >> 8; - int idistx = 256 - distx; - int rb = ((buf1[x1] * idistx + buf1[x2] * distx) >> 8) & 0xff00ff; - int ag = (buf2[x1] * idistx + buf2[x2] * distx) & 0xff00ff00; - *b++ = rb | ag; - fx += fdx; - } + // Now interpolate the values from the intermediate.buffer to get the final result. + intermediate_adder(b, end, intermediate, offset, fx, fdx); } @@ -2926,15 +2922,20 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper if (fdy == 0) { // simple scale, no rotation or shear if (qAbs(fdx) <= fixed_scale) { // scale up on X - fetchTransformedBilinear_simple_upscale_helper<blendType, bpp>(buffer, buffer + length, data->texture, fx, fy, fdx, fdy); + fetchTransformedBilinear_simple_scale_helper<blendType, bpp>(buffer, buffer + length, data->texture, fx, fy, fdx, fdy); + } else if (qAbs(fdx) <= 2 * fixed_scale) { // scale down on X less than 2x + const int mid = (length * 2 < BufferSize) ? length : ((length + 1) / 2); + fetchTransformedBilinear_simple_scale_helper<blendType, bpp>(buffer, buffer + mid, data->texture, fx, fy, fdx, fdy); + if (mid != length) + fetchTransformedBilinear_simple_scale_helper<blendType, bpp>(buffer + mid, buffer + length, data->texture, fx, fy, fdx, fdy); } else { const BilinearFastTransformFetcher fetcher = fetchTransformedBilinear_fetcher<blendType,bpp>; - uint buf1[buffer_size]; - uint buf2[buffer_size]; + uint buf1[BufferSize]; + uint buf2[BufferSize]; uint *b = buffer; while (length) { - int len = qMin(length, buffer_size / 2); + int len = qMin(length, BufferSize / 2); fetcher(buf1, buf2, len, data->texture, fx, fy, fdx, 0); layout->convertToARGB32PM(buf1, buf1, len * 2, clut, 0); layout->convertToARGB32PM(buf2, buf2, len * 2, clut, 0); @@ -2965,11 +2966,11 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper } else { // rotation or shear const BilinearFastTransformFetcher fetcher = fetchTransformedBilinear_fetcher<blendType,bpp>; - uint buf1[buffer_size]; - uint buf2[buffer_size]; + uint buf1[BufferSize]; + uint buf2[BufferSize]; uint *b = buffer; while (length) { - int len = qMin(length, buffer_size / 2); + int len = qMin(length, BufferSize / 2); fetcher(buf1, buf2, len, data->texture, fx, fy, fdx, fdy); layout->convertToARGB32PM(buf1, buf1, len * 2, clut, 0); layout->convertToARGB32PM(buf2, buf2, len * 2, clut, 0); @@ -3019,15 +3020,15 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper qreal fy = data->m22 * cy + data->m12 * cx + data->dy; qreal fw = data->m23 * cy + data->m13 * cx + data->m33; - uint buf1[buffer_size]; - uint buf2[buffer_size]; + uint buf1[BufferSize]; + uint buf2[BufferSize]; uint *b = buffer; - int distxs[buffer_size / 2]; - int distys[buffer_size / 2]; + int distxs[BufferSize / 2]; + int distys[BufferSize / 2]; while (length) { - int len = qMin(length, buffer_size / 2); + int len = qMin(length, BufferSize / 2); for (int i = 0; i < len; ++i) { const qreal iw = fw == 0 ? 1 : 1 / fw; const qreal px = fx * iw - qreal(0.5); @@ -3104,13 +3105,13 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co if (fdy == 0) { //simple scale, no rotation - uint sbuf1[buffer_size]; - uint sbuf2[buffer_size]; - quint64 buf1[buffer_size]; - quint64 buf2[buffer_size]; + uint sbuf1[BufferSize]; + uint sbuf2[BufferSize]; + quint64 buf1[BufferSize]; + quint64 buf2[BufferSize]; QRgba64 *b = buffer; while (length) { - int len = qMin(length, buffer_size / 2); + int len = qMin(length, BufferSize / 2); int disty = (fy & 0x0000ffff); #if defined(__SSE2__) const __m128i vdy = _mm_set1_epi16(disty); @@ -3148,15 +3149,15 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co b += len; } } else { //rotation - uint sbuf1[buffer_size]; - uint sbuf2[buffer_size]; - quint64 buf1[buffer_size]; - quint64 buf2[buffer_size]; + uint sbuf1[BufferSize]; + uint sbuf2[BufferSize]; + quint64 buf1[BufferSize]; + quint64 buf2[BufferSize]; QRgba64 *end = buffer + length; QRgba64 *b = buffer; while (b < end) { - int len = qMin(length, buffer_size / 2); + int len = qMin(length, BufferSize / 2); fetcher(sbuf1, sbuf2, len, data->texture, fx, fy, fdx, fdy); @@ -3187,17 +3188,17 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co qreal fw = data->m23 * cy + data->m13 * cx + data->m33; FetchPixelFunc fetch = qFetchPixel[layout->bpp]; - uint sbuf1[buffer_size]; - uint sbuf2[buffer_size]; - quint64 buf1[buffer_size]; - quint64 buf2[buffer_size]; + uint sbuf1[BufferSize]; + uint sbuf2[BufferSize]; + quint64 buf1[BufferSize]; + quint64 buf2[BufferSize]; QRgba64 *b = buffer; - int distxs[buffer_size / 2]; - int distys[buffer_size / 2]; + int distxs[BufferSize / 2]; + int distys[BufferSize / 2]; while (length) { - int len = qMin(length, buffer_size / 2); + int len = qMin(length, BufferSize / 2); for (int i = 0; i < len; ++i) { const qreal iw = fw == 0 ? 1 : 1 / fw; const qreal px = fx * iw - qreal(0.5); @@ -3302,6 +3303,15 @@ static SourceFetchProc sourceFetchARGB32PM[NBlendTypes] = { fetchTransformedBilinearARGB32PM<BlendTransformedBilinearTiled> // BilinearTiled }; +static SourceFetchProc sourceFetchAny16[NBlendTypes] = { + fetchUntransformed, // Untransformed + fetchUntransformed, // Tiled + fetchTransformed<BlendTransformed, QPixelLayout::BPP16>, // Transformed + fetchTransformed<BlendTransformedTiled, QPixelLayout::BPP16>, // TransformedTiled + fetchTransformedBilinear<BlendTransformedBilinear, QPixelLayout::BPP16>, // TransformedBilinear + fetchTransformedBilinear<BlendTransformedBilinearTiled, QPixelLayout::BPP16> // TransformedBilinearTiled +}; + static SourceFetchProc sourceFetchAny32[NBlendTypes] = { fetchUntransformed, // Untransformed fetchUntransformed, // Tiled @@ -3326,6 +3336,8 @@ static inline SourceFetchProc getSourceFetch(TextureBlendType blendType, QImage: return sourceFetchARGB32PM[blendType]; if (blendType == BlendUntransformed || blendType == BlendTiled) return sourceFetchUntransformed[format]; + if (qPixelLayouts[format].bpp == QPixelLayout::BPP16) + return sourceFetchAny16[blendType]; if (qPixelLayouts[format].bpp == QPixelLayout::BPP32) return sourceFetchAny32[blendType]; return sourceFetchGeneric[blendType]; @@ -3727,7 +3739,7 @@ static void blend_color_generic(int count, const QSpan *spans, void *userData) { QSpanData *data = reinterpret_cast<QSpanData *>(userData); - uint buffer[buffer_size]; + uint buffer[BufferSize]; Operator op = getOperator(data, spans, count); const uint color = data->solid.color.toArgb32(); @@ -3735,7 +3747,7 @@ void blend_color_generic(int count, const QSpan *spans, void *userData) int x = spans->x; int length = spans->len; while (length) { - int l = qMin(buffer_size, length); + int l = qMin(BufferSize, length); uint *dest = op.destFetch ? op.destFetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer; op.funcSolid(dest, l, color, spans->coverage); if (op.destStore) @@ -3787,14 +3799,14 @@ void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData) return blend_color_generic(count, spans, userData); } - quint64 buffer[buffer_size]; + quint64 buffer[BufferSize]; const QRgba64 color = data->solid.color; while (count--) { int x = spans->x; int length = spans->len; while (length) { - int l = qMin(buffer_size, length); + int l = qMin(BufferSize, length); QRgba64 *dest = op.destFetch64((QRgba64 *)buffer, data->rasterBuffer, x, spans->y, l); op.funcSolid64(dest, l, color, spans->coverage); op.destStore64(data->rasterBuffer, x, spans->y, dest, l); @@ -3899,7 +3911,7 @@ void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handle int length = right - x; while (length) { - int l = qMin(buffer_size, length); + int l = qMin(BufferSize, length); length -= l; int process_length = l; @@ -3946,8 +3958,8 @@ struct QBlendBase BlendType *dest; - BlendType buffer[buffer_size]; - BlendType src_buffer[buffer_size]; + BlendType buffer[BufferSize]; + BlendType src_buffer[BufferSize]; }; class BlendSrcGeneric : public QBlendBase<uint> @@ -4031,8 +4043,8 @@ static void blend_untransformed_generic(int count, const QSpan *spans, void *use { QSpanData *data = reinterpret_cast<QSpanData *>(userData); - uint buffer[buffer_size]; - uint src_buffer[buffer_size]; + uint buffer[BufferSize]; + uint src_buffer[BufferSize]; Operator op = getOperator(data, spans, count); const int image_width = data->texture.width; @@ -4056,7 +4068,7 @@ static void blend_untransformed_generic(int count, const QSpan *spans, void *use if (length > 0) { const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; while (length) { - int l = qMin(buffer_size, length); + int l = qMin(BufferSize, length); const uint *src = op.srcFetch(src_buffer, &op, data, sy, sx, l); uint *dest = op.destFetch ? op.destFetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer; op.func(dest, src, l, coverage); @@ -4081,8 +4093,8 @@ static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, voi qCDebug(lcQtGuiDrawHelper, "blend_untransformed_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit"); return blend_untransformed_generic(count, spans, userData); } - quint64 buffer[buffer_size]; - quint64 src_buffer[buffer_size]; + quint64 buffer[BufferSize]; + quint64 src_buffer[BufferSize]; const int image_width = data->texture.width; const int image_height = data->texture.height; @@ -4105,7 +4117,7 @@ static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, voi if (length > 0) { const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; while (length) { - int l = qMin(buffer_size, length); + int l = qMin(BufferSize, length); const QRgba64 *src = op.srcFetch64((QRgba64 *)src_buffer, &op, data, sy, sx, l); QRgba64 *dest = op.destFetch64((QRgba64 *)buffer, data->rasterBuffer, x, spans->y, l); op.func64(dest, src, l, coverage); @@ -4269,8 +4281,8 @@ static void blend_tiled_generic(int count, const QSpan *spans, void *userData) { QSpanData *data = reinterpret_cast<QSpanData *>(userData); - uint buffer[buffer_size]; - uint src_buffer[buffer_size]; + uint buffer[BufferSize]; + uint src_buffer[BufferSize]; Operator op = getOperator(data, spans, count); const int image_width = data->texture.width; @@ -4296,8 +4308,8 @@ static void blend_tiled_generic(int count, const QSpan *spans, void *userData) const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; while (length) { int l = qMin(image_width - sx, length); - if (buffer_size < l) - l = buffer_size; + if (BufferSize < l) + l = BufferSize; const uint *src = op.srcFetch(src_buffer, &op, data, sy, sx, l); uint *dest = op.destFetch ? op.destFetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer; op.func(dest, src, l, coverage); @@ -4322,8 +4334,8 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD qCDebug(lcQtGuiDrawHelper, "blend_tiled_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit"); return blend_tiled_generic(count, spans, userData); } - quint64 buffer[buffer_size]; - quint64 src_buffer[buffer_size]; + quint64 buffer[BufferSize]; + quint64 src_buffer[BufferSize]; const int image_width = data->texture.width; const int image_height = data->texture.height; @@ -4348,8 +4360,8 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; while (length) { int l = qMin(image_width - sx, length); - if (buffer_size < l) - l = buffer_size; + if (BufferSize < l) + l = BufferSize; const QRgba64 *src = op.srcFetch64((QRgba64 *)src_buffer, &op, data, sy, sx, l); QRgba64 *dest = op.destFetch64((QRgba64 *)buffer, data->rasterBuffer, x, spans->y, l); op.func64(dest, src, l, coverage); @@ -4398,8 +4410,8 @@ static void blend_tiled_argb(int count, const QSpan *spans, void *userData) const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; while (length) { int l = qMin(image_width - sx, length); - if (buffer_size < l) - l = buffer_size; + if (BufferSize < l) + l = BufferSize; const uint *src = (const uint *)data->texture.scanLine(sy) + sx; uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x; op.func(dest, src, l, coverage); @@ -4458,8 +4470,8 @@ static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData) int tx = x; while (length) { int l = qMin(image_width - sx, length); - if (buffer_size < l) - l = buffer_size; + if (BufferSize < l) + l = BufferSize; quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + tx; const quint16 *src = (const quint16 *)data->texture.scanLine(sy) + sx; memcpy(dest, src, l * sizeof(quint16)); @@ -4494,8 +4506,8 @@ static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData) if (alpha > 0) { while (length) { int l = qMin(image_width - sx, length); - if (buffer_size < l) - l = buffer_size; + if (BufferSize < l) + l = BufferSize; quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + x; const quint16 *src = (const quint16 *)data->texture.scanLine(sy) + sx; blend_sourceOver_rgb16_rgb16(dest, src, l, alpha, ialpha); @@ -4511,199 +4523,6 @@ static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData) } } -static void blend_transformed_bilinear_rgb565(int count, const QSpan *spans, void *userData) -{ - QSpanData *data = reinterpret_cast<QSpanData*>(userData); - QPainter::CompositionMode mode = data->rasterBuffer->compositionMode; - - if (data->texture.format != QImage::Format_RGB16 - || (mode != QPainter::CompositionMode_SourceOver - && mode != QPainter::CompositionMode_Source)) - { - blend_src_generic(count, spans, userData); - return; - } - - quint16 buffer[buffer_size]; - - const int src_minx = data->texture.x1; - const int src_miny = data->texture.y1; - const int src_maxx = data->texture.x2 - 1; - const int src_maxy = data->texture.y2 - 1; - - if (data->fast_matrix) { - // The increment pr x in the scanline - const int fdx = (int)(data->m11 * fixed_scale); - const int fdy = (int)(data->m12 * fixed_scale); - - while (count--) { - const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8; - const quint8 alpha = (coverage + 1) >> 3; - const quint8 ialpha = 0x20 - alpha; - if (alpha == 0) { - ++spans; - continue; - } - - quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x; - const qreal cx = spans->x + qreal(0.5); - const qreal cy = spans->y + qreal(0.5); - int x = int((data->m21 * cy - + data->m11 * cx + data->dx) * fixed_scale) - half_point; - int y = int((data->m22 * cy - + data->m12 * cx + data->dy) * fixed_scale) - half_point; - int length = spans->len; - - while (length) { - int l; - quint16 *b; - if (ialpha == 0) { - l = length; - b = dest; - } else { - l = qMin(length, buffer_size); - b = buffer; - } - const quint16 *end = b + l; - - while (b < end) { - int x1 = (x >> 16); - int x2; - int y1 = (y >> 16); - int y2; - - fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_minx, src_maxx, x1, x2); - fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_miny, src_maxy, y1, y2); - - const quint16 *src1 = (const quint16*)data->texture.scanLine(y1); - const quint16 *src2 = (const quint16*)data->texture.scanLine(y2); - quint16 tl = src1[x1]; - const quint16 tr = src1[x2]; - quint16 bl = src2[x1]; - const quint16 br = src2[x2]; - - const uint distxsl8 = x & 0xff00; - const uint distysl8 = y & 0xff00; - const uint distx = distxsl8 >> 8; - const uint disty = distysl8 >> 8; - const uint distxy = distx * disty; - - const uint tlw = 0x10000 - distxsl8 - distysl8 + distxy; // (256 - distx) * (256 - disty) - const uint trw = distxsl8 - distxy; // distx * (256 - disty) - const uint blw = distysl8 - distxy; // (256 - distx) * disty - const uint brw = distxy; // distx * disty - uint red = ((tl & 0xf800) * tlw + (tr & 0xf800) * trw - + (bl & 0xf800) * blw + (br & 0xf800) * brw) & 0xf8000000; - uint green = ((tl & 0x07e0) * tlw + (tr & 0x07e0) * trw - + (bl & 0x07e0) * blw + (br & 0x07e0) * brw) & 0x07e00000; - uint blue = ((tl & 0x001f) * tlw + (tr & 0x001f) * trw - + (bl & 0x001f) * blw + (br & 0x001f) * brw); - *b = quint16((red | green | blue) >> 16); - - ++b; - x += fdx; - y += fdy; - } - - if (ialpha != 0) - blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha); - - dest += l; - length -= l; - } - ++spans; - } - } else { - const qreal fdx = data->m11; - const qreal fdy = data->m12; - const qreal fdw = data->m13; - - while (count--) { - const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8; - const quint8 alpha = (coverage + 1) >> 3; - const quint8 ialpha = 0x20 - alpha; - if (alpha == 0) { - ++spans; - continue; - } - - quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x; - - const qreal cx = spans->x + qreal(0.5); - const qreal cy = spans->y + qreal(0.5); - - qreal x = data->m21 * cy + data->m11 * cx + data->dx; - qreal y = data->m22 * cy + data->m12 * cx + data->dy; - qreal w = data->m23 * cy + data->m13 * cx + data->m33; - - int length = spans->len; - while (length) { - int l; - quint16 *b; - if (ialpha == 0) { - l = length; - b = dest; - } else { - l = qMin(length, buffer_size); - b = buffer; - } - const quint16 *end = b + l; - - while (b < end) { - const qreal iw = w == 0 ? 1 : 1 / w; - const qreal px = x * iw - qreal(0.5); - const qreal py = y * iw - qreal(0.5); - - int x1 = int(px) - (px < 0); - int x2; - int y1 = int(py) - (py < 0); - int y2; - - fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_minx, src_maxx, x1, x2); - fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_miny, src_maxy, y1, y2); - - const quint16 *src1 = (const quint16 *)data->texture.scanLine(y1); - const quint16 *src2 = (const quint16 *)data->texture.scanLine(y2); - quint16 tl = src1[x1]; - const quint16 tr = src1[x2]; - quint16 bl = src2[x1]; - const quint16 br = src2[x2]; - - const uint distx = uint((px - x1) * 256); - const uint disty = uint((py - y1) * 256); - const uint distxsl8 = distx << 8; - const uint distysl8 = disty << 8; - const uint distxy = distx * disty; - - const uint tlw = 0x10000 - distxsl8 - distysl8 + distxy; // (256 - distx) * (256 - disty) - const uint trw = distxsl8 - distxy; // distx * (256 - disty) - const uint blw = distysl8 - distxy; // (256 - distx) * disty - const uint brw = distxy; // distx * disty - uint red = ((tl & 0xf800) * tlw + (tr & 0xf800) * trw - + (bl & 0xf800) * blw + (br & 0xf800) * brw) & 0xf8000000; - uint green = ((tl & 0x07e0) * tlw + (tr & 0x07e0) * trw - + (bl & 0x07e0) * blw + (br & 0x07e0) * brw) & 0x07e00000; - uint blue = ((tl & 0x001f) * tlw + (tr & 0x001f) * trw - + (bl & 0x001f) * blw + (br & 0x001f) * brw); - *b = quint16((red | green | blue) >> 16); - - ++b; - x += fdx; - y += fdy; - w += fdw; - } - - if (ialpha != 0) - blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha); - - dest += l; - length -= l; - } - ++spans; - } - } -} - static void blend_transformed_argb(int count, const QSpan *spans, void *userData) { QSpanData *data = reinterpret_cast<QSpanData *>(userData); @@ -4714,7 +4533,7 @@ static void blend_transformed_argb(int count, const QSpan *spans, void *userData } CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode]; - uint buffer[buffer_size]; + uint buffer[BufferSize]; quint32 mask = (data->texture.format == QImage::Format_RGB32) ? 0xff000000 : 0; const int image_x1 = data->texture.x1; @@ -4743,7 +4562,7 @@ static void blend_transformed_argb(int count, const QSpan *spans, void *userData int length = spans->len; const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; while (length) { - int l = qMin(length, buffer_size); + int l = qMin(length, BufferSize); const uint *end = buffer + l; uint *b = buffer; while (b < end) { @@ -4780,7 +4599,7 @@ static void blend_transformed_argb(int count, const QSpan *spans, void *userData int length = spans->len; const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; while (length) { - int l = qMin(length, buffer_size); + int l = qMin(length, BufferSize); const uint *end = buffer + l; uint *b = buffer; while (b < end) { @@ -4819,7 +4638,7 @@ static void blend_transformed_rgb565(int count, const QSpan *spans, void *userDa return; } - quint16 buffer[buffer_size]; + quint16 buffer[BufferSize]; const int image_x1 = data->texture.x1; const int image_y1 = data->texture.y1; const int image_x2 = data->texture.x2 - 1; @@ -4855,7 +4674,7 @@ static void blend_transformed_rgb565(int count, const QSpan *spans, void *userDa l = length; b = dest; } else { - l = qMin(length, buffer_size); + l = qMin(length, BufferSize); b = buffer; } const quint16 *end = b + l; @@ -4910,7 +4729,7 @@ static void blend_transformed_rgb565(int count, const QSpan *spans, void *userDa l = length; b = dest; } else { - l = qMin(length, buffer_size); + l = qMin(length, BufferSize); b = buffer; } const quint16 *end = b + l; @@ -4952,7 +4771,7 @@ static void blend_transformed_tiled_argb(int count, const QSpan *spans, void *us } CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode]; - uint buffer[buffer_size]; + uint buffer[BufferSize]; int image_width = data->texture.width; int image_height = data->texture.height; @@ -4980,7 +4799,7 @@ static void blend_transformed_tiled_argb(int count, const QSpan *spans, void *us const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; int length = spans->len; while (length) { - int l = qMin(length, buffer_size); + int l = qMin(length, BufferSize); const uint *end = buffer + l; uint *b = buffer; int px16 = x % (image_width << 16); @@ -5034,7 +4853,7 @@ static void blend_transformed_tiled_argb(int count, const QSpan *spans, void *us const int coverage = (spans->coverage * data->texture.const_alpha) >> 8; int length = spans->len; while (length) { - int l = qMin(length, buffer_size); + int l = qMin(length, BufferSize); const uint *end = buffer + l; uint *b = buffer; while (b < end) { @@ -5085,7 +4904,7 @@ static void blend_transformed_tiled_rgb565(int count, const QSpan *spans, void * return; } - quint16 buffer[buffer_size]; + quint16 buffer[BufferSize]; const int image_width = data->texture.width; const int image_height = data->texture.height; @@ -5119,7 +4938,7 @@ static void blend_transformed_tiled_rgb565(int count, const QSpan *spans, void * l = length; b = dest; } else { - l = qMin(length, buffer_size); + l = qMin(length, BufferSize); b = buffer; } const quint16 *end = b + l; @@ -5179,7 +4998,7 @@ static void blend_transformed_tiled_rgb565(int count, const QSpan *spans, void * l = length; b = dest; } else { - l = qMin(length, buffer_size); + l = qMin(length, BufferSize); b = buffer; } const quint16 *end = b + l; @@ -5237,7 +5056,7 @@ static const ProcessSpans processTextureSpansRGB16[NBlendTypes] = { blend_tiled_rgb565, // Tiled blend_transformed_rgb565, // Transformed blend_transformed_tiled_rgb565, // TransformedTiled - blend_transformed_bilinear_rgb565, // TransformedBilinear + blend_src_generic, // TransformedBilinear blend_src_generic // TransformedBilinearTiled }; @@ -5533,7 +5352,7 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied(); } - quint64 buffer[buffer_size]; + quint64 buffer[BufferSize]; const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format]; const DestStoreProc64 destStore64 = destStoreProc64[rasterBuffer->format]; @@ -5542,7 +5361,7 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, int i = x; int length = mapWidth; while (length > 0) { - int l = qMin(buffer_size, length); + int l = qMin(BufferSize, length); QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, i, y + ly, l); for (int j=0; j < l; ++j) { const int coverage = map[j + (i - x)]; @@ -5571,7 +5390,7 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer, int end = qMin<int>(x + mapWidth, clip.x + clip.len); if (end <= start) continue; - Q_ASSERT(end - start <= buffer_size); + Q_ASSERT(end - start <= BufferSize); QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, start, clip.y, end - start); for (int xp=start; xp<end; ++xp) { @@ -5810,7 +5629,7 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied(); } - quint64 buffer[buffer_size]; + quint64 buffer[BufferSize]; const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format]; const DestStoreProc64 destStore64 = destStoreProc64[rasterBuffer->format]; @@ -5819,7 +5638,7 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, int i = x; int length = mapWidth; while (length > 0) { - int l = qMin(buffer_size, length); + int l = qMin(BufferSize, length); QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, i, y + ly, l); for (int j=0; j < l; ++j) { const uint coverage = src[j + (i - x)]; @@ -5848,7 +5667,7 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer, int end = qMin<int>(x + mapWidth, clip.x + clip.len); if (end <= start) continue; - Q_ASSERT(end - start <= buffer_size); + Q_ASSERT(end - start <= BufferSize); QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, start, clip.y, end - start); for (int xp=start; xp<end; ++xp) { @@ -5938,8 +5757,26 @@ static void qt_rectfill_quint16(QRasterBuffer *rasterBuffer, int x, int y, int width, int height, const QRgba64 &color) { + const QPixelLayout &layout = qPixelLayouts[rasterBuffer->format]; + quint32 c32 = color.toArgb32(); + layout.convertFromARGB32PM(&c32, &c32, 1, nullptr, nullptr); + quint16 c16; + storePixel<QPixelLayout::BPP16>(reinterpret_cast<uchar *>(&c16), 0, c32); qt_rectfill<quint16>(reinterpret_cast<quint16 *>(rasterBuffer->buffer()), - color.toRgb16(), x, y, width, height, rasterBuffer->bytesPerLine()); + c16, x, y, width, height, rasterBuffer->bytesPerLine()); +} + +static void qt_rectfill_quint24(QRasterBuffer *rasterBuffer, + int x, int y, int width, int height, + const QRgba64 &color) +{ + const QPixelLayout &layout = qPixelLayouts[rasterBuffer->format]; + quint32 c32 = color.toArgb32(); + layout.convertFromARGB32PM(&c32, &c32, 1, nullptr, nullptr); + quint24 c24; + storePixel<QPixelLayout::BPP24>(reinterpret_cast<uchar *>(&c24), 0, c32); + qt_rectfill<quint24>(reinterpret_cast<quint24 *>(rasterBuffer->buffer()), + c24, x, y, width, height, rasterBuffer->bytesPerLine()); } static void qt_rectfill_nonpremul_argb32(QRasterBuffer *rasterBuffer, @@ -6059,7 +5896,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = 0, qt_alphamapblit_generic, qt_alphargbblit_generic, - 0 + qt_rectfill_quint24 }, // Format_RGB666 { @@ -6068,7 +5905,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = 0, qt_alphamapblit_generic, qt_alphargbblit_generic, - 0 + qt_rectfill_quint24 }, // Format_ARGB6666_Premultiplied { @@ -6077,7 +5914,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = 0, qt_alphamapblit_generic, qt_alphargbblit_generic, - 0 + qt_rectfill_quint24 }, // Format_RGB555 { @@ -6086,7 +5923,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = 0, qt_alphamapblit_generic, qt_alphargbblit_generic, - 0 + qt_rectfill_quint16 }, // Format_ARGB8555_Premultiplied { @@ -6095,7 +5932,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = 0, qt_alphamapblit_generic, qt_alphargbblit_generic, - 0 + qt_rectfill_quint24 }, // Format_RGB888 { @@ -6104,7 +5941,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = 0, qt_alphamapblit_generic, qt_alphargbblit_generic, - 0 + qt_rectfill_quint24 }, // Format_RGB444 { @@ -6113,7 +5950,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = 0, qt_alphamapblit_generic, qt_alphargbblit_generic, - 0 + qt_rectfill_quint16 }, // Format_ARGB4444_Premultiplied { @@ -6122,7 +5959,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = 0, qt_alphamapblit_generic, qt_alphargbblit_generic, - 0 + qt_rectfill_quint16 }, // Format_RGBX8888 { @@ -6411,14 +6248,14 @@ static void qInitDrawhelperFunctions() qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_avx2; qt_functionForModeSolid64_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_rgb64_avx2; - extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uint *b, uint *end, const QTextureData &image, - int &fx, int &fy, int fdx, int /*fdy*/); + extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2(uint *b, uint *end, const QTextureData &image, + int &fx, int &fy, int fdx, int /*fdy*/); extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_downscale_helper_avx2(uint *b, uint *end, const QTextureData &image, int &fx, int &fy, int fdx, int /*fdy*/); extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_fast_rotate_helper_avx2(uint *b, uint *end, const QTextureData &image, int &fx, int &fy, int fdx, int fdy); - bilinearFastTransformHelperARGB32PM[0][SimpleUpscaleTransform] = fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2; + bilinearFastTransformHelperARGB32PM[0][SimpleScaleTransform] = fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2; bilinearFastTransformHelperARGB32PM[0][DownscaleTransform] = fetchTransformedBilinearARGB32PM_downscale_helper_avx2; bilinearFastTransformHelperARGB32PM[0][FastRotateTransform] = fetchTransformedBilinearARGB32PM_fast_rotate_helper_avx2; } diff --git a/src/gui/painting/qdrawhelper_avx2.cpp b/src/gui/painting/qdrawhelper_avx2.cpp index 3a70524a9d..1c225b4568 100644 --- a/src/gui/painting/qdrawhelper_avx2.cpp +++ b/src/gui/painting/qdrawhelper_avx2.cpp @@ -45,8 +45,6 @@ QT_BEGIN_NAMESPACE -static Q_CONSTEXPR int BufferSize = 2048; - enum { FixedScale = 1 << 16, HalfPoint = 1 << 15 @@ -576,8 +574,10 @@ inline void fetchTransformedBilinear_pixelBounds(int, int l1, int l2, int &v1, i Q_ASSERT(v2 >= l1 && v2 <= l2); } -void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uint *b, uint *end, const QTextureData &image, - int &fx, int &fy, int fdx, int /*fdy*/) +void QT_FASTCALL intermediate_adder_avx2(uint *b, uint *end, const IntermediateBuffer &intermediate, int offset, int &fx, int fdx); + +void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2(uint *b, uint *end, const QTextureData &image, + int &fx, int &fy, int fdx, int /*fdy*/) { int y1 = (fy >> 16); int y2; @@ -594,16 +594,12 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin const int offset = (fx + adjust) >> 16; int x = offset; - // The idea is first to do the interpolation between the row s1 and the row s2 - // into an intermediate buffer, then we interpolate between two pixel of this buffer. - - // intermediate_buffer[0] is a buffer of red-blue component of the pixel, in the form 0x00RR00BB - // intermediate_buffer[1] is the alpha-green component of the pixel, in the form 0x00AA00GG - // +1 for the last pixel to interpolate with, and +1 for rounding errors. - quint32 intermediate_buffer[2][BufferSize + 2]; + IntermediateBuffer intermediate; // count is the size used in the intermediate_buffer. int count = (qint64(length) * qAbs(fdx) + FixedScale - 1) / FixedScale + 2; - Q_ASSERT(count <= BufferSize + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case + // length is supposed to be <= BufferSize either because data->m11 < 1 or + // data->m11 < 2, and any larger buffers split + Q_ASSERT(count <= BufferSize + 2); int f = 0; int lim = qMin(count, image.x2 - x); if (x < image.x1) { @@ -613,8 +609,8 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin quint32 rb = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff; quint32 ag = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff; do { - intermediate_buffer[0][f] = rb; - intermediate_buffer[1][f] = ag; + intermediate.buffer_rb[f] = rb; + intermediate.buffer_ag[f] = ag; f++; x++; } while (x < image.x1 && f < lim); @@ -644,10 +640,10 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin // Add the values, and shift to only keep 8 significant bits per colors __m256i rAG =_mm256_add_epi16(topAG, bottomAG); rAG = _mm256_srli_epi16(rAG, 8); - _mm256_storeu_si256((__m256i*)(&intermediate_buffer[1][f]), rAG); + _mm256_storeu_si256((__m256i*)(&intermediate.buffer_ag[f]), rAG); __m256i rRB =_mm256_add_epi16(topRB, bottomRB); rRB = _mm256_srli_epi16(rRB, 8); - _mm256_storeu_si256((__m256i*)(&intermediate_buffer[0][f]), rRB); + _mm256_storeu_si256((__m256i*)(&intermediate.buffer_rb[f]), rRB); } for (; f < count; f++) { // Same as above but without simd @@ -656,11 +652,17 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin uint t = s1[x]; uint b = s2[x]; - intermediate_buffer[0][f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff; - intermediate_buffer[1][f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff; + intermediate.buffer_rb[f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff; + intermediate.buffer_ag[f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff; x++; } + // Now interpolate the values from the intermediate_buffer to get the final result. + intermediate_adder_avx2(b, end, intermediate, offset, fx, fdx); +} + +void QT_FASTCALL intermediate_adder_avx2(uint *b, uint *end, const IntermediateBuffer &intermediate, int offset, int &fx, int fdx) +{ fx -= offset * FixedScale; const __m128i v_fdx = _mm_set1_epi32(fdx * 4); @@ -669,8 +671,8 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin while (b < end - 3) { const __m128i offset = _mm_srli_epi32(v_fx, 16); - __m256i vrb = _mm256_i32gather_epi64((const long long *)intermediate_buffer[0], offset, 4); - __m256i vag = _mm256_i32gather_epi64((const long long *)intermediate_buffer[1], offset, 4); + __m256i vrb = _mm256_i32gather_epi64((const long long *)intermediate.buffer_rb, offset, 4); + __m256i vag = _mm256_i32gather_epi64((const long long *)intermediate.buffer_ag, offset, 4); __m128i vdx = _mm_and_si128(v_fx, _mm_set1_epi32(0x0000ffff)); vdx = _mm_srli_epi16(vdx, 8); @@ -695,17 +697,17 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin v_fx = _mm_add_epi32(v_fx, v_fdx); } while (b < end) { - int x = (fx >> 16); - - uint distx = (fx & 0x0000ffff) >> 8; - uint idistx = 256 - distx; + const int x = (fx >> 16); - uint rb = ((intermediate_buffer[0][x] * idistx + intermediate_buffer[0][x + 1] * distx) >> 8) & 0xff00ff; - uint ag = (intermediate_buffer[1][x] * idistx + intermediate_buffer[1][x + 1] * distx) & 0xff00ff00; - *b = rb | ag; + const uint distx = (fx & 0x0000ffff) >> 8; + const uint idistx = 256 - distx; + const uint rb = (intermediate.buffer_rb[x] * idistx + intermediate.buffer_rb[x + 1] * distx) & 0xff00ff00; + const uint ag = (intermediate.buffer_ag[x] * idistx + intermediate.buffer_ag[x + 1] * distx) & 0xff00ff00; + *b = (rb >> 8) | ag; b++; fx += fdx; } + fx += offset * FixedScale; } void QT_FASTCALL fetchTransformedBilinearARGB32PM_downscale_helper_avx2(uint *b, uint *end, const QTextureData &image, diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index ebf215a3eb..4604e0f8af 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -784,6 +784,7 @@ static Q_ALWAYS_INLINE uint qAlphaRgb30(uint c) } struct quint24 { + quint24() = default; quint24(uint value); operator uint() const; uchar data[3]; @@ -1191,6 +1192,22 @@ inline uint comp_func_Plus_one_pixel(uint d, const uint s) #undef MIX #undef AMIX +// must be multiple of 4 for easier SIMD implementations +static Q_CONSTEXPR int BufferSize = 2048; + +// A buffer of intermediate results used by simple bilinear scaling. +struct IntermediateBuffer +{ + // The idea is first to do the interpolation between the row s1 and the row s2 + // into this intermediate buffer, then later interpolate between two pixel of this buffer. + // + // buffer_rb is a buffer of red-blue component of the pixel, in the form 0x00RR00BB + // buffer_ag is the alpha-green component of the pixel, in the form 0x00AA00GG + // +1 for the last pixel to interpolate with, and +1 for rounding errors. + quint32 buffer_rb[BufferSize+2]; + quint32 buffer_ag[BufferSize+2]; +}; + struct QDitherInfo { int x; int y; diff --git a/src/gui/painting/qpagedpaintdevice.cpp b/src/gui/painting/qpagedpaintdevice.cpp index 1c7d6471b6..613a686848 100644 --- a/src/gui/painting/qpagedpaintdevice.cpp +++ b/src/gui/painting/qpagedpaintdevice.cpp @@ -42,6 +42,41 @@ QT_BEGIN_NAMESPACE +class QDummyPagedPaintDevicePrivate : public QPagedPaintDevicePrivate +{ + bool setPageLayout(const QPageLayout &newPageLayout) override + { + m_pageLayout = newPageLayout; + return m_pageLayout.isEquivalentTo(newPageLayout); + } + + bool setPageSize(const QPageSize &pageSize) override + { + m_pageLayout.setPageSize(pageSize); + return m_pageLayout.pageSize().isEquivalentTo(pageSize); + } + + bool setPageOrientation(QPageLayout::Orientation orientation) override + { + m_pageLayout.setOrientation(orientation); + return m_pageLayout.orientation() == orientation; + } + + bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units) override + { + m_pageLayout.setUnits(units); + m_pageLayout.setMargins(margins); + return m_pageLayout.margins() == margins && m_pageLayout.units() == units; + } + + QPageLayout pageLayout() const override + { + return m_pageLayout; + } + + QPageLayout m_pageLayout; +}; + QPagedPaintDevicePrivate::~QPagedPaintDevicePrivate() { } @@ -61,9 +96,11 @@ QPagedPaintDevicePrivate::~QPagedPaintDevicePrivate() /*! Constructs a new paged paint device. + + \deprecated */ QPagedPaintDevice::QPagedPaintDevice() - : d(new QPagedPaintDevicePrivate) + : d(new QDummyPagedPaintDevicePrivate) { } @@ -263,7 +300,7 @@ QPagedPaintDevicePrivate *QPagedPaintDevice::dd() */ void QPagedPaintDevice::setPageSize(PageSize size) { - d->m_pageLayout.setPageSize(QPageSize(QPageSize::PageSizeId(size))); + d->setPageSize(QPageSize(QPageSize::PageSizeId(size))); } /*! @@ -271,7 +308,7 @@ void QPagedPaintDevice::setPageSize(PageSize size) */ QPagedPaintDevice::PageSize QPagedPaintDevice::pageSize() const { - return PageSize(d->m_pageLayout.pageSize().id()); + return PageSize(d->pageLayout().pageSize().id()); } /*! @@ -282,7 +319,7 @@ QPagedPaintDevice::PageSize QPagedPaintDevice::pageSize() const */ void QPagedPaintDevice::setPageSizeMM(const QSizeF &size) { - d->m_pageLayout.setPageSize(QPageSize(size, QPageSize::Millimeter)); + d->setPageSize(QPageSize(size, QPageSize::Millimeter)); } /*! @@ -290,7 +327,7 @@ void QPagedPaintDevice::setPageSizeMM(const QSizeF &size) */ QSizeF QPagedPaintDevice::pageSizeMM() const { - return d->m_pageLayout.pageSize().size(QPageSize::Millimeter); + return d->pageLayout().pageSize().size(QPageSize::Millimeter); } /*! @@ -305,8 +342,7 @@ QSizeF QPagedPaintDevice::pageSizeMM() const */ void QPagedPaintDevice::setMargins(const Margins &margins) { - d->m_pageLayout.setUnits(QPageLayout::Millimeter); - d->m_pageLayout.setMargins(QMarginsF(margins.left, margins.top, margins.right, margins.bottom)); + d->setPageMargins(QMarginsF(margins.left, margins.top, margins.right, margins.bottom), QPageLayout::Millimeter); } /*! @@ -318,7 +354,7 @@ void QPagedPaintDevice::setMargins(const Margins &margins) */ QPagedPaintDevice::Margins QPagedPaintDevice::margins() const { - QMarginsF margins = d->m_pageLayout.margins(QPageLayout::Millimeter); + QMarginsF margins = d->pageLayout().margins(QPageLayout::Millimeter); Margins result; result.left = margins.left(); result.top = margins.top(); @@ -413,7 +449,7 @@ bool QPagedPaintDevice::setPageOrientation(QPageLayout::Orientation orientation) bool QPagedPaintDevice::setPageMargins(const QMarginsF &margins) { - return d->setPageMargins(margins); + return setPageMargins(margins, pageLayout().units()); } /*! @@ -458,23 +494,30 @@ QPageLayout QPagedPaintDevice::pageLayout() const /*! \internal + \deprecated + Returns the internal device page layout. */ QPageLayout QPagedPaintDevice::devicePageLayout() const { - return d->m_pageLayout; + qWarning("QPagedPaintDevice::devicePageLayout() is deprecated, just use QPagedPaintDevice::pageLayout()"); + return d->pageLayout(); } /*! \internal + \deprecated + Returns the internal device page layout. */ QPageLayout &QPagedPaintDevice::devicePageLayout() { - return d->m_pageLayout; + qWarning("QPagedPaintDevice::devicePageLayout() is deprecated, you shouldn't be using this at all."); + static QPageLayout dummy; + return dummy; } QT_END_NAMESPACE diff --git a/src/gui/painting/qpagedpaintdevice.h b/src/gui/painting/qpagedpaintdevice.h index 66dd6fa8cf..c8957edab8 100644 --- a/src/gui/painting/qpagedpaintdevice.h +++ b/src/gui/painting/qpagedpaintdevice.h @@ -55,7 +55,7 @@ class QPagedPaintDevicePrivate; class Q_GUI_EXPORT QPagedPaintDevice : public QPaintDevice { public: - QPagedPaintDevice(); + QT_DEPRECATED QPagedPaintDevice(); ~QPagedPaintDevice(); virtual bool newPage() = 0; @@ -243,8 +243,8 @@ public: protected: QPagedPaintDevice(QPagedPaintDevicePrivate *dd); QPagedPaintDevicePrivate *dd(); - QPageLayout devicePageLayout() const; - QPageLayout &devicePageLayout(); + QT_DEPRECATED QPageLayout devicePageLayout() const; + QT_DEPRECATED QPageLayout &devicePageLayout(); friend class QPagedPaintDevicePrivate; QPagedPaintDevicePrivate *d; }; diff --git a/src/gui/painting/qpagedpaintdevice_p.h b/src/gui/painting/qpagedpaintdevice_p.h index a993ea4cac..3a43bd7828 100644 --- a/src/gui/painting/qpagedpaintdevice_p.h +++ b/src/gui/painting/qpagedpaintdevice_p.h @@ -60,8 +60,7 @@ class Q_GUI_EXPORT QPagedPaintDevicePrivate { public: QPagedPaintDevicePrivate() - : m_pageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0, 0, 0, 0)), - fromPage(0), + : fromPage(0), toPage(0), pageOrderAscending(true), printSelectionOnly(false) @@ -70,46 +69,19 @@ public: virtual ~QPagedPaintDevicePrivate(); - // ### Qt6 Remove these and make public class methods virtual - virtual bool setPageLayout(const QPageLayout &newPageLayout) - { - m_pageLayout = newPageLayout; - return m_pageLayout.isEquivalentTo(newPageLayout);; - } - virtual bool setPageSize(const QPageSize &pageSize) - { - m_pageLayout.setPageSize(pageSize); - return m_pageLayout.pageSize().isEquivalentTo(pageSize); - } + virtual bool setPageLayout(const QPageLayout &newPageLayout) = 0; - virtual bool setPageOrientation(QPageLayout::Orientation orientation) - { - m_pageLayout.setOrientation(orientation); - return m_pageLayout.orientation() == orientation; - } + virtual bool setPageSize(const QPageSize &pageSize) = 0; - virtual bool setPageMargins(const QMarginsF &margins) - { - return setPageMargins(margins, m_pageLayout.units()); - } + virtual bool setPageOrientation(QPageLayout::Orientation orientation) = 0; - virtual bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units) - { - m_pageLayout.setUnits(units); - m_pageLayout.setMargins(margins); - return m_pageLayout.margins() == margins && m_pageLayout.units() == units; - } + virtual bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units) = 0; - virtual QPageLayout pageLayout() const - { - return m_pageLayout; - } + virtual QPageLayout pageLayout() const = 0; static inline QPagedPaintDevicePrivate *get(QPagedPaintDevice *pd) { return pd->d; } - QPageLayout m_pageLayout; - // These are currently required to keep QPrinter functionality working in QTextDocument::print() int fromPage; int toPage; diff --git a/src/gui/painting/qpdfwriter.cpp b/src/gui/painting/qpdfwriter.cpp index 2f24c7efcb..e6c5cabd7f 100644 --- a/src/gui/painting/qpdfwriter.cpp +++ b/src/gui/painting/qpdfwriter.cpp @@ -83,41 +83,28 @@ public: { // Try to set the paint engine page layout pd->engine->setPageLayout(newPageLayout); - // Set QPagedPaintDevice layout to match the current paint engine layout - m_pageLayout = pd->engine->pageLayout(); - return m_pageLayout.isEquivalentTo(newPageLayout); + return pageLayout().isEquivalentTo(newPageLayout); } bool setPageSize(const QPageSize &pageSize) override { // Try to set the paint engine page size pd->engine->setPageSize(pageSize); - // Set QPagedPaintDevice layout to match the current paint engine layout - m_pageLayout = pd->engine->pageLayout(); - return m_pageLayout.pageSize().isEquivalentTo(pageSize); + return pageLayout().pageSize().isEquivalentTo(pageSize); } bool setPageOrientation(QPageLayout::Orientation orientation) override { // Set the print engine value pd->engine->setPageOrientation(orientation); - // Set QPagedPaintDevice layout to match the current paint engine layout - m_pageLayout = pd->engine->pageLayout(); - return m_pageLayout.orientation() == orientation; - } - - bool setPageMargins(const QMarginsF &margins) override - { - return setPageMargins(margins, pageLayout().units()); + return pageLayout().orientation() == orientation; } bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units) override { // Try to set engine margins pd->engine->setPageMargins(margins, units); - // Set QPagedPaintDevice layout to match the current paint engine layout - m_pageLayout = pd->engine->pageLayout(); - return m_pageLayout.margins() == margins && m_pageLayout.units() == units; + return pageLayout().margins() == margins && pageLayout().units() == units; } QPageLayout pageLayout() const override @@ -150,9 +137,6 @@ QPdfWriter::QPdfWriter(const QString &filename) Q_D(QPdfWriter); d->engine->setOutputFilename(filename); - - // Set QPagedPaintDevice layout to match the current paint engine layout - devicePageLayout() = d->engine->pageLayout(); } /*! @@ -165,9 +149,6 @@ QPdfWriter::QPdfWriter(QIODevice *device) Q_D(QPdfWriter); d->engine->d_func()->outDevice = device; - - // Set QPagedPaintDevice layout to match the current paint engine layout - devicePageLayout() = d->engine->pageLayout(); } /*! diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp index 64adeaa260..70623939e1 100644 --- a/src/gui/text/qcssparser.cpp +++ b/src/gui/text/qcssparser.cpp @@ -345,13 +345,6 @@ static const QCssKnownValue styleFeatures[NumKnownStyleFeatures - 1] = { { "none", StyleFeature_None } }; -#if defined(Q_CC_MSVC) && _MSC_VER < 1600 -static bool operator<(const QCssKnownValue &prop1, const QCssKnownValue &prop2) -{ - return QString::compare(QString::fromLatin1(prop1.name), QLatin1String(prop2.name), Qt::CaseInsensitive) < 0; -} -#endif - static bool operator<(const QString &name, const QCssKnownValue &prop) { return QString::compare(name, QLatin1String(prop.name), Qt::CaseInsensitive) < 0; diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index e27b388762..1c0751fbad 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -2906,7 +2906,11 @@ void QTextHtmlExporter::emitBlock(const QTextBlock &block) html += QLatin1Char('>'); html += QLatin1String("<pre"); } else if (!list) { - html += QLatin1String("<p"); + int headingLevel = blockFormat.headingLevel(); + if (headingLevel > 0 && headingLevel <= 6) + html += QLatin1String("<h") + QString::number(headingLevel); + else + html += QLatin1String("<p"); } emitBlockAttributes(block); @@ -2929,8 +2933,13 @@ void QTextHtmlExporter::emitBlock(const QTextBlock &block) html += QLatin1String("</pre>"); else if (list) html += QLatin1String("</li>"); - else - html += QLatin1String("</p>"); + else { + int headingLevel = blockFormat.headingLevel(); + if (headingLevel > 0 && headingLevel <= 6) + html += QLatin1String("</h") + QString::number(headingLevel) + QLatin1Char('>'); + else + html += QLatin1String("</p>"); + } if (list) { if (list->itemNumber(block) == list->count() - 1) { // last item? close list diff --git a/src/gui/text/qtextdocumentfragment.cpp b/src/gui/text/qtextdocumentfragment.cpp index ea37695f4e..3ad49b3f88 100644 --- a/src/gui/text/qtextdocumentfragment.cpp +++ b/src/gui/text/qtextdocumentfragment.cpp @@ -420,7 +420,7 @@ static QTextListFormat::Style nextListStyle(QTextListFormat::Style style) } QTextHtmlImporter::QTextHtmlImporter(QTextDocument *_doc, const QString &_html, ImportMode mode, const QTextDocument *resourceProvider) - : indent(0), compressNextWhitespace(PreserveWhiteSpace), doc(_doc), importMode(mode) + : indent(0), headingLevel(0), compressNextWhitespace(PreserveWhiteSpace), doc(_doc), importMode(mode) { cursor = QTextCursor(doc); wsm = QTextHtmlParserNode::WhiteSpaceNormal; @@ -747,8 +747,28 @@ QTextHtmlImporter::ProcessNodeResult QTextHtmlImporter::processSpecialNodes() return ContinueWithNextNode; } + case Html_h1: + headingLevel = 1; + break; + case Html_h2: + headingLevel = 2; + break; + case Html_h3: + headingLevel = 3; + break; + case Html_h4: + headingLevel = 4; + break; + case Html_h5: + headingLevel = 5; + break; + case Html_h6: + headingLevel = 6; + break; + default: break; } + return ContinueWithCurrentNode; } @@ -832,6 +852,15 @@ bool QTextHtmlImporter::closeTag() } } break; + case Html_h1: + case Html_h2: + case Html_h3: + case Html_h4: + case Html_h5: + case Html_h6: + headingLevel = 0; + blockTagClosed = true; + break; default: if (closedNode->isBlock()) blockTagClosed = true; @@ -1093,6 +1122,11 @@ QTextHtmlImporter::ProcessNodeResult QTextHtmlImporter::processBlockNode() modifiedBlockFormat = true; } + if (headingLevel) { + block.setHeadingLevel(headingLevel); + modifiedBlockFormat = true; + } + if (currentNode->blockFormat.propertyCount() > 0) { modifiedBlockFormat = true; block.merge(currentNode->blockFormat); diff --git a/src/gui/text/qtextdocumentfragment_p.h b/src/gui/text/qtextdocumentfragment_p.h index e8699545f7..02a6a429fa 100644 --- a/src/gui/text/qtextdocumentfragment_p.h +++ b/src/gui/text/qtextdocumentfragment_p.h @@ -152,6 +152,7 @@ private: friend class QTypeInfo<List>; QVector<List> lists; int indent; + int headingLevel; // insert a named anchor the next time we emit a char format, // either in a block or in regular text diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp index 9877a23fa6..d04dd08058 100644 --- a/src/gui/text/qtextdocumentlayout.cpp +++ b/src/gui/text/qtextdocumentlayout.cpp @@ -399,26 +399,6 @@ static bool operator<(const QCheckPoint &checkPoint, int pos) return checkPoint.positionInFrame < pos; } -#if defined(Q_CC_MSVC) && _MSC_VER < 1600 -//The STL implementation of MSVC 2008 requires the definitions - -static bool operator<(const QCheckPoint &checkPoint1, const QCheckPoint &checkPoint2) -{ - return checkPoint1.y < checkPoint2.y; -} - -static bool operator<(QFixed y, const QCheckPoint &checkPoint) -{ - return y < checkPoint.y; -} - -static bool operator<(int pos, const QCheckPoint &checkPoint) -{ - return pos < checkPoint.positionInFrame; -} - -#endif - static void fillBackground(QPainter *p, const QRectF &rect, QBrush brush, const QPointF &origin, const QRectF &gradientRect = QRectF()) { p->save(); diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 5e38311fa1..9169ed8da1 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1927,7 +1927,7 @@ const QCharAttributes *QTextEngine::attributes() const QVarLengthArray<QUnicodeTools::ScriptItem> scriptItems(layoutData->items.size()); for (int i = 0; i < layoutData->items.size(); ++i) { - const QScriptItem &si = layoutData->items[i]; + const QScriptItem &si = layoutData->items.at(i); scriptItems[i].position = si.position; scriptItems[i].script = si.analysis.script; } @@ -1944,14 +1944,14 @@ const QCharAttributes *QTextEngine::attributes() const void QTextEngine::shape(int item) const { - if (layoutData->items[item].analysis.flags == QScriptAnalysis::Object) { + if (layoutData->items.at(item).analysis.flags == QScriptAnalysis::Object) { ensureSpace(1); if (block.docHandle()) { docLayout()->resizeInlineObject(QTextInlineObject(item, const_cast<QTextEngine *>(this)), layoutData->items[item].position + block.position(), format(&layoutData->items[item])); } - } else if (layoutData->items[item].analysis.flags == QScriptAnalysis::Tab) { + } else if (layoutData->items.at(item).analysis.flags == QScriptAnalysis::Tab) { // set up at least the ascent/descent/leading of the script item for the tab fontEngine(layoutData->items[item], &layoutData->items[item].ascent, @@ -2193,9 +2193,9 @@ int QTextEngine::findItem(int strPos, int firstItem) const int right = layoutData->items.size()-1; while(left <= right) { int middle = ((right-left)/2)+left; - if (strPos > layoutData->items[middle].position) + if (strPos > layoutData->items.at(middle).position) left = middle+1; - else if(strPos < layoutData->items[middle].position) + else if (strPos < layoutData->items.at(middle).position) right = middle-1; else { return middle; @@ -2587,7 +2587,7 @@ void QTextEngine::justify(const QScriptLine &line) int end = line.from + (int)line.length + line.trailingSpaces; if (end == layoutData->string.length()) return; // no justification at end of paragraph - if (end && layoutData->items[findItem(end-1)].analysis.flags == QScriptAnalysis::LineOrParagraphSeparator) + if (end && layoutData->items.at(findItem(end - 1)).analysis.flags == QScriptAnalysis::LineOrParagraphSeparator) return; // no justification at the end of an explicitly separated line } @@ -2621,13 +2621,13 @@ void QTextEngine::justify(const QScriptLine &line) // store pointers to the glyph data that could get reallocated by the shaping // process. for (int i = 0; i < nItems; ++i) { - QScriptItem &si = layoutData->items[firstItem + i]; + const QScriptItem &si = layoutData->items.at(firstItem + i); if (!si.num_glyphs) shape(firstItem + i); } for (int i = 0; i < nItems; ++i) { - QScriptItem &si = layoutData->items[firstItem + i]; + const QScriptItem &si = layoutData->items.at(firstItem + i); int kashida_type = Justification_Arabic_Normal; int kashida_pos = -1; @@ -2923,7 +2923,7 @@ int QTextEngine::formatIndex(const QScriptItem *si) const if (specialData && !specialData->resolvedFormats.isEmpty()) { QTextFormatCollection *collection = formatCollection(); Q_ASSERT(collection); - return collection->indexForFormat(specialData->resolvedFormats.at(si - &layoutData->items[0])); + return collection->indexForFormat(specialData->resolvedFormats.at(si - &layoutData->items.at(0))); } QTextDocumentPrivate *p = block.docHandle(); @@ -3129,7 +3129,7 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int if (!attributes) return QString(); for (int i = 0; i < layoutData->items.size(); ++i) { - QScriptItem &si = layoutData->items[i]; + const QScriptItem &si = layoutData->items.at(i); if (!si.num_glyphs) shape(i); @@ -3314,24 +3314,29 @@ QFixed QTextEngine::calculateTabWidth(int item, QFixed x) const QList<QTextOption::Tab> tabArray = option.tabs(); if (!tabArray.isEmpty()) { if (isRightToLeft()) { // rebase the tabArray positions. - QList<QTextOption::Tab> newTabs; - newTabs.reserve(tabArray.count()); - QList<QTextOption::Tab>::Iterator iter = tabArray.begin(); - while(iter != tabArray.end()) { - QTextOption::Tab tab = *iter; - if (tab.type == QTextOption::LeftTab) - tab.type = QTextOption::RightTab; - else if (tab.type == QTextOption::RightTab) - tab.type = QTextOption::LeftTab; - newTabs << tab; - ++iter; - } - tabArray = newTabs; - } - for (int i = 0; i < tabArray.size(); ++i) { - QFixed tab = QFixed::fromReal(tabArray[i].position) * dpiScale; + auto isLeftOrRightTab = [](const QTextOption::Tab &tab) { + return tab.type == QTextOption::LeftTab || tab.type == QTextOption::RightTab; + }; + const auto cbegin = tabArray.cbegin(); + const auto cend = tabArray.cend(); + const auto cit = std::find_if(cbegin, cend, isLeftOrRightTab); + if (cit != cend) { + const int index = std::distance(cbegin, cit); + auto iter = tabArray.begin() + index; + const auto end = tabArray.end(); + while (iter != end) { + QTextOption::Tab &tab = *iter; + if (tab.type == QTextOption::LeftTab) + tab.type = QTextOption::RightTab; + else if (tab.type == QTextOption::RightTab) + tab.type = QTextOption::LeftTab; + ++iter; + } + } + } + for (const QTextOption::Tab &tabSpec : qAsConst(tabArray)) { + QFixed tab = QFixed::fromReal(tabSpec.position) * dpiScale; if (tab > x) { // this is the tab we need. - QTextOption::Tab tabSpec = tabArray[i]; int tabSectionEnd = layoutData->string.count(); if (tabSpec.type == QTextOption::RightTab || tabSpec.type == QTextOption::CenterTab) { // find next tab to calculate the width required. @@ -3352,7 +3357,7 @@ QFixed QTextEngine::calculateTabWidth(int item, QFixed x) const QFixed length; // Calculate the length of text between this tab and the tabSectionEnd for (int i=item; i < layoutData->items.count(); i++) { - QScriptItem &item = layoutData->items[i]; + const QScriptItem &item = layoutData->items.at(i); if (item.position > tabSectionEnd || item.position <= si.position) continue; shape(i); // first, lets make sure relevant text is already shaped @@ -3652,11 +3657,12 @@ int QTextEngine::lineNumberForTextPosition(int pos) return -1; } -void QTextEngine::insertionPointsForLine(int lineNum, QVector<int> &insertionPoints) +std::vector<int> QTextEngine::insertionPointsForLine(int lineNum) { QTextLineItemIterator iterator(this, lineNum); - insertionPoints.reserve(iterator.line.length); + std::vector<int> insertionPoints; + insertionPoints.reserve(size_t(iterator.line.length)); bool lastLine = lineNum >= lines.size() - 1; @@ -3674,25 +3680,22 @@ void QTextEngine::insertionPointsForLine(int lineNum, QVector<int> &insertionPoi insertionPoints.push_back(i); } } + return insertionPoints; } int QTextEngine::endOfLine(int lineNum) { - QVector<int> insertionPoints; - insertionPointsForLine(lineNum, insertionPoints); - + const auto insertionPoints = insertionPointsForLine(lineNum); if (insertionPoints.size() > 0) - return insertionPoints.constLast(); + return insertionPoints.back(); return 0; } int QTextEngine::beginningOfLine(int lineNum) { - QVector<int> insertionPoints; - insertionPointsForLine(lineNum, insertionPoints); - + const auto insertionPoints = insertionPointsForLine(lineNum); if (insertionPoints.size() > 0) - return insertionPoints.constFirst(); + return insertionPoints.front(); return 0; } @@ -3709,10 +3712,8 @@ int QTextEngine::positionAfterVisualMovement(int pos, QTextCursor::MoveOperation if (lineNum < 0) return pos; - QVector<int> insertionPoints; - insertionPointsForLine(lineNum, insertionPoints); - int i, max = insertionPoints.size(); - for (i = 0; i < max; i++) + const auto insertionPoints = insertionPointsForLine(lineNum); + for (size_t i = 0, max = insertionPoints.size(); i < max; ++i) if (pos == insertionPoints[i]) { if (moveRight) { if (i + 1 < max) @@ -3990,7 +3991,7 @@ QTextLineItemIterator::QTextLineItemIterator(QTextEngine *_eng, int _lineNum, co QVarLengthArray<uchar> levels(nItems); for (int i = 0; i < nItems; ++i) - levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel; + levels[i] = eng->layoutData->items.at(i + firstItem).analysis.bidiLevel; QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); eng->shapeLine(line); diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index f9eb055478..42061deff5 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -74,6 +74,7 @@ #include <private/qunicodetools_p.h> #include <stdlib.h> +#include <vector> QT_BEGIN_NAMESPACE @@ -632,7 +633,7 @@ public: int nextLogicalPosition(int oldPos) const; int lineNumberForTextPosition(int pos); int positionAfterVisualMovement(int oldPos, QTextCursor::MoveOperation op); - void insertionPointsForLine(int lineNum, QVector<int> &insertionPoints); + std::vector<int> insertionPointsForLine(int lineNum); void resetFontEngineCache(); void enableDelayDecorations(bool enable = true) { delayDecorations = enable; } diff --git a/src/gui/text/qtextformat.h b/src/gui/text/qtextformat.h index 28c3035537..8f8d3d4299 100644 --- a/src/gui/text/qtextformat.h +++ b/src/gui/text/qtextformat.h @@ -175,6 +175,7 @@ public: LineHeightType = 0x1049, BlockNonBreakableLines = 0x1050, BlockTrailingHorizontalRulerWidth = 0x1060, + HeadingLevel = 0x1070, // character properties FirstFontProperty = 0x1FE0, @@ -624,6 +625,11 @@ public: inline int indent() const { return intProperty(BlockIndent); } + inline void setHeadingLevel(int alevel) + { setProperty(HeadingLevel, alevel); } + inline int headingLevel() const + { return intProperty(HeadingLevel); } + inline void setLineHeight(qreal height, int heightType) { setProperty(LineHeight, height); setProperty(LineHeightType, heightType); } inline qreal lineHeight(qreal scriptLineHeight, qreal scaling) const; diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp index 9154182df1..4be800b251 100644 --- a/src/gui/text/qtexthtmlparser.cpp +++ b/src/gui/text/qtexthtmlparser.cpp @@ -448,13 +448,6 @@ static const QTextHtmlElement elements[Html_NumElements]= { { "var", Html_var, QTextHtmlElement::DisplayInline }, }; -#if defined(Q_CC_MSVC) && _MSC_VER < 1600 -static bool operator<(const QTextHtmlElement &e1, const QTextHtmlElement &e2) -{ - return QLatin1String(e1.name) < QLatin1String(e2.name); -} -#endif - static bool operator<(const QString &str, const QTextHtmlElement &e) { return str < QLatin1String(e.name); diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 6e824b2ed1..cd1990dfb9 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -1006,10 +1006,8 @@ static void addSelectedRegionsToPath(QTextEngine *eng, int lineNumber, const QPo } if (lastSelectionWidth > 0) { - QRectF rect = boundingRect & QRectF(lastSelectionX.toReal(), selectionY, lastSelectionWidth.toReal(), lineHeight); - rect.moveLeft(qFloor(rect.left())); - rect.moveTop(qFloor(rect.top())); - region->addRect(rect); + const QRectF rect = boundingRect & QRectF(lastSelectionX.toReal(), selectionY, lastSelectionWidth.toReal(), lineHeight); + region->addRect(rect.toAlignedRect()); } lastSelectionX = selectionX; @@ -1017,10 +1015,8 @@ static void addSelectedRegionsToPath(QTextEngine *eng, int lineNumber, const QPo } } if (lastSelectionWidth > 0) { - QRectF rect = boundingRect & QRectF(lastSelectionX.toReal(), selectionY, lastSelectionWidth.toReal(), lineHeight); - rect.moveLeft(qFloor(rect.left())); - rect.moveTop(qFloor(rect.top())); - region->addRect(rect); + const QRectF rect = boundingRect & QRectF(lastSelectionX.toReal(), selectionY, lastSelectionWidth.toReal(), lineHeight); + region->addRect(rect.toAlignedRect()); } } @@ -2135,7 +2131,7 @@ static void setPenAndDrawBackground(QPainter *p, const QPen &defaultPen, const Q QBrush bg = chf.background(); if (bg.style() != Qt::NoBrush && !chf.property(SuppressBackground).toBool()) - p->fillRect(QRectF(qFloor(r.x()), qFloor(r.y()), r.width(), r.height()), bg); + p->fillRect(r.toAlignedRect(), bg); if (c.style() != Qt::NoBrush) { p->setPen(QPen(c, 0)); } @@ -2845,9 +2841,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const bool rtl = eng->isRightToLeft(); eng->shapeLine(line); - QVector<int> insertionPoints; - if (visual && rtl) - eng->insertionPointsForLine(lineNum, insertionPoints); + const auto insertionPoints = (visual && rtl) ? eng->insertionPointsForLine(lineNum) : std::vector<int>(); int nchars = 0; for (int i = 0; i < nItems; ++i) { int item = visualOrder[i]+firstItem; @@ -2979,7 +2973,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const continue; } if (rtl && nchars > 0) - return insertionPoints[lastLine ? nchars : nchars - 1]; + return insertionPoints[size_t(lastLine ? nchars : nchars - 1)]; } return eng->positionInLigature(&si, end, x, pos, -1, cpos == QTextLine::CursorOnCharacter); |