diff options
Diffstat (limited to 'src/gui/image')
33 files changed, 559 insertions, 267 deletions
diff --git a/src/gui/image/qbitmap.h b/src/gui/image/qbitmap.h index def59b3f89..6a8c8b3457 100644 --- a/src/gui/image/qbitmap.h +++ b/src/gui/image/qbitmap.h @@ -55,7 +55,7 @@ public: QBitmap(const QPixmap &); QBitmap(int w, int h); explicit QBitmap(const QSize &); - explicit QBitmap(const QString &fileName, const char *format = Q_NULLPTR); + explicit QBitmap(const QString &fileName, const char *format = nullptr); // ### Qt 6: don't inherit QPixmap #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QBitmap(const QBitmap &other) : QPixmap(other) {} diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index 703c5c0f31..587f375ce7 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -49,10 +49,10 @@ QT_BEGIN_NAMESPACE static void swapPixel01(QImage *image) // 1-bpp: swap 0 and 1 pixels { - int i; + qsizetype i; if (image->depth() == 1 && image->colorCount() == 2) { uint *p = (uint *)image->bits(); - int nbytes = image->byteCount(); + qsizetype nbytes = static_cast<qsizetype>(image->sizeInBytes()); for (i=0; i<nbytes/4; i++) { *p = ~*p; p++; diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index fa4b4e01af..32fa9e75ac 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -1158,6 +1158,36 @@ QStringList QIcon::themeSearchPaths() } /*! + \since 5.11 + + Returns the fallback search paths for icons. + + The default value will depend on the platform. + + \sa setFallbackSearchPaths(), themeSearchPaths() +*/ +QStringList QIcon::fallbackSearchPaths() +{ + return QIconLoader::instance()->fallbackSearchPaths(); +} + +/*! + \since 5.11 + + Sets the fallback search paths for icons to \a paths. + + \note To add some path without replacing existing ones: + + \snippet code/src_gui_image_qicon.cpp 5 + + \sa fallbackSearchPaths(), setThemeSearchPaths() +*/ +void QIcon::setFallbackSearchPaths(const QStringList &paths) +{ + QIconLoader::instance()->setFallbackSearchPaths(paths); +} + +/*! \since 4.6 Sets the current icon theme to \a name. @@ -1216,7 +1246,10 @@ QString QIcon::themeName() the lookup. These caches can be generated using gtk-update-icon-cache: \l{https://developer.gnome.org/gtk3/stable/gtk-update-icon-cache.html}. - \sa themeName(), setThemeName(), themeSearchPaths() + \note If an icon can't be found in the current theme, then it will be + searched in fallbackSearchPaths() as an unthemed icon. + + \sa themeName(), setThemeName(), themeSearchPaths(), fallbackSearchPaths() */ QIcon QIcon::fromTheme(const QString &name) { @@ -1469,8 +1502,13 @@ QString qt_findAtNxFile(const QString &baseFileName, qreal targetDevicePixelRati return baseFileName; int dotIndex = baseFileName.lastIndexOf(QLatin1Char('.')); - if (dotIndex == -1) /* no dot */ + if (dotIndex == -1) { /* no dot */ dotIndex = baseFileName.size(); /* append */ + } else if (dotIndex >= 2 && baseFileName[dotIndex - 1] == QLatin1Char('9') + && baseFileName[dotIndex - 2] == QLatin1Char('.')) { + // If the file has a .9.* (9-patch image) extension, we must ensure that the @nx goes before it. + dotIndex -= 2; + } QString atNxfileName = baseFileName; atNxfileName.insert(dotIndex, QLatin1String("@2x")); diff --git a/src/gui/image/qicon.h b/src/gui/image/qicon.h index 40d3e92af9..653ba6fda4 100644 --- a/src/gui/image/qicon.h +++ b/src/gui/image/qicon.h @@ -63,7 +63,7 @@ public: #ifdef Q_COMPILER_RVALUE_REFS QIcon(QIcon &&other) Q_DECL_NOEXCEPT : d(other.d) - { other.d = Q_NULLPTR; } + { other.d = nullptr; } #endif explicit QIcon(const QString &fileName); // file or resource name explicit QIcon(QIconEngine *engine); @@ -118,6 +118,9 @@ public: static QStringList themeSearchPaths(); static void setThemeSearchPaths(const QStringList &searchpath); + static QStringList fallbackSearchPaths(); + static void setFallbackSearchPaths(const QStringList &paths); + static QString themeName(); static void setThemeName(const QString &path); @@ -147,7 +150,7 @@ Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QIcon &); #endif Q_GUI_EXPORT QString qt_findAtNxFile(const QString &baseFileName, qreal targetDevicePixelRatio, - qreal *sourceDevicePixelRatio = Q_NULLPTR); + qreal *sourceDevicePixelRatio = nullptr); QT_END_NAMESPACE diff --git a/src/gui/image/qicon_p.h b/src/gui/image/qicon_p.h index aa358e88af..e384ff9e49 100644 --- a/src/gui/image/qicon_p.h +++ b/src/gui/image/qicon_p.h @@ -112,18 +112,18 @@ public: QPixmapIconEngine(); QPixmapIconEngine(const QPixmapIconEngine &); ~QPixmapIconEngine(); - void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE; - QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE; + void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override; + QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override; QPixmapIconEngineEntry *bestMatch(const QSize &size, QIcon::Mode mode, QIcon::State state, bool sizeOnly); - QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE; - void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE; - void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE; - - QString key() const Q_DECL_OVERRIDE; - QIconEngine *clone() const Q_DECL_OVERRIDE; - bool read(QDataStream &in) Q_DECL_OVERRIDE; - bool write(QDataStream &out) const Q_DECL_OVERRIDE; - void virtual_hook(int id, void *data) Q_DECL_OVERRIDE; + QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override; + void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state) override; + void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state) override; + + QString key() const override; + QIconEngine *clone() const override; + bool read(QDataStream &in) override; + bool write(QDataStream &out) const override; + void virtual_hook(int id, void *data) override; private: QPixmapIconEngineEntry *tryMatch(const QSize &size, QIcon::Mode mode, QIcon::State state); diff --git a/src/gui/image/qiconengineplugin.h b/src/gui/image/qiconengineplugin.h index 7a01d3731c..f2a1c0107a 100644 --- a/src/gui/image/qiconengineplugin.h +++ b/src/gui/image/qiconengineplugin.h @@ -55,7 +55,7 @@ class Q_GUI_EXPORT QIconEnginePlugin : public QObject { Q_OBJECT public: - QIconEnginePlugin(QObject *parent = Q_NULLPTR); + QIconEnginePlugin(QObject *parent = nullptr); ~QIconEnginePlugin(); virtual QIconEngine *create(const QString &filename = QString()) = 0; diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp index 349e0dfbe3..1ea4f1340b 100644 --- a/src/gui/image/qiconloader.cpp +++ b/src/gui/image/qiconloader.cpp @@ -95,6 +95,16 @@ static inline QStringList systemIconSearchPaths() return QStringList(); } +static inline QStringList systemFallbackSearchPaths() +{ + if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) { + const QVariant themeHint = theme->themeHint(QPlatformTheme::IconFallbackSearchPaths); + if (themeHint.isValid()) + return themeHint.toStringList(); + } + return QStringList(); +} + extern QFactoryLoader *qt_iconEngineFactoryLoader(); // qicon.cpp void QIconLoader::ensureInitialized() @@ -158,6 +168,20 @@ QStringList QIconLoader::themeSearchPaths() const return m_iconDirs; } +void QIconLoader::setFallbackSearchPaths(const QStringList &searchPaths) +{ + m_fallbackDirs = searchPaths; + invalidateKey(); +} + +QStringList QIconLoader::fallbackSearchPaths() const +{ + if (m_fallbackDirs.isEmpty()) { + m_fallbackDirs = systemFallbackSearchPaths(); + } + return m_fallbackDirs; +} + /*! \internal Helper class that reads and looks up into the icon-theme.cache generated with @@ -481,11 +505,54 @@ QThemeIconInfo QIconLoader::findIconHelper(const QString &themeName, return info; } +QThemeIconInfo QIconLoader::lookupFallbackIcon(const QString &iconName) const +{ + QThemeIconInfo info; + + const QString pngIconName = iconName + QLatin1String(".png"); + const QString xpmIconName = iconName + QLatin1String(".xpm"); + const QString svgIconName = iconName + QLatin1String(".svg"); + + const auto searchPaths = QIcon::fallbackSearchPaths(); + for (const QString &iconDir: searchPaths) { + QDir currentDir(iconDir); + if (currentDir.exists(pngIconName)) { + PixmapEntry *iconEntry = new PixmapEntry; + iconEntry->dir.type = QIconDirInfo::Fallback; + iconEntry->filename = currentDir.filePath(pngIconName); + info.entries.append(iconEntry); + break; + } else if (currentDir.exists(xpmIconName)) { + PixmapEntry *iconEntry = new PixmapEntry; + iconEntry->dir.type = QIconDirInfo::Fallback; + iconEntry->filename = currentDir.filePath(xpmIconName); + info.entries.append(iconEntry); + break; + } else if (m_supportsSvg && + currentDir.exists(svgIconName)) { + ScalableEntry *iconEntry = new ScalableEntry; + iconEntry->dir.type = QIconDirInfo::Fallback; + iconEntry->filename = currentDir.filePath(svgIconName); + info.entries.append(iconEntry); + break; + } + } + + if (!info.entries.isEmpty()) + info.iconName = iconName; + + return info; +} + QThemeIconInfo QIconLoader::loadIcon(const QString &name) const { if (!themeName().isEmpty()) { QStringList visited; - return findIconHelper(themeName(), name, visited); + const QThemeIconInfo iconInfo = findIconHelper(themeName(), name, visited); + if (!iconInfo.entries.isEmpty()) + return iconInfo; + + return lookupFallbackIcon(name); } return QThemeIconInfo(); @@ -573,6 +640,8 @@ static bool directoryMatchesSize(const QIconDirInfo &dir, int iconsize, int icon } else if (dir.type == QIconDirInfo::Threshold) { return iconsize >= dir.size - dir.threshold && iconsize <= dir.size + dir.threshold; + } else if (dir.type == QIconDirInfo::Fallback) { + return true; } Q_ASSERT(1); // Not a valid value @@ -603,24 +672,26 @@ static int directorySizeDistance(const QIconDirInfo &dir, int iconsize, int icon else if (scaledIconSize > (dir.size + dir.threshold) * dir.scale) return scaledIconSize - dir.maxSize * dir.scale; else return 0; + } else if (dir.type == QIconDirInfo::Fallback) { + return 0; } Q_ASSERT(1); // Not a valid value return INT_MAX; } -QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size, int scale) +QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QThemeIconInfo &info, const QSize &size, int scale) { int iconsize = qMin(size.width(), size.height()); // Note that m_info.entries are sorted so that png-files // come first - const int numEntries = m_info.entries.size(); + const int numEntries = info.entries.size(); // Search for exact matches first for (int i = 0; i < numEntries; ++i) { - QIconLoaderEngineEntry *entry = m_info.entries.at(i); + QIconLoaderEngineEntry *entry = info.entries.at(i); if (directoryMatchesSize(entry->dir, iconsize, scale)) { return entry; } @@ -630,7 +701,7 @@ QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size, int s int minimalSize = INT_MAX; QIconLoaderEngineEntry *closestMatch = 0; for (int i = 0; i < numEntries; ++i) { - QIconLoaderEngineEntry *entry = m_info.entries.at(i); + QIconLoaderEngineEntry *entry = info.entries.at(i); int distance = directorySizeDistance(entry->dir, iconsize, scale); if (distance < minimalSize) { minimalSize = distance; @@ -654,12 +725,14 @@ QSize QIconLoaderEngine::actualSize(const QSize &size, QIcon::Mode mode, ensureLoaded(); - QIconLoaderEngineEntry *entry = entryForSize(size); + QIconLoaderEngineEntry *entry = entryForSize(m_info, size); if (entry) { const QIconDirInfo &dir = entry->dir; - if (dir.type == QIconDirInfo::Scalable) + if (dir.type == QIconDirInfo::Scalable) { return size; - else { + } else if (dir.type == QIconDirInfo::Fallback) { + return QIcon(entry->filename).actualSize(size, mode, state); + } else { int result = qMin<int>(dir.size, qMin(size.width(), size.height())); return QSize(result, result); } @@ -718,7 +791,7 @@ QPixmap QIconLoaderEngine::pixmap(const QSize &size, QIcon::Mode mode, { ensureLoaded(); - QIconLoaderEngineEntry *entry = entryForSize(size); + QIconLoaderEngineEntry *entry = entryForSize(m_info, size); if (entry) return entry->pixmap(size, mode, state); @@ -745,8 +818,13 @@ void QIconLoaderEngine::virtual_hook(int id, void *data) // Gets all sizes from the DirectoryInfo entries for (int i = 0; i < N; ++i) { - int size = m_info.entries.at(i)->dir.size; - sizes.append(QSize(size, size)); + const QIconLoaderEngineEntry *entry = m_info.entries.at(i); + if (entry->dir.type == QIconDirInfo::Fallback) { + sizes.append(QIcon(entry->filename).availableSizes()); + } else { + int size = entry->dir.size; + sizes.append(QSize(size, size)); + } } arg.sizes.swap(sizes); // commit } @@ -767,7 +845,7 @@ void QIconLoaderEngine::virtual_hook(int id, void *data) QIconEngine::ScaledPixmapArgument &arg = *reinterpret_cast<QIconEngine::ScaledPixmapArgument*>(data); // QIcon::pixmap() multiplies size by the device pixel ratio. const int integerScale = qCeil(arg.scale); - QIconLoaderEngineEntry *entry = entryForSize(arg.size / integerScale, integerScale); + QIconLoaderEngineEntry *entry = entryForSize(m_info, arg.size / integerScale, integerScale); arg.pixmap = entry ? entry->pixmap(arg.size, arg.mode, arg.state) : QPixmap(); } break; diff --git a/src/gui/image/qiconloader_p.h b/src/gui/image/qiconloader_p.h index 5f3a3ef948..746e871fb1 100644 --- a/src/gui/image/qiconloader_p.h +++ b/src/gui/image/qiconloader_p.h @@ -69,7 +69,7 @@ class QIconLoader; struct QIconDirInfo { - enum Type { Fixed, Scalable, Threshold }; + enum Type { Fixed, Scalable, Threshold, Fallback }; QIconDirInfo(const QString &_path = QString()) : path(_path), size(0), @@ -101,13 +101,13 @@ public: struct ScalableEntry : public QIconLoaderEngineEntry { - QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE; + QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override; QIcon svgIcon; }; struct PixmapEntry : public QIconLoaderEngineEntry { - QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE; + QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override; QPixmap basePixmap; }; @@ -125,19 +125,20 @@ public: QIconLoaderEngine(const QString& iconName = QString()); ~QIconLoaderEngine(); - void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE; - QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE; - QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE; - QIconEngine *clone() const Q_DECL_OVERRIDE; - bool read(QDataStream &in) Q_DECL_OVERRIDE; - bool write(QDataStream &out) const Q_DECL_OVERRIDE; + void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override; + QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override; + QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override; + QIconEngine *clone() const override; + bool read(QDataStream &in) override; + bool write(QDataStream &out) const override; + + Q_GUI_EXPORT static QIconLoaderEngineEntry *entryForSize(const QThemeIconInfo &info, const QSize &size, int scale = 1); private: - QString key() const Q_DECL_OVERRIDE; + QString key() const override; bool hasIcon() const; void ensureLoaded(); - void virtual_hook(int id, void *data) Q_DECL_OVERRIDE; - QIconLoaderEngineEntry *entryForSize(const QSize &size, int scale = 1); + void virtual_hook(int id, void *data) override; QIconLoaderEngine(const QIconLoaderEngine &other); QThemeIconInfo m_info; @@ -179,6 +180,8 @@ public: QIconTheme theme() { return themeList.value(themeName()); } void setThemeSearchPath(const QStringList &searchPaths); QStringList themeSearchPaths() const; + void setFallbackSearchPaths(const QStringList &searchPaths); + QStringList fallbackSearchPaths() const; QIconDirInfo dirInfo(int dirindex); static QIconLoader *instance(); void updateSystemTheme(); @@ -190,6 +193,8 @@ private: QThemeIconInfo findIconHelper(const QString &themeName, const QString &iconName, QStringList &visited) const; + QThemeIconInfo lookupFallbackIcon(const QString &iconName) const; + uint m_themeKey; bool m_supportsSvg; bool m_initialized; @@ -198,6 +203,7 @@ private: mutable QString m_systemTheme; mutable QStringList m_iconDirs; mutable QHash <QString, QIconTheme> themeList; + mutable QStringList m_fallbackDirs; }; QT_END_NAMESPACE diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index bd10012bf6..7fcae12cbd 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -127,11 +127,11 @@ QImageData * QImageData::create(const QSize &size, QImage::Format format) const int bytes_per_line = ((width * depth + 31) >> 5) << 2; // bytes per scanline (must be multiple of 4) // sanity check for potential overflows - if (INT_MAX/depth < width + if (std::numeric_limits<int>::max()/depth < width || bytes_per_line <= 0 || height <= 0 - || INT_MAX/uint(bytes_per_line) < height - || INT_MAX/sizeof(uchar *) < uint(height)) + || std::numeric_limits<qsizetype>::max()/uint(bytes_per_line) < height + || std::numeric_limits<int>::max()/sizeof(uchar *) < uint(height)) return 0; QScopedPointer<QImageData> d(new QImageData); @@ -452,7 +452,7 @@ bool QImageData::checkForAlphaPixels() const used. For more information see the \l {QImage#Image Formats}{Image Formats} section. - The format(), bytesPerLine(), and byteCount() functions provide + The format(), bytesPerLine(), and sizeInBytes() functions provide low-level information about the data stored in the image. The cacheKey() function returns a number that uniquely @@ -1449,26 +1449,43 @@ void QImage::setDevicePixelRatio(qreal scaleFactor) /*! \since 4.6 + \obsolete Returns the number of bytes occupied by the image data. - \sa bytesPerLine(), bits(), {QImage#Image Information}{Image + Note this method should never be called on an image larger than 2 gigabytes. + Instead use sizeInBytes(). + + \sa sizeInBytes(), bytesPerLine(), bits(), {QImage#Image Information}{Image Information} */ int QImage::byteCount() const { + Q_ASSERT(!d || d->nbytes < std::numeric_limits<int>::max()); + return d ? int(d->nbytes) : 0; +} + +/*! + \since 5.10 + Returns the image data size in bytes. + + \sa byteCount(), bytesPerLine(), bits(), {QImage#Image Information}{Image + Information} +*/ +qsizetype QImage::sizeInBytes() const +{ return d ? d->nbytes : 0; } /*! Returns the number of bytes per image scanline. - This is equivalent to byteCount() / height(). + This is equivalent to sizeInBytes() / height() if height() is non-zero. \sa scanLine() */ int QImage::bytesPerLine() const { - return (d && d->height) ? d->nbytes / d->height : 0; + return d ? d->bytes_per_line : 0; } @@ -1595,7 +1612,7 @@ const uchar *QImage::constScanLine(int i) const data, thus ensuring that this QImage is the only one using the current return value. - \sa scanLine(), byteCount(), constBits() + \sa scanLine(), sizeInBytes(), constBits() */ uchar *QImage::bits() { @@ -1959,7 +1976,8 @@ QImage::Format QImage::format() const } /*! - \fn QImage QImage::convertToFormat(Format format, Qt::ImageConversionFlags flags) const + \fn QImage QImage::convertToFormat(Format format, Qt::ImageConversionFlags flags) const & + \fn QImage QImage::convertToFormat(Format format, Qt::ImageConversionFlags flags) && Returns a copy of the image in the given \a format. @@ -2117,8 +2135,8 @@ QImage QImage::convertToFormat(Format format, const QVector<QRgb> &colorTable, Q /*! \since 5.9 - Changes the \a format of the image without changing the data. Only - works between formats of the same depth. + Changes the format of the image to \a format without changing the + data. Only works between formats of the same depth. Returns \c true if successful. @@ -2971,7 +2989,9 @@ QImage QImage::createMaskFromColor(QRgb color, Qt::MaskMode mode) const } /*! - \fn QImage QImage::mirrored(bool horizontal = false, bool vertical = true) const + \fn QImage QImage::mirrored(bool horizontal = false, bool vertical = true) const & + \fn QImage QImage::mirrored(bool horizontal = false, bool vertical = true) && + Returns a mirror of the image, mirrored in the horizontal and/or the vertical direction depending on whether \a horizontal and \a vertical are set to true or false. @@ -3176,7 +3196,9 @@ void QImage::mirrored_inplace(bool horizontal, bool vertical) } /*! - \fn QImage QImage::rgbSwapped() const + \fn QImage QImage::rgbSwapped() const & + \fn QImage QImage::rgbSwapped() && + Returns a QImage in which the values of the red and blue components of all pixels have been swapped, effectively converting an RGB image to an BGR image. @@ -3245,14 +3267,31 @@ QImage QImage::rgbSwapped_helper() const res.d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00)); } break; - case Format_RGB32: - case Format_ARGB32: - case Format_ARGB32_Premultiplied: -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN case Format_RGBX8888: case Format_RGBA8888: case Format_RGBA8888_Premultiplied: +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + res = QImage(d->width, d->height, d->format); + QIMAGE_SANITYCHECK_MEMORY(res); + for (int i = 0; i < d->height; i++) { + uint *q = (uint*)res.scanLine(i); + const uint *p = (const uint*)constScanLine(i); + const uint *end = p + d->width; + while (p < end) { + uint c = *p; + *q = ((c << 16) & 0xff000000) | ((c >> 16) & 0xff00) | (c & 0x00ff00ff); + p++; + q++; + } + } + break; +#else + // On little-endian rgba8888 is abgr32 and can use same rgb-swap as argb32 + Q_FALLTHROUGH(); #endif + case Format_RGB32: + case Format_ARGB32: + case Format_ARGB32_Premultiplied: res = QImage(d->width, d->height, d->format); QIMAGE_SANITYCHECK_MEMORY(res); for (int i = 0; i < d->height; i++) { @@ -3336,14 +3375,27 @@ void QImage::rgbSwapped_inplace() d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00)); } break; - case Format_RGB32: - case Format_ARGB32: - case Format_ARGB32_Premultiplied: -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN case Format_RGBX8888: case Format_RGBA8888: case Format_RGBA8888_Premultiplied: +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + for (int i = 0; i < d->height; i++) { + uint *p = (uint*)scanLine(i); + uint *end = p + d->width; + while (p < end) { + uint c = *p; + *p = ((c << 16) & 0xff000000) | ((c >> 16) & 0xff00) | (c & 0x00ff00ff); + p++; + } + } + break; +#else + // On little-endian rgba8888 is abgr32 and can use same rgb-swap as argb32 + Q_FALLTHROUGH(); #endif + case Format_RGB32: + case Format_ARGB32: + case Format_ARGB32_Premultiplied: for (int i = 0; i < d->height; i++) { uint *p = (uint*)scanLine(i); uint *end = p + d->width; @@ -4662,12 +4714,12 @@ QImage QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode if (dImage.d->colortable.size() < 256) { // colors are left in the color table, so pick that one as transparent dImage.d->colortable.append(0x0); - memset(dImage.bits(), dImage.d->colortable.size() - 1, dImage.byteCount()); + memset(dImage.bits(), dImage.d->colortable.size() - 1, dImage.d->nbytes); } else { - memset(dImage.bits(), 0, dImage.byteCount()); + memset(dImage.bits(), 0, dImage.d->nbytes); } } else - memset(dImage.bits(), 0x00, dImage.byteCount()); + memset(dImage.bits(), 0x00, dImage.d->nbytes); if (target_format >= QImage::Format_RGB32) { // Prevent QPainter from applying devicePixelRatio corrections @@ -4762,8 +4814,8 @@ bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFla QDebug operator<<(QDebug dbg, const QImage &i) { QDebugStateSaver saver(dbg); - dbg.resetFormat(); dbg.nospace(); + dbg.noquote(); dbg << "QImage("; if (i.isNull()) { dbg << "null"; @@ -4771,8 +4823,15 @@ QDebug operator<<(QDebug dbg, const QImage &i) dbg << i.size() << ",format=" << i.format() << ",depth=" << i.depth(); if (i.colorCount()) dbg << ",colorCount=" << i.colorCount(); + const int bytesPerLine = i.bytesPerLine(); dbg << ",devicePixelRatio=" << i.devicePixelRatio() - << ",bytesPerLine=" << i.bytesPerLine() << ",byteCount=" << i.byteCount(); + << ",bytesPerLine=" << bytesPerLine << ",sizeInBytes=" << i.sizeInBytes(); + if (dbg.verbosity() > 2 && i.height() > 0) { + const int outputLength = qMin(bytesPerLine, 24); + dbg << ",line0=" + << QByteArray(reinterpret_cast<const char *>(i.scanLine(0)), outputLength).toHex() + << "..."; + } } dbg << ')'; return dbg; @@ -4794,7 +4853,7 @@ QDebug operator<<(QDebug dbg, const QImage &i) Returns the number of bytes occupied by the image data. - \sa byteCount() + \sa sizeInBytes() */ /*! diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index 225ef3d2e8..9b76b62f24 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -136,20 +136,20 @@ public: QImage() Q_DECL_NOEXCEPT; QImage(const QSize &size, Format format); QImage(int width, int height, Format format); - QImage(uchar *data, int width, int height, Format format, QImageCleanupFunction cleanupFunction = Q_NULLPTR, void *cleanupInfo = Q_NULLPTR); - QImage(const uchar *data, int width, int height, Format format, QImageCleanupFunction cleanupFunction = Q_NULLPTR, void *cleanupInfo = Q_NULLPTR); - QImage(uchar *data, int width, int height, int bytesPerLine, Format format, QImageCleanupFunction cleanupFunction = Q_NULLPTR, void *cleanupInfo = Q_NULLPTR); - QImage(const uchar *data, int width, int height, int bytesPerLine, Format format, QImageCleanupFunction cleanupFunction = Q_NULLPTR, void *cleanupInfo = Q_NULLPTR); + QImage(uchar *data, int width, int height, Format format, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr); + QImage(const uchar *data, int width, int height, Format format, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr); + QImage(uchar *data, int width, int height, int bytesPerLine, Format format, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr); + QImage(const uchar *data, int width, int height, int bytesPerLine, Format format, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr); #ifndef QT_NO_IMAGEFORMAT_XPM explicit QImage(const char * const xpm[]); #endif - explicit QImage(const QString &fileName, const char *format = Q_NULLPTR); + explicit QImage(const QString &fileName, const char *format = nullptr); QImage(const QImage &); #ifdef Q_COMPILER_RVALUE_REFS inline QImage(QImage &&other) Q_DECL_NOEXCEPT - : QPaintDevice(), d(Q_NULLPTR) + : QPaintDevice(), d(nullptr) { qSwap(d, other.d); } #endif ~QImage(); @@ -164,7 +164,7 @@ public: bool isNull() const; - int devType() const Q_DECL_OVERRIDE; + int devType() const override; bool operator==(const QImage &) const; bool operator!=(const QImage &) const; @@ -214,7 +214,10 @@ public: const uchar *bits() const; const uchar *constBits() const; - int byteCount() const; +#if QT_DEPRECATED_SINCE(5, 10) + QT_DEPRECATED_X("Use sizeInBytes") int byteCount() const; +#endif + qsizetype sizeInBytes() const; uchar *scanLine(int); const uchar *scanLine(int) const; @@ -291,16 +294,16 @@ public: bool load(QIODevice *device, const char* format); - bool load(const QString &fileName, const char *format = Q_NULLPTR); - bool loadFromData(const uchar *buf, int len, const char *format = Q_NULLPTR); - inline bool loadFromData(const QByteArray &data, const char *aformat = Q_NULLPTR) + bool load(const QString &fileName, const char *format = nullptr); + bool loadFromData(const uchar *buf, int len, const char *format = nullptr); + inline bool loadFromData(const QByteArray &data, const char *aformat = nullptr) { return loadFromData(reinterpret_cast<const uchar *>(data.constData()), data.size(), aformat); } - bool save(const QString &fileName, const char *format = Q_NULLPTR, int quality = -1) const; - bool save(QIODevice *device, const char *format = Q_NULLPTR, int quality = -1) const; + bool save(const QString &fileName, const char *format = nullptr, int quality = -1) const; + bool save(QIODevice *device, const char *format = nullptr, int quality = -1) const; - static QImage fromData(const uchar *data, int size, const char *format = Q_NULLPTR); - inline static QImage fromData(const QByteArray &data, const char *format = Q_NULLPTR) + static QImage fromData(const uchar *data, int size, const char *format = nullptr); + inline static QImage fromData(const QByteArray &data, const char *format = nullptr) { return fromData(reinterpret_cast<const uchar *>(data.constData()), data.size(), format); } #if QT_DEPRECATED_SINCE(5, 0) @@ -308,7 +311,7 @@ public: #endif qint64 cacheKey() const; - QPaintEngine *paintEngine() const Q_DECL_OVERRIDE; + QPaintEngine *paintEngine() const override; // Auxiliary data int dotsPerMeterX() const; @@ -332,7 +335,7 @@ public: #endif #if QT_DEPRECATED_SINCE(5, 0) - QT_DEPRECATED inline QString text(const char *key, const char *lang = Q_NULLPTR) const; + QT_DEPRECATED inline QString text(const char *key, const char *lang = nullptr) const; QT_DEPRECATED inline QList<QImageTextKeyLang> textList() const; QT_DEPRECATED inline QStringList textLanguages() const; QT_DEPRECATED inline QString text(const QImageTextKeyLang&) const; @@ -346,7 +349,7 @@ public: #endif protected: - virtual int metric(PaintDeviceMetric metric) const Q_DECL_OVERRIDE; + virtual int metric(PaintDeviceMetric metric) const override; QImage mirrored_helper(bool horizontal, bool vertical) const; QImage rgbSwapped_helper() const; void mirrored_inplace(bool horizontal, bool vertical); @@ -468,7 +471,7 @@ inline void QImage::setNumColors(int n) inline int QImage::numBytes() const { - return byteCount(); + return int(sizeInBytes()); } #endif diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 50fad1566c..4eef617336 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -40,6 +40,7 @@ #include <private/qdrawhelper_p.h> #include <private/qguiapplication_p.h> #include <private/qcolorprofile_p.h> +#include <private/qendian_p.h> #include <private/qsimd_p.h> #include <private/qimage_p.h> #include <qendian.h> @@ -126,8 +127,8 @@ static const uint *QT_FASTCALL convertRGB32FromARGB32PM(uint *buffer, const uint return buffer; } -static const uint *QT_FASTCALL convertRGB32ToARGB32PM(uint *buffer, const uint *src, int count, - const QVector<QRgb> *, QDitherInfo *) +static const uint *QT_FASTCALL maskRGB32(uint *buffer, const uint *src, int count, + const QVector<QRgb> *, QDitherInfo *) { for (int i = 0; i < count; ++i) buffer[i] = 0xff000000 |src[i]; @@ -160,8 +161,9 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio // If the source doesn't have an alpha channel, we can use the faster convertFromRGB32 method. convertFromARGB32PM = destLayout->convertFromRGB32; } else { + // The drawhelpers do not mask the alpha value in RGB32, we want to here. if (src->format == QImage::Format_RGB32) - convertToARGB32PM = convertRGB32ToARGB32PM; + convertToARGB32PM = maskRGB32; if (dest->format == QImage::Format_RGB32) { #ifdef QT_COMPILER_SUPPORTS_SSE4_1 if (qCpuHasFeature(SSE4_1)) @@ -171,6 +173,15 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio convertFromARGB32PM = convertRGB32FromARGB32PM; } } + if ((src->format == QImage::Format_ARGB32 || src->format == QImage::Format_RGBA8888) && + destLayout->alphaWidth == 0 && destLayout->convertFromRGB32) { + // Avoid unnecessary premultiply and unpremultiply when converting from unpremultiplied src format. + convertToARGB32PM = qPixelLayouts[src->format + 1].convertToARGB32PM; + if (dest->format == QImage::Format_RGB32) + convertFromARGB32PM = maskRGB32; + else + convertFromARGB32PM = destLayout->convertFromRGB32; + } QDitherInfo dither; QDitherInfo *ditherPtr = 0; if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither) @@ -221,7 +232,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im convertFromARGB32PM = destLayout->convertFromRGB32; } else { if (data->format == QImage::Format_RGB32) - convertToARGB32PM = convertRGB32ToARGB32PM; + convertToARGB32PM = maskRGB32; if (dst_format == QImage::Format_RGB32) { #ifdef QT_COMPILER_SUPPORTS_SSE4_1 if (qCpuHasFeature(SSE4_1)) @@ -231,6 +242,15 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im convertFromARGB32PM = convertRGB32FromARGB32PM; } } + if ((data->format == QImage::Format_ARGB32 || data->format == QImage::Format_RGBA8888) && + destLayout->alphaWidth == 0 && destLayout->convertFromRGB32) { + // Avoid unnecessary premultiply and unpremultiply when converting from unpremultiplied src format. + convertToARGB32PM = qPixelLayouts[data->format + 1].convertToARGB32PM; + if (dst_format == QImage::Format_RGB32) + convertFromARGB32PM = maskRGB32; + else + convertFromARGB32PM = destLayout->convertFromRGB32; + } QDitherInfo dither; QDitherInfo *ditherPtr = 0; if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither) @@ -322,10 +342,10 @@ Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32(quint32 *dest_data, con // Handle 4 pixels at a time 12 bytes input to 16 bytes output. for (; pixel + 3 < len; pixel += 4) { - const quint32 *src_packed = (const quint32 *) src_data; - const quint32 src1 = qFromBigEndian(src_packed[0]); - const quint32 src2 = qFromBigEndian(src_packed[1]); - const quint32 src3 = qFromBigEndian(src_packed[2]); + const quint32_be *src_packed = reinterpret_cast<const quint32_be *>(src_data); + const quint32 src1 = src_packed[0]; + const quint32 src2 = src_packed[1]; + const quint32 src3 = src_packed[2]; dest_data[0] = 0xff000000 | (src1 >> 8); dest_data[1] = 0xff000000 | (src1 << 16) | (src2 >> 16); @@ -803,8 +823,8 @@ static bool convert_indexed8_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConve const int depth = 32; - const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; - const int nbytes = dst_bytes_per_line * data->height; + const qsizetype dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; + const qsizetype nbytes = dst_bytes_per_line * data->height; uchar *const newData = (uchar *)realloc(data->data, nbytes); if (!newData) return false; @@ -857,8 +877,8 @@ static bool convert_indexed8_to_ARGB_inplace(QImageData *data, Qt::ImageConversi const int depth = 32; - const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; - const int nbytes = dst_bytes_per_line * data->height; + const qsizetype dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; + const qsizetype nbytes = dst_bytes_per_line * data->height; uchar *const newData = (uchar *)realloc(data->data, nbytes); if (!newData) return false; @@ -925,8 +945,8 @@ static bool convert_indexed8_to_RGB16_inplace(QImageData *data, Qt::ImageConvers const int depth = 16; - const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; - const int nbytes = dst_bytes_per_line * data->height; + const qsizetype dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; + const qsizetype nbytes = dst_bytes_per_line * data->height; uchar *const newData = (uchar *)realloc(data->data, nbytes); if (!newData) return false; @@ -982,8 +1002,8 @@ static bool convert_RGB_to_RGB16_inplace(QImageData *data, Qt::ImageConversionFl const int depth = 16; - const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; - const int src_bytes_per_line = data->bytes_per_line; + const qsizetype dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; + const qsizetype src_bytes_per_line = data->bytes_per_line; quint32 *src_data = (quint32 *) data->data; quint16 *dst_data = (quint16 *) data->data; @@ -1237,9 +1257,9 @@ void dither_to_Mono(QImageData *dst, const QImageData *src, } uchar *dst_data = dst->data; - int dst_bpl = dst->bytes_per_line; + qsizetype dst_bpl = dst->bytes_per_line; const uchar *src_data = src->data; - int src_bpl = src->bytes_per_line; + qsizetype src_bpl = src->bytes_per_line; switch (dithermode) { case Diffuse: { @@ -1892,8 +1912,8 @@ static void convert_Indexed8_to_Alpha8(QImageData *dest, const QImageData *src, if (simpleCase) memcpy(dest->data, src->data, src->bytes_per_line * src->height); else { - int size = src->bytes_per_line * src->height; - for (int i = 0; i < size; ++i) { + qsizetype size = src->bytes_per_line * src->height; + for (qsizetype i = 0; i < size; ++i) { dest->data[i] = translate[src->data[i]]; } } @@ -1916,8 +1936,8 @@ static void convert_Indexed8_to_Grayscale8(QImageData *dest, const QImageData *s if (simpleCase) memcpy(dest->data, src->data, src->bytes_per_line * src->height); else { - int size = src->bytes_per_line * src->height; - for (int i = 0; i < size; ++i) { + qsizetype size = src->bytes_per_line * src->height; + for (qsizetype i = 0; i < size; ++i) { dest->data[i] = translate[src->data[i]]; } } diff --git a/src/gui/image/qimage_darwin.mm b/src/gui/image/qimage_darwin.mm index 3764bef06b..a5c391ad21 100644 --- a/src/gui/image/qimage_darwin.mm +++ b/src/gui/image/qimage_darwin.mm @@ -130,7 +130,7 @@ CGImageRef QImage::toCGImage() const auto deleter = [](void *image, const void *, size_t) { delete static_cast<QImage *>(image); }; QCFType<CGDataProviderRef> dataProvider = - CGDataProviderCreateWithData(new QImage(*this), bits(), byteCount(), deleter); + CGDataProviderCreateWithData(new QImage(*this), bits(), sizeInBytes(), deleter); QCFType<CGColorSpaceRef> colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h index 775ab6d541..befecbfe8b 100644 --- a/src/gui/image/qimage_p.h +++ b/src/gui/image/qimage_p.h @@ -71,12 +71,12 @@ struct Q_GUI_EXPORT QImageData { // internal image data int width; int height; int depth; - int nbytes; // number of bytes data + qsizetype nbytes; // number of bytes data qreal devicePixelRatio; QVector<QRgb> colortable; uchar *data; QImage::Format format; - int bytes_per_line; + qsizetype bytes_per_line; int ser_no; // serial number int detach_no; diff --git a/src/gui/image/qimageiohandler.h b/src/gui/image/qimageiohandler.h index baf9853259..35984dd6a5 100644 --- a/src/gui/image/qimageiohandler.h +++ b/src/gui/image/qimageiohandler.h @@ -140,7 +140,7 @@ class Q_GUI_EXPORT QImageIOPlugin : public QObject { Q_OBJECT public: - explicit QImageIOPlugin(QObject *parent = Q_NULLPTR); + explicit QImageIOPlugin(QObject *parent = nullptr); virtual ~QImageIOPlugin(); enum Capability { diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index e1089936c2..7086e102ea 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -570,6 +570,16 @@ bool QImageReaderPrivate::initHandler() // probe the file extension if (deleteDevice && !device->isOpen() && !device->open(QIODevice::ReadOnly) && autoDetectImageFormat) { + Q_ASSERT(qobject_cast<QFile*>(device) != 0); // future-proofing; for now this should always be the case, so... + QFile *file = static_cast<QFile *>(device); + + if (file->error() == QFileDevice::ResourceError) { + // this is bad. we should abort the open attempt and note the failure. + imageReaderError = QImageReader::DeviceError; + errorString = file->errorString(); + return false; + } + QList<QByteArray> extensions = QImageReader::supportedImageFormats(); if (!format.isEmpty()) { // Try the most probable extension first @@ -580,7 +590,6 @@ bool QImageReaderPrivate::initHandler() int currentExtension = 0; - QFile *file = static_cast<QFile *>(device); QString fileName = file->fileName(); do { diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp index ab15d8ee29..a39d204677 100644 --- a/src/gui/image/qimagewriter.cpp +++ b/src/gui/image/qimagewriter.cpp @@ -87,6 +87,9 @@ \value UnsupportedFormatError Qt does not support the requested image format. + \value InvalidImageError An attempt was made to write an invalid QImage. An + example of an invalid image would be a null QImage. + \value UnknownError An unknown error occurred. If you get this value after calling write(), it is most likely caused by a bug in QImageWriter. @@ -736,6 +739,13 @@ extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orie */ bool QImageWriter::write(const QImage &image) { + // Do this before canWrite, so it doesn't create a file if this fails. + if (Q_UNLIKELY(image.isNull())) { + d->imageWriterError = QImageWriter::InvalidImageError; + d->errorString = QImageWriter::tr("Image is empty"); + return false; + } + if (!canWrite()) return false; diff --git a/src/gui/image/qimagewriter.h b/src/gui/image/qimagewriter.h index 58f8c51472..fd1fdd07e8 100644 --- a/src/gui/image/qimagewriter.h +++ b/src/gui/image/qimagewriter.h @@ -60,7 +60,8 @@ public: enum ImageWriterError { UnknownError, DeviceError, - UnsupportedFormatError + UnsupportedFormatError, + InvalidImageError }; QImageWriter(); diff --git a/src/gui/image/qmovie.cpp b/src/gui/image/qmovie.cpp index fbbf6e9802..d5e8b1b974 100644 --- a/src/gui/image/qmovie.cpp +++ b/src/gui/image/qmovie.cpp @@ -161,6 +161,8 @@ This signal is emitted by QMovie when the error \a error occurred during playback. QMovie will stop the movie, and enter QMovie::NotRunning state. + + \sa lastError(), lastErrorString() */ /*! \fn void QMovie::finished() @@ -328,6 +330,8 @@ int QMoviePrivate::speedAdjustedDelay(int delay) const */ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber) { + Q_Q(QMovie); + if (frameNumber < 0) return QFrameInfo(); // Invalid @@ -356,7 +360,8 @@ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber) reader = new QImageReader(device, format); else reader = new QImageReader(absoluteFilePath, format); - (void)reader->canRead(); // Provoke a device->open() call + if (!reader->canRead()) // Provoke a device->open() call + emit q->error(reader->error()); reader->device()->seek(initialDevicePos); reader->setBackgroundColor(bgColor); reader->setScaledSize(scaledSize); @@ -523,8 +528,20 @@ void QMoviePrivate::_q_loadNextFrame(bool starting) */ bool QMoviePrivate::isValid() const { - return (greatestFrameNumber >= 0) // have we seen valid data - || reader->canRead(); // or does the reader see valid data + Q_Q(const QMovie); + + if (greatestFrameNumber >= 0) + return true; // have we seen valid data + bool canRead = reader->canRead(); + if (!canRead) { + // let the consumer know it's broken + // + // ### the const_cast here is ugly, but 'const' of this method is + // technically wrong right now, since it may cause the underlying device + // to open. + emit const_cast<QMovie*>(q)->error(reader->error()); + } + return canRead; } /*! @@ -775,6 +792,8 @@ QImage QMovie::currentImage() const /*! Returns \c true if the movie is valid (e.g., the image data is readable and the image format is supported); otherwise returns \c false. + + For information about why the movie is not valid, see lastError(). */ bool QMovie::isValid() const { @@ -783,6 +802,29 @@ bool QMovie::isValid() const } /*! + Returns the most recent error that occurred while attempting to read image data. + + \sa lastErrorString() +*/ +QImageReader::ImageReaderError QMovie::lastError() const +{ + Q_D(const QMovie); + return d->reader->error(); +} + +/*! + Returns a human-readable representation of the most recent error that occurred + while attempting to read image data. + + \sa lastError() +*/ +QString QMovie::lastErrorString() const +{ + Q_D(const QMovie); + return d->reader->errorString(); +} + +/*! Returns the number of frames in the movie. Certain animation formats do not support this feature, in which diff --git a/src/gui/image/qmovie.h b/src/gui/image/qmovie.h index 930d502892..e13c528894 100644 --- a/src/gui/image/qmovie.h +++ b/src/gui/image/qmovie.h @@ -79,9 +79,9 @@ public: }; Q_ENUM(CacheMode) - explicit QMovie(QObject *parent = Q_NULLPTR); - explicit QMovie(QIODevice *device, const QByteArray &format = QByteArray(), QObject *parent = Q_NULLPTR); - explicit QMovie(const QString &fileName, const QByteArray &format = QByteArray(), QObject *parent = Q_NULLPTR); + explicit QMovie(QObject *parent = nullptr); + explicit QMovie(QIODevice *device, const QByteArray &format = QByteArray(), QObject *parent = nullptr); + explicit QMovie(const QString &fileName, const QByteArray &format = QByteArray(), QObject *parent = nullptr); ~QMovie(); static QList<QByteArray> supportedFormats(); @@ -105,6 +105,8 @@ public: QPixmap currentPixmap() const; bool isValid() const; + QImageReader::ImageReaderError lastError() const; + QString lastErrorString() const; bool jumpToFrame(int frameNumber); int loopCount() const; diff --git a/src/gui/image/qpaintengine_pic_p.h b/src/gui/image/qpaintengine_pic_p.h index 7c690c1498..c3044796ad 100644 --- a/src/gui/image/qpaintengine_pic_p.h +++ b/src/gui/image/qpaintengine_pic_p.h @@ -68,10 +68,10 @@ public: QPicturePaintEngine(); ~QPicturePaintEngine(); - bool begin(QPaintDevice *pdev) Q_DECL_OVERRIDE; - bool end() Q_DECL_OVERRIDE; + bool begin(QPaintDevice *pdev) override; + bool end() override; - void updateState(const QPaintEngineState &state) Q_DECL_OVERRIDE; + void updateState(const QPaintEngineState &state) override; void updatePen(const QPen &pen); void updateBrush(const QBrush &brush); @@ -86,18 +86,18 @@ public: void updateClipEnabled(bool enabled); void updateOpacity(qreal opacity); - void drawEllipse(const QRectF &rect) Q_DECL_OVERRIDE; - void drawPath(const QPainterPath &path) Q_DECL_OVERRIDE; - void drawPolygon(const QPointF *points, int numPoints, PolygonDrawMode mode) Q_DECL_OVERRIDE; + void drawEllipse(const QRectF &rect) override; + void drawPath(const QPainterPath &path) override; + void drawPolygon(const QPointF *points, int numPoints, PolygonDrawMode mode) override; using QPaintEngine::drawPolygon; - void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) Q_DECL_OVERRIDE; - void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s) Q_DECL_OVERRIDE; + void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) override; + void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s) override; void drawImage(const QRectF &r, const QImage &image, const QRectF &sr, - Qt::ImageConversionFlags flags = Qt::AutoColor) Q_DECL_OVERRIDE; - void drawTextItem(const QPointF &p, const QTextItem &ti) Q_DECL_OVERRIDE; + Qt::ImageConversionFlags flags = Qt::AutoColor) override; + void drawTextItem(const QPointF &p, const QTextItem &ti) override; - Type type() const Q_DECL_OVERRIDE { return Picture; } + Type type() const override { return Picture; } protected: QPicturePaintEngine(QPaintEnginePrivate &dptr); diff --git a/src/gui/image/qpicture.cpp b/src/gui/image/qpicture.cpp index 010f5ecf67..7aa221948e 100644 --- a/src/gui/image/qpicture.cpp +++ b/src/gui/image/qpicture.cpp @@ -456,8 +456,8 @@ public: QFakeDevice() { dpi_x = qt_defaultDpiX(); dpi_y = qt_defaultDpiY(); } void setDpiX(int dpi) { dpi_x = dpi; } void setDpiY(int dpi) { dpi_y = dpi; } - QPaintEngine *paintEngine() const Q_DECL_OVERRIDE { return 0; } - int metric(PaintDeviceMetric m) const Q_DECL_OVERRIDE + QPaintEngine *paintEngine() const override { return 0; } + int metric(PaintDeviceMetric m) const override { switch(m) { case PdmPhysicalDpiX: @@ -1194,6 +1194,7 @@ QT_BEGIN_INCLUDE_NAMESPACE #include "qpictureformatplugin.h" QT_END_INCLUDE_NAMESPACE +#if QT_DEPRECATED_SINCE(5, 10) /*! \obsolete @@ -1284,6 +1285,7 @@ QList<QByteArray> QPicture::outputFormats() { return QPictureIO::outputFormats(); } +#endif // QT_DEPRECATED_SINCE(5, 10) /***************************************************************************** QPictureIO member functions diff --git a/src/gui/image/qpicture.h b/src/gui/image/qpicture.h index 8da11caee4..ec7b4bd7e3 100644 --- a/src/gui/image/qpicture.h +++ b/src/gui/image/qpicture.h @@ -62,17 +62,17 @@ public: bool isNull() const; - int devType() const Q_DECL_OVERRIDE; + int devType() const override; uint size() const; const char* data() const; virtual void setData(const char* data, uint size); bool play(QPainter *p); - bool load(QIODevice *dev, const char *format = Q_NULLPTR); - bool load(const QString &fileName, const char *format = Q_NULLPTR); - bool save(QIODevice *dev, const char *format = Q_NULLPTR); - bool save(const QString &fileName, const char *format = Q_NULLPTR); + bool load(QIODevice *dev, const char *format = nullptr); + bool load(const QString &fileName, const char *format = nullptr); + bool save(QIODevice *dev, const char *format = nullptr); + bool save(const QString &fileName, const char *format = nullptr); QRect boundingRect() const; void setBoundingRect(const QRect &r); @@ -90,18 +90,20 @@ public: friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &in, const QPicture &p); friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &in, QPicture &p); - static const char* pictureFormat(const QString &fileName); - static QList<QByteArray> inputFormats(); - static QList<QByteArray> outputFormats(); - static QStringList inputFormatList(); - static QStringList outputFormatList(); +#if QT_DEPRECATED_SINCE(5, 10) + static QT_DEPRECATED const char* pictureFormat(const QString &fileName); + static QT_DEPRECATED QList<QByteArray> inputFormats(); + static QT_DEPRECATED QList<QByteArray> outputFormats(); + static QT_DEPRECATED QStringList inputFormatList(); + static QT_DEPRECATED QStringList outputFormatList(); +#endif // QT_DEPRECATED_SINCE(5, 10) - QPaintEngine *paintEngine() const Q_DECL_OVERRIDE; + QPaintEngine *paintEngine() const override; protected: QPicture(QPicturePrivate &data); - int metric(PaintDeviceMetric m) const Q_DECL_OVERRIDE; + int metric(PaintDeviceMetric m) const override; private: bool exec(QPainter *p, QDataStream &ds, int i); diff --git a/src/gui/image/qpictureformatplugin.h b/src/gui/image/qpictureformatplugin.h index 32195687c7..3f59c04d79 100644 --- a/src/gui/image/qpictureformatplugin.h +++ b/src/gui/image/qpictureformatplugin.h @@ -60,7 +60,7 @@ class Q_GUI_EXPORT QPictureFormatPlugin : public QObject { Q_OBJECT public: - explicit QPictureFormatPlugin(QObject *parent = Q_NULLPTR); + explicit QPictureFormatPlugin(QObject *parent = nullptr); ~QPictureFormatPlugin(); virtual bool loadPicture(const QString &format, const QString &filename, QPicture *pic); diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 0aa05a04e2..5b3e3985a7 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -596,44 +596,7 @@ void QPixmap::setMask(const QBitmap &mask) return; detach(); - - QImage image = data->toImage(); - if (mask.size().isEmpty()) { - if (image.depth() != 1) { // hw: ???? - image = image.convertToFormat(QImage::Format_RGB32); - } - } else { - const int w = image.width(); - const int h = image.height(); - - switch (image.depth()) { - case 1: { - const QImage imageMask = mask.toImage().convertToFormat(image.format()); - for (int y = 0; y < h; ++y) { - const uchar *mscan = imageMask.scanLine(y); - uchar *tscan = image.scanLine(y); - int bytesPerLine = image.bytesPerLine(); - for (int i = 0; i < bytesPerLine; ++i) - tscan[i] &= mscan[i]; - } - break; - } - default: { - const QImage imageMask = mask.toImage().convertToFormat(QImage::Format_MonoLSB); - image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); - for (int y = 0; y < h; ++y) { - const uchar *mscan = imageMask.scanLine(y); - QRgb *tscan = (QRgb *)image.scanLine(y); - for (int x = 0; x < w; ++x) { - if (!(mscan[x>>3] & (1 << (x&7)))) - tscan[x] = 0; - } - } - break; - } - } - } - data->fromImage(image, Qt::AutoColor); + data->setMask(mask); } /*! @@ -1496,37 +1459,7 @@ QPaintEngine *QPixmap::paintEngine() const */ QBitmap QPixmap::mask() const { - if (!data || !hasAlphaChannel()) - return QBitmap(); - - const QImage img = toImage(); - bool shouldConvert = (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_ARGB32_Premultiplied); - const QImage image = (shouldConvert ? img.convertToFormat(QImage::Format_ARGB32_Premultiplied) : img); - const int w = image.width(); - const int h = image.height(); - - QImage mask(w, h, QImage::Format_MonoLSB); - if (mask.isNull()) // allocation failed - return QBitmap(); - - mask.setColorCount(2); - mask.setColor(0, QColor(Qt::color0).rgba()); - mask.setColor(1, QColor(Qt::color1).rgba()); - - const int bpl = mask.bytesPerLine(); - - for (int y = 0; y < h; ++y) { - const QRgb *src = reinterpret_cast<const QRgb*>(image.scanLine(y)); - uchar *dest = mask.scanLine(y); - memset(dest, 0, bpl); - for (int x = 0; x < w; ++x) { - if (qAlpha(*src) > 0) - dest[x >> 3] |= (1 << (x & 7)); - ++src; - } - } - - return QBitmap::fromImage(mask); + return data ? data->mask() : QBitmap(); } /*! diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h index d651b57fd5..55cca7a766 100644 --- a/src/gui/image/qpixmap.h +++ b/src/gui/image/qpixmap.h @@ -65,7 +65,7 @@ public: explicit QPixmap(QPlatformPixmap *data); QPixmap(int w, int h); explicit QPixmap(const QSize &); - QPixmap(const QString& fileName, const char *format = Q_NULLPTR, Qt::ImageConversionFlags flags = Qt::AutoColor); + QPixmap(const QString& fileName, const char *format = nullptr, Qt::ImageConversionFlags flags = Qt::AutoColor); #ifndef QT_NO_IMAGEFORMAT_XPM explicit QPixmap(const char * const xpm[]); #endif @@ -83,7 +83,7 @@ public: operator QVariant() const; bool isNull() const; - int devType() const Q_DECL_OVERRIDE; + int devType() const override; int width() const; int height() const; @@ -138,19 +138,19 @@ public: } #endif - bool load(const QString& fileName, const char *format = Q_NULLPTR, Qt::ImageConversionFlags flags = Qt::AutoColor); - bool loadFromData(const uchar *buf, uint len, const char* format = Q_NULLPTR, Qt::ImageConversionFlags flags = Qt::AutoColor); - inline bool loadFromData(const QByteArray &data, const char* format = Q_NULLPTR, Qt::ImageConversionFlags flags = Qt::AutoColor); - bool save(const QString& fileName, const char* format = Q_NULLPTR, int quality = -1) const; - bool save(QIODevice* device, const char* format = Q_NULLPTR, int quality = -1) const; + bool load(const QString& fileName, const char *format = nullptr, Qt::ImageConversionFlags flags = Qt::AutoColor); + bool loadFromData(const uchar *buf, uint len, const char* format = nullptr, Qt::ImageConversionFlags flags = Qt::AutoColor); + inline bool loadFromData(const QByteArray &data, const char* format = nullptr, Qt::ImageConversionFlags flags = Qt::AutoColor); + bool save(const QString& fileName, const char* format = nullptr, int quality = -1) const; + bool save(QIODevice* device, const char* format = nullptr, int quality = -1) const; bool convertFromImage(const QImage &img, Qt::ImageConversionFlags flags = Qt::AutoColor); inline QPixmap copy(int x, int y, int width, int height) const; QPixmap copy(const QRect &rect = QRect()) const; - inline void scroll(int dx, int dy, int x, int y, int width, int height, QRegion *exposed = Q_NULLPTR); - void scroll(int dx, int dy, const QRect &rect, QRegion *exposed = Q_NULLPTR); + inline void scroll(int dx, int dy, int x, int y, int width, int height, QRegion *exposed = nullptr); + void scroll(int dx, int dy, const QRect &rect, QRegion *exposed = nullptr); #if QT_DEPRECATED_SINCE(5, 0) QT_DEPRECATED inline int serialNumber() const { return cacheKey() >> 32; } @@ -162,7 +162,7 @@ public: bool isQBitmap() const; - QPaintEngine *paintEngine() const Q_DECL_OVERRIDE; + QPaintEngine *paintEngine() const override; inline bool operator!() const { return isNull(); } @@ -172,7 +172,7 @@ public: #endif protected: - int metric(PaintDeviceMetric) const Q_DECL_OVERRIDE; + int metric(PaintDeviceMetric) const override; static QPixmap fromImageInPlace(QImage &image, Qt::ImageConversionFlags flags = Qt::AutoColor); private: diff --git a/src/gui/image/qpixmap_blitter.cpp b/src/gui/image/qpixmap_blitter.cpp index 950695a9d7..646e737afa 100644 --- a/src/gui/image/qpixmap_blitter.cpp +++ b/src/gui/image/qpixmap_blitter.cpp @@ -41,6 +41,7 @@ #include <qpainter.h> #include <qimage.h> +#include <qrandom.h> #include <qscreen.h> #include <private/qguiapplication_p.h> @@ -190,8 +191,8 @@ void QBlittablePlatformPixmap::fromImage(const QImage &image, uchar *mem = thisImg->bits(); const uchar *bits = correctFormatPic.constBits(); - int bytesCopied = 0; - while (bytesCopied < correctFormatPic.byteCount()) { + qsizetype bytesCopied = 0; + while (bytesCopied < correctFormatPic.sizeInBytes()) { memcpy(mem,bits,correctFormatPic.bytesPerLine()); mem += thisImg->bytesPerLine(); bits += correctFormatPic.bytesPerLine(); @@ -252,7 +253,7 @@ QImage *QBlittablePlatformPixmap::overlay() m_rasterOverlay->size() != QSize(w,h)){ m_rasterOverlay = new QImage(w,h,QImage::Format_ARGB32_Premultiplied); m_rasterOverlay->fill(0x00000000); - uint color = (qrand() % 11)+7; + uint color = QRandomGenerator::global()->bounded(11)+7; m_overlayColor = QColor(Qt::GlobalColor(color)); m_overlayColor.setAlpha(0x88); diff --git a/src/gui/image/qpixmap_blitter_p.h b/src/gui/image/qpixmap_blitter_p.h index 9889cfb8ec..d70cbcdcc3 100644 --- a/src/gui/image/qpixmap_blitter_p.h +++ b/src/gui/image/qpixmap_blitter_p.h @@ -69,17 +69,17 @@ public: QBlittable *blittable() const; void setBlittable(QBlittable *blittable); - void resize(int width, int height) Q_DECL_OVERRIDE; - int metric(QPaintDevice::PaintDeviceMetric metric) const Q_DECL_OVERRIDE; - void fill(const QColor &color) Q_DECL_OVERRIDE; - QImage *buffer() Q_DECL_OVERRIDE; - QImage toImage() const Q_DECL_OVERRIDE; - bool hasAlphaChannel() const Q_DECL_OVERRIDE; - void fromImage(const QImage &image, Qt::ImageConversionFlags flags) Q_DECL_OVERRIDE; - qreal devicePixelRatio() const Q_DECL_OVERRIDE; - void setDevicePixelRatio(qreal scaleFactor) Q_DECL_OVERRIDE; - - QPaintEngine *paintEngine() const Q_DECL_OVERRIDE; + void resize(int width, int height) override; + int metric(QPaintDevice::PaintDeviceMetric metric) const override; + void fill(const QColor &color) override; + QImage *buffer() override; + QImage toImage() const override; + bool hasAlphaChannel() const override; + void fromImage(const QImage &image, Qt::ImageConversionFlags flags) override; + qreal devicePixelRatio() const override; + void setDevicePixelRatio(qreal scaleFactor) override; + + QPaintEngine *paintEngine() const override; void markRasterOverlay(const QRectF &); void markRasterOverlay(const QPointF &, const QTextItem &); diff --git a/src/gui/image/qpixmap_raster_p.h b/src/gui/image/qpixmap_raster_p.h index 6ea965a324..cff962181a 100644 --- a/src/gui/image/qpixmap_raster_p.h +++ b/src/gui/image/qpixmap_raster_p.h @@ -63,28 +63,28 @@ public: QRasterPlatformPixmap(PixelType type); ~QRasterPlatformPixmap(); - QPlatformPixmap *createCompatiblePlatformPixmap() const Q_DECL_OVERRIDE; - - void resize(int width, int height) Q_DECL_OVERRIDE; - bool fromData(const uchar *buffer, uint len, const char *format, Qt::ImageConversionFlags flags) Q_DECL_OVERRIDE; - void fromImage(const QImage &image, Qt::ImageConversionFlags flags) Q_DECL_OVERRIDE; - void fromImageInPlace(QImage &image, Qt::ImageConversionFlags flags) Q_DECL_OVERRIDE; - void fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags) Q_DECL_OVERRIDE; - - void copy(const QPlatformPixmap *data, const QRect &rect) Q_DECL_OVERRIDE; - bool scroll(int dx, int dy, const QRect &rect) Q_DECL_OVERRIDE; - void fill(const QColor &color) Q_DECL_OVERRIDE; - bool hasAlphaChannel() const Q_DECL_OVERRIDE; - QImage toImage() const Q_DECL_OVERRIDE; - QImage toImage(const QRect &rect) const Q_DECL_OVERRIDE; - QPaintEngine* paintEngine() const Q_DECL_OVERRIDE; - QImage* buffer() Q_DECL_OVERRIDE; - qreal devicePixelRatio() const Q_DECL_OVERRIDE; - void setDevicePixelRatio(qreal scaleFactor) Q_DECL_OVERRIDE; + QPlatformPixmap *createCompatiblePlatformPixmap() const override; + + void resize(int width, int height) override; + bool fromData(const uchar *buffer, uint len, const char *format, Qt::ImageConversionFlags flags) override; + void fromImage(const QImage &image, Qt::ImageConversionFlags flags) override; + void fromImageInPlace(QImage &image, Qt::ImageConversionFlags flags) override; + void fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags) override; + + void copy(const QPlatformPixmap *data, const QRect &rect) override; + bool scroll(int dx, int dy, const QRect &rect) override; + void fill(const QColor &color) override; + bool hasAlphaChannel() const override; + QImage toImage() const override; + QImage toImage(const QRect &rect) const override; + QPaintEngine* paintEngine() const override; + QImage* buffer() override; + qreal devicePixelRatio() const override; + void setDevicePixelRatio(qreal scaleFactor) override; protected: - int metric(QPaintDevice::PaintDeviceMetric metric) const Q_DECL_OVERRIDE; + int metric(QPaintDevice::PaintDeviceMetric metric) const override; void createPixmapForImage(QImage sourceImage, Qt::ImageConversionFlags flags); void setImage(const QImage &image); QImage image; diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp index 742aa31ba9..4b8b1203d6 100644 --- a/src/gui/image/qpixmapcache.cpp +++ b/src/gui/image/qpixmapcache.cpp @@ -193,7 +193,7 @@ public: QPMCache(); ~QPMCache(); - void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE; + void timerEvent(QTimerEvent *) override; bool insert(const QString& key, const QPixmap &pixmap, int cost); QPixmapCache::Key insert(const QPixmap &pixmap, int cost); bool replace(const QPixmapCache::Key &key, const QPixmap &pixmap, int cost); diff --git a/src/gui/image/qpixmapcache.h b/src/gui/image/qpixmapcache.h index 856b82f559..ea10ab1b76 100644 --- a/src/gui/image/qpixmapcache.h +++ b/src/gui/image/qpixmapcache.h @@ -56,7 +56,7 @@ public: Key(); Key(const Key &other); #ifdef Q_COMPILER_RVALUE_REFS - Key(Key &&other) Q_DECL_NOTHROW : d(other.d) { other.d = Q_NULLPTR; } + Key(Key &&other) Q_DECL_NOTHROW : d(other.d) { other.d = nullptr; } Key &operator =(Key &&other) Q_DECL_NOTHROW { swap(other); return *this; } #endif ~Key(); diff --git a/src/gui/image/qplatformpixmap.cpp b/src/gui/image/qplatformpixmap.cpp index b3b9f79fb1..2209c3de4d 100644 --- a/src/gui/image/qplatformpixmap.cpp +++ b/src/gui/image/qplatformpixmap.cpp @@ -163,6 +163,82 @@ bool QPlatformPixmap::scroll(int dx, int dy, const QRect &rect) return false; } +QBitmap QPlatformPixmap::mask() const +{ + if (!hasAlphaChannel()) + return QBitmap(); + + const QImage img = toImage(); + bool shouldConvert = (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_ARGB32_Premultiplied); + const QImage image = (shouldConvert ? img.convertToFormat(QImage::Format_ARGB32_Premultiplied) : img); + const int w = image.width(); + const int h = image.height(); + + QImage mask(w, h, QImage::Format_MonoLSB); + if (mask.isNull()) // allocation failed + return QBitmap(); + + mask.setColorCount(2); + mask.setColor(0, QColor(Qt::color0).rgba()); + mask.setColor(1, QColor(Qt::color1).rgba()); + + const int bpl = mask.bytesPerLine(); + + for (int y = 0; y < h; ++y) { + const QRgb *src = reinterpret_cast<const QRgb*>(image.scanLine(y)); + uchar *dest = mask.scanLine(y); + memset(dest, 0, bpl); + for (int x = 0; x < w; ++x) { + if (qAlpha(*src) > 0) + dest[x >> 3] |= (1 << (x & 7)); + ++src; + } + } + + return QBitmap::fromImage(mask); +} + +void QPlatformPixmap::setMask(const QBitmap &mask) +{ + QImage image = toImage(); + if (mask.size().isEmpty()) { + if (image.depth() != 1) { // hw: ???? + image = image.convertToFormat(QImage::Format_RGB32); + } + } else { + const int w = image.width(); + const int h = image.height(); + + switch (image.depth()) { + case 1: { + const QImage imageMask = mask.toImage().convertToFormat(image.format()); + for (int y = 0; y < h; ++y) { + const uchar *mscan = imageMask.scanLine(y); + uchar *tscan = image.scanLine(y); + int bytesPerLine = image.bytesPerLine(); + for (int i = 0; i < bytesPerLine; ++i) + tscan[i] &= mscan[i]; + } + break; + } + default: { + const QImage imageMask = mask.toImage().convertToFormat(QImage::Format_MonoLSB); + image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + for (int y = 0; y < h; ++y) { + const uchar *mscan = imageMask.scanLine(y); + QRgb *tscan = (QRgb *)image.scanLine(y); + for (int x = 0; x < w; ++x) { + if (!(mscan[x>>3] & (1 << (x&7)))) + tscan[x] = 0; + } + } + break; + } + } + } + fromImage(image, Qt::AutoColor); +} + QPixmap QPlatformPixmap::transformed(const QTransform &matrix, Qt::TransformationMode mode) const { diff --git a/src/gui/image/qplatformpixmap.h b/src/gui/image/qplatformpixmap.h index 8513755cca..7635ac2949 100644 --- a/src/gui/image/qplatformpixmap.h +++ b/src/gui/image/qplatformpixmap.h @@ -69,7 +69,7 @@ public: enum ClassId { RasterClass, DirectFBClass, BlitterClass, Direct2DClass, - CustomClass = 1024 }; + X11Class, CustomClass = 1024 }; QPlatformPixmap(PixelType pixelType, int classId); virtual ~QPlatformPixmap(); @@ -99,6 +99,9 @@ public: virtual int metric(QPaintDevice::PaintDeviceMetric metric) const = 0; virtual void fill(const QColor &color) = 0; + virtual QBitmap mask() const; + virtual void setMask(const QBitmap &mask); + virtual bool hasAlphaChannel() const = 0; virtual QPixmap transformed(const QTransform &matrix, Qt::TransformationMode mode) const; @@ -144,6 +147,7 @@ protected: private: friend class QPixmap; + friend class QX11PlatformPixmap; friend class QImagePixmapCleanupHooks; // Needs to set is_cached friend class QOpenGLTextureCache; //Needs to check the reference count friend class QExplicitlySharedDataPointer<QPlatformPixmap>; @@ -159,7 +163,7 @@ private: # define QT_XFORM_TYPE_MSBFIRST 0 # define QT_XFORM_TYPE_LSBFIRST 1 -extern bool qt_xForm_helper(const QTransform&, int, int, int, uchar*, int, int, int, const uchar*, int, int, int); +Q_GUI_EXPORT bool qt_xForm_helper(const QTransform&, int, int, int, uchar*, int, int, int, const uchar*, int, int, int); QT_END_NAMESPACE diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp index ce7f7b8a0f..9c54b9ada4 100644 --- a/src/gui/image/qxpmhandler.cpp +++ b/src/gui/image/qxpmhandler.cpp @@ -42,6 +42,7 @@ #ifndef QT_NO_IMAGEFORMAT_XPM #include <private/qcolor_p.h> +#include <qbytearraymatcher.h> #include <qimage.h> #include <qmap.h> #include <qtextstream.h> @@ -1041,7 +1042,9 @@ bool qt_read_xpm_image_or_array(QIODevice *device, const char * const * source, if ((readBytes = device->readLine(buf.data(), buf.size())) < 0) return false; - if (buf.indexOf("/* XPM") != 0) { + static Q_RELAXED_CONSTEXPR auto matcher = qMakeStaticByteArrayMatcher("/* XPM"); + + if (matcher.indexIn(buf) != 0) { while (readBytes > 0) { device->ungetChar(buf.at(readBytes - 1)); --readBytes; |