diff options
Diffstat (limited to 'src/gui')
77 files changed, 2432 insertions, 576 deletions
diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp index a7053aa3da..7abe40d30c 100644 --- a/src/gui/accessible/qaccessible.cpp +++ b/src/gui/accessible/qaccessible.cpp @@ -455,14 +455,13 @@ QT_BEGIN_NAMESPACE Synonym for unsigned, used by the QAccessibleInterface cache. */ +#ifndef QT_NO_ACCESSIBILITY /* accessible widgets plugin discovery stuff */ -#ifndef QT_NO_ACCESSIBILITY #ifndef QT_NO_LIBRARY Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QAccessibleFactoryInterface_iid, QLatin1String("/accessible"))) #endif -#endif // FIXME turn this into one global static struct Q_GLOBAL_STATIC(QList<QAccessible::InterfaceFactory>, qAccessibleFactories) @@ -475,13 +474,11 @@ QAccessible::RootObjectHandler QAccessible::rootObjectHandler = 0; static bool cleanupAdded = false; -#ifndef QT_NO_ACCESSIBILITY static QPlatformAccessibility *platformAccessibility() { QPlatformIntegration *pfIntegration = QGuiApplicationPrivate::platformIntegration(); return pfIntegration ? pfIntegration->accessibility() : 0; } -#endif /*! \fn QAccessible::QAccessible() @@ -497,10 +494,8 @@ static QPlatformAccessibility *platformAccessibility() */ void QAccessible::cleanup() { -#ifndef QT_NO_ACCESSIBILITY if (QPlatformAccessibility *pfAccessibility = platformAccessibility()) pfAccessibility->cleanup(); -#endif } static void qAccessibleCleanup() @@ -684,7 +679,6 @@ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object) return iface; } } -#ifndef QT_NO_ACCESSIBILITY #ifndef QT_NO_LIBRARY // Find a QAccessiblePlugin (factory) for the class name. If there's // no entry in the cache try to create it using the plugin loader. @@ -708,18 +702,15 @@ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object) return result; } #endif -#endif mo = mo->superClass(); } -#ifndef QT_NO_ACCESSIBILITY if (object == qApp) { QAccessibleInterface *appInterface = new QAccessibleApplication; QAccessibleCache::instance()->insert(object, appInterface); Q_ASSERT(QAccessibleCache::instance()->objectToId.contains(qApp)); return appInterface; } -#endif return 0; } @@ -789,10 +780,8 @@ QAccessibleInterface *QAccessible::accessibleInterface(Id id) */ bool QAccessible::isActive() { -#ifndef QT_NO_ACCESSIBILITY if (QPlatformAccessibility *pfAccessibility = platformAccessibility()) return pfAccessibility->isActive(); -#endif return false; } @@ -827,10 +816,8 @@ void QAccessible::setRootObject(QObject *object) return; } -#ifndef QT_NO_ACCESSIBILITY if (QPlatformAccessibility *pfAccessibility = platformAccessibility()) pfAccessibility->setRootObject(object); -#endif } /*! @@ -863,7 +850,6 @@ void QAccessible::updateAccessibility(QAccessibleEvent *event) if (!isActive() || !event->accessibleInterface()) return; -#ifndef QT_NO_ACCESSIBILITY if (event->type() == QAccessible::TableModelChanged) { QAccessibleInterface *iface = event->accessibleInterface(); if (iface && iface->tableInterface()) @@ -877,7 +863,6 @@ void QAccessible::updateAccessibility(QAccessibleEvent *event) if (QPlatformAccessibility *pfAccessibility = platformAccessibility()) pfAccessibility->notifyAccessibilityUpdate(event); -#endif } #if QT_DEPRECATED_SINCE(5, 0) @@ -1824,7 +1809,7 @@ QDebug operator<<(QDebug d, const QAccessibleEvent &ev) d.nospace() << ")"; return d.space(); } - +#endif // QT_NO_DEBUGSTREAM /*! \class QAccessibleTextInterface @@ -2626,7 +2611,14 @@ struct QAccessibleActionStrings decreaseAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Decrease"))), showMenuAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "ShowMenu"))), setFocusAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "SetFocus"))), - toggleAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Toggle"))) {} + toggleAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Toggle"))), + scrollLeftAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Scroll Left"))), + scrollRightAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Scroll Right"))), + scrollUpAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Scroll Up"))), + scrollDownAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Scroll Down"))), + previousPageAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Previous Page"))), + nextPageAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Next Page"))) + {} const QString pressAction; const QString increaseAction; @@ -2634,6 +2626,12 @@ struct QAccessibleActionStrings const QString showMenuAction; const QString setFocusAction; const QString toggleAction; + const QString scrollLeftAction; + const QString scrollRightAction; + const QString scrollUpAction; + const QString scrollDownAction; + const QString previousPageAction; + const QString nextPageAction; QString localizedDescription(const QString &actionName) { @@ -2649,6 +2647,20 @@ struct QAccessibleActionStrings return QAccessibleActionInterface::tr("Sets the focus"); else if (actionName == toggleAction) return QAccessibleActionInterface::tr("Toggles the state"); + else if (actionName == scrollLeftAction) + return QAccessibleActionInterface::tr("Scrolls to the left"); + else if (actionName == scrollRightAction) + return QAccessibleActionInterface::tr("Scrolls to the right"); + else if (actionName == scrollUpAction) + return QAccessibleActionInterface::tr("Scrolls up"); + else if (actionName == scrollDownAction) + return QAccessibleActionInterface::tr("Scrolls down"); + else if (actionName == previousPageAction) + return QAccessibleActionInterface::tr("Goes back a page"); + else if (actionName == nextPageAction) + return QAccessibleActionInterface::tr("Goes to the next page"); + + return QString(); } }; @@ -2719,14 +2731,67 @@ const QString &QAccessibleActionInterface::toggleAction() return accessibleActionStrings()->toggleAction; } +/*! + Returns the name of the scroll left default action. + \sa actionNames(), localizedActionName() + */ +const QString &QAccessibleActionInterface::scrollLeftAction() +{ + return accessibleActionStrings()->scrollLeftAction; +} + +/*! + Returns the name of the scroll right default action. + \sa actionNames(), localizedActionName() + */ +const QString &QAccessibleActionInterface::scrollRightAction() +{ + return accessibleActionStrings()->scrollRightAction; +} + +/*! + Returns the name of the scroll up default action. + \sa actionNames(), localizedActionName() + */ +const QString &QAccessibleActionInterface::scrollUpAction() +{ + return accessibleActionStrings()->scrollUpAction; +} + +/*! + Returns the name of the scroll down default action. + \sa actionNames(), localizedActionName() + */ +const QString &QAccessibleActionInterface::scrollDownAction() +{ + return accessibleActionStrings()->scrollDownAction; +} + +/*! + Returns the name of the previous page default action. + \sa actionNames(), localizedActionName() + */ +const QString &QAccessibleActionInterface::previousPageAction() +{ + return accessibleActionStrings()->previousPageAction; +} + +/*! + Returns the name of the next page default action. + \sa actionNames(), localizedActionName() + */ +const QString &QAccessibleActionInterface::nextPageAction() +{ + return accessibleActionStrings()->nextPageAction; +} + /*! \internal */ QString qAccessibleLocalizedActionDescription(const QString &actionName) { return accessibleActionStrings()->localizedDescription(actionName); } - -#endif +#endif // QT_NO_ACCESSIBILITY QT_END_NAMESPACE diff --git a/src/gui/accessible/qaccessible.h b/src/gui/accessible/qaccessible.h index 7b5d7a1bfd..1d935cbf2d 100644 --- a/src/gui/accessible/qaccessible.h +++ b/src/gui/accessible/qaccessible.h @@ -635,6 +635,12 @@ public: static const QString &showMenuAction(); static const QString &setFocusAction(); static const QString &toggleAction(); + static const QString &scrollLeftAction(); + static const QString &scrollRightAction(); + static const QString &scrollUpAction(); + static const QString &scrollDownAction(); + static const QString &nextPageAction(); + static const QString &previousPageAction(); }; class Q_GUI_EXPORT QAccessibleImageInterface diff --git a/src/gui/accessible/qaccessiblecache.cpp b/src/gui/accessible/qaccessiblecache.cpp index cf5290ed38..825ef032cb 100644 --- a/src/gui/accessible/qaccessiblecache.cpp +++ b/src/gui/accessible/qaccessiblecache.cpp @@ -33,6 +33,8 @@ #include "qaccessiblecache_p.h" +#ifndef QT_NO_ACCESSIBILITY + QT_BEGIN_NAMESPACE /*! @@ -119,3 +121,5 @@ void QAccessibleCache::deleteInterface(QAccessible::Id id, QObject *obj) } QT_END_NAMESPACE + +#endif diff --git a/src/gui/accessible/qaccessiblecache_p.h b/src/gui/accessible/qaccessiblecache_p.h index 97d2b41bbb..9866b8fdb1 100644 --- a/src/gui/accessible/qaccessiblecache_p.h +++ b/src/gui/accessible/qaccessiblecache_p.h @@ -51,6 +51,8 @@ #include "qaccessible.h" +#ifndef QT_NO_ACCESSIBILITY + Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QMacAccessibilityElement)); QT_BEGIN_NAMESPACE @@ -90,4 +92,6 @@ private: QT_END_NAMESPACE +#endif // QT_NO_ACCESSIBILITY + #endif diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index 21c1a2f813..bf3563932d 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -791,6 +791,10 @@ bool QBmpHandler::write(const QImage &img) case QImage::Format_ARGB32: image = img; break; + case QImage::Format_Alpha8: + case QImage::Format_Grayscale8: + image = img.convertToFormat(QImage::Format_Indexed8); + break; default: if (img.hasAlphaChannel()) image = img.convertToFormat(QImage::Format_ARGB32); diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index 6f6bf158c8..d885729cbd 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -1024,7 +1024,7 @@ void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State d->engine->addFile(fileName, size, mode, state); // Check if a "@2x" file exists and add it. - static bool disable2xImageLoading = !qgetenv("QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING").isEmpty(); + static bool disable2xImageLoading = !qEnvironmentVariableIsEmpty("QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING"); if (!disable2xImageLoading && qApp->devicePixelRatio() > 1.0) { int dotIndex = fileName.lastIndexOf(QLatin1Char('.')); if (dotIndex != -1) { diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 4e10b4cb4b..867cb7c322 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -653,7 +653,8 @@ bool QImageData::checkForAlphaPixels() const The following image formats are available in Qt. Values from Format_ARGB8565_Premultiplied to Format_ARGB4444_Premultiplied were added in Qt 4.4. Values Format_RGBX8888, Format_RGBA8888 and Format_RGBA8888_Premultiplied were added in Qt 5.2. Values Format_BGR30, Format_A2BGR30_Premultiplied, - Format_RGB30, Format_A2RGB30_Premultiplied were added in Qt 5.4. + Format_RGB30, Format_A2RGB30_Premultiplied were added in Qt 5.4. Format_Alpha8 and Format_Grayscale8 + were added in Qt 5.5. See the notes after the table. \value Format_Invalid The image is invalid. @@ -709,6 +710,8 @@ bool QImageData::checkForAlphaPixels() const \value Format_A2BGR30_Premultiplied The image is stored using a 32-bit premultiplied ABGR format (2-10-10-10). \value Format_RGB30 The image is stored using a 32-bit RGB format (x-10-10-10). \value Format_A2RGB30_Premultiplied The image is stored using a 32-bit premultiplied ARGB format (2-10-10-10). + \value Format_Alpha8 The image is stored using an 8-bit alpha only format. + \value Format_Grayscale8 The image is stored using an 8-bit grayscale format. \note Drawing into a QImage with QImage::Format_Indexed8 is not supported. @@ -2352,6 +2355,10 @@ bool QImage::allGray() const return false; } return true; + case Format_Alpha8: + return false; + case Format_Grayscale8: + return true; case Format_RGB32: case Format_ARGB32: case Format_ARGB32_Premultiplied: @@ -2405,9 +2412,9 @@ bool QImage::allGray() const /*! For 32-bit images, this function is equivalent to allGray(). - For 8-bpp images, this function returns \c true if color(i) is - QRgb(i, i, i) for all indexes of the color table; otherwise - returns \c false. + For color indexed images, this function returns \c true if + color(i) is QRgb(i, i, i) for all indexes of the color table; + otherwise returns \c false. \sa allGray(), {QImage#Image Formats}{Image Formats} */ @@ -2416,12 +2423,19 @@ bool QImage::isGrayscale() const if (!d) return false; + if (d->format == QImage::Format_Alpha8) + return false; + + if (d->format == QImage::Format_Grayscale8) + return true; + switch (depth()) { case 32: case 24: case 16: return allGray(); case 8: { + Q_ASSERT(d->format == QImage::Format_Indexed8); for (int i = 0; i < colorCount(); i++) if (d->colortable.at(i) != qRgb(i,i,i)) return false; @@ -2998,6 +3012,9 @@ QImage QImage::rgbSwapped_helper() const case NImageFormats: Q_ASSERT(false); break; + case Format_Alpha8: + case Format_Grayscale8: + return *this; case Format_Mono: case Format_MonoLSB: case Format_Indexed8: @@ -3084,6 +3101,9 @@ void QImage::rgbSwapped_inplace() case NImageFormats: Q_ASSERT(false); break; + case Format_Alpha8: + case Format_Grayscale8: + return; case Format_Mono: case Format_MonoLSB: case Format_Indexed8: @@ -4017,7 +4037,7 @@ void QImage::setAlphaChannel(const QImage &alphaChannel) return; // Slight optimization since alphachannels are returned as 8-bit grays. - if (alphaChannel.d->depth == 8 && alphaChannel.isGrayscale()) { + if (alphaChannel.format() == QImage::Format_Alpha8 ||( alphaChannel.d->depth == 8 && alphaChannel.isGrayscale())) { const uchar *src_data = alphaChannel.d->data; const uchar *dest_data = d->data; for (int y=0; y<h; ++y) { @@ -4075,9 +4095,13 @@ void QImage::setAlphaChannel(const QImage &alphaChannel) Most usecases for this function can be replaced with QPainter and using composition modes. + Note this returns a color-indexed image if you want the alpha channel in + the alpha8 format instead use convertToFormat(Format_Alpha8) on the source + image. + \warning This is an expensive function. - \sa setAlphaChannel(), hasAlphaChannel(), + \sa setAlphaChannel(), hasAlphaChannel(), convertToFormat(), {QPixmap#Pixmap Information}{Pixmap}, {QImage#Image Transformations}{Image Transformations} */ @@ -4087,6 +4111,9 @@ QImage QImage::alphaChannel() const if (!d) return QImage(); + if (d->format == QImage::Format_Alpha8) + return *this; + int w = d->width; int h = d->height; @@ -4264,6 +4291,8 @@ static QImage rotated90(const QImage &image) { reinterpret_cast<quint16*>(out.bits()), out.bytesPerLine()); break; + case QImage::Format_Alpha8: + case QImage::Format_Grayscale8: case QImage::Format_Indexed8: qt_memrotate270(reinterpret_cast<const quint8*>(image.bits()), w, h, image.bytesPerLine(), @@ -4330,6 +4359,8 @@ static QImage rotated270(const QImage &image) { reinterpret_cast<quint16*>(out.bits()), out.bytesPerLine()); break; + case QImage::Format_Alpha8: + case QImage::Format_Grayscale8: case QImage::Format_Indexed8: qt_memrotate90(reinterpret_cast<const quint8*>(image.bits()), w, h, image.bytesPerLine(), @@ -4482,24 +4513,17 @@ QImage QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode dImage.d->dpmy = dotsPerMeterY(); dImage.d->devicePixelRatio = devicePixelRatio(); - switch (bpp) { - // initizialize the data - case 8: - 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()); - } else { - memset(dImage.bits(), 0, dImage.byteCount()); - } - break; - case 1: - case 16: - case 24: - case 32: - memset(dImage.bits(), 0x00, dImage.byteCount()); - break; - } + // initizialize the data + if (d->format == QImage::Format_Indexed8) { + 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()); + } else { + memset(dImage.bits(), 0, dImage.byteCount()); + } + } else + memset(dImage.bits(), 0x00, dImage.byteCount()); if (target_format >= QImage::Format_RGB32) { QPainter p(&dImage); @@ -4935,6 +4959,32 @@ static Q_CONSTEXPR QPixelFormat pixelformats[] = { /*PREMULTIPLIED*/ QPixelFormat::Premultiplied, /*INTERPRETATION*/ QPixelFormat::UnsignedInteger, /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), + //QImage::Format_Alpha8: + QPixelFormat(QPixelFormat::Alpha, + /*First*/ 0, + /*SECOND*/ 0, + /*THIRD*/ 0, + /*FOURTH*/ 0, + /*FIFTH*/ 0, + /*ALPHA*/ 8, + /*ALPHA USAGE*/ QPixelFormat::UsesAlpha, + /*ALPHA POSITION*/ QPixelFormat::AtBeginning, + /*PREMULTIPLIED*/ QPixelFormat::Premultiplied, + /*INTERPRETATION*/ QPixelFormat::UnsignedByte, + /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), + //QImage::Format_Grayscale8: + QPixelFormat(QPixelFormat::Grayscale, + /*GRAY*/ 8, + /*SECOND*/ 0, + /*THIRD*/ 0, + /*FOURTH*/ 0, + /*FIFTH*/ 0, + /*ALPHA*/ 0, + /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha, + /*ALPHA POSITION*/ QPixelFormat::AtBeginning, + /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied, + /*INTERPRETATION*/ QPixelFormat::UnsignedByte, + /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), }; Q_STATIC_ASSERT(sizeof(pixelformats) / sizeof(*pixelformats) == QImage::NImageFormats); diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index 55b8690c77..5ba9a890d4 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -106,20 +106,16 @@ public: Format_RGBX8888, Format_RGBA8888, Format_RGBA8888_Premultiplied, -#if 0 - // reserved for future use - Format_RGB15, - Format_Grayscale16, - Format_Grayscale8, - Format_Grayscale4, - Format_Grayscale4LSB, - Format_Grayscale2, - Format_Grayscale2LSB -#endif Format_BGR30, Format_A2BGR30_Premultiplied, Format_RGB30, Format_A2RGB30_Premultiplied, + Format_Alpha8, + Format_Grayscale8, +#if 0 + // reserved for future use + Format_Grayscale16, +#endif #ifndef Q_QDOC NImageFormats #endif diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 17563b19c3..2e8fc1963d 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -1861,11 +1861,154 @@ static void convert_Mono_to_Indexed8(QImageData *dest, const QImageData *src, Qt } } +static void convert_Indexed8_to_Alpha8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_Indexed8); + Q_ASSERT(dest->format == QImage::Format_Alpha8); + + uchar translate[256]; + const QVector<QRgb> &colors = src->colortable; + bool simpleCase = (colors.size() == 256); + for (int i = 0; i < colors.size(); ++i) { + uchar alpha = qAlpha(colors[i]); + translate[i] = alpha; + simpleCase = simpleCase && (alpha == i); + } + + 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) { + dest->data[i] = translate[src->data[i]]; + } + } +} + +static void convert_Indexed8_to_Grayscale8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_Indexed8); + Q_ASSERT(dest->format == QImage::Format_Grayscale8); + + uchar translate[256]; + const QVector<QRgb> &colors = src->colortable; + bool simpleCase = (colors.size() == 256); + for (int i = 0; i < colors.size(); ++i) { + uchar gray = qGray(colors[i]); + translate[i] = gray; + simpleCase = simpleCase && (gray == i); + } + + 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) { + dest->data[i] = translate[src->data[i]]; + } + } +} + +static bool convert_Indexed8_to_Alpha8_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Indexed8); + + // Just check if this is an Alpha8 in Indexed8 disguise. + const QVector<QRgb> &colors = data->colortable; + if (colors.size() != 256) + return false; + for (int i = 0; i < colors.size(); ++i) { + if (i != qAlpha(colors[i])) + return false; + } + + data->colortable.clear(); + data->format = QImage::Format_Alpha8; + + return true; +} + +static bool convert_Indexed8_to_Grayscale8_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Indexed8); + + // Just check if this is a Grayscale8 in Indexed8 disguise. + const QVector<QRgb> &colors = data->colortable; + if (colors.size() != 256) + return false; + for (int i = 0; i < colors.size(); ++i) { + if (i != qGray(colors[i])) + return false; + } + + data->colortable.clear(); + data->format = QImage::Format_Grayscale8; + + return true; +} + +static void convert_Alpha8_to_Indexed8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_Alpha8); + Q_ASSERT(dest->format == QImage::Format_Indexed8); + + memcpy(dest->data, src->data, src->bytes_per_line * src->height); + + QVector<QRgb> colors(256); + for (int i=0; i<256; ++i) + colors[i] = qRgba(0, 0, 0, i); + + dest->colortable = colors; +} + +static void convert_Grayscale8_to_Indexed8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_Grayscale8); + Q_ASSERT(dest->format == QImage::Format_Indexed8); + + memcpy(dest->data, src->data, src->bytes_per_line * src->height); + + QVector<QRgb> colors(256); + for (int i=0; i<256; ++i) + colors[i] = qRgb(i, i, i); + + dest->colortable = colors; +} + +static bool convert_Alpha8_to_Indexed8_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Alpha8); + + QVector<QRgb> colors(256); + for (int i=0; i<256; ++i) + colors[i] = qRgba(0, 0, 0, i); + + data->colortable = colors; + data->format = QImage::Format_Indexed8; + + return true; +} + +static bool convert_Grayscale8_to_Indexed8_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Grayscale8); + + QVector<QRgb> colors(256); + for (int i=0; i<256; ++i) + colors[i] = qRgb(i, i, i); + + data->colortable = colors; + data->format = QImage::Format_Indexed8; + + return true; +} + + // first index source, second dest Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats] = { { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, @@ -1886,7 +2029,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_Mono { @@ -1908,7 +2051,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_MonoLSB { @@ -1930,7 +2073,9 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, + convert_Indexed8_to_Alpha8, + convert_Indexed8_to_Grayscale8, }, // Format_Indexed8 { @@ -1957,6 +2102,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_RGB_to_RGB30<PixelOrderBGR>, convert_RGB_to_RGB30<PixelOrderRGB>, convert_RGB_to_RGB30<PixelOrderRGB>, + 0, 0 }, // Format_RGB32 { @@ -1983,6 +2129,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, convert_RGB_to_RGB30<PixelOrderRGB>, 0, + 0, 0 }, // Format_ARGB32 { @@ -2009,6 +2156,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_ARGB_to_A2RGB30<PixelOrderBGR>, convert_ARGB_PM_to_RGB30<PixelOrderRGB>, convert_ARGB_to_A2RGB30<PixelOrderRGB>, + 0, 0 }, // Format_ARGB32_Premultiplied { @@ -2030,7 +2178,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB16 { @@ -2052,7 +2200,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB8565_Premultiplied { @@ -2074,7 +2222,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB666 { @@ -2096,7 +2244,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB6666_Premultiplied { @@ -2118,7 +2266,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB555 { @@ -2140,7 +2288,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB8555_Premultiplied { @@ -2162,7 +2310,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB888 { @@ -2184,7 +2332,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB444 { @@ -2205,7 +2353,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB4444_Premultiplied { 0, @@ -2227,7 +2375,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, mask_alpha_converter_RGBx, mask_alpha_converter_RGBx, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBX8888 { 0, @@ -2252,9 +2400,9 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_ARGB_to_ARGB_PM, #else 0, - 0 + 0, #endif - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBA8888 { @@ -2281,9 +2429,9 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat #else 0, 0, - 0 + 0, #endif - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBA8888_Premultiplied { @@ -2309,7 +2457,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, convert_passthrough, convert_BGR30_to_RGB30, - convert_BGR30_to_RGB30 + convert_BGR30_to_RGB30, + 0, 0 }, // Format_BGR30 { 0, @@ -2334,7 +2483,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_A2RGB30_PM_to_RGB30, 0, 0, - convert_BGR30_to_RGB30 + convert_BGR30_to_RGB30, + 0, 0 }, // Format_BGR30A2_Premultiplied { 0, @@ -2360,6 +2510,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, convert_passthrough, + 0, 0 }, // Format_RGB30 { 0, @@ -2385,19 +2536,61 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_BGR30_to_RGB30, convert_A2RGB30_PM_to_RGB30, 0, + 0, + 0, }, // Format_RGB30A2_Premultiplied + { + 0, + 0, + 0, + convert_Alpha8_to_Indexed8, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0, 0, 0, 0, 0, 0 + }, // Format_Alpha8 + { + 0, + 0, + 0, + convert_Grayscale8_to_Indexed8, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0, 0, 0, 0, 0, 0 + } // Format_Grayscale8 }; InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats] = { { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_Mono { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_MonoLSB { 0, @@ -2418,7 +2611,9 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, + convert_Indexed8_to_Alpha8_inplace, + convert_Indexed8_to_Grayscale8_inplace, }, // Format_Indexed8 { 0, @@ -2439,7 +2634,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB32 { 0, @@ -2464,7 +2659,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, convert_ARGB_to_RGBA_inplace, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB32 { 0, @@ -2486,34 +2681,34 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, convert_ARGB_to_RGBA_inplace, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_ARGB32_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB16 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB8565_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB666 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB6666_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB555 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB8555_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB888 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB444 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB4444_Premultiplied { 0, @@ -2535,7 +2730,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, convert_passthrough_inplace<QImage::Format_RGBA8888>, convert_passthrough_inplace<QImage::Format_RGBA8888_Premultiplied>, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBX8888 { 0, @@ -2557,7 +2752,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBA8888 { 0, @@ -2579,7 +2774,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 }, // Format_RGBA8888_Premultiplied { 0, @@ -2604,7 +2799,8 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, convert_passthrough_inplace<QImage::Format_A2BGR30_Premultiplied>, convert_BGR30_to_RGB30_inplace, - convert_BGR30_to_RGB30_inplace + convert_BGR30_to_RGB30_inplace, + 0, 0 }, // Format_BGR30 { 0, @@ -2629,7 +2825,8 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma convert_A2RGB30_PM_to_RGB30_inplace, 0, 0, - convert_BGR30_to_RGB30_inplace + convert_BGR30_to_RGB30_inplace, + 0, 0 }, // Format_BGR30A2_Premultiplied { 0, @@ -2654,7 +2851,8 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma convert_BGR30_to_RGB30_inplace, convert_BGR30_to_RGB30_inplace, 0, - convert_passthrough_inplace<QImage::Format_A2RGB30_Premultiplied> + convert_passthrough_inplace<QImage::Format_A2RGB30_Premultiplied>, + 0, 0 }, // Format_RGB30 { 0, @@ -2679,8 +2877,61 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, convert_BGR30_to_RGB30_inplace, convert_A2RGB30_PM_to_RGB30_inplace, - 0 + 0, + 0, 0 }, // Format_RGB30A2_Premultiplied + { + 0, + 0, + 0, + convert_Alpha8_to_Indexed8_inplace, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0 + }, // Format_Alpha8 + { + 0, + 0, + 0, + convert_Grayscale8_to_Indexed8_inplace, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0 + } // Format_Grayscale8 }; void qInitImageConversions() diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h index eec54ed4eb..26c42b988e 100644 --- a/src/gui/image/qimage_p.h +++ b/src/gui/image/qimage_p.h @@ -128,6 +128,8 @@ inline int qt_depthForFormat(QImage::Format format) depth = 1; break; case QImage::Format_Indexed8: + case QImage::Format_Alpha8: + case QImage::Format_Grayscale8: depth = 8; break; case QImage::Format_RGB32: diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index a7a08a6fee..ad84b0a091 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -1290,7 +1290,7 @@ bool QImageReader::read(QImage *image) } // successful read; check for "@2x" file name suffix and set device pixel ratio. - static bool disable2xImageLoading = !qgetenv("QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING").isEmpty(); + static bool disable2xImageLoading = !qEnvironmentVariableIsEmpty("QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING"); if (!disable2xImageLoading && QFileInfo(fileName()).baseName().endsWith(QLatin1String("@2x"))) { image->setDevicePixelRatio(2.0); } diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp index 87992bcced..ae30de634a 100644 --- a/src/gui/image/qjpeghandler.cpp +++ b/src/gui/image/qjpeghandler.cpp @@ -220,7 +220,7 @@ inline static bool read_jpeg_format(QImage::Format &format, j_decompress_ptr cin bool result = true; switch (cinfo->output_components) { case 1: - format = QImage::Format_Indexed8; + format = QImage::Format_Grayscale8; break; case 3: case 4: @@ -240,7 +240,7 @@ static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info, QImage::Format format; switch (info->output_components) { case 1: - format = QImage::Format_Indexed8; + format = QImage::Format_Grayscale8; break; case 3: case 4: @@ -250,16 +250,9 @@ static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info, return false; // unsupported format } - if (dest->size() != size || dest->format() != format) { + if (dest->size() != size || dest->format() != format) *dest = QImage(size, format); - if (format == QImage::Format_Indexed8) { - dest->setColorCount(256); - for (int i = 0; i < 256; i++) - dest->setColor(i, qRgb(i,i,i)); - } - } - return !dest->isNull(); } @@ -550,6 +543,9 @@ static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile in bool success = false; const QVector<QRgb> cmap = image.colorTable(); + if (image.format() == QImage::Format_Invalid || image.format() == QImage::Format_Alpha8) + return false; + struct jpeg_compress_struct cinfo; JSAMPROW row_pointer[1]; row_pointer[0] = 0; @@ -573,19 +569,23 @@ static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile in cinfo.image_width = image.width(); cinfo.image_height = image.height(); - bool gray=false; + bool gray = false; switch (image.format()) { case QImage::Format_Mono: case QImage::Format_MonoLSB: case QImage::Format_Indexed8: gray = true; - for (int i = image.colorCount(); gray && i--;) { - gray = gray & (qRed(cmap[i]) == qGreen(cmap[i]) && - qRed(cmap[i]) == qBlue(cmap[i])); + for (int i = image.colorCount(); gray && i; i--) { + gray = gray & qIsGray(cmap[i-1]); } cinfo.input_components = gray ? 1 : 3; cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB; break; + case QImage::Format_Grayscale8: + gray = true; + cinfo.input_components = 1; + cinfo.in_color_space = JCS_GRAYSCALE; + break; default: cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; @@ -670,6 +670,9 @@ static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile in } } break; + case QImage::Format_Grayscale8: + memcpy(row, image.constScanLine(cinfo.next_scanline), w); + break; case QImage::Format_RGB888: memcpy(row, image.constScanLine(cinfo.next_scanline), w * 3); break; diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp index 65e7fb0096..9c9db1c9c1 100644 --- a/src/gui/image/qpixmap_raster.cpp +++ b/src/gui/image/qpixmap_raster.cpp @@ -203,9 +203,14 @@ void QRasterPlatformPixmap::fill(const QColor &color) pixel = qPremultiply(color.rgba()); const QPixelLayout *layout = &qPixelLayouts[image.format()]; layout->convertFromARGB32PM(&pixel, &pixel, 1, layout, 0); - } else { + } else if (image.format() == QImage::Format_Alpha8) { + pixel = qAlpha(color.rgba()); + } else if (image.format() == QImage::Format_Grayscale8) { + pixel = qGray(color.rgba()); + } else + { pixel = 0; - // ### what about 8 bits + // ### what about 8 bit indexed? } image.fill(pixel); diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index 17a0dd3eb9..d09ed0fda7 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -295,6 +295,15 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scal png_set_swap_alpha(png_ptr); png_read_update_info(png_ptr, info_ptr); + } else if (bit_depth == 8 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + png_set_expand(png_ptr); + if (image.size() != QSize(width, height) || image.format() != QImage::Format_Grayscale8) { + image = QImage(width, height, QImage::Format_Grayscale8); + if (image.isNull()) + return; + } + + png_read_update_info(png_ptr, info_ptr); } else { if (bit_depth == 16) png_set_strip_16(png_ptr); @@ -666,6 +675,8 @@ QImage::Format QPngHandlerPrivate::readImageFormat() format = QImage::Format_Mono; } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { format = QImage::Format_ARGB32; + } else if (bit_depth == 8 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + format = QImage::Format_Grayscale8; } else { format = QImage::Format_Indexed8; } @@ -857,6 +868,8 @@ bool Q_INTERNAL_WIN_NO_THROW QPNGImageWriter::writeImage(const QImage& image, vo else color_type = PNG_COLOR_TYPE_PALETTE; } + else if (image.format() == QImage::Format_Grayscale8) + color_type = PNG_COLOR_TYPE_GRAY; else if (image.hasAlphaChannel()) color_type = PNG_COLOR_TYPE_RGB_ALPHA; else @@ -955,6 +968,7 @@ bool Q_INTERNAL_WIN_NO_THROW QPNGImageWriter::writeImage(const QImage& image, vo case QImage::Format_Mono: case QImage::Format_MonoLSB: case QImage::Format_Indexed8: + case QImage::Format_Grayscale8: case QImage::Format_RGB32: case QImage::Format_ARGB32: case QImage::Format_RGB888: diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp index 314abca9f0..e1c76cce7f 100644 --- a/src/gui/image/qppmhandler.cpp +++ b/src/gui/image/qppmhandler.cpp @@ -122,7 +122,7 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q case '2': // ascii PGM case '5': // raw PGM nbits = 8; - format = QImage::Format_Indexed8; + format = QImage::Format_Grayscale8; break; case '3': // ascii PPM case '6': // raw PPM @@ -200,13 +200,13 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q *p++ = b; } } else if (nbits == 8) { - if (mcc == maxc) { + if (mcc == 255) { while (n--) { *p++ = read_pbm_int(device); } } else { while (n--) { - *p++ = read_pbm_int(device) * maxc / mcc; + *p++ = read_pbm_int(device) * 255 / mcc; } } } else { // 32 bits @@ -233,14 +233,10 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q } } - if (nbits == 1) { // bitmap + if (format == QImage::Format_Mono) { outImage->setColorCount(2); - outImage->setColor(0, qRgb(255,255,255)); // white - outImage->setColor(1, qRgb(0,0,0)); // black - } else if (nbits == 8) { // graymap - outImage->setColorCount(maxc+1); - for (int i=0; i<=maxc; i++) - outImage->setColor(i, qRgb(i*255/maxc,i*255/maxc,i*255/maxc)); + outImage->setColor(0, qRgb(255,255,255)); // white + outImage->setColor(1, qRgb(0,0,0)); // black } return true; @@ -257,6 +253,8 @@ static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QBy if (format == "pbm") { image = image.convertToFormat(QImage::Format_Mono); + } else if (gray) { + image = image.convertToFormat(QImage::Format_Grayscale8); } else { switch (image.format()) { case QImage::Format_Mono: @@ -317,63 +315,77 @@ static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QBy str.append("255\n"); if (out->write(str, str.length()) != str.length()) return false; - QVector<QRgb> color = image.colorTable(); - uint bpl = w*(gray ? 1 : 3); - uchar *buf = new uchar[bpl]; - for (uint y=0; y<h; y++) { - uchar *b = image.scanLine(y); - uchar *p = buf; - uchar *end = buf+bpl; - if (gray) { - while (p < end) { - uchar g = (uchar)qGray(color[*b++]); - *p++ = g; + uint bpl = w * (gray ? 1 : 3); + uchar *buf = new uchar[bpl]; + if (image.format() == QImage::Format_Indexed8) { + QVector<QRgb> color = image.colorTable(); + for (uint y=0; y<h; y++) { + uchar *b = image.scanLine(y); + uchar *p = buf; + uchar *end = buf+bpl; + if (gray) { + while (p < end) { + uchar g = (uchar)qGray(color[*b++]); + *p++ = g; + } + } else { + while (p < end) { + QRgb rgb = color[*b++]; + *p++ = qRed(rgb); + *p++ = qGreen(rgb); + *p++ = qBlue(rgb); + } } - } else { - while (p < end) { - QRgb rgb = color[*b++]; - *p++ = qRed(rgb); - *p++ = qGreen(rgb); - *p++ = qBlue(rgb); + if (bpl != (uint)out->write((char*)buf, bpl)) + return false; + } + } else { + for (uint y=0; y<h; y++) { + uchar *b = image.scanLine(y); + uchar *p = buf; + uchar *end = buf + bpl; + if (gray) { + while (p < end) + *p++ = *b++; + } else { + while (p < end) { + uchar color = *b++; + *p++ = color; + *p++ = color; + *p++ = color; + } } + if (bpl != (uint)out->write((char*)buf, bpl)) + return false; } - if (bpl != (uint)out->write((char*)buf, bpl)) - return false; } delete [] buf; - } break; + } case 32: { - str.insert(1, gray ? '5' : '6'); + str.insert(1, '6'); str.append("255\n"); if (out->write(str, str.length()) != str.length()) return false; - uint bpl = w*(gray ? 1 : 3); + uint bpl = w * 3; uchar *buf = new uchar[bpl]; for (uint y=0; y<h; y++) { QRgb *b = (QRgb*)image.scanLine(y); uchar *p = buf; uchar *end = buf+bpl; - if (gray) { - while (p < end) { - uchar g = (uchar)qGray(*b++); - *p++ = g; - } - } else { - while (p < end) { - QRgb rgb = *b++; - *p++ = qRed(rgb); - *p++ = qGreen(rgb); - *p++ = qBlue(rgb); - } + while (p < end) { + QRgb rgb = *b++; + *p++ = qRed(rgb); + *p++ = qGreen(rgb); + *p++ = qBlue(rgb); } if (bpl != (uint)out->write((char*)buf, bpl)) return false; } delete [] buf; - } break; + } default: return false; @@ -488,11 +500,11 @@ QVariant QPpmHandler::option(ImageOption option) const switch (type) { case '1': // ascii PBM case '4': // raw PBM - format = QImage::Format_Mono; - break; + format = QImage::Format_Mono; + break; case '2': // ascii PGM case '5': // raw PGM - format = QImage::Format_Indexed8; + format = QImage::Format_Grayscale8; break; case '3': // ascii PPM case '6': // raw PPM diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index a8539e8013..a0b6256e72 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -1324,6 +1324,55 @@ QExposeEvent::~QExposeEvent() } /*! + \class QPlatformSurfaceEvent + \since 5.5 + \brief The QPlatformSurfaceEvent class is used to notify about native platform surface events. + \inmodule QtGui + + \ingroup events + + Platform window events are synchronously sent to windows and offscreen surfaces when their + underlying native surfaces are created or are about to be destroyed. + + Applications can respond to these events to know when the underlying platform + surface exists. +*/ + +/*! + \enum QPlatformSurfaceEvent::SurfaceEventType + + This enum describes the type of platform surface event. The possible types are: + + \value SurfaceCreated The underlying native surface has been created + \value SurfaceAboutToBeDestroyed The underlying native surface will be destroyed immediately after this event + + The \c SurfaceAboutToBeDestroyed event type is useful as a means of stopping rendering to + a platform window before it is destroyed. +*/ + +/*! + \fn QPlatformSurfaceEvent::SurfaceEventType QPlatformSurfaceEvent::surfaceEventType() const + + Returns the specific type of platform surface event. +*/ + +/*! + Constructs a platform surface event for the given \a surfaceEventType. +*/ +QPlatformSurfaceEvent::QPlatformSurfaceEvent(SurfaceEventType surfaceEventType) + : QEvent(PlatformSurface) + , m_surfaceEventType(surfaceEventType) +{ +} + +/*! + \internal +*/ +QPlatformSurfaceEvent::~QPlatformSurfaceEvent() +{ +} + +/*! \fn const QRegion &QExposeEvent::region() const Returns the window area that has been exposed. The region is given in local coordinates. @@ -3554,6 +3603,8 @@ static const char *eventClassName(QEvent::Type t) return "QGraphicsSceneEvent"; case QEvent::Timer: return "QTimerEvent"; + case QEvent::PlatformSurface: + return "QPlatformSurfaceEvent"; default: break; } @@ -3812,6 +3863,18 @@ QDebug operator<<(QDebug dbg, const QEvent *e) case QEvent::Timer: dbg << "QTimerEvent(id=" << static_cast<const QTimerEvent *>(e)->timerId() << ')'; break; + case QEvent::PlatformSurface: + dbg << "QPlatformSurfaceEvent(surfaceEventType="; + switch (static_cast<const QPlatformSurfaceEvent *>(e)->surfaceEventType()) { + case QPlatformSurfaceEvent::SurfaceCreated: + dbg << "SurfaceCreated"; + break; + case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed: + dbg << "SurfaceAboutToBeDestroyed"; + break; + } + dbg << ')'; + break; default: dbg << eventClassName(type) << '(' << eventTypeName(type) << ", " << (const void *)e << ", type = " << e->type() << ')'; diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 6fca54e2b6..0b6d96a590 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -162,6 +162,8 @@ protected: class Q_GUI_EXPORT QWheelEvent : public QInputEvent { public: + enum { DefaultDeltasPerStep = 120 }; + QWheelEvent(const QPointF &pos, int delta, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Qt::Orientation orient = Qt::Vertical); @@ -408,6 +410,23 @@ protected: QRegion rgn; }; +class Q_GUI_EXPORT QPlatformSurfaceEvent : public QEvent +{ +public: + enum SurfaceEventType { + SurfaceCreated, + SurfaceAboutToBeDestroyed + }; + + explicit QPlatformSurfaceEvent(SurfaceEventType surfaceEventType); + ~QPlatformSurfaceEvent(); + + inline SurfaceEventType surfaceEventType() const { return m_surfaceEventType; } + +protected: + SurfaceEventType m_surfaceEventType; +}; + class Q_GUI_EXPORT QResizeEvent : public QEvent { public: diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index fe92ead846..e421f79e91 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -215,11 +215,6 @@ static inline void clearFontUnlocked() QGuiApplicationPrivate::app_font = 0; } -static inline bool isPopupWindow(const QWindow *w) -{ - return (w->flags() & Qt::WindowType_Mask) == Qt::Popup; -} - // Geometry specification for top level windows following the convention of the // -geometry command line arguments in X11 (see XParseGeometry). struct QWindowGeometrySpecification @@ -671,7 +666,7 @@ static void updateBlockedStatusRecursion(QWindow *window, bool shouldBeBlocked) void QGuiApplicationPrivate::updateBlockedStatus(QWindow *window) { bool shouldBeBlocked = false; - if (!isPopupWindow(window) && !self->modalWindowList.isEmpty()) + if (!QWindowPrivate::get(window)->isPopup() && !self->modalWindowList.isEmpty()) shouldBeBlocked = self->isWindowBlocked(window); updateBlockedStatusRecursion(window, shouldBeBlocked); } @@ -681,7 +676,7 @@ void QGuiApplicationPrivate::showModalWindow(QWindow *modal) self->modalWindowList.prepend(modal); // Send leave for currently entered window if it should be blocked - if (currentMouseWindow && !isPopupWindow(currentMouseWindow)) { + if (currentMouseWindow && !QWindowPrivate::get(currentMouseWindow)->isPopup()) { bool shouldBeBlocked = self->isWindowBlocked(currentMouseWindow); if (shouldBeBlocked) { // Remove the new window from modalWindowList temporarily so leave can go through @@ -1366,6 +1361,8 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate() } #endif + platform_integration->destroy(); + delete platform_theme; platform_theme = 0; delete platform_integration; @@ -1511,18 +1508,6 @@ int QGuiApplication::exec() */ bool QGuiApplication::notify(QObject *object, QEvent *event) { -#ifndef QT_NO_SHORTCUT - if (event->type() == QEvent::KeyPress) { - // Try looking for a Shortcut before sending key events - QWindow *w = qobject_cast<QWindow *>(object); - QObject *focus = w ? w->focusObject() : 0; - if (!focus) - focus = object; - if (QGuiApplicationPrivate::instance()->shortcutMap.tryShortcutEvent(focus, static_cast<QKeyEvent *>(event))) - return true; - } -#endif - if (object->isWindowType()) QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(static_cast<QWindow *>(object), event); return QCoreApplication::notify(object, event); @@ -1686,7 +1671,8 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo // will update the global mouse position and cause the second event to be a button only event. QWindowSystemInterfacePrivate::MouseEvent moveEvent(e->window.data(), e->timestamp, e->type, e->localPos, e->globalPos, buttons, e->modifiers, e->source); - moveEvent.synthetic = e->synthetic; + if (e->flags & QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic) + moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; processMouseEvent(&moveEvent); Q_ASSERT(e->globalPos == QGuiApplicationPrivate::lastCursorPosition); // continue with processing mouse button change event @@ -1698,7 +1684,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo QPointF localPoint = e->localPos; QPointF globalPoint = e->globalPos; - if (e->nullWindow) { + if (e->nullWindow()) { window = QGuiApplication::topLevelAt(globalPoint.toPoint()); if (window) { QPointF delta = globalPoint - globalPoint.toPoint(); @@ -1751,7 +1737,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo ev.setTimestamp(e->timestamp); setMouseEventSource(&ev, e->source); #ifndef QT_NO_CURSOR - if (!e->synthetic) { + if (!e->synthetic()) { if (const QScreen *screen = window->screen()) if (QPlatformCursor *cursor = screen->handle()->cursor()) cursor->pointerEvent(ev); @@ -1769,7 +1755,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo } QGuiApplication::sendSpontaneousEvent(window, &ev); - if (!e->synthetic && !ev.isAccepted() + if (!e->synthetic() && !ev.isAccepted() && !frameStrut && qApp->testAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents)) { if (!m_fakeTouchDevice) { @@ -1800,12 +1786,12 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::convertTouchPoints(points, &type); QWindowSystemInterfacePrivate::TouchEvent fake(window, e->timestamp, type, m_fakeTouchDevice, touchPoints, e->modifiers); - fake.synthetic = true; + fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; processTouchEvent(&fake); } if (doubleClick) { mousePressButton = Qt::NoButton; - if (!e->window.isNull() || e->nullWindow) { // QTBUG-36364, check if window closed in response to press + if (!e->window.isNull() || e->nullWindow()) { // QTBUG-36364, check if window closed in response to press const QEvent::Type doubleClickType = frameStrut ? QEvent::NonClientAreaMouseButtonDblClick : QEvent::MouseButtonDblClick; QMouseEvent dblClickEvent(doubleClickType, localPoint, localPoint, globalPoint, button, buttons, e->modifiers); @@ -1823,7 +1809,7 @@ void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::Wh QPointF globalPoint = e->globalPos; QPointF localPoint = e->localPos; - if (e->nullWindow) { + if (e->nullWindow()) { window = QGuiApplication::topLevelAt(globalPoint.toPoint()); if (window) { QPointF delta = globalPoint - globalPoint.toPoint(); @@ -1854,7 +1840,7 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE { QWindow *window = e->window.data(); modifier_buttons = e->modifiers; - if (e->nullWindow + if (e->nullWindow() #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK) || e->key == Qt::Key_Back || e->key == Qt::Key_Menu #endif @@ -2095,7 +2081,7 @@ void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::T // subsequent events up to the release are delivered to that same window. // If window is given, just send to that. if (type == QEvent::TabletPress) { - if (e->nullWindow) { + if (e->nullWindow()) { window = QGuiApplication::topLevelAt(e->global.toPoint()); localValid = false; } @@ -2103,7 +2089,7 @@ void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::T return; tabletPressTarget = window; } else { - if (e->nullWindow) { + if (e->nullWindow()) { window = tabletPressTarget; localValid = false; } @@ -2237,7 +2223,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To touchEvent.setWindow(*winIt); QGuiApplication::sendSpontaneousEvent(*winIt, &touchEvent); } - if (!self->synthesizedMousePoints.isEmpty() && !e->synthetic) { + if (!self->synthesizedMousePoints.isEmpty() && !e->synthetic()) { for (QHash<QWindow *, SynthesizedMouseData>::const_iterator synthIt = self->synthesizedMousePoints.constBegin(), synthItEnd = self->synthesizedMousePoints.constEnd(); synthIt != synthItEnd; ++synthIt) { if (!synthIt->window) @@ -2249,7 +2235,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To buttons & ~Qt::LeftButton, e->modifiers, Qt::MouseEventSynthesizedByQt); - fake.synthetic = true; + fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; processMouseEvent(&fake); } self->synthesizedMousePoints.clear(); @@ -2428,7 +2414,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To } QGuiApplication::sendSpontaneousEvent(w, &touchEvent); - if (!e->synthetic && !touchEvent.isAccepted() && synthesizeMouseFromTouchEventsEnabled()) { + if (!e->synthetic() && !touchEvent.isAccepted() && synthesizeMouseFromTouchEventsEnabled()) { // exclude touchpads as those generate their own mouse events if (touchEvent.device()->type() != QTouchDevice::TouchPad) { Qt::MouseButtons b = eventType == QEvent::TouchEnd ? Qt::NoButton : Qt::LeftButton; @@ -2451,7 +2437,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To b | (buttons & ~Qt::LeftButton), e->modifiers, Qt::MouseEventSynthesizedByQt); - fake.synthetic = true; + fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; processMouseEvent(&fake); break; } diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index 209d1dd499..c0e8a8454e 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -289,6 +289,7 @@ void Q_GUI_EXPORT qt_set_sequence_auto_mnemonic(bool b) { qt_sequence_no_mnemoni \row \li DeleteCompleteLine \li (none) \li (none) \li Ctrl+U \li Ctrl+U \row \li InsertParagraphSeparator \li Enter \li Enter \li Enter \li Enter \row \li InsertLineSeparator \li Shift+Enter \li Meta+Enter, Meta+O \li Shift+Enter \li Shift+Enter + \row \li Backspace \li (none) \li Meta+H \li (none) \li (none) \endtable Note that, since the key sequences used for the standard shortcuts differ @@ -679,6 +680,7 @@ static const struct { \value AddTab Add new tab. \value Back Navigate back. + \value Backspace Delete previous character. \value Bold Bold text. \value Close Close document/tab. \value Copy Copy. diff --git a/src/gui/kernel/qkeysequence.h b/src/gui/kernel/qkeysequence.h index 5a2ce5a8b9..fd2a3e9d7b 100644 --- a/src/gui/kernel/qkeysequence.h +++ b/src/gui/kernel/qkeysequence.h @@ -134,7 +134,8 @@ public: Quit, FullScreen, Deselect, - DeleteCompleteLine + DeleteCompleteLine, + Backspace }; enum SequenceFormat { diff --git a/src/gui/kernel/qoffscreensurface.cpp b/src/gui/kernel/qoffscreensurface.cpp index 5cf77de5d8..fb1dfd8df5 100644 --- a/src/gui/kernel/qoffscreensurface.cpp +++ b/src/gui/kernel/qoffscreensurface.cpp @@ -180,6 +180,9 @@ void QOffscreenSurface::create() d->offscreenWindow->setGeometry(0, 0, d->size.width(), d->size.height()); d->offscreenWindow->create(); } + + QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceCreated); + QGuiApplication::sendEvent(this, &e); } } @@ -191,6 +194,10 @@ void QOffscreenSurface::create() void QOffscreenSurface::destroy() { Q_D(QOffscreenSurface); + + QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed); + QGuiApplication::sendEvent(this, &e); + delete d->platformOffscreenSurface; d->platformOffscreenSurface = 0; if (d->offscreenWindow) { diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp index 1a8a534e11..07a7c601fa 100644 --- a/src/gui/kernel/qopenglcontext.cpp +++ b/src/gui/kernel/qopenglcontext.cpp @@ -596,6 +596,7 @@ bool QOpenGLContext::create() d->platformGLContext = QGuiApplicationPrivate::platformIntegration()->createPlatformOpenGLContext(this); if (!d->platformGLContext) return false; + d->platformGLContext->initialize(); d->platformGLContext->setContext(this); if (!d->platformGLContext->isSharing()) d->shareContext = 0; diff --git a/src/gui/kernel/qpaintdevicewindow.cpp b/src/gui/kernel/qpaintdevicewindow.cpp index cf8653426f..d5b15ed5f5 100644 --- a/src/gui/kernel/qpaintdevicewindow.cpp +++ b/src/gui/kernel/qpaintdevicewindow.cpp @@ -76,7 +76,7 @@ void QPaintDeviceWindow::update(const QRect &rect) { Q_D(QPaintDeviceWindow); d->dirtyRegion += rect; - d->triggerUpdate(); + requestUpdate(); } /*! @@ -89,7 +89,7 @@ void QPaintDeviceWindow::update(const QRegion ®ion) { Q_D(QPaintDeviceWindow); d->dirtyRegion += region; - d->triggerUpdate(); + requestUpdate(); } /*! @@ -179,7 +179,6 @@ bool QPaintDeviceWindow::event(QEvent *event) Q_D(QPaintDeviceWindow); if (event->type() == QEvent::UpdateRequest) { - d->paintEventSent = false; if (handle()) // platform window may be gone when the window is closed during app exit d->handleUpdateEvent(); return true; diff --git a/src/gui/kernel/qpaintdevicewindow_p.h b/src/gui/kernel/qpaintdevicewindow_p.h index 1935bb6db5..865861125b 100644 --- a/src/gui/kernel/qpaintdevicewindow_p.h +++ b/src/gui/kernel/qpaintdevicewindow_p.h @@ -46,8 +46,6 @@ class Q_GUI_EXPORT QPaintDeviceWindowPrivate : public QWindowPrivate Q_DECLARE_PUBLIC(QPaintDeviceWindow) public: - QPaintDeviceWindowPrivate() : paintEventSent(false) { } - virtual void beginPaint(const QRegion ®ion) { Q_UNUSED(region); @@ -82,15 +80,6 @@ public: return true; } - void triggerUpdate() - { - Q_Q(QPaintDeviceWindow); - if (!paintEventSent) { - QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest)); - paintEventSent = true; - } - } - void doFlush(const QRegion ®ion) { QRegion toFlush = region; @@ -113,7 +102,6 @@ public: private: QRegion dirtyRegion; - bool paintEventSent; }; diff --git a/src/gui/kernel/qpixelformat.cpp b/src/gui/kernel/qpixelformat.cpp index cfa8a96d69..7e50a0cd41 100644 --- a/src/gui/kernel/qpixelformat.cpp +++ b/src/gui/kernel/qpixelformat.cpp @@ -69,6 +69,7 @@ QT_BEGIN_NAMESPACE \enum QPixelFormat::ColorModel This enum type is used to describe the color model of the pixelformat. + Alpha was added in 5.5. \value RGB The color model is RGB. @@ -86,6 +87,8 @@ QT_BEGIN_NAMESPACE \value HSV The color model is HSV. \value YUV The color model is YUV. + + \value Alpha There is no color model, only alpha is used. */ /*! @@ -282,6 +285,21 @@ QT_BEGIN_NAMESPACE */ /*! + \fn QPixelFormat qPixelFormatAlpha(uchar channelSize, + QPixelFormat::TypeInterpretation typeInterpretation = QPixelFormat::UnsignedInteger) + \relates QPixelFormat + \since 5.5 + + Constructor function for creating an Alpha format. A mask format can be + described by passing 1 to \a channelSize. Its also possible to define very + accurate alpha formats using doubles to describe each pixel by passing 8 + as \a channelSize and FloatingPoint as \a typeInterpretation. + + \sa QPixelFormat::TypeInterpretation +*/ + + +/*! \fn QPixelFormat qPixelFormatCmyk(uchar channelSize, uchar alphaSize = 0, QPixelFormat::AlphaUsage alphaUsage = QPixelFormat::IgnoresAlpha, diff --git a/src/gui/kernel/qpixelformat.h b/src/gui/kernel/qpixelformat.h index f55c97c7c0..b7a4377a69 100644 --- a/src/gui/kernel/qpixelformat.h +++ b/src/gui/kernel/qpixelformat.h @@ -103,7 +103,8 @@ public: CMYK, HSL, HSV, - YUV + YUV, + Alpha }; enum AlphaUsage { @@ -304,6 +305,22 @@ Q_DECL_CONSTEXPR inline QPixelFormat qPixelFormatGrayscale(uchar channelSize, typeInt); } +Q_DECL_CONSTEXPR inline QPixelFormat qPixelFormatAlpha(uchar channelSize, + QPixelFormat::TypeInterpretation typeInt=QPixelFormat::UnsignedInteger) Q_DECL_NOTHROW +{ + return QPixelFormat(QPixelFormat::Alpha, + 0, + 0, + 0, + 0, + 0, + channelSize, + QPixelFormat::UsesAlpha, + QPixelFormat::AtBeginning, + QPixelFormat::NotPremultiplied, + typeInt); +} + Q_DECL_CONSTEXPR inline QPixelFormat qPixelFormatCmyk(uchar channelSize, uchar alfa=0, QPixelFormat::AlphaUsage usage=QPixelFormat::IgnoresAlpha, diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp index 39b031ef6d..7e291e9050 100644 --- a/src/gui/kernel/qplatformintegration.cpp +++ b/src/gui/kernel/qplatformintegration.cpp @@ -324,6 +324,16 @@ void QPlatformIntegration::initialize() } /*! + Called before the platform integration is deleted. Useful when cleanup relies on virtual + functions. + + \since 5.5 +*/ +void QPlatformIntegration::destroy() +{ +} + +/*! Returns the platforms input context. The default implementation returns 0, implying no input method support. diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h index d510240fa4..ccbe4cc73d 100644 --- a/src/gui/kernel/qplatformintegration.h +++ b/src/gui/kernel/qplatformintegration.h @@ -109,6 +109,7 @@ public: // Event dispatcher: virtual QAbstractEventDispatcher *createEventDispatcher() const = 0; virtual void initialize(); + virtual void destroy(); //Deeper window system integrations virtual QPlatformFontDatabase *fontDatabase() const; diff --git a/src/gui/kernel/qplatformopenglcontext.cpp b/src/gui/kernel/qplatformopenglcontext.cpp index 527bfdd983..bf0dccd440 100644 --- a/src/gui/kernel/qplatformopenglcontext.cpp +++ b/src/gui/kernel/qplatformopenglcontext.cpp @@ -89,6 +89,16 @@ QPlatformOpenGLContext::~QPlatformOpenGLContext() } /*! + Called after a new instance is constructed. The default implementation does nothing. + + Subclasses can use this function to perform additional initialization that relies on + virtual functions. + */ +void QPlatformOpenGLContext::initialize() +{ +} + +/*! Reimplement in subclass if your platform uses framebuffer objects for surfaces. The default implementation returns 0. diff --git a/src/gui/kernel/qplatformopenglcontext.h b/src/gui/kernel/qplatformopenglcontext.h index 261b6921a4..0a2bacfbde 100644 --- a/src/gui/kernel/qplatformopenglcontext.h +++ b/src/gui/kernel/qplatformopenglcontext.h @@ -63,6 +63,8 @@ public: QPlatformOpenGLContext(); virtual ~QPlatformOpenGLContext(); + virtual void initialize(); + virtual QSurfaceFormat format() const = 0; virtual void swapBuffers(QPlatformSurface *surface) = 0; diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp index 646bd90e56..92c1b09406 100644 --- a/src/gui/kernel/qplatformtheme.cpp +++ b/src/gui/kernel/qplatformtheme.cpp @@ -320,7 +320,8 @@ const QKeyBinding QPlatformThemePrivate::keyBindings[] = { {QKeySequence::FullScreen, 1, Qt::CTRL | Qt::Key_F11, KB_Gnome}, {QKeySequence::FullScreen, 1, Qt::Key_F11, KB_Win | KB_KDE}, {QKeySequence::Deselect, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_A, KB_X11}, - {QKeySequence::DeleteCompleteLine, 0, Qt::CTRL | Qt::Key_U, KB_X11} + {QKeySequence::DeleteCompleteLine, 0, Qt::CTRL | Qt::Key_U, KB_X11}, + {QKeySequence::Backspace, 0, Qt::META | Qt::Key_H, KB_Mac} }; const uint QPlatformThemePrivate::numberOfKeyBindings = sizeof(QPlatformThemePrivate::keyBindings)/(sizeof(QKeyBinding)); @@ -502,9 +503,11 @@ QVariant QPlatformTheme::defaultThemeHint(ThemeHint hint) case MouseDoubleClickDistance: { bool ok = false; - int dist = qgetenv("QT_DBL_CLICK_DIST").toInt(&ok); + const int dist = qEnvironmentVariableIntValue("QT_DBL_CLICK_DIST", &ok); return QVariant(ok ? dist : 5); } + case WheelScrollLines: + return QVariant(3); } return QVariant(); } diff --git a/src/gui/kernel/qplatformtheme.h b/src/gui/kernel/qplatformtheme.h index a41dd8f257..be1eacf002 100644 --- a/src/gui/kernel/qplatformtheme.h +++ b/src/gui/kernel/qplatformtheme.h @@ -101,7 +101,8 @@ public: DialogSnapToDefaultButton, ContextMenuOnMouseRelease, MousePressAndHoldInterval, - MouseDoubleClickDistance + MouseDoubleClickDistance, + WheelScrollLines }; enum DialogType { diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp index bd5e21c485..976d89b30a 100644 --- a/src/gui/kernel/qplatformwindow.cpp +++ b/src/gui/kernel/qplatformwindow.cpp @@ -593,6 +593,36 @@ QRect QPlatformWindow::initialGeometry(const QWindow *w, } /*! + Requests an QEvent::UpdateRequest event. The event will be + delivered to the QWindow. + + QPlatformWindow subclasses can re-implement this function to + provide display refresh synchronized updates. The event + should be delivered using QWindowPrivate::deliverUpdateRequest() + to not get out of sync with the the internal state of QWindow. + + The default implementation posts an UpdateRequest event to the + window after 5 ms. The additional time is there to give the event + loop a bit of idle time to gather system events. + +*/ +void QPlatformWindow::requestUpdate() +{ + static int timeout = -1; + if (timeout == -1) { + bool ok = false; + timeout = qEnvironmentVariableIntValue("QT_QPA_UPDATE_IDLE_TIME", &ok); + if (!ok) + timeout = 5; + } + + QWindow *w = window(); + QWindowPrivate *wp = (QWindowPrivate *) QObjectPrivate::get(w); + Q_ASSERT(wp->updateTimer == 0); + wp->updateTimer = w->startTimer(timeout, Qt::PreciseTimer); +} + +/*! \class QPlatformWindow \since 4.8 \internal diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h index 5c351a69d2..87781caf8b 100644 --- a/src/gui/kernel/qplatformwindow.h +++ b/src/gui/kernel/qplatformwindow.h @@ -129,6 +129,7 @@ public: static QRect initialGeometry(const QWindow *w, const QRect &initialGeometry, int defaultWidth, int defaultHeight); + virtual void requestUpdate(); protected: static QString formatWindowTitle(const QString &title, const QString &separator); QPlatformScreen *screenForGeometry(const QRect &newGeometry) const; diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp index cad707ab70..b3e71c77fa 100644 --- a/src/gui/kernel/qshortcutmap.cpp +++ b/src/gui/kernel/qshortcutmap.cpp @@ -310,6 +310,10 @@ QKeySequence::SequenceMatch QShortcutMap::state() Uses ShortcutOverride event to see if any widgets want to override the event. If not, uses nextState(QKeyEvent) to check for a grabbed Shortcut, and dispatchEvent() is found and identical. + + \note that this function should only be called from QWindowSystemInterface, + otherwise it will result in duplicate events. + \sa nextState, dispatchEvent */ bool QShortcutMap::tryShortcutEvent(QObject *o, QKeyEvent *e) diff --git a/src/gui/kernel/qsurface.h b/src/gui/kernel/qsurface.h index 58b7ce018e..0c02a3564c 100644 --- a/src/gui/kernel/qsurface.h +++ b/src/gui/kernel/qsurface.h @@ -36,7 +36,7 @@ #include <QtCore/qnamespace.h> #include <QtGui/qsurfaceformat.h> - +#include <QtCore/qmetatype.h> #include <QtCore/qsize.h> QT_BEGIN_NAMESPACE @@ -82,4 +82,6 @@ protected: QT_END_NAMESPACE +Q_DECLARE_METATYPE(QSurface*) + #endif //QSURFACE_H diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index c6dd0955aa..fa99390af0 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -404,6 +404,11 @@ void QWindowPrivate::create(bool recursive) window->d_func()->platformWindow->setParent(platformWindow); } } + + if (platformWindow) { + QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceCreated); + QGuiApplication::sendEvent(q, &e); + } } } @@ -1594,6 +1599,10 @@ void QWindow::destroy() bool wasVisible = isVisible(); setVisible(false); + + QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed); + QGuiApplication::sendEvent(this, &e); + delete d->platformWindow; d->resizeEventPending = true; d->receivedExpose = false; @@ -2043,12 +2052,56 @@ bool QWindow::event(QEvent *ev) break; #endif + case QEvent::Timer: { + Q_D(QWindow); + if (static_cast<QTimerEvent *>(ev)->timerId() == d->updateTimer) { + killTimer(d->updateTimer); + d->updateTimer = 0; + d->deliverUpdateRequest(); + } else { + QObject::event(ev); + } + break; + } + default: return QObject::event(ev); } return true; } +void QWindowPrivate::deliverUpdateRequest() +{ + Q_Q(QWindow); + updateRequestPending = false; + QEvent request(QEvent::UpdateRequest); + QCoreApplication::sendEvent(q, &request); +} + +/*! + Schedules a QEvent::UpdateRequest event to be delivered to this window. + + The event is delivered in sync with the display vsync on platforms + where this is possible. When driving animations, this function should + be called once after drawing has completed. + + Calling this function multiple times will result in a single event + being delivered to the window. + + Subclasses of QWindow should reimplement QWindow::event(), intercept + the event and call the application's rendering code, then call the + base class implementation. +*/ + +void QWindow::requestUpdate() +{ + Q_D(QWindow); + if (d->updateRequestPending || !d->platformWindow) + return; + d->updateRequestPending = true; + d->platformWindow->requestUpdate(); +} + /*! Override this to handle key press events (\a ev). diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h index 473d275b56..2230ed8801 100644 --- a/src/gui/kernel/qwindow.h +++ b/src/gui/kernel/qwindow.h @@ -286,6 +286,8 @@ public Q_SLOTS: Q_REVISION(1) void alert(int msec); + Q_REVISION(3) void requestUpdate(); + Q_SIGNALS: void screenChanged(QScreen *screen); void modalityChanged(Qt::WindowModality modality); diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 46dc2e463c..40f23b1c36 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -86,6 +86,8 @@ public: , maximumSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX) , modality(Qt::NonModal) , blockedByModalWindow(false) + , updateRequestPending(false) + , updateTimer(0) , transientParent(0) , topLevelScreen(0) #ifndef QT_NO_CURSOR @@ -109,6 +111,8 @@ public: void applyCursor(); #endif + void deliverUpdateRequest(); + QPoint globalPosition() const { Q_Q(const QWindow); QPoint offset = q->position(); @@ -133,6 +137,10 @@ public: virtual void clearFocusObject(); + bool isPopup() const { return (windowFlags & Qt::WindowType_Mask) == Qt::Popup; } + + static QWindowPrivate *get(QWindow *window) { return window->d_func(); } + QWindow::SurfaceType surfaceType; Qt::WindowFlags windowFlags; QWindow *parentWindow; @@ -162,6 +170,9 @@ public: Qt::WindowModality modality; bool blockedByModalWindow; + bool updateRequestPending; + int updateTimer; + QPointer<QWindow> transientParent; QScreen *topLevelScreen; diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 722a695481..ec158bdc40 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -220,6 +220,28 @@ bool QWindowSystemInterface::tryHandleShortcutEvent(QWindow *w, ulong timestamp, #endif } +// used by QTestLib to directly send shortcuts to objects +bool QWindowSystemInterface::tryHandleShortcutEventToObject(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, + const QString &text, bool autorep, ushort count) +{ +#ifndef QT_NO_SHORTCUT + QGuiApplicationPrivate::modifier_buttons = mods; + + QKeyEvent qevent(QEvent::ShortcutOverride, k, mods, text, autorep, count); + qevent.setTimestamp(timestamp); + return QGuiApplicationPrivate::instance()->shortcutMap.tryShortcutEvent(o, &qevent); +#else + Q_UNUSED(w) + Q_UNUSED(timestamp) + Q_UNUSED(k) + Q_UNUSED(mods) + Q_UNUSED(text) + Q_UNUSED(autorep) + Q_UNUSED(count) + return false; +#endif +} + bool QWindowSystemInterface::tryHandleExtendedShortcutEvent(QWindow *w, int k, Qt::KeyboardModifiers mods, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString &text, bool autorep, ushort count) @@ -265,6 +287,9 @@ void QWindowSystemInterface::handleKeyEvent(QWindow *w, QEvent::Type t, int k, Q void QWindowSystemInterface::handleKeyEvent(QWindow *tlw, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) { + if (t == QEvent::KeyPress && tlw && QWindowSystemInterface::tryHandleShortcutEvent(tlw, timestamp, k, mods, text)) + return; + QWindowSystemInterfacePrivate::KeyEvent * e = new QWindowSystemInterfacePrivate::KeyEvent(tlw, timestamp, t, k, mods, text, autorep, count); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); @@ -286,8 +311,12 @@ void QWindowSystemInterface::handleExtendedKeyEvent(QWindow *tlw, ulong timestam quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString& text, bool autorep, - ushort count) + ushort count, bool tryShortcutOverride) { + // on OS X we try the shortcut override even earlier and thus shouldn't handle it here + if (tryShortcutOverride && type == QEvent::KeyPress && QWindowSystemInterface::tryHandleShortcutEvent(tlw, timestamp, key, modifiers, text)) + return; + QWindowSystemInterfacePrivate::KeyEvent * e = new QWindowSystemInterfacePrivate::KeyEvent(tlw, timestamp, type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count); @@ -760,6 +789,11 @@ Q_GUI_EXPORT void qt_handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::Keybo QWindowSystemInterface::handleKeyEvent(w, t, k, mods, text, autorep, count); } +Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, const QString &text = QString(), bool autorep = false, ushort count = 1) +{ + return QWindowSystemInterface::tryHandleShortcutEventToObject(o, timestamp, k, mods, text, autorep, count); +} + static QWindowSystemInterface::TouchPoint touchPoint(const QTouchEvent::TouchPoint& pt) { QWindowSystemInterface::TouchPoint p; diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index 30c236b51f..7bb3938fe6 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -83,6 +83,9 @@ public: static bool tryHandleShortcutEvent(QWindow *w, ulong timestamp, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1); + static bool tryHandleShortcutEventToObject(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, + const QString & text = QString(), bool autorep = false, ushort count = 1); + static bool tryHandleExtendedShortcutEvent(QWindow *w, int k, Qt::KeyboardModifiers mods, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString & text = QString(), bool autorep = false, ushort count = 1); @@ -102,7 +105,7 @@ public: quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString& text = QString(), bool autorep = false, - ushort count = 1); + ushort count = 1, bool tryShortcutOverride = true); static void handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods = Qt::NoModifier, Qt::ScrollPhase phase = Qt::ScrollUpdate); static void handleWheelEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods = Qt::NoModifier, Qt::ScrollPhase phase = Qt::ScrollUpdate); diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h index c3f41da835..57411d8101 100644 --- a/src/gui/kernel/qwindowsysteminterface_p.h +++ b/src/gui/kernel/qwindowsysteminterface_p.h @@ -93,11 +93,20 @@ public: class WindowSystemEvent { public: + enum { + Synthetic = 0x1, + NullWindow = 0x2 + }; + explicit WindowSystemEvent(EventType t) - : type(t), synthetic(false) { } + : type(t), flags(0) { } virtual ~WindowSystemEvent() { } + + bool synthetic() const { return flags & Synthetic; } + bool nullWindow() const { return flags & NullWindow; } + EventType type; - bool synthetic; + int flags; }; class CloseEvent : public WindowSystemEvent { @@ -188,9 +197,12 @@ public: class UserEvent : public WindowSystemEvent { public: UserEvent(QWindow * w, ulong time, EventType t) - : WindowSystemEvent(t), window(w), nullWindow(w == 0), timestamp(time) { } + : WindowSystemEvent(t), window(w), timestamp(time) + { + if (!w) + flags |= NullWindow; + } QPointer<QWindow> window; - bool nullWindow; unsigned long timestamp; }; diff --git a/src/gui/opengl/qopenglengineshadermanager.cpp b/src/gui/opengl/qopenglengineshadermanager.cpp index 5bdb2f35ac..93425b0b3a 100644 --- a/src/gui/opengl/qopenglengineshadermanager.cpp +++ b/src/gui/opengl/qopenglengineshadermanager.cpp @@ -154,6 +154,8 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context) code[ImageSrcFragmentShader] = qopenglslImageSrcFragmentShader; code[ImageSrcWithPatternFragmentShader] = qopenglslImageSrcWithPatternFragmentShader; code[NonPremultipliedImageSrcFragmentShader] = qopenglslNonPremultipliedImageSrcFragmentShader; + code[GrayscaleImageSrcFragmentShader] = qopenglslGrayscaleImageSrcFragmentShader; + code[AlphaImageSrcFragmentShader] = qopenglslAlphaImageSrcFragmentShader; code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader; // Calls "customShader", which must be appended code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader; if (context->isOpenGLES()) @@ -700,6 +702,16 @@ bool QOpenGLEngineShaderManager::useCorrectShaderProg() requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader; texCoords = true; break; + case QOpenGLEngineShaderManager::GrayscaleImageSrc: + requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::GrayscaleImageSrcFragmentShader; + requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader; + texCoords = true; + break; + case QOpenGLEngineShaderManager::AlphaImageSrc: + requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::AlphaImageSrcFragmentShader; + requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader; + texCoords = true; + break; case QOpenGLEngineShaderManager::PatternSrc: requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::ImageSrcWithPatternFragmentShader; requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader; diff --git a/src/gui/opengl/qopenglengineshadermanager_p.h b/src/gui/opengl/qopenglengineshadermanager_p.h index 2ae0ae0866..56aa18cb6b 100644 --- a/src/gui/opengl/qopenglengineshadermanager_p.h +++ b/src/gui/opengl/qopenglengineshadermanager_p.h @@ -288,6 +288,8 @@ public: ImageSrcFragmentShader, ImageSrcWithPatternFragmentShader, NonPremultipliedImageSrcFragmentShader, + GrayscaleImageSrcFragmentShader, + AlphaImageSrcFragmentShader, CustomImageSrcFragmentShader, SolidBrushSrcFragmentShader, TextureBrushSrcFragmentShader, @@ -414,7 +416,9 @@ public: ImageSrc = Qt::TexturePattern+1, NonPremultipliedImageSrc = Qt::TexturePattern+2, PatternSrc = Qt::TexturePattern+3, - TextureSrcWithPattern = Qt::TexturePattern+4 + TextureSrcWithPattern = Qt::TexturePattern+4, + GrayscaleImageSrc = Qt::TexturePattern+5, + AlphaImageSrc = Qt::TexturePattern+6, }; enum Uniform { diff --git a/src/gui/opengl/qopenglengineshadersource_p.h b/src/gui/opengl/qopenglengineshadersource_p.h index bc81fe4c77..acda09a8ee 100644 --- a/src/gui/opengl/qopenglengineshadersource_p.h +++ b/src/gui/opengl/qopenglengineshadersource_p.h @@ -367,6 +367,22 @@ static const char* const qopenglslNonPremultipliedImageSrcFragmentShader = "\n\ return sample; \n\ }\n"; +static const char* const qopenglslGrayscaleImageSrcFragmentShader = "\n\ + varying highp vec2 textureCoords; \n\ + uniform sampler2D imageTexture; \n\ + lowp vec4 srcPixel() \n\ + { \n\ + return texture2D(imageTexture, textureCoords).rrra; \n\ + }\n"; + +static const char* const qopenglslAlphaImageSrcFragmentShader = "\n\ + varying highp vec2 textureCoords; \n\ + uniform sampler2D imageTexture; \n\ + lowp vec4 srcPixel() \n\ + { \n\ + return vec4(0, 0, 0, texture2D(imageTexture, textureCoords).r); \n\ + }\n"; + static const char* const qopenglslShockingPinkSrcFragmentShader = "\n\ lowp vec4 srcPixel() \n\ { \n\ diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp index 44b56699df..67b978a570 100644 --- a/src/gui/opengl/qopenglfunctions.cpp +++ b/src/gui/opengl/qopenglfunctions.cpp @@ -173,6 +173,7 @@ QT_BEGIN_NAMESPACE \value NPOTTextures Non power of two textures are available. \value NPOTTextureRepeat Non power of two textures can use GL_REPEAT as wrap parameter. \value FixedFunctionPipeline The fixed function pipeline is available. + \value TextureRGFormats The GL_RED and GL_RG texture formats are available. */ // Hidden private fields for additional extension data. @@ -284,10 +285,12 @@ static int qt_gl_resolve_features() if (extensions.match("GL_OES_texture_npot")) features |= QOpenGLFunctions::NPOTTextures | QOpenGLFunctions::NPOTTextureRepeat; + if (ctx->format().majorVersion() >= 3 || extensions.match("GL_EXT_texture_rg")) + features |= QOpenGLFunctions::TextureRGFormats; return features; } else { // OpenGL - int features = 0; + int features = QOpenGLFunctions::TextureRGFormats; QSurfaceFormat format = QOpenGLContext::currentContext()->format(); QOpenGLExtensionMatcher extensions; diff --git a/src/gui/opengl/qopenglfunctions.h b/src/gui/opengl/qopenglfunctions.h index 479a280abe..85d255fe61 100644 --- a/src/gui/opengl/qopenglfunctions.h +++ b/src/gui/opengl/qopenglfunctions.h @@ -240,7 +240,8 @@ public: StencilSeparate = 0x0800, NPOTTextures = 0x1000, NPOTTextureRepeat = 0x2000, - FixedFunctionPipeline = 0x4000 + FixedFunctionPipeline = 0x4000, + TextureRGFormats = 0x8000 }; Q_DECLARE_FLAGS(OpenGLFeatures, OpenGLFeature) diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index c490726359..299d3da73d 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -1421,6 +1421,20 @@ void QOpenGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, c d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::NonPremultipliedImageSrc); bindOption = 0; break; + case QImage::Format_Alpha8: + if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::TextureRGFormats)) { + d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::AlphaImageSrc); + bindOption = QOpenGLTextureCache::UseRedFor8BitBindOption; + } else + d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc); + break; + case QImage::Format_Grayscale8: + if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::TextureRGFormats)) { + d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::GrayscaleImageSrc); + bindOption = QOpenGLTextureCache::UseRedFor8BitBindOption; + } else + d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc); + break; default: d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc); break; diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp index 5ea7a10e0d..d64847510b 100644 --- a/src/gui/opengl/qopenglshaderprogram.cpp +++ b/src/gui/opengl/qopenglshaderprogram.cpp @@ -39,6 +39,7 @@ #include <QtCore/qfile.h> #include <QtCore/qvarlengtharray.h> #include <QtCore/qvector.h> +#include <QtCore/qregularexpression.h> #include <QtGui/qtransform.h> #include <QtGui/QColor> #include <QtGui/QSurfaceFormat> @@ -47,6 +48,8 @@ #include <QtGui/qopenglfunctions_4_0_core.h> #endif +#include <algorithm> + QT_BEGIN_NAMESPACE /*! @@ -401,6 +404,95 @@ static const char redefineHighp[] = "#endif\n"; #endif +struct QVersionDirectivePosition +{ + Q_DECL_CONSTEXPR QVersionDirectivePosition(int position = 0, int line = -1) + : position(position) + , line(line) + { + } + + Q_DECL_CONSTEXPR bool hasPosition() const + { + return position > 0; + } + + const int position; + const int line; +}; + +static QVersionDirectivePosition findVersionDirectivePosition(const char *source) +{ + Q_ASSERT(source); + + QString working = QString::fromUtf8(source); + + // According to the GLSL spec the #version directive must not be + // preceded by anything but whitespace and comments. + // In order to not get confused by #version directives within a + // multiline comment, we need to run a minimal preprocessor first. + enum { + Normal, + CommentStarting, + MultiLineComment, + SingleLineComment, + CommentEnding + } state = Normal; + + for (QChar *c = working.begin(); c != working.end(); ++c) { + switch (state) { + case Normal: + if (*c == QLatin1Char('/')) + state = CommentStarting; + break; + case CommentStarting: + if (*c == QLatin1Char('*')) + state = MultiLineComment; + else if (*c == QLatin1Char('/')) + state = SingleLineComment; + else + state = Normal; + break; + case MultiLineComment: + if (*c == QLatin1Char('*')) + state = CommentEnding; + else if (*c == QLatin1Char('#')) + *c = QLatin1Char('_'); + break; + case SingleLineComment: + if (*c == QLatin1Char('\n')) + state = Normal; + else if (*c == QLatin1Char('#')) + *c = QLatin1Char('_'); + break; + case CommentEnding: + if (*c == QLatin1Char('/')) { + state = Normal; + } else { + if (*c == QLatin1Char('#')) + *c = QLatin1Char('_'); + state = MultiLineComment; + } + break; + } + } + + // Search for #version directive + int splitPosition = 0; + int linePosition = 1; + + static const QRegularExpression pattern(QStringLiteral("^#\\s*version.*(\\n)?"), + QRegularExpression::MultilineOption + | QRegularExpression::OptimizeOnFirstUsageOption); + QRegularExpressionMatch match = pattern.match(working); + if (match.hasMatch()) { + splitPosition = match.capturedEnd(); + linePosition += int(std::count(working.begin(), working.begin() + splitPosition, QLatin1Char('\n'))); + } + + return QVersionDirectivePosition(splitPosition, linePosition); +} + /*! Sets the \a source code for this shader and compiles it. Returns \c true if the source was successfully compiled, false otherwise. @@ -410,26 +502,24 @@ static const char redefineHighp[] = bool QOpenGLShader::compileSourceCode(const char *source) { Q_D(QOpenGLShader); - if (d->shaderGuard && d->shaderGuard->id()) { - QVarLengthArray<const char *, 4> src; - QVarLengthArray<GLint, 4> srclen; - int headerLen = 0; - while (source && source[headerLen] == '#') { - // Skip #version and #extension directives at the start of - // the shader code. We need to insert the qualifierDefines - // and redefineHighp just after them. - if (qstrncmp(source + headerLen, "#version", 8) != 0 && - qstrncmp(source + headerLen, "#extension", 10) != 0) { - break; - } - while (source[headerLen] != '\0' && source[headerLen] != '\n') - ++headerLen; - if (source[headerLen] == '\n') - ++headerLen; - } - if (headerLen > 0) { - src.append(source); - srclen.append(GLint(headerLen)); + // This method breaks the shader code into two parts: + // 1. Up to and including an optional #version directive. + // 2. The rest. + // If a #version directive exists, qualifierDefines and redefineHighp + // are inserted after. Otherwise they are inserted right at the start. + // In both cases a #line directive is appended in order to compensate + // for line number changes in case of compiler errors. + + if (d->shaderGuard && d->shaderGuard->id() && source) { + const QVersionDirectivePosition versionDirectivePosition = findVersionDirectivePosition(source); + + QVarLengthArray<const char *, 5> sourceChunks; + QVarLengthArray<GLint, 5> sourceChunkLengths; + + if (versionDirectivePosition.hasPosition()) { + // Append source up to #version directive + sourceChunks.append(source); + sourceChunkLengths.append(GLint(versionDirectivePosition.position)); } // The precision qualifiers are useful on OpenGL/ES systems, @@ -442,20 +532,28 @@ bool QOpenGLShader::compileSourceCode(const char *source) || true #endif ) { - src.append(qualifierDefines); - srclen.append(GLint(sizeof(qualifierDefines) - 1)); + sourceChunks.append(qualifierDefines); + sourceChunkLengths.append(GLint(sizeof(qualifierDefines) - 1)); } #ifdef QOpenGL_REDEFINE_HIGHP if (d->shaderType == Fragment && !ctx_d->workaround_missingPrecisionQualifiers && QOpenGLContext::currentContext()->isOpenGLES()) { - src.append(redefineHighp); - srclen.append(GLint(sizeof(redefineHighp) - 1)); + sourceChunks.append(redefineHighp); + sourceChunkLengths.append(GLint(sizeof(redefineHighp) - 1)); } #endif - src.append(source + headerLen); - srclen.append(GLint(qstrlen(source + headerLen))); - d->glfuncs->glShaderSource(d->shaderGuard->id(), src.size(), src.data(), srclen.data()); + + // Append #line directive in order to compensate for text insertion + QByteArray lineDirective = QStringLiteral("#line %1\n").arg(versionDirectivePosition.line).toUtf8(); + sourceChunks.append(lineDirective.constData()); + sourceChunkLengths.append(GLint(lineDirective.length())); + + // Append rest of shader code + sourceChunks.append(source + versionDirectivePosition.position); + sourceChunkLengths.append(GLint(qstrlen(source + versionDirectivePosition.position))); + + d->glfuncs->glShaderSource(d->shaderGuard->id(), sourceChunks.size(), sourceChunks.data(), sourceChunkLengths.data()); return d->compile(this); } else { return false; diff --git a/src/gui/opengl/qopengltexture.cpp b/src/gui/opengl/qopengltexture.cpp index f6083b8cf9..8ba139d003 100644 --- a/src/gui/opengl/qopengltexture.cpp +++ b/src/gui/opengl/qopengltexture.cpp @@ -294,16 +294,166 @@ int QOpenGLTexturePrivate::evaluateMipLevels() const } } -void QOpenGLTexturePrivate::allocateStorage() +static bool isSizedTextureFormat(QOpenGLTexture::TextureFormat internalFormat) +{ + switch (internalFormat) { + case QOpenGLTexture::NoFormat: + return false; + + case QOpenGLTexture::R8_UNorm: + case QOpenGLTexture::RG8_UNorm: + case QOpenGLTexture::RGB8_UNorm: + case QOpenGLTexture::RGBA8_UNorm: + case QOpenGLTexture::R16_UNorm: + case QOpenGLTexture::RG16_UNorm: + case QOpenGLTexture::RGB16_UNorm: + case QOpenGLTexture::RGBA16_UNorm: + case QOpenGLTexture::R8_SNorm: + case QOpenGLTexture::RG8_SNorm: + case QOpenGLTexture::RGB8_SNorm: + case QOpenGLTexture::RGBA8_SNorm: + case QOpenGLTexture::R16_SNorm: + case QOpenGLTexture::RG16_SNorm: + case QOpenGLTexture::RGB16_SNorm: + case QOpenGLTexture::RGBA16_SNorm: + case QOpenGLTexture::R8U: + case QOpenGLTexture::RG8U: + case QOpenGLTexture::RGB8U: + case QOpenGLTexture::RGBA8U: + case QOpenGLTexture::R16U: + case QOpenGLTexture::RG16U: + case QOpenGLTexture::RGB16U: + case QOpenGLTexture::RGBA16U: + case QOpenGLTexture::R32U: + case QOpenGLTexture::RG32U: + case QOpenGLTexture::RGB32U: + case QOpenGLTexture::RGBA32U: + case QOpenGLTexture::R8I: + case QOpenGLTexture::RG8I: + case QOpenGLTexture::RGB8I: + case QOpenGLTexture::RGBA8I: + case QOpenGLTexture::R16I: + case QOpenGLTexture::RG16I: + case QOpenGLTexture::RGB16I: + case QOpenGLTexture::RGBA16I: + case QOpenGLTexture::R32I: + case QOpenGLTexture::RG32I: + case QOpenGLTexture::RGB32I: + case QOpenGLTexture::RGBA32I: + case QOpenGLTexture::R16F: + case QOpenGLTexture::RG16F: + case QOpenGLTexture::RGB16F: + case QOpenGLTexture::RGBA16F: + case QOpenGLTexture::R32F: + case QOpenGLTexture::RG32F: + case QOpenGLTexture::RGB32F: + case QOpenGLTexture::RGBA32F: + case QOpenGLTexture::RGB9E5: + case QOpenGLTexture::RG11B10F: + case QOpenGLTexture::RG3B2: + case QOpenGLTexture::R5G6B5: + case QOpenGLTexture::RGB5A1: + case QOpenGLTexture::RGBA4: + case QOpenGLTexture::RGB10A2: + + case QOpenGLTexture::D16: + case QOpenGLTexture::D24: + case QOpenGLTexture::D32: + case QOpenGLTexture::D32F: + + case QOpenGLTexture::D24S8: + case QOpenGLTexture::D32FS8X24: + + case QOpenGLTexture::S8: + + case QOpenGLTexture::RGB_DXT1: + case QOpenGLTexture::RGBA_DXT1: + case QOpenGLTexture::RGBA_DXT3: + case QOpenGLTexture::RGBA_DXT5: + case QOpenGLTexture::R_ATI1N_UNorm: + case QOpenGLTexture::R_ATI1N_SNorm: + case QOpenGLTexture::RG_ATI2N_UNorm: + case QOpenGLTexture::RG_ATI2N_SNorm: + case QOpenGLTexture::RGB_BP_UNSIGNED_FLOAT: + case QOpenGLTexture::RGB_BP_SIGNED_FLOAT: + case QOpenGLTexture::RGB_BP_UNorm: + case QOpenGLTexture::SRGB8: + case QOpenGLTexture::SRGB8_Alpha8: + case QOpenGLTexture::SRGB_DXT1: + case QOpenGLTexture::SRGB_Alpha_DXT1: + case QOpenGLTexture::SRGB_Alpha_DXT3: + case QOpenGLTexture::SRGB_Alpha_DXT5: + case QOpenGLTexture::SRGB_BP_UNorm: + case QOpenGLTexture::R11_EAC_UNorm: + case QOpenGLTexture::R11_EAC_SNorm: + case QOpenGLTexture::RG11_EAC_UNorm: + case QOpenGLTexture::RG11_EAC_SNorm: + case QOpenGLTexture::RGB8_ETC2: + case QOpenGLTexture::SRGB8_ETC2: + case QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2: + case QOpenGLTexture::SRGB8_PunchThrough_Alpha1_ETC2: + case QOpenGLTexture::RGBA8_ETC2_EAC: + case QOpenGLTexture::SRGB8_Alpha8_ETC2_EAC: + return true; + + case QOpenGLTexture::DepthFormat: + case QOpenGLTexture::AlphaFormat: + + case QOpenGLTexture::RGBFormat: + case QOpenGLTexture::RGBAFormat: + + case QOpenGLTexture::LuminanceFormat: + + case QOpenGLTexture::LuminanceAlphaFormat: + return false; + } + + Q_UNREACHABLE(); + return false; +} + +static bool isTextureTargetMultisample(QOpenGLTexture::Target target) +{ + switch (target) { + case QOpenGLTexture::Target1D: + case QOpenGLTexture::Target1DArray: + case QOpenGLTexture::Target2D: + case QOpenGLTexture::Target2DArray: + case QOpenGLTexture::Target3D: + case QOpenGLTexture::TargetCubeMap: + case QOpenGLTexture::TargetCubeMapArray: + return false; + + case QOpenGLTexture::Target2DMultisample: + case QOpenGLTexture::Target2DMultisampleArray: + return true; + + case QOpenGLTexture::TargetRectangle: + case QOpenGLTexture::TargetBuffer: + return false; + } + + Q_UNREACHABLE(); + return false; +} + +void QOpenGLTexturePrivate::allocateStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType) { // Resolve the actual number of mipmap levels we can use mipLevels = evaluateMipLevels(); - // Use immutable storage whenever possible, falling back to mutable when not available - if (features.testFlag(QOpenGLTexture::ImmutableStorage)) + // Use immutable storage whenever possible, falling back to mutable + // Note that if multisample textures are not supported at all, we'll still fail into + // the mutable storage allocation + const bool useImmutableStorage = isSizedTextureFormat(format) + && (isTextureTargetMultisample(target) + ? features.testFlag(QOpenGLTexture::ImmutableMultisampleStorage) + : features.testFlag(QOpenGLTexture::ImmutableStorage)); + + if (useImmutableStorage) allocateImmutableStorage(); else - allocateMutableStorage(); + allocateMutableStorage(pixelFormat, pixelType); } static QOpenGLTexture::PixelFormat pixelFormatCompatibleWithInternalFormat(QOpenGLTexture::TextureFormat internalFormat) @@ -313,59 +463,167 @@ static QOpenGLTexture::PixelFormat pixelFormatCompatibleWithInternalFormat(QOpen return QOpenGLTexture::NoSourceFormat; case QOpenGLTexture::R8_UNorm: + return QOpenGLTexture::Red; + case QOpenGLTexture::RG8_UNorm: + return QOpenGLTexture::RG; + case QOpenGLTexture::RGB8_UNorm: + return QOpenGLTexture::RGB; + case QOpenGLTexture::RGBA8_UNorm: + return QOpenGLTexture::RGBA; + case QOpenGLTexture::R16_UNorm: + return QOpenGLTexture::Red; + case QOpenGLTexture::RG16_UNorm: + return QOpenGLTexture::RG; + case QOpenGLTexture::RGB16_UNorm: + return QOpenGLTexture::RGB; + case QOpenGLTexture::RGBA16_UNorm: + return QOpenGLTexture::RGBA; + case QOpenGLTexture::R8_SNorm: + return QOpenGLTexture::Red; + case QOpenGLTexture::RG8_SNorm: + return QOpenGLTexture::RG; + case QOpenGLTexture::RGB8_SNorm: + return QOpenGLTexture::RGB; + case QOpenGLTexture::RGBA8_SNorm: + return QOpenGLTexture::RGBA; + case QOpenGLTexture::R16_SNorm: + return QOpenGLTexture::Red; + case QOpenGLTexture::RG16_SNorm: + return QOpenGLTexture::RG; + case QOpenGLTexture::RGB16_SNorm: + return QOpenGLTexture::RGB; + case QOpenGLTexture::RGBA16_SNorm: + return QOpenGLTexture::RGBA; + case QOpenGLTexture::R8U: + return QOpenGLTexture::Red_Integer; + case QOpenGLTexture::RG8U: + return QOpenGLTexture::RG_Integer; + case QOpenGLTexture::RGB8U: + return QOpenGLTexture::RGB_Integer; + case QOpenGLTexture::RGBA8U: + return QOpenGLTexture::RGBA_Integer; + case QOpenGLTexture::R16U: + return QOpenGLTexture::Red_Integer; + case QOpenGLTexture::RG16U: + return QOpenGLTexture::RG_Integer; + case QOpenGLTexture::RGB16U: + return QOpenGLTexture::RGB_Integer; + case QOpenGLTexture::RGBA16U: + return QOpenGLTexture::RGBA_Integer; + case QOpenGLTexture::R32U: + return QOpenGLTexture::Red_Integer; + case QOpenGLTexture::RG32U: + return QOpenGLTexture::RG_Integer; + case QOpenGLTexture::RGB32U: + return QOpenGLTexture::RGB_Integer; + case QOpenGLTexture::RGBA32U: + return QOpenGLTexture::RGBA_Integer; + case QOpenGLTexture::R8I: + return QOpenGLTexture::Red_Integer; + case QOpenGLTexture::RG8I: + return QOpenGLTexture::RG_Integer; + case QOpenGLTexture::RGB8I: + return QOpenGLTexture::RGB_Integer; + case QOpenGLTexture::RGBA8I: + return QOpenGLTexture::RGBA_Integer; + case QOpenGLTexture::R16I: + return QOpenGLTexture::Red_Integer; + case QOpenGLTexture::RG16I: + return QOpenGLTexture::RG_Integer; + case QOpenGLTexture::RGB16I: + return QOpenGLTexture::RGB_Integer; + case QOpenGLTexture::RGBA16I: + return QOpenGLTexture::RGBA_Integer; + case QOpenGLTexture::R32I: + return QOpenGLTexture::Red_Integer; + case QOpenGLTexture::RG32I: + return QOpenGLTexture::RG_Integer; + case QOpenGLTexture::RGB32I: + return QOpenGLTexture::RGB_Integer; + case QOpenGLTexture::RGBA32I: + return QOpenGLTexture::RGBA_Integer; + case QOpenGLTexture::R16F: + return QOpenGLTexture::Red; + case QOpenGLTexture::RG16F: + return QOpenGLTexture::RG; + case QOpenGLTexture::RGB16F: + return QOpenGLTexture::RGB; + case QOpenGLTexture::RGBA16F: + return QOpenGLTexture::RGBA; + case QOpenGLTexture::R32F: + return QOpenGLTexture::Red; + case QOpenGLTexture::RG32F: + return QOpenGLTexture::RG; + case QOpenGLTexture::RGB32F: + return QOpenGLTexture::RGB; + case QOpenGLTexture::RGBA32F: + return QOpenGLTexture::RGBA; + case QOpenGLTexture::RGB9E5: + return QOpenGLTexture::RGB; + case QOpenGLTexture::RG11B10F: + return QOpenGLTexture::RGB; + case QOpenGLTexture::RG3B2: + return QOpenGLTexture::RGB; + case QOpenGLTexture::R5G6B5: + return QOpenGLTexture::RGB; + case QOpenGLTexture::RGB5A1: + return QOpenGLTexture::RGBA; + case QOpenGLTexture::RGBA4: + return QOpenGLTexture::RGBA; + case QOpenGLTexture::RGB10A2: return QOpenGLTexture::RGBA; @@ -402,6 +660,26 @@ static QOpenGLTexture::PixelFormat pixelFormatCompatibleWithInternalFormat(QOpen case QOpenGLTexture::SRGB_BP_UNorm: return QOpenGLTexture::RGBA; + case QOpenGLTexture::R11_EAC_UNorm: + case QOpenGLTexture::R11_EAC_SNorm: + return QOpenGLTexture::Red; + + case QOpenGLTexture::RG11_EAC_UNorm: + case QOpenGLTexture::RG11_EAC_SNorm: + return QOpenGLTexture::RG; + + case QOpenGLTexture::RGB8_ETC2: + case QOpenGLTexture::SRGB8_ETC2: + return QOpenGLTexture::RGB; + + case QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2: + case QOpenGLTexture::SRGB8_PunchThrough_Alpha1_ETC2: + return QOpenGLTexture::RGBA; + + case QOpenGLTexture::RGBA8_ETC2_EAC: + case QOpenGLTexture::SRGB8_Alpha8_ETC2_EAC: + return QOpenGLTexture::RGBA; + case QOpenGLTexture::DepthFormat: return QOpenGLTexture::Depth; @@ -437,6 +715,8 @@ static QOpenGLTexture::PixelType pixelTypeCompatibleWithInternalFormat(QOpenGLTe case QOpenGLTexture::RG16_UNorm: case QOpenGLTexture::RGB16_UNorm: case QOpenGLTexture::RGBA16_UNorm: + return QOpenGLTexture::UInt8; + case QOpenGLTexture::R8_SNorm: case QOpenGLTexture::RG8_SNorm: case QOpenGLTexture::RGB8_SNorm: @@ -445,6 +725,8 @@ static QOpenGLTexture::PixelType pixelTypeCompatibleWithInternalFormat(QOpenGLTe case QOpenGLTexture::RG16_SNorm: case QOpenGLTexture::RGB16_SNorm: case QOpenGLTexture::RGBA16_SNorm: + return QOpenGLTexture::Int8; + case QOpenGLTexture::R8U: case QOpenGLTexture::RG8U: case QOpenGLTexture::RGB8U: @@ -457,6 +739,8 @@ static QOpenGLTexture::PixelType pixelTypeCompatibleWithInternalFormat(QOpenGLTe case QOpenGLTexture::RG32U: case QOpenGLTexture::RGB32U: case QOpenGLTexture::RGBA32U: + return QOpenGLTexture::UInt8; + case QOpenGLTexture::R8I: case QOpenGLTexture::RG8I: case QOpenGLTexture::RGB8I: @@ -469,28 +753,50 @@ static QOpenGLTexture::PixelType pixelTypeCompatibleWithInternalFormat(QOpenGLTe case QOpenGLTexture::RG32I: case QOpenGLTexture::RGB32I: case QOpenGLTexture::RGBA32I: + return QOpenGLTexture::Int8; + case QOpenGLTexture::R16F: case QOpenGLTexture::RG16F: case QOpenGLTexture::RGB16F: case QOpenGLTexture::RGBA16F: + return QOpenGLTexture::Float16; + case QOpenGLTexture::R32F: case QOpenGLTexture::RG32F: case QOpenGLTexture::RGB32F: case QOpenGLTexture::RGBA32F: + return QOpenGLTexture::Float32; + case QOpenGLTexture::RGB9E5: + return QOpenGLTexture::UInt16_RGB5A1_Rev; + case QOpenGLTexture::RG11B10F: + return QOpenGLTexture::UInt32_RG11B10F; + case QOpenGLTexture::RG3B2: + return QOpenGLTexture::UInt8_RG3B2; + case QOpenGLTexture::R5G6B5: + return QOpenGLTexture::UInt16_R5G6B5; + case QOpenGLTexture::RGB5A1: + return QOpenGLTexture::UInt16_RGB5A1; + case QOpenGLTexture::RGBA4: + return QOpenGLTexture::UInt16_RGBA4; + case QOpenGLTexture::RGB10A2: - return QOpenGLTexture::UInt8; + return QOpenGLTexture::UInt32_RGB10A2; case QOpenGLTexture::D16: + return QOpenGLTexture::UInt16; + case QOpenGLTexture::D24: case QOpenGLTexture::D32: + return QOpenGLTexture::UInt32; + case QOpenGLTexture::D32F: - return QOpenGLTexture::UInt8; + return QOpenGLTexture::Float32; case QOpenGLTexture::D24S8: return QOpenGLTexture::UInt32_D24S8; @@ -519,6 +825,16 @@ static QOpenGLTexture::PixelType pixelTypeCompatibleWithInternalFormat(QOpenGLTe case QOpenGLTexture::SRGB_Alpha_DXT3: case QOpenGLTexture::SRGB_Alpha_DXT5: case QOpenGLTexture::SRGB_BP_UNorm: + case QOpenGLTexture::R11_EAC_UNorm: + case QOpenGLTexture::R11_EAC_SNorm: + case QOpenGLTexture::RG11_EAC_UNorm: + case QOpenGLTexture::RG11_EAC_SNorm: + case QOpenGLTexture::RGB8_ETC2: + case QOpenGLTexture::SRGB8_ETC2: + case QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2: + case QOpenGLTexture::SRGB8_PunchThrough_Alpha1_ETC2: + case QOpenGLTexture::RGBA8_ETC2_EAC: + case QOpenGLTexture::SRGB8_Alpha8_ETC2_EAC: return QOpenGLTexture::UInt8; case QOpenGLTexture::DepthFormat: @@ -534,11 +850,8 @@ static QOpenGLTexture::PixelType pixelTypeCompatibleWithInternalFormat(QOpenGLTe return QOpenGLTexture::NoPixelType; } -void QOpenGLTexturePrivate::allocateMutableStorage() +void QOpenGLTexturePrivate::allocateMutableStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType) { - const QOpenGLTexture::PixelFormat pixelFormat = pixelFormatCompatibleWithInternalFormat(format); - const QOpenGLTexture::PixelType pixelType = pixelTypeCompatibleWithInternalFormat(format); - switch (target) { case QOpenGLTexture::TargetBuffer: // Buffer textures get their storage from an external OpenGL buffer @@ -747,7 +1060,7 @@ void QOpenGLTexturePrivate::allocateImmutableStorage() break; case QOpenGLTexture::Target2DMultisample: - if (features.testFlag(QOpenGLTexture::TextureMultisample)) { + if (features.testFlag(QOpenGLTexture::ImmutableMultisampleStorage)) { texFuncs->glTextureStorage2DMultisample(textureId, target, bindingTarget, samples, format, dimensions[0], dimensions[1], fixedSamplePositions); @@ -758,7 +1071,7 @@ void QOpenGLTexturePrivate::allocateImmutableStorage() break; case QOpenGLTexture::Target2DMultisampleArray: - if (features.testFlag(QOpenGLTexture::TextureMultisample) + if (features.testFlag(QOpenGLTexture::ImmutableMultisampleStorage) && features.testFlag(QOpenGLTexture::TextureArrays)) { texFuncs->glTextureStorage3DMultisample(textureId, target, bindingTarget, samples, format, dimensions[0], dimensions[1], layers, @@ -1525,6 +1838,16 @@ QOpenGLTexture *QOpenGLTexturePrivate::createTextureView(QOpenGLTexture::Target \value RGB_BP_UNSIGNED_FLOAT Equivalent to GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB \value RGB_BP_SIGNED_FLOAT Equivalent to GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB \value RGB_BP_UNorm Equivalent to GL_COMPRESSED_RGBA_BPTC_UNORM_ARB + \value R11_EAC_UNorm Equivalent to GL_COMPRESSED_R11_EAC + \value R11_EAC_SNorm Equivalent to GL_COMPRESSED_SIGNED_R11_EAC + \value RG11_EAC_UNorm Equivalent to GL_COMPRESSED_RG11_EAC + \value RG11_EAC_SNorm Equivalent to GL_COMPRESSED_SIGNED_RG11_EAC + \value RGB8_ETC2 Equivalent to GL_COMPRESSED_RGB8_ETC2 + \value SRGB8_ETC2 Equivalent to GL_COMPRESSED_SRGB8_ETC2 + \value RGB8_PunchThrough_Alpha1_ETC2 Equivalent to GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 + \value SRGB8_PunchThrough_Alpha1_ETC2 Equivalent to GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 + \value RGBA8_ETC2_EAC Equivalent to GL_COMPRESSED_RGBA8_ETC2_EAC + \value SRGB8_Alpha8_ETC2_EAC Equivalent to GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC \value SRGB8 Equivalent to GL_SRGB8 \value SRGB8_Alpha8 Equivalent to GL_SRGB8_ALPHA8 @@ -2050,6 +2373,16 @@ void QOpenGLTexture::setFormat(TextureFormat format) d->formatClass = FormatClass_S3TC_DXT5_RGBA; break; + case QOpenGLTexture::R11_EAC_UNorm: + case QOpenGLTexture::R11_EAC_SNorm: + case QOpenGLTexture::RG11_EAC_UNorm: + case QOpenGLTexture::RG11_EAC_SNorm: + case QOpenGLTexture::RGB8_ETC2: + case QOpenGLTexture::SRGB8_ETC2: + case QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2: + case QOpenGLTexture::SRGB8_PunchThrough_Alpha1_ETC2: + case QOpenGLTexture::RGBA8_ETC2_EAC: + case QOpenGLTexture::SRGB8_Alpha8_ETC2_EAC: case RG3B2: case R5G6B5: case RGB5A1: @@ -2436,17 +2769,58 @@ bool QOpenGLTexture::isFixedSamplePositions() const Once storage has been allocated for the texture then pixel data can be uploaded via one of the setData() overloads. + \note If immutable texture storage is not available, + then a default pixel format and pixel type will be used to + create the mutable storage. You can use the other + allocateStorage() overload to specify exactly the pixel format + and the pixel type to use when allocating mutable storage; + this is particulary useful under certain OpenGL ES implementations + (notably, OpenGL ES 2), where the pixel format and the pixel type + used at allocation time must perfectly match the format + and the type passed to any subsequent setData() call. + \sa isStorageAllocated(), setData() */ void QOpenGLTexture::allocateStorage() { Q_D(QOpenGLTexture); if (d->create()) { - d->allocateStorage(); + const QOpenGLTexture::PixelFormat pixelFormat = pixelFormatCompatibleWithInternalFormat(d->format); + const QOpenGLTexture::PixelType pixelType = pixelTypeCompatibleWithInternalFormat(d->format); + d->allocateStorage(pixelFormat, pixelType); } } /*! + \since 5.5 + + Allocates server-side storage for this texture object taking + into account, the format, dimensions, mipmap levels, array + layers and cubemap faces. + + Once storage has been allocated it is no longer possible to change + these properties. + + If supported QOpenGLTexture makes use of immutable texture + storage. However, if immutable texture storage is not available, + then the specified \a pixelFormat and \a pixelType will be used + to allocate mutable storage; note that in certain OpenGL implementations + (notably, OpenGL ES 2) they must perfectly match the format + and the type passed to any subsequent setData() call. + + Once storage has been allocated for the texture then pixel data + can be uploaded via one of the setData() overloads. + + \sa isStorageAllocated(), setData() +*/ +void QOpenGLTexture::allocateStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType) +{ + Q_D(QOpenGLTexture); + if (d->create()) + d->allocateStorage(pixelFormat, pixelType); +} + +/*! Returns \c true if server-side storage for this texture as been allocated. @@ -2547,7 +2921,7 @@ void QOpenGLTexture::setData(int mipLevel, int layer, CubeMapFace cubeFace, Q_ASSERT(d->textureId); if (!isStorageAllocated()) { qWarning("Cannot set data on a texture that does not have storage allocated.\n" - "To do so call allocate() before this function"); + "To do so call allocateStorage() before this function"); return; } d->setData(mipLevel, layer, cubeFace, sourceFormat, sourceType, data, options); @@ -2605,7 +2979,7 @@ void QOpenGLTexture::setData(int mipLevel, int layer, CubeMapFace cubeFace, Q_ASSERT(d->textureId); if (!isStorageAllocated()) { qWarning("Cannot set data on a texture that does not have storage allocated.\n" - "To do so call allocate() before this function"); + "To do so call allocateStorage() before this function"); return; } d->setData(mipLevel, layer, cubeFace, sourceFormat, sourceType, data, options); @@ -2670,7 +3044,7 @@ void QOpenGLTexture::setData(const QImage& image, MipMapGeneration genMipMaps) setSize(image.width(), image.height()); setMipLevels(genMipMaps == GenerateMipMaps ? maximumMipLevels() : 1); - allocateStorage(); + allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); // Upload pixel data and generate mipmaps QImage glImage = image.convertToFormat(QImage::Format_RGBA8888); @@ -2697,7 +3071,7 @@ void QOpenGLTexture::setCompressedData(int mipLevel, int layer, CubeMapFace cube Q_ASSERT(d->textureId); if (!isStorageAllocated()) { qWarning("Cannot set data on a texture that does not have storage allocated.\n" - "To do so call allocate() before this function"); + "To do so call allocateStorage() before this function"); return; } d->setCompressedData(mipLevel, layer, cubeFace, dataSize, data, options); @@ -2748,7 +3122,7 @@ void QOpenGLTexture::setCompressedData(int mipLevel, int layer, CubeMapFace cube Q_ASSERT(d->textureId); if (!isStorageAllocated()) { qWarning("Cannot set data on a texture that does not have storage allocated.\n" - "To do so call allocate() before this function"); + "To do so call allocateStorage() before this function"); return; } d->setCompressedData(mipLevel, layer, cubeFace, dataSize, data, options); @@ -2826,7 +3200,8 @@ bool QOpenGLTexture::hasFeature(Feature feature) case ImmutableStorage: supported = f.version() >= qMakePair(4, 2) - || ctx->hasExtension(QByteArrayLiteral("GL_ARB_texture_storage")); + || ctx->hasExtension(QByteArrayLiteral("GL_ARB_texture_storage")) + || ctx->hasExtension(QByteArrayLiteral("GL_EXT_texture_storage")); break; case TextureCubeMapArrays: @@ -2873,9 +3248,6 @@ bool QOpenGLTexture::hasFeature(Feature feature) case MaxFeatureFlag: break; - - default: - break; } } @@ -2883,21 +3255,59 @@ bool QOpenGLTexture::hasFeature(Feature feature) #endif { switch (feature) { + case ImmutableStorage: + supported = f.version() >= qMakePair(3, 0) + || ctx->hasExtension(QByteArrayLiteral("EXT_texture_storage")); + break; + + case ImmutableMultisampleStorage: + supported = f.version() >= qMakePair(3, 1); + break; + + case TextureRectangle: + break; + + case TextureArrays: + supported = f.version() >= qMakePair(3, 0); + break; + case Texture3D: - supported = ctx->hasExtension(QByteArrayLiteral("GL_OES_texture_3D")); + supported = f.version() >= qMakePair(3, 0) + || ctx->hasExtension(QByteArrayLiteral("GL_OES_texture_3D")); + break; + + case TextureMultisample: + supported = f.version() >= qMakePair(3, 1); break; + + case TextureBuffer: + break; + + case TextureCubeMapArrays: + break; + + case Swizzle: + supported = f.version() >= qMakePair(3, 0); + break; + + case StencilTexturing: + break; + case AnisotropicFiltering: supported = ctx->hasExtension(QByteArrayLiteral("GL_EXT_texture_filter_anisotropic")); break; + case NPOTTextures: case NPOTTextureRepeat: - supported = f.version() >= qMakePair(3,0); - if (!supported) { - supported = ctx->hasExtension(QByteArrayLiteral("GL_OES_texture_npot")); - if (!supported) - supported = ctx->hasExtension(QByteArrayLiteral("GL_ARB_texture_non_power_of_two")); - } - default: + supported = f.version() >= qMakePair(3,0) + || ctx->hasExtension(QByteArrayLiteral("GL_OES_texture_npot")) + || ctx->hasExtension(QByteArrayLiteral("GL_ARB_texture_non_power_of_two")); + break; + + case Texture1D: + break; + + case MaxFeatureFlag: break; } } diff --git a/src/gui/opengl/qopengltexture.h b/src/gui/opengl/qopengltexture.h index a53b1730b7..0f999a8409 100644 --- a/src/gui/opengl/qopengltexture.h +++ b/src/gui/opengl/qopengltexture.h @@ -88,29 +88,6 @@ public: DontResetTextureUnit }; - explicit QOpenGLTexture(Target target); - explicit QOpenGLTexture(const QImage& image, MipMapGeneration genMipMaps = GenerateMipMaps); - ~QOpenGLTexture(); - - Target target() const; - - // Creation and destruction - bool create(); - void destroy(); - bool isCreated() const; - GLuint textureId() const; - - // Binding and releasing - void bind(); - void bind(uint unit, TextureUnitReset reset = DontResetTextureUnit); - void release(); - void release(uint unit, TextureUnitReset reset = DontResetTextureUnit); - - bool isBound() const; - bool isBound(uint unit); - static GLuint boundTextureId(BindingTarget target); - static GLuint boundTextureId(uint unit, BindingTarget target); - enum TextureFormat { NoFormat = 0, // GL_NONE @@ -209,6 +186,16 @@ public: RGB_BP_UNSIGNED_FLOAT = 0x8E8F, // GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB RGB_BP_SIGNED_FLOAT = 0x8E8E, // GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB RGB_BP_UNorm = 0x8E8C, // GL_COMPRESSED_RGBA_BPTC_UNORM_ARB + R11_EAC_UNorm = 0x9270, // GL_COMPRESSED_R11_EAC + R11_EAC_SNorm = 0x9271, // GL_COMPRESSED_SIGNED_R11_EAC + RG11_EAC_UNorm = 0x9272, // GL_COMPRESSED_RG11_EAC + RG11_EAC_SNorm = 0x9273, // GL_COMPRESSED_SIGNED_RG11_EAC + RGB8_ETC2 = 0x9274, // GL_COMPRESSED_RGB8_ETC2 + SRGB8_ETC2 = 0x9275, // GL_COMPRESSED_SRGB8_ETC2 + RGB8_PunchThrough_Alpha1_ETC2 = 0x9276, // GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 + SRGB8_PunchThrough_Alpha1_ETC2 = 0x9277, // GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 + RGBA8_ETC2_EAC = 0x9278, // GL_COMPRESSED_RGBA8_ETC2_EAC + SRGB8_Alpha8_ETC2_EAC = 0x9279, // GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC // sRGB formats SRGB8 = 0x8C41, // GL_SRGB8 @@ -254,32 +241,6 @@ public: }; #endif - // Storage allocation - void setFormat(TextureFormat format); - TextureFormat format() const; - void setSize(int width, int height = 1, int depth = 1); - int width() const; - int height() const; - int depth() const; - void setMipLevels(int levels); - int mipLevels() const; - int maximumMipLevels() const; - void setLayers(int layers); - int layers() const; - int faces() const; - void setSamples(int samples); - int samples() const; - void setFixedSamplePositions(bool fixed); - bool isFixedSamplePositions() const; - void allocateStorage(); - bool isStorageAllocated() const; - - QOpenGLTexture *createTextureView(Target target, - TextureFormat viewFormat, - int minimumMipmapLevel, int maximumMipmapLevel, - int minimumLayer, int maximumLayer) const; - bool isTextureView() const; - enum CubeMapFace { CubeMapPositiveX = 0x8515, // GL_TEXTURE_CUBE_MAP_POSITIVE_X CubeMapNegativeX = 0x8516, // GL_TEXTURE_CUBE_MAP_NEGATIVE_X @@ -340,6 +301,107 @@ public: Float32_D32_UInt32_S8_X24 = 0x8DAD // GL_FLOAT_32_UNSIGNED_INT_24_8_REV }; + enum SwizzleComponent { + SwizzleRed = 0x8E42, // GL_TEXTURE_SWIZZLE_R + SwizzleGreen = 0x8E43, // GL_TEXTURE_SWIZZLE_G + SwizzleBlue = 0x8E44, // GL_TEXTURE_SWIZZLE_B + SwizzleAlpha = 0x8E45 // GL_TEXTURE_SWIZZLE_A + }; + + enum SwizzleValue { + RedValue = 0x1903, // GL_RED + GreenValue = 0x1904, // GL_GREEN + BlueValue = 0x1905, // GL_BLUE + AlphaValue = 0x1906, // GL_ALPHA + ZeroValue = 0, // GL_ZERO + OneValue = 1 // GL_ONE + }; + + enum WrapMode { + Repeat = 0x2901, // GL_REPEAT + MirroredRepeat = 0x8370, // GL_MIRRORED_REPEAT + ClampToEdge = 0x812F, // GL_CLAMP_TO_EDGE + ClampToBorder = 0x812D // GL_CLAMP_TO_BORDER + }; + + enum CoordinateDirection { + DirectionS = 0x2802, // GL_TEXTURE_WRAP_S + DirectionT = 0x2803, // GL_TEXTURE_WRAP_T + DirectionR = 0x8072 // GL_TEXTURE_WRAP_R + }; + + // Features + enum Feature { + ImmutableStorage = 0x00000001, + ImmutableMultisampleStorage = 0x00000002, + TextureRectangle = 0x00000004, + TextureArrays = 0x00000008, + Texture3D = 0x00000010, + TextureMultisample = 0x00000020, + TextureBuffer = 0x00000040, + TextureCubeMapArrays = 0x00000080, + Swizzle = 0x00000100, + StencilTexturing = 0x00000200, + AnisotropicFiltering = 0x00000400, + NPOTTextures = 0x00000800, + NPOTTextureRepeat = 0x00001000, + Texture1D = 0x00002000, +#ifndef Q_QDOC + MaxFeatureFlag = 0x00004000 +#endif + }; + Q_DECLARE_FLAGS(Features, Feature) + + explicit QOpenGLTexture(Target target); + explicit QOpenGLTexture(const QImage& image, MipMapGeneration genMipMaps = GenerateMipMaps); + ~QOpenGLTexture(); + + Target target() const; + + // Creation and destruction + bool create(); + void destroy(); + bool isCreated() const; + GLuint textureId() const; + + // Binding and releasing + void bind(); + void bind(uint unit, TextureUnitReset reset = DontResetTextureUnit); + void release(); + void release(uint unit, TextureUnitReset reset = DontResetTextureUnit); + + bool isBound() const; + bool isBound(uint unit); + static GLuint boundTextureId(BindingTarget target); + static GLuint boundTextureId(uint unit, BindingTarget target); + + // Storage allocation + void setFormat(TextureFormat format); + TextureFormat format() const; + void setSize(int width, int height = 1, int depth = 1); + int width() const; + int height() const; + int depth() const; + void setMipLevels(int levels); + int mipLevels() const; + int maximumMipLevels() const; + void setLayers(int layers); + int layers() const; + int faces() const; + void setSamples(int samples); + int samples() const; + void setFixedSamplePositions(bool fixed); + bool isFixedSamplePositions() const; + void allocateStorage(); + void allocateStorage(PixelFormat pixelFormat, PixelType pixelType); + bool isStorageAllocated() const; + + QOpenGLTexture *createTextureView(Target target, + TextureFormat viewFormat, + int minimumMipmapLevel, int maximumMipmapLevel, + int minimumLayer, int maximumLayer) const; + bool isTextureView() const; + // Pixel transfer // ### Qt 6: remove the non-const void * overloads QT_DEPRECATED void setData(int mipLevel, int layer, CubeMapFace cubeFace, @@ -393,28 +455,6 @@ public: // Helpful overloads for setData void setData(const QImage& image, MipMapGeneration genMipMaps = GenerateMipMaps); - // Features - enum Feature { - ImmutableStorage = 0x00000001, - ImmutableMultisampleStorage = 0x00000002, - TextureRectangle = 0x00000004, - TextureArrays = 0x00000008, - Texture3D = 0x00000010, - TextureMultisample = 0x00000020, - TextureBuffer = 0x00000040, - TextureCubeMapArrays = 0x00000080, - Swizzle = 0x00000100, - StencilTexturing = 0x00000200, - AnisotropicFiltering = 0x00000400, - NPOTTextures = 0x00000800, - NPOTTextureRepeat = 0x00001000, - Texture1D = 0x00002000, -#ifndef Q_QDOC - MaxFeatureFlag = 0x00004000 -#endif - }; - Q_DECLARE_FLAGS(Features, Feature) - static bool hasFeature(Feature feature); // Texture Parameters @@ -431,22 +471,6 @@ public: void generateMipMaps(); void generateMipMaps(int baseLevel, bool resetBaseLevel = true); - enum SwizzleComponent { - SwizzleRed = 0x8E42, // GL_TEXTURE_SWIZZLE_R - SwizzleGreen = 0x8E43, // GL_TEXTURE_SWIZZLE_G - SwizzleBlue = 0x8E44, // GL_TEXTURE_SWIZZLE_B - SwizzleAlpha = 0x8E45 // GL_TEXTURE_SWIZZLE_A - }; - - enum SwizzleValue { - RedValue = 0x1903, // GL_RED - GreenValue = 0x1904, // GL_GREEN - BlueValue = 0x1905, // GL_BLUE - AlphaValue = 0x1906, // GL_ALPHA - ZeroValue = 0, // GL_ZERO - OneValue = 1 // GL_ONE - }; - void setSwizzleMask(SwizzleComponent component, SwizzleValue value); void setSwizzleMask(SwizzleValue r, SwizzleValue g, SwizzleValue b, SwizzleValue a); @@ -480,19 +504,6 @@ public: void setMaximumAnisotropy(float anisotropy); float maximumAnisotropy() const; - enum WrapMode { - Repeat = 0x2901, // GL_REPEAT - MirroredRepeat = 0x8370, // GL_MIRRORED_REPEAT - ClampToEdge = 0x812F, // GL_CLAMP_TO_EDGE - ClampToBorder = 0x812D // GL_CLAMP_TO_BORDER - }; - - enum CoordinateDirection { - DirectionS = 0x2802, // GL_TEXTURE_WRAP_S - DirectionT = 0x2803, // GL_TEXTURE_WRAP_T - DirectionR = 0x8072 // GL_TEXTURE_WRAP_R - }; - void setWrapMode(WrapMode mode); void setWrapMode(CoordinateDirection direction, WrapMode mode); WrapMode wrapMode(CoordinateDirection direction) const; diff --git a/src/gui/opengl/qopengltexture_p.h b/src/gui/opengl/qopengltexture_p.h index b584d3ec8f..3b70010231 100644 --- a/src/gui/opengl/qopengltexture_p.h +++ b/src/gui/opengl/qopengltexture_p.h @@ -87,8 +87,8 @@ public: bool isBound() const; bool isBound(uint unit) const; - void allocateStorage(); - void allocateMutableStorage(); + void allocateStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType); + void allocateMutableStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType); void allocateImmutableStorage(); void setData(int mipLevel, int layer, QOpenGLTexture::CubeMapFace cubeFace, QOpenGLTexture::PixelFormat sourceFormat, QOpenGLTexture::PixelType sourceType, diff --git a/src/gui/opengl/qopengltexturecache.cpp b/src/gui/opengl/qopengltexturecache.cpp index 3b24e1f576..f85a26cd6e 100644 --- a/src/gui/opengl/qopengltexturecache.cpp +++ b/src/gui/opengl/qopengltexturecache.cpp @@ -41,6 +41,10 @@ QT_BEGIN_NAMESPACE +#ifndef GL_RED +#define GL_RED 0x1903 +#endif + #ifndef GL_RGB10_A2 #define GL_RGB10_A2 0x8059 #endif @@ -273,6 +277,35 @@ GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, qint64 key, con pixelType = GL_UNSIGNED_BYTE; targetFormat = image.format(); break; + case QImage::Format_Indexed8: + if (options & UseRedFor8BitBindOption) { + externalFormat = internalFormat = GL_RED; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = image.format(); + } + break; + case QImage::Format_Alpha8: + if (options & UseRedFor8BitBindOption) { + externalFormat = internalFormat = GL_RED; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = image.format(); + } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) { + externalFormat = internalFormat = GL_ALPHA; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = image.format(); + } + break; + case QImage::Format_Grayscale8: + if (options & UseRedFor8BitBindOption) { + externalFormat = internalFormat = GL_RED; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = image.format(); + } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) { + externalFormat = internalFormat = GL_LUMINANCE; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = image.format(); + } + break; default: break; } diff --git a/src/gui/opengl/qopengltexturecache_p.h b/src/gui/opengl/qopengltexturecache_p.h index f856054a85..45dc20e146 100644 --- a/src/gui/opengl/qopengltexturecache_p.h +++ b/src/gui/opengl/qopengltexturecache_p.h @@ -78,6 +78,7 @@ public: enum BindOption { NoBindOption = 0x0000, PremultipliedAlphaBindOption = 0x0001, + UseRedFor8BitBindOption = 0x0002, }; Q_DECLARE_FLAGS(BindOptions, BindOption) diff --git a/src/gui/opengl/qopengltexturehelper.cpp b/src/gui/opengl/qopengltexturehelper.cpp index 29cecf0ea8..1eeab64911 100644 --- a/src/gui/opengl/qopengltexturehelper.cpp +++ b/src/gui/opengl/qopengltexturehelper.cpp @@ -200,8 +200,13 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context) TexImage2DMultisample = 0; // OpenGL 4.2 +#ifdef QT_OPENGL_ES_3 + TexStorage3D = ::glTexStorage3D; + TexStorage2D = ::glTexStorage2D; +#else TexStorage3D = 0; TexStorage2D = 0; +#endif TexStorage1D = 0; // OpenGL 4.3 diff --git a/src/gui/opengl/qopenglvertexarrayobject.cpp b/src/gui/opengl/qopenglvertexarrayobject.cpp index 5520dfed08..d8979fd98f 100644 --- a/src/gui/opengl/qopenglvertexarrayobject.cpp +++ b/src/gui/opengl/qopenglvertexarrayobject.cpp @@ -146,6 +146,11 @@ bool QOpenGLVertexArrayObjectPrivate::create() qWarning("QOpenGLVertexArrayObject::create() requires a valid current OpenGL context"); return false; } + + //Fail early, if context is the same as ctx, it means we have tried to initialize for this context and failed + if (ctx == context) + return false; + context = ctx; QObject::connect(context, SIGNAL(aboutToBeDestroyed()), q, SLOT(_q_contextAboutToBeDestroyed())); diff --git a/src/gui/opengl/qtriangulator.cpp b/src/gui/opengl/qtriangulator.cpp index f44c8adcf5..74b8f01985 100644 --- a/src/gui/opengl/qtriangulator.cpp +++ b/src/gui/opengl/qtriangulator.cpp @@ -441,8 +441,8 @@ T QMaxHeap<T>::pop() // Copied from qhash.cpp static const uchar prime_deltas[] = { - 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3, - 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0 + 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 17, 27, 3, + 1, 29, 3, 21, 7, 17, 15, 9, 43, 35, 15, 0, 0, 0, 0, 0 }; // Copied from qhash.cpp @@ -457,7 +457,7 @@ static inline int primeForCount(int count) int high = 32; for (int i = 0; i < 5; ++i) { int mid = (high + low) / 2; - if (count >= 1 << mid) + if (uint(count) >= (1u << mid)) low = mid; else high = mid; diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index a5a395cce2..588a2f0a88 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -41,6 +41,7 @@ HEADERS += \ painting/qrasterdefs_p.h \ painting/qrasterizer_p.h \ painting/qregion.h \ + painting/qrgb.h \ painting/qstroker_p.h \ painting/qtextureglyphcache_p.h \ painting/qtransform.h \ diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp index 2da5dbb356..e174d1f1cd 100644 --- a/src/gui/painting/qblendfunctions.cpp +++ b/src/gui/painting/qblendfunctions.cpp @@ -764,7 +764,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGRs30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_Mono 0, // Format_Invalid, @@ -789,7 +791,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_MonoLSB 0, // Format_Invalid, @@ -814,7 +818,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_Indexed8 0, // Format_Invalid, @@ -839,7 +845,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB32 0, // Format_Invalid, @@ -864,7 +872,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB32 0, // Format_Invalid, @@ -889,7 +899,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB32_Premultiplied 0, // Format_Invalid, @@ -914,7 +926,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB16 0, // Format_Invalid, @@ -939,7 +953,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB8565_Premultiplied 0, // Format_Invalid, @@ -964,7 +980,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB666 0, // Format_Invalid, @@ -989,7 +1007,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB6666_Premultiplied 0, // Format_Invalid, @@ -1014,7 +1034,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB555 0, // Format_Invalid, @@ -1039,7 +1061,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB8555_Premultiplied 0, // Format_Invalid, @@ -1064,7 +1088,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB888 0, // Format_Invalid, @@ -1089,7 +1115,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB444 0, // Format_Invalid, @@ -1114,7 +1142,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB4444_Premultiplied 0, // Format_Invalid, @@ -1139,7 +1169,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGBX8888 0, // Format_Invalid, @@ -1170,7 +1202,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGBA8888 0, // Format_Invalid, @@ -1195,7 +1229,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGBA8888_Premultiplied 0, // Format_Invalid, @@ -1226,7 +1262,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_BGR30 0, // Format_Invalid, @@ -1251,7 +1289,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_A2BGR30_Premultiplied 0, // Format_Invalid, @@ -1276,7 +1316,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB30 0, // Format_Invalid, @@ -1301,7 +1343,9 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_A2RGB30_Premultiplied 0, // Format_Invalid, @@ -1326,8 +1370,64 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 + }, + { // Format_Alpha8 + 0, // Format_Invalid, + 0, // Format_Mono, + 0, // Format_MonoLSB, + 0, // Format_Indexed8, + 0, // Format_RGB32, + 0, // Format_ARGB32, + 0, // Format_ARGB32_Premultiplied, + 0, // Format_RGB16, + 0, // Format_ARGB8565_Premultiplied, + 0, // Format_RGB666, + 0, // Format_ARGB6666_Premultiplied, + 0, // Format_RGB555, + 0, // Format_ARGB8555_Premultiplied, + 0, // Format_RGB888, + 0, // Format_RGB444, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0, // Format_RGBA8888_Premultiplied, + 0, // Format_BGR30, + 0, // Format_A2BGR30_Premultiplied, + 0, // Format_RGB30, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, + { // Format_Grayscale8 + 0, // Format_Invalid, + 0, // Format_Mono, + 0, // Format_MonoLSB, + 0, // Format_Indexed8, + 0, // Format_RGB32, + 0, // Format_ARGB32, + 0, // Format_ARGB32_Premultiplied, + 0, // Format_RGB16, + 0, // Format_ARGB8565_Premultiplied, + 0, // Format_RGB666, + 0, // Format_ARGB6666_Premultiplied, + 0, // Format_RGB555, + 0, // Format_ARGB8555_Premultiplied, + 0, // Format_RGB888, + 0, // Format_RGB444, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0, // Format_RGBA8888_Premultiplied, + 0, // Format_BGR30, + 0, // Format_A2BGR30_Premultiplied, + 0, // Format_RGB30, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 + } }; @@ -1355,7 +1455,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_Mono 0, // Format_Invalid, @@ -1380,7 +1482,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_MonoLSB 0, // Format_Invalid, @@ -1405,7 +1509,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_Indexed8 0, // Format_Invalid, @@ -1430,7 +1536,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB32 0, // Format_Invalid, @@ -1455,7 +1563,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB32 0, // Format_Invalid, @@ -1480,7 +1590,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB32_Premultiplied 0, // Format_Invalid, @@ -1505,7 +1617,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB16 0, // Format_Invalid, @@ -1530,7 +1644,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB8565_Premultiplied 0, // Format_Invalid, @@ -1555,7 +1671,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB666 0, // Format_Invalid, @@ -1580,7 +1698,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB6666_Premultiplied 0, // Format_Invalid, @@ -1605,7 +1725,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB555 0, // Format_Invalid, @@ -1630,7 +1752,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB8555_Premultiplied 0, // Format_Invalid, @@ -1655,7 +1779,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB888 0, // Format_Invalid, @@ -1680,7 +1806,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB444 0, // Format_Invalid, @@ -1705,7 +1833,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB4444_Premultiplied 0, // Format_Invalid, @@ -1730,7 +1860,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGBX8888 0, // Format_Invalid, @@ -1761,7 +1893,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGBA8888 0, // Format_Invalid, @@ -1786,7 +1920,9 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGBA8888_Premultiplied 0, // Format_Invalid, @@ -1818,6 +1954,8 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_BGR30 0, // Format_Invalid, @@ -1843,6 +1981,7 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = qt_blend_a2rgb30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_RGB30, qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, + 0, 0, }, { // Format_A2BGR30_Premultiplied 0, // Format_Invalid, @@ -1868,6 +2007,7 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = qt_blend_a2rgb30pm_on_a2rgb30pm, // Format_A2BGR30_Premultiplied, qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_RGB30, qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, + 0, 0, }, { // Format_RGB30 0, // Format_Invalid, @@ -1893,6 +2033,7 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_A2BGR30_Premultiplied, qt_blend_rgb30_on_rgb30, // Format_RGB30, qt_blend_a2rgb30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, + 0, 0, }, { // Format_A2RGB30_Premultiplied 0, // Format_Invalid, @@ -1917,8 +2058,63 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_BGR30, qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_A2BGR30_Premultiplied, qt_blend_rgb30_on_rgb30, // Format_RGB30, - qt_blend_a2rgb30pm_on_a2rgb30pm // Format_A2RGB30_Premultiplied, + qt_blend_a2rgb30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, + 0, 0, + }, + { // Format_Alpha8 + 0, // Format_Invalid, + 0, // Format_Mono, + 0, // Format_MonoLSB, + 0, // Format_Indexed8, + 0, // Format_RGB32, + 0, // Format_ARGB32, + 0, // Format_ARGB32_Premultiplied, + 0, // Format_RGB16, + 0, // Format_ARGB8565_Premultiplied, + 0, // Format_RGB666, + 0, // Format_ARGB6666_Premultiplied, + 0, // Format_RGB555, + 0, // Format_ARGB8555_Premultiplied, + 0, // Format_RGB888, + 0, // Format_RGB444, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0, // Format_RGBA8888_Premultiplied, + 0, // Format_BGR30, + 0, // Format_A2BGR30_Premultiplied, + 0, // Format_RGB30, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, + { // Format_Grayscale8 + 0, // Format_Invalid, + 0, // Format_Mono, + 0, // Format_MonoLSB, + 0, // Format_Indexed8, + 0, // Format_RGB32, + 0, // Format_ARGB32, + 0, // Format_ARGB32_Premultiplied, + 0, // Format_RGB16, + 0, // Format_ARGB8565_Premultiplied, + 0, // Format_RGB666, + 0, // Format_ARGB6666_Premultiplied, + 0, // Format_RGB555, + 0, // Format_ARGB8555_Premultiplied, + 0, // Format_RGB888, + 0, // Format_RGB444, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0, // Format_RGBA8888_Premultiplied, + 0, // Format_BGR30, + 0, // Format_A2BGR30_Premultiplied, + 0, // Format_RGB30, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 + } }; SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFormats] = { @@ -1945,7 +2141,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_Mono 0, // Format_Invalid, @@ -1970,7 +2168,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_MonoLSB 0, // Format_Invalid, @@ -1995,7 +2195,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_Indexed8 0, // Format_Invalid, @@ -2020,7 +2222,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB32 0, // Format_Invalid, @@ -2045,7 +2249,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB32 0, // Format_Invalid, @@ -2070,7 +2276,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB32_Premultiplied 0, // Format_Invalid, @@ -2095,7 +2303,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB16 0, // Format_Invalid, @@ -2120,7 +2330,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB8565_Premultiplied 0, // Format_Invalid, @@ -2145,7 +2357,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB666 0, // Format_Invalid, @@ -2170,7 +2384,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB6666_Premultiplied 0, // Format_Invalid, @@ -2195,7 +2411,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB555 0, // Format_Invalid, @@ -2220,7 +2438,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB8555_Premultiplied 0, // Format_Invalid, @@ -2245,7 +2465,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB888 0, // Format_Invalid, @@ -2270,7 +2492,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB444 0, // Format_Invalid, @@ -2295,7 +2519,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_ARGB4444_Premultiplied 0, // Format_Invalid, @@ -2320,7 +2546,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGBX8888 0, // Format_Invalid, @@ -2351,7 +2579,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGBA8888 0, // Format_Invalid, @@ -2376,7 +2606,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGBA8888_Premultiplied 0, // Format_Invalid, @@ -2407,7 +2639,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_BGR30 0, // Format_Invalid, @@ -2432,7 +2666,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_A2BGR30_Premultiplied 0, // Format_Invalid, @@ -2457,7 +2693,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_RGB30 0, // Format_Invalid, @@ -2482,7 +2720,9 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, { // Format_A2RGB30_Premultiplied 0, // Format_Invalid, @@ -2507,7 +2747,63 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo 0, // Format_BGR30, 0, // Format_A2BGR30_Premultiplied, 0, // Format_RGB30, - 0 // Format_A2RGB30_Premultiplied, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 + }, + { // Format_Alpha8 + 0, // Format_Invalid, + 0, // Format_Mono, + 0, // Format_MonoLSB, + 0, // Format_Indexed8, + 0, // Format_RGB32, + 0, // Format_ARGB32, + 0, // Format_ARGB32_Premultiplied, + 0, // Format_RGB16, + 0, // Format_ARGB8565_Premultiplied, + 0, // Format_RGB666, + 0, // Format_ARGB6666_Premultiplied, + 0, // Format_RGB555, + 0, // Format_ARGB8555_Premultiplied, + 0, // Format_RGB888, + 0, // Format_RGB444, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0, // Format_RGBA8888_Premultiplied, + 0, // Format_BGR30, + 0, // Format_A2BGR30_Premultiplied, + 0, // Format_RGB30, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 + }, + { // Format_Grayscale8 + 0, // Format_Invalid, + 0, // Format_Mono, + 0, // Format_MonoLSB, + 0, // Format_Indexed8, + 0, // Format_RGB32, + 0, // Format_ARGB32, + 0, // Format_ARGB32_Premultiplied, + 0, // Format_RGB16, + 0, // Format_ARGB8565_Premultiplied, + 0, // Format_RGB666, + 0, // Format_ARGB6666_Premultiplied, + 0, // Format_RGB555, + 0, // Format_ARGB8555_Premultiplied, + 0, // Format_RGB888, + 0, // Format_RGB444, + 0, // Format_ARGB4444_Premultiplied, + 0, // Format_RGBX8888, + 0, // Format_RGBA8888, + 0, // Format_RGBA8888_Premultiplied, + 0, // Format_BGR30, + 0, // Format_A2BGR30_Premultiplied, + 0, // Format_RGB30, + 0, // Format_A2RGB30_Premultiplied, + 0, // Format_Alpha8 + 0, // Format_Grayscale8 }, }; diff --git a/src/gui/painting/qbrush.h b/src/gui/painting/qbrush.h index ff652fe288..3dc2230afc 100644 --- a/src/gui/painting/qbrush.h +++ b/src/gui/painting/qbrush.h @@ -235,7 +235,7 @@ private: qreal cx, cy, angle; } conical; } m_data; - void *dummy; + void *dummy; // ### Qt 6: replace with actual content (CoordinateMode, InterpolationMode, ...) }; inline void QGradient::setSpread(Spread aspread) diff --git a/src/gui/painting/qcolor.h b/src/gui/painting/qcolor.h index b68504c865..926d05707e 100644 --- a/src/gui/painting/qcolor.h +++ b/src/gui/painting/qcolor.h @@ -65,7 +65,7 @@ public: QColor(QRgb rgb); QColor(const QString& name); QColor(const char *name); - QColor(const QColor &color); + QColor(const QColor &color); // ### Qt 6: remove, the trivial one is fine. QColor(Spec spec); bool isValid() const; diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 6482cc50f7..a991b89f48 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -527,6 +527,22 @@ static const uint *QT_FASTCALL convertRGBA8888ToARGB32PM(uint *buffer, const uin return buffer; } +static const uint *QT_FASTCALL convertAlpha8ToRGB32(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qRgba(0, 0, 0, src[i]); + return buffer; +} + +static const uint *QT_FASTCALL convertGrayscale8ToRGB32(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qRgb(src[i], src[i], src[i]); + return buffer; +} + static const uint *QT_FASTCALL convertARGB32FromARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) { @@ -603,6 +619,30 @@ static const uint *QT_FASTCALL convertRGB30FromARGB32PM(uint *buffer, const uint return buffer; } +static const uint *QT_FASTCALL convertAlpha8FromARGB32PM(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qAlpha(src[i]); + return buffer; +} + +static const uint *QT_FASTCALL convertGrayscale8FromRGB32(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qGray(src[i]); + return buffer; +} + +static const uint *QT_FASTCALL convertGrayscale8FromARGB32PM(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qGray(qUnpremultiply(src[i])); + return buffer; +} + template <QPixelLayout::BPP bpp> static uint QT_FASTCALL fetchPixel(const uchar *src, int index); @@ -756,6 +796,8 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = { { 10, 20, 10, 10, 10, 0, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertA2RGB30PMFromARGB32PM<PixelOrderBGR>, 0 }, // Format_A2BGR30_Premultiplied { 10, 0, 10, 10, 10, 20, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertRGB30FromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB> }, // Format_RGB30 { 10, 0, 10, 10, 10, 20, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertA2RGB30PMFromARGB32PM<PixelOrderRGB>, 0 }, // Format_A2RGB30_Premultiplied + { 0, 0, 0, 0, 0, 0, 8, 0, false, QPixelLayout::BPP8, convertAlpha8ToRGB32, convertAlpha8FromARGB32PM, 0 }, // Format_Alpha8 + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertGrayscale8ToRGB32, convertGrayscale8FromARGB32PM, convertGrayscale8FromRGB32 } // Format_Grayscale8 }; FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount] = { @@ -867,6 +909,8 @@ static DestFetchProc destFetchProc[QImage::NImageFormats] = destFetch, // Format_A2BGR30_Premultiplied destFetch, // Format_RGB30 destFetch, // Format_A2RGB30_Premultiplied + destFetch, // Format_Alpha8 + destFetch, // Format_Grayscale8 }; /* @@ -1011,6 +1055,8 @@ static DestStoreProc destStoreProc[QImage::NImageFormats] = destStore, // Format_A2BGR30_Premultiplied destStore, // Format_RGB30 destStore, // Format_A2RGB30_Premultiplied + destStore, // Format_Alpha8 + destStore, // Format_Grayscale8 }; /* @@ -2266,6 +2312,8 @@ static SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { fetchUntransformed, // Format_A2BGR30_Premultiplied fetchUntransformed, // Format_RGB30 fetchUntransformed, // Format_A2RGB30_Premultiplied + fetchUntransformed, // Alpha8 + fetchUntransformed, // Grayscale8 }, // Tiled { @@ -2291,7 +2339,9 @@ static SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { fetchUntransformed, // BGR30 fetchUntransformed, // A2BGR30_Premultiplied fetchUntransformed, // RGB30 - fetchUntransformed // A2RGB30_Premultiplied + fetchUntransformed, // A2RGB30_Premultiplied + fetchUntransformed, // Alpha8 + fetchUntransformed, // Grayscale8 }, // Transformed { @@ -2318,6 +2368,8 @@ static SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { fetchTransformed<BlendTransformed>, // A2BGR30_Premultiplied fetchTransformed<BlendTransformed>, // RGB30 fetchTransformed<BlendTransformed>, // A2RGB30_Premultiplied + fetchTransformed<BlendTransformed>, // Alpah8 + fetchTransformed<BlendTransformed>, // Grayscale8 }, { 0, // TransformedTiled @@ -2343,6 +2395,8 @@ static SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { fetchTransformed<BlendTransformedTiled>, // A2BGR30_Premultiplied fetchTransformed<BlendTransformedTiled>, // RGB30 fetchTransformed<BlendTransformedTiled>, // A2RGB30_Premultiplied + fetchTransformed<BlendTransformedTiled>, // Alpha8 + fetchTransformed<BlendTransformedTiled>, // Grayscale8 }, { 0, // Bilinear @@ -2368,6 +2422,8 @@ static SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { fetchTransformedBilinear<BlendTransformedBilinear>, // A2BGR30_Premultiplied fetchTransformedBilinear<BlendTransformedBilinear>, // RGB30 fetchTransformedBilinear<BlendTransformedBilinear>, // A2RGB30_Premultiplied + fetchTransformedBilinear<BlendTransformedBilinear>, // Alpha8 + fetchTransformedBilinear<BlendTransformedBilinear>, // Grayscale8 }, { 0, // BilinearTiled @@ -2392,7 +2448,9 @@ static SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { fetchTransformedBilinear<BlendTransformedBilinearTiled>, // BGR30 fetchTransformedBilinear<BlendTransformedBilinearTiled>, // A2BGR30_Premultiplied fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB30 - fetchTransformedBilinear<BlendTransformedBilinearTiled> // A2RGB30_Premultiplied + fetchTransformedBilinear<BlendTransformedBilinearTiled>, // A2RGB30_Premultiplied + fetchTransformedBilinear<BlendTransformedBilinearTiled>, // Alpha8 + fetchTransformedBilinear<BlendTransformedBilinearTiled>, // Grayscale8 }, }; @@ -5815,6 +5873,8 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_untransformed_generic, blend_untransformed_generic, blend_untransformed_generic, + blend_untransformed_generic, + blend_untransformed_generic, }, // Tiled { @@ -5841,6 +5901,8 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_tiled_generic, blend_tiled_generic, blend_tiled_generic, + blend_tiled_generic, + blend_tiled_generic, }, // Transformed { @@ -5867,6 +5929,8 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_src_generic, blend_src_generic, blend_src_generic, + blend_src_generic, + blend_src_generic, }, // TransformedTiled { @@ -5892,6 +5956,7 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_src_generic, blend_src_generic, blend_src_generic, + blend_src_generic, blend_src_generic }, // Bilinear @@ -5919,6 +5984,8 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_src_generic, blend_src_generic, blend_src_generic, + blend_src_generic, + blend_src_generic, }, // BilinearTiled { @@ -5945,6 +6012,8 @@ static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats blend_src_generic, // A2BGR30_Premultiplied blend_src_generic, // RGB30 blend_src_generic, // A2RGB30_Premultiplied + blend_src_generic, // Alpha8 + blend_src_generic, // Grayscale8 } }; @@ -6465,6 +6534,22 @@ static void qt_rectfill_nonpremul_rgba(QRasterBuffer *rasterBuffer, ARGB2RGBA(qUnpremultiply(color)), x, y, width, height, rasterBuffer->bytesPerLine()); } +static void qt_rectfill_alpha(QRasterBuffer *rasterBuffer, + int x, int y, int width, int height, + quint32 color) +{ + qt_rectfill<quint8>(reinterpret_cast<quint8 *>(rasterBuffer->buffer()), + qAlpha(color), x, y, width, height, rasterBuffer->bytesPerLine()); +} + +static void qt_rectfill_gray(QRasterBuffer *rasterBuffer, + int x, int y, int width, int height, + quint32 color) +{ + qt_rectfill<quint8>(reinterpret_cast<quint8 *>(rasterBuffer->buffer()), + qGray(color), x, y, width, height, rasterBuffer->bytesPerLine()); +} + // Map table for destination image format. Contains function pointers // for blends of various types unto the destination @@ -6649,6 +6734,20 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = 0, 0 }, + // Format_Alpha8 + { + blend_color_generic, + blend_src_generic, + 0, 0, 0, + qt_rectfill_alpha + }, + // Format_Grayscale8 + { + blend_color_generic, + blend_src_generic, + 0, 0, 0, + qt_rectfill_gray + }, }; #if defined(Q_CC_MSVC) && !defined(_MIPS_) diff --git a/src/gui/painting/qmemrotate.cpp b/src/gui/painting/qmemrotate.cpp index b55f3b0dcc..442eda14ad 100644 --- a/src/gui/painting/qmemrotate.cpp +++ b/src/gui/painting/qmemrotate.cpp @@ -473,6 +473,21 @@ QT_IMPL_MEMROTATE(quint16) QT_IMPL_MEMROTATE(quint24) QT_IMPL_MEMROTATE(quint8) +void qt_memrotate90_8(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl) +{ + qt_memrotate90(srcPixels, w, h, sbpl, destPixels, dbpl); +} + +void qt_memrotate180_8(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl) +{ + qt_memrotate180(srcPixels, w, h, sbpl, destPixels, dbpl); +} + +void qt_memrotate270_8(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl) +{ + qt_memrotate270(srcPixels, w, h, sbpl, destPixels, dbpl); +} + void qt_memrotate90_16(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl) { qt_memrotate90((const ushort *)srcPixels, w, h, sbpl, (ushort *)destPixels, dbpl); @@ -529,6 +544,8 @@ MemRotateFunc qMemRotateFunctions[QImage::NImageFormats][3] = { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_A2BGR30_Premultiplied, { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_RGB30, { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_A2RGB30_Premultiplied, + { qt_memrotate90_8, qt_memrotate180_8, qt_memrotate270_8 }, // Format_Alpha8, + { qt_memrotate90_8, qt_memrotate180_8, qt_memrotate270_8 }, // Format_Grayscale8, }; QT_END_NAMESPACE diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 57079a5b21..eeebfde98c 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -200,11 +200,8 @@ void QPainterPrivate::checkEmulation() QPainterPrivate::~QPainterPrivate() { delete emulationEngine; - for (int i=0; i<states.size(); ++i) - delete states.at(i); - - if (dummyState) - delete dummyState; + qDeleteAll(states); + delete dummyState; } @@ -456,7 +453,7 @@ void QPainterPrivate::draw_helper(const QPainterPath &originalPath, DrawOperatio p.drawPath(originalPath); #ifndef QT_NO_DEBUG - static bool do_fallback_overlay = qgetenv("QT_PAINT_FALLBACK_OVERLAY").size() > 0; + static bool do_fallback_overlay = !qEnvironmentVariableIsEmpty("QT_PAINT_FALLBACK_OVERLAY"); if (do_fallback_overlay) { QImage block(8, 8, QImage::Format_ARGB32_Premultiplied); QPainter pt(&block); @@ -3432,8 +3429,7 @@ void QPainter::drawPath(const QPainterPath &path) \fn void QPainter::drawLine(int x1, int y1, int x2, int y2) \overload - Draws a line from (\a x1, \a y1) to (\a x2, \a y2) and sets the - current pen position to (\a x2, \a y2). + Draws a line from (\a x1, \a y1) to (\a x2, \a y2). */ /*! @@ -7024,7 +7020,7 @@ void QPainter::setRenderHint(RenderHint hint, bool on) #endif #ifndef QT_NO_DEBUG - static const bool antialiasingDisabled = qgetenv("QT_NO_ANTIALIASING").toInt(); + static const bool antialiasingDisabled = qEnvironmentVariableIntValue("QT_NO_ANTIALIASING"); if (hint == QPainter::Antialiasing && antialiasingDisabled) return; #endif diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index 46d016de6b..8cf45863b8 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -2319,6 +2319,14 @@ int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor, return patternObj; } +static inline bool is_monochrome(const QVector<QRgb> &colorTable) +{ + return colorTable.size() == 2 + && colorTable.at(0) == QColor(Qt::black).rgba() + && colorTable.at(1) == QColor(Qt::white).rgba() + ; +} + /*! * Adds an image to the pdf and return the pdf-object id. Returns -1 if adding the image failed. */ @@ -2333,10 +2341,7 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, qint64 serial_n QImage image = img; QImage::Format format = image.format(); - if (image.depth() == 1 && *bitmap && img.colorTable().size() == 2 - && img.colorTable().at(0) == QColor(Qt::black).rgba() - && img.colorTable().at(1) == QColor(Qt::white).rgba()) - { + if (image.depth() == 1 && *bitmap && is_monochrome(img.colorTable())) { if (format == QImage::Format_MonoLSB) image = image.convertToFormat(QImage::Format_Mono); format = QImage::Format_Mono; diff --git a/src/gui/painting/qrgb.h b/src/gui/painting/qrgb.h index 6b0516e557..e6bda490ff 100644 --- a/src/gui/painting/qrgb.h +++ b/src/gui/painting/qrgb.h @@ -72,9 +72,11 @@ inline Q_DECL_CONSTEXPR int qGray(QRgb rgb) // convert RGB to gra inline Q_DECL_CONSTEXPR bool qIsGray(QRgb rgb) { return qRed(rgb) == qGreen(rgb) && qRed(rgb) == qBlue(rgb); } +template <int ProcessorWordSize> +inline QRgb qPremultiply_impl(QRgb x); -#if Q_PROCESSOR_WORDSIZE == 8 // 64-bit version -inline QRgb qPremultiply(QRgb x) +template <> // 64-bit version +inline QRgb qPremultiply_impl<8>(QRgb x) { const uint a = qAlpha(x); quint64 t = (((quint64(x)) | ((quint64(x)) << 24)) & 0x00ff00ff00ff00ff) * a; @@ -82,8 +84,9 @@ inline QRgb qPremultiply(QRgb x) t &= 0x000000ff00ff00ff; return (uint(t)) | (uint(t >> 24)) | (a << 24); } -#else // 32-bit version -inline QRgb qPremultiply(QRgb x) + +template <> // 32-bit version +inline QRgb qPremultiply_impl<4>(QRgb x) { const uint a = qAlpha(x); uint t = (x & 0xff00ff) * a; @@ -96,7 +99,8 @@ inline QRgb qPremultiply(QRgb x) x |= t | (a << 24); return x; } -#endif + +inline QRgb qPremultiply(QRgb x) { return qPremultiply_impl<Q_PROCESSOR_WORDSIZE>(x); } Q_GUI_EXPORT extern const uint qt_inv_premul_factor[]; diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index e12d61bbf4..79ebf12fec 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -285,13 +285,7 @@ void QImageTextureGlyphCache::createTextureData(int width, int height) m_image = QImage(width, height, QImage::Format_Mono); break; case QFontEngine::Format_A8: { - m_image = QImage(width, height, QImage::Format_Indexed8); - m_image.fill(0); - QVector<QRgb> colors(256); - QRgb *it = colors.data(); - for (int i=0; i<256; ++i, ++it) - *it = 0xff000000 | i | (i<<8) | (i<<16); - m_image.setColorTable(colors); + m_image = QImage(width, height, QImage::Format_Alpha8); break; } case QFontEngine::Format_A32: m_image = QImage(width, height, QImage::Format_RGB32); diff --git a/src/gui/text/qdistancefield.cpp b/src/gui/text/qdistancefield.cpp index ca6cafb13c..38215cd418 100644 --- a/src/gui/text/qdistancefield.cpp +++ b/src/gui/text/qdistancefield.cpp @@ -34,6 +34,7 @@ #include "qdistancefield_p.h" #include <qmath.h> #include <private/qdatabuffer_p.h> +#include <private/qimage_p.h> #include <private/qpathsimplifier_p.h> QT_BEGIN_NAMESPACE @@ -987,12 +988,12 @@ QImage QDistanceField::toImage(QImage::Format format) const if (isNull()) return QImage(); - QImage image(d->width, d->height, format == QImage::Format_Indexed8 ? + QImage image(d->width, d->height, qt_depthForFormat(format) == 8 ? format : QImage::Format_ARGB32_Premultiplied); if (image.isNull()) return image; - if (format == QImage::Format_Indexed8) { + if (image.depth() == 8) { for (int y = 0; y < d->height; ++y) memcpy(image.scanLine(y), scanLine(y), d->width); } else { diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 645d86c0fe..8fe6aff79f 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -84,20 +84,22 @@ static int getFontWeight(const QString &weightString) { QString s = weightString.toLower(); - // Test in decreasing order of commonness - if (s == QLatin1String("normal") - || s.compare(QCoreApplication::translate("QFontDatabase", "Normal"), Qt::CaseInsensitive) == 0) + // Order here is important. We want to match the common cases first, but we + // must also take care to acknowledge the cost of our tests. + // + // As a result, we test in two orders; the order of commonness, and the + // order of "expense". + // + // A simple string test is the cheapest, so let's do that first. + if (s == QLatin1String("normal")) return QFont::Normal; if (s == QLatin1String("medium")) return qt_mediumFontWeight; - if (s == QLatin1String("bold") - || s.compare(QCoreApplication::translate("QFontDatabase", "Bold"), Qt::CaseInsensitive) == 0) + if (s == QLatin1String("bold")) return QFont::Bold; - if (s == QLatin1String("demibold") || s == QLatin1String("demi bold") - || s.compare(QCoreApplication::translate("QFontDatabase", "Demi Bold"), Qt::CaseInsensitive) == 0) + if (s == QLatin1String("demibold") || s == QLatin1String("demi bold")) return QFont::DemiBold; - if (s == QLatin1String("black") - || s.compare(QCoreApplication::translate("QFontDatabase", "Black"), Qt::CaseInsensitive) == 0) + if (s == QLatin1String("black")) return QFont::Black; if (s == QLatin1String("light")) return QFont::Light; @@ -106,23 +108,48 @@ static int getFontWeight(const QString &weightString) if (s == QLatin1String("extralight")) return qt_extralightFontWeight; - if (s.contains(QLatin1String("bold")) - || s.contains(QCoreApplication::translate("QFontDatabase", "Bold"), Qt::CaseInsensitive)) { - if (s.contains(QLatin1String("demi")) - || s.compare(QCoreApplication::translate("QFontDatabase", "Demi"), Qt::CaseInsensitive) == 0) - return (int) QFont::DemiBold; - return (int) QFont::Bold; + // Next up, let's see if contains() matches: slightly more expensive, but + // still fast enough. + if (s.contains(QLatin1String("bold"))) { + if (s.contains(QLatin1String("demi"))) + return QFont::DemiBold; + return QFont::Bold; } + if (s.contains(QLatin1String("light"))) + return QFont::Light; + if (s.contains(QLatin1String("black"))) + return QFont::Black; - if (s.contains(QLatin1String("light")) - || s.compare(QCoreApplication::translate("QFontDatabase", "Light"), Qt::CaseInsensitive) == 0) - return (int) QFont::Light; + // Now, we perform string translations & comparisons with those. + // These are (very) slow compared to simple string ops, so we do these last. + // As using translated values for such things is not very common, this should + // not be too bad. + QString translatedNormal = QCoreApplication::translate("QFontDatabase", "Normal").toLower(); + if (s == translatedNormal) + return QFont::Normal; + QString translatedBold = QCoreApplication::translate("QFontDatabase", "Bold").toLower(); + if (s == translatedBold) + return QFont::Bold; + QString translatedDemiBold = QCoreApplication::translate("QFontDatabase", "Demi Bold").toLower(); + if (s == translatedDemiBold) + return QFont::DemiBold; + QString translatedBlack = QCoreApplication::translate("QFontDatabase", "Black").toLower(); + if (s == translatedBlack) + return QFont::Black; - if (s.contains(QLatin1String("black")) - || s.compare(QCoreApplication::translate("QFontDatabase", "Black"), Qt::CaseInsensitive) == 0) - return (int) QFont::Black; + // And now the contains() checks for the translated strings. + if (s.contains(translatedBold)) { + QString translatedDemi = QCoreApplication::translate("QFontDatabase", "Demi").toLower(); + if (s == translatedDemi) + return QFont::DemiBold; + return QFont::Bold; + } + + QString translatedLight = QCoreApplication::translate("QFontDatabase", "Light").toLower(); + if (s == translatedLight || s.contains(translatedLight)) + return QFont::Light; - return (int) QFont::Normal; + return QFont::Normal; } // convert 0 ~ 1000 integer to QFont::Weight @@ -1562,6 +1589,15 @@ bool QFontDatabase::isSmoothlyScalable(const QString &family, const QString &sty QtFontStyle::Key styleKey(style); QtFontFamily *f = d->family(familyName); + if (!f) { + for (int i = 0; i < d->count; i++) { + if (d->families[i]->matchesFamilyName(familyName)) { + f = d->families[i]; + f->ensurePopulated(); + break; + } + } + } if (!f) return smoothScalable; for (int j = 0; j < f->count; j++) { diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index b2a7a8e91f..4c6fc7c1a6 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -761,7 +761,7 @@ QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &t) { QImage i = alphaMapForGlyph(glyph); if (t.type() > QTransform::TxTranslate) - i = i.transformed(t).convertToFormat(QImage::Format_Indexed8); + i = i.transformed(t).convertToFormat(QImage::Format_Alpha8); Q_ASSERT(i.depth() <= 8); // To verify that transformed didn't change the format... return i; @@ -774,7 +774,7 @@ QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, con QImage i = alphaMapForGlyph(glyph, subPixelPosition); if (t.type() > QTransform::TxTranslate) - i = i.transformed(t).convertToFormat(QImage::Format_Indexed8); + i = i.transformed(t).convertToFormat(QImage::Format_Alpha8); Q_ASSERT(i.depth() <= 8); // To verify that transformed didn't change the format... return i; @@ -785,12 +785,11 @@ QImage QFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition QImage alphaMask = alphaMapForGlyph(glyph, t); QImage rgbMask(alphaMask.width(), alphaMask.height(), QImage::Format_RGB32); - QVector<QRgb> colorTable = alphaMask.colorTable(); for (int y=0; y<alphaMask.height(); ++y) { uint *dst = (uint *) rgbMask.scanLine(y); uchar *src = (uchar *) alphaMask.scanLine(y); for (int x=0; x<alphaMask.width(); ++x) { - int val = qAlpha(colorTable.at(src[x])); + int val = src[x]; dst[x] = qRgb(val, val, val); } } @@ -871,20 +870,16 @@ QImage QFontEngine::alphaMapForGlyph(glyph_t glyph) p.drawPath(path); p.end(); - QImage indexed(im.width(), im.height(), QImage::Format_Indexed8); - QVector<QRgb> colors(256); - for (int i=0; i<256; ++i) - colors[i] = qRgba(0, 0, 0, i); - indexed.setColorTable(colors); + QImage alphaMap(im.width(), im.height(), QImage::Format_Alpha8); for (int y=0; y<im.height(); ++y) { - uchar *dst = (uchar *) indexed.scanLine(y); + uchar *dst = (uchar *) alphaMap.scanLine(y); uint *src = (uint *) im.scanLine(y); for (int x=0; x<im.width(); ++x) dst[x] = qAlpha(src[x]); } - return indexed; + return alphaMap; } void QFontEngine::removeGlyphFromCache(glyph_t) @@ -1535,14 +1530,10 @@ bool QFontEngineBox::canRender(const QChar *, int) const QImage QFontEngineBox::alphaMapForGlyph(glyph_t) { - QImage image(_size, _size, QImage::Format_Indexed8); - QVector<QRgb> colors(256); - for (int i=0; i<256; ++i) - colors[i] = qRgba(0, 0, 0, i); - image.setColorTable(colors); + QImage image(_size, _size, QImage::Format_Alpha8); image.fill(0); - // can't use qpainter for index8; so use setPixel to draw our rectangle. + // FIXME: use qpainter for (int i=2; i <= _size-3; ++i) { image.setPixel(i, 2, 255); image.setPixel(i, _size-3, 255); diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index 83d9edab94..4c5bab77d6 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -1848,7 +1848,7 @@ QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixe format = QImage::Format_Mono; break; case Format_A8: - format = QImage::Format_Indexed8; + format = QImage::Format_Alpha8; break; case Format_A32: format = QImage::Format_ARGB32; @@ -2016,13 +2016,8 @@ QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition, const const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4; - QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono); - if (antialias) { - QVector<QRgb> colors(256); - for (int i=0; i<256; ++i) - colors[i] = qRgba(0, 0, 0, i); - img.setColorTable(colors); - } else { + QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Alpha8 : QImage::Format_Mono); + if (!antialias) { QVector<QRgb> colors(2); colors[0] = qRgba(0, 0, 0, 0); colors[1] = qRgba(0, 0, 0, 255); diff --git a/src/gui/text/qfontengine_qpf2.cpp b/src/gui/text/qfontengine_qpf2.cpp index 4785902c99..8e924102e5 100644 --- a/src/gui/text/qfontengine_qpf2.cpp +++ b/src/gui/text/qfontengine_qpf2.cpp @@ -396,7 +396,7 @@ QImage QFontEngineQPF2::alphaMapForGlyph(glyph_t g) const uchar *bits = ((const uchar *) glyph) + sizeof(Glyph); - QImage image(bits,glyph->width, glyph->height, glyph->bytesPerLine, QImage::Format_Indexed8); + QImage image(bits,glyph->width, glyph->height, glyph->bytesPerLine, QImage::Format_Alpha8); return image; } diff --git a/src/gui/text/qfragmentmap_p.h b/src/gui/text/qfragmentmap_p.h index 012d3c25ce..a19e3d9ea3 100644 --- a/src/gui/text/qfragmentmap_p.h +++ b/src/gui/text/qfragmentmap_p.h @@ -249,6 +249,8 @@ uint QFragmentMapData<Fragment>::createFragment() uint freePos = head->freelist; if (freePos == head->allocated) { // need to create some free space + if (freePos >= uint(MaxAllocSize) / fragmentSize) + qBadAlloc(); uint needed = qAllocMore((freePos+1)*fragmentSize, 0); Q_ASSERT(needed/fragmentSize > head->allocated); Fragment *newFragments = (Fragment *)realloc(fragments, needed); diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index ea2b794feb..3820b415a3 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -40,6 +40,7 @@ #include "qtextlist.h" #include <qdebug.h> #include <qregexp.h> +#include <qregularexpression.h> #include <qvarlengtharray.h> #include <qtextcodec.h> #include <qthread.h> @@ -1269,8 +1270,6 @@ QTextCursor QTextDocument::find(const QString &subString, int from, FindFlags op } /*! - \fn QTextCursor QTextDocument::find(const QString &subString, const QTextCursor &cursor, FindFlags options) const - Finds the next occurrence of the string, \a subString, in the document. The search starts at the position of the given \a cursor, and proceeds forwards through the document unless specified otherwise in the search @@ -1285,14 +1284,14 @@ QTextCursor QTextDocument::find(const QString &subString, int from, FindFlags op By default the search is case-sensitive, and can match text anywhere in the document. */ -QTextCursor QTextDocument::find(const QString &subString, const QTextCursor &from, FindFlags options) const +QTextCursor QTextDocument::find(const QString &subString, const QTextCursor &cursor, FindFlags options) const { int pos = 0; - if (!from.isNull()) { + if (!cursor.isNull()) { if (options & QTextDocument::FindBackward) - pos = from.selectionStart(); + pos = cursor.selectionStart(); else - pos = from.selectionEnd(); + pos = cursor.selectionEnd(); } QRegExp expr(subString); expr.setPatternSyntax(QRegExp::FixedString); @@ -1303,7 +1302,7 @@ QTextCursor QTextDocument::find(const QString &subString, const QTextCursor &fro static bool findInBlock(const QTextBlock &block, const QRegExp &expression, int offset, - QTextDocument::FindFlags options, QTextCursor &cursor) + QTextDocument::FindFlags options, QTextCursor *cursor) { QRegExp expr(expression); QString text = block.text(); @@ -1332,18 +1331,16 @@ static bool findInBlock(const QTextBlock &block, const QRegExp &expression, int } if (idx == -1) return false; - cursor = QTextCursor(block.docHandle(), block.position() + idx); - cursor.setPosition(cursor.position() + expr.matchedLength(), QTextCursor::KeepAnchor); + *cursor = QTextCursor(block.docHandle(), block.position() + idx); + cursor->setPosition(cursor->position() + expr.matchedLength(), QTextCursor::KeepAnchor); return true; } /*! - \fn QTextCursor QTextDocument::find(const QRegExp & expr, int position, FindFlags options) const - \overload Finds the next occurrence, matching the regular expression, \a expr, in the document. - The search starts at the given \a position, and proceeds forwards + The search starts at the given \a from position, and proceeds forwards through the document unless specified otherwise in the search options. The \a options control the type of search performed. The FindCaseSensitively option is ignored for this overload, use QRegExp::caseSensitivity instead. @@ -1351,7 +1348,7 @@ static bool findInBlock(const QTextBlock &block, const QRegExp &expression, int Returns a cursor with the match selected if a match was found; otherwise returns a null cursor. - If the \a position is 0 (the default) the search begins from the beginning + If the \a from position is 0 (the default) the search begins from the beginning of the document; otherwise it begins at the specified position. */ QTextCursor QTextDocument::find(const QRegExp & expr, int from, FindFlags options) const @@ -1376,7 +1373,7 @@ QTextCursor QTextDocument::find(const QRegExp & expr, int from, FindFlags option if (!(options & FindBackward)) { int blockOffset = qMax(0, pos - block.position()); while (block.isValid()) { - if (findInBlock(block, expr, blockOffset, options, cursor)) + if (findInBlock(block, expr, blockOffset, options, &cursor)) return cursor; blockOffset = 0; block = block.next(); @@ -1384,7 +1381,7 @@ QTextCursor QTextDocument::find(const QRegExp & expr, int from, FindFlags option } else { int blockOffset = pos - block.position(); while (block.isValid()) { - if (findInBlock(block, expr, blockOffset, options, cursor)) + if (findInBlock(block, expr, blockOffset, options, &cursor)) return cursor; block = block.previous(); blockOffset = block.length() - 1; @@ -1395,10 +1392,10 @@ QTextCursor QTextDocument::find(const QRegExp & expr, int from, FindFlags option } /*! - \fn QTextCursor QTextDocument::find(const QRegExp &expr, const QTextCursor &cursor, FindFlags options) const + \overload Finds the next occurrence, matching the regular expression, \a expr, in the document. - The search starts at the position of the given \a cursor, and proceeds + The search starts at the position of the given \a from cursor, and proceeds forwards through the document unless specified otherwise in the search options. The \a options control the type of search performed. The FindCaseSensitively option is ignored for this overload, use QRegExp::caseSensitivity instead. @@ -1406,24 +1403,149 @@ QTextCursor QTextDocument::find(const QRegExp & expr, int from, FindFlags option Returns a cursor with the match selected if a match was found; otherwise returns a null cursor. - If the given \a cursor has a selection, the search begins after the + If the given \a from cursor has a selection, the search begins after the selection; otherwise it begins at the cursor's position. By default the search is case-sensitive, and can match text anywhere in the document. */ -QTextCursor QTextDocument::find(const QRegExp &expr, const QTextCursor &from, FindFlags options) const +QTextCursor QTextDocument::find(const QRegExp &expr, const QTextCursor &cursor, FindFlags options) const { int pos = 0; - if (!from.isNull()) { + if (!cursor.isNull()) { if (options & QTextDocument::FindBackward) - pos = from.selectionStart(); + pos = cursor.selectionStart(); else - pos = from.selectionEnd(); + pos = cursor.selectionEnd(); } return find(expr, pos, options); } +#ifndef QT_NO_REGULAREXPRESSION +static bool findInBlock(const QTextBlock &block, const QRegularExpression &expression, int offset, + QTextDocument::FindFlags options, QTextCursor *cursor) +{ + QRegularExpression expr(expression); + if (!(options & QTextDocument::FindCaseSensitively)) + expr.setPatternOptions(expr.patternOptions() | QRegularExpression::CaseInsensitiveOption); + else + expr.setPatternOptions(expr.patternOptions() & ~QRegularExpression::CaseInsensitiveOption); + + QString text = block.text(); + text.replace(QChar::Nbsp, QLatin1Char(' ')); + QRegularExpressionMatch match; + int idx = -1; + + while (offset >= 0 && offset <= text.length()) { + idx = (options & QTextDocument::FindBackward) ? + text.lastIndexOf(expr, offset, &match) : text.indexOf(expr, offset, &match); + if (idx == -1) + return false; + + if (options & QTextDocument::FindWholeWords) { + const int start = idx; + const int end = start + match.capturedLength(); + if ((start != 0 && text.at(start - 1).isLetterOrNumber()) + || (end != text.length() && text.at(end).isLetterOrNumber())) { + //if this is not a whole word, continue the search in the string + offset = (options & QTextDocument::FindBackward) ? idx-1 : end+1; + idx = -1; + continue; + } + } + //we have a hit, return the cursor for that. + break; + } + if (idx == -1) + return false; + *cursor = qMove(QTextCursor(block.docHandle(), block.position() + idx)); + cursor->setPosition(cursor->position() + match.capturedLength(), QTextCursor::KeepAnchor); + return true; +} + +/*! + \since 5.5 + + Finds the next occurrence, matching the regular expression, \a expr, in the document. + The search starts at the given \a from position, and proceeds forwards + through the document unless specified otherwise in the search options. + The \a options control the type of search performed. + + Returns a cursor with the match selected if a match was found; otherwise + returns a null cursor. + + If the \a from position is 0 (the default) the search begins from the beginning + of the document; otherwise it begins at the specified position. +*/ +QTextCursor QTextDocument::find(const QRegularExpression &expr, int from, FindFlags options) const +{ + Q_D(const QTextDocument); + + if (!expr.isValid()) + return QTextCursor(); + + int pos = from; + //the cursor is positioned between characters, so for a backward search + //do not include the character given in the position. + if (options & FindBackward) { + --pos ; + if (pos < 0) + return QTextCursor(); + } + + QTextCursor cursor; + QTextBlock block = d->blocksFind(pos); + + if (!(options & FindBackward)) { + int blockOffset = qMax(0, pos - block.position()); + while (block.isValid()) { + if (findInBlock(block, expr, blockOffset, options, &cursor)) + return cursor; + blockOffset = 0; + block = block.next(); + } + } else { + int blockOffset = pos - block.position(); + while (block.isValid()) { + if (findInBlock(block, expr, blockOffset, options, &cursor)) + return cursor; + block = block.previous(); + blockOffset = block.length() - 1; + } + } + + return QTextCursor(); +} + +/*! + \since 5.5 + + Finds the next occurrence, matching the regular expression, \a expr, in the document. + The search starts at the position of the given \a cursor, and proceeds + forwards through the document unless specified otherwise in the search + options. The \a options control the type of search performed. + + Returns a cursor with the match selected if a match was found; otherwise + returns a null cursor. + + If the given \a cursor has a selection, the search begins after the + selection; otherwise it begins at the cursor's position. + + By default the search is case-sensitive, and can match text anywhere in the + document. +*/ +QTextCursor QTextDocument::find(const QRegularExpression &expr, const QTextCursor &cursor, FindFlags options) const +{ + int pos = 0; + if (!cursor.isNull()) { + if (options & QTextDocument::FindBackward) + pos = cursor.selectionStart(); + else + pos = cursor.selectionEnd(); + } + return find(expr, pos, options); +} +#endif // QT_NO_REGULAREXPRESSION /*! \fn QTextObject *QTextDocument::createObject(const QTextFormat &format) diff --git a/src/gui/text/qtextdocument.h b/src/gui/text/qtextdocument.h index 2329a9e721..83e255bd96 100644 --- a/src/gui/text/qtextdocument.h +++ b/src/gui/text/qtextdocument.h @@ -160,10 +160,14 @@ public: Q_DECLARE_FLAGS(FindFlags, FindFlag) QTextCursor find(const QString &subString, int from = 0, FindFlags options = 0) const; - QTextCursor find(const QString &subString, const QTextCursor &from, FindFlags options = 0) const; - + QTextCursor find(const QString &subString, const QTextCursor &cursor, FindFlags options = 0) const; QTextCursor find(const QRegExp &expr, int from = 0, FindFlags options = 0) const; - QTextCursor find(const QRegExp &expr, const QTextCursor &from, FindFlags options = 0) const; + QTextCursor find(const QRegExp &expr, const QTextCursor &cursor, FindFlags options = 0) const; + +#ifndef QT_NO_REGULAREXPRESSION + QTextCursor find(const QRegularExpression &expr, int from = 0, FindFlags options = 0) const; + QTextCursor find(const QRegularExpression &expr, const QTextCursor &cursor, FindFlags options = 0) const; +#endif QTextFrame *frameAt(int pos) const; QTextFrame *rootFrame() const; diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp index 8ff15106e3..d30ff78b8f 100644 --- a/src/gui/text/qtextdocument_p.cpp +++ b/src/gui/text/qtextdocument_p.cpp @@ -125,14 +125,12 @@ static bool isValidBlockSeparator(QChar ch) || ch == QTextEndOfFrame; } -#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS) static bool noBlockInString(const QString &str) { return !str.contains(QChar::ParagraphSeparator) && !str.contains(QTextBeginningOfFrame) && !str.contains(QTextEndOfFrame); } -#endif bool QTextUndoCommand::tryMerge(const QTextUndoCommand &other) { diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp index cecfd85df1..1502758ee8 100644 --- a/src/gui/text/qtextformat.cpp +++ b/src/gui/text/qtextformat.cpp @@ -258,20 +258,6 @@ private: friend QDataStream &operator>>(QDataStream &, QTextFormat &); }; -// this is only safe because sizeof(int) == sizeof(float) -static inline uint hash(float d) -{ -#ifdef Q_CC_GNU - // this is a GCC extension and isn't guaranteed to work in other compilers - // the reinterpret_cast below generates a strict-aliasing warning with GCC - union { float f; uint u; } cvt; - cvt.f = d; - return cvt.u; -#else - return reinterpret_cast<uint&>(d); -#endif -} - static inline uint hash(const QColor &color) { return (color.isValid()) ? color.rgba() : 0x234109; @@ -279,7 +265,7 @@ static inline uint hash(const QColor &color) static inline uint hash(const QPen &pen) { - return hash(pen.color()) + hash(pen.widthF()); + return hash(pen.color()) + qHash(pen.widthF()); } static inline uint hash(const QBrush &brush) @@ -292,7 +278,7 @@ static inline uint variantHash(const QVariant &variant) // simple and fast hash functions to differentiate between type and value switch (variant.userType()) { // sorted by occurrence frequency case QVariant::String: return qHash(variant.toString()); - case QVariant::Double: return hash(variant.toDouble()); + case QVariant::Double: return qHash(variant.toDouble()); case QVariant::Int: return 0x811890 + variant.toInt(); case QVariant::Brush: return 0x01010101 + hash(qvariant_cast<QBrush>(variant)); @@ -303,7 +289,7 @@ static inline uint variantHash(const QVariant &variant) case QVariant::Color: return hash(qvariant_cast<QColor>(variant)); case QVariant::TextLength: return 0x377 + hash(qvariant_cast<QTextLength>(variant).rawValue()); - case QMetaType::Float: return hash(variant.toFloat()); + case QMetaType::Float: return qHash(variant.toFloat()); case QVariant::Invalid: return 0; default: break; } |
