diff options
author | Oswald Buddenhagen <oswald.buddenhagen@digia.com> | 2014-02-19 10:06:25 +0100 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@digia.com> | 2014-02-19 10:06:25 +0100 |
commit | 30fd22b9574def54726e7b193127cc0c901c1b4c (patch) | |
tree | 96dfc923044db0515064ba39d052d9ed577e3e40 /src/gui | |
parent | d7b0581c1c2ef60c08d238dae39298af6904918f (diff) | |
parent | 6aa09bbce59828d028f6d1e81d2bfc6ba537aae1 (diff) |
Merge remote-tracking branch 'origin/dev' into stable
Change-Id: Ice524edcc51373509f0023ae7f7c2963f4602f88
Diffstat (limited to 'src/gui')
149 files changed, 14872 insertions, 4693 deletions
diff --git a/src/gui/accessible/qaccessiblecache.cpp b/src/gui/accessible/qaccessiblecache.cpp index a9a880e71f..fe66c6e19d 100644 --- a/src/gui/accessible/qaccessiblecache.cpp +++ b/src/gui/accessible/qaccessiblecache.cpp @@ -90,7 +90,7 @@ QAccessible::Id QAccessibleCache::insert(QObject *object, QAccessibleInterface * Q_ASSERT(object == obj); if (obj) { objectToId.insert(obj, id); - connect(obj, SIGNAL(destroyed(QObject *)), this, SLOT(objectDestroyed(QObject *))); + connect(obj, &QObject::destroyed, this, &QAccessibleCache::objectDestroyed); } idToInterface.insert(id, iface); return id; diff --git a/src/gui/doc/snippets/image/supportedformat.cpp b/src/gui/doc/snippets/image/supportedformat.cpp index f4d2606728..0b52156b80 100644 --- a/src/gui/doc/snippets/image/supportedformat.cpp +++ b/src/gui/doc/snippets/image/supportedformat.cpp @@ -43,10 +43,10 @@ int main(int argv, char **args) { //! [0] - QImageWriter writer; - writer.setFormat("png"); - if (writer.supportsOption(QImageIOHandler::Description)) - qDebug() << "Png supports embedded text"; + QImageWriter writer; + writer.setFormat("png"); + if (writer.supportsOption(QImageIOHandler::Description)) + qDebug() << "Png supports embedded text"; //! [0] return 0; } diff --git a/src/gui/doc/src/coordsys.qdoc b/src/gui/doc/src/coordsys.qdoc index e66afcfe55..d9c7c7e3c1 100644 --- a/src/gui/doc/src/coordsys.qdoc +++ b/src/gui/doc/src/coordsys.qdoc @@ -29,7 +29,7 @@ \page coordsys.html \title Coordinate System \ingroup qt-graphics - \ingroup best-practices + \ingroup best-practices \brief Information about the coordinate system used by the paint system. diff --git a/src/gui/doc/src/paintsystem.qdoc b/src/gui/doc/src/paintsystem.qdoc index cd208e9e18..1006d2ef65 100644 --- a/src/gui/doc/src/paintsystem.qdoc +++ b/src/gui/doc/src/paintsystem.qdoc @@ -93,8 +93,8 @@ \page paintsystem-devices.html \title Paint Devices and Backends - \contentspage The Paint System - \nextpage Drawing and Filling + \contentspage The Paint System + \nextpage Drawing and Filling \section1 Creating a Paint Device diff --git a/src/gui/gui.pro b/src/gui/gui.pro index f4c35a36c5..9bd33d1f57 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -13,11 +13,13 @@ MODULE_PLUGIN_TYPES = \ imageformats # This is here only because the platform plugin is no module, obviously. -win32:contains(QT_CONFIG, angle) { +win32:contains(QT_CONFIG, angle)|contains(QT_CONFIG, dynamicgl) { MODULE_AUX_INCLUDES = \ \$\$QT_MODULE_INCLUDE_BASE/QtANGLE } +contains(QT_CONFIG, dynamicgl): DEFINES += QT_OPENGL_DYNAMIC_IN_GUI + load(qt_module) # Code coverage with TestCocoon diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index bf4b5ddf01..bbdd0f3da7 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -32,6 +32,7 @@ HEADERS += \ SOURCES += \ image/qbitmap.cpp \ image/qimage.cpp \ + image/qimage_conversions.cpp \ image/qimageiohandler.cpp \ image/qimagereader.cpp \ image/qimagewriter.cpp \ @@ -54,6 +55,9 @@ SOURCES += \ win32:!winrt: SOURCES += image/qpixmap_win.cpp +NO_PCH_SOURCES += image/qimage_compat.cpp +false: SOURCES += $$NO_PCH_SOURCES # Hack for QtCreator + # Built-in image format support HEADERS += \ image/qbmphandler_p.h \ @@ -74,9 +78,12 @@ contains(QT_CONFIG, jpeg):include($$PWD/qjpeghandler.pri) contains(QT_CONFIG, gif):include($$PWD/qgifhandler.pri) # SIMD -NEON_SOURCES += image/qimage_neon.cpp -SSE2_SOURCES += image/qimage_sse2.cpp -SSSE3_SOURCES += image/qimage_ssse3.cpp -AVX_SOURCES += image/qimage_avx.cpp +contains(QT_CPU_FEATURES.$$QT_ARCH, neon) { + SOURCES += image/qimage_neon.cpp +} +contains(QT_CPU_FEATURES.$$QT_ARCH, sse2) { + SOURCES += image/qimage_sse2.cpp + SSSE3_SOURCES += image/qimage_ssse3.cpp +} MIPS_DSPR2_SOURCES += image/qimage_mips_dspr2.cpp MIPS_DSPR2_ASM += image/qimage_mips_dspr2_asm.S diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index c03d9b8e5d..bb79a139b3 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -210,54 +210,15 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int uint red_mask = 0; uint green_mask = 0; uint blue_mask = 0; + uint alpha_mask = 0; int red_shift = 0; int green_shift = 0; int blue_shift = 0; + int alpha_shift = 0; int red_scale = 0; int green_scale = 0; int blue_scale = 0; - - int ncols = 0; - int depth = 0; - QImage::Format format; - switch (nbits) { - case 32: - case 24: - case 16: - depth = 32; - format = QImage::Format_RGB32; - break; - case 8: - case 4: - depth = 8; - format = QImage::Format_Indexed8; - break; - default: - depth = 1; - format = QImage::Format_Mono; - } - - if (bi.biHeight < 0) - h = -h; // support images with negative height - - if (image.size() != QSize(w, h) || image.format() != format) { - image = QImage(w, h, format); - if (image.isNull()) // could not create image - return false; - } - - if (depth != 32) { - ncols = bi.biClrUsed ? bi.biClrUsed : 1 << nbits; - if (ncols > 256) // sanity check - don't run out of mem if color table is broken - return false; - image.setColorCount(ncols); - } - - image.setDotsPerMeterX(bi.biXPelsPerMeter); - image.setDotsPerMeterY(bi.biYPelsPerMeter); - - if (!d->isSequential()) - d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap + int alpha_scale = 0; if (bi.biSize >= BMP_WIN4 || (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32))) { if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask)) @@ -269,7 +230,6 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int // Read BMP v4+ header if (bi.biSize >= BMP_WIN4) { - int alpha_mask = 0; int CSType = 0; int gamma_red = 0; int gamma_green = 0; @@ -307,6 +267,49 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int } } + bool transp = (comp == BMP_BITFIELDS) && alpha_mask; + int ncols = 0; + int depth = 0; + QImage::Format format; + switch (nbits) { + case 32: + case 24: + case 16: + depth = 32; + format = transp ? QImage::Format_ARGB32 : QImage::Format_RGB32; + break; + case 8: + case 4: + depth = 8; + format = QImage::Format_Indexed8; + break; + default: + depth = 1; + format = QImage::Format_Mono; + } + + if (bi.biHeight < 0) + h = -h; // support images with negative height + + if (image.size() != QSize(w, h) || image.format() != format) { + image = QImage(w, h, format); + if (image.isNull()) // could not create image + return false; + } + + if (depth != 32) { + ncols = bi.biClrUsed ? bi.biClrUsed : 1 << nbits; + if (ncols > 256) // sanity check - don't run out of mem if color table is broken + return false; + image.setColorCount(ncols); + } + + image.setDotsPerMeterX(bi.biXPelsPerMeter); + image.setDotsPerMeterY(bi.biYPelsPerMeter); + + if (!d->isSequential()) + d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap + if (ncols > 0) { // read color table uchar rgb[4]; int rgb_len = t == BMP_OLD ? 3 : 4; @@ -324,6 +327,8 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int green_scale = 256 / ((green_mask >> green_shift) + 1); blue_shift = calc_shift(blue_mask); blue_scale = 256 / ((blue_mask >> blue_shift) + 1); + alpha_shift = calc_shift(alpha_mask); + alpha_scale = 256 / ((alpha_mask >> alpha_shift) + 1); } else if (comp == BMP_RGB && (nbits == 24 || nbits == 32)) { blue_mask = 0x000000ff; green_mask = 0x0000ff00; @@ -344,6 +349,13 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int blue_scale = 8; } +#if 0 + qDebug("Rmask: %08x Rshift: %08x Rscale:%08x", red_mask, red_shift, red_scale); + qDebug("Gmask: %08x Gshift: %08x Gscale:%08x", green_mask, green_shift, green_scale); + qDebug("Bmask: %08x Bshift: %08x Bscale:%08x", blue_mask, blue_shift, blue_scale); + qDebug("Amask: %08x Ashift: %08x Ascale:%08x", alpha_mask, alpha_shift, alpha_scale); +#endif + // offset can be bogus, be careful if (offset>=0 && startpos + offset > d->pos()) { if (!d->isSequential()) @@ -535,11 +547,14 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int b = buf24; while (p < end) { c = *(uchar*)b | (*(uchar*)(b+1)<<8); - if (nbits != 16) + if (nbits > 16) c |= *(uchar*)(b+2)<<16; - *p++ = qRgb(((c & red_mask) >> red_shift) * red_scale, + if (nbits > 24) + c |= *(uchar*)(b+3)<<24; + *p++ = qRgba(((c & red_mask) >> red_shift) * red_scale, ((c & green_mask) >> green_shift) * green_scale, - ((c & blue_mask) >> blue_shift) * blue_scale); + ((c & blue_mask) >> blue_shift) * blue_scale, + transp ? ((c & alpha_mask) >> alpha_shift) * alpha_scale : 0xff); b += nbits/8; } } diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 0b2211defc..48c262ae7a 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -715,42 +715,6 @@ bool QImageData::checkForAlphaPixels() const QImage member functions *****************************************************************************/ -// table to flip bits -static const uchar bitflip[256] = { - /* - open OUT, "| fmt"; - for $i (0..255) { - print OUT (($i >> 7) & 0x01) | (($i >> 5) & 0x02) | - (($i >> 3) & 0x04) | (($i >> 1) & 0x08) | - (($i << 7) & 0x80) | (($i << 5) & 0x40) | - (($i << 3) & 0x20) | (($i << 1) & 0x10), ", "; - } - close OUT; - */ - 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, - 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, - 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, - 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, - 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, - 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, - 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, - 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, - 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, - 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, - 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, - 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, - 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, - 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, - 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, - 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 -}; - -const uchar *qt_get_bitflip_array() // called from QPixmap code -{ - return bitflip; -} - - /*! Constructs a null image. @@ -1105,8 +1069,7 @@ void QImage::detach() if (d->ref.load() != 1 || d->ro_data) *this = copy(); - if (d) - ++d->detach_no; + ++d->detach_no; } } @@ -1756,7 +1719,7 @@ void QImage::fill(const QColor &color) if (d->depth == 32) { uint pixel = color.rgba(); if (d->format == QImage::Format_ARGB32_Premultiplied || d->format == QImage::Format_RGBA8888_Premultiplied) - pixel = PREMUL(pixel); + pixel = qPremultiply(pixel); fill((uint) pixel); } else if (d->format == QImage::Format_RGB16) { @@ -1898,2101 +1861,9 @@ QImage::Format QImage::format() const return d ? d->format : Format_Invalid; } - - -/***************************************************************************** - Internal routines for converting image depth. - *****************************************************************************/ - -typedef void (*Image_Converter)(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags); - -typedef bool (*InPlace_Image_Converter)(QImageData *data, Qt::ImageConversionFlags); - -static void convert_ARGB_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_ARGB32 || src->format == QImage::Format_RGBA8888); - Q_ASSERT(dest->format == QImage::Format_ARGB32_Premultiplied || dest->format == QImage::Format_RGBA8888_Premultiplied); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const QRgb *src_data = (QRgb *) src->data; - QRgb *dest_data = (QRgb *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const QRgb *end = src_data + src->width; - while (src_data < end) { - *dest_data = PREMUL(*src_data); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static bool convert_ARGB_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags) -{ - Q_ASSERT(data->format == QImage::Format_ARGB32); - - const int pad = (data->bytes_per_line >> 2) - data->width; - QRgb *rgb_data = (QRgb *) data->data; - - for (int i = 0; i < data->height; ++i) { - const QRgb *end = rgb_data + data->width; - while (rgb_data < end) { - *rgb_data = PREMUL(*rgb_data); - ++rgb_data; - } - rgb_data += pad; - } - data->format = QImage::Format_ARGB32_Premultiplied; - return true; -} - -static void convert_ARGB_to_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_ARGB32); - Q_ASSERT(dest->format == QImage::Format_RGBX8888); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const quint32 *src_data = (quint32 *) src->data; - quint32 *dest_data = (quint32 *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const quint32 *end = src_data + src->width; - while (src_data < end) { - *dest_data = ARGB2RGBA(0xff000000 | *src_data); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static void convert_ARGB_to_RGBA(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_ARGB32 || src->format == QImage::Format_ARGB32_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_RGBA8888 || dest->format == QImage::Format_RGBA8888_Premultiplied); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const quint32 *src_data = (quint32 *) src->data; - quint32 *dest_data = (quint32 *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const quint32 *end = src_data + src->width; - while (src_data < end) { - *dest_data = ARGB2RGBA(*src_data); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static bool convert_ARGB_to_RGBA_inplace(QImageData *data, Qt::ImageConversionFlags) -{ - Q_ASSERT(data->format == QImage::Format_ARGB32 || data->format == QImage::Format_ARGB32_Premultiplied); - - const int pad = (data->bytes_per_line >> 2) - data->width; - quint32 *rgb_data = (quint32 *) data->data; - - for (int i = 0; i < data->height; ++i) { - const quint32 *end = rgb_data + data->width; - while (rgb_data < end) { - *rgb_data = ARGB2RGBA(*rgb_data); - ++rgb_data; - } - rgb_data += pad; - } - if (data->format == QImage::Format_ARGB32) - data->format = QImage::Format_RGBA8888; - else - data->format = QImage::Format_RGBA8888_Premultiplied; - return true; -} - -static void convert_ARGB_to_RGBA_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_ARGB32); - Q_ASSERT(dest->format == QImage::Format_RGBA8888_Premultiplied); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const quint32 *src_data = (quint32 *) src->data; - quint32 *dest_data = (quint32 *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const quint32 *end = src_data + src->width; - while (src_data < end) { - *dest_data = ARGB2RGBA(PREMUL(*src_data)); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static void convert_RGBA_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_RGBX8888 || src->format == QImage::Format_RGBA8888 || src->format == QImage::Format_RGBA8888_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_ARGB32_Premultiplied); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const quint32 *src_data = (quint32 *) src->data; - quint32 *dest_data = (quint32 *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const quint32 *end = src_data + src->width; - while (src_data < end) { - *dest_data = RGBA2ARGB(*src_data); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static bool convert_RGBA_to_ARGB_inplace(QImageData *data, Qt::ImageConversionFlags) -{ - Q_ASSERT(data->format == QImage::Format_RGBX8888 || data->format == QImage::Format_RGBA8888 || data->format == QImage::Format_RGBA8888_Premultiplied); - - const int pad = (data->bytes_per_line >> 2) - data->width; - QRgb *rgb_data = (QRgb *) data->data; - - for (int i = 0; i < data->height; ++i) { - const QRgb *end = rgb_data + data->width; - while (rgb_data < end) { - *rgb_data = RGBA2ARGB(*rgb_data); - ++rgb_data; - } - rgb_data += pad; - } - if (data->format == QImage::Format_RGBA8888_Premultiplied) - data->format = QImage::Format_ARGB32_Premultiplied; - else if (data->format == QImage::Format_RGBX8888) - data->format = QImage::Format_RGB32; - else - data->format = QImage::Format_ARGB32; - return true; -} - -static void convert_RGBA_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_RGBA8888); - Q_ASSERT(dest->format == QImage::Format_ARGB32_Premultiplied); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const quint32 *src_data = (quint32 *) src->data; - quint32 *dest_data = (quint32 *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const quint32 *end = src_data + src->width; - while (src_data < end) { - *dest_data = PREMUL(RGBA2ARGB(*src_data)); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static bool convert_RGBA_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags) -{ - Q_ASSERT(data->format == QImage::Format_RGBA8888); - - const int pad = (data->bytes_per_line >> 2) - data->width; - QRgb *rgb_data = (QRgb *) data->data; - - for (int i = 0; i < data->height; ++i) { - const QRgb *end = rgb_data + data->width; - while (rgb_data < end) { - *rgb_data = PREMUL(RGBA2ARGB(*rgb_data)); - ++rgb_data; - } - rgb_data += pad; - } - data->format = QImage::Format_ARGB32_Premultiplied; - return true; -} - -static bool convert_indexed8_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags) -{ - Q_ASSERT(data->format == QImage::Format_Indexed8); - const int depth = 32; - - const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; - const int nbytes = dst_bytes_per_line * data->height; - uchar *const newData = (uchar *)realloc(data->data, nbytes); - if (!newData) - return false; - - data->data = newData; - - // start converting from the end because the end image is bigger than the source - uchar *src_data = newData + data->nbytes; // end of src - quint32 *dest_data = (quint32 *) (newData + nbytes); // end of dest > end of src - const int width = data->width; - const int src_pad = data->bytes_per_line - width; - const int dest_pad = (dst_bytes_per_line >> 2) - width; - if (data->colortable.size() == 0) { - data->colortable.resize(256); - for (int i = 0; i < 256; ++i) - data->colortable[i] = qRgb(i, i, i); - } else { - for (int i = 0; i < data->colortable.size(); ++i) - data->colortable[i] = PREMUL(data->colortable.at(i)); - - // Fill the rest of the table in case src_data > colortable.size() - const int oldSize = data->colortable.size(); - const QRgb lastColor = data->colortable.at(oldSize - 1); - data->colortable.insert(oldSize, 256 - oldSize, lastColor); - } - - for (int i = 0; i < data->height; ++i) { - src_data -= src_pad; - dest_data -= dest_pad; - for (int pixI = 0; pixI < width; ++pixI) { - --src_data; - --dest_data; - *dest_data = data->colortable.at(*src_data); - } - } - - data->colortable = QVector<QRgb>(); - data->format = QImage::Format_ARGB32_Premultiplied; - data->bytes_per_line = dst_bytes_per_line; - data->depth = depth; - data->nbytes = nbytes; - - return true; -} - -static bool convert_indexed8_to_RGB_inplace(QImageData *data, Qt::ImageConversionFlags) -{ - Q_ASSERT(data->format == QImage::Format_Indexed8); - const int depth = 32; - - const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; - const int nbytes = dst_bytes_per_line * data->height; - uchar *const newData = (uchar *)realloc(data->data, nbytes); - if (!newData) - return false; - - data->data = newData; - - // start converting from the end because the end image is bigger than the source - uchar *src_data = newData + data->nbytes; - quint32 *dest_data = (quint32 *) (newData + nbytes); - const int width = data->width; - const int src_pad = data->bytes_per_line - width; - const int dest_pad = (dst_bytes_per_line >> 2) - width; - if (data->colortable.size() == 0) { - data->colortable.resize(256); - for (int i = 0; i < 256; ++i) - data->colortable[i] = qRgb(i, i, i); - } else { - // Fill the rest of the table in case src_data > colortable.size() - const int oldSize = data->colortable.size(); - const QRgb lastColor = data->colortable.at(oldSize - 1); - data->colortable.insert(oldSize, 256 - oldSize, lastColor); - } - - for (int i = 0; i < data->height; ++i) { - src_data -= src_pad; - dest_data -= dest_pad; - for (int pixI = 0; pixI < width; ++pixI) { - --src_data; - --dest_data; - *dest_data = (quint32) data->colortable.at(*src_data); - } - } - - data->colortable = QVector<QRgb>(); - data->format = QImage::Format_RGB32; - data->bytes_per_line = dst_bytes_per_line; - data->depth = depth; - data->nbytes = nbytes; - - return true; -} - -static bool convert_indexed8_to_RGB16_inplace(QImageData *data, Qt::ImageConversionFlags) -{ - Q_ASSERT(data->format == QImage::Format_Indexed8); - const int depth = 16; - - const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; - const int nbytes = dst_bytes_per_line * data->height; - uchar *const newData = (uchar *)realloc(data->data, nbytes); - if (!newData) - return false; - - data->data = newData; - - // start converting from the end because the end image is bigger than the source - uchar *src_data = newData + data->nbytes; - quint16 *dest_data = (quint16 *) (newData + nbytes); - const int width = data->width; - const int src_pad = data->bytes_per_line - width; - const int dest_pad = (dst_bytes_per_line >> 1) - width; - - quint16 colorTableRGB16[256]; - if (data->colortable.isEmpty()) { - for (int i = 0; i < 256; ++i) - colorTableRGB16[i] = qConvertRgb32To16(qRgb(i, i, i)); - } else { - // 1) convert the existing colors to RGB16 - const int tableSize = data->colortable.size(); - for (int i = 0; i < tableSize; ++i) - colorTableRGB16[i] = qConvertRgb32To16(data->colortable.at(i)); - data->colortable = QVector<QRgb>(); - - // 2) fill the rest of the table in case src_data > colortable.size() - const quint16 lastColor = colorTableRGB16[tableSize - 1]; - for (int i = tableSize; i < 256; ++i) - colorTableRGB16[i] = lastColor; - } - - for (int i = 0; i < data->height; ++i) { - src_data -= src_pad; - dest_data -= dest_pad; - for (int pixI = 0; pixI < width; ++pixI) { - --src_data; - --dest_data; - *dest_data = colorTableRGB16[*src_data]; - } - } - - data->format = QImage::Format_RGB16; - data->bytes_per_line = dst_bytes_per_line; - data->depth = depth; - data->nbytes = nbytes; - - return true; -} - -static bool convert_RGB_to_RGB16_inplace(QImageData *data, Qt::ImageConversionFlags) -{ - Q_ASSERT(data->format == QImage::Format_RGB32); - const int depth = 16; - - const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; - const int src_bytes_per_line = data->bytes_per_line; - quint32 *src_data = (quint32 *) data->data; - quint16 *dst_data = (quint16 *) data->data; - - for (int i = 0; i < data->height; ++i) { - for (int j = 0; j < data->width; ++j) - dst_data[j] = qConvertRgb32To16(src_data[j]); - src_data = (quint32 *) (((char*)src_data) + src_bytes_per_line); - dst_data = (quint16 *) (((char*)dst_data) + dst_bytes_per_line); - } - data->format = QImage::Format_RGB16; - data->bytes_per_line = dst_bytes_per_line; - data->depth = depth; - data->nbytes = dst_bytes_per_line * data->height; - uchar *const newData = (uchar *)realloc(data->data, data->nbytes); - if (newData) { - data->data = newData; - return true; - } else { - return false; - } -} - -static void convert_ARGB_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied || src->format == QImage::Format_RGBA8888_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_RGBA8888); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const QRgb *src_data = (QRgb *) src->data; - QRgb *dest_data = (QRgb *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const QRgb *end = src_data + src->width; - while (src_data < end) { - *dest_data = INV_PREMUL(*src_data); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static void convert_ARGB_PM_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied || src->format == QImage::Format_RGBA8888_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_RGB32 || dest->format == QImage::Format_RGBX8888); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const QRgb *src_data = (QRgb *) src->data; - QRgb *dest_data = (QRgb *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const QRgb *end = src_data + src->width; - while (src_data < end) { - *dest_data = 0xff000000 | INV_PREMUL(*src_data); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static void convert_ARGB_PM_to_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_RGBX8888); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const QRgb *src_data = (QRgb *) src->data; - QRgb *dest_data = (QRgb *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const QRgb *end = src_data + src->width; - while (src_data < end) { - *dest_data = ARGB2RGBA(0xff000000 | INV_PREMUL(*src_data)); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static void convert_ARGB_PM_to_RGBA(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_RGBA8888); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const QRgb *src_data = (QRgb *) src->data; - QRgb *dest_data = (QRgb *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const QRgb *end = src_data + src->width; - while (src_data < end) { - *dest_data = ARGB2RGBA(INV_PREMUL(*src_data)); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static void convert_RGBA_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_RGBA8888 || src->format == QImage::Format_RGBX8888); - Q_ASSERT(dest->format == QImage::Format_RGB32); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const uint *src_data = (const uint *)src->data; - uint *dest_data = (uint *)dest->data; - - for (int i = 0; i < src->height; ++i) { - const uint *end = src_data + src->width; - while (src_data < end) { - *dest_data = RGBA2ARGB(*src_data) | 0xff000000; - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static void convert_RGB_to_RGBA(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_RGB32); - Q_ASSERT(dest->format == QImage::Format_RGBX8888 || dest->format == QImage::Format_RGBA8888 || dest->format == QImage::Format_RGBA8888_Premultiplied); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const uint *src_data = (const uint *)src->data; - uint *dest_data = (uint *)dest->data; - - for (int i = 0; i < src->height; ++i) { - const uint *end = src_data + src->width; - while (src_data < end) { - *dest_data = ARGB2RGBA(*src_data | 0xff000000); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static void convert_RGBA_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_RGBA8888_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_ARGB32); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const QRgb *src_data = (QRgb *) src->data; - QRgb *dest_data = (QRgb *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const QRgb *end = src_data + src->width; - while (src_data < end) { - *dest_data = INV_PREMUL(RGBA2ARGB(*src_data)); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static void convert_RGBA_PM_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_RGBA8888_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_RGB32); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const QRgb *src_data = (QRgb *) src->data; - QRgb *dest_data = (QRgb *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const QRgb *end = src_data + src->width; - while (src_data < end) { - *dest_data = 0xff000000 | INV_PREMUL(RGBA2ARGB(*src_data)); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static void swap_bit_order(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_Mono || src->format == QImage::Format_MonoLSB); - Q_ASSERT(dest->format == QImage::Format_Mono || dest->format == QImage::Format_MonoLSB); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - Q_ASSERT(src->nbytes == dest->nbytes); - Q_ASSERT(src->bytes_per_line == dest->bytes_per_line); - - dest->colortable = src->colortable; - - const uchar *src_data = src->data; - const uchar *end = src->data + src->nbytes; - uchar *dest_data = dest->data; - while (src_data < end) { - *dest_data = bitflip[*src_data]; - ++src_data; - ++dest_data; - } -} - -static void mask_alpha_converter(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const uint *src_data = (const uint *)src->data; - uint *dest_data = (uint *)dest->data; - - for (int i = 0; i < src->height; ++i) { - const uint *end = src_data + src->width; - while (src_data < end) { - *dest_data = *src_data | 0xff000000; - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - -static void mask_alpha_converter_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags flags) -{ -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - return mask_alpha_converter(dest, src, flags); -#else - Q_UNUSED(flags); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const uint *src_data = (const uint *)src->data; - uint *dest_data = (uint *)dest->data; - - for (int i = 0; i < src->height; ++i) { - const uint *end = src_data + src->width; - while (src_data < end) { - *dest_data = *src_data | 0x000000ff; - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -#endif -} - -static QVector<QRgb> fix_color_table(const QVector<QRgb> &ctbl, QImage::Format format) -{ - QVector<QRgb> colorTable = ctbl; - if (format == QImage::Format_RGB32) { - // check if the color table has alpha - for (int i = 0; i < colorTable.size(); ++i) - if (qAlpha(colorTable.at(i) != 0xff)) - colorTable[i] = colorTable.at(i) | 0xff000000; - } else if (format == QImage::Format_ARGB32_Premultiplied) { - // check if the color table has alpha - for (int i = 0; i < colorTable.size(); ++i) - colorTable[i] = PREMUL(colorTable.at(i)); - } - return colorTable; -} - -// -// dither_to_1: Uses selected dithering algorithm. -// - -static void dither_to_Mono(QImageData *dst, const QImageData *src, - Qt::ImageConversionFlags flags, bool fromalpha) -{ - Q_ASSERT(src->width == dst->width); - Q_ASSERT(src->height == dst->height); - Q_ASSERT(dst->format == QImage::Format_Mono || dst->format == QImage::Format_MonoLSB); - - dst->colortable.clear(); - dst->colortable.append(0xffffffff); - dst->colortable.append(0xff000000); - - enum { Threshold, Ordered, Diffuse } dithermode; - - if (fromalpha) { - if ((flags & Qt::AlphaDither_Mask) == Qt::DiffuseAlphaDither) - dithermode = Diffuse; - else if ((flags & Qt::AlphaDither_Mask) == Qt::OrderedAlphaDither) - dithermode = Ordered; - else - dithermode = Threshold; - } else { - if ((flags & Qt::Dither_Mask) == Qt::ThresholdDither) - dithermode = Threshold; - else if ((flags & Qt::Dither_Mask) == Qt::OrderedDither) - dithermode = Ordered; - else - dithermode = Diffuse; - } - - int w = src->width; - int h = src->height; - int d = src->depth; - uchar gray[256]; // gray map for 8 bit images - bool use_gray = (d == 8); - if (use_gray) { // make gray map - if (fromalpha) { - // Alpha 0x00 -> 0 pixels (white) - // Alpha 0xFF -> 1 pixels (black) - for (int i = 0; i < src->colortable.size(); i++) - gray[i] = (255 - (src->colortable.at(i) >> 24)); - } else { - // Pixel 0x00 -> 1 pixels (black) - // Pixel 0xFF -> 0 pixels (white) - for (int i = 0; i < src->colortable.size(); i++) - gray[i] = qGray(src->colortable.at(i)); - } - } - - uchar *dst_data = dst->data; - int dst_bpl = dst->bytes_per_line; - const uchar *src_data = src->data; - int src_bpl = src->bytes_per_line; - - switch (dithermode) { - case Diffuse: { - QScopedArrayPointer<int> lineBuffer(new int[w * 2]); - int *line1 = lineBuffer.data(); - int *line2 = lineBuffer.data() + w; - int bmwidth = (w+7)/8; - - int *b1, *b2; - int wbytes = w * (d/8); - const uchar *p = src->data; - const uchar *end = p + wbytes; - b2 = line2; - if (use_gray) { // 8 bit image - while (p < end) - *b2++ = gray[*p++]; - } else { // 32 bit image - if (fromalpha) { - while (p < end) { - *b2++ = 255 - (*(uint*)p >> 24); - p += 4; - } - } else { - while (p < end) { - *b2++ = qGray(*(uint*)p); - p += 4; - } - } - } - for (int y=0; y<h; y++) { // for each scan line... - int *tmp = line1; line1 = line2; line2 = tmp; - bool not_last_line = y < h - 1; - if (not_last_line) { // calc. grayvals for next line - p = src->data + (y+1)*src->bytes_per_line; - end = p + wbytes; - b2 = line2; - if (use_gray) { // 8 bit image - while (p < end) - *b2++ = gray[*p++]; - } else { // 24 bit image - if (fromalpha) { - while (p < end) { - *b2++ = 255 - (*(uint*)p >> 24); - p += 4; - } - } else { - while (p < end) { - *b2++ = qGray(*(uint*)p); - p += 4; - } - } - } - } - - int err; - uchar *p = dst->data + y*dst->bytes_per_line; - memset(p, 0, bmwidth); - b1 = line1; - b2 = line2; - int bit = 7; - for (int x=1; x<=w; x++) { - if (*b1 < 128) { // black pixel - err = *b1++; - *p |= 1 << bit; - } else { // white pixel - err = *b1++ - 255; - } - if (bit == 0) { - p++; - bit = 7; - } else { - bit--; - } - if (x < w) - *b1 += (err*7)>>4; // spread error to right pixel - if (not_last_line) { - b2[0] += (err*5)>>4; // pixel below - if (x > 1) - b2[-1] += (err*3)>>4; // pixel below left - if (x < w) - b2[1] += err>>4; // pixel below right - } - b2++; - } - } - } break; - case Ordered: { - - memset(dst->data, 0, dst->nbytes); - if (d == 32) { - for (int i=0; i<h; i++) { - const uint *p = (const uint *)src_data; - const uint *end = p + w; - uchar *m = dst_data; - int bit = 7; - int j = 0; - if (fromalpha) { - while (p < end) { - if ((*p++ >> 24) >= qt_bayer_matrix[j++&15][i&15]) - *m |= 1 << bit; - if (bit == 0) { - m++; - bit = 7; - } else { - bit--; - } - } - } else { - while (p < end) { - if ((uint)qGray(*p++) < qt_bayer_matrix[j++&15][i&15]) - *m |= 1 << bit; - if (bit == 0) { - m++; - bit = 7; - } else { - bit--; - } - } - } - dst_data += dst_bpl; - src_data += src_bpl; - } - } else - /* (d == 8) */ { - for (int i=0; i<h; i++) { - const uchar *p = src_data; - const uchar *end = p + w; - uchar *m = dst_data; - int bit = 7; - int j = 0; - while (p < end) { - if ((uint)gray[*p++] < qt_bayer_matrix[j++&15][i&15]) - *m |= 1 << bit; - if (bit == 0) { - m++; - bit = 7; - } else { - bit--; - } - } - dst_data += dst_bpl; - src_data += src_bpl; - } - } - } break; - default: { // Threshold: - memset(dst->data, 0, dst->nbytes); - if (d == 32) { - for (int i=0; i<h; i++) { - const uint *p = (const uint *)src_data; - const uint *end = p + w; - uchar *m = dst_data; - int bit = 7; - if (fromalpha) { - while (p < end) { - if ((*p++ >> 24) >= 128) - *m |= 1 << bit; // Set mask "on" - if (bit == 0) { - m++; - bit = 7; - } else { - bit--; - } - } - } else { - while (p < end) { - if (qGray(*p++) < 128) - *m |= 1 << bit; // Set pixel "black" - if (bit == 0) { - m++; - bit = 7; - } else { - bit--; - } - } - } - dst_data += dst_bpl; - src_data += src_bpl; - } - } else - if (d == 8) { - for (int i=0; i<h; i++) { - const uchar *p = src_data; - const uchar *end = p + w; - uchar *m = dst_data; - int bit = 7; - while (p < end) { - if (gray[*p++] < 128) - *m |= 1 << bit; // Set mask "on"/ pixel "black" - if (bit == 0) { - m++; - bit = 7; - } else { - bit--; - } - } - dst_data += dst_bpl; - src_data += src_bpl; - } - } - } - } - - if (dst->format == QImage::Format_MonoLSB) { - // need to swap bit order - uchar *sl = dst->data; - int bpl = (dst->width + 7) * dst->depth / 8; - int pad = dst->bytes_per_line - bpl; - for (int y=0; y<dst->height; ++y) { - for (int x=0; x<bpl; ++x) { - *sl = bitflip[*sl]; - ++sl; - } - sl += pad; - } - } -} - -static void convert_X_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags) -{ - dither_to_Mono(dst, src, flags, false); -} - -static void convert_ARGB_PM_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags) -{ - QScopedPointer<QImageData> tmp(QImageData::create(QSize(src->width, src->height), QImage::Format_ARGB32)); - convert_ARGB_PM_to_ARGB(tmp.data(), src, flags); - dither_to_Mono(dst, tmp.data(), flags, false); -} - -// -// convert_32_to_8: Converts a 32 bits depth (true color) to an 8 bit -// image with a colormap. If the 32 bit image has more than 256 colors, -// we convert the red,green and blue bytes into a single byte encoded -// as 6 shades of each of red, green and blue. -// -// if dithering is needed, only 1 color at most is available for alpha. -// -struct QRgbMap { - inline QRgbMap() : used(0) { } - uchar pix; - uchar used; - QRgb rgb; -}; - -static void convert_RGB_to_Indexed8(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags) -{ - Q_ASSERT(src->format == QImage::Format_RGB32 || src->format == QImage::Format_ARGB32); - Q_ASSERT(dst->format == QImage::Format_Indexed8); - Q_ASSERT(src->width == dst->width); - Q_ASSERT(src->height == dst->height); - - bool do_quant = (flags & Qt::DitherMode_Mask) == Qt::PreferDither - || src->format == QImage::Format_ARGB32; - uint alpha_mask = src->format == QImage::Format_RGB32 ? 0xff000000 : 0; - - const int tablesize = 997; // prime - QRgbMap table[tablesize]; - int pix=0; - - if (!dst->colortable.isEmpty()) { - QVector<QRgb> ctbl = dst->colortable; - dst->colortable.resize(256); - // Preload palette into table. - // Almost same code as pixel insertion below - for (int i = 0; i < dst->colortable.size(); ++i) { - // Find in table... - QRgb p = ctbl.at(i) | alpha_mask; - int hash = p % tablesize; - for (;;) { - if (table[hash].used) { - if (table[hash].rgb == p) { - // Found previous insertion - use it - break; - } else { - // Keep searching... - if (++hash == tablesize) hash = 0; - } - } else { - // Cannot be in table - Q_ASSERT (pix != 256); // too many colors - // Insert into table at this unused position - dst->colortable[pix] = p; - table[hash].pix = pix++; - table[hash].rgb = p; - table[hash].used = 1; - break; - } - } - } - } - - if ((flags & Qt::DitherMode_Mask) != Qt::PreferDither) { - dst->colortable.resize(256); - const uchar *src_data = src->data; - uchar *dest_data = dst->data; - for (int y = 0; y < src->height; y++) { // check if <= 256 colors - const QRgb *s = (const QRgb *)src_data; - uchar *b = dest_data; - for (int x = 0; x < src->width; ++x) { - QRgb p = s[x] | alpha_mask; - int hash = p % tablesize; - for (;;) { - if (table[hash].used) { - if (table[hash].rgb == (p)) { - // Found previous insertion - use it - break; - } else { - // Keep searching... - if (++hash == tablesize) hash = 0; - } - } else { - // Cannot be in table - if (pix == 256) { // too many colors - do_quant = true; - // Break right out - x = src->width; - y = src->height; - } else { - // Insert into table at this unused position - dst->colortable[pix] = p; - table[hash].pix = pix++; - table[hash].rgb = p; - table[hash].used = 1; - } - break; - } - } - *b++ = table[hash].pix; // May occur once incorrectly - } - src_data += src->bytes_per_line; - dest_data += dst->bytes_per_line; - } - } - int numColors = do_quant ? 256 : pix; - - dst->colortable.resize(numColors); - - if (do_quant) { // quantization needed - -#define MAX_R 5 -#define MAX_G 5 -#define MAX_B 5 -#define INDEXOF(r,g,b) (((r)*(MAX_G+1)+(g))*(MAX_B+1)+(b)) - - for (int rc=0; rc<=MAX_R; rc++) // build 6x6x6 color cube - for (int gc=0; gc<=MAX_G; gc++) - for (int bc=0; bc<=MAX_B; bc++) - dst->colortable[INDEXOF(rc,gc,bc)] = 0xff000000 | qRgb(rc*255/MAX_R, gc*255/MAX_G, bc*255/MAX_B); - - const uchar *src_data = src->data; - uchar *dest_data = dst->data; - if ((flags & Qt::Dither_Mask) == Qt::ThresholdDither) { - for (int y = 0; y < src->height; y++) { - const QRgb *p = (const QRgb *)src_data; - const QRgb *end = p + src->width; - uchar *b = dest_data; - - while (p < end) { -#define DITHER(p,m) ((uchar) ((p * (m) + 127) / 255)) - *b++ = - INDEXOF( - DITHER(qRed(*p), MAX_R), - DITHER(qGreen(*p), MAX_G), - DITHER(qBlue(*p), MAX_B) - ); -#undef DITHER - p++; - } - src_data += src->bytes_per_line; - dest_data += dst->bytes_per_line; - } - } else if ((flags & Qt::Dither_Mask) == Qt::DiffuseDither) { - int* line1[3]; - int* line2[3]; - int* pv[3]; - QScopedArrayPointer<int> lineBuffer(new int[src->width * 9]); - line1[0] = lineBuffer.data(); - line2[0] = lineBuffer.data() + src->width; - line1[1] = lineBuffer.data() + src->width * 2; - line2[1] = lineBuffer.data() + src->width * 3; - line1[2] = lineBuffer.data() + src->width * 4; - line2[2] = lineBuffer.data() + src->width * 5; - pv[0] = lineBuffer.data() + src->width * 6; - pv[1] = lineBuffer.data() + src->width * 7; - pv[2] = lineBuffer.data() + src->width * 8; - - int endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian); - for (int y = 0; y < src->height; y++) { - const uchar* q = src_data; - const uchar* q2 = y < src->height - 1 ? q + src->bytes_per_line : src->data; - uchar *b = dest_data; - for (int chan = 0; chan < 3; chan++) { - int *l1 = (y&1) ? line2[chan] : line1[chan]; - int *l2 = (y&1) ? line1[chan] : line2[chan]; - if (y == 0) { - for (int i = 0; i < src->width; i++) - l1[i] = q[i*4+chan+endian]; - } - if (y+1 < src->height) { - for (int i = 0; i < src->width; i++) - l2[i] = q2[i*4+chan+endian]; - } - // Bi-directional error diffusion - if (y&1) { - for (int x = 0; x < src->width; x++) { - int pix = qMax(qMin(5, (l1[x] * 5 + 128)/ 255), 0); - int err = l1[x] - pix * 255 / 5; - pv[chan][x] = pix; - - // Spread the error around... - if (x + 1< src->width) { - l1[x+1] += (err*7)>>4; - l2[x+1] += err>>4; - } - l2[x]+=(err*5)>>4; - if (x>1) - l2[x-1]+=(err*3)>>4; - } - } else { - for (int x = src->width; x-- > 0;) { - int pix = qMax(qMin(5, (l1[x] * 5 + 128)/ 255), 0); - int err = l1[x] - pix * 255 / 5; - pv[chan][x] = pix; - - // Spread the error around... - if (x > 0) { - l1[x-1] += (err*7)>>4; - l2[x-1] += err>>4; - } - l2[x]+=(err*5)>>4; - if (x + 1 < src->width) - l2[x+1]+=(err*3)>>4; - } - } - } - if (endian) { - for (int x = 0; x < src->width; x++) { - *b++ = INDEXOF(pv[0][x],pv[1][x],pv[2][x]); - } - } else { - for (int x = 0; x < src->width; x++) { - *b++ = INDEXOF(pv[2][x],pv[1][x],pv[0][x]); - } - } - src_data += src->bytes_per_line; - dest_data += dst->bytes_per_line; - } - } else { // OrderedDither - for (int y = 0; y < src->height; y++) { - const QRgb *p = (const QRgb *)src_data; - const QRgb *end = p + src->width; - uchar *b = dest_data; - - int x = 0; - while (p < end) { - uint d = qt_bayer_matrix[y & 15][x & 15] << 8; - -#define DITHER(p, d, m) ((uchar) ((((256 * (m) + (m) + 1)) * (p) + (d)) >> 16)) - *b++ = - INDEXOF( - DITHER(qRed(*p), d, MAX_R), - DITHER(qGreen(*p), d, MAX_G), - DITHER(qBlue(*p), d, MAX_B) - ); -#undef DITHER - - p++; - x++; - } - src_data += src->bytes_per_line; - dest_data += dst->bytes_per_line; - } - } - - if (src->format != QImage::Format_RGB32 - && src->format != QImage::Format_RGB16) { - const int trans = 216; - Q_ASSERT(dst->colortable.size() > trans); - dst->colortable[trans] = 0; - QScopedPointer<QImageData> mask(QImageData::create(QSize(src->width, src->height), QImage::Format_Mono)); - dither_to_Mono(mask.data(), src, flags, true); - uchar *dst_data = dst->data; - const uchar *mask_data = mask->data; - for (int y = 0; y < src->height; y++) { - for (int x = 0; x < src->width ; x++) { - if (!(mask_data[x>>3] & (0x80 >> (x & 7)))) - dst_data[x] = trans; - } - mask_data += mask->bytes_per_line; - dst_data += dst->bytes_per_line; - } - dst->has_alpha_clut = true; - } - -#undef MAX_R -#undef MAX_G -#undef MAX_B -#undef INDEXOF - - } -} - -static void convert_ARGB_PM_to_Indexed8(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags) -{ - QScopedPointer<QImageData> tmp(QImageData::create(QSize(src->width, src->height), QImage::Format_ARGB32)); - convert_ARGB_PM_to_ARGB(tmp.data(), src, flags); - convert_RGB_to_Indexed8(dst, tmp.data(), flags); -} - -static void convert_ARGB_to_Indexed8(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags) -{ - convert_RGB_to_Indexed8(dst, src, flags); -} - -static void convert_Indexed8_to_X32(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_Indexed8); - Q_ASSERT(dest->format == QImage::Format_RGB32 - || dest->format == QImage::Format_ARGB32 - || dest->format == QImage::Format_ARGB32_Premultiplied); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - QVector<QRgb> colorTable = fix_color_table(src->colortable, dest->format); - if (colorTable.size() == 0) { - colorTable.resize(256); - for (int i=0; i<256; ++i) - colorTable[i] = qRgb(i, i, i); - } - - int w = src->width; - const uchar *src_data = src->data; - uchar *dest_data = dest->data; - int tableSize = colorTable.size() - 1; - for (int y = 0; y < src->height; y++) { - uint *p = (uint *)dest_data; - const uchar *b = src_data; - uint *end = p + w; - - while (p < end) - *p++ = colorTable.at(qMin<int>(tableSize, *b++)); - - src_data += src->bytes_per_line; - dest_data += dest->bytes_per_line; - } -} - -static void convert_Mono_to_X32(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_Mono || src->format == QImage::Format_MonoLSB); - Q_ASSERT(dest->format == QImage::Format_RGB32 - || dest->format == QImage::Format_ARGB32 - || dest->format == QImage::Format_ARGB32_Premultiplied); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - QVector<QRgb> colorTable = fix_color_table(src->colortable, dest->format); - - // Default to black / white colors - if (colorTable.size() < 2) { - if (colorTable.size() == 0) - colorTable << 0xff000000; - colorTable << 0xffffffff; - } - - const uchar *src_data = src->data; - uchar *dest_data = dest->data; - if (src->format == QImage::Format_Mono) { - for (int y = 0; y < dest->height; y++) { - uint *p = (uint *)dest_data; - for (int x = 0; x < dest->width; x++) - *p++ = colorTable.at((src_data[x>>3] >> (7 - (x & 7))) & 1); - - src_data += src->bytes_per_line; - dest_data += dest->bytes_per_line; - } - } else { - for (int y = 0; y < dest->height; y++) { - uint *p = (uint *)dest_data; - for (int x = 0; x < dest->width; x++) - *p++ = colorTable.at((src_data[x>>3] >> (x & 7)) & 1); - - src_data += src->bytes_per_line; - dest_data += dest->bytes_per_line; - } - } -} - - -static void convert_Mono_to_Indexed8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - Q_ASSERT(src->format == QImage::Format_Mono || src->format == QImage::Format_MonoLSB); - Q_ASSERT(dest->format == QImage::Format_Indexed8); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - QVector<QRgb> ctbl = src->colortable; - if (ctbl.size() > 2) { - ctbl.resize(2); - } else if (ctbl.size() < 2) { - if (ctbl.size() == 0) - ctbl << 0xff000000; - ctbl << 0xffffffff; - } - dest->colortable = ctbl; - dest->has_alpha_clut = src->has_alpha_clut; - - - const uchar *src_data = src->data; - uchar *dest_data = dest->data; - if (src->format == QImage::Format_Mono) { - for (int y = 0; y < dest->height; y++) { - uchar *p = dest_data; - for (int x = 0; x < dest->width; x++) - *p++ = (src_data[x>>3] >> (7 - (x & 7))) & 1; - src_data += src->bytes_per_line; - dest_data += dest->bytes_per_line; - } - } else { - for (int y = 0; y < dest->height; y++) { - uchar *p = dest_data; - for (int x = 0; x < dest->width; x++) - *p++ = (src_data[x>>3] >> (x & 7)) & 1; - src_data += src->bytes_per_line; - dest_data += dest->bytes_per_line; - } - } -} - -// Cannot be used with indexed formats. -static void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) -{ - const int buffer_size = 2048; - uint buffer[buffer_size]; - const QPixelLayout *srcLayout = &qPixelLayouts[src->format]; - const QPixelLayout *destLayout = &qPixelLayouts[dest->format]; - const uchar *srcData = src->data; - uchar *destData = dest->data; - - FetchPixelsFunc fetch = qFetchPixels[srcLayout->bpp]; - StorePixelsFunc store = qStorePixels[destLayout->bpp]; - - for (int y = 0; y < src->height; ++y) { - int x = 0; - while (x < src->width) { - int l = qMin(src->width - x, buffer_size); - const uint *ptr = fetch(buffer, srcData, x, l); - ptr = srcLayout->convertToARGB32PM(buffer, ptr, l, srcLayout, 0); - ptr = destLayout->convertFromARGB32PM(buffer, ptr, l, destLayout, 0); - store(destData, ptr, x, l); - x += l; - } - srcData += src->bytes_per_line; - destData += dest->bytes_per_line; - } -} - - -// first index source, second dest -static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormats] = -{ - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, - { - 0, - 0, - swap_bit_order, - convert_Mono_to_Indexed8, - convert_Mono_to_X32, - convert_Mono_to_X32, - convert_Mono_to_X32, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - }, // Format_Mono - - { - 0, - swap_bit_order, - 0, - convert_Mono_to_Indexed8, - convert_Mono_to_X32, - convert_Mono_to_X32, - convert_Mono_to_X32, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - }, // Format_MonoLSB - - { - 0, - convert_X_to_Mono, - convert_X_to_Mono, - 0, - convert_Indexed8_to_X32, - convert_Indexed8_to_X32, - convert_Indexed8_to_X32, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - }, // Format_Indexed8 - - { - 0, - convert_X_to_Mono, - convert_X_to_Mono, - convert_RGB_to_Indexed8, - 0, - mask_alpha_converter, - mask_alpha_converter, - convert_generic, - convert_generic, - convert_generic, - convert_generic, - convert_generic, - convert_generic, - convert_generic, - convert_generic, - convert_generic, - convert_RGB_to_RGBA, - convert_RGB_to_RGBA, - convert_RGB_to_RGBA - }, // Format_RGB32 - - { - 0, - convert_X_to_Mono, - convert_X_to_Mono, - convert_ARGB_to_Indexed8, - mask_alpha_converter, - 0, - convert_ARGB_to_ARGB_PM, - convert_generic, - convert_generic, - convert_generic, - convert_generic, - convert_generic, - convert_generic, - convert_generic, - convert_generic, - convert_generic, - convert_ARGB_to_RGBx, - convert_ARGB_to_RGBA, - convert_ARGB_to_RGBA_PM, - }, // Format_ARGB32 - - { - 0, - convert_ARGB_PM_to_Mono, - convert_ARGB_PM_to_Mono, - convert_ARGB_PM_to_Indexed8, - convert_ARGB_PM_to_RGB, - convert_ARGB_PM_to_ARGB, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_ARGB_PM_to_RGBx, - convert_ARGB_PM_to_RGBA, - convert_ARGB_to_RGBA, - }, // Format_ARGB32_Premultiplied - - { - 0, - 0, - 0, - 0, - convert_generic, - convert_generic, - convert_generic, - 0, - 0, - 0, - 0, -#if defined(QT_QWS_DEPTH_15) && defined(QT_QWS_DEPTH_16) - convert_generic, -#else - 0, -#endif - 0, - 0, - 0, - 0, - 0, - 0, - 0 - }, // Format_RGB16 - - { - 0, - 0, - 0, - 0, - convert_generic, - convert_generic, - convert_generic, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - }, // Format_ARGB8565_Premultiplied - - { - 0, - 0, - 0, - 0, - convert_generic, - convert_generic, - convert_generic, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - }, // Format_RGB666 - - { - 0, - 0, - 0, - 0, - convert_generic, - convert_generic, - convert_generic, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - }, // Format_ARGB6666_Premultiplied - - { - 0, - 0, - 0, - 0, - convert_generic, - convert_generic, - convert_generic, -#if defined(QT_QWS_DEPTH_15) && defined(QT_QWS_DEPTH_16) - convert_generic, -#else - 0, -#endif - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - }, // Format_RGB555 - - { - 0, - 0, - 0, - 0, - convert_generic, - convert_generic, - convert_generic, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - }, // Format_ARGB8555_Premultiplied - - { - 0, - 0, - 0, - 0, - convert_generic, - convert_generic, - convert_generic, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - }, // Format_RGB888 - - { - 0, - 0, - 0, - 0, - convert_generic, - convert_generic, - convert_generic, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - }, // Format_RGB444 - - { - 0, - 0, - 0, - 0, - convert_generic, - convert_generic, - convert_generic, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - }, // Format_ARGB4444_Premultiplied - { - 0, - 0, - 0, - 0, - convert_RGBA_to_RGB, - convert_RGBA_to_ARGB, - convert_RGBA_to_ARGB, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - mask_alpha_converter_RGBx, - mask_alpha_converter_RGBx, - }, // Format_RGBX8888 - { - 0, - 0, - 0, - 0, - convert_RGBA_to_RGB, - convert_RGBA_to_ARGB, - convert_RGBA_to_ARGB_PM, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - mask_alpha_converter_RGBx, -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - 0, - convert_ARGB_to_ARGB_PM, -#else - 0, - 0 -#endif - }, // Format_RGBA8888 - - { - 0, - 0, - 0, - 0, - convert_RGBA_PM_to_RGB, - convert_RGBA_PM_to_ARGB, - convert_RGBA_to_ARGB, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - convert_ARGB_PM_to_RGB, - convert_ARGB_PM_to_ARGB, - 0, -#else - 0, - 0, - 0 -#endif - } // Format_RGBA8888_Premultiplied -}; - -static InPlace_Image_Converter 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 - }, // Format_Mono - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_MonoLSB - { - 0, - 0, - 0, - 0, - 0, - convert_indexed8_to_RGB_inplace, - convert_indexed8_to_ARGB_PM_inplace, - convert_indexed8_to_RGB16_inplace, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - }, // Format_Indexed8 - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_RGB_to_RGB16_inplace, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - }, // Format_RGB32 - { - 0, - 0, - 0, - 0, - 0, - 0, - convert_ARGB_to_ARGB_PM_inplace, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_ARGB_to_RGBA_inplace, - 0, - }, // Format_ARGB32 - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_ARGB_to_RGBA_inplace - }, // Format_ARGB32_Premultiplied - { - 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 - }, // Format_ARGB8565_Premultiplied - { - 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 - }, // Format_ARGB6666_Premultiplied - { - 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 - }, // Format_ARGB8555_Premultiplied - { - 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 - }, // Format_RGB444 - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, // Format_ARGB4444_Premultiplied - { - 0, - 0, - 0, - 0, - 0, - convert_RGBA_to_ARGB_inplace, - convert_RGBA_to_ARGB_inplace, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - }, // Format_RGBX8888 - { - 0, - 0, - 0, - 0, - 0, - 0, - convert_RGBA_to_ARGB_inplace, - convert_RGBA_to_ARGB_PM_inplace, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - }, // Format_RGBA8888 - { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - convert_RGBA_to_ARGB_inplace, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - } // Format_RGBA8888_Premultiplied -}; - -void qInitImageConversions() -{ -#ifdef QT_COMPILER_SUPPORTS_AVX - if (qCpuHasFeature(AVX)) { - extern bool convert_ARGB_to_ARGB_PM_inplace_avx(QImageData *data, Qt::ImageConversionFlags); - inplace_converter_map[QImage::Format_ARGB32][QImage::Format_ARGB32_Premultiplied] = convert_ARGB_to_ARGB_PM_inplace_avx; - - extern void convert_RGB888_to_RGB32_avx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags); - converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_avx; - converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_avx; - converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_avx; - return; - } -#endif - -#if defined(QT_COMPILER_SUPPORTS_SSE2) && !defined(__AVX__) - if (qCpuHasFeature(SSE2)) { - extern bool convert_ARGB_to_ARGB_PM_inplace_sse2(QImageData *data, Qt::ImageConversionFlags); - inplace_converter_map[QImage::Format_ARGB32][QImage::Format_ARGB32_Premultiplied] = convert_ARGB_to_ARGB_PM_inplace_sse2; -#ifdef QT_COMPILER_SUPPORTS_SSSE3 - if (qCpuHasFeature(SSSE3)) { - extern void convert_RGB888_to_RGB32_ssse3(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags); - converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_ssse3; - converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_ssse3; - converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_ssse3; - } -#endif - return; - } -#endif // SSE2 - -#ifdef QT_COMPILER_SUPPORTS_NEON - if (qCpuHasFeature(NEON)) { - extern void convert_RGB888_to_RGB32_neon(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags); - converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_neon; - converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_neon; - converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_neon; - return; - } -#endif - -#ifdef QT_COMPILER_SUPPORTS_MIPS_DSPR2 - extern bool convert_ARGB_to_ARGB_PM_inplace_mips_dspr2(QImageData *data, Qt::ImageConversionFlags); - inplace_converter_map[QImage::Format_ARGB32][QImage::Format_ARGB32_Premultiplied] = convert_ARGB_to_ARGB_PM_inplace_mips_dspr2; - return; -#endif -} - -extern const uchar *qt_pow_rgb_gamma(); - -void qGamma_correct_back_to_linear_cs(QImage *image) -{ - const QDrawHelperGammaTables *tables = QGuiApplicationPrivate::instance()->gammaTables(); - if (!tables) - return; - const uchar *gamma = tables->qt_pow_rgb_gamma; - // gamma correct the pixels back to linear color space... - int h = image->height(); - int w = image->width(); - - for (int y=0; y<h; ++y) { - uint *pixels = (uint *) image->scanLine(y); - for (int x=0; x<w; ++x) { - uint p = pixels[x]; - uint r = gamma[qRed(p)]; - uint g = gamma[qGreen(p)]; - uint b = gamma[qBlue(p)]; - pixels[x] = (r << 16) | (g << 8) | b | 0xff000000; - } - } -} - /*! + \fn QImage QImage::convertToFormat(Format format, Qt::ImageConversionFlags flags) const + Returns a copy of the image in the given \a format. The specified image conversion \a flags control how the image data @@ -4000,7 +1871,11 @@ void qGamma_correct_back_to_linear_cs(QImage *image) \sa {Image Formats} */ -QImage QImage::convertToFormat(Format format, Qt::ImageConversionFlags flags) const + +/*! + \internal +*/ +QImage QImage::convertToFormat_helper(Format format, Qt::ImageConversionFlags flags) const { if (!d || d->format == format) return *this; @@ -4008,8 +1883,9 @@ QImage QImage::convertToFormat(Format format, Qt::ImageConversionFlags flags) co if (format == Format_Invalid || d->format == Format_Invalid) return QImage(); - const Image_Converter *converterPtr = &converter_map[d->format][format]; - Image_Converter converter = *converterPtr; + Image_Converter converter = qimage_converter_map[d->format][format]; + if (!converter && format > QImage::Format_Indexed8 && d->format > QImage::Format_Indexed8) + converter = convert_generic; if (converter) { QImage image(d->width, d->height, format); @@ -4025,14 +1901,20 @@ QImage QImage::convertToFormat(Format format, Qt::ImageConversionFlags flags) co return image; } + // Convert indexed formats over ARGB32 to the final format. Q_ASSERT(format != QImage::Format_ARGB32); Q_ASSERT(d->format != QImage::Format_ARGB32); - QImage image = convertToFormat(Format_ARGB32, flags); - return image.convertToFormat(format, flags); + return convertToFormat(Format_ARGB32, flags).convertToFormat(format, flags); } - +/*! + \internal +*/ +bool QImage::convertToFormat_inplace(Format format, Qt::ImageConversionFlags flags) +{ + return d && d->convertInPlace(format, flags); +} static inline int pixel_distance(QRgb p1, QRgb p2) { int r1 = qRed(p1); @@ -4131,7 +2013,7 @@ QImage QImage::convertToFormat(Format format, const QVector<QRgb> &colorTable, Q return convertWithPalette(*this, format, colorTable); } - const Image_Converter *converterPtr = &converter_map[d->format][format]; + const Image_Converter *converterPtr = &qimage_converter_map[d->format][format]; Image_Converter converter = *converterPtr; if (!converter) return QImage(); @@ -4240,6 +2122,7 @@ QRgb QImage::pixel(int x, int y) const case Format_Indexed8: return d->colortable.at((int)s[x]); case Format_RGB32: + return 0xff000000 | reinterpret_cast<const QRgb *>(s)[x]; case Format_ARGB32: // Keep old behaviour. case Format_ARGB32_Premultiplied: return reinterpret_cast<const QRgb *>(s)[x]; @@ -4321,17 +2204,17 @@ void QImage::setPixel(int x, int y, uint index_or_rgb) case Format_RGB32: //make sure alpha is 255, we depend on it in qdrawhelper for cases // when image is set as a texture pattern on a qbrush - ((uint *)s)[x] = uint(255 << 24) | index_or_rgb; + ((uint *)s)[x] = 0xff000000 | index_or_rgb; return; case Format_ARGB32: case Format_ARGB32_Premultiplied: ((uint *)s)[x] = index_or_rgb; return; case Format_RGB16: - ((quint16 *)s)[x] = qConvertRgb32To16(INV_PREMUL(index_or_rgb)); + ((quint16 *)s)[x] = qConvertRgb32To16(qUnpremultiply(index_or_rgb)); return; case Format_RGBX8888: - ((uint *)s)[x] = ARGB2RGBA(index_or_rgb | 0xff000000); + ((uint *)s)[x] = ARGB2RGBA(0xff000000 | index_or_rgb); return; case Format_RGBA8888: case Format_RGBA8888_Premultiplied: @@ -4810,6 +2693,7 @@ QImage QImage::createMaskFromColor(QRgb color, Qt::MaskMode mode) const */ /*! + \fn QImage QImage::mirrored(bool horizontal = false, bool vertical = true) const Returns a mirror of the image, mirrored in the horizontal and/or the vertical direction depending on whether \a horizontal and \a vertical are set to true or false. @@ -4818,7 +2702,70 @@ QImage QImage::createMaskFromColor(QRgb color, Qt::MaskMode mode) const \sa {QImage#Image Transformations}{Image Transformations} */ -QImage QImage::mirrored(bool horizontal, bool vertical) const + +template<typename T> +inline void mirrored_helper_loop(int w, int h, int dxi, int dxs, int dyi, int dy, const uchar* sdata, uchar* ddata, int sbpl, int dbpl) +{ + for (int sy = 0; sy < h; sy++, dy += dyi) { + const T* ssl = (T*)(sdata + sy*sbpl); + T* dsl = (T*)(ddata + dy*dbpl); + int dx = dxs; + for (int sx = 0; sx < w; sx++, dx += dxi) + dsl[dx] = ssl[sx]; + } +} + +template<typename T> +inline void mirrored_helper_loop_inplace(int w, int h, int dxi, int dxs, int dyi, int dy, uchar* sdata, int sbpl) +{ + for (int sy = 0; sy < h; sy++, dy += dyi) { + T* ssl = (T*)(sdata + sy*sbpl); + T* dsl = (T*)(sdata + dy*sbpl); + int dx = dxs; + for (int sx = 0; sx < w; sx++, dx += dxi) + std::swap(dsl[dx], ssl[sx]); + } +} + +inline void mirror_horizonal_bitmap(int w, int h, int dxs, uchar* data, int bpl, bool monolsb) +{ + int shift = w % 8; + const uchar* bitflip = qt_get_bitflip_array(); + for (int y = h-1; y >= 0; y--) { + quint8* a0 = (quint8*)(data + y*bpl); + // Swap bytes + quint8* a = a0+dxs; + while (a >= a0) { + *a = bitflip[*a]; + a--; + } + // Shift bits if unaligned + if (shift != 0) { + a = a0+dxs; + quint8 c = 0; + if (monolsb) { + while (a >= a0) { + quint8 nc = *a << shift; + *a = (*a >> (8-shift)) | c; + --a; + c = nc; + } + } else { + while (a >= a0) { + quint8 nc = *a >> shift; + *a = (*a << (8-shift)) | c; + --a; + c = nc; + } + } + } + } +} + +/*! + \internal +*/ +QImage QImage::mirrored_helper(bool horizontal, bool vertical) const { if (!d) return QImage(); @@ -4840,92 +2787,80 @@ QImage QImage::mirrored(bool horizontal, bool vertical) const result.d->has_alpha_clut = d->has_alpha_clut; result.d->devicePixelRatio = d->devicePixelRatio; - if (depth() == 1) + if (d->depth == 1) w = (w+7)/8; int dxi = horizontal ? -1 : 1; int dxs = horizontal ? w-1 : 0; int dyi = vertical ? -1 : 1; - int dy = vertical ? h-1: 0; + int dys = vertical ? h-1 : 0; // 1 bit, 8 bit - if (d->depth == 1 || d->depth == 8) { - for (int sy = 0; sy < h; sy++, dy += dyi) { - quint8* ssl = (quint8*)(d->data + sy*d->bytes_per_line); - quint8* dsl = (quint8*)(result.d->data + dy*result.d->bytes_per_line); - int dx = dxs; - for (int sx = 0; sx < w; sx++, dx += dxi) - dsl[dx] = ssl[sx]; - } - } + if (d->depth == 1 || d->depth == 8) + mirrored_helper_loop<quint8>(w, h, dxi, dxs, dyi, dys, d->data, result.d->data, d->bytes_per_line, result.d->bytes_per_line); // 16 bit - else if (d->depth == 16) { - for (int sy = 0; sy < h; sy++, dy += dyi) { - quint16* ssl = (quint16*)(d->data + sy*d->bytes_per_line); - quint16* dsl = (quint16*)(result.d->data + dy*result.d->bytes_per_line); - int dx = dxs; - for (int sx = 0; sx < w; sx++, dx += dxi) - dsl[dx] = ssl[sx]; - } - } + else if (d->depth == 16) + mirrored_helper_loop<quint16>(w, h, dxi, dxs, dyi, dys, d->data, result.d->data, d->bytes_per_line, result.d->bytes_per_line); // 24 bit - else if (d->depth == 24) { - for (int sy = 0; sy < h; sy++, dy += dyi) { - quint24* ssl = (quint24*)(d->data + sy*d->bytes_per_line); - quint24* dsl = (quint24*)(result.d->data + dy*result.d->bytes_per_line); - int dx = dxs; - for (int sx = 0; sx < w; sx++, dx += dxi) - dsl[dx] = ssl[sx]; - } - } + else if (d->depth == 24) + mirrored_helper_loop<quint24>(w, h, dxi, dxs, dyi, dys, d->data, result.d->data, d->bytes_per_line, result.d->bytes_per_line); // 32 bit - else if (d->depth == 32) { - for (int sy = 0; sy < h; sy++, dy += dyi) { - quint32* ssl = (quint32*)(d->data + sy*d->bytes_per_line); - quint32* dsl = (quint32*)(result.d->data + dy*result.d->bytes_per_line); - int dx = dxs; - for (int sx = 0; sx < w; sx++, dx += dxi) - dsl[dx] = ssl[sx]; - } - } + else if (d->depth == 32) + mirrored_helper_loop<quint32>(w, h, dxi, dxs, dyi, dys, d->data, result.d->data, d->bytes_per_line, result.d->bytes_per_line); // special handling of 1 bit images for horizontal mirroring - if (horizontal && d->depth == 1) { - int shift = width() % 8; - for (int y = h-1; y >= 0; y--) { - quint8* a0 = (quint8*)(result.d->data + y*d->bytes_per_line); - // Swap bytes - quint8* a = a0+dxs; - while (a >= a0) { - *a = bitflip[*a]; - a--; - } - // Shift bits if unaligned - if (shift != 0) { - a = a0+dxs; - quint8 c = 0; - if (format() == Format_MonoLSB) { - while (a >= a0) { - quint8 nc = *a << shift; - *a = (*a >> (8-shift)) | c; - --a; - c = nc; - } - } else { - while (a >= a0) { - quint8 nc = *a >> shift; - *a = (*a << (8-shift)) | c; - --a; - c = nc; - } - } - } - } - } - + if (horizontal && d->depth == 1) + mirror_horizonal_bitmap(d->width, d->height, dxs, result.d->data, result.d->bytes_per_line, d->format == Format_MonoLSB); return result; } /*! + \internal +*/ +void QImage::mirrored_inplace(bool horizontal, bool vertical) +{ + if (!d) + return; + + if ((d->width <= 1 && d->height <= 1) || (!horizontal && !vertical)) + return; + + detach(); + + int w = d->width; + int h = d->height; + + if (d->depth == 1) + w = (w+7)/8; + int dxi = horizontal ? -1 : 1; + int dxs = horizontal ? w-1 : 0; + int dyi = vertical ? -1 : 1; + int dys = vertical ? h-1 : 0; + + if (vertical) + h = h/2; + else if (horizontal) + w = w/2; + + // 1 bit, 8 bit + if (d->depth == 1 || d->depth == 8) + mirrored_helper_loop_inplace<quint8>(w, h, dxi, dxs, dyi, dys, d->data, d->bytes_per_line); + // 16 bit + else if (d->depth == 16) + mirrored_helper_loop_inplace<quint16>(w, h, dxi, dxs, dyi, dys, d->data, d->bytes_per_line); + // 24 bit + else if (d->depth == 24) + mirrored_helper_loop_inplace<quint24>(w, h, dxi, dxs, dyi, dys, d->data, d->bytes_per_line); + // 32 bit + else if (d->depth == 32) + mirrored_helper_loop_inplace<quint32>(w, h, dxi, dxs, dyi, dys, d->data, d->bytes_per_line); + + // special handling of 1 bit images for horizontal mirroring + if (horizontal && d->depth == 1) + mirror_horizonal_bitmap(d->width, d->height, dxs, d->data, d->bytes_per_line, d->format == Format_MonoLSB); +} + +/*! + \fn QImage QImage::rgbSwapped() const Returns a QImage in which the values of the red and blue components of all pixels have been swapped, effectively converting an RGB image to an BGR image. @@ -4934,16 +2869,54 @@ QImage QImage::mirrored(bool horizontal, bool vertical) const \sa {QImage#Image Transformations}{Image Transformations} */ -QImage QImage::rgbSwapped() const + +inline void rgbSwapped_generic(int width, int height, const QImage *src, QImage *dst, const QPixelLayout* layout) +{ + Q_ASSERT(layout->redWidth == layout->blueWidth); + FetchPixelsFunc fetch = qFetchPixels[layout->bpp]; + StorePixelsFunc store = qStorePixels[layout->bpp]; + + const uint redBlueMask = (1 << layout->redWidth) - 1; + const uint alphaGreenMask = (((1 << layout->alphaWidth) - 1) << layout->alphaShift) + | (((1 << layout->greenWidth) - 1) << layout->greenShift); + + const int buffer_size = 2048; + uint buffer[buffer_size]; + for (int i = 0; i < height; ++i) { + uchar *q = dst->scanLine(i); + const uchar *p = src->constScanLine(i); + int x = 0; + while (x < width) { + int l = qMin(width - x, buffer_size); + const uint *ptr = fetch(buffer, p, x, l); + for (int j = 0; j < l; ++j) { + uint red = (ptr[j] >> layout->redShift) & redBlueMask; + uint blue = (ptr[j] >> layout->blueShift) & redBlueMask; + buffer[j] = (ptr[j] & alphaGreenMask) + | (red << layout->blueShift) + | (blue << layout->redShift); + } + store(q, buffer, x, l); + x += l; + } + } +} + +/*! + \internal +*/ +QImage QImage::rgbSwapped_helper() const { if (isNull()) return *this; + QImage res; + switch (d->format) { case Format_Invalid: case NImageFormats: Q_ASSERT(false); - return res; + break; case Format_Mono: case Format_MonoLSB: case Format_Indexed8: @@ -4952,7 +2925,7 @@ QImage QImage::rgbSwapped() const QRgb c = res.d->colortable.at(i); res.d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00)); } - return res; + break; case Format_RGB32: case Format_ARGB32: case Format_ARGB32_Premultiplied: @@ -4965,15 +2938,16 @@ QImage QImage::rgbSwapped() const QIMAGE_SANITYCHECK_MEMORY(res); for (int i = 0; i < d->height; i++) { uint *q = (uint*)res.scanLine(i); - uint *p = (uint*)constScanLine(i); - uint *end = p + d->width; + const uint *p = (const uint*)constScanLine(i); + const uint *end = p + d->width; while (p < end) { - *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00); + uint c = *p; + *q = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00); p++; q++; } } - return res; + break; case Format_RGB16: res = QImage(d->width, d->height, d->format); QIMAGE_SANITYCHECK_MEMORY(res); @@ -4982,48 +2956,77 @@ QImage QImage::rgbSwapped() const const ushort *p = (const ushort*)constScanLine(i); const ushort *end = p + d->width; while (p < end) { - *q = ((*p << 11) & 0xf800) | ((*p >> 11) & 0x1f) | (*p & 0x07e0); + ushort c = *p; + *q = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0); p++; q++; } } - return res; + break; default: + res = QImage(d->width, d->height, d->format); + rgbSwapped_generic(d->width, d->height, this, &res, &qPixelLayouts[d->format]); break; } + return res; +} - res = QImage(d->width, d->height, d->format); - QIMAGE_SANITYCHECK_MEMORY(res); - const QPixelLayout *layout = &qPixelLayouts[d->format]; - Q_ASSERT(layout->redWidth == layout->blueWidth); - FetchPixelsFunc fetch = qFetchPixels[layout->bpp]; - StorePixelsFunc store = qStorePixels[layout->bpp]; +/*! + \internal +*/ +void QImage::rgbSwapped_inplace() +{ + if (isNull()) + return; - const uint redBlueMask = (1 << layout->redWidth) - 1; - const uint alphaGreenMask = (((1 << layout->alphaWidth) - 1) << layout->alphaShift) - | (((1 << layout->greenWidth) - 1) << layout->greenShift); + detach(); - const int buffer_size = 2048; - uint buffer[buffer_size]; - for (int i = 0; i < d->height; ++i) { - uchar *q = res.scanLine(i); - const uchar *p = constScanLine(i); - int x = 0; - while (x < d->width) { - int l = qMin(d->width - x, buffer_size); - const uint *ptr = fetch(buffer, p, x, l); - for (int j = 0; j < l; ++j) { - uint red = (ptr[j] >> layout->redShift) & redBlueMask; - uint blue = (ptr[j] >> layout->blueShift) & redBlueMask; - buffer[j] = (ptr[j] & alphaGreenMask) - | (red << layout->blueShift) - | (blue << layout->redShift); + switch (d->format) { + case Format_Invalid: + case NImageFormats: + Q_ASSERT(false); + break; + case Format_Mono: + case Format_MonoLSB: + case Format_Indexed8: + for (int i = 0; i < d->colortable.size(); i++) { + QRgb c = d->colortable.at(i); + d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00)); + } + break; + case Format_RGB32: + case Format_ARGB32: + case Format_ARGB32_Premultiplied: +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + case Format_RGBX8888: + case Format_RGBA8888: + case Format_RGBA8888_Premultiplied: +#endif + for (int i = 0; i < d->height; i++) { + uint *p = (uint*)scanLine(i); + uint *end = p + d->width; + while (p < end) { + uint c = *p; + *p = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00); + p++; } - store(q, buffer, x, l); - x += l; } + break; + case Format_RGB16: + for (int i = 0; i < d->height; i++) { + ushort *p = (ushort*)scanLine(i); + ushort *end = p + d->width; + while (p < end) { + ushort c = *p; + *p = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0); + p++; + } + } + break; + default: + rgbSwapped_generic(d->width, d->height, this, this, &qPixelLayouts[d->format]); + break; } - return res; } /*! @@ -6433,10 +4436,12 @@ bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFla if (ref.load() > 1) return false; - const InPlace_Image_Converter *const converterPtr = &inplace_converter_map[format][newFormat]; + const InPlace_Image_Converter *const converterPtr = &qimage_inplace_converter_map[format][newFormat]; InPlace_Image_Converter converter = *converterPtr; if (converter) return converter(this, flags); + else if (format > QImage::Format_Indexed8 && newFormat > QImage::Format_Indexed8) + return convert_generic_inplace(this, newFormat, flags); else return false; } diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index bc7f3729ad..4326d5dbbc 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -172,7 +172,19 @@ public: Format format() const; +#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QIMAGE_COMPAT_CPP) + QImage convertToFormat(Format f, Qt::ImageConversionFlags flags = Qt::AutoColor) const & Q_REQUIRED_RESULT + { return convertToFormat_helper(f, flags); } + QImage convertToFormat(Format f, Qt::ImageConversionFlags flags = Qt::AutoColor) && Q_REQUIRED_RESULT + { + if (convertToFormat_inplace(f, flags)) + return std::move(*this); + else + return convertToFormat_helper(f, flags); + } +#else QImage convertToFormat(Format f, Qt::ImageConversionFlags flags = Qt::AutoColor) const Q_REQUIRED_RESULT; +#endif QImage convertToFormat(Format f, const QVector<QRgb> &colorTable, Qt::ImageConversionFlags flags = Qt::AutoColor) const Q_REQUIRED_RESULT; int width() const; @@ -245,8 +257,19 @@ public: static QMatrix trueMatrix(const QMatrix &, int w, int h); QImage transformed(const QTransform &matrix, Qt::TransformationMode mode = Qt::FastTransformation) const; static QTransform trueMatrix(const QTransform &, int w, int h); +#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QIMAGE_COMPAT_CPP) + QImage mirrored(bool horizontally = false, bool vertically = true) const & + { return mirrored_helper(horizontally, vertically); } + QImage &&mirrored(bool horizontally = false, bool vertically = true) && + { mirrored_inplace(horizontally, vertically); return qMove(*this); } + QImage rgbSwapped() const & + { return rgbSwapped_helper(); } + QImage &&rgbSwapped() && + { rgbSwapped_inplace(); return qMove(*this); } +#else QImage mirrored(bool horizontally = false, bool vertically = true) const; QImage rgbSwapped() const; +#endif void invertPixels(InvertMode = InvertRgb); @@ -298,6 +321,12 @@ public: protected: virtual int metric(PaintDeviceMetric metric) const; + QImage mirrored_helper(bool horizontal, bool vertical) const; + QImage rgbSwapped_helper() const; + void mirrored_inplace(bool horizontal, bool vertical); + void rgbSwapped_inplace(); + QImage convertToFormat_helper(Format format, Qt::ImageConversionFlags flags) const; + bool convertToFormat_inplace(Format format, Qt::ImageConversionFlags flags); private: friend class QWSOnScreenSurface; diff --git a/src/gui/painting/qdrawhelper_avx.cpp b/src/gui/image/qimage_compat.cpp index 7da6ce6a20..9acf5c18fa 100644 --- a/src/gui/painting/qdrawhelper_avx.cpp +++ b/src/gui/image/qimage_compat.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2012 Intel Corporation +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtGui module of the Qt Toolkit. @@ -39,32 +39,30 @@ ** ****************************************************************************/ -#include <private/qsimd_p.h> +#ifdef QIMAGE_H +# error "This file cannot be used with precompiled headers" +#endif +#define QT_COMPILING_QIMAGE_COMPAT_CPP -#ifdef QT_COMPILER_SUPPORTS_AVX -#define QDRAWHELPER_AVX +#include "qimage.h" -#ifndef __AVX__ -#error "AVX not enabled in this file, cannot proceed" -#endif +QT_BEGIN_NAMESPACE -#define qt_blend_argb32_on_argb32_ssse3 qt_blend_argb32_on_argb32_avx -#include "qdrawhelper_ssse3.cpp" +// These implementations must be the same as the inline versions in qimage.h -//#define qt_blend_argb32_on_argb32_sse2 qt_blend_argb32_on_argb32_avx -#define qt_blend_rgb32_on_rgb32_sse2 qt_blend_rgb32_on_rgb32_avx -#define comp_func_SourceOver_sse2 comp_func_SourceOver_avx -#define comp_func_Plus_sse2 comp_func_Plus_avx -#define comp_func_Source_sse2 comp_func_Source_avx -#define comp_func_solid_SourceOver_sse2 comp_func_solid_SourceOver_avx -#define qt_memfill32_sse2 qt_memfill32_avx -#define qt_memfill16_sse2 qt_memfill16_avx -#define qt_bitmapblit32_sse2 qt_bitmapblit32_avx -#define qt_bitmapblit16_sse2 qt_bitmapblit16_avx -#define QSimdSse2 QSimdAvx -#define qt_fetch_radial_gradient_sse2 qt_fetch_radial_gradient_avx -#define qt_scale_image_argb32_on_argb32_sse2 qt_scale_image_argb32_on_argb32_avx +QImage QImage::convertToFormat(Format f, Qt::ImageConversionFlags flags) const +{ + return convertToFormat_helper(f, flags); +} -#include "qdrawhelper_sse2.cpp" +QImage QImage::mirrored(bool horizontally, bool vertically) const +{ + return mirrored_helper(horizontally, vertically); +} -#endif +QImage QImage::rgbSwapped() const +{ + return rgbSwapped_helper(); +} + +QT_END_NAMESPACE diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp new file mode 100644 index 0000000000..629a7c9b69 --- /dev/null +++ b/src/gui/image/qimage_conversions.cpp @@ -0,0 +1,2183 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <private/qdrawhelper_p.h> +#include <private/qguiapplication_p.h> +#include <private/qsimd_p.h> + +#include <private/qimage_p.h> + +QT_BEGIN_NAMESPACE + +// table to flip bits +static const uchar bitflip[256] = { + /* + open OUT, "| fmt"; + for $i (0..255) { + print OUT (($i >> 7) & 0x01) | (($i >> 5) & 0x02) | + (($i >> 3) & 0x04) | (($i >> 1) & 0x08) | + (($i << 7) & 0x80) | (($i << 5) & 0x40) | + (($i << 3) & 0x20) | (($i << 1) & 0x10), ", "; + } + close OUT; + */ + 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, + 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, + 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, + 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, + 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, + 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, + 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, + 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, + 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, + 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, + 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, + 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, + 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, + 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, + 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, + 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 +}; + +const uchar *qt_get_bitflip_array() +{ + return bitflip; +} + +void qGamma_correct_back_to_linear_cs(QImage *image) +{ + const QDrawHelperGammaTables *tables = QGuiApplicationPrivate::instance()->gammaTables(); + if (!tables) + return; + const uchar *gamma = tables->qt_pow_rgb_gamma; + // gamma correct the pixels back to linear color space... + int h = image->height(); + int w = image->width(); + + for (int y=0; y<h; ++y) { + uint *pixels = (uint *) image->scanLine(y); + for (int x=0; x<w; ++x) { + uint p = pixels[x]; + uint r = gamma[qRed(p)]; + uint g = gamma[qGreen(p)]; + uint b = gamma[qBlue(p)]; + pixels[x] = (r << 16) | (g << 8) | b | 0xff000000; + } + } +} + +/***************************************************************************** + Internal routines for converting image depth. + *****************************************************************************/ + +// Cannot be used with indexed formats. +void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(dest->format > QImage::Format_Indexed8); + Q_ASSERT(src->format > QImage::Format_Indexed8); + const int buffer_size = 2048; + uint buffer[buffer_size]; + const QPixelLayout *srcLayout = &qPixelLayouts[src->format]; + const QPixelLayout *destLayout = &qPixelLayouts[dest->format]; + const uchar *srcData = src->data; + uchar *destData = dest->data; + + FetchPixelsFunc fetch = qFetchPixels[srcLayout->bpp]; + StorePixelsFunc store = qStorePixels[destLayout->bpp]; + + for (int y = 0; y < src->height; ++y) { + int x = 0; + while (x < src->width) { + int l = qMin(src->width - x, buffer_size); + const uint *ptr = fetch(buffer, srcData, x, l); + ptr = srcLayout->convertToARGB32PM(buffer, ptr, l, srcLayout, 0); + ptr = destLayout->convertFromARGB32PM(buffer, ptr, l, destLayout, 0); + store(destData, ptr, x, l); + x += l; + } + srcData += src->bytes_per_line; + destData += dest->bytes_per_line; + } +} + +// Cannot be used with indexed formats or between formats with different pixel depths. +bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags) +{ + Q_ASSERT(dst_format > QImage::Format_Indexed8); + Q_ASSERT(data->format > QImage::Format_Indexed8); + if (data->depth != qt_depthForFormat(dst_format)) + return false; + + const int buffer_size = 2048; + uint buffer[buffer_size]; + const QPixelLayout *srcLayout = &qPixelLayouts[data->format]; + const QPixelLayout *destLayout = &qPixelLayouts[dst_format]; + + uchar *srcData = data->data; + + FetchPixelsFunc fetch = qFetchPixels[srcLayout->bpp]; + StorePixelsFunc store = qStorePixels[destLayout->bpp]; + + for (int y = 0; y < data->height; ++y) { + int x = 0; + while (x < data->width) { + int l = qMin(data->width - x, buffer_size); + const uint *ptr = fetch(buffer, srcData, x, l); + ptr = srcLayout->convertToARGB32PM(buffer, ptr, l, srcLayout, 0); + ptr = destLayout->convertFromARGB32PM(buffer, ptr, l, destLayout, 0); + store(srcData, ptr, x, l); + x += l; + } + srcData += data->bytes_per_line; + } + data->format = dst_format; + return true; +} + +static void convert_ARGB_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_ARGB32 || src->format == QImage::Format_RGBA8888); + Q_ASSERT(dest->format == QImage::Format_ARGB32_Premultiplied || dest->format == QImage::Format_RGBA8888_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const QRgb *src_data = (QRgb *) src->data; + QRgb *dest_data = (QRgb *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const QRgb *end = src_data + src->width; + while (src_data < end) { + *dest_data = qPremultiply(*src_data); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +extern bool convert_ARGB_to_ARGB_PM_inplace_sse2(QImageData *data, Qt::ImageConversionFlags); + +#ifndef __SSE2__ +static bool convert_ARGB_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_ARGB32); + + const int pad = (data->bytes_per_line >> 2) - data->width; + QRgb *rgb_data = (QRgb *) data->data; + + for (int i = 0; i < data->height; ++i) { + const QRgb *end = rgb_data + data->width; + while (rgb_data < end) { + *rgb_data = PREMUL(*rgb_data); + ++rgb_data; + } + rgb_data += pad; + } + data->format = QImage::Format_ARGB32_Premultiplied; + return true; +} +#endif + +static void convert_ARGB_to_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_ARGB32); + Q_ASSERT(dest->format == QImage::Format_RGBX8888); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = ARGB2RGBA(0xff000000 | *src_data); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void convert_ARGB_to_RGBA(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_ARGB32 || src->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_RGBA8888 || dest->format == QImage::Format_RGBA8888_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = ARGB2RGBA(*src_data); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static bool convert_ARGB_to_RGBA_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_ARGB32 || data->format == QImage::Format_ARGB32_Premultiplied); + + const int pad = (data->bytes_per_line >> 2) - data->width; + quint32 *rgb_data = (quint32 *) data->data; + + for (int i = 0; i < data->height; ++i) { + const quint32 *end = rgb_data + data->width; + while (rgb_data < end) { + *rgb_data = ARGB2RGBA(*rgb_data); + ++rgb_data; + } + rgb_data += pad; + } + if (data->format == QImage::Format_ARGB32) + data->format = QImage::Format_RGBA8888; + else + data->format = QImage::Format_RGBA8888_Premultiplied; + return true; +} + +static void convert_ARGB_to_RGBA_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_ARGB32); + Q_ASSERT(dest->format == QImage::Format_RGBA8888_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = ARGB2RGBA(qPremultiply(*src_data)); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void convert_RGBA_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_RGBX8888 || src->format == QImage::Format_RGBA8888 || src->format == QImage::Format_RGBA8888_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = RGBA2ARGB(*src_data); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static bool convert_RGBA_to_ARGB_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_RGBX8888 || data->format == QImage::Format_RGBA8888 || data->format == QImage::Format_RGBA8888_Premultiplied); + + const int pad = (data->bytes_per_line >> 2) - data->width; + QRgb *rgb_data = (QRgb *) data->data; + + for (int i = 0; i < data->height; ++i) { + const QRgb *end = rgb_data + data->width; + while (rgb_data < end) { + *rgb_data = RGBA2ARGB(*rgb_data); + ++rgb_data; + } + rgb_data += pad; + } + if (data->format == QImage::Format_RGBA8888_Premultiplied) + data->format = QImage::Format_ARGB32_Premultiplied; + else if (data->format == QImage::Format_RGBX8888) + data->format = QImage::Format_RGB32; + else + data->format = QImage::Format_ARGB32; + return true; +} + +static void convert_RGBA_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_RGBA8888); + Q_ASSERT(dest->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = qPremultiply(RGBA2ARGB(*src_data)); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static bool convert_RGBA_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_RGBA8888); + + const int pad = (data->bytes_per_line >> 2) - data->width; + QRgb *rgb_data = (QRgb *) data->data; + + for (int i = 0; i < data->height; ++i) { + const QRgb *end = rgb_data + data->width; + while (rgb_data < end) { + *rgb_data = qPremultiply(RGBA2ARGB(*rgb_data)); + ++rgb_data; + } + rgb_data += pad; + } + data->format = QImage::Format_ARGB32_Premultiplied; + return true; +} + +static bool convert_indexed8_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Indexed8); + const int depth = 32; + + const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; + const int nbytes = dst_bytes_per_line * data->height; + uchar *const newData = (uchar *)realloc(data->data, nbytes); + if (!newData) + return false; + + data->data = newData; + + // start converting from the end because the end image is bigger than the source + uchar *src_data = newData + data->nbytes; // end of src + quint32 *dest_data = (quint32 *) (newData + nbytes); // end of dest > end of src + const int width = data->width; + const int src_pad = data->bytes_per_line - width; + const int dest_pad = (dst_bytes_per_line >> 2) - width; + if (data->colortable.size() == 0) { + data->colortable.resize(256); + for (int i = 0; i < 256; ++i) + data->colortable[i] = qRgb(i, i, i); + } else { + for (int i = 0; i < data->colortable.size(); ++i) + data->colortable[i] = qPremultiply(data->colortable.at(i)); + + // Fill the rest of the table in case src_data > colortable.size() + const int oldSize = data->colortable.size(); + const QRgb lastColor = data->colortable.at(oldSize - 1); + data->colortable.insert(oldSize, 256 - oldSize, lastColor); + } + + for (int i = 0; i < data->height; ++i) { + src_data -= src_pad; + dest_data -= dest_pad; + for (int pixI = 0; pixI < width; ++pixI) { + --src_data; + --dest_data; + *dest_data = data->colortable.at(*src_data); + } + } + + data->colortable = QVector<QRgb>(); + data->format = QImage::Format_ARGB32_Premultiplied; + data->bytes_per_line = dst_bytes_per_line; + data->depth = depth; + data->nbytes = nbytes; + + return true; +} + +static bool convert_indexed8_to_RGB_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Indexed8); + const int depth = 32; + + const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; + const int nbytes = dst_bytes_per_line * data->height; + uchar *const newData = (uchar *)realloc(data->data, nbytes); + if (!newData) + return false; + + data->data = newData; + + // start converting from the end because the end image is bigger than the source + uchar *src_data = newData + data->nbytes; + quint32 *dest_data = (quint32 *) (newData + nbytes); + const int width = data->width; + const int src_pad = data->bytes_per_line - width; + const int dest_pad = (dst_bytes_per_line >> 2) - width; + if (data->colortable.size() == 0) { + data->colortable.resize(256); + for (int i = 0; i < 256; ++i) + data->colortable[i] = qRgb(i, i, i); + } else { + // Fill the rest of the table in case src_data > colortable.size() + const int oldSize = data->colortable.size(); + const QRgb lastColor = data->colortable.at(oldSize - 1); + data->colortable.insert(oldSize, 256 - oldSize, lastColor); + } + + for (int i = 0; i < data->height; ++i) { + src_data -= src_pad; + dest_data -= dest_pad; + for (int pixI = 0; pixI < width; ++pixI) { + --src_data; + --dest_data; + *dest_data = (quint32) data->colortable.at(*src_data); + } + } + + data->colortable = QVector<QRgb>(); + data->format = QImage::Format_RGB32; + data->bytes_per_line = dst_bytes_per_line; + data->depth = depth; + data->nbytes = nbytes; + + return true; +} + +static bool convert_indexed8_to_RGB16_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Indexed8); + const int depth = 16; + + const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; + const int nbytes = dst_bytes_per_line * data->height; + uchar *const newData = (uchar *)realloc(data->data, nbytes); + if (!newData) + return false; + + data->data = newData; + + // start converting from the end because the end image is bigger than the source + uchar *src_data = newData + data->nbytes; + quint16 *dest_data = (quint16 *) (newData + nbytes); + const int width = data->width; + const int src_pad = data->bytes_per_line - width; + const int dest_pad = (dst_bytes_per_line >> 1) - width; + + quint16 colorTableRGB16[256]; + if (data->colortable.isEmpty()) { + for (int i = 0; i < 256; ++i) + colorTableRGB16[i] = qConvertRgb32To16(qRgb(i, i, i)); + } else { + // 1) convert the existing colors to RGB16 + const int tableSize = data->colortable.size(); + for (int i = 0; i < tableSize; ++i) + colorTableRGB16[i] = qConvertRgb32To16(data->colortable.at(i)); + data->colortable = QVector<QRgb>(); + + // 2) fill the rest of the table in case src_data > colortable.size() + const quint16 lastColor = colorTableRGB16[tableSize - 1]; + for (int i = tableSize; i < 256; ++i) + colorTableRGB16[i] = lastColor; + } + + for (int i = 0; i < data->height; ++i) { + src_data -= src_pad; + dest_data -= dest_pad; + for (int pixI = 0; pixI < width; ++pixI) { + --src_data; + --dest_data; + *dest_data = colorTableRGB16[*src_data]; + } + } + + data->format = QImage::Format_RGB16; + data->bytes_per_line = dst_bytes_per_line; + data->depth = depth; + data->nbytes = nbytes; + + return true; +} + +static bool convert_RGB_to_RGB16_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_RGB32); + const int depth = 16; + + const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; + const int src_bytes_per_line = data->bytes_per_line; + quint32 *src_data = (quint32 *) data->data; + quint16 *dst_data = (quint16 *) data->data; + + for (int i = 0; i < data->height; ++i) { + for (int j = 0; j < data->width; ++j) + dst_data[j] = qConvertRgb32To16(src_data[j]); + src_data = (quint32 *) (((char*)src_data) + src_bytes_per_line); + dst_data = (quint16 *) (((char*)dst_data) + dst_bytes_per_line); + } + data->format = QImage::Format_RGB16; + data->bytes_per_line = dst_bytes_per_line; + data->depth = depth; + data->nbytes = dst_bytes_per_line * data->height; + uchar *const newData = (uchar *)realloc(data->data, data->nbytes); + if (newData) { + data->data = newData; + return true; + } else { + return false; + } +} + +static void convert_ARGB_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied || src->format == QImage::Format_RGBA8888_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_RGBA8888); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const QRgb *src_data = (QRgb *) src->data; + QRgb *dest_data = (QRgb *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const QRgb *end = src_data + src->width; + while (src_data < end) { + *dest_data = qUnpremultiply(*src_data); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void convert_ARGB_PM_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied || src->format == QImage::Format_RGBA8888_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_RGB32 || dest->format == QImage::Format_RGBX8888); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const QRgb *src_data = (QRgb *) src->data; + QRgb *dest_data = (QRgb *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const QRgb *end = src_data + src->width; + while (src_data < end) { + *dest_data = 0xff000000 | qUnpremultiply(*src_data); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void convert_ARGB_PM_to_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_RGBX8888); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const QRgb *src_data = (QRgb *) src->data; + QRgb *dest_data = (QRgb *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const QRgb *end = src_data + src->width; + while (src_data < end) { + *dest_data = ARGB2RGBA(0xff000000 | qUnpremultiply(*src_data)); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void convert_ARGB_PM_to_RGBA(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_RGBA8888); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const QRgb *src_data = (QRgb *) src->data; + QRgb *dest_data = (QRgb *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const QRgb *end = src_data + src->width; + while (src_data < end) { + *dest_data = ARGB2RGBA(qUnpremultiply(*src_data)); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void convert_RGBA_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_RGBA8888 || src->format == QImage::Format_RGBX8888); + Q_ASSERT(dest->format == QImage::Format_RGB32); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const uint *src_data = (const uint *)src->data; + uint *dest_data = (uint *)dest->data; + + for (int i = 0; i < src->height; ++i) { + const uint *end = src_data + src->width; + while (src_data < end) { + *dest_data = RGBA2ARGB(*src_data) | 0xff000000; + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void convert_RGB_to_RGBA(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_RGB32); + Q_ASSERT(dest->format == QImage::Format_RGBX8888 || dest->format == QImage::Format_RGBA8888 || dest->format == QImage::Format_RGBA8888_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const uint *src_data = (const uint *)src->data; + uint *dest_data = (uint *)dest->data; + + for (int i = 0; i < src->height; ++i) { + const uint *end = src_data + src->width; + while (src_data < end) { + *dest_data = ARGB2RGBA(*src_data | 0xff000000); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void convert_RGBA_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_RGBA8888_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_ARGB32); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const QRgb *src_data = (QRgb *) src->data; + QRgb *dest_data = (QRgb *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const QRgb *end = src_data + src->width; + while (src_data < end) { + *dest_data = qUnpremultiply(RGBA2ARGB(*src_data)); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void convert_RGBA_PM_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_RGBA8888_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_RGB32); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const QRgb *src_data = (QRgb *) src->data; + QRgb *dest_data = (QRgb *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const QRgb *end = src_data + src->width; + while (src_data < end) { + *dest_data = 0xff000000 | qUnpremultiply(RGBA2ARGB(*src_data)); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void swap_bit_order(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_Mono || src->format == QImage::Format_MonoLSB); + Q_ASSERT(dest->format == QImage::Format_Mono || dest->format == QImage::Format_MonoLSB); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + Q_ASSERT(src->nbytes == dest->nbytes); + Q_ASSERT(src->bytes_per_line == dest->bytes_per_line); + + dest->colortable = src->colortable; + + const uchar *src_data = src->data; + const uchar *end = src->data + src->nbytes; + uchar *dest_data = dest->data; + while (src_data < end) { + *dest_data = bitflip[*src_data]; + ++src_data; + ++dest_data; + } +} + +static void mask_alpha_converter(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const uint *src_data = (const uint *)src->data; + uint *dest_data = (uint *)dest->data; + + for (int i = 0; i < src->height; ++i) { + const uint *end = src_data + src->width; + while (src_data < end) { + *dest_data = *src_data | 0xff000000; + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static void mask_alpha_converter_RGBx(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags flags) +{ +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + return mask_alpha_converter(dest, src, flags); +#else + Q_UNUSED(flags); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const uint *src_data = (const uint *)src->data; + uint *dest_data = (uint *)dest->data; + + for (int i = 0; i < src->height; ++i) { + const uint *end = src_data + src->width; + while (src_data < end) { + *dest_data = *src_data | 0x000000ff; + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +#endif +} + +static QVector<QRgb> fix_color_table(const QVector<QRgb> &ctbl, QImage::Format format) +{ + QVector<QRgb> colorTable = ctbl; + if (format == QImage::Format_RGB32) { + // check if the color table has alpha + for (int i = 0; i < colorTable.size(); ++i) + if (qAlpha(colorTable.at(i) != 0xff)) + colorTable[i] = colorTable.at(i) | 0xff000000; + } else if (format == QImage::Format_ARGB32_Premultiplied) { + // check if the color table has alpha + for (int i = 0; i < colorTable.size(); ++i) + colorTable[i] = qPremultiply(colorTable.at(i)); + } + return colorTable; +} + +// +// dither_to_1: Uses selected dithering algorithm. +// + +void dither_to_Mono(QImageData *dst, const QImageData *src, + Qt::ImageConversionFlags flags, bool fromalpha) +{ + Q_ASSERT(src->width == dst->width); + Q_ASSERT(src->height == dst->height); + Q_ASSERT(dst->format == QImage::Format_Mono || dst->format == QImage::Format_MonoLSB); + + dst->colortable.clear(); + dst->colortable.append(0xffffffff); + dst->colortable.append(0xff000000); + + enum { Threshold, Ordered, Diffuse } dithermode; + + if (fromalpha) { + if ((flags & Qt::AlphaDither_Mask) == Qt::DiffuseAlphaDither) + dithermode = Diffuse; + else if ((flags & Qt::AlphaDither_Mask) == Qt::OrderedAlphaDither) + dithermode = Ordered; + else + dithermode = Threshold; + } else { + if ((flags & Qt::Dither_Mask) == Qt::ThresholdDither) + dithermode = Threshold; + else if ((flags & Qt::Dither_Mask) == Qt::OrderedDither) + dithermode = Ordered; + else + dithermode = Diffuse; + } + + int w = src->width; + int h = src->height; + int d = src->depth; + uchar gray[256]; // gray map for 8 bit images + bool use_gray = (d == 8); + if (use_gray) { // make gray map + if (fromalpha) { + // Alpha 0x00 -> 0 pixels (white) + // Alpha 0xFF -> 1 pixels (black) + for (int i = 0; i < src->colortable.size(); i++) + gray[i] = (255 - (src->colortable.at(i) >> 24)); + } else { + // Pixel 0x00 -> 1 pixels (black) + // Pixel 0xFF -> 0 pixels (white) + for (int i = 0; i < src->colortable.size(); i++) + gray[i] = qGray(src->colortable.at(i)); + } + } + + uchar *dst_data = dst->data; + int dst_bpl = dst->bytes_per_line; + const uchar *src_data = src->data; + int src_bpl = src->bytes_per_line; + + switch (dithermode) { + case Diffuse: { + QScopedArrayPointer<int> lineBuffer(new int[w * 2]); + int *line1 = lineBuffer.data(); + int *line2 = lineBuffer.data() + w; + int bmwidth = (w+7)/8; + + int *b1, *b2; + int wbytes = w * (d/8); + const uchar *p = src->data; + const uchar *end = p + wbytes; + b2 = line2; + if (use_gray) { // 8 bit image + while (p < end) + *b2++ = gray[*p++]; + } else { // 32 bit image + if (fromalpha) { + while (p < end) { + *b2++ = 255 - (*(uint*)p >> 24); + p += 4; + } + } else { + while (p < end) { + *b2++ = qGray(*(uint*)p); + p += 4; + } + } + } + for (int y=0; y<h; y++) { // for each scan line... + int *tmp = line1; line1 = line2; line2 = tmp; + bool not_last_line = y < h - 1; + if (not_last_line) { // calc. grayvals for next line + p = src->data + (y+1)*src->bytes_per_line; + end = p + wbytes; + b2 = line2; + if (use_gray) { // 8 bit image + while (p < end) + *b2++ = gray[*p++]; + } else { // 24 bit image + if (fromalpha) { + while (p < end) { + *b2++ = 255 - (*(uint*)p >> 24); + p += 4; + } + } else { + while (p < end) { + *b2++ = qGray(*(uint*)p); + p += 4; + } + } + } + } + + int err; + uchar *p = dst->data + y*dst->bytes_per_line; + memset(p, 0, bmwidth); + b1 = line1; + b2 = line2; + int bit = 7; + for (int x=1; x<=w; x++) { + if (*b1 < 128) { // black pixel + err = *b1++; + *p |= 1 << bit; + } else { // white pixel + err = *b1++ - 255; + } + if (bit == 0) { + p++; + bit = 7; + } else { + bit--; + } + if (x < w) + *b1 += (err*7)>>4; // spread error to right pixel + if (not_last_line) { + b2[0] += (err*5)>>4; // pixel below + if (x > 1) + b2[-1] += (err*3)>>4; // pixel below left + if (x < w) + b2[1] += err>>4; // pixel below right + } + b2++; + } + } + } break; + case Ordered: { + + memset(dst->data, 0, dst->nbytes); + if (d == 32) { + for (int i=0; i<h; i++) { + const uint *p = (const uint *)src_data; + const uint *end = p + w; + uchar *m = dst_data; + int bit = 7; + int j = 0; + if (fromalpha) { + while (p < end) { + if ((*p++ >> 24) >= qt_bayer_matrix[j++&15][i&15]) + *m |= 1 << bit; + if (bit == 0) { + m++; + bit = 7; + } else { + bit--; + } + } + } else { + while (p < end) { + if ((uint)qGray(*p++) < qt_bayer_matrix[j++&15][i&15]) + *m |= 1 << bit; + if (bit == 0) { + m++; + bit = 7; + } else { + bit--; + } + } + } + dst_data += dst_bpl; + src_data += src_bpl; + } + } else + /* (d == 8) */ { + for (int i=0; i<h; i++) { + const uchar *p = src_data; + const uchar *end = p + w; + uchar *m = dst_data; + int bit = 7; + int j = 0; + while (p < end) { + if ((uint)gray[*p++] < qt_bayer_matrix[j++&15][i&15]) + *m |= 1 << bit; + if (bit == 0) { + m++; + bit = 7; + } else { + bit--; + } + } + dst_data += dst_bpl; + src_data += src_bpl; + } + } + } break; + default: { // Threshold: + memset(dst->data, 0, dst->nbytes); + if (d == 32) { + for (int i=0; i<h; i++) { + const uint *p = (const uint *)src_data; + const uint *end = p + w; + uchar *m = dst_data; + int bit = 7; + if (fromalpha) { + while (p < end) { + if ((*p++ >> 24) >= 128) + *m |= 1 << bit; // Set mask "on" + if (bit == 0) { + m++; + bit = 7; + } else { + bit--; + } + } + } else { + while (p < end) { + if (qGray(*p++) < 128) + *m |= 1 << bit; // Set pixel "black" + if (bit == 0) { + m++; + bit = 7; + } else { + bit--; + } + } + } + dst_data += dst_bpl; + src_data += src_bpl; + } + } else + if (d == 8) { + for (int i=0; i<h; i++) { + const uchar *p = src_data; + const uchar *end = p + w; + uchar *m = dst_data; + int bit = 7; + while (p < end) { + if (gray[*p++] < 128) + *m |= 1 << bit; // Set mask "on"/ pixel "black" + if (bit == 0) { + m++; + bit = 7; + } else { + bit--; + } + } + dst_data += dst_bpl; + src_data += src_bpl; + } + } + } + } + + if (dst->format == QImage::Format_MonoLSB) { + // need to swap bit order + uchar *sl = dst->data; + int bpl = (dst->width + 7) * dst->depth / 8; + int pad = dst->bytes_per_line - bpl; + for (int y=0; y<dst->height; ++y) { + for (int x=0; x<bpl; ++x) { + *sl = bitflip[*sl]; + ++sl; + } + sl += pad; + } + } +} + +static void convert_X_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags) +{ + dither_to_Mono(dst, src, flags, false); +} + +static void convert_ARGB_PM_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags) +{ + QScopedPointer<QImageData> tmp(QImageData::create(QSize(src->width, src->height), QImage::Format_ARGB32)); + convert_ARGB_PM_to_ARGB(tmp.data(), src, flags); + dither_to_Mono(dst, tmp.data(), flags, false); +} + +// +// convert_32_to_8: Converts a 32 bits depth (true color) to an 8 bit +// image with a colormap. If the 32 bit image has more than 256 colors, +// we convert the red,green and blue bytes into a single byte encoded +// as 6 shades of each of red, green and blue. +// +// if dithering is needed, only 1 color at most is available for alpha. +// +struct QRgbMap { + inline QRgbMap() : used(0) { } + uchar pix; + uchar used; + QRgb rgb; +}; + +static void convert_RGB_to_Indexed8(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags) +{ + Q_ASSERT(src->format == QImage::Format_RGB32 || src->format == QImage::Format_ARGB32); + Q_ASSERT(dst->format == QImage::Format_Indexed8); + Q_ASSERT(src->width == dst->width); + Q_ASSERT(src->height == dst->height); + + bool do_quant = (flags & Qt::DitherMode_Mask) == Qt::PreferDither + || src->format == QImage::Format_ARGB32; + uint alpha_mask = src->format == QImage::Format_RGB32 ? 0xff000000 : 0; + + const int tablesize = 997; // prime + QRgbMap table[tablesize]; + int pix=0; + + if (!dst->colortable.isEmpty()) { + QVector<QRgb> ctbl = dst->colortable; + dst->colortable.resize(256); + // Preload palette into table. + // Almost same code as pixel insertion below + for (int i = 0; i < dst->colortable.size(); ++i) { + // Find in table... + QRgb p = ctbl.at(i) | alpha_mask; + int hash = p % tablesize; + for (;;) { + if (table[hash].used) { + if (table[hash].rgb == p) { + // Found previous insertion - use it + break; + } else { + // Keep searching... + if (++hash == tablesize) hash = 0; + } + } else { + // Cannot be in table + Q_ASSERT (pix != 256); // too many colors + // Insert into table at this unused position + dst->colortable[pix] = p; + table[hash].pix = pix++; + table[hash].rgb = p; + table[hash].used = 1; + break; + } + } + } + } + + if ((flags & Qt::DitherMode_Mask) != Qt::PreferDither) { + dst->colortable.resize(256); + const uchar *src_data = src->data; + uchar *dest_data = dst->data; + for (int y = 0; y < src->height; y++) { // check if <= 256 colors + const QRgb *s = (const QRgb *)src_data; + uchar *b = dest_data; + for (int x = 0; x < src->width; ++x) { + QRgb p = s[x] | alpha_mask; + int hash = p % tablesize; + for (;;) { + if (table[hash].used) { + if (table[hash].rgb == (p)) { + // Found previous insertion - use it + break; + } else { + // Keep searching... + if (++hash == tablesize) hash = 0; + } + } else { + // Cannot be in table + if (pix == 256) { // too many colors + do_quant = true; + // Break right out + x = src->width; + y = src->height; + } else { + // Insert into table at this unused position + dst->colortable[pix] = p; + table[hash].pix = pix++; + table[hash].rgb = p; + table[hash].used = 1; + } + break; + } + } + *b++ = table[hash].pix; // May occur once incorrectly + } + src_data += src->bytes_per_line; + dest_data += dst->bytes_per_line; + } + } + int numColors = do_quant ? 256 : pix; + + dst->colortable.resize(numColors); + + if (do_quant) { // quantization needed + +#define MAX_R 5 +#define MAX_G 5 +#define MAX_B 5 +#define INDEXOF(r,g,b) (((r)*(MAX_G+1)+(g))*(MAX_B+1)+(b)) + + for (int rc=0; rc<=MAX_R; rc++) // build 6x6x6 color cube + for (int gc=0; gc<=MAX_G; gc++) + for (int bc=0; bc<=MAX_B; bc++) + dst->colortable[INDEXOF(rc,gc,bc)] = 0xff000000 | qRgb(rc*255/MAX_R, gc*255/MAX_G, bc*255/MAX_B); + + const uchar *src_data = src->data; + uchar *dest_data = dst->data; + if ((flags & Qt::Dither_Mask) == Qt::ThresholdDither) { + for (int y = 0; y < src->height; y++) { + const QRgb *p = (const QRgb *)src_data; + const QRgb *end = p + src->width; + uchar *b = dest_data; + + while (p < end) { +#define DITHER(p,m) ((uchar) ((p * (m) + 127) / 255)) + *b++ = + INDEXOF( + DITHER(qRed(*p), MAX_R), + DITHER(qGreen(*p), MAX_G), + DITHER(qBlue(*p), MAX_B) + ); +#undef DITHER + p++; + } + src_data += src->bytes_per_line; + dest_data += dst->bytes_per_line; + } + } else if ((flags & Qt::Dither_Mask) == Qt::DiffuseDither) { + int* line1[3]; + int* line2[3]; + int* pv[3]; + QScopedArrayPointer<int> lineBuffer(new int[src->width * 9]); + line1[0] = lineBuffer.data(); + line2[0] = lineBuffer.data() + src->width; + line1[1] = lineBuffer.data() + src->width * 2; + line2[1] = lineBuffer.data() + src->width * 3; + line1[2] = lineBuffer.data() + src->width * 4; + line2[2] = lineBuffer.data() + src->width * 5; + pv[0] = lineBuffer.data() + src->width * 6; + pv[1] = lineBuffer.data() + src->width * 7; + pv[2] = lineBuffer.data() + src->width * 8; + + int endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian); + for (int y = 0; y < src->height; y++) { + const uchar* q = src_data; + const uchar* q2 = y < src->height - 1 ? q + src->bytes_per_line : src->data; + uchar *b = dest_data; + for (int chan = 0; chan < 3; chan++) { + int *l1 = (y&1) ? line2[chan] : line1[chan]; + int *l2 = (y&1) ? line1[chan] : line2[chan]; + if (y == 0) { + for (int i = 0; i < src->width; i++) + l1[i] = q[i*4+chan+endian]; + } + if (y+1 < src->height) { + for (int i = 0; i < src->width; i++) + l2[i] = q2[i*4+chan+endian]; + } + // Bi-directional error diffusion + if (y&1) { + for (int x = 0; x < src->width; x++) { + int pix = qMax(qMin(5, (l1[x] * 5 + 128)/ 255), 0); + int err = l1[x] - pix * 255 / 5; + pv[chan][x] = pix; + + // Spread the error around... + if (x + 1< src->width) { + l1[x+1] += (err*7)>>4; + l2[x+1] += err>>4; + } + l2[x]+=(err*5)>>4; + if (x>1) + l2[x-1]+=(err*3)>>4; + } + } else { + for (int x = src->width; x-- > 0;) { + int pix = qMax(qMin(5, (l1[x] * 5 + 128)/ 255), 0); + int err = l1[x] - pix * 255 / 5; + pv[chan][x] = pix; + + // Spread the error around... + if (x > 0) { + l1[x-1] += (err*7)>>4; + l2[x-1] += err>>4; + } + l2[x]+=(err*5)>>4; + if (x + 1 < src->width) + l2[x+1]+=(err*3)>>4; + } + } + } + if (endian) { + for (int x = 0; x < src->width; x++) { + *b++ = INDEXOF(pv[0][x],pv[1][x],pv[2][x]); + } + } else { + for (int x = 0; x < src->width; x++) { + *b++ = INDEXOF(pv[2][x],pv[1][x],pv[0][x]); + } + } + src_data += src->bytes_per_line; + dest_data += dst->bytes_per_line; + } + } else { // OrderedDither + for (int y = 0; y < src->height; y++) { + const QRgb *p = (const QRgb *)src_data; + const QRgb *end = p + src->width; + uchar *b = dest_data; + + int x = 0; + while (p < end) { + uint d = qt_bayer_matrix[y & 15][x & 15] << 8; + +#define DITHER(p, d, m) ((uchar) ((((256 * (m) + (m) + 1)) * (p) + (d)) >> 16)) + *b++ = + INDEXOF( + DITHER(qRed(*p), d, MAX_R), + DITHER(qGreen(*p), d, MAX_G), + DITHER(qBlue(*p), d, MAX_B) + ); +#undef DITHER + + p++; + x++; + } + src_data += src->bytes_per_line; + dest_data += dst->bytes_per_line; + } + } + + if (src->format != QImage::Format_RGB32 + && src->format != QImage::Format_RGB16) { + const int trans = 216; + Q_ASSERT(dst->colortable.size() > trans); + dst->colortable[trans] = 0; + QScopedPointer<QImageData> mask(QImageData::create(QSize(src->width, src->height), QImage::Format_Mono)); + dither_to_Mono(mask.data(), src, flags, true); + uchar *dst_data = dst->data; + const uchar *mask_data = mask->data; + for (int y = 0; y < src->height; y++) { + for (int x = 0; x < src->width ; x++) { + if (!(mask_data[x>>3] & (0x80 >> (x & 7)))) + dst_data[x] = trans; + } + mask_data += mask->bytes_per_line; + dst_data += dst->bytes_per_line; + } + dst->has_alpha_clut = true; + } + +#undef MAX_R +#undef MAX_G +#undef MAX_B +#undef INDEXOF + + } +} + +static void convert_ARGB_PM_to_Indexed8(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags) +{ + QScopedPointer<QImageData> tmp(QImageData::create(QSize(src->width, src->height), QImage::Format_ARGB32)); + convert_ARGB_PM_to_ARGB(tmp.data(), src, flags); + convert_RGB_to_Indexed8(dst, tmp.data(), flags); +} + +static void convert_ARGB_to_Indexed8(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags) +{ + convert_RGB_to_Indexed8(dst, src, flags); +} + +static void convert_Indexed8_to_X32(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_Indexed8); + Q_ASSERT(dest->format == QImage::Format_RGB32 + || dest->format == QImage::Format_ARGB32 + || dest->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + QVector<QRgb> colorTable = fix_color_table(src->colortable, dest->format); + if (colorTable.size() == 0) { + colorTable.resize(256); + for (int i=0; i<256; ++i) + colorTable[i] = qRgb(i, i, i); + } + + int w = src->width; + const uchar *src_data = src->data; + uchar *dest_data = dest->data; + int tableSize = colorTable.size() - 1; + for (int y = 0; y < src->height; y++) { + uint *p = (uint *)dest_data; + const uchar *b = src_data; + uint *end = p + w; + + while (p < end) + *p++ = colorTable.at(qMin<int>(tableSize, *b++)); + + src_data += src->bytes_per_line; + dest_data += dest->bytes_per_line; + } +} + +static void convert_Mono_to_X32(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_Mono || src->format == QImage::Format_MonoLSB); + Q_ASSERT(dest->format == QImage::Format_RGB32 + || dest->format == QImage::Format_ARGB32 + || dest->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + QVector<QRgb> colorTable = fix_color_table(src->colortable, dest->format); + + // Default to black / white colors + if (colorTable.size() < 2) { + if (colorTable.size() == 0) + colorTable << 0xff000000; + colorTable << 0xffffffff; + } + + const uchar *src_data = src->data; + uchar *dest_data = dest->data; + if (src->format == QImage::Format_Mono) { + for (int y = 0; y < dest->height; y++) { + uint *p = (uint *)dest_data; + for (int x = 0; x < dest->width; x++) + *p++ = colorTable.at((src_data[x>>3] >> (7 - (x & 7))) & 1); + + src_data += src->bytes_per_line; + dest_data += dest->bytes_per_line; + } + } else { + for (int y = 0; y < dest->height; y++) { + uint *p = (uint *)dest_data; + for (int x = 0; x < dest->width; x++) + *p++ = colorTable.at((src_data[x>>3] >> (x & 7)) & 1); + + src_data += src->bytes_per_line; + dest_data += dest->bytes_per_line; + } + } +} + + +static void convert_Mono_to_Indexed8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_Mono || src->format == QImage::Format_MonoLSB); + Q_ASSERT(dest->format == QImage::Format_Indexed8); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + QVector<QRgb> ctbl = src->colortable; + if (ctbl.size() > 2) { + ctbl.resize(2); + } else if (ctbl.size() < 2) { + if (ctbl.size() == 0) + ctbl << 0xff000000; + ctbl << 0xffffffff; + } + dest->colortable = ctbl; + dest->has_alpha_clut = src->has_alpha_clut; + + + const uchar *src_data = src->data; + uchar *dest_data = dest->data; + if (src->format == QImage::Format_Mono) { + for (int y = 0; y < dest->height; y++) { + uchar *p = dest_data; + for (int x = 0; x < dest->width; x++) + *p++ = (src_data[x>>3] >> (7 - (x & 7))) & 1; + src_data += src->bytes_per_line; + dest_data += dest->bytes_per_line; + } + } else { + for (int y = 0; y < dest->height; y++) { + uchar *p = dest_data; + for (int x = 0; x < dest->width; x++) + *p++ = (src_data[x>>3] >> (x & 7)) & 1; + src_data += src->bytes_per_line; + dest_data += dest->bytes_per_line; + } + } +} + +// 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, + swap_bit_order, + convert_Mono_to_Indexed8, + convert_Mono_to_X32, + convert_Mono_to_X32, + convert_Mono_to_X32, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }, // Format_Mono + + { + 0, + swap_bit_order, + 0, + convert_Mono_to_Indexed8, + convert_Mono_to_X32, + convert_Mono_to_X32, + convert_Mono_to_X32, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }, // Format_MonoLSB + + { + 0, + convert_X_to_Mono, + convert_X_to_Mono, + 0, + convert_Indexed8_to_X32, + convert_Indexed8_to_X32, + convert_Indexed8_to_X32, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }, // Format_Indexed8 + + { + 0, + convert_X_to_Mono, + convert_X_to_Mono, + convert_RGB_to_Indexed8, + 0, + mask_alpha_converter, + mask_alpha_converter, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_RGB_to_RGBA, + convert_RGB_to_RGBA, + convert_RGB_to_RGBA + }, // Format_RGB32 + + { + 0, + convert_X_to_Mono, + convert_X_to_Mono, + convert_ARGB_to_Indexed8, + mask_alpha_converter, + 0, + convert_ARGB_to_ARGB_PM, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_ARGB_to_RGBx, + convert_ARGB_to_RGBA, + convert_ARGB_to_RGBA_PM, + }, // Format_ARGB32 + + { + 0, + convert_ARGB_PM_to_Mono, + convert_ARGB_PM_to_Mono, + convert_ARGB_PM_to_Indexed8, + convert_ARGB_PM_to_RGB, + convert_ARGB_PM_to_ARGB, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_ARGB_PM_to_RGBx, + convert_ARGB_PM_to_RGBA, + convert_ARGB_to_RGBA, + }, // Format_ARGB32_Premultiplied + + { + 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 + }, // Format_ARGB8565_Premultiplied + + { + 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 + }, // Format_ARGB6666_Premultiplied + + { + 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 + }, // Format_ARGB8555_Premultiplied + + { + 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 + }, // Format_RGB444 + + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }, // Format_ARGB4444_Premultiplied + { + 0, + 0, + 0, + 0, + convert_RGBA_to_RGB, + convert_RGBA_to_ARGB, + convert_RGBA_to_ARGB, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + mask_alpha_converter_RGBx, + mask_alpha_converter_RGBx, + }, // Format_RGBX8888 + { + 0, + 0, + 0, + 0, + convert_RGBA_to_RGB, + convert_RGBA_to_ARGB, + convert_RGBA_to_ARGB_PM, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + mask_alpha_converter_RGBx, +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + 0, + convert_ARGB_to_ARGB_PM, +#else + 0, + 0 +#endif + }, // Format_RGBA8888 + + { + 0, + 0, + 0, + 0, + convert_RGBA_PM_to_RGB, + convert_RGBA_PM_to_ARGB, + convert_RGBA_to_ARGB, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + convert_ARGB_PM_to_RGB, + convert_ARGB_PM_to_ARGB, + 0, +#else + 0, + 0, + 0 +#endif + } // Format_RGBA8888_Premultiplied +}; + +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 + }, // Format_Mono + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, // Format_MonoLSB + { + 0, + 0, + 0, + 0, + 0, + convert_indexed8_to_RGB_inplace, + convert_indexed8_to_ARGB_PM_inplace, + convert_indexed8_to_RGB16_inplace, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + }, // Format_Indexed8 + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_RGB_to_RGB16_inplace, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + }, // Format_RGB32 + { + 0, + 0, + 0, + 0, + 0, + 0, +#ifdef __SSE2__ + convert_ARGB_to_ARGB_PM_inplace_sse2, +#else + convert_ARGB_to_ARGB_PM_inplace, +#endif + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_ARGB_to_RGBA_inplace, + 0, + }, // Format_ARGB32 + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_ARGB_to_RGBA_inplace + }, // Format_ARGB32_Premultiplied + { + 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 + }, // Format_ARGB8565_Premultiplied + { + 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 + }, // Format_ARGB6666_Premultiplied + { + 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 + }, // Format_ARGB8555_Premultiplied + { + 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 + }, // Format_RGB444 + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, // Format_ARGB4444_Premultiplied + { + 0, + 0, + 0, + 0, + 0, + convert_RGBA_to_ARGB_inplace, + convert_RGBA_to_ARGB_inplace, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + }, // Format_RGBX8888 + { + 0, + 0, + 0, + 0, + 0, + 0, + convert_RGBA_to_ARGB_inplace, + convert_RGBA_to_ARGB_PM_inplace, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + }, // Format_RGBA8888 + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_RGBA_to_ARGB_inplace, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + } // Format_RGBA8888_Premultiplied +}; + +void qInitImageConversions() +{ +#if defined(__SSE2__) && defined(QT_COMPILER_SUPPORTS_SSSE3) + if (qCpuHasFeature(SSSE3)) { + extern void convert_RGB888_to_RGB32_ssse3(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags); + qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_ssse3; + qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_ssse3; + qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_ssse3; + } +#endif + +#ifdef __ARM_NEON__ + extern void convert_RGB888_to_RGB32_neon(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags); + qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_neon; + qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_neon; + qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_neon; +#endif + +#ifdef QT_COMPILER_SUPPORTS_MIPS_DSPR2 + extern bool convert_ARGB_to_ARGB_PM_inplace_mips_dspr2(QImageData *data, Qt::ImageConversionFlags); + inplace_converter_map[QImage::Format_ARGB32][QImage::Format_ARGB32_Premultiplied] = convert_ARGB_to_ARGB_PM_inplace_mips_dspr2; + return; +#endif +} + +QT_END_NAMESPACE diff --git a/src/gui/image/qimage_neon.cpp b/src/gui/image/qimage_neon.cpp index 1ac0a87272..60c2da6a58 100644 --- a/src/gui/image/qimage_neon.cpp +++ b/src/gui/image/qimage_neon.cpp @@ -43,7 +43,7 @@ #include <private/qimage_p.h> #include <private/qsimd_p.h> -#ifdef QT_COMPILER_SUPPORTS_NEON +#ifdef __ARM_NEON__ QT_BEGIN_NAMESPACE @@ -111,4 +111,4 @@ void convert_RGB888_to_RGB32_neon(QImageData *dest, const QImageData *src, Qt::I QT_END_NAMESPACE -#endif // QT_COMPILER_SUPPORTS_NEON +#endif // __ARM_NEON__ diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h index 36f117df60..81730b92f2 100644 --- a/src/gui/image/qimage_p.h +++ b/src/gui/image/qimage_p.h @@ -108,7 +108,20 @@ struct Q_GUI_EXPORT QImageData { // internal image data QPaintEngine *paintEngine; }; +typedef void (*Image_Converter)(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags); +typedef bool (*InPlace_Image_Converter)(QImageData *data, Qt::ImageConversionFlags); + +extern Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats]; +extern InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats]; + +void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags); +bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags); + +void dither_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags, bool fromalpha); + void qInitImageConversions(); + +const uchar *qt_get_bitflip_array(); Q_GUI_EXPORT void qGamma_correct_back_to_linear_cs(QImage *image); inline int qt_depthForFormat(QImage::Format format) diff --git a/src/gui/image/qimage_sse2.cpp b/src/gui/image/qimage_sse2.cpp index 0d6eac4ea2..037846c9aa 100644 --- a/src/gui/image/qimage_sse2.cpp +++ b/src/gui/image/qimage_sse2.cpp @@ -94,7 +94,7 @@ bool convert_ARGB_to_ARGB_PM_inplace_sse2(QImageData *data, Qt::ImageConversionF if (*p < 0x00ffffff) *p = 0; else if (*p < 0xff000000) - *p = PREMUL(*p); + *p = qPremultiply(*p); } d = reinterpret_cast<__m128i*>(p+pad); diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index 636d86991b..091837b8b4 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -190,37 +190,36 @@ enum _qt_BuiltInFormatType { struct _qt_BuiltInFormatStruct { - _qt_BuiltInFormatType type; const char *extension; const char *mimeType; }; static const _qt_BuiltInFormatStruct _qt_BuiltInFormats[] = { #ifndef QT_NO_IMAGEFORMAT_PNG - {_qt_PngFormat, "png", "image/png"}, + {"png", "image/png"}, #endif #ifndef QT_NO_IMAGEFORMAT_JPEG - {_qt_JpgFormat, "jpg", "image/jpeg"}, - {_qt_JpegFormat, "jpeg", "image/jpeg"}, + {"jpg", "image/jpeg"}, + {"jpeg", "image/jpeg"}, #endif #ifdef QT_BUILTIN_GIF_READER - {_qt_GifFormat, "gif", "image/gif"}, + {"gif", "image/gif"}, #endif #ifndef QT_NO_IMAGEFORMAT_BMP - {_qt_BmpFormat, "bmp", "image/bmp"}, + {"bmp", "image/bmp"}, #endif #ifndef QT_NO_IMAGEFORMAT_PPM - {_qt_PpmFormat, "ppm", "image/x-portable-pixmap"}, - {_qt_PgmFormat, "pgm", "image/x-portable-graymap"}, - {_qt_PbmFormat, "pbm", "image/x-portable-bitmap"}, + {"ppm", "image/x-portable-pixmap"}, + {"pgm", "image/x-portable-graymap"}, + {"pbm", "image/x-portable-bitmap"}, #endif #ifndef QT_NO_IMAGEFORMAT_XBM - {_qt_XbmFormat, "xbm", "image/x-xbitmap"}, + {"xbm", "image/x-xbitmap"}, #endif #ifndef QT_NO_IMAGEFORMAT_XPM - {_qt_XpmFormat, "xpm", "image/x-xpixmap"}, + {"xpm", "image/x-xpixmap"}, #endif - {_qt_NoFormat, "", ""} + {"", ""} }; static QImageIOHandler *createReadHandlerHelper(QIODevice *device, @@ -423,10 +422,8 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device, QByteArray subType; int numFormats = _qt_NumFormats; while (device && numFormats >= 0) { - const _qt_BuiltInFormatStruct *formatStruct = &_qt_BuiltInFormats[currentFormat]; - const qint64 pos = device->pos(); - switch (formatStruct->type) { + switch (currentFormat) { #ifndef QT_NO_IMAGEFORMAT_PNG case _qt_PngFormat: if (QPngHandler::canRead(device)) @@ -482,7 +479,7 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device, if (handler) { #ifdef QIMAGEREADER_DEBUG - qDebug() << "QImageReader::createReadHandler: the" << formatStruct->extension + qDebug() << "QImageReader::createReadHandler: the" << _qt_BuiltInFormats[currentFormat].extension << "built-in handler can read this data"; #endif break; diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp index 3f90bb42f0..bd358b7228 100644 --- a/src/gui/image/qjpeghandler.cpp +++ b/src/gui/image/qjpeghandler.cpp @@ -861,24 +861,18 @@ Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_avx(quint32 *dst, const QJpegHandler::QJpegHandler() : d(new QJpegHandlerPrivate(this)) { -#if defined(QT_COMPILER_SUPPORTS_NEON) +#if defined(__ARM_NEON__) // from qimage_neon.cpp if (qCpuHasFeature(NEON)) rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_neon; -#endif // QT_COMPILER_SUPPORTS_NEON +#endif // __ARM_NEON__ #if defined(QT_COMPILER_SUPPORTS_SSSE3) // from qimage_ssse3.cpp if (false) { -# if defined(QT_COMPILER_SUPPORTS_AVX) - } else if (qCpuHasFeature(AVX)) { - rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_avx; -# endif -# ifndef __AVX__ } else if (qCpuHasFeature(SSSE3)) { rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_ssse3; -# endif } #endif // QT_COMPILER_SUPPORTS_SSSE3 } diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 6dced54d20..86c4dfbdca 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -1617,6 +1617,28 @@ QPixmap QPixmap::fromImage(const QImage &image, Qt::ImageConversionFlags flags) } /*! + \fn QPixmap QPixmap::fromImage(QImage &&image, Qt::ImageConversionFlags flags) + \since 5.3 + \overload + + Converts the given \a image to a pixmap without copying if possible. +*/ + + +/*! + \internal +*/ +QPixmap QPixmap::fromImageInPlace(QImage &image, Qt::ImageConversionFlags flags) +{ + if (image.isNull()) + return QPixmap(); + + QScopedPointer<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::PixmapType)); + data->fromImageInPlace(image, flags); + return QPixmap(data.take()); +} + +/*! \fn QPixmap QPixmap::fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags) Create a QPixmap from an image read directly from an \a imageReader. diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h index f1fce03c80..0efd606283 100644 --- a/src/gui/image/qpixmap.h +++ b/src/gui/image/qpixmap.h @@ -131,6 +131,12 @@ public: QImage toImage() const; static QPixmap fromImage(const QImage &image, Qt::ImageConversionFlags flags = Qt::AutoColor); static QPixmap fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags = Qt::AutoColor); +#ifdef Q_COMPILER_RVALUE_REFS + static QPixmap fromImage(QImage &&image, Qt::ImageConversionFlags flags = Qt::AutoColor) + { + return fromImageInPlace(image, flags); + } +#endif bool load(const QString& fileName, const char *format = 0, Qt::ImageConversionFlags flags = Qt::AutoColor); bool loadFromData(const uchar *buf, uint len, const char* format = 0, Qt::ImageConversionFlags flags = Qt::AutoColor); @@ -167,6 +173,7 @@ public: protected: int metric(PaintDeviceMetric) const; + static QPixmap fromImageInPlace(QImage &image, Qt::ImageConversionFlags flags = Qt::AutoColor); private: QExplicitlySharedDataPointer<QPlatformPixmap> data; diff --git a/src/gui/image/qpixmap_blitter.cpp b/src/gui/image/qpixmap_blitter.cpp index 4c1b30a6d8..839a7a709f 100644 --- a/src/gui/image/qpixmap_blitter.cpp +++ b/src/gui/image/qpixmap_blitter.cpp @@ -148,7 +148,7 @@ void QBlittablePlatformPixmap::fill(const QColor &color) m_alpha = true; } - uint pixel = PREMUL(color.rgba()); + uint pixel = qPremultiply(color.rgba()); const QPixelLayout *layout = &qPixelLayouts[blittable()->lock()->format()]; Q_ASSERT(layout->convertFromARGB32PM); layout->convertFromARGB32PM(&pixel, &pixel, 1, layout, 0); diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp index f9a017c281..1465fea8b9 100644 --- a/src/gui/image/qpixmap_raster.cpp +++ b/src/gui/image/qpixmap_raster.cpp @@ -135,11 +135,16 @@ bool QRasterPlatformPixmap::fromData(const uchar *buffer, uint len, const char * void QRasterPlatformPixmap::fromImage(const QImage &sourceImage, Qt::ImageConversionFlags flags) { - Q_UNUSED(flags); QImage image = sourceImage; createPixmapForImage(image, flags, /* inplace = */false); } +void QRasterPlatformPixmap::fromImageInPlace(QImage &sourceImage, + Qt::ImageConversionFlags flags) +{ + createPixmapForImage(sourceImage, flags, /* inplace = */true); +} + void QRasterPlatformPixmap::fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags) { @@ -182,7 +187,7 @@ void QRasterPlatformPixmap::fill(const QColor &color) if (alpha != 255) { if (!image.hasAlphaChannel()) { QImage::Format toFormat; -#if !(defined(QT_COMPILER_SUPPORTS_NEON) || defined(__SSE2__)) +#if !(defined(__ARM_NEON__) || defined(__SSE2__)) if (image.format() == QImage::Format_RGB16) toFormat = QImage::Format_ARGB8565_Premultiplied; else if (image.format() == QImage::Format_RGB666) @@ -203,7 +208,7 @@ void QRasterPlatformPixmap::fill(const QColor &color) } } } - pixel = PREMUL(color.rgba()); + pixel = qPremultiply(color.rgba()); const QPixelLayout *layout = &qPixelLayouts[image.format()]; layout->convertFromARGB32PM(&pixel, &pixel, 1, layout, 0); } else { @@ -311,7 +316,7 @@ void QRasterPlatformPixmap::createPixmapForImage(QImage &sourceImage, Qt::ImageC QImage::Format opaqueFormat = QNativeImage::systemFormat(); QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied; -#if !defined(QT_COMPILER_SUPPORTS_NEON) && !defined(__SSE2__) +#if !defined(__ARM_NEON__) && !defined(__SSE2__) switch (opaqueFormat) { case QImage::Format_RGB16: alphaFormat = QImage::Format_ARGB8565_Premultiplied; diff --git a/src/gui/image/qpixmap_raster_p.h b/src/gui/image/qpixmap_raster_p.h index cef8821888..b273d65c9f 100644 --- a/src/gui/image/qpixmap_raster_p.h +++ b/src/gui/image/qpixmap_raster_p.h @@ -69,6 +69,7 @@ public: void resize(int width, int height); bool fromData(const uchar *buffer, uint len, const char *format, Qt::ImageConversionFlags flags); void fromImage(const QImage &image, Qt::ImageConversionFlags flags); + void fromImageInPlace(QImage &image, Qt::ImageConversionFlags flags); void fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags); void copy(const QPlatformPixmap *data, const QRect &rect); diff --git a/src/gui/image/qplatformpixmap.h b/src/gui/image/qplatformpixmap.h index 08e03f10bd..435811eb84 100644 --- a/src/gui/image/qplatformpixmap.h +++ b/src/gui/image/qplatformpixmap.h @@ -69,7 +69,8 @@ public: }; enum ClassId { RasterClass, DirectFBClass, - BlitterClass, CustomClass = 1024 }; + BlitterClass, Direct2DClass, + CustomClass = 1024 }; QPlatformPixmap(PixelType pixelType, int classId); virtual ~QPlatformPixmap(); @@ -79,6 +80,12 @@ public: virtual void resize(int width, int height) = 0; virtual void fromImage(const QImage &image, Qt::ImageConversionFlags flags) = 0; + virtual void fromImageInPlace(QImage &image, + Qt::ImageConversionFlags flags) + { + fromImage(image, flags); + } + virtual void fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags); diff --git a/src/gui/image/qpnghandler.pri b/src/gui/image/qpnghandler.pri index bedf23ff12..aca7e2c568 100644 --- a/src/gui/image/qpnghandler.pri +++ b/src/gui/image/qpnghandler.pri @@ -2,7 +2,7 @@ INCLUDEPATH *= $$PWD HEADERS += $$PWD/qpnghandler_p.h SOURCES += $$PWD/qpnghandler.cpp contains(QT_CONFIG, system-png) { - if(unix|win32-g++*): LIBS_PRIVATE += -lpng + if(unix|mingw): LIBS_PRIVATE += -lpng else:win32: LIBS += libpng.lib } else { diff --git a/src/gui/image/qxbmhandler.cpp b/src/gui/image/qxbmhandler.cpp index aceb6623ea..5311afd745 100644 --- a/src/gui/image/qxbmhandler.cpp +++ b/src/gui/image/qxbmhandler.cpp @@ -103,7 +103,7 @@ static bool read_xbm_header(QIODevice *device, int& w, int& h) // "#define .._height <num>" readBytes = device->readLine(buf, buflen); if (readBytes <= 0) - return false; + return false; buf[readBytes - 1] = '\0'; sbuf = QString::fromLatin1(buf); @@ -183,9 +183,9 @@ static bool read_xbm_image(QIODevice *device, QImage *outImage) static bool write_xbm_image(const QImage &sourceImage, QIODevice *device, const QString &fileName) { QImage image = sourceImage; - int w = image.width(); - int h = image.height(); - int i; + int w = image.width(); + int h = image.height(); + int i; QString s = fileName; // get file base name int msize = s.length() + 100; char *buf = new char[msize]; @@ -203,16 +203,16 @@ static bool write_xbm_image(const QImage &sourceImage, QIODevice *device, const bool invert = qGray(image.color(0)) < qGray(image.color(1)); char hexrep[16]; for (i=0; i<10; i++) - hexrep[i] = '0' + i; + hexrep[i] = '0' + i; for (i=10; i<16; i++) - hexrep[i] = 'a' -10 + i; + hexrep[i] = 'a' -10 + i; if (invert) { - char t; - for (i=0; i<8; i++) { - t = hexrep[15-i]; - hexrep[15-i] = hexrep[i]; - hexrep[i] = t; - } + char t; + for (i=0; i<8; i++) { + t = hexrep[15-i]; + hexrep[15-i] = hexrep[i]; + hexrep[i] = t; + } } int bcnt = 0; char *p = buf; diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index d9bcbf316f..e9e4a1d818 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -121,7 +121,8 @@ SOURCES += \ kernel/qplatformservices.cpp \ kernel/qplatformscreenpageflipper.cpp \ kernel/qplatformsystemtrayicon_qpa.cpp \ - kernel/qplatformsessionmanager.cpp + kernel/qplatformsessionmanager.cpp \ + kernel/qplatformmenu.cpp contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles2) { HEADERS += \ diff --git a/src/gui/kernel/qdrag.cpp b/src/gui/kernel/qdrag.cpp index 91aae94730..465c04cdc8 100644 --- a/src/gui/kernel/qdrag.cpp +++ b/src/gui/kernel/qdrag.cpp @@ -103,7 +103,7 @@ QT_BEGIN_NAMESPACE \sa {Drag and Drop}, QClipboard, QMimeData, QWindowsMime, QMacPasteboardMime, {Draggable Icons Example}, {Draggable Text Example}, {Drop Site Example}, - {Fridge Magnets Example} + {Fridge Magnets Example} */ /*! @@ -253,8 +253,8 @@ Qt::DropAction QDrag::exec(Qt::DropActions supportedActions) loop. Other events are still delivered to the application while the operation is performed. On Windows, the Qt event loop is blocked during the operation. However, QDrag::exec() on - Windows causes processEvents() to be called frequently to keep the GUI responsive. - If any loops or operations are called while a drag operation is active, it will block the drag operation. + Windows causes processEvents() to be called frequently to keep the GUI responsive. + If any loops or operations are called while a drag operation is active, it will block the drag operation. */ Qt::DropAction QDrag::exec(Qt::DropActions supportedActions, Qt::DropAction defaultDropAction) diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 131f1863a5..7759e812cb 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -274,6 +274,38 @@ QMouseEvent::~QMouseEvent() { } +/*! + \since 5.3 + + Returns information about the mouse event source. + + The mouse event source can be used to distinguish between genuine + and artificial mouse events. The latter are events that are + synthesized from touch events by the operating system or Qt itself. + + \note Many platforms provide no such information. On such platforms + \l Qt::MouseEventNotSynthesized is returned always. + + \sa Qt::MouseEventSource + */ +Qt::MouseEventSource QMouseEvent::source() const +{ + return QGuiApplicationPrivate::mouseEventSource(this); +} + +/*! + \since 5.3 + + Returns the mouse event flags. + + The mouse event flags provide additional information about a mouse event. + + \sa Qt::MouseEventFlag + */ +Qt::MouseEventFlags QMouseEvent::flags() const +{ + return QGuiApplicationPrivate::mouseEventFlags(this); +} /*! \fn QPointF QMouseEvent::localPos() const diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index d22e423248..0a826284c9 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -135,6 +135,9 @@ public: QT_DEPRECATED inline QPointF posF() const { return l; } #endif + Qt::MouseEventSource source() const; + Qt::MouseEventFlags flags() const; + protected: QPointF l, w, s; Qt::MouseButton b; diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index c935a45085..c587e51299 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -59,6 +59,7 @@ #include <QtCore/qmutex.h> #include <QtCore/private/qthread_p.h> #include <QtCore/qdir.h> +#include <QtCore/qlibraryinfo.h> #include <QtCore/qnumeric.h> #include <QtDebug> #ifndef QT_NO_ACCESSIBILITY @@ -132,6 +133,8 @@ enum ApplicationResourceFlags static unsigned applicationResourceFlags = 0; +QIcon *QGuiApplicationPrivate::app_icon = 0; + QString *QGuiApplicationPrivate::platform_name = 0; QString *QGuiApplicationPrivate::displayName = 0; @@ -490,6 +493,8 @@ static QWindowGeometrySpecification windowGeometrySpecification; Qt::RightToLeft \li \c{-session} \e session, restores the application from an earlier \l{Session Management}{session}. + \li -qwindowgeometry, sets the geometry of the first window + \li -qwindowtitle, sets the title of the first window \endlist The following standard command line options are available for X11: @@ -565,6 +570,8 @@ QGuiApplication::~QGuiApplication() d->cursor_list.clear(); #endif + delete QGuiApplicationPrivate::app_icon; + QGuiApplicationPrivate::app_icon = 0; delete QGuiApplicationPrivate::platform_name; QGuiApplicationPrivate::platform_name = 0; delete QGuiApplicationPrivate::displayName; @@ -960,11 +967,14 @@ QString QGuiApplication::platformName() *QGuiApplicationPrivate::platform_name : QString(); } -static void init_platform(const QString &pluginArgument, const QString &platformPluginPath, int &argc, char **argv) +static void init_platform(const QString &pluginArgument, const QString &platformPluginPath, const QString &platformThemeName, int &argc, char **argv) { // Split into platform name and arguments QStringList arguments = pluginArgument.split(QLatin1Char(':')); const QString name = arguments.takeFirst().toLower(); + QString argumentsKey = name; + argumentsKey[0] = argumentsKey.at(0).toUpper(); + arguments.append(QLibraryInfo::platformPluginArguments(argumentsKey)); // Create the platform integration. QGuiApplicationPrivate::platform_integration = QPlatformIntegrationFactory::create(name, arguments, argc, argv, platformPluginPath); @@ -991,15 +1001,21 @@ static void init_platform(const QString &pluginArgument, const QString &platform } // Create the platform theme: - // 1) Ask the platform integration for a list of names. - const QStringList themeNames = QGuiApplicationPrivate::platform_integration->themeNames(); + + // 1) Fetch the platform name from the environment if present. + QStringList themeNames; + if (!platformThemeName.isEmpty()) + themeNames.append(platformThemeName); + + // 2) Ask the platform integration for a list of names and try loading them. + themeNames += QGuiApplicationPrivate::platform_integration->themeNames(); foreach (const QString &themeName, themeNames) { QGuiApplicationPrivate::platform_theme = QPlatformThemeFactory::create(themeName, platformPluginPath); if (QGuiApplicationPrivate::platform_theme) break; } - // 2) If none found, look for a theme plugin. Theme plugins are located in the + // 3) If none found, look for a theme plugin. Theme plugins are located in the // same directory as platform plugins. if (!QGuiApplicationPrivate::platform_theme) { foreach (const QString &themeName, themeNames) { @@ -1010,7 +1026,7 @@ static void init_platform(const QString &pluginArgument, const QString &platform // No error message; not having a theme plugin is allowed. } - // 3) Fall back on the built-in "null" platform theme. + // 4) Fall back on the built-in "null" platform theme. if (!QGuiApplicationPrivate::platform_theme) QGuiApplicationPrivate::platform_theme = new QPlatformTheme; @@ -1070,6 +1086,8 @@ void QGuiApplicationPrivate::createPlatformIntegration() platformName = platformNameEnv; } + QString platformThemeName = QString::fromLocal8Bit(qgetenv("QT_QPA_PLATFORMTHEME")); + // Get command line params int j = argc ? 1 : 0; @@ -1079,15 +1097,23 @@ void QGuiApplicationPrivate::createPlatformIntegration() continue; } QByteArray arg = argv[i]; + if (arg.startsWith("--")) + arg.remove(0, 1); if (arg == "-platformpluginpath") { if (++i < argc) platformPluginPath = QLatin1String(argv[i]); } else if (arg == "-platform") { if (++i < argc) platformName = argv[i]; + } else if (arg == "-platformtheme") { + if (++i < argc) + platformThemeName = QString::fromLocal8Bit(argv[i]); } else if (arg == "-qwindowgeometry" || (platformName == "xcb" && arg == "-geometry")) { if (++i < argc) windowGeometrySpecification = QWindowGeometrySpecification::fromArgument(argv[i]); + } else if (arg == "-qwindowtitle" || (platformName == "xcb" && arg == "-title")) { + if (++i < argc) + firstWindowTitle = QString::fromLocal8Bit(argv[i]); } else { argv[j++] = argv[i]; } @@ -1098,7 +1124,7 @@ void QGuiApplicationPrivate::createPlatformIntegration() argc = j; } - init_platform(QLatin1String(platformName), platformPluginPath, argc, argv); + init_platform(QLatin1String(platformName), platformPluginPath, platformThemeName, argc, argv); } @@ -1156,6 +1182,8 @@ void QGuiApplicationPrivate::init() continue; } QByteArray arg = argv[i]; + if (arg.startsWith("--")) + arg.remove(0, 1); if (arg == "-plugin") { if (++i < argc) pluginList << argv[i]; @@ -1644,6 +1672,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, buttons, e->modifiers); ev.setTimestamp(e->timestamp); + setMouseEventSource(&ev, e->source); #ifndef QT_NO_CURSOR if (!e->synthetic) { if (const QScreen *screen = window->screen()) @@ -1657,6 +1686,11 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo return; } + if (doubleClick && (ev.type() == QEvent::MouseButtonPress)) { + // QtBUG-25831, used to suppress delivery in qwidgetwindow.cpp + setMouseEventFlags(&ev, ev.flags() | Qt::MouseEventCreatedDoubleClick); + } + QGuiApplication::sendSpontaneousEvent(window, &ev); if (!e->synthetic && !ev.isAccepted() && !frameStrut @@ -1694,11 +1728,14 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo } if (doubleClick) { mousePressButton = Qt::NoButton; - const QEvent::Type doubleClickType = frameStrut ? QEvent::NonClientAreaMouseButtonDblClick : QEvent::MouseButtonDblClick; - QMouseEvent dblClickEvent(doubleClickType, localPoint, localPoint, globalPoint, - button, buttons, e->modifiers); - dblClickEvent.setTimestamp(e->timestamp); - QGuiApplication::sendSpontaneousEvent(window, &dblClickEvent); + if (!e->window.isNull()) { // 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); + dblClickEvent.setTimestamp(e->timestamp); + setMouseEventSource(&dblClickEvent, e->source); + QGuiApplication::sendSpontaneousEvent(window, &dblClickEvent); + } } } @@ -2114,7 +2151,8 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To synthIt->pos, synthIt->screenPos, Qt::NoButton, - e->modifiers); + e->modifiers, + Qt::MouseEventSynthesizedByQt); fake.synthetic = true; processMouseEvent(&fake); } @@ -2634,6 +2672,35 @@ void QGuiApplicationPrivate::notifyActiveWindowChange(QWindow *) { } +/*! + \property QGuiApplication::windowIcon + \brief the default window icon + + \sa QWindow::setIcon(), {Setting the Application Icon} +*/ +QIcon QGuiApplication::windowIcon() +{ + return QGuiApplicationPrivate::app_icon ? *QGuiApplicationPrivate::app_icon : QIcon(); +} + +void QGuiApplication::setWindowIcon(const QIcon &icon) +{ + if (!QGuiApplicationPrivate::app_icon) + QGuiApplicationPrivate::app_icon = new QIcon(); + *QGuiApplicationPrivate::app_icon = icon; + if (QGuiApplicationPrivate::is_app_running && !QGuiApplicationPrivate::is_app_closing) + QGuiApplicationPrivate::self->notifyWindowIconChanged(); +} + +void QGuiApplicationPrivate::notifyWindowIconChanged() +{ + QEvent ev(QEvent::ApplicationWindowIconChange); + const QWindowList list = QGuiApplication::topLevelWindows(); + for (int i = 0; i < list.size(); ++i) + QCoreApplication::sendEvent(list.at(i), &ev); +} + + /*! \property QGuiApplication::quitOnLastWindowClosed @@ -2701,6 +2768,27 @@ bool QGuiApplicationPrivate::shouldQuitInternal(const QWindowList &processedWind return true; } +bool QGuiApplicationPrivate::tryCloseAllWindows() +{ + return tryCloseRemainingWindows(QWindowList()); +} + +bool QGuiApplicationPrivate::tryCloseRemainingWindows(QWindowList processedWindows) +{ + QWindowList list = QGuiApplication::topLevelWindows(); + for (int i = 0; i < list.size(); ++i) { + QWindow *w = list.at(i); + if (w->isVisible() && !processedWindows.contains(w)) { + if (!w->close()) + return false; + processedWindows.append(w); + list = QGuiApplication::topLevelWindows(); + i = -1; + } + } + return true; +} + /*! \since 5.2 \fn Qt::ApplicationState QGuiApplication::applicationState() @@ -2907,23 +2995,8 @@ void QGuiApplicationPrivate::commitData() Q_Q(QGuiApplication); is_saving_session = true; emit q->commitDataRequest(*session_manager); - if (session_manager->allowsInteraction()) { - QWindowList done; - QWindowList list = QGuiApplication::topLevelWindows(); - bool cancelled = false; - for (int i = 0; !cancelled && i < list.size(); ++i) { - QWindow* w = list.at(i); - if (w->isVisible() && !done.contains(w)) { - cancelled = !w->close(); - if (!cancelled) - done.append(w); - list = QGuiApplication::topLevelWindows(); - i = -1; - } - } - if (cancelled) - session_manager->cancel(); - } + if (session_manager->allowsInteraction() && !tryCloseAllWindows()) + session_manager->cancel(); is_saving_session = false; } @@ -3219,9 +3292,18 @@ void QGuiApplicationPrivate::_q_updateFocusObject(QObject *object) emit q->focusObjectChanged(object); } +enum { + MouseCapsMask = 0xFF, + MouseSourceMaskDst = 0xFF00, + MouseSourceMaskSrc = MouseCapsMask, + MouseSourceShift = 8, + MouseFlagsCapsMask = 0xFF0000, + MouseFlagsShift = 16 +}; + int QGuiApplicationPrivate::mouseEventCaps(QMouseEvent *event) { - return event->caps; + return event->caps & MouseCapsMask; } QVector2D QGuiApplicationPrivate::mouseEventVelocity(QMouseEvent *event) @@ -3231,16 +3313,40 @@ QVector2D QGuiApplicationPrivate::mouseEventVelocity(QMouseEvent *event) void QGuiApplicationPrivate::setMouseEventCapsAndVelocity(QMouseEvent *event, int caps, const QVector2D &velocity) { - event->caps = caps; + Q_ASSERT(caps <= MouseCapsMask); + event->caps &= ~MouseCapsMask; + event->caps |= caps & MouseCapsMask; event->velocity = velocity; } -void QGuiApplicationPrivate::setMouseEventCapsAndVelocity(QMouseEvent *event, QMouseEvent *other) +Qt::MouseEventSource QGuiApplicationPrivate::mouseEventSource(const QMouseEvent *event) +{ + return Qt::MouseEventSource((event->caps & MouseSourceMaskDst) >> MouseSourceShift); +} + +void QGuiApplicationPrivate::setMouseEventSource(QMouseEvent *event, Qt::MouseEventSource source) +{ + // Mouse event synthesization status is encoded in the caps field because + // QTouchDevice::CapabilityFlag uses only 6 bits from it. + int value = source; + Q_ASSERT(value <= MouseSourceMaskSrc); + event->caps &= ~MouseSourceMaskDst; + event->caps |= (value & MouseSourceMaskSrc) << MouseSourceShift; +} + +Qt::MouseEventFlags QGuiApplicationPrivate::mouseEventFlags(const QMouseEvent *event) { - event->caps = other->caps; - event->velocity = other->velocity; + return Qt::MouseEventFlags((event->caps & MouseFlagsCapsMask) >> MouseFlagsShift); } +void QGuiApplicationPrivate::setMouseEventFlags(QMouseEvent *event, Qt::MouseEventFlags flags) +{ + // use the 0x00FF0000 byte from caps (containing up to 7 mouse event flags) + unsigned int value = flags; + Q_ASSERT(value <= Qt::MouseEventFlagMask); + event->caps &= ~MouseFlagsCapsMask; + event->caps |= (value & Qt::MouseEventFlagMask) << MouseFlagsShift; +} #include "moc_qguiapplication.cpp" diff --git a/src/gui/kernel/qguiapplication.h b/src/gui/kernel/qguiapplication.h index 0089d48fa6..6d9a4b2376 100644 --- a/src/gui/kernel/qguiapplication.h +++ b/src/gui/kernel/qguiapplication.h @@ -73,6 +73,7 @@ class QStyleHints; class Q_GUI_EXPORT QGuiApplication : public QCoreApplication { Q_OBJECT + Q_PROPERTY(QIcon windowIcon READ windowIcon WRITE setWindowIcon) Q_PROPERTY(QString applicationDisplayName READ applicationDisplayName WRITE setApplicationDisplayName) Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection) Q_PROPERTY(QString platformName READ platformName STORED false) @@ -93,6 +94,9 @@ public: static QWindowList topLevelWindows(); static QWindow *topLevelAt(const QPoint &pos); + static void setWindowIcon(const QIcon &icon); + static QIcon windowIcon(); + static QString platformName(); static QWindow *modalWindow(); diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index 218036033e..1ec808ec27 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -92,6 +92,7 @@ public: virtual bool shouldQuit(); bool shouldQuitInternal(const QWindowList &processedWindows); + virtual bool tryCloseAllWindows(); static Qt::KeyboardModifiers modifier_buttons; static Qt::MouseButtons mouse_buttons; @@ -171,7 +172,7 @@ public: { if (!(alignment & Qt::AlignHorizontal_Mask)) alignment |= Qt::AlignLeft; - if ((alignment & Qt::AlignAbsolute) == 0 && (alignment & (Qt::AlignLeft | Qt::AlignRight))) { + if (!(alignment & Qt::AlignAbsolute) && (alignment & (Qt::AlignLeft | Qt::AlignRight))) { if (direction == Qt::RightToLeft) alignment ^= (Qt::AlignLeft | Qt::AlignRight); alignment |= Qt::AlignAbsolute; @@ -187,6 +188,7 @@ public: static QGuiApplicationPrivate *instance() { return self; } + static QIcon *app_icon; static QString *platform_name; static QString *displayName; @@ -231,6 +233,8 @@ public: static bool noGrab; QInputMethod *inputMethod; + QString firstWindowTitle; + static QList<QObject *> generic_plugin_list; #ifndef QT_NO_SHORTCUT QShortcutMap shortcutMap; @@ -268,19 +272,27 @@ public: static int mouseEventCaps(QMouseEvent *event); static QVector2D mouseEventVelocity(QMouseEvent *event); static void setMouseEventCapsAndVelocity(QMouseEvent *event, int caps, const QVector2D &velocity); - static void setMouseEventCapsAndVelocity(QMouseEvent *event, QMouseEvent *other); + + static Qt::MouseEventSource mouseEventSource(const QMouseEvent *event); + static void setMouseEventSource(QMouseEvent *event, Qt::MouseEventSource source); + + static Qt::MouseEventFlags mouseEventFlags(const QMouseEvent *event); + static void setMouseEventFlags(QMouseEvent *event, Qt::MouseEventFlags flags); const QDrawHelperGammaTables *gammaTables(); // hook reimplemented in QApplication to apply the QStyle function on the QIcon virtual QPixmap applyQIconStyleHelper(QIcon::Mode, const QPixmap &basePixmap) const { return basePixmap; } + virtual void notifyWindowIconChanged(); + static QRect applyWindowGeometrySpecification(const QRect &windowGeometry, const QWindow *window); static void setApplicationState(Qt::ApplicationState state); protected: virtual void notifyThemeChanged(); + bool tryCloseRemainingWindows(QWindowList processedWindows); #ifndef QT_NO_DRAGANDDROP virtual void notifyDragStarted(const QDrag *); #endif // QT_NO_DRAGANDDROP diff --git a/src/gui/kernel/qguivariant.cpp b/src/gui/kernel/qguivariant.cpp index b4e936f818..1739e8c6fd 100644 --- a/src/gui/kernel/qguivariant.cpp +++ b/src/gui/kernel/qguivariant.cpp @@ -165,7 +165,7 @@ public: #ifndef QT_NO_ICON bool delegate(const QIcon *) { - return false; + return v_cast<QIcon>(Base::m_a)->cacheKey() == v_cast<QIcon>(Base::m_b)->cacheKey(); } #endif bool delegate(const void *p) { return Base::delegate(p); } diff --git a/src/gui/kernel/qinputmethod.cpp b/src/gui/kernel/qinputmethod.cpp index 438c169f71..495ea8f6e7 100644 --- a/src/gui/kernel/qinputmethod.cpp +++ b/src/gui/kernel/qinputmethod.cpp @@ -45,6 +45,8 @@ #include <qtimer.h> #include <qpa/qplatforminputcontext_p.h> +#include <QDebug> + QT_BEGIN_NAMESPACE /*! @@ -365,6 +367,29 @@ bool QInputMethodPrivate::objectAcceptsInputMethod(QObject *object) return enabled; } +/*! + Send \a query to the current focus object with parameters \a argument and return the result. + */ +QVariant QInputMethod::queryFocusObject(Qt::InputMethodQuery query, QVariant argument) +{ + QVariant retval; + QObject *focusObject = qGuiApp->focusObject(); + if (!focusObject) + return retval; + + bool newMethodWorks = QMetaObject::invokeMethod(focusObject, "inputMethodQuery", + Qt::DirectConnection, + Q_RETURN_ARG(QVariant, retval), + Q_ARG(Qt::InputMethodQuery, query), + Q_ARG(QVariant, argument)); + if (newMethodWorks) + return retval; + + QInputMethodQueryEvent queryEvent(query); + QCoreApplication::sendEvent(focusObject, &queryEvent); + return queryEvent.value(query); +} + QT_END_NAMESPACE #include "moc_qinputmethod.cpp" diff --git a/src/gui/kernel/qinputmethod.h b/src/gui/kernel/qinputmethod.h index fe6cc3f331..b155b5c0ca 100644 --- a/src/gui/kernel/qinputmethod.h +++ b/src/gui/kernel/qinputmethod.h @@ -50,6 +50,7 @@ class QInputMethodPrivate; class QWindow; class QRectF; class QTransform; +class QInputMethodQueryEvent; class Q_GUI_EXPORT QInputMethod : public QObject { @@ -89,6 +90,8 @@ public: QLocale locale() const; Qt::LayoutDirection inputDirection() const; + static QVariant queryFocusObject(Qt::InputMethodQuery query, QVariant argument); + public Q_SLOTS: void show(); void hide(); diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index 5770b76f1f..4569457a20 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -1567,7 +1567,7 @@ QDataStream &operator<<(QDataStream &s, const QKeySequence &keysequence) */ QDataStream &operator>>(QDataStream &s, QKeySequence &keysequence) { - qAtomicDetach(keysequence.d); + qAtomicDetach(keysequence.d); QList<quint32> list; s >> list; for (int i = 0; i < 4; ++i) diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp index 39dd2a2dfa..7257663799 100644 --- a/src/gui/kernel/qopenglcontext.cpp +++ b/src/gui/kernel/qopenglcontext.cpp @@ -337,31 +337,32 @@ int QOpenGLContextPrivate::maxTextureSize() glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); -#if defined(QT_OPENGL_ES) - return max_texture_size; -#else - GLenum proxy = GL_PROXY_TEXTURE_2D; - - GLint size; - GLint next = 64; - glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &size); - if (size == 0) { - return max_texture_size; - } - do { - size = next; - next = size * 2; +#ifndef QT_OPENGL_ES + if (!QOpenGLFunctions::isES()) { + GLenum proxy = GL_PROXY_TEXTURE_2D; - if (next > max_texture_size) - break; + GLint size; + GLint next = 64; glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &next); - } while (next > size); + glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &size); + if (size == 0) { + return max_texture_size; + } + do { + size = next; + next = size * 2; + + if (next > max_texture_size) + break; + glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &next); + } while (next > size); + + max_texture_size = size; + } +#endif // QT_OPENGL_ES - max_texture_size = size; return max_texture_size; -#endif } /*! @@ -641,6 +642,13 @@ QOpenGLFunctions *QOpenGLContext::functions() const */ QAbstractOpenGLFunctions *QOpenGLContext::versionFunctions(const QOpenGLVersionProfile &versionProfile) const { +#ifndef QT_OPENGL_ES_2 + if (QOpenGLFunctions::isES()) { + qWarning("versionFunctions: Not supported on dynamic GL ES"); + return 0; + } +#endif // QT_OPENGL_ES_2 + Q_D(const QOpenGLContext); const QSurfaceFormat f = format(); @@ -761,8 +769,7 @@ bool QOpenGLContext::makeCurrent(QSurface *surface) if (!surface->surfaceHandle()) return false; - - if (surface->surfaceType() != QSurface::OpenGLSurface) { + if (!surface->supportsOpenGL()) { qWarning() << "QOpenGLContext::makeCurrent() called with non-opengl surface" << surface; return false; } @@ -837,9 +844,9 @@ void QOpenGLContext::swapBuffers(QSurface *surface) return; } - if (surface->surfaceType() != QSurface::OpenGLSurface) { - qWarning() << "QOpenGLContext::swapBuffers() called with non-opengl surface"; - return; + if (!surface->supportsOpenGL()) { + qWarning() << "QOpenGLContext::swapBuffers() called with non-opengl surface"; + return; } if (surface->surfaceClass() == QSurface::Window diff --git a/src/gui/kernel/qplatformdialoghelper.cpp b/src/gui/kernel/qplatformdialoghelper.cpp index 5ddd718e69..66a2fdff96 100644 --- a/src/gui/kernel/qplatformdialoghelper.cpp +++ b/src/gui/kernel/qplatformdialoghelper.cpp @@ -62,6 +62,70 @@ QT_BEGIN_NAMESPACE */ +static const int buttonRoleLayouts[2][5][14] = +{ + // Qt::Horizontal + { + // WinLayout + { QPlatformDialogHelper::ResetRole, QPlatformDialogHelper::Stretch, QPlatformDialogHelper::YesRole, QPlatformDialogHelper::AcceptRole, + QPlatformDialogHelper::AlternateRole, QPlatformDialogHelper::DestructiveRole, QPlatformDialogHelper::NoRole, + QPlatformDialogHelper::ActionRole, QPlatformDialogHelper::RejectRole, QPlatformDialogHelper::ApplyRole, + QPlatformDialogHelper::HelpRole, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL }, + + // MacLayout + { QPlatformDialogHelper::HelpRole, QPlatformDialogHelper::ResetRole, QPlatformDialogHelper::ApplyRole, QPlatformDialogHelper::ActionRole, + QPlatformDialogHelper::Stretch, QPlatformDialogHelper::DestructiveRole | QPlatformDialogHelper::Reverse, + QPlatformDialogHelper::AlternateRole | QPlatformDialogHelper::Reverse, QPlatformDialogHelper::RejectRole | QPlatformDialogHelper::Reverse, + QPlatformDialogHelper::AcceptRole | QPlatformDialogHelper::Reverse, QPlatformDialogHelper::NoRole | QPlatformDialogHelper::Reverse, + QPlatformDialogHelper::YesRole | QPlatformDialogHelper::Reverse, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL }, + + // KdeLayout + { QPlatformDialogHelper::HelpRole, QPlatformDialogHelper::ResetRole, QPlatformDialogHelper::Stretch, QPlatformDialogHelper::YesRole, + QPlatformDialogHelper::NoRole, QPlatformDialogHelper::ActionRole, QPlatformDialogHelper::AcceptRole, QPlatformDialogHelper::AlternateRole, + QPlatformDialogHelper::ApplyRole, QPlatformDialogHelper::DestructiveRole, QPlatformDialogHelper::RejectRole, QPlatformDialogHelper::EOL }, + + // GnomeLayout + { QPlatformDialogHelper::HelpRole, QPlatformDialogHelper::ResetRole, QPlatformDialogHelper::Stretch, QPlatformDialogHelper::ActionRole, + QPlatformDialogHelper::ApplyRole | QPlatformDialogHelper::Reverse, QPlatformDialogHelper::DestructiveRole | QPlatformDialogHelper::Reverse, + QPlatformDialogHelper::AlternateRole | QPlatformDialogHelper::Reverse, QPlatformDialogHelper::RejectRole | QPlatformDialogHelper::Reverse, + QPlatformDialogHelper::AcceptRole | QPlatformDialogHelper::Reverse, QPlatformDialogHelper::NoRole | QPlatformDialogHelper::Reverse, + QPlatformDialogHelper::YesRole | QPlatformDialogHelper::Reverse, QPlatformDialogHelper::EOL }, + + // MacModelessLayout + { QPlatformDialogHelper::ResetRole, QPlatformDialogHelper::ApplyRole, QPlatformDialogHelper::ActionRole, QPlatformDialogHelper::Stretch, + QPlatformDialogHelper::HelpRole, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, + QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL } + }, + + // Qt::Vertical + { + // WinLayout + { QPlatformDialogHelper::ActionRole, QPlatformDialogHelper::YesRole, QPlatformDialogHelper::AcceptRole, QPlatformDialogHelper::AlternateRole, + QPlatformDialogHelper::DestructiveRole, QPlatformDialogHelper::NoRole, QPlatformDialogHelper::RejectRole, QPlatformDialogHelper::ApplyRole, QPlatformDialogHelper::ResetRole, + QPlatformDialogHelper::HelpRole, QPlatformDialogHelper::Stretch, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL }, + + // MacLayout + { QPlatformDialogHelper::YesRole, QPlatformDialogHelper::NoRole, QPlatformDialogHelper::AcceptRole, QPlatformDialogHelper::RejectRole, + QPlatformDialogHelper::AlternateRole, QPlatformDialogHelper::DestructiveRole, QPlatformDialogHelper::Stretch, QPlatformDialogHelper::ActionRole, QPlatformDialogHelper::ApplyRole, + QPlatformDialogHelper::ResetRole, QPlatformDialogHelper::HelpRole, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL }, + + // KdeLayout + { QPlatformDialogHelper::AcceptRole, QPlatformDialogHelper::AlternateRole, QPlatformDialogHelper::ApplyRole, QPlatformDialogHelper::ActionRole, + QPlatformDialogHelper::YesRole, QPlatformDialogHelper::NoRole, QPlatformDialogHelper::Stretch, QPlatformDialogHelper::ResetRole, + QPlatformDialogHelper::DestructiveRole, QPlatformDialogHelper::RejectRole, QPlatformDialogHelper::HelpRole, QPlatformDialogHelper::EOL }, + + // GnomeLayout + { QPlatformDialogHelper::YesRole, QPlatformDialogHelper::NoRole, QPlatformDialogHelper::AcceptRole, QPlatformDialogHelper::RejectRole, + QPlatformDialogHelper::AlternateRole, QPlatformDialogHelper::DestructiveRole, QPlatformDialogHelper::ApplyRole, QPlatformDialogHelper::ActionRole, QPlatformDialogHelper::Stretch, + QPlatformDialogHelper::ResetRole, QPlatformDialogHelper::HelpRole, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL }, + + // MacModelessLayout + { QPlatformDialogHelper::ActionRole, QPlatformDialogHelper::ApplyRole, QPlatformDialogHelper::ResetRole, QPlatformDialogHelper::Stretch, + QPlatformDialogHelper::HelpRole, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, + QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL } + } +}; + QPlatformDialogHelper::QPlatformDialogHelper() { } @@ -603,7 +667,7 @@ class QMessageDialogOptionsPrivate : public QSharedData public: QMessageDialogOptionsPrivate() : icon(QMessageDialogOptions::NoIcon), - buttons(QMessageDialogOptions::Ok) + buttons(QPlatformDialogHelper::Ok) {} QString windowTitle; @@ -611,7 +675,7 @@ public: QString text; QString informativeText; QString detailedText; - QMessageDialogOptions::StandardButtons buttons; + QPlatformDialogHelper::StandardButtons buttons; }; QMessageDialogOptions::QMessageDialogOptions() : d(new QMessageDialogOptionsPrivate) @@ -683,17 +747,17 @@ void QMessageDialogOptions::setDetailedText(const QString &detailedText) d->detailedText = detailedText; } -void QMessageDialogOptions::setStandardButtons(StandardButtons buttons) +void QMessageDialogOptions::setStandardButtons(QPlatformDialogHelper::StandardButtons buttons) { d->buttons = buttons; } -QMessageDialogOptions::StandardButtons QMessageDialogOptions::standardButtons() const +QPlatformDialogHelper::StandardButtons QMessageDialogOptions::standardButtons() const { return d->buttons; } -QMessageDialogOptions::ButtonRole QMessageDialogOptions::buttonRole(QMessageDialogOptions::StandardButton button) +QPlatformDialogHelper::ButtonRole QPlatformDialogHelper::buttonRole(QPlatformDialogHelper::StandardButton button) { switch (button) { case Ok: @@ -736,6 +800,20 @@ QMessageDialogOptions::ButtonRole QMessageDialogOptions::buttonRole(QMessageDial return InvalidRole; } +const int *QPlatformDialogHelper::buttonLayout(Qt::Orientation orientation, ButtonLayout policy) +{ + if (policy == UnknownLayout) { +#if defined (Q_OS_OSX) + policy = MacLayout; +#elif defined (Q_OS_LINUX) || defined (Q_OS_UNIX) + policy = KdeLayout; +#else + policy = WinLayout; +#endif + } + return buttonRoleLayouts[orientation == Qt::Vertical][policy]; +} + /*! \class QPlatformMessageDialogHelper \since 5.0 diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h index 9eeb0a6da4..731440723b 100644 --- a/src/gui/kernel/qplatformdialoghelper.h +++ b/src/gui/kernel/qplatformdialoghelper.h @@ -82,6 +82,71 @@ public: }; enum DialogCode { Rejected, Accepted }; + enum StandardButton { + // keep this in sync with QDialogButtonBox::StandardButton and QMessageBox::StandardButton + NoButton = 0x00000000, + Ok = 0x00000400, + Save = 0x00000800, + SaveAll = 0x00001000, + Open = 0x00002000, + Yes = 0x00004000, + YesToAll = 0x00008000, + No = 0x00010000, + NoToAll = 0x00020000, + Abort = 0x00040000, + Retry = 0x00080000, + Ignore = 0x00100000, + Close = 0x00200000, + Cancel = 0x00400000, + Discard = 0x00800000, + Help = 0x01000000, + Apply = 0x02000000, + Reset = 0x04000000, + RestoreDefaults = 0x08000000, + + + FirstButton = Ok, // internal + LastButton = RestoreDefaults, // internal + LowestBit = 10, // internal: log2(FirstButton) + HighestBit = 27 // internal: log2(LastButton) + }; + + Q_DECLARE_FLAGS(StandardButtons, StandardButton) + + enum ButtonRole { + // keep this in sync with QDialogButtonBox::ButtonRole and QMessageBox::ButtonRole + // TODO Qt 6: make the enum copies explicit, and make InvalidRole == 0 so that + // AcceptRole can be or'ed with flags, and EOL can be the same as InvalidRole (null-termination) + InvalidRole = -1, + AcceptRole, + RejectRole, + DestructiveRole, + ActionRole, + HelpRole, + YesRole, + NoRole, + ResetRole, + ApplyRole, + + NRoles, + + RoleMask = 0x0FFFFFFF, + AlternateRole = 0x10000000, + Stretch = 0x20000000, + Reverse = 0x40000000, + EOL = InvalidRole + }; + + enum ButtonLayout { + // keep this in sync with QDialogButtonBox::ButtonLayout and QMessageBox::ButtonLayout + UnknownLayout = -1, + WinLayout, + MacLayout, + KdeLayout, + GnomeLayout, + MacModelessLayout + }; + QPlatformDialogHelper(); virtual ~QPlatformDialogHelper(); @@ -95,6 +160,9 @@ public: static QVariant defaultStyleHint(QPlatformDialogHelper::StyleHint hint); + static const int *buttonLayout(Qt::Orientation orientation = Qt::Horizontal, ButtonLayout policy = UnknownLayout); + static ButtonRole buttonRole(StandardButton button); + Q_SIGNALS: void accept(); void reject(); @@ -332,50 +400,6 @@ public: // Keep in sync with QMessageBox::Icon enum Icon { NoIcon, Information, Warning, Critical, Question }; - enum StandardButton { - // keep this in sync with QDialogButtonBox::StandardButton and QMessageBox::StandardButton - NoButton = 0x00000000, - Ok = 0x00000400, - Save = 0x00000800, - SaveAll = 0x00001000, - Open = 0x00002000, - Yes = 0x00004000, - YesToAll = 0x00008000, - No = 0x00010000, - NoToAll = 0x00020000, - Abort = 0x00040000, - Retry = 0x00080000, - Ignore = 0x00100000, - Close = 0x00200000, - Cancel = 0x00400000, - Discard = 0x00800000, - Help = 0x01000000, - Apply = 0x02000000, - Reset = 0x04000000, - RestoreDefaults = 0x08000000, - - - FirstButton = Ok, // internal - LastButton = RestoreDefaults // internal - }; - - Q_DECLARE_FLAGS(StandardButtons, StandardButton) - - enum ButtonRole { - InvalidRole = -1, - AcceptRole, - RejectRole, - DestructiveRole, - ActionRole, - HelpRole, - YesRole, - NoRole, - ResetRole, - ApplyRole, - - NRoles - }; - QMessageDialogOptions(); QMessageDialogOptions(const QMessageDialogOptions &rhs); QMessageDialogOptions &operator=(const QMessageDialogOptions &rhs); @@ -398,10 +422,8 @@ public: void setDetailedText(const QString &text); QString detailedText() const; - void setStandardButtons(StandardButtons buttons); - StandardButtons standardButtons() const; - - static ButtonRole buttonRole(StandardButton button); + void setStandardButtons(QPlatformDialogHelper::StandardButtons buttons); + QPlatformDialogHelper::StandardButtons standardButtons() const; private: QSharedDataPointer<QMessageDialogOptionsPrivate> d; @@ -417,7 +439,7 @@ public: void setOptions(const QSharedPointer<QMessageDialogOptions> &options); Q_SIGNALS: - void clicked(QMessageDialogOptions::StandardButton button, QMessageDialogOptions::ButtonRole role); + void clicked(QPlatformDialogHelper::StandardButton button, QPlatformDialogHelper::ButtonRole role); private: QSharedPointer<QMessageDialogOptions> m_options; diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp index 26aaf931b3..bec201f3f7 100644 --- a/src/gui/kernel/qplatformintegration.cpp +++ b/src/gui/kernel/qplatformintegration.cpp @@ -359,6 +359,8 @@ QVariant QPlatformIntegration::styleHint(StyleHint hint) const return true; case SetFocusOnTouchRelease: return QVariant(false); + case MousePressAndHoldInterval: + return QPlatformTheme::defaultThemeHint(QPlatformTheme::MousePressAndHoldInterval); } return 0; diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h index 580fc15233..35ef88949f 100644 --- a/src/gui/kernel/qplatformintegration.h +++ b/src/gui/kernel/qplatformintegration.h @@ -95,7 +95,8 @@ public: NonFullScreenWindows, NativeWidgets, WindowManagement, - SyncState + SyncState, + RasterGLSurface }; virtual ~QPlatformIntegration() { } @@ -148,7 +149,8 @@ public: SynthesizeMouseFromTouchEvents, PasswordMaskCharacter, SetFocusOnTouchRelease, - ShowIsMaximized + ShowIsMaximized, + MousePressAndHoldInterval }; virtual QVariant styleHint(StyleHint hint) const; diff --git a/src/gui/image/qimage_avx.cpp b/src/gui/kernel/qplatformmenu.cpp index d04ec5b3de..54c340abf9 100644 --- a/src/gui/image/qimage_avx.cpp +++ b/src/gui/kernel/qplatformmenu.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2012 Intel Corporation +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Martin Graesslin <mgraesslin@kde.org> ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtGui module of the Qt Toolkit. @@ -39,19 +40,16 @@ ** ****************************************************************************/ -#include <private/qsimd_p.h> +#include "qplatformmenu.h" -#ifdef QT_COMPILER_SUPPORTS_AVX +#include <qpa/qplatformtheme.h> +#include <private/qguiapplication_p.h> -#ifndef __AVX__ -#error "AVX not enabled in this file, cannot proceed" -#endif +QT_BEGIN_NAMESPACE -#define convert_ARGB_to_ARGB_PM_inplace_sse2 convert_ARGB_to_ARGB_PM_inplace_avx -#include "qimage_sse2.cpp" +QPlatformMenuItem *QPlatformMenu::createMenuItem() const +{ + return QGuiApplicationPrivate::platformTheme()->createPlatformMenuItem(); +} -#define qt_convert_rgb888_to_rgb32_ssse3 qt_convert_rgb888_to_rgb32_avx -#define convert_RGB888_to_RGB32_ssse3 convert_RGB888_to_RGB32_avx -#include "qimage_ssse3.cpp" - -#endif +QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformmenu.h b/src/gui/kernel/qplatformmenu.h index 3485cc58dd..9326a2b3a1 100644 --- a/src/gui/kernel/qplatformmenu.h +++ b/src/gui/kernel/qplatformmenu.h @@ -116,6 +116,8 @@ public: virtual QPlatformMenuItem *menuItemAt(int position) const = 0; virtual QPlatformMenuItem *menuItemForTag(quintptr tag) const = 0; + + virtual QPlatformMenuItem *createMenuItem() const; Q_SIGNALS: void aboutToShow(); void aboutToHide(); diff --git a/src/gui/kernel/qplatformsessionmanager.h b/src/gui/kernel/qplatformsessionmanager.h index 23b7a62436..80f1bcbaa0 100644 --- a/src/gui/kernel/qplatformsessionmanager.h +++ b/src/gui/kernel/qplatformsessionmanager.h @@ -91,10 +91,10 @@ public: virtual bool isPhase2() const; virtual void requestPhase2(); -protected: - virtual void appCommitData(); - virtual void appSaveState(); + void appCommitData(); + void appSaveState(); +protected: QString m_sessionId; QString m_sessionKey; diff --git a/src/gui/kernel/qplatformsystemtrayicon.h b/src/gui/kernel/qplatformsystemtrayicon.h index 2c05b1a7fa..6bad643c7c 100644 --- a/src/gui/kernel/qplatformsystemtrayicon.h +++ b/src/gui/kernel/qplatformsystemtrayicon.h @@ -83,6 +83,8 @@ public: virtual bool isSystemTrayAvailable() const = 0; virtual bool supportsMessages() const = 0; + virtual QPlatformMenu *createMenu() const; + Q_SIGNALS: void activated(QPlatformSystemTrayIcon::ActivationReason reason); void messageClicked(); diff --git a/src/gui/kernel/qplatformsystemtrayicon_qpa.cpp b/src/gui/kernel/qplatformsystemtrayicon_qpa.cpp index c4cec40a10..bc37f99210 100644 --- a/src/gui/kernel/qplatformsystemtrayicon_qpa.cpp +++ b/src/gui/kernel/qplatformsystemtrayicon_qpa.cpp @@ -159,6 +159,22 @@ QPlatformSystemTrayIcon::~QPlatformSystemTrayIcon() \sa activated() */ +/*! + This method is called in case there is no QPlatformMenu available when + updating the menu. This allows the abstraction to provide a menu for the + system tray icon even if normally a non-native menu is used. + + The default implementation returns a null pointer. + + \sa updateMenu() + \since 5.3 + */ + +QPlatformMenu *QPlatformSystemTrayIcon::createMenu() const +{ + return Q_NULLPTR; +} + QT_END_NAMESPACE #include "moc_qplatformsystemtrayicon.cpp" diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp index 3548ec0199..e12eb318dc 100644 --- a/src/gui/kernel/qplatformtheme.cpp +++ b/src/gui/kernel/qplatformtheme.cpp @@ -51,6 +51,7 @@ #include <private/qiconloader_p.h> #include <private/qguiapplication_p.h> #include <qpa/qplatformintegration.h> +#include <qpa/qplatformdialoghelper.h> QT_BEGIN_NAMESPACE @@ -79,6 +80,9 @@ QT_BEGIN_NAMESPACE \value MouseDoubleClickInterval (int) Mouse double click interval in ms, overriding QPlatformIntegration::styleHint. + \value MousePressAndHoldInterval (int) Mouse press and hold interval in ms, + overriding QPlatformIntegration::styleHint. + \value StartDragDistance (int) Start drag distance, overriding QPlatformIntegration::styleHint. @@ -425,6 +429,8 @@ QVariant QPlatformTheme::themeHint(ThemeHint hint) const return QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::PasswordMaskDelay); case QPlatformTheme::PasswordMaskCharacter: return QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::PasswordMaskCharacter); + case QPlatformTheme::MousePressAndHoldInterval: + return QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::MousePressAndHoldInterval); default: return QPlatformTheme::defaultThemeHint(hint); } @@ -491,6 +497,8 @@ QVariant QPlatformTheme::defaultThemeHint(ThemeHint hint) case DialogSnapToDefaultButton: case ContextMenuOnMouseRelease: return QVariant(false); + case MousePressAndHoldInterval: + return QVariant(800); } return QVariant(); } @@ -620,6 +628,63 @@ QList<QKeySequence> QPlatformTheme::keyBindings(QKeySequence::StandardKey key) c return list; } +/*! + Returns the text of a standard \a button. + + \since 5.3 + \sa QPlatformDialogHelper::StandardButton + */ + +QString QPlatformTheme::standardButtonText(int button) const +{ + return QPlatformTheme::defaultStandardButtonText(button); +} + +QString QPlatformTheme::defaultStandardButtonText(int button) +{ + switch (button) { + case QPlatformDialogHelper::Ok: + return QCoreApplication::translate("QPlatformTheme", "OK"); + case QPlatformDialogHelper::Save: + return QCoreApplication::translate("QPlatformTheme", "Save"); + case QPlatformDialogHelper::SaveAll: + return QCoreApplication::translate("QPlatformTheme", "Save All"); + case QPlatformDialogHelper::Open: + return QCoreApplication::translate("QPlatformTheme", "Open"); + case QPlatformDialogHelper::Yes: + return QCoreApplication::translate("QPlatformTheme", "&Yes"); + case QPlatformDialogHelper::YesToAll: + return QCoreApplication::translate("QPlatformTheme", "Yes to &All"); + case QPlatformDialogHelper::No: + return QCoreApplication::translate("QPlatformTheme", "&No"); + case QPlatformDialogHelper::NoToAll: + return QCoreApplication::translate("QPlatformTheme", "N&o to All"); + case QPlatformDialogHelper::Abort: + return QCoreApplication::translate("QPlatformTheme", "Abort"); + case QPlatformDialogHelper::Retry: + return QCoreApplication::translate("QPlatformTheme", "Retry"); + case QPlatformDialogHelper::Ignore: + return QCoreApplication::translate("QPlatformTheme", "Ignore"); + case QPlatformDialogHelper::Close: + return QCoreApplication::translate("QPlatformTheme", "Close"); + case QPlatformDialogHelper::Cancel: + return QCoreApplication::translate("QPlatformTheme", "Cancel"); + case QPlatformDialogHelper::Discard: + return QCoreApplication::translate("QPlatformTheme", "Discard"); + case QPlatformDialogHelper::Help: + return QCoreApplication::translate("QPlatformTheme", "Help"); + case QPlatformDialogHelper::Apply: + return QCoreApplication::translate("QPlatformTheme", "Apply"); + case QPlatformDialogHelper::Reset: + return QCoreApplication::translate("QPlatformTheme", "Reset"); + case QPlatformDialogHelper::RestoreDefaults: + return QCoreApplication::translate("QPlatformTheme", "Restore Defaults"); + default: + break; + } + return QString(); +} + unsigned QPlatformThemePrivate::currentKeyPlatforms() { const uint keyboardScheme = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::KeyboardScheme).toInt(); diff --git a/src/gui/kernel/qplatformtheme.h b/src/gui/kernel/qplatformtheme.h index 5cdec48ca3..205a5bab69 100644 --- a/src/gui/kernel/qplatformtheme.h +++ b/src/gui/kernel/qplatformtheme.h @@ -107,7 +107,8 @@ public: IconPixmapSizes, PasswordMaskCharacter, DialogSnapToDefaultButton, - ContextMenuOnMouseRelease + ContextMenuOnMouseRelease, + MousePressAndHoldInterval }; enum DialogType { @@ -295,7 +296,10 @@ public: virtual QList<QKeySequence> keyBindings(QKeySequence::StandardKey key) const; + virtual QString standardButtonText(int button) const; + static QVariant defaultThemeHint(ThemeHint hint); + static QString defaultStandardButtonText(int button); protected: explicit QPlatformTheme(QPlatformThemePrivate *priv); diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp index 954d47f18c..faaf418522 100644 --- a/src/gui/kernel/qplatformwindow.cpp +++ b/src/gui/kernel/qplatformwindow.cpp @@ -127,6 +127,18 @@ QRect QPlatformWindow::geometry() const return d->rect; } +/*! + Returns the geometry of a window in 'normal' state + (neither maximized, fullscreen nor minimized) for saving geometries to + application settings. + + \since 5.3 +*/ +QRect QPlatformWindow::normalGeometry() const +{ + return QRect(); +} + QMargins QPlatformWindow::frameMargins() const { return QMargins(); @@ -509,6 +521,20 @@ static inline const QScreen *effectiveScreen(const QWindow *window) } /*! + Invalidates the window's surface by releasing its surface buffers. + + Many platforms do not support releasing the surface memory, + and the default implementation does nothing. + + The platform window is expected to recreate the surface again if + it is needed. For instance, if an OpenGL context is made current + on this window. + */ +void QPlatformWindow::invalidateSurface() +{ +} + +/*! Helper function to get initial geometry on windowing systems which do not do smart positioning and also do not provide a means of centering a transient window w.r.t. its parent. For example this is useful on Windows @@ -521,14 +547,13 @@ QRect QPlatformWindow::initialGeometry(const QWindow *w, const QRect &initialGeometry, int defaultWidth, int defaultHeight) { QRect rect(initialGeometry); - if (rect.isNull()) { - QSize minimumSize = w->minimumSize(); - if (minimumSize.width() > 0 || minimumSize.height() > 0) { - rect.setSize(minimumSize); - } else { - rect.setWidth(defaultWidth); - rect.setHeight(defaultHeight); - } + if (rect.width() == 0) { + const int minWidth = w->minimumWidth(); + rect.setWidth(minWidth > 0 ? minWidth : defaultWidth); + } + if (rect.height() == 0) { + const int minHeight = w->minimumHeight(); + rect.setHeight(minHeight > 0 ? minHeight : defaultHeight); } if (w->isTopLevel() && qt_window_private(const_cast<QWindow*>(w))->positionAutomatic && w->type() != Qt::Popup) { diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h index 7dfbae036f..39bd8324a0 100644 --- a/src/gui/kernel/qplatformwindow.h +++ b/src/gui/kernel/qplatformwindow.h @@ -84,6 +84,7 @@ public: virtual void setGeometry(const QRect &rect); virtual QRect geometry() const; + virtual QRect normalGeometry() const; virtual QMargins frameMargins() const; @@ -131,6 +132,8 @@ public: virtual void setAlertState(bool enabled); virtual bool isAlertState() const; + virtual void invalidateSurface(); + static QRect initialGeometry(const QWindow *w, const QRect &initialGeometry, int defaultWidth, int defaultHeight); diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp index 2573f76374..70ee631fc8 100644 --- a/src/gui/kernel/qscreen.cpp +++ b/src/gui/kernel/qscreen.cpp @@ -401,8 +401,8 @@ Qt::ScreenOrientations QScreen::orientationUpdateMask() const The screen orientation represents the physical orientation of the display. For example, the screen orientation of a mobile device - will change based on the device is being held, and a desktop display - might be rotated so that it's in portrait mode. + will change based on how it is being held. A change to the orientation + might or might not trigger a change to the primary orientation of the screen. Changes to this property will be filtered by orientationUpdateMask(), so in order to receive orientation updates the application must first @@ -435,7 +435,12 @@ qreal QScreen::refreshRate() const The primary screen orientation is Qt::LandscapeOrientation if the screen geometry's width is greater than or equal to its - height, or Qt::PortraitOrientation otherwise. + height, or Qt::PortraitOrientation otherwise. This property might + change when the screen orientation was changed (i.e. when the + display is rotated). + The behavior is however platform dependent and can often be specified in + an application manifest file. + */ Qt::ScreenOrientation QScreen::primaryOrientation() const { diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp index 513e21937e..c915ed3928 100644 --- a/src/gui/kernel/qshortcutmap.cpp +++ b/src/gui/kernel/qshortcutmap.cpp @@ -359,7 +359,7 @@ bool QShortcutMap::tryShortcutEvent(QObject *o, QKeyEvent *e) resetState(); dispatchEvent(e); default: - break; + break; } // If nextState is QKeySequence::ExactMatch && identicals.count == 0 // we've only found disabled shortcuts diff --git a/src/gui/kernel/qstylehints.cpp b/src/gui/kernel/qstylehints.cpp index 68eb724454..e1468942af 100644 --- a/src/gui/kernel/qstylehints.cpp +++ b/src/gui/kernel/qstylehints.cpp @@ -62,6 +62,25 @@ static inline QVariant themeableHint(QPlatformTheme::ThemeHint th, return QGuiApplicationPrivate::platformIntegration()->styleHint(ih); } +class QStyleHintsPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QStyleHints) +public: + inline QStyleHintsPrivate() + : m_mouseDoubleClickInterval(-1) + , m_startDragDistance(-1) + , m_startDragTime(-1) + , m_keyboardInputInterval(-1) + , m_cursorFlashTime(-1) + {} + + int m_mouseDoubleClickInterval; + int m_startDragDistance; + int m_startDragTime; + int m_keyboardInputInterval; + int m_cursorFlashTime; +}; + /*! \class QStyleHints \since 5.0 @@ -80,17 +99,55 @@ static inline QVariant themeableHint(QPlatformTheme::ThemeHint th, \sa QGuiApplication::styleHints(), QPlatformTheme */ QStyleHints::QStyleHints() - : QObject() + : QObject(*new QStyleHintsPrivate(), 0) { } /*! + Sets the \a mouseDoubleClickInterval. + \internal + \sa mouseDoubleClickInterval() + \since 5.3 +*/ +void QStyleHints::setMouseDoubleClickInterval(int mouseDoubleClickInterval) +{ + Q_D(QStyleHints); + d->m_mouseDoubleClickInterval = mouseDoubleClickInterval; +} + +/*! Returns the time limit in milliseconds that distinguishes a double click from two consecutive mouse clicks. */ int QStyleHints::mouseDoubleClickInterval() const { - return themeableHint(QPlatformTheme::MouseDoubleClickInterval, QPlatformIntegration::MouseDoubleClickInterval).toInt(); + Q_D(const QStyleHints); + return d->m_mouseDoubleClickInterval >= 0 ? + d->m_mouseDoubleClickInterval : + themeableHint(QPlatformTheme::MouseDoubleClickInterval, QPlatformIntegration::MouseDoubleClickInterval).toInt(); +} + +/*! + Returns the time limit in milliseconds that activates + a press and hold. + + \since 5.3 +*/ +int QStyleHints::mousePressAndHoldInterval() const +{ + return themeableHint(QPlatformTheme::MousePressAndHoldInterval, QPlatformIntegration::MousePressAndHoldInterval).toInt(); +} + +/*! + Sets the \a startDragDistance. + \internal + \sa startDragDistance() + \since 5.3 +*/ +void QStyleHints::setStartDragDistance(int startDragDistance) +{ + Q_D(QStyleHints); + d->m_startDragDistance = startDragDistance; } /*! @@ -112,7 +169,22 @@ int QStyleHints::mouseDoubleClickInterval() const */ int QStyleHints::startDragDistance() const { - return themeableHint(QPlatformTheme::StartDragDistance, QPlatformIntegration::StartDragDistance).toInt(); + Q_D(const QStyleHints); + return d->m_startDragDistance >= 0 ? + d->m_startDragDistance : + themeableHint(QPlatformTheme::StartDragDistance, QPlatformIntegration::StartDragDistance).toInt(); +} + +/*! + Sets the \a startDragDragTime. + \internal + \sa startDragTime() + \since 5.3 +*/ +void QStyleHints::setStartDragTime(int startDragTime) +{ + Q_D(QStyleHints); + d->m_startDragTime = startDragTime; } /*! @@ -127,7 +199,10 @@ int QStyleHints::startDragDistance() const */ int QStyleHints::startDragTime() const { - return themeableHint(QPlatformTheme::StartDragTime, QPlatformIntegration::StartDragTime).toInt(); + Q_D(const QStyleHints); + return d->m_startDragTime >= 0 ? + d->m_startDragTime : + themeableHint(QPlatformTheme::StartDragTime, QPlatformIntegration::StartDragTime).toInt(); } /*! @@ -143,12 +218,27 @@ int QStyleHints::startDragVelocity() const } /*! + Sets the \a keyboardInputInterval. + \internal + \sa keyboardInputInterval() + \since 5.3 +*/ +void QStyleHints::setKeyboardInputInterval(int keyboardInputInterval) +{ + Q_D(QStyleHints); + d->m_keyboardInputInterval = keyboardInputInterval; +} + +/*! Returns the time limit, in milliseconds, that distinguishes a key press from two consecutive key presses. */ int QStyleHints::keyboardInputInterval() const { - return themeableHint(QPlatformTheme::KeyboardInputInterval, QPlatformIntegration::KeyboardInputInterval).toInt(); + Q_D(const QStyleHints); + return d->m_keyboardInputInterval >= 0 ? + d->m_keyboardInputInterval : + themeableHint(QPlatformTheme::KeyboardInputInterval, QPlatformIntegration::KeyboardInputInterval).toInt(); } /*! @@ -161,6 +251,18 @@ int QStyleHints::keyboardAutoRepeatRate() const } /*! + Sets the \a cursorFlashTime. + \internal + \sa cursorFlashTime() + \since 5.3 +*/ +void QStyleHints::setCursorFlashTime(int cursorFlashTime) +{ + Q_D(QStyleHints); + d->m_cursorFlashTime = cursorFlashTime; +} + +/*! Returns the text cursor's flash (blink) time in milliseconds. The flash time is the time used to display, invert and restore the @@ -169,7 +271,10 @@ int QStyleHints::keyboardAutoRepeatRate() const */ int QStyleHints::cursorFlashTime() const { - return themeableHint(QPlatformTheme::CursorFlashTime, QPlatformIntegration::CursorFlashTime).toInt(); + Q_D(const QStyleHints); + return d->m_cursorFlashTime >= 0 ? + d->m_cursorFlashTime : + themeableHint(QPlatformTheme::CursorFlashTime, QPlatformIntegration::CursorFlashTime).toInt(); } /*! diff --git a/src/gui/kernel/qstylehints.h b/src/gui/kernel/qstylehints.h index a0facd5f94..33fbe2965e 100644 --- a/src/gui/kernel/qstylehints.h +++ b/src/gui/kernel/qstylehints.h @@ -48,17 +48,25 @@ QT_BEGIN_NAMESPACE class QPlatformIntegration; +class QStyleHintsPrivate; class Q_GUI_EXPORT QStyleHints : public QObject { Q_OBJECT + Q_DECLARE_PRIVATE(QStyleHints) public: + void setMouseDoubleClickInterval(int mouseDoubleClickInterval); int mouseDoubleClickInterval() const; + int mousePressAndHoldInterval() const; + void setStartDragDistance(int startDragDistance); int startDragDistance() const; + void setStartDragTime(int startDragTime); int startDragTime() const; int startDragVelocity() const; + void setKeyboardInputInterval(int keyboardInputInterval); int keyboardInputInterval() const; int keyboardAutoRepeatRate() const; + void setCursorFlashTime(int cursorFlashTime); int cursorFlashTime() const; bool showIsFullScreen() const; int passwordMaskDelay() const; diff --git a/src/gui/kernel/qsurface.cpp b/src/gui/kernel/qsurface.cpp index a943639d5f..a27bdaccde 100644 --- a/src/gui/kernel/qsurface.cpp +++ b/src/gui/kernel/qsurface.cpp @@ -74,6 +74,9 @@ QT_BEGIN_NAMESPACE a software rasterizer like Qt's raster paint engine. \value OpenGLSurface The surface is an OpenGL compatible surface and can be used in conjunction with QOpenGLContext. + \value RasterGLSurface The surface can be rendered to using a software rasterizer, + and also supports OpenGL. This surface type is intended for internal Qt use, and + requires the use of private API. */ @@ -84,6 +87,19 @@ QT_BEGIN_NAMESPACE */ /*! + Returns true if the surface is OpenGL compatible and can be used in + conjunction with QOpenGLContext; otherwise returns false. + + \since 5.3 +*/ + +bool QSurface::supportsOpenGL() const +{ + SurfaceType type = surfaceType(); + return type == OpenGLSurface || type == RasterGLSurface; +} + +/*! \fn QPlatformSurface *QSurface::surfaceHandle() const Returns a handle to the platform-specific implementation of the surface. diff --git a/src/gui/kernel/qsurface.h b/src/gui/kernel/qsurface.h index 8dbc230c10..c4a3276372 100644 --- a/src/gui/kernel/qsurface.h +++ b/src/gui/kernel/qsurface.h @@ -64,7 +64,8 @@ public: enum SurfaceType { RasterSurface, - OpenGLSurface + OpenGLSurface, + RasterGLSurface }; virtual ~QSurface(); @@ -75,6 +76,7 @@ public: virtual QPlatformSurface *surfaceHandle() const = 0; virtual SurfaceType surfaceType() const = 0; + bool supportsOpenGL() const; virtual QSize size() const = 0; diff --git a/src/gui/kernel/qsurfaceformat.cpp b/src/gui/kernel/qsurfaceformat.cpp index fe5615d394..2b6cb2d949 100644 --- a/src/gui/kernel/qsurfaceformat.cpp +++ b/src/gui/kernel/qsurfaceformat.cpp @@ -72,6 +72,7 @@ public: , profile(QSurfaceFormat::NoProfile) , major(2) , minor(0) + , swapInterval(1) // default to vsync { } @@ -89,7 +90,8 @@ public: renderableType(other->renderableType), profile(other->profile), major(other->major), - minor(other->minor) + minor(other->minor), + swapInterval(other->swapInterval) { } @@ -107,6 +109,7 @@ public: QSurfaceFormat::OpenGLContextProfile profile; int major; int minor; + int swapInterval; }; /*! @@ -311,9 +314,15 @@ void QSurfaceFormat::setSamples(int numSamples) } /*! - Sets the format option to \a opt. + \obsolete + \overload - \sa testOption() + Use setOption(QSurfaceFormat::FormatOption, bool) or setOptions() instead. + + Sets the format options to the OR combination of \a opt and the + current format options. + + \sa options(), testOption() */ void QSurfaceFormat::setOption(QSurfaceFormat::FormatOptions opt) { @@ -325,7 +334,13 @@ void QSurfaceFormat::setOption(QSurfaceFormat::FormatOptions opt) } /*! - Returns \c true if format option \a opt is set; otherwise returns \c false. + \obsolete + \overload + + Use testOption(QSurfaceFormat::FormatOption) instead. + + Returns \c true if any of the options in \a opt is currently set + on this object; otherwise returns false. \sa setOption() */ @@ -335,6 +350,63 @@ bool QSurfaceFormat::testOption(QSurfaceFormat::FormatOptions opt) const } /*! + \since 5.3 + + Sets the format options to \a options. + + \sa options(), testOption() +*/ +void QSurfaceFormat::setOptions(QSurfaceFormat::FormatOptions options) +{ + if (int(d->opts) != int(options)) { + detach(); + d->opts = options; + } +} + +/*! + \since 5.3 + + Sets the format option \a option if \a on is true; otherwise, clears the option. + + \sa setOptions(), options(), testOption() +*/ +void QSurfaceFormat::setOption(QSurfaceFormat::FormatOption option, bool on) +{ + if (testOption(option) == on) + return; + detach(); + if (on) + d->opts |= option; + else + d->opts &= ~option; +} + +/*! + \since 5.3 + + Returns true if the format option \a option is set; otherwise returns false. + + \sa options(), testOption() +*/ +bool QSurfaceFormat::testOption(QSurfaceFormat::FormatOption option) const +{ + return d->opts & option; +} + +/*! + \since 5.3 + + Returns the currently set format options. + + \sa setOption(), setOptions(), testOption() +*/ +QSurfaceFormat::FormatOptions QSurfaceFormat::options() const +{ + return d->opts; +} + +/*! Set the minimum depth buffer size to \a size. \sa depthBufferSize() @@ -607,6 +679,46 @@ void QSurfaceFormat::setVersion(int major, int minor) } /*! + Sets the preferred swap interval. The swap interval specifies the + minimum number of video frames that are displayed before a buffer + swap occurs. This can be used to sync the GL drawing into a window + to the vertical refresh of the screen. + + Setting an \a interval value of 0 will turn the vertical refresh + syncing off, any value higher than 0 will turn the vertical + syncing on. Setting \a interval to a higher value, for example 10, + results in having 10 vertical retraces between every buffer swap. + + The default interval is 1. + + Changing the swap interval may not be supported by the underlying + platform. In this case, the request will be silently ignored. + + \since 5.3 + + \sa swapInterval() + */ +void QSurfaceFormat::setSwapInterval(int interval) +{ + if (d->swapInterval != interval) { + detach(); + d->swapInterval = interval; + } +} + +/*! + Returns the swap interval. + + \since 5.3 + + \sa setSwapInterval() +*/ +int QSurfaceFormat::swapInterval() const +{ + return d->swapInterval; +} + +/*! Returns \c true if all the options of the two QSurfaceFormat objects \a a and \a b are equal. @@ -625,7 +737,8 @@ bool operator==(const QSurfaceFormat& a, const QSurfaceFormat& b) && a.d->swapBehavior == b.d->swapBehavior && a.d->profile == b.d->profile && a.d->major == b.d->major - && a.d->minor == b.d->minor); + && a.d->minor == b.d->minor + && a.d->swapInterval == b.d->swapInterval); } /*! @@ -655,6 +768,7 @@ QDebug operator<<(QDebug dbg, const QSurfaceFormat &f) << ", stencilBufferSize " << d->stencilSize << ", samples " << d->numSamples << ", swapBehavior " << d->swapBehavior + << ", swapInterval " << d->swapInterval << ", profile " << d->profile << ')'; diff --git a/src/gui/kernel/qsurfaceformat.h b/src/gui/kernel/qsurfaceformat.h index 7c3c846df3..453beac5cd 100644 --- a/src/gui/kernel/qsurfaceformat.h +++ b/src/gui/kernel/qsurfaceformat.h @@ -127,8 +127,16 @@ public: bool stereo() const; void setStereo(bool enable); - void setOption(QSurfaceFormat::FormatOptions opt); - bool testOption(QSurfaceFormat::FormatOptions opt) const; + QT_DEPRECATED void setOption(QSurfaceFormat::FormatOptions opt); + QT_DEPRECATED bool testOption(QSurfaceFormat::FormatOptions opt) const; + + void setOptions(QSurfaceFormat::FormatOptions options); + void setOption(FormatOption option, bool on = true); + bool testOption(FormatOption option) const; + QSurfaceFormat::FormatOptions options() const; + + int swapInterval() const; + void setSwapInterval(int interval); private: QSurfaceFormatPrivate *d; diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 19bd947c2c..51548aa371 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -163,9 +163,7 @@ QWindow::QWindow(QScreen *targetScreen) //if your applications aborts here, then chances are your creating a QWindow before the //screen list is populated. Q_ASSERT(d->screen); - - connect(d->screen, SIGNAL(destroyed(QObject*)), this, SLOT(screenDestroyed(QObject*))); - QGuiApplicationPrivate::window_list.prepend(this); + d->init(); } /*! @@ -188,8 +186,7 @@ QWindow::QWindow(QWindow *parent) d->screen = parent->screen(); if (!d->screen) d->screen = QGuiApplication::primaryScreen(); - connect(d->screen, SIGNAL(destroyed(QObject*)), this, SLOT(screenDestroyed(QObject*))); - QGuiApplicationPrivate::window_list.prepend(this); + d->init(); } /*! @@ -214,8 +211,7 @@ QWindow::QWindow(QWindowPrivate &dd, QWindow *parent) d->screen = parent->screen(); if (!d->screen) d->screen = QGuiApplication::primaryScreen(); - connect(d->screen, SIGNAL(destroyed(QObject*)), this, SLOT(screenDestroyed(QObject*))); - QGuiApplicationPrivate::window_list.prepend(this); + d->init(); } /*! @@ -233,6 +229,13 @@ QWindow::~QWindow() destroy(); } +void QWindowPrivate::init() +{ + Q_Q(QWindow); + QObject::connect(screen, SIGNAL(destroyed(QObject*)), q, SLOT(screenDestroyed(QObject*))); + QGuiApplicationPrivate::window_list.prepend(q); +} + /*! \enum QWindow::Visibility \since 5.1 @@ -429,6 +432,14 @@ void QWindow::setVisible(bool visible) // remove posted quit events when showing a new window QCoreApplication::removePostedEvents(qApp, QEvent::Quit); + if (type() == Qt::Window) { + QString &firstWindowTitle = QGuiApplicationPrivate::instance()->firstWindowTitle; + if (!firstWindowTitle.isEmpty()) { + setTitle(firstWindowTitle); + firstWindowTitle = QString(); + } + } + QShowEvent showEvent; QGuiApplication::sendEvent(this, &showEvent); } @@ -765,6 +776,8 @@ void QWindow::setIcon(const QIcon &icon) d->windowIcon = icon; if (d->platformWindow) d->platformWindow->setWindowIcon(icon); + QEvent e(QEvent::WindowIconChange); + QCoreApplication::sendEvent(this, &e); } /*! @@ -775,6 +788,8 @@ void QWindow::setIcon(const QIcon &icon) QIcon QWindow::icon() const { Q_D(const QWindow); + if (d->windowIcon.isNull()) + return QGuiApplication::windowIcon(); return d->windowIcon; } @@ -1929,6 +1944,10 @@ bool QWindow::event(QEvent *ev) hideEvent(static_cast<QHideEvent *>(ev)); break; + case QEvent::ApplicationWindowIconChange: + setIcon(icon()); + break; + case QEvent::WindowStateChange: { Q_D(QWindow); emit windowStateChanged(d->windowState); @@ -2147,6 +2166,26 @@ void QWindowPrivate::maybeQuitOnLastWindowClosed() } +QWindow *QWindowPrivate::topLevelWindow() const +{ + Q_Q(const QWindow); + + QWindow *window = const_cast<QWindow *>(q); + + while (window) { + QWindow *parent = window->parent(); + if (!parent) + parent = window->transientParent(); + + if (!parent) + break; + + window = parent; + } + + return window; +} + /*! Creates a local representation of a window created by another process or by using native libraries below Qt. diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 8d8fca3ce6..4305edea51 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -108,6 +108,8 @@ public: { } + void init(); + void maybeQuitOnLastWindowClosed(); #ifndef QT_NO_CURSOR void setCursor(const QCursor *c = 0); @@ -122,6 +124,8 @@ public: return offset; } + QWindow *topLevelWindow() const; + virtual QWindow *eventReceiver() { Q_Q(QWindow); return q; } void updateVisibility(); diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 8ef275a27c..49ff8bcb0d 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -164,31 +164,35 @@ void QWindowSystemInterface::handleCloseEvent(QWindow *tlw, bool *accepted) \a w == 0 means that the event is in global coords only, \a local will be ignored in this case */ -void QWindowSystemInterface::handleMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods) +void QWindowSystemInterface::handleMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, + Qt::KeyboardModifiers mods, Qt::MouseEventSource source) { unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed(); - handleMouseEvent(w, time, local, global, b, mods); + handleMouseEvent(w, time, local, global, b, mods, source); } -void QWindowSystemInterface::handleMouseEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods) +void QWindowSystemInterface::handleMouseEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b, + Qt::KeyboardModifiers mods, Qt::MouseEventSource source) { QWindowSystemInterfacePrivate::MouseEvent * e = - new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp, local, global, b, mods); + new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp, local, global, b, mods, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } -void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods) +void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, + Qt::KeyboardModifiers mods, Qt::MouseEventSource source) { const unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed(); - handleFrameStrutMouseEvent(w, time, local, global, b, mods); + handleFrameStrutMouseEvent(w, time, local, global, b, mods, source); } -void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods) +void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b, + Qt::KeyboardModifiers mods, Qt::MouseEventSource source) { QWindowSystemInterfacePrivate::MouseEvent * e = new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp, QWindowSystemInterfacePrivate::FrameStrutMouse, - local, global, b, mods); + local, global, b, mods, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index d1c3c8e249..71feb1bcb7 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -73,10 +73,18 @@ class QPlatformDropQtResponse; class Q_GUI_EXPORT QWindowSystemInterface { public: - static void handleMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier); - static void handleMouseEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier); - static void handleFrameStrutMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier); - static void handleFrameStrutMouseEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier); + static void handleMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, + Qt::KeyboardModifiers mods = Qt::NoModifier, + Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); + static void handleMouseEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b, + Qt::KeyboardModifiers mods = Qt::NoModifier, + Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); + static void handleFrameStrutMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, + Qt::KeyboardModifiers mods = Qt::NoModifier, + Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); + static void handleFrameStrutMouseEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b, + Qt::KeyboardModifiers mods = Qt::NoModifier, + Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); static bool tryHandleShortcutEvent(QWindow *w, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1); diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h index 42dbe7509e..8e503bbf3d 100644 --- a/src/gui/kernel/qwindowsysteminterface_p.h +++ b/src/gui/kernel/qwindowsysteminterface_p.h @@ -209,14 +209,17 @@ public: class MouseEvent : public InputEvent { public: MouseEvent(QWindow * w, ulong time, const QPointF & local, const QPointF & global, - Qt::MouseButtons b, Qt::KeyboardModifiers mods) - : InputEvent(w, time, Mouse, mods), localPos(local), globalPos(global), buttons(b) { } + Qt::MouseButtons b, Qt::KeyboardModifiers mods, + Qt::MouseEventSource src = Qt::MouseEventNotSynthesized) + : InputEvent(w, time, Mouse, mods), localPos(local), globalPos(global), buttons(b), source(src) { } MouseEvent(QWindow * w, ulong time, EventType t, const QPointF & local, const QPointF & global, - Qt::MouseButtons b, Qt::KeyboardModifiers mods) - : InputEvent(w, time, t, mods), localPos(local), globalPos(global), buttons(b) { } + Qt::MouseButtons b, Qt::KeyboardModifiers mods, + Qt::MouseEventSource src = Qt::MouseEventNotSynthesized) + : InputEvent(w, time, t, mods), localPos(local), globalPos(global), buttons(b), source(src) { } QPointF localPos; QPointF globalPos; Qt::MouseButtons buttons; + Qt::MouseEventSource source; }; class WheelEvent : public InputEvent { diff --git a/src/gui/math3d/qvector2d.h b/src/gui/math3d/qvector2d.h index 55e606ec35..649d45d477 100644 --- a/src/gui/math3d/qvector2d.h +++ b/src/gui/math3d/qvector2d.h @@ -57,10 +57,10 @@ class QVariant; class Q_GUI_EXPORT QVector2D { public: - QVector2D(); - QVector2D(float xpos, float ypos); - explicit QVector2D(const QPoint& point); - explicit QVector2D(const QPointF& point); + Q_DECL_CONSTEXPR QVector2D(); + Q_DECL_CONSTEXPR QVector2D(float xpos, float ypos); + Q_DECL_CONSTEXPR explicit QVector2D(const QPoint& point); + Q_DECL_CONSTEXPR explicit QVector2D(const QPointF& point); #ifndef QT_NO_VECTOR3D explicit QVector2D(const QVector3D& vector); #endif @@ -70,8 +70,8 @@ public: bool isNull() const; - float x() const; - float y() const; + Q_DECL_CONSTEXPR float x() const; + Q_DECL_CONSTEXPR float y() const; void setX(float x); void setY(float y); @@ -80,7 +80,12 @@ public: float operator[](int i) const; float length() const; +#ifdef QT_BUILD_GUI_LIB float lengthSquared() const; +#else + Q_DECL_CONSTEXPR inline float lengthSquared() const + { return xp * xp + yp * yp; } +#endif QVector2D normalized() const; void normalize(); @@ -94,19 +99,24 @@ public: QVector2D &operator*=(const QVector2D &vector); QVector2D &operator/=(float divisor); +#ifdef QT_BUILD_GUI_LIB static float dotProduct(const QVector2D& v1, const QVector2D& v2); +#else + Q_DECL_CONSTEXPR inline static float dotProduct(const QVector2D& v1, const QVector2D& v2) + { return v1.xp * v2.xp + v1.yp * v2.yp; } +#endif - friend inline bool operator==(const QVector2D &v1, const QVector2D &v2); - friend inline bool operator!=(const QVector2D &v1, const QVector2D &v2); - friend inline const QVector2D operator+(const QVector2D &v1, const QVector2D &v2); - friend inline const QVector2D operator-(const QVector2D &v1, const QVector2D &v2); - friend inline const QVector2D operator*(float factor, const QVector2D &vector); - friend inline const QVector2D operator*(const QVector2D &vector, float factor); - friend inline const QVector2D operator*(const QVector2D &v1, const QVector2D &v2); - friend inline const QVector2D operator-(const QVector2D &vector); - friend inline const QVector2D operator/(const QVector2D &vector, float divisor); + Q_DECL_CONSTEXPR friend inline bool operator==(const QVector2D &v1, const QVector2D &v2); + Q_DECL_CONSTEXPR friend inline bool operator!=(const QVector2D &v1, const QVector2D &v2); + Q_DECL_CONSTEXPR friend inline const QVector2D operator+(const QVector2D &v1, const QVector2D &v2); + Q_DECL_CONSTEXPR friend inline const QVector2D operator-(const QVector2D &v1, const QVector2D &v2); + Q_DECL_CONSTEXPR friend inline const QVector2D operator*(float factor, const QVector2D &vector); + Q_DECL_CONSTEXPR friend inline const QVector2D operator*(const QVector2D &vector, float factor); + Q_DECL_CONSTEXPR friend inline const QVector2D operator*(const QVector2D &v1, const QVector2D &v2); + Q_DECL_CONSTEXPR friend inline const QVector2D operator-(const QVector2D &vector); + Q_DECL_CONSTEXPR friend inline const QVector2D operator/(const QVector2D &vector, float divisor); - friend inline bool qFuzzyCompare(const QVector2D& v1, const QVector2D& v2); + Q_DECL_CONSTEXPR friend inline bool qFuzzyCompare(const QVector2D& v1, const QVector2D& v2); #ifndef QT_NO_VECTOR3D QVector3D toVector3D() const; @@ -115,8 +125,8 @@ public: QVector4D toVector4D() const; #endif - QPoint toPoint() const; - QPointF toPointF() const; + Q_DECL_CONSTEXPR QPoint toPoint() const; + Q_DECL_CONSTEXPR QPointF toPointF() const; operator QVariant() const; @@ -129,21 +139,21 @@ private: Q_DECLARE_TYPEINFO(QVector2D, Q_MOVABLE_TYPE); -inline QVector2D::QVector2D() : xp(0.0f), yp(0.0f) {} +Q_DECL_CONSTEXPR inline QVector2D::QVector2D() : xp(0.0f), yp(0.0f) {} -inline QVector2D::QVector2D(float xpos, float ypos) : xp(xpos), yp(ypos) {} +Q_DECL_CONSTEXPR inline QVector2D::QVector2D(float xpos, float ypos) : xp(xpos), yp(ypos) {} -inline QVector2D::QVector2D(const QPoint& point) : xp(point.x()), yp(point.y()) {} +Q_DECL_CONSTEXPR inline QVector2D::QVector2D(const QPoint& point) : xp(point.x()), yp(point.y()) {} -inline QVector2D::QVector2D(const QPointF& point) : xp(point.x()), yp(point.y()) {} +Q_DECL_CONSTEXPR inline QVector2D::QVector2D(const QPointF& point) : xp(point.x()), yp(point.y()) {} inline bool QVector2D::isNull() const { return qIsNull(xp) && qIsNull(yp); } -inline float QVector2D::x() const { return xp; } -inline float QVector2D::y() const { return yp; } +Q_DECL_CONSTEXPR inline float QVector2D::x() const { return xp; } +Q_DECL_CONSTEXPR inline float QVector2D::y() const { return yp; } inline void QVector2D::setX(float aX) { xp = aX; } inline void QVector2D::setY(float aY) { yp = aY; } @@ -195,62 +205,62 @@ inline QVector2D &QVector2D::operator/=(float divisor) return *this; } -inline bool operator==(const QVector2D &v1, const QVector2D &v2) +Q_DECL_CONSTEXPR inline bool operator==(const QVector2D &v1, const QVector2D &v2) { return v1.xp == v2.xp && v1.yp == v2.yp; } -inline bool operator!=(const QVector2D &v1, const QVector2D &v2) +Q_DECL_CONSTEXPR inline bool operator!=(const QVector2D &v1, const QVector2D &v2) { return v1.xp != v2.xp || v1.yp != v2.yp; } -inline const QVector2D operator+(const QVector2D &v1, const QVector2D &v2) +Q_DECL_CONSTEXPR inline const QVector2D operator+(const QVector2D &v1, const QVector2D &v2) { return QVector2D(v1.xp + v2.xp, v1.yp + v2.yp); } -inline const QVector2D operator-(const QVector2D &v1, const QVector2D &v2) +Q_DECL_CONSTEXPR inline const QVector2D operator-(const QVector2D &v1, const QVector2D &v2) { return QVector2D(v1.xp - v2.xp, v1.yp - v2.yp); } -inline const QVector2D operator*(float factor, const QVector2D &vector) +Q_DECL_CONSTEXPR inline const QVector2D operator*(float factor, const QVector2D &vector) { return QVector2D(vector.xp * factor, vector.yp * factor); } -inline const QVector2D operator*(const QVector2D &vector, float factor) +Q_DECL_CONSTEXPR inline const QVector2D operator*(const QVector2D &vector, float factor) { return QVector2D(vector.xp * factor, vector.yp * factor); } -inline const QVector2D operator*(const QVector2D &v1, const QVector2D &v2) +Q_DECL_CONSTEXPR inline const QVector2D operator*(const QVector2D &v1, const QVector2D &v2) { return QVector2D(v1.xp * v2.xp, v1.yp * v2.yp); } -inline const QVector2D operator-(const QVector2D &vector) +Q_DECL_CONSTEXPR inline const QVector2D operator-(const QVector2D &vector) { return QVector2D(-vector.xp, -vector.yp); } -inline const QVector2D operator/(const QVector2D &vector, float divisor) +Q_DECL_CONSTEXPR inline const QVector2D operator/(const QVector2D &vector, float divisor) { return QVector2D(vector.xp / divisor, vector.yp / divisor); } -inline bool qFuzzyCompare(const QVector2D& v1, const QVector2D& v2) +Q_DECL_CONSTEXPR inline bool qFuzzyCompare(const QVector2D& v1, const QVector2D& v2) { return qFuzzyCompare(v1.xp, v2.xp) && qFuzzyCompare(v1.yp, v2.yp); } -inline QPoint QVector2D::toPoint() const +Q_DECL_CONSTEXPR inline QPoint QVector2D::toPoint() const { return QPoint(qRound(xp), qRound(yp)); } -inline QPointF QVector2D::toPointF() const +Q_DECL_CONSTEXPR inline QPointF QVector2D::toPointF() const { return QPointF(qreal(xp), qreal(yp)); } diff --git a/src/gui/math3d/qvector3d.h b/src/gui/math3d/qvector3d.h index c880930935..c5506bf1ac 100644 --- a/src/gui/math3d/qvector3d.h +++ b/src/gui/math3d/qvector3d.h @@ -57,10 +57,11 @@ class QVector4D; class Q_GUI_EXPORT QVector3D { public: - QVector3D(); - QVector3D(float xpos, float ypos, float zpos); - explicit QVector3D(const QPoint& point); - explicit QVector3D(const QPointF& point); + Q_DECL_CONSTEXPR QVector3D(); + Q_DECL_CONSTEXPR QVector3D(float xpos, float ypos, float zpos) : xp(xpos), yp(ypos), zp(zpos) {} + + Q_DECL_CONSTEXPR explicit QVector3D(const QPoint& point); + Q_DECL_CONSTEXPR explicit QVector3D(const QPointF& point); #ifndef QT_NO_VECTOR2D QVector3D(const QVector2D& vector); QVector3D(const QVector2D& vector, float zpos); @@ -71,9 +72,9 @@ public: bool isNull() const; - float x() const; - float y() const; - float z() const; + Q_DECL_CONSTEXPR float x() const; + Q_DECL_CONSTEXPR float y() const; + Q_DECL_CONSTEXPR float z() const; void setX(float x); void setY(float y); @@ -94,8 +95,17 @@ public: QVector3D &operator*=(const QVector3D& vector); QVector3D &operator/=(float divisor); +#ifdef QT_BUILD_GUI_LIB static float dotProduct(const QVector3D& v1, const QVector3D& v2); static QVector3D crossProduct(const QVector3D& v1, const QVector3D& v2); +#else + Q_DECL_CONSTEXPR inline static float dotProduct(const QVector3D& v1, const QVector3D& v2) + { return v1.xp * v2.xp + v1.yp * v2.yp + v1.zp * v2.zp; } + Q_DECL_CONSTEXPR inline static QVector3D crossProduct(const QVector3D& v1, const QVector3D& v2) + { return QVector3D(v1.yp * v2.zp - v1.zp * v2.yp, + v1.zp * v2.xp - v1.xp * v2.zp, + v1.xp * v2.yp - v1.yp * v2.xp); } +#endif static QVector3D normal(const QVector3D& v1, const QVector3D& v2); static QVector3D normal (const QVector3D& v1, const QVector3D& v2, const QVector3D& v3); @@ -105,17 +115,17 @@ public: float distanceToPlane(const QVector3D& plane1, const QVector3D& plane2, const QVector3D& plane3) const; float distanceToLine(const QVector3D& point, const QVector3D& direction) const; - friend inline bool operator==(const QVector3D &v1, const QVector3D &v2); - friend inline bool operator!=(const QVector3D &v1, const QVector3D &v2); - friend inline const QVector3D operator+(const QVector3D &v1, const QVector3D &v2); - friend inline const QVector3D operator-(const QVector3D &v1, const QVector3D &v2); - friend inline const QVector3D operator*(float factor, const QVector3D &vector); - friend inline const QVector3D operator*(const QVector3D &vector, float factor); - friend const QVector3D operator*(const QVector3D &v1, const QVector3D& v2); - friend inline const QVector3D operator-(const QVector3D &vector); - friend inline const QVector3D operator/(const QVector3D &vector, float divisor); + Q_DECL_CONSTEXPR friend inline bool operator==(const QVector3D &v1, const QVector3D &v2); + Q_DECL_CONSTEXPR friend inline bool operator!=(const QVector3D &v1, const QVector3D &v2); + Q_DECL_CONSTEXPR friend inline const QVector3D operator+(const QVector3D &v1, const QVector3D &v2); + Q_DECL_CONSTEXPR friend inline const QVector3D operator-(const QVector3D &v1, const QVector3D &v2); + Q_DECL_CONSTEXPR friend inline const QVector3D operator*(float factor, const QVector3D &vector); + Q_DECL_CONSTEXPR friend inline const QVector3D operator*(const QVector3D &vector, float factor); + Q_DECL_CONSTEXPR friend const QVector3D operator*(const QVector3D &v1, const QVector3D& v2); + Q_DECL_CONSTEXPR friend inline const QVector3D operator-(const QVector3D &vector); + Q_DECL_CONSTEXPR friend inline const QVector3D operator/(const QVector3D &vector, float divisor); - friend inline bool qFuzzyCompare(const QVector3D& v1, const QVector3D& v2); + Q_DECL_CONSTEXPR friend inline bool qFuzzyCompare(const QVector3D& v1, const QVector3D& v2); #ifndef QT_NO_VECTOR2D QVector2D toVector2D() const; @@ -124,8 +134,8 @@ public: QVector4D toVector4D() const; #endif - QPoint toPoint() const; - QPointF toPointF() const; + Q_DECL_CONSTEXPR QPoint toPoint() const; + Q_DECL_CONSTEXPR QPointF toPointF() const; operator QVariant() const; @@ -142,22 +152,20 @@ private: Q_DECLARE_TYPEINFO(QVector3D, Q_MOVABLE_TYPE); -inline QVector3D::QVector3D() : xp(0.0f), yp(0.0f), zp(0.0f) {} - -inline QVector3D::QVector3D(float xpos, float ypos, float zpos) : xp(xpos), yp(ypos), zp(zpos) {} +Q_DECL_CONSTEXPR inline QVector3D::QVector3D() : xp(0.0f), yp(0.0f), zp(0.0f) {} -inline QVector3D::QVector3D(const QPoint& point) : xp(point.x()), yp(point.y()), zp(0.0f) {} +Q_DECL_CONSTEXPR inline QVector3D::QVector3D(const QPoint& point) : xp(point.x()), yp(point.y()), zp(0.0f) {} -inline QVector3D::QVector3D(const QPointF& point) : xp(point.x()), yp(point.y()), zp(0.0f) {} +Q_DECL_CONSTEXPR inline QVector3D::QVector3D(const QPointF& point) : xp(point.x()), yp(point.y()), zp(0.0f) {} inline bool QVector3D::isNull() const { return qIsNull(xp) && qIsNull(yp) && qIsNull(zp); } -inline float QVector3D::x() const { return xp; } -inline float QVector3D::y() const { return yp; } -inline float QVector3D::z() const { return zp; } +Q_DECL_CONSTEXPR inline float QVector3D::x() const { return xp; } +Q_DECL_CONSTEXPR inline float QVector3D::y() const { return yp; } +Q_DECL_CONSTEXPR inline float QVector3D::z() const { return zp; } inline void QVector3D::setX(float aX) { xp = aX; } inline void QVector3D::setY(float aY) { yp = aY; } @@ -215,64 +223,64 @@ inline QVector3D &QVector3D::operator/=(float divisor) return *this; } -inline bool operator==(const QVector3D &v1, const QVector3D &v2) +Q_DECL_CONSTEXPR inline bool operator==(const QVector3D &v1, const QVector3D &v2) { return v1.xp == v2.xp && v1.yp == v2.yp && v1.zp == v2.zp; } -inline bool operator!=(const QVector3D &v1, const QVector3D &v2) +Q_DECL_CONSTEXPR inline bool operator!=(const QVector3D &v1, const QVector3D &v2) { return v1.xp != v2.xp || v1.yp != v2.yp || v1.zp != v2.zp; } -inline const QVector3D operator+(const QVector3D &v1, const QVector3D &v2) +Q_DECL_CONSTEXPR inline const QVector3D operator+(const QVector3D &v1, const QVector3D &v2) { return QVector3D(v1.xp + v2.xp, v1.yp + v2.yp, v1.zp + v2.zp); } -inline const QVector3D operator-(const QVector3D &v1, const QVector3D &v2) +Q_DECL_CONSTEXPR inline const QVector3D operator-(const QVector3D &v1, const QVector3D &v2) { return QVector3D(v1.xp - v2.xp, v1.yp - v2.yp, v1.zp - v2.zp); } -inline const QVector3D operator*(float factor, const QVector3D &vector) +Q_DECL_CONSTEXPR inline const QVector3D operator*(float factor, const QVector3D &vector) { return QVector3D(vector.xp * factor, vector.yp * factor, vector.zp * factor); } -inline const QVector3D operator*(const QVector3D &vector, float factor) +Q_DECL_CONSTEXPR inline const QVector3D operator*(const QVector3D &vector, float factor) { return QVector3D(vector.xp * factor, vector.yp * factor, vector.zp * factor); } -inline const QVector3D operator*(const QVector3D &v1, const QVector3D& v2) +Q_DECL_CONSTEXPR inline const QVector3D operator*(const QVector3D &v1, const QVector3D& v2) { return QVector3D(v1.xp * v2.xp, v1.yp * v2.yp, v1.zp * v2.zp); } -inline const QVector3D operator-(const QVector3D &vector) +Q_DECL_CONSTEXPR inline const QVector3D operator-(const QVector3D &vector) { return QVector3D(-vector.xp, -vector.yp, -vector.zp); } -inline const QVector3D operator/(const QVector3D &vector, float divisor) +Q_DECL_CONSTEXPR inline const QVector3D operator/(const QVector3D &vector, float divisor) { return QVector3D(vector.xp / divisor, vector.yp / divisor, vector.zp / divisor); } -inline bool qFuzzyCompare(const QVector3D& v1, const QVector3D& v2) +Q_DECL_CONSTEXPR inline bool qFuzzyCompare(const QVector3D& v1, const QVector3D& v2) { return qFuzzyCompare(v1.xp, v2.xp) && qFuzzyCompare(v1.yp, v2.yp) && qFuzzyCompare(v1.zp, v2.zp); } -inline QPoint QVector3D::toPoint() const +Q_DECL_CONSTEXPR inline QPoint QVector3D::toPoint() const { return QPoint(qRound(xp), qRound(yp)); } -inline QPointF QVector3D::toPointF() const +Q_DECL_CONSTEXPR inline QPointF QVector3D::toPointF() const { return QPointF(qreal(xp), qreal(yp)); } diff --git a/src/gui/math3d/qvector4d.h b/src/gui/math3d/qvector4d.h index 810380b805..1256f384a0 100644 --- a/src/gui/math3d/qvector4d.h +++ b/src/gui/math3d/qvector4d.h @@ -57,10 +57,10 @@ class QVector3D; class Q_GUI_EXPORT QVector4D { public: - QVector4D(); - QVector4D(float xpos, float ypos, float zpos, float wpos); - explicit QVector4D(const QPoint& point); - explicit QVector4D(const QPointF& point); + Q_DECL_CONSTEXPR QVector4D(); + Q_DECL_CONSTEXPR QVector4D(float xpos, float ypos, float zpos, float wpos); + Q_DECL_CONSTEXPR explicit QVector4D(const QPoint& point); + Q_DECL_CONSTEXPR explicit QVector4D(const QPointF& point); #ifndef QT_NO_VECTOR2D QVector4D(const QVector2D& vector); QVector4D(const QVector2D& vector, float zpos, float wpos); @@ -72,10 +72,10 @@ public: bool isNull() const; - float x() const; - float y() const; - float z() const; - float w() const; + Q_DECL_CONSTEXPR float x() const; + Q_DECL_CONSTEXPR float y() const; + Q_DECL_CONSTEXPR float z() const; + Q_DECL_CONSTEXPR float w() const; void setX(float x); void setY(float y); @@ -86,7 +86,12 @@ public: float operator[](int i) const; float length() const; +#ifdef QT_BUILD_GUI_LIB float lengthSquared() const; +#else + Q_DECL_CONSTEXPR inline float lengthSquared() const + { return xp * xp + yp * yp + zp * zp + wp * wp; } +#endif QVector4D normalized() const; void normalize(); @@ -97,19 +102,24 @@ public: QVector4D &operator*=(const QVector4D &vector); QVector4D &operator/=(float divisor); +#ifdef QT_BUILD_GUI_LIB static float dotProduct(const QVector4D& v1, const QVector4D& v2); +#else + static float dotProduct(const QVector4D& v1, const QVector4D& v2) + { return v1.xp * v2.xp + v1.yp * v2.yp + v1.zp * v2.zp + v1.wp * v2.wp; } +#endif - friend inline bool operator==(const QVector4D &v1, const QVector4D &v2); - friend inline bool operator!=(const QVector4D &v1, const QVector4D &v2); - friend inline const QVector4D operator+(const QVector4D &v1, const QVector4D &v2); - friend inline const QVector4D operator-(const QVector4D &v1, const QVector4D &v2); - friend inline const QVector4D operator*(float factor, const QVector4D &vector); - friend inline const QVector4D operator*(const QVector4D &vector, float factor); - friend inline const QVector4D operator*(const QVector4D &v1, const QVector4D& v2); - friend inline const QVector4D operator-(const QVector4D &vector); - friend inline const QVector4D operator/(const QVector4D &vector, float divisor); + Q_DECL_CONSTEXPR friend inline bool operator==(const QVector4D &v1, const QVector4D &v2); + Q_DECL_CONSTEXPR friend inline bool operator!=(const QVector4D &v1, const QVector4D &v2); + Q_DECL_CONSTEXPR friend inline const QVector4D operator+(const QVector4D &v1, const QVector4D &v2); + Q_DECL_CONSTEXPR friend inline const QVector4D operator-(const QVector4D &v1, const QVector4D &v2); + Q_DECL_CONSTEXPR friend inline const QVector4D operator*(float factor, const QVector4D &vector); + Q_DECL_CONSTEXPR friend inline const QVector4D operator*(const QVector4D &vector, float factor); + Q_DECL_CONSTEXPR friend inline const QVector4D operator*(const QVector4D &v1, const QVector4D& v2); + Q_DECL_CONSTEXPR friend inline const QVector4D operator-(const QVector4D &vector); + Q_DECL_CONSTEXPR friend inline const QVector4D operator/(const QVector4D &vector, float divisor); - friend inline bool qFuzzyCompare(const QVector4D& v1, const QVector4D& v2); + Q_DECL_CONSTEXPR friend inline bool qFuzzyCompare(const QVector4D& v1, const QVector4D& v2); #ifndef QT_NO_VECTOR2D QVector2D toVector2D() const; @@ -120,8 +130,8 @@ public: QVector3D toVector3DAffine() const; #endif - QPoint toPoint() const; - QPointF toPointF() const; + Q_DECL_CONSTEXPR QPoint toPoint() const; + Q_DECL_CONSTEXPR QPointF toPointF() const; operator QVariant() const; @@ -138,23 +148,23 @@ private: Q_DECLARE_TYPEINFO(QVector4D, Q_MOVABLE_TYPE); -inline QVector4D::QVector4D() : xp(0.0f), yp(0.0f), zp(0.0f), wp(0.0f) {} +Q_DECL_CONSTEXPR inline QVector4D::QVector4D() : xp(0.0f), yp(0.0f), zp(0.0f), wp(0.0f) {} -inline QVector4D::QVector4D(float xpos, float ypos, float zpos, float wpos) : xp(xpos), yp(ypos), zp(zpos), wp(wpos) {} +Q_DECL_CONSTEXPR inline QVector4D::QVector4D(float xpos, float ypos, float zpos, float wpos) : xp(xpos), yp(ypos), zp(zpos), wp(wpos) {} -inline QVector4D::QVector4D(const QPoint& point) : xp(point.x()), yp(point.y()), zp(0.0f), wp(0.0f) {} +Q_DECL_CONSTEXPR inline QVector4D::QVector4D(const QPoint& point) : xp(point.x()), yp(point.y()), zp(0.0f), wp(0.0f) {} -inline QVector4D::QVector4D(const QPointF& point) : xp(point.x()), yp(point.y()), zp(0.0f), wp(0.0f) {} +Q_DECL_CONSTEXPR inline QVector4D::QVector4D(const QPointF& point) : xp(point.x()), yp(point.y()), zp(0.0f), wp(0.0f) {} inline bool QVector4D::isNull() const { return qIsNull(xp) && qIsNull(yp) && qIsNull(zp) && qIsNull(wp); } -inline float QVector4D::x() const { return xp; } -inline float QVector4D::y() const { return yp; } -inline float QVector4D::z() const { return zp; } -inline float QVector4D::w() const { return wp; } +Q_DECL_CONSTEXPR inline float QVector4D::x() const { return xp; } +Q_DECL_CONSTEXPR inline float QVector4D::y() const { return yp; } +Q_DECL_CONSTEXPR inline float QVector4D::z() const { return zp; } +Q_DECL_CONSTEXPR inline float QVector4D::w() const { return wp; } inline void QVector4D::setX(float aX) { xp = aX; } inline void QVector4D::setY(float aY) { yp = aY; } @@ -218,52 +228,52 @@ inline QVector4D &QVector4D::operator/=(float divisor) return *this; } -inline bool operator==(const QVector4D &v1, const QVector4D &v2) +Q_DECL_CONSTEXPR inline bool operator==(const QVector4D &v1, const QVector4D &v2) { return v1.xp == v2.xp && v1.yp == v2.yp && v1.zp == v2.zp && v1.wp == v2.wp; } -inline bool operator!=(const QVector4D &v1, const QVector4D &v2) +Q_DECL_CONSTEXPR inline bool operator!=(const QVector4D &v1, const QVector4D &v2) { return v1.xp != v2.xp || v1.yp != v2.yp || v1.zp != v2.zp || v1.wp != v2.wp; } -inline const QVector4D operator+(const QVector4D &v1, const QVector4D &v2) +Q_DECL_CONSTEXPR inline const QVector4D operator+(const QVector4D &v1, const QVector4D &v2) { return QVector4D(v1.xp + v2.xp, v1.yp + v2.yp, v1.zp + v2.zp, v1.wp + v2.wp); } -inline const QVector4D operator-(const QVector4D &v1, const QVector4D &v2) +Q_DECL_CONSTEXPR inline const QVector4D operator-(const QVector4D &v1, const QVector4D &v2) { return QVector4D(v1.xp - v2.xp, v1.yp - v2.yp, v1.zp - v2.zp, v1.wp - v2.wp); } -inline const QVector4D operator*(float factor, const QVector4D &vector) +Q_DECL_CONSTEXPR inline const QVector4D operator*(float factor, const QVector4D &vector) { return QVector4D(vector.xp * factor, vector.yp * factor, vector.zp * factor, vector.wp * factor); } -inline const QVector4D operator*(const QVector4D &vector, float factor) +Q_DECL_CONSTEXPR inline const QVector4D operator*(const QVector4D &vector, float factor) { return QVector4D(vector.xp * factor, vector.yp * factor, vector.zp * factor, vector.wp * factor); } -inline const QVector4D operator*(const QVector4D &v1, const QVector4D& v2) +Q_DECL_CONSTEXPR inline const QVector4D operator*(const QVector4D &v1, const QVector4D& v2) { return QVector4D(v1.xp * v2.xp, v1.yp * v2.yp, v1.zp * v2.zp, v1.wp * v2.wp); } -inline const QVector4D operator-(const QVector4D &vector) +Q_DECL_CONSTEXPR inline const QVector4D operator-(const QVector4D &vector) { return QVector4D(-vector.xp, -vector.yp, -vector.zp, -vector.wp); } -inline const QVector4D operator/(const QVector4D &vector, float divisor) +Q_DECL_CONSTEXPR inline const QVector4D operator/(const QVector4D &vector, float divisor) { return QVector4D(vector.xp / divisor, vector.yp / divisor, vector.zp / divisor, vector.wp / divisor); } -inline bool qFuzzyCompare(const QVector4D& v1, const QVector4D& v2) +Q_DECL_CONSTEXPR inline bool qFuzzyCompare(const QVector4D& v1, const QVector4D& v2) { return qFuzzyCompare(v1.xp, v2.xp) && qFuzzyCompare(v1.yp, v2.yp) && @@ -271,12 +281,12 @@ inline bool qFuzzyCompare(const QVector4D& v1, const QVector4D& v2) qFuzzyCompare(v1.wp, v2.wp); } -inline QPoint QVector4D::toPoint() const +Q_DECL_CONSTEXPR inline QPoint QVector4D::toPoint() const { return QPoint(qRound(xp), qRound(yp)); } -inline QPointF QVector4D::toPointF() const +Q_DECL_CONSTEXPR inline QPointF QVector4D::toPointF() const { return QPointF(qreal(xp), qreal(yp)); } diff --git a/src/gui/opengl/opengl.pri b/src/gui/opengl/opengl.pri index d249b855f5..56aecd49e2 100644 --- a/src/gui/opengl/opengl.pri +++ b/src/gui/opengl/opengl.pri @@ -31,7 +31,8 @@ contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles2) { opengl/qopenglversionfunctions.h \ opengl/qopenglversionfunctionsfactory_p.h \ opengl/qopenglvertexarrayobject.h \ - opengl/qopengldebug.h + opengl/qopengldebug.h \ + opengl/qopengltextureblitter_p.h SOURCES += opengl/qopengl.cpp \ opengl/qopenglfunctions.cpp \ @@ -51,7 +52,8 @@ contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles2) { opengl/qopenglversionfunctions.cpp \ opengl/qopenglversionfunctionsfactory.cpp \ opengl/qopenglvertexarrayobject.cpp \ - opengl/qopengldebug.cpp + opengl/qopengldebug.cpp \ + opengl/qopengltextureblitter.cpp !wince* { HEADERS += opengl/qopengltexture.h \ @@ -120,4 +122,8 @@ contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles2) { SOURCES += opengl/qopenglfunctions_es2.cpp } + + contains(QT_CONFIG, dynamicgl) { + win32: SOURCES += opengl/qopenglproxy_win.cpp + } } diff --git a/src/gui/opengl/qopengl.h b/src/gui/opengl/qopengl.h index 6eb656cd09..025f8b823c 100644 --- a/src/gui/opengl/qopengl.h +++ b/src/gui/opengl/qopengl.h @@ -107,7 +107,17 @@ typedef GLfloat GLdouble; # include <OpenGL/glext.h> # else # define GL_GLEXT_LEGACY // Prevents GL/gl.h from #including system glext.h + // In dynamic GL builds qopenglproxy will export the GL functions that are + // called also in QtGui itself. To prevent linker warnings (msvc) or errors (mingw) + // we need to make sure the prototypes do not have dllimport. +# ifdef QT_OPENGL_DYNAMIC_IN_GUI +# undef WINGDIAPI +# define WINGDIAPI +# endif // QT_OPENGL_DYNAMIC_IN_GUI # include <GL/gl.h> +# ifdef QT_OPENGL_DYNAMIC_IN_GUI +# undef WINGDIAPI +# endif // QT_OPENGL_DYNAMIC_IN_GUI # include <QtGui/qopenglext.h> # endif // Q_OS_MAC #endif diff --git a/src/gui/opengl/qopenglbuffer.cpp b/src/gui/opengl/qopenglbuffer.cpp index b832cefd70..a4c1e538ee 100644 --- a/src/gui/opengl/qopenglbuffer.cpp +++ b/src/gui/opengl/qopenglbuffer.cpp @@ -333,18 +333,20 @@ void QOpenGLBuffer::destroy() bool QOpenGLBuffer::read(int offset, void *data, int count) { #if !defined(QT_OPENGL_ES) - Q_D(QOpenGLBuffer); - if (!d->funcs->hasOpenGLFeature(QOpenGLFunctions::Buffers) || !d->guard->id()) - return false; - while (glGetError() != GL_NO_ERROR) ; // Clear error state. - d->funcs->glGetBufferSubData(d->type, offset, count, data); - return glGetError() == GL_NO_ERROR; + if (QOpenGLFunctions::platformGLType() != QOpenGLFunctions::GLES1) { + Q_D(QOpenGLBuffer); + if (!d->funcs->hasOpenGLFeature(QOpenGLFunctions::Buffers) || !d->guard->id()) + return false; + while (glGetError() != GL_NO_ERROR) ; // Clear error state. + d->funcs->glGetBufferSubData(d->type, offset, count, data); + return glGetError() == GL_NO_ERROR; + } #else Q_UNUSED(offset); Q_UNUSED(data); Q_UNUSED(count); - return false; #endif + return false; } /*! diff --git a/src/gui/opengl/qopenglengineshadermanager.cpp b/src/gui/opengl/qopenglengineshadermanager.cpp index 7c3c309ea5..95bafb07d9 100644 --- a/src/gui/opengl/qopenglengineshadermanager.cpp +++ b/src/gui/opengl/qopenglengineshadermanager.cpp @@ -164,7 +164,10 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context) code[NonPremultipliedImageSrcFragmentShader] = qopenglslNonPremultipliedImageSrcFragmentShader; code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader; // Calls "customShader", which must be appended code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader; - code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader; + if (QOpenGLFunctions::isES()) + code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_ES; + else + code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_desktop; code[TextureBrushSrcWithPatternFragmentShader] = qopenglslTextureBrushSrcWithPatternFragmentShader; code[PatternBrushSrcFragmentShader] = qopenglslPatternBrushSrcFragmentShader; code[LinearGradientBrushSrcFragmentShader] = qopenglslLinearGradientBrushSrcFragmentShader; diff --git a/src/gui/opengl/qopenglengineshadersource_p.h b/src/gui/opengl/qopenglengineshadersource_p.h index ba72de3fb0..5bb0bc4704 100644 --- a/src/gui/opengl/qopenglengineshadersource_p.h +++ b/src/gui/opengl/qopenglengineshadersource_p.h @@ -305,25 +305,23 @@ static const char* const qopenglslPositionWithTextureBrushVertexShader = "\n\ static const char* const qopenglslAffinePositionWithTextureBrushVertexShader = qopenglslPositionWithTextureBrushVertexShader; -#if defined(QT_OPENGL_ES_2) // OpenGL ES does not support GL_REPEAT wrap modes for NPOT textures. So instead, // we emulate GL_REPEAT by only taking the fractional part of the texture coords. // TODO: Special case POT textures which don't need this emulation -static const char* const qopenglslTextureBrushSrcFragmentShader = "\n\ +static const char* const qopenglslTextureBrushSrcFragmentShader_ES = "\n\ varying highp vec2 brushTextureCoords; \n\ uniform sampler2D brushTexture; \n\ lowp vec4 srcPixel() { \n\ return texture2D(brushTexture, fract(brushTextureCoords)); \n\ }\n"; -#else -static const char* const qopenglslTextureBrushSrcFragmentShader = "\n\ + +static const char* const qopenglslTextureBrushSrcFragmentShader_desktop = "\n\ varying highp vec2 brushTextureCoords; \n\ uniform sampler2D brushTexture; \n\ lowp vec4 srcPixel() \n\ { \n\ return texture2D(brushTexture, brushTextureCoords); \n\ }\n"; -#endif static const char* const qopenglslTextureBrushSrcWithPatternFragmentShader = "\n\ varying highp vec2 brushTextureCoords; \n\ diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp index 14d7fac9f7..9953b4e889 100644 --- a/src/gui/opengl/qopenglframebufferobject.cpp +++ b/src/gui/opengl/qopenglframebufferobject.cpp @@ -72,8 +72,6 @@ QT_BEGIN_NAMESPACE #define QT_CHECK_GLERROR() {} #endif -// ####TODO Properly #ifdef this class to use #define symbols actually defined -// by OpenGL/ES includes #ifndef GL_MAX_SAMPLES #define GL_MAX_SAMPLES 0x8D57 #endif @@ -448,42 +446,12 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi funcs.glGenFramebuffers(1, &fbo); funcs.glBindFramebuffer(GL_FRAMEBUFFER, fbo); - GLuint texture = 0; GLuint color_buffer = 0; QT_CHECK_GLERROR(); // init texture if (samples == 0) { - glGenTextures(1, &texture); - glBindTexture(target, texture); - - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - if (mipmap) { - int width = size.width(); - int height = size.height(); - int level = 0; - while (width > 1 || height > 1) { - width = qMax(1, width >> 1); - height = qMax(1, height >> 1); - ++level; - glTexImage2D(target, level, internal_format, width, height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - } - } - funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - target, texture, 0); - - QT_CHECK_GLERROR(); - valid = checkFramebufferStatus(ctx); - glBindTexture(target, 0); - - color_buffer = 0; + initTexture(texture_target, internal_format, size, mipmap); } else { mipmap = false; funcs.glGenRenderbuffers(1, &color_buffer); @@ -494,8 +462,10 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi QT_CHECK_GLERROR(); valid = checkFramebufferStatus(ctx); - if (valid) + if (valid) { funcs.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples); + color_buffer_guard = new QOpenGLSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc); + } } format.setTextureTarget(target); @@ -508,20 +478,59 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi funcs.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_func()->current_fbo); if (valid) { fbo_guard = new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc); - if (color_buffer) - color_buffer_guard = new QOpenGLSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc); - else - texture_guard = new QOpenGLSharedResourceGuard(ctx, texture, freeTextureFunc); } else { - if (color_buffer) - funcs.glDeleteRenderbuffers(1, &color_buffer); - else - glDeleteTextures(1, &texture); + if (color_buffer_guard) { + color_buffer_guard->free(); + color_buffer_guard = 0; + } else if (texture_guard) { + texture_guard->free(); + texture_guard = 0; + } funcs.glDeleteFramebuffers(1, &fbo); } QT_CHECK_GLERROR(); } +void QOpenGLFramebufferObjectPrivate::initTexture(GLenum target, GLenum internal_format, + const QSize &size, bool mipmap) +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + GLuint texture = 0; + + glGenTextures(1, &texture); + glBindTexture(target, texture); + + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + if (mipmap) { + int width = size.width(); + int height = size.height(); + int level = 0; + while (width > 1 || height > 1) { + width = qMax(1, width >> 1); + height = qMax(1, height >> 1); + ++level; + glTexImage2D(target, level, internal_format, width, height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } + } + funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + target, texture, 0); + + QT_CHECK_GLERROR(); + glBindTexture(target, 0); + valid = checkFramebufferStatus(ctx); + if (valid) + texture_guard = new QOpenGLSharedResourceGuard(ctx, texture, freeTextureFunc); + else + glDeleteTextures(1, &texture); +} + void QOpenGLFramebufferObjectPrivate::initAttachments(QOpenGLContext *ctx, QOpenGLFramebufferObject::Attachment attachment) { int samples = format.samples(); @@ -581,30 +590,29 @@ void QOpenGLFramebufferObjectPrivate::initAttachments(QOpenGLContext *ctx, QOpen funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer); Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer)); if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) { -#ifdef QT_OPENGL_ES - if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) { - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - GL_DEPTH_COMPONENT24, size.width(), size.height()); + if (QOpenGLFunctions::isES()) { + if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) + funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, + GL_DEPTH_COMPONENT24, size.width(), size.height()); + else + funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, + GL_DEPTH_COMPONENT16, size.width(), size.height()); } else { funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - GL_DEPTH_COMPONENT16, size.width(), size.height()); + GL_DEPTH_COMPONENT, size.width(), size.height()); } -#else - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - GL_DEPTH_COMPONENT, size.width(), size.height()); -#endif } else { -#ifdef QT_OPENGL_ES - if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) { - funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, - size.width(), size.height()); + if (QOpenGLFunctions::isES()) { + if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) { + funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, + size.width(), size.height()); + } else { + funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, + size.width(), size.height()); + } } else { - funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, - size.width(), size.height()); + funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.width(), size.height()); } -#else - funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.width(), size.height()); -#endif } funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buffer); @@ -619,23 +627,18 @@ void QOpenGLFramebufferObjectPrivate::initAttachments(QOpenGLContext *ctx, QOpen funcs.glGenRenderbuffers(1, &stencil_buffer); funcs.glBindRenderbuffer(GL_RENDERBUFFER, stencil_buffer); Q_ASSERT(funcs.glIsRenderbuffer(stencil_buffer)); - if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) { -#ifdef QT_OPENGL_ES - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - GL_STENCIL_INDEX8, size.width(), size.height()); -#else - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - GL_STENCIL_INDEX, size.width(), size.height()); -#endif - } else { + #ifdef QT_OPENGL_ES - funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, - size.width(), size.height()); + GLenum storage = GL_STENCIL_INDEX8; #else - funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX, - size.width(), size.height()); + GLenum storage = QOpenGLFunctions::isES() ? GL_STENCIL_INDEX8 : GL_STENCIL_INDEX; #endif - } + + if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) + funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, storage, size.width(), size.height()); + else + funcs.glRenderbufferStorage(GL_RENDERBUFFER, storage, size.width(), size.height()); + funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencil_buffer); valid = checkFramebufferStatus(ctx); @@ -768,7 +771,13 @@ QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, GLenum tar : d_ptr(new QOpenGLFramebufferObjectPrivate) { Q_D(QOpenGLFramebufferObject); - d->init(this, size, NoAttachment, target, DEFAULT_FORMAT); + d->init(this, size, NoAttachment, target, +#ifndef QT_OPENGL_ES_2 + QOpenGLFunctions::isES() ? GL_RGBA : GL_RGBA8 +#else + GL_RGBA +#endif + ); } /*! \overload @@ -782,7 +791,13 @@ QOpenGLFramebufferObject::QOpenGLFramebufferObject(int width, int height, GLenum : d_ptr(new QOpenGLFramebufferObjectPrivate) { Q_D(QOpenGLFramebufferObject); - d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT); + d->init(this, QSize(width, height), NoAttachment, target, +#ifndef QT_OPENGL_ES_2 + QOpenGLFunctions::isES() ? GL_RGBA : GL_RGBA8 +#else + GL_RGBA +#endif + ); } /*! \overload @@ -831,6 +846,12 @@ QOpenGLFramebufferObject::QOpenGLFramebufferObject(int width, int height, Attach : d_ptr(new QOpenGLFramebufferObjectPrivate) { Q_D(QOpenGLFramebufferObject); + if (!internal_format) +#ifdef QT_OPENGL_ES_2 + internal_format = GL_RGBA; +#else + internal_format = QOpenGLFunctions::isES() ? GL_RGBA : GL_RGBA8; +#endif d->init(this, QSize(width, height), attachment, target, internal_format); } @@ -852,6 +873,12 @@ QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, Attachment : d_ptr(new QOpenGLFramebufferObjectPrivate) { Q_D(QOpenGLFramebufferObject); + if (!internal_format) +#ifdef QT_OPENGL_ES_2 + internal_format = GL_RGBA; +#else + internal_format = QOpenGLFunctions::isES() ? GL_RGBA : GL_RGBA8; +#endif d->init(this, size, attachment, target, internal_format); } @@ -907,12 +934,16 @@ bool QOpenGLFramebufferObject::isValid() const framebuffer to this framebuffer object. Returns \c true upon success, false otherwise. + \note If takeTexture() was called, a new texture is created and associated + with the framebuffer object. This is potentially expensive and changes the + context state (the currently bound texture). + \sa release() */ bool QOpenGLFramebufferObject::bind() { if (!isValid()) - return false; + return false; Q_D(QOpenGLFramebufferObject); QOpenGLContext *current = QOpenGLContext::currentContext(); if (!current) @@ -922,7 +953,10 @@ bool QOpenGLFramebufferObject::bind() qWarning("QOpenGLFramebufferObject::bind() called from incompatible context"); #endif d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo()); - d->valid = d->checkFramebufferStatus(current); + if (d->texture_guard || d->format.samples() != 0) + d->valid = d->checkFramebufferStatus(current); + else + d->initTexture(d->format.textureTarget(), d->format.internalTextureFormat(), d->size, d->format.mipmap()); if (d->valid && current) current->d_func()->current_fbo = d->fbo(); return d->valid; @@ -940,7 +974,7 @@ bool QOpenGLFramebufferObject::bind() bool QOpenGLFramebufferObject::release() { if (!isValid()) - return false; + return false; QOpenGLContext *current = QOpenGLContext::currentContext(); if (!current) @@ -969,6 +1003,8 @@ bool QOpenGLFramebufferObject::release() If a multisample framebuffer object is used then the value returned from this function will be invalid. + + \sa takeTexture() */ GLuint QOpenGLFramebufferObject::texture() const { @@ -977,6 +1013,40 @@ GLuint QOpenGLFramebufferObject::texture() const } /*! + \fn GLuint QOpenGLFramebufferObject::takeTexture() + + Returns the texture id for the texture attached to this framebuffer + object. The ownership of the texture is transferred to the caller. + + If the framebuffer object is currently bound, an implicit release() + will be done. During the next call to bind() a new texture will be + created. + + If a multisample framebuffer object is used, then there is no + texture and the return value from this function will be invalid. + Similarly, incomplete framebuffer objects will also return 0. + + \since 5.3 + + \sa texture(), bind(), release() + */ +GLuint QOpenGLFramebufferObject::takeTexture() +{ + Q_D(QOpenGLFramebufferObject); + GLuint id = 0; + if (isValid() && d->texture_guard) { + QOpenGLContext *current = QOpenGLContext::currentContext(); + if (current && current->shareGroup() == d->fbo_guard->group() && current->d_func()->current_fbo == d->fbo()) + release(); + id = d->texture_guard->id(); + // Do not call free() on texture_guard, just null it out. + // This way the texture will not be deleted when the guard is destroyed. + d->texture_guard = 0; + } + return id; +} + +/*! \fn QSize QOpenGLFramebufferObject::size() const Returns the size of the texture attached to this framebuffer diff --git a/src/gui/opengl/qopenglframebufferobject.h b/src/gui/opengl/qopenglframebufferobject.h index 215d3701ca..3df929c210 100644 --- a/src/gui/opengl/qopenglframebufferobject.h +++ b/src/gui/opengl/qopenglframebufferobject.h @@ -69,17 +69,11 @@ public: explicit QOpenGLFramebufferObject(const QSize &size, GLenum target = GL_TEXTURE_2D); QOpenGLFramebufferObject(int width, int height, GLenum target = GL_TEXTURE_2D); -#if !defined(QT_OPENGL_ES) || defined(Q_QDOC) - QOpenGLFramebufferObject(const QSize &size, Attachment attachment, - GLenum target = GL_TEXTURE_2D, GLenum internal_format = GL_RGBA8); - QOpenGLFramebufferObject(int width, int height, Attachment attachment, - GLenum target = GL_TEXTURE_2D, GLenum internal_format = GL_RGBA8); -#else + QOpenGLFramebufferObject(const QSize &size, Attachment attachment, - GLenum target = GL_TEXTURE_2D, GLenum internal_format = GL_RGBA); + GLenum target = GL_TEXTURE_2D, GLenum internal_format = 0); QOpenGLFramebufferObject(int width, int height, Attachment attachment, - GLenum target = GL_TEXTURE_2D, GLenum internal_format = GL_RGBA); -#endif + GLenum target = GL_TEXTURE_2D, GLenum internal_format = 0); QOpenGLFramebufferObject(const QSize &size, const QOpenGLFramebufferObjectFormat &format); QOpenGLFramebufferObject(int width, int height, const QOpenGLFramebufferObjectFormat &format); @@ -97,6 +91,7 @@ public: int height() const { return size().height(); } GLuint texture() const; + GLuint takeTexture(); QSize size() const; QImage toImage() const; Attachment attachment() const; diff --git a/src/gui/opengl/qopenglframebufferobject_p.h b/src/gui/opengl/qopenglframebufferobject_p.h index c8c69c4b3e..f0e07f2119 100644 --- a/src/gui/opengl/qopenglframebufferobject_p.h +++ b/src/gui/opengl/qopenglframebufferobject_p.h @@ -59,12 +59,6 @@ QT_BEGIN_NAMESPACE -#ifndef QT_OPENGL_ES -#define DEFAULT_FORMAT GL_RGBA8 -#else -#define DEFAULT_FORMAT GL_RGBA -#endif - class QOpenGLFramebufferObjectFormatPrivate { public: @@ -73,9 +67,13 @@ public: samples(0), attachment(QOpenGLFramebufferObject::NoAttachment), target(GL_TEXTURE_2D), - internal_format(DEFAULT_FORMAT), mipmap(false) { +#ifndef QT_OPENGL_ES_2 + internal_format = QOpenGLFunctions::isES() ? GL_RGBA : GL_RGBA8; +#else + internal_format = GL_RGBA; +#endif } QOpenGLFramebufferObjectFormatPrivate (const QOpenGLFramebufferObjectFormatPrivate *other) @@ -116,6 +114,7 @@ public: QOpenGLFramebufferObject::Attachment attachment, GLenum internal_format, GLenum texture_target, GLint samples = 0, bool mipmap = false); + void initTexture(GLenum target, GLenum internal_format, const QSize &size, bool mipmap); void initAttachments(QOpenGLContext *ctx, QOpenGLFramebufferObject::Attachment attachment); bool checkFramebufferStatus(QOpenGLContext *ctx) const; diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp index 0e5a1327b0..150e7dcb32 100644 --- a/src/gui/opengl/qopenglfunctions.cpp +++ b/src/gui/opengl/qopenglfunctions.cpp @@ -249,98 +249,98 @@ QOpenGLExtensions::QOpenGLExtensions(QOpenGLContext *context) static int qt_gl_resolve_features() { -#if defined(QT_OPENGL_ES_2) - int features = QOpenGLFunctions::Multitexture | - QOpenGLFunctions::Shaders | - QOpenGLFunctions::Buffers | - QOpenGLFunctions::Framebuffers | - QOpenGLFunctions::BlendColor | - QOpenGLFunctions::BlendEquation | - QOpenGLFunctions::BlendEquationSeparate | - QOpenGLFunctions::BlendFuncSeparate | - QOpenGLFunctions::BlendSubtract | - QOpenGLFunctions::CompressedTextures | - QOpenGLFunctions::Multisample | - QOpenGLFunctions::StencilSeparate; - QOpenGLExtensionMatcher extensions; - if (extensions.match("GL_IMG_texture_npot")) - features |= QOpenGLFunctions::NPOTTextures; - if (extensions.match("GL_OES_texture_npot")) - features |= QOpenGLFunctions::NPOTTextures | - QOpenGLFunctions::NPOTTextureRepeat; - return features; -#elif defined(QT_OPENGL_ES) - int features = QOpenGLFunctions::Multitexture | - QOpenGLFunctions::Buffers | - QOpenGLFunctions::CompressedTextures | - QOpenGLFunctions::Multisample; - QOpenGLExtensionMatcher extensions; - if (extensions.match("GL_OES_framebuffer_object")) - features |= QOpenGLFunctions::Framebuffers; - if (extensions.match("GL_OES_blend_equation_separate")) - features |= QOpenGLFunctions::BlendEquationSeparate; - if (extensions.match("GL_OES_blend_func_separate")) - features |= QOpenGLFunctions::BlendFuncSeparate; - if (extensions.match("GL_OES_blend_subtract")) - features |= QOpenGLFunctions::BlendSubtract; - if (extensions.match("GL_OES_texture_npot")) - features |= QOpenGLFunctions::NPOTTextures; - if (extensions.match("GL_IMG_texture_npot")) - features |= QOpenGLFunctions::NPOTTextures; - return features; -#else - int features = 0; - QSurfaceFormat format = QOpenGLContext::currentContext()->format(); - QOpenGLExtensionMatcher extensions; - - // Recognize features by extension name. - if (extensions.match("GL_ARB_multitexture")) - features |= QOpenGLFunctions::Multitexture; - if (extensions.match("GL_ARB_shader_objects")) - features |= QOpenGLFunctions::Shaders; - if (extensions.match("GL_EXT_framebuffer_object") || + if (QOpenGLFunctions::platformGLType() == QOpenGLFunctions::GLES2) { + int features = QOpenGLFunctions::Multitexture | + QOpenGLFunctions::Shaders | + QOpenGLFunctions::Buffers | + QOpenGLFunctions::Framebuffers | + QOpenGLFunctions::BlendColor | + QOpenGLFunctions::BlendEquation | + QOpenGLFunctions::BlendEquationSeparate | + QOpenGLFunctions::BlendFuncSeparate | + QOpenGLFunctions::BlendSubtract | + QOpenGLFunctions::CompressedTextures | + QOpenGLFunctions::Multisample | + QOpenGLFunctions::StencilSeparate; + QOpenGLExtensionMatcher extensions; + if (extensions.match("GL_IMG_texture_npot")) + features |= QOpenGLFunctions::NPOTTextures; + if (extensions.match("GL_OES_texture_npot")) + features |= QOpenGLFunctions::NPOTTextures | + QOpenGLFunctions::NPOTTextureRepeat; + return features; + } else if (QOpenGLFunctions::platformGLType() == QOpenGLFunctions::GLES1) { + int features = QOpenGLFunctions::Multitexture | + QOpenGLFunctions::Buffers | + QOpenGLFunctions::CompressedTextures | + QOpenGLFunctions::Multisample; + QOpenGLExtensionMatcher extensions; + if (extensions.match("GL_OES_framebuffer_object")) + features |= QOpenGLFunctions::Framebuffers; + if (extensions.match("GL_OES_blend_equation_separate")) + features |= QOpenGLFunctions::BlendEquationSeparate; + if (extensions.match("GL_OES_blend_func_separate")) + features |= QOpenGLFunctions::BlendFuncSeparate; + if (extensions.match("GL_OES_blend_subtract")) + features |= QOpenGLFunctions::BlendSubtract; + if (extensions.match("GL_OES_texture_npot")) + features |= QOpenGLFunctions::NPOTTextures; + if (extensions.match("GL_IMG_texture_npot")) + features |= QOpenGLFunctions::NPOTTextures; + return features; + } else { + int features = 0; + QSurfaceFormat format = QOpenGLContext::currentContext()->format(); + QOpenGLExtensionMatcher extensions; + + // Recognize features by extension name. + if (extensions.match("GL_ARB_multitexture")) + features |= QOpenGLFunctions::Multitexture; + if (extensions.match("GL_ARB_shader_objects")) + features |= QOpenGLFunctions::Shaders; + if (extensions.match("GL_EXT_framebuffer_object") || extensions.match("GL_ARB_framebuffer_object")) - features |= QOpenGLFunctions::Framebuffers; - if (extensions.match("GL_EXT_blend_color")) - features |= QOpenGLFunctions::BlendColor; - if (extensions.match("GL_EXT_blend_equation_separate")) - features |= QOpenGLFunctions::BlendEquationSeparate; - if (extensions.match("GL_EXT_blend_func_separate")) - features |= QOpenGLFunctions::BlendFuncSeparate; - if (extensions.match("GL_EXT_blend_subtract")) - features |= QOpenGLFunctions::BlendSubtract; - if (extensions.match("GL_ARB_texture_compression")) - features |= QOpenGLFunctions::CompressedTextures; - if (extensions.match("GL_ARB_multisample")) - features |= QOpenGLFunctions::Multisample; - if (extensions.match("GL_ARB_texture_non_power_of_two")) - features |= QOpenGLFunctions::NPOTTextures; - - // assume version 2.0 or higher - features |= QOpenGLFunctions::BlendColor | - QOpenGLFunctions::BlendEquation | - QOpenGLFunctions::Multitexture | - QOpenGLFunctions::CompressedTextures | - QOpenGLFunctions::Multisample | - QOpenGLFunctions::BlendFuncSeparate | - QOpenGLFunctions::Buffers | - QOpenGLFunctions::Shaders | - QOpenGLFunctions::StencilSeparate | - QOpenGLFunctions::BlendEquationSeparate | - QOpenGLFunctions::NPOTTextures; - - if (format.majorVersion() >= 3) - features |= QOpenGLFunctions::Framebuffers; - - const QPair<int, int> version = format.version(); - if (version < qMakePair(3, 0) + features |= QOpenGLFunctions::Framebuffers; + if (extensions.match("GL_EXT_blend_color")) + features |= QOpenGLFunctions::BlendColor; + if (extensions.match("GL_EXT_blend_equation_separate")) + features |= QOpenGLFunctions::BlendEquationSeparate; + if (extensions.match("GL_EXT_blend_func_separate")) + features |= QOpenGLFunctions::BlendFuncSeparate; + if (extensions.match("GL_EXT_blend_subtract")) + features |= QOpenGLFunctions::BlendSubtract; + if (extensions.match("GL_ARB_texture_compression")) + features |= QOpenGLFunctions::CompressedTextures; + if (extensions.match("GL_ARB_multisample")) + features |= QOpenGLFunctions::Multisample; + if (extensions.match("GL_ARB_texture_non_power_of_two")) + features |= QOpenGLFunctions::NPOTTextures; + + // assume version 2.0 or higher + features |= QOpenGLFunctions::BlendColor | + QOpenGLFunctions::BlendEquation | + QOpenGLFunctions::Multitexture | + QOpenGLFunctions::CompressedTextures | + QOpenGLFunctions::Multisample | + QOpenGLFunctions::BlendFuncSeparate | + QOpenGLFunctions::Buffers | + QOpenGLFunctions::Shaders | + QOpenGLFunctions::StencilSeparate | + QOpenGLFunctions::BlendEquationSeparate | + QOpenGLFunctions::NPOTTextures; + + if (format.majorVersion() >= 3) + features |= QOpenGLFunctions::Framebuffers; + + const QPair<int, int> version = format.version(); + if (version < qMakePair(3, 0) || (version == qMakePair(3, 0) && format.testOption(QSurfaceFormat::DeprecatedFunctions)) || (version == qMakePair(3, 1) && extensions.match("GL_ARB_compatibility")) || (version >= qMakePair(3, 2) && format.profile() == QSurfaceFormat::CompatibilityProfile)) { - features |= QOpenGLFunctions::FixedFunctionPipeline; + features |= QOpenGLFunctions::FixedFunctionPipeline; + } + return features; } - return features; -#endif } static int qt_gl_resolve_extensions() @@ -350,38 +350,38 @@ static int qt_gl_resolve_extensions() if (extensionMatcher.match("GL_EXT_bgra")) extensions |= QOpenGLExtensions::BGRATextureFormat; -#if defined(QT_OPENGL_ES) - if (extensionMatcher.match("GL_OES_mapbuffer")) - extensions |= QOpenGLExtensions::MapBuffer; - if (extensionMatcher.match("GL_OES_packed_depth_stencil")) - extensions |= QOpenGLExtensions::PackedDepthStencil; - if (extensionMatcher.match("GL_OES_element_index_uint")) - extensions |= QOpenGLExtensions::ElementIndexUint; - if (extensionMatcher.match("GL_OES_depth24")) - extensions |= QOpenGLExtensions::Depth24; - // TODO: Consider matching GL_APPLE_texture_format_BGRA8888 as well, but it needs testing. - if (extensionMatcher.match("GL_IMG_texture_format_BGRA8888") || extensionMatcher.match("GL_EXT_texture_format_BGRA8888")) - extensions |= QOpenGLExtensions::BGRATextureFormat; -#else - QSurfaceFormat format = QOpenGLContext::currentContext()->format(); - extensions |= QOpenGLExtensions::ElementIndexUint | QOpenGLExtensions::MapBuffer; - - // Recognize features by extension name. - if (format.majorVersion() >= 3 - || extensionMatcher.match("GL_ARB_framebuffer_object")) - { - extensions |= QOpenGLExtensions::FramebufferMultisample | - QOpenGLExtensions::FramebufferBlit | - QOpenGLExtensions::PackedDepthStencil; - } else { - if (extensionMatcher.match("GL_EXT_framebuffer_multisample")) - extensions |= QOpenGLExtensions::FramebufferMultisample; - if (extensionMatcher.match("GL_EXT_framebuffer_blit")) - extensions |= QOpenGLExtensions::FramebufferBlit; - if (extensionMatcher.match("GL_EXT_packed_depth_stencil")) + if (QOpenGLFunctions::isES()) { + if (extensionMatcher.match("GL_OES_mapbuffer")) + extensions |= QOpenGLExtensions::MapBuffer; + if (extensionMatcher.match("GL_OES_packed_depth_stencil")) extensions |= QOpenGLExtensions::PackedDepthStencil; + if (extensionMatcher.match("GL_OES_element_index_uint")) + extensions |= QOpenGLExtensions::ElementIndexUint; + if (extensionMatcher.match("GL_OES_depth24")) + extensions |= QOpenGLExtensions::Depth24; + // TODO: Consider matching GL_APPLE_texture_format_BGRA8888 as well, but it needs testing. + if (extensionMatcher.match("GL_IMG_texture_format_BGRA8888") || extensionMatcher.match("GL_EXT_texture_format_BGRA8888")) + extensions |= QOpenGLExtensions::BGRATextureFormat; + } else { + QSurfaceFormat format = QOpenGLContext::currentContext()->format(); + extensions |= QOpenGLExtensions::ElementIndexUint | QOpenGLExtensions::MapBuffer; + + // Recognize features by extension name. + if (format.majorVersion() >= 3 + || extensionMatcher.match("GL_ARB_framebuffer_object")) + { + extensions |= QOpenGLExtensions::FramebufferMultisample | + QOpenGLExtensions::FramebufferBlit | + QOpenGLExtensions::PackedDepthStencil; + } else { + if (extensionMatcher.match("GL_EXT_framebuffer_multisample")) + extensions |= QOpenGLExtensions::FramebufferMultisample; + if (extensionMatcher.match("GL_EXT_framebuffer_blit")) + extensions |= QOpenGLExtensions::FramebufferBlit; + if (extensionMatcher.match("GL_EXT_packed_depth_stencil")) + extensions |= QOpenGLExtensions::PackedDepthStencil; + } } -#endif return extensions; } @@ -2509,4 +2509,88 @@ QOpenGLExtensionsPrivate::QOpenGLExtensionsPrivate(QOpenGLContext *ctx) GetBufferSubData = qopenglfResolveGetBufferSubData; } +#if defined(QT_OPENGL_DYNAMIC) +extern int qgl_proxyLibraryType(void); +extern HMODULE qgl_glHandle(void); +#endif + +/*! + \enum QOpenGLFunctions::PlatformGLType + This enum defines the type of the underlying GL implementation. + + \value DesktopGL Desktop OpenGL + \value GLES2 OpenGL ES 2.0 or higher + \value GLES1 OpenGL ES 1.x + + \since 5.3 + */ + +/*! + \fn QOpenGLFunctions::isES() + + On platforms where the OpenGL implementation is dynamically loaded + this function returns true if the underlying GL implementation is + Open GL ES. + + On platforms that do not use runtime loading of the GL the return + value is based on Qt's compile-time configuration and will never + change during runtime. + + \sa platformGLType() + + \since 5.3 + */ + +/*! + Returns the underlying GL implementation type. + + On platforms where the OpenGL implementation is not dynamically + loaded, the return value is determined during compile time and never + changes. + + Platforms that use dynamic GL loading (e.g. Windows) cannot rely on + compile-time defines for differentiating between desktop and ES + OpenGL code. Instead, they rely on this function to query, during + runtime, the type of the loaded graphics library. + + \since 5.3 + */ +QOpenGLFunctions::PlatformGLType QOpenGLFunctions::platformGLType() +{ +#if defined(QT_OPENGL_DYNAMIC) + return PlatformGLType(qgl_proxyLibraryType()); +#elif defined(QT_OPENGL_ES_2) + return GLES2; +#elif defined(QT_OPENGL_ES) + return GLES1; +#else + return DesktopGL; +#endif +} + +/*! + Returns the platform-specific handle for the OpenGL implementation that + is currently in use. (for example, a HMODULE on Windows) + + On platforms that do not use dynamic GL switch the return value is null. + + The library might be GL-only, meaning that windowing system interface + functions (for example EGL) may live in another, separate library. + + Always use platformGLType() before resolving any functions to check if the + library implements desktop OpenGL or OpenGL ES. + + \sa platformGLType() + + \since 5.3 + */ +void *QOpenGLFunctions::platformGLHandle() +{ +#if defined(QT_OPENGL_DYNAMIC) + return qgl_glHandle(); +#else + return 0; +#endif +} + QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglfunctions.h b/src/gui/opengl/qopenglfunctions.h index 9d8da209ad..6d3f038004 100644 --- a/src/gui/opengl/qopenglfunctions.h +++ b/src/gui/opengl/qopenglfunctions.h @@ -311,6 +311,15 @@ public: void glVertexAttrib4fv(GLuint indx, const GLfloat* values); void glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr); + enum PlatformGLType { + DesktopGL = 0, + GLES2, + GLES1 + }; + static PlatformGLType platformGLType(); + static void *platformGLHandle(); + static bool isES() { return platformGLType() != DesktopGL; } + protected: QOpenGLFunctionsPrivate *d_ptr; static bool isInitialized(const QOpenGLFunctionsPrivate *d) { return d != 0; } @@ -322,7 +331,6 @@ struct QOpenGLFunctionsPrivate { QOpenGLFunctionsPrivate(QOpenGLContext *ctx); -#ifndef QT_OPENGL_ES_2 void (QOPENGLF_APIENTRYP ActiveTexture)(GLenum texture); void (QOPENGLF_APIENTRYP AttachShader)(GLuint program, GLuint shader); void (QOPENGLF_APIENTRYP BindAttribLocation)(GLuint program, GLuint index, const char* name); @@ -418,7 +426,6 @@ struct QOpenGLFunctionsPrivate void (QOPENGLF_APIENTRYP VertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w); void (QOPENGLF_APIENTRYP VertexAttrib4fv)(GLuint indx, const GLfloat* values); void (QOPENGLF_APIENTRYP VertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr); -#endif }; inline void QOpenGLFunctions::glActiveTexture(GLenum texture) diff --git a/src/gui/opengl/qopenglgradientcache.cpp b/src/gui/opengl/qopenglgradientcache.cpp index 9c4fbbe013..9c312808a2 100644 --- a/src/gui/opengl/qopenglgradientcache.cpp +++ b/src/gui/opengl/qopenglgradientcache.cpp @@ -168,7 +168,7 @@ void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient uint current_color = ARGB_COMBINE_ALPHA(colors[0], alpha); qreal incr = 1.0 / qreal(size); qreal fpos = 1.5 * incr; - colorTable[pos++] = ARGB2RGBA(PREMUL(current_color)); + colorTable[pos++] = ARGB2RGBA(qPremultiply(current_color)); while (fpos <= s.first().first) { colorTable[pos] = colorTable[pos - 1]; @@ -177,13 +177,13 @@ void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient } if (colorInterpolation) - current_color = PREMUL(current_color); + current_color = qPremultiply(current_color); for (int i = 0; i < s.size() - 1; ++i) { qreal delta = 1/(s[i+1].first - s[i].first); uint next_color = ARGB_COMBINE_ALPHA(colors[i+1], alpha); if (colorInterpolation) - next_color = PREMUL(next_color); + next_color = qPremultiply(next_color); while (fpos < s[i+1].first && pos < size) { int dist = int(256 * ((fpos - s[i].first) * delta)); @@ -191,7 +191,7 @@ void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient if (colorInterpolation) colorTable[pos] = ARGB2RGBA(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)); else - colorTable[pos] = ARGB2RGBA(PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist))); + colorTable[pos] = ARGB2RGBA(qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist))); ++pos; fpos += incr; } @@ -200,7 +200,7 @@ void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient Q_ASSERT(s.size() > 0); - uint last_color = ARGB2RGBA(PREMUL(ARGB_COMBINE_ALPHA(colors[s.size() - 1], alpha))); + uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(colors[s.size() - 1], alpha))); for (;pos < size; ++pos) colorTable[pos] = last_color; diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index 05135519f8..e91ada7b3a 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -220,14 +220,14 @@ void QOpenGL2PaintEngineExPrivate::updateBrushTexture() if (currentBrushPixmap.width() > max_texture_size || currentBrushPixmap.height() > max_texture_size) currentBrushPixmap = currentBrushPixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio); -#if defined(QT_OPENGL_ES_2) - // OpenGL ES does not support GL_REPEAT wrap modes for NPOT textures. So instead, - // we emulate GL_REPEAT by only taking the fractional part of the texture coords - // in the qopenglslTextureBrushSrcFragmentShader program. - GLuint wrapMode = GL_CLAMP_TO_EDGE; -#else GLuint wrapMode = GL_REPEAT; -#endif + if (QOpenGLFunctions::isES()) { + // OpenGL ES does not support GL_REPEAT wrap modes for NPOT textures. So instead, + // we emulate GL_REPEAT by only taking the fractional part of the texture coords + // in the qopenglslTextureBrushSrcFragmentShader program. + wrapMode = GL_CLAMP_TO_EDGE; + } + funcs.glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, currentBrushPixmap); updateTextureFilter(GL_TEXTURE_2D, wrapMode, q->state()->renderHints & QPainter::SmoothPixmapTransform); @@ -542,36 +542,38 @@ void QOpenGL2PaintEngineEx::beginNativePainting() d->funcs.glDisableVertexAttribArray(i); #ifndef QT_OPENGL_ES_2 - Q_ASSERT(QOpenGLContext::currentContext()); - const QOpenGLContext *ctx = d->ctx; - const QSurfaceFormat &fmt = d->device->context()->format(); - if (fmt.majorVersion() < 3 || (fmt.majorVersion() == 3 && fmt.minorVersion() < 1) - || (fmt.majorVersion() == 3 && fmt.minorVersion() == 1 && ctx->hasExtension(QByteArrayLiteral("GL_ARB_compatibility"))) - || fmt.profile() == QSurfaceFormat::CompatibilityProfile) - { - // be nice to people who mix OpenGL 1.x code with QPainter commands - // by setting modelview and projection matrices to mirror the GL 1 - // paint engine - const QTransform& mtx = state()->matrix; - - float mv_matrix[4][4] = + if (!QOpenGLFunctions::isES()) { + Q_ASSERT(QOpenGLContext::currentContext()); + const QOpenGLContext *ctx = d->ctx; + const QSurfaceFormat &fmt = d->device->context()->format(); + if (fmt.majorVersion() < 3 || (fmt.majorVersion() == 3 && fmt.minorVersion() < 1) + || (fmt.majorVersion() == 3 && fmt.minorVersion() == 1 && ctx->hasExtension(QByteArrayLiteral("GL_ARB_compatibility"))) + || fmt.profile() == QSurfaceFormat::CompatibilityProfile) { - { float(mtx.m11()), float(mtx.m12()), 0, float(mtx.m13()) }, - { float(mtx.m21()), float(mtx.m22()), 0, float(mtx.m23()) }, - { 0, 0, 1, 0 }, - { float(mtx.dx()), float(mtx.dy()), 0, float(mtx.m33()) } - }; - - const QSize sz = d->device->size(); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999); - - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(&mv_matrix[0][0]); + // be nice to people who mix OpenGL 1.x code with QPainter commands + // by setting modelview and projection matrices to mirror the GL 1 + // paint engine + const QTransform& mtx = state()->matrix; + + float mv_matrix[4][4] = + { + { float(mtx.m11()), float(mtx.m12()), 0, float(mtx.m13()) }, + { float(mtx.m21()), float(mtx.m22()), 0, float(mtx.m23()) }, + { 0, 0, 1, 0 }, + { float(mtx.dx()), float(mtx.dy()), 0, float(mtx.m33()) } + }; + + const QSize sz = d->device->size(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999); + + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(&mv_matrix[0][0]); + } } -#endif +#endif // QT_OPENGL_ES_2 d->lastTextureUsed = GLuint(-1); d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); @@ -598,11 +600,11 @@ void QOpenGL2PaintEngineExPrivate::resetGLState() setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false); setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, false); setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false); -#ifndef QT_OPENGL_ES_2 - // gl_Color, corresponding to vertex attribute 3, may have been changed - float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; - funcs.glVertexAttrib4fv(3, color); -#endif + if (!QOpenGLFunctions::isES()) { + // gl_Color, corresponding to vertex attribute 3, may have been changed + float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + funcs.glVertexAttrib4fv(3, color); + } } void QOpenGL2PaintEngineEx::endNativePainting() @@ -1332,13 +1334,15 @@ void QOpenGL2PaintEngineEx::renderHintsChanged() { state()->renderHintsChanged = true; -#if !defined(QT_OPENGL_ES_2) - if ((state()->renderHints & QPainter::Antialiasing) - || (state()->renderHints & QPainter::HighQualityAntialiasing)) - glEnable(GL_MULTISAMPLE); - else - glDisable(GL_MULTISAMPLE); -#endif +#ifndef QT_OPENGL_ES_2 + if (!QOpenGLFunctions::isES()) { + if ((state()->renderHints & QPainter::Antialiasing) + || (state()->renderHints & QPainter::HighQualityAntialiasing)) + glEnable(GL_MULTISAMPLE); + else + glDisable(GL_MULTISAMPLE); + } +#endif // QT_OPENGL_ES_2 Q_D(QOpenGL2PaintEngineEx); d->lastTextureUsed = GLuint(-1); @@ -2008,23 +2012,20 @@ bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev) glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); -#if !defined(QT_OPENGL_ES_2) - glDisable(GL_MULTISAMPLE); -#endif - d->glyphCacheType = QFontEngineGlyphCache::Raster_A8; -#if !defined(QT_OPENGL_ES_2) +#ifndef QT_OPENGL_ES_2 + if (!QOpenGLFunctions::isES()) { + glDisable(GL_MULTISAMPLE); d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask; -#endif - -#if defined(QT_OPENGL_ES_2) - // OpenGL ES can't switch MSAA off, so if the gl paint device is - // multisampled, it's always multisampled. - d->multisamplingAlwaysEnabled = d->device->context()->format().samples() > 1; -#else - d->multisamplingAlwaysEnabled = false; -#endif + d->multisamplingAlwaysEnabled = false; + } else +#endif // QT_OPENGL_ES_2 + { + // OpenGL ES can't switch MSAA off, so if the gl paint device is + // multisampled, it's always multisampled. + d->multisamplingAlwaysEnabled = d->device->context()->format().samples() > 1; + } return true; } diff --git a/src/gui/opengl/qopenglproxy_win.cpp b/src/gui/opengl/qopenglproxy_win.cpp new file mode 100644 index 0000000000..83c3073f63 --- /dev/null +++ b/src/gui/opengl/qopenglproxy_win.cpp @@ -0,0 +1,4600 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QByteArray> +#include <QVector> +#include <QCoreApplication> +#include <QLoggingCategory> +#include <qt_windows.h> +// Must not include QOpenGLFunctions or anything that pulls in qopengl.h. +// Otherwise we end up with errors about inconsistent linkage. +#include <GL/gl.h> +#include <EGL/egl.h> + +#if defined(QT_OPENGL_ES) || defined(QT_OPENGL_ES_2) +# error "Proxy GL is not compatible with static ES builds" +#endif + +// This should not be an issue with the compilers used on Windows, but just in case: +#ifndef Q_COMPILER_VARIADIC_MACROS +# error "Proxy GL requires variadic macro support" +#endif + +// Disable inconsistent dll linkage warnings. gl.h and egl.h are included and these mark +// the egl and (w)gl functions as imported. We will mark them as exported. +#if defined(Q_CC_MSVC) +# pragma warning(disable : 4273) +#elif defined(Q_CC_MINGW) +# pragma GCC diagnostic ignored "-Wattributes" +#endif + +#ifdef Q_OS_WIN64 +typedef signed long long int khronos_intptr_t; +typedef signed long long int khronos_ssize_t; +#else +typedef signed long int khronos_intptr_t; +typedef signed long int khronos_ssize_t; +#endif + +typedef char GLchar; +typedef khronos_intptr_t GLintptr; +typedef khronos_ssize_t GLsizeiptr; + +Q_LOGGING_CATEGORY(qglLc, "qt.gui.openglproxy") + +class QAbstractWindowsOpenGL +{ +public: + QAbstractWindowsOpenGL(); + virtual ~QAbstractWindowsOpenGL() { } + + enum LibType { // must match QOpenGLFunctions::PlatformGLType + DesktopGL = 0, + GLES2 + }; + + LibType libraryType() const { return m_libraryType; } + HMODULE libraryHandle() const { return m_lib; } + bool functionsReady() const { return m_loaded; } + + // WGL + BOOL (WINAPI * CopyContext)(HGLRC src, HGLRC dst, UINT mask); + HGLRC (WINAPI * CreateContext)(HDC dc); + HGLRC (WINAPI * CreateLayerContext)(HDC dc, int plane); + BOOL (WINAPI * DeleteContext)(HGLRC context); + HGLRC (WINAPI * GetCurrentContext)(); + HDC (WINAPI * GetCurrentDC)(); + PROC (WINAPI * GetProcAddress)(LPCSTR name); + BOOL (WINAPI * MakeCurrent)(HDC dc, HGLRC context); + BOOL (WINAPI * ShareLists)(HGLRC context1, HGLRC context2); + BOOL (WINAPI * UseFontBitmapsW)(HDC dc, DWORD first, DWORD count, DWORD base); + BOOL (WINAPI * UseFontOutlinesW)(HDC dc, DWORD first, DWORD count, DWORD base, FLOAT deviation, + FLOAT extrusion, int format, LPGLYPHMETRICSFLOAT gmf); + BOOL (WINAPI * DescribeLayerPlane)(HDC dc, int pixelFormat, int plane, UINT n, + LPLAYERPLANEDESCRIPTOR planeDescriptor); + int (WINAPI * SetLayerPaletteEntries)(HDC dc, int plane, int start, int entries, + CONST COLORREF *colors); + int (WINAPI * GetLayerPaletteEntries)(HDC dc, int plane, int start, int entries, + COLORREF *color); + BOOL (WINAPI * RealizeLayerPalette)(HDC dc, int plane, BOOL realize); + BOOL (WINAPI * SwapLayerBuffers)(HDC dc, UINT planes); + DWORD (WINAPI * SwapMultipleBuffers)(UINT n, CONST WGLSWAP *buffers); + + // EGL + EGLint (EGLAPIENTRY * EGL_GetError)(void); + EGLDisplay (EGLAPIENTRY * EGL_GetDisplay)(EGLNativeDisplayType display_id); + EGLBoolean (EGLAPIENTRY * EGL_Initialize)(EGLDisplay dpy, EGLint *major, EGLint *minor); + EGLBoolean (EGLAPIENTRY * EGL_Terminate)(EGLDisplay dpy); + const char * (EGLAPIENTRY * EGL_QueryString)(EGLDisplay dpy, EGLint name); + EGLBoolean (EGLAPIENTRY * EGL_GetConfigs)(EGLDisplay dpy, EGLConfig *configs, + EGLint config_size, EGLint *num_config); + EGLBoolean (EGLAPIENTRY * EGL_ChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list, + EGLConfig *configs, EGLint config_size, + EGLint *num_config); + EGLBoolean (EGLAPIENTRY * EGL_GetConfigAttrib)(EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint *value); + EGLSurface (EGLAPIENTRY * EGL_CreateWindowSurface)(EGLDisplay dpy, EGLConfig config, + EGLNativeWindowType win, + const EGLint *attrib_list); + EGLSurface (EGLAPIENTRY * EGL_CreatePbufferSurface)(EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list); + EGLSurface (EGLAPIENTRY * EGL_CreatePixmapSurface)(EGLDisplay dpy, EGLConfig config, + EGLNativePixmapType pixmap, + const EGLint *attrib_list); + EGLBoolean (EGLAPIENTRY * EGL_DestroySurface)(EGLDisplay dpy, EGLSurface surface); + EGLBoolean (EGLAPIENTRY * EGL_QuerySurface)(EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint *value); + EGLBoolean (EGLAPIENTRY * EGL_BindAPI)(EGLenum api); + EGLenum (EGLAPIENTRY * EGL_QueryAPI)(void); + EGLBoolean (EGLAPIENTRY * EGL_WaitClient)(void); + EGLBoolean (EGLAPIENTRY * EGL_ReleaseThread)(void); + EGLSurface (EGLAPIENTRY * EGL_CreatePbufferFromClientBuffer)(EGLDisplay dpy, EGLenum buftype, + EGLClientBuffer buffer, + EGLConfig config, const EGLint *attrib_list); + EGLBoolean (EGLAPIENTRY * EGL_SurfaceAttrib)(EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint value); + EGLBoolean (EGLAPIENTRY * EGL_BindTexImage)(EGLDisplay dpy, EGLSurface surface, EGLint buffer); + EGLBoolean (EGLAPIENTRY * EGL_ReleaseTexImage)(EGLDisplay dpy, EGLSurface surface, EGLint buffer); + EGLBoolean (EGLAPIENTRY * EGL_SwapInterval)(EGLDisplay dpy, EGLint interval); + EGLContext (EGLAPIENTRY * EGL_CreateContext)(EGLDisplay dpy, EGLConfig config, + EGLContext share_context, + const EGLint *attrib_list); + EGLBoolean (EGLAPIENTRY * EGL_DestroyContext)(EGLDisplay dpy, EGLContext ctx); + EGLBoolean (EGLAPIENTRY * EGL_MakeCurrent)(EGLDisplay dpy, EGLSurface draw, + EGLSurface read, EGLContext ctx); + EGLContext (EGLAPIENTRY * EGL_GetCurrentContext)(void); + EGLSurface (EGLAPIENTRY * EGL_GetCurrentSurface)(EGLint readdraw); + EGLDisplay (EGLAPIENTRY * EGL_GetCurrentDisplay)(void); + EGLBoolean (EGLAPIENTRY * EGL_QueryContext)(EGLDisplay dpy, EGLContext ctx, + EGLint attribute, EGLint *value); + EGLBoolean (EGLAPIENTRY * EGL_WaitGL)(void); + EGLBoolean (EGLAPIENTRY * EGL_WaitNative)(EGLint engine); + EGLBoolean (EGLAPIENTRY * EGL_SwapBuffers)(EGLDisplay dpy, EGLSurface surface); + EGLBoolean (EGLAPIENTRY * EGL_CopyBuffers)(EGLDisplay dpy, EGLSurface surface, + EGLNativePixmapType target); + __eglMustCastToProperFunctionPointerType (EGLAPIENTRY * EGL_GetProcAddress)(const char *procname); + + // OpenGL 1.0 + void (APIENTRY * Viewport)(GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY * DepthRange)(GLdouble nearVal, GLdouble farVal); + GLboolean (APIENTRY * IsEnabled)(GLenum cap); + void (APIENTRY * GetTexLevelParameteriv)(GLenum target, GLint level, GLenum pname, GLint *params); + void (APIENTRY * GetTexLevelParameterfv)(GLenum target, GLint level, GLenum pname, GLfloat *params); + void (APIENTRY * GetTexParameteriv)(GLenum target, GLenum pname, GLint *params); + void (APIENTRY * GetTexParameterfv)(GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY * GetTexImage)(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); + const GLubyte * (APIENTRY * GetString)(GLenum name); + void (APIENTRY * GetIntegerv)(GLenum pname, GLint *params); + void (APIENTRY * GetFloatv)(GLenum pname, GLfloat *params); + GLenum (APIENTRY * GetError)(); + void (APIENTRY * GetDoublev)(GLenum pname, GLdouble *params); + void (APIENTRY * GetBooleanv)(GLenum pname, GLboolean *params); + void (APIENTRY * ReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); + void (APIENTRY * ReadBuffer)(GLenum mode); + void (APIENTRY * PixelStorei)(GLenum pname, GLint param); + void (APIENTRY * PixelStoref)(GLenum pname, GLfloat param); + void (APIENTRY * DepthFunc)(GLenum func); + void (APIENTRY * StencilOp)(GLenum fail, GLenum zfail, GLenum zpass); + void (APIENTRY * StencilFunc)(GLenum func, GLint ref, GLuint mask); + void (APIENTRY * LogicOp)(GLenum opcode); + void (APIENTRY * BlendFunc)(GLenum sfactor, GLenum dfactor); + void (APIENTRY * Flush)(); + void (APIENTRY * Finish)(); + void (APIENTRY * Enable)(GLenum cap); + void (APIENTRY * Disable)(GLenum cap); + void (APIENTRY * DepthMask)(GLboolean flag); + void (APIENTRY * ColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); + void (APIENTRY * StencilMask)(GLuint mask); + void (APIENTRY * ClearDepth)(GLdouble depth); + void (APIENTRY * ClearStencil)(GLint s); + void (APIENTRY * ClearColor)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); + void (APIENTRY * Clear)(GLbitfield mask); + void (APIENTRY * DrawBuffer)(GLenum mode); + void (APIENTRY * TexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY * TexImage1D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY * TexParameteriv)(GLenum target, GLenum pname, const GLint *params); + void (APIENTRY * TexParameteri)(GLenum target, GLenum pname, GLint param); + void (APIENTRY * TexParameterfv)(GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY * TexParameterf)(GLenum target, GLenum pname, GLfloat param); + void (APIENTRY * Scissor)(GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY * PolygonMode)(GLenum face, GLenum mode); + void (APIENTRY * PointSize)(GLfloat size); + void (APIENTRY * LineWidth)(GLfloat width); + void (APIENTRY * Hint)(GLenum target, GLenum mode); + void (APIENTRY * FrontFace)(GLenum mode); + void (APIENTRY * CullFace)(GLenum mode); + + void (APIENTRY * Translatef)(GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY * Translated)(GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY * Scalef)(GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY * Scaled)(GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY * Rotatef)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY * Rotated)(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY * PushMatrix)(); + void (APIENTRY * PopMatrix)(); + void (APIENTRY * Ortho)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); + void (APIENTRY * MultMatrixd)(const GLdouble *m); + void (APIENTRY * MultMatrixf)(const GLfloat *m); + void (APIENTRY * MatrixMode)(GLenum mode); + void (APIENTRY * LoadMatrixd)(const GLdouble *m); + void (APIENTRY * LoadMatrixf)(const GLfloat *m); + void (APIENTRY * LoadIdentity)(); + void (APIENTRY * Frustum)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); + GLboolean (APIENTRY * IsList)(GLuint list); + void (APIENTRY * GetTexGeniv)(GLenum coord, GLenum pname, GLint *params); + void (APIENTRY * GetTexGenfv)(GLenum coord, GLenum pname, GLfloat *params); + void (APIENTRY * GetTexGendv)(GLenum coord, GLenum pname, GLdouble *params); + void (APIENTRY * GetTexEnviv)(GLenum target, GLenum pname, GLint *params); + void (APIENTRY * GetTexEnvfv)(GLenum target, GLenum pname, GLfloat *params); + void (APIENTRY * GetPolygonStipple)(GLubyte *mask); + void (APIENTRY * GetPixelMapusv)(GLenum map, GLushort *values); + void (APIENTRY * GetPixelMapuiv)(GLenum map, GLuint *values); + void (APIENTRY * GetPixelMapfv)(GLenum map, GLfloat *values); + void (APIENTRY * GetMaterialiv)(GLenum face, GLenum pname, GLint *params); + void (APIENTRY * GetMaterialfv)(GLenum face, GLenum pname, GLfloat *params); + void (APIENTRY * GetMapiv)(GLenum target, GLenum query, GLint *v); + void (APIENTRY * GetMapfv)(GLenum target, GLenum query, GLfloat *v); + void (APIENTRY * GetMapdv)(GLenum target, GLenum query, GLdouble *v); + void (APIENTRY * GetLightiv)(GLenum light, GLenum pname, GLint *params); + void (APIENTRY * GetLightfv)(GLenum light, GLenum pname, GLfloat *params); + void (APIENTRY * GetClipPlane)(GLenum plane, GLdouble *equation); + void (APIENTRY * DrawPixels)(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY * CopyPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); + void (APIENTRY * PixelMapusv)(GLenum map, GLint mapsize, const GLushort *values); + void (APIENTRY * PixelMapuiv)(GLenum map, GLint mapsize, const GLuint *values); + void (APIENTRY * PixelMapfv)(GLenum map, GLint mapsize, const GLfloat *values); + void (APIENTRY * PixelTransferi)(GLenum pname, GLint param); + void (APIENTRY * PixelTransferf)(GLenum pname, GLfloat param); + void (APIENTRY * PixelZoom)(GLfloat xfactor, GLfloat yfactor); + void (APIENTRY * AlphaFunc)(GLenum func, GLfloat ref); + void (APIENTRY * EvalPoint2)(GLint i, GLint j); + void (APIENTRY * EvalMesh2)(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); + void (APIENTRY * EvalPoint1)(GLint i); + void (APIENTRY * EvalMesh1)(GLenum mode, GLint i1, GLint i2); + void (APIENTRY * EvalCoord2fv)(const GLfloat *u); + void (APIENTRY * EvalCoord2f)(GLfloat u, GLfloat v); + void (APIENTRY * EvalCoord2dv)(const GLdouble *u); + void (APIENTRY * EvalCoord2d)(GLdouble u, GLdouble v); + void (APIENTRY * EvalCoord1fv)(const GLfloat *u); + void (APIENTRY * EvalCoord1f)(GLfloat u); + void (APIENTRY * EvalCoord1dv)(const GLdouble *u); + void (APIENTRY * EvalCoord1d)(GLdouble u); + void (APIENTRY * MapGrid2f)(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); + void (APIENTRY * MapGrid2d)(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); + void (APIENTRY * MapGrid1f)(GLint un, GLfloat u1, GLfloat u2); + void (APIENTRY * MapGrid1d)(GLint un, GLdouble u1, GLdouble u2); + void (APIENTRY * Map2f)(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); + void (APIENTRY * Map2d)(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); + void (APIENTRY * Map1f)(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); + void (APIENTRY * Map1d)(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); + void (APIENTRY * PushAttrib)(GLbitfield mask); + void (APIENTRY * PopAttrib)(); + void (APIENTRY * Accum)(GLenum op, GLfloat value); + void (APIENTRY * IndexMask)(GLuint mask); + void (APIENTRY * ClearIndex)(GLfloat c); + void (APIENTRY * ClearAccum)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); + void (APIENTRY * PushName)(GLuint name); + void (APIENTRY * PopName)(); + void (APIENTRY * PassThrough)(GLfloat token); + void (APIENTRY * LoadName)(GLuint name); + void (APIENTRY * InitNames)(); + GLint (APIENTRY * RenderMode)(GLenum mode); + void (APIENTRY * SelectBuffer)(GLsizei size, GLuint *buffer); + void (APIENTRY * FeedbackBuffer)(GLsizei size, GLenum type, GLfloat *buffer); + void (APIENTRY * TexGeniv)(GLenum coord, GLenum pname, const GLint *params); + void (APIENTRY * TexGeni)(GLenum coord, GLenum pname, GLint param); + void (APIENTRY * TexGenfv)(GLenum coord, GLenum pname, const GLfloat *params); + void (APIENTRY * TexGenf)(GLenum coord, GLenum pname, GLfloat param); + void (APIENTRY * TexGendv)(GLenum coord, GLenum pname, const GLdouble *params); + void (APIENTRY * TexGend)(GLenum coord, GLenum pname, GLdouble param); + void (APIENTRY * TexEnviv)(GLenum target, GLenum pname, const GLint *params); + void (APIENTRY * TexEnvi)(GLenum target, GLenum pname, GLint param); + void (APIENTRY * TexEnvfv)(GLenum target, GLenum pname, const GLfloat *params); + void (APIENTRY * TexEnvf)(GLenum target, GLenum pname, GLfloat param); + void (APIENTRY * ShadeModel)(GLenum mode); + void (APIENTRY * PolygonStipple)(const GLubyte *mask); + void (APIENTRY * Materialiv)(GLenum face, GLenum pname, const GLint *params); + void (APIENTRY * Materiali)(GLenum face, GLenum pname, GLint param); + void (APIENTRY * Materialfv)(GLenum face, GLenum pname, const GLfloat *params); + void (APIENTRY * Materialf)(GLenum face, GLenum pname, GLfloat param); + void (APIENTRY * LineStipple)(GLint factor, GLushort pattern); + void (APIENTRY * LightModeliv)(GLenum pname, const GLint *params); + void (APIENTRY * LightModeli)(GLenum pname, GLint param); + void (APIENTRY * LightModelfv)(GLenum pname, const GLfloat *params); + void (APIENTRY * LightModelf)(GLenum pname, GLfloat param); + void (APIENTRY * Lightiv)(GLenum light, GLenum pname, const GLint *params); + void (APIENTRY * Lighti)(GLenum light, GLenum pname, GLint param); + void (APIENTRY * Lightfv)(GLenum light, GLenum pname, const GLfloat *params); + void (APIENTRY * Lightf)(GLenum light, GLenum pname, GLfloat param); + void (APIENTRY * Fogiv)(GLenum pname, const GLint *params); + void (APIENTRY * Fogi)(GLenum pname, GLint param); + void (APIENTRY * Fogfv)(GLenum pname, const GLfloat *params); + void (APIENTRY * Fogf)(GLenum pname, GLfloat param); + void (APIENTRY * ColorMaterial)(GLenum face, GLenum mode); + void (APIENTRY * ClipPlane)(GLenum plane, const GLdouble *equation); + void (APIENTRY * Vertex4sv)(const GLshort *v); + void (APIENTRY * Vertex4s)(GLshort x, GLshort y, GLshort z, GLshort w); + void (APIENTRY * Vertex4iv)(const GLint *v); + void (APIENTRY * Vertex4i)(GLint x, GLint y, GLint z, GLint w); + void (APIENTRY * Vertex4fv)(const GLfloat *v); + void (APIENTRY * Vertex4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY * Vertex4dv)(const GLdouble *v); + void (APIENTRY * Vertex4d)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY * Vertex3sv)(const GLshort *v); + void (APIENTRY * Vertex3s)(GLshort x, GLshort y, GLshort z); + void (APIENTRY * Vertex3iv)(const GLint *v); + void (APIENTRY * Vertex3i)(GLint x, GLint y, GLint z); + void (APIENTRY * Vertex3fv)(const GLfloat *v); + void (APIENTRY * Vertex3f)(GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY * Vertex3dv)(const GLdouble *v); + void (APIENTRY * Vertex3d)(GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY * Vertex2sv)(const GLshort *v); + void (APIENTRY * Vertex2s)(GLshort x, GLshort y); + void (APIENTRY * Vertex2iv)(const GLint *v); + void (APIENTRY * Vertex2i)(GLint x, GLint y); + void (APIENTRY * Vertex2fv)(const GLfloat *v); + void (APIENTRY * Vertex2f)(GLfloat x, GLfloat y); + void (APIENTRY * Vertex2dv)(const GLdouble *v); + void (APIENTRY * Vertex2d)(GLdouble x, GLdouble y); + void (APIENTRY * TexCoord4sv)(const GLshort *v); + void (APIENTRY * TexCoord4s)(GLshort s, GLshort t, GLshort r, GLshort q); + void (APIENTRY * TexCoord4iv)(const GLint *v); + void (APIENTRY * TexCoord4i)(GLint s, GLint t, GLint r, GLint q); + void (APIENTRY * TexCoord4fv)(const GLfloat *v); + void (APIENTRY * TexCoord4f)(GLfloat s, GLfloat t, GLfloat r, GLfloat q); + void (APIENTRY * TexCoord4dv)(const GLdouble *v); + void (APIENTRY * TexCoord4d)(GLdouble s, GLdouble t, GLdouble r, GLdouble q); + void (APIENTRY * TexCoord3sv)(const GLshort *v); + void (APIENTRY * TexCoord3s)(GLshort s, GLshort t, GLshort r); + void (APIENTRY * TexCoord3iv)(const GLint *v); + void (APIENTRY * TexCoord3i)(GLint s, GLint t, GLint r); + void (APIENTRY * TexCoord3fv)(const GLfloat *v); + void (APIENTRY * TexCoord3f)(GLfloat s, GLfloat t, GLfloat r); + void (APIENTRY * TexCoord3dv)(const GLdouble *v); + void (APIENTRY * TexCoord3d)(GLdouble s, GLdouble t, GLdouble r); + void (APIENTRY * TexCoord2sv)(const GLshort *v); + void (APIENTRY * TexCoord2s)(GLshort s, GLshort t); + void (APIENTRY * TexCoord2iv)(const GLint *v); + void (APIENTRY * TexCoord2i)(GLint s, GLint t); + void (APIENTRY * TexCoord2fv)(const GLfloat *v); + void (APIENTRY * TexCoord2f)(GLfloat s, GLfloat t); + void (APIENTRY * TexCoord2dv)(const GLdouble *v); + void (APIENTRY * TexCoord2d)(GLdouble s, GLdouble t); + void (APIENTRY * TexCoord1sv)(const GLshort *v); + void (APIENTRY * TexCoord1s)(GLshort s); + void (APIENTRY * TexCoord1iv)(const GLint *v); + void (APIENTRY * TexCoord1i)(GLint s); + void (APIENTRY * TexCoord1fv)(const GLfloat *v); + void (APIENTRY * TexCoord1f)(GLfloat s); + void (APIENTRY * TexCoord1dv)(const GLdouble *v); + void (APIENTRY * TexCoord1d)(GLdouble s); + void (APIENTRY * Rectsv)(const GLshort *v1, const GLshort *v2); + void (APIENTRY * Rects)(GLshort x1, GLshort y1, GLshort x2, GLshort y2); + void (APIENTRY * Rectiv)(const GLint *v1, const GLint *v2); + void (APIENTRY * Recti)(GLint x1, GLint y1, GLint x2, GLint y2); + void (APIENTRY * Rectfv)(const GLfloat *v1, const GLfloat *v2); + void (APIENTRY * Rectf)(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); + void (APIENTRY * Rectdv)(const GLdouble *v1, const GLdouble *v2); + void (APIENTRY * Rectd)(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); + void (APIENTRY * RasterPos4sv)(const GLshort *v); + void (APIENTRY * RasterPos4s)(GLshort x, GLshort y, GLshort z, GLshort w); + void (APIENTRY * RasterPos4iv)(const GLint *v); + void (APIENTRY * RasterPos4i)(GLint x, GLint y, GLint z, GLint w); + void (APIENTRY * RasterPos4fv)(const GLfloat *v); + void (APIENTRY * RasterPos4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY * RasterPos4dv)(const GLdouble *v); + void (APIENTRY * RasterPos4d)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); + void (APIENTRY * RasterPos3sv)(const GLshort *v); + void (APIENTRY * RasterPos3s)(GLshort x, GLshort y, GLshort z); + void (APIENTRY * RasterPos3iv)(const GLint *v); + void (APIENTRY * RasterPos3i)(GLint x, GLint y, GLint z); + void (APIENTRY * RasterPos3fv)(const GLfloat *v); + void (APIENTRY * RasterPos3f)(GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY * RasterPos3dv)(const GLdouble *v); + void (APIENTRY * RasterPos3d)(GLdouble x, GLdouble y, GLdouble z); + void (APIENTRY * RasterPos2sv)(const GLshort *v); + void (APIENTRY * RasterPos2s)(GLshort x, GLshort y); + void (APIENTRY * RasterPos2iv)(const GLint *v); + void (APIENTRY * RasterPos2i)(GLint x, GLint y); + void (APIENTRY * RasterPos2fv)(const GLfloat *v); + void (APIENTRY * RasterPos2f)(GLfloat x, GLfloat y); + void (APIENTRY * RasterPos2dv)(const GLdouble *v); + void (APIENTRY * RasterPos2d)(GLdouble x, GLdouble y); + void (APIENTRY * Normal3sv)(const GLshort *v); + void (APIENTRY * Normal3s)(GLshort nx, GLshort ny, GLshort nz); + void (APIENTRY * Normal3iv)(const GLint *v); + void (APIENTRY * Normal3i)(GLint nx, GLint ny, GLint nz); + void (APIENTRY * Normal3fv)(const GLfloat *v); + void (APIENTRY * Normal3f)(GLfloat nx, GLfloat ny, GLfloat nz); + void (APIENTRY * Normal3dv)(const GLdouble *v); + void (APIENTRY * Normal3d)(GLdouble nx, GLdouble ny, GLdouble nz); + void (APIENTRY * Normal3bv)(const GLbyte *v); + void (APIENTRY * Normal3b)(GLbyte nx, GLbyte ny, GLbyte nz); + void (APIENTRY * Indexsv)(const GLshort *c); + void (APIENTRY * Indexs)(GLshort c); + void (APIENTRY * Indexiv)(const GLint *c); + void (APIENTRY * Indexi)(GLint c); + void (APIENTRY * Indexfv)(const GLfloat *c); + void (APIENTRY * Indexf)(GLfloat c); + void (APIENTRY * Indexdv)(const GLdouble *c); + void (APIENTRY * Indexd)(GLdouble c); + void (APIENTRY * End)(); + void (APIENTRY * EdgeFlagv)(const GLboolean *flag); + void (APIENTRY * EdgeFlag)(GLboolean flag); + void (APIENTRY * Color4usv)(const GLushort *v); + void (APIENTRY * Color4us)(GLushort red, GLushort green, GLushort blue, GLushort alpha); + void (APIENTRY * Color4uiv)(const GLuint *v); + void (APIENTRY * Color4ui)(GLuint red, GLuint green, GLuint blue, GLuint alpha); + void (APIENTRY * Color4ubv)(const GLubyte *v); + void (APIENTRY * Color4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); + void (APIENTRY * Color4sv)(const GLshort *v); + void (APIENTRY * Color4s)(GLshort red, GLshort green, GLshort blue, GLshort alpha); + void (APIENTRY * Color4iv)(const GLint *v); + void (APIENTRY * Color4i)(GLint red, GLint green, GLint blue, GLint alpha); + void (APIENTRY * Color4fv)(const GLfloat *v); + void (APIENTRY * Color4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); + void (APIENTRY * Color4dv)(const GLdouble *v); + void (APIENTRY * Color4d)(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); + void (APIENTRY * Color4bv)(const GLbyte *v); + void (APIENTRY * Color4b)(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); + void (APIENTRY * Color3usv)(const GLushort *v); + void (APIENTRY * Color3us)(GLushort red, GLushort green, GLushort blue); + void (APIENTRY * Color3uiv)(const GLuint *v); + void (APIENTRY * Color3ui)(GLuint red, GLuint green, GLuint blue); + void (APIENTRY * Color3ubv)(const GLubyte *v); + void (APIENTRY * Color3ub)(GLubyte red, GLubyte green, GLubyte blue); + void (APIENTRY * Color3sv)(const GLshort *v); + void (APIENTRY * Color3s)(GLshort red, GLshort green, GLshort blue); + void (APIENTRY * Color3iv)(const GLint *v); + void (APIENTRY * Color3i)(GLint red, GLint green, GLint blue); + void (APIENTRY * Color3fv)(const GLfloat *v); + void (APIENTRY * Color3f)(GLfloat red, GLfloat green, GLfloat blue); + void (APIENTRY * Color3dv)(const GLdouble *v); + void (APIENTRY * Color3d)(GLdouble red, GLdouble green, GLdouble blue); + void (APIENTRY * Color3bv)(const GLbyte *v); + void (APIENTRY * Color3b)(GLbyte red, GLbyte green, GLbyte blue); + void (APIENTRY * Bitmap)(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); + void (APIENTRY * Begin)(GLenum mode); + void (APIENTRY * ListBase)(GLuint base); + GLuint (APIENTRY * GenLists)(GLsizei range); + void (APIENTRY * DeleteLists)(GLuint list, GLsizei range); + void (APIENTRY * CallLists)(GLsizei n, GLenum type, const GLvoid *lists); + void (APIENTRY * CallList)(GLuint list); + void (APIENTRY * EndList)(); + void (APIENTRY * NewList)(GLuint list, GLenum mode); + + // OpenGL 1.1 + void (APIENTRY * Indexubv)(const GLubyte *c); + void (APIENTRY * Indexub)(GLubyte c); + GLboolean (APIENTRY * IsTexture)(GLuint texture); + void (APIENTRY * GenTextures)(GLsizei n, GLuint *textures); + void (APIENTRY * DeleteTextures)(GLsizei n, const GLuint *textures); + void (APIENTRY * BindTexture)(GLenum target, GLuint texture); + void (APIENTRY * TexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY * TexSubImage1D)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); + void (APIENTRY * CopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY * CopyTexSubImage1D)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); + void (APIENTRY * CopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); + void (APIENTRY * CopyTexImage1D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); + void (APIENTRY * PolygonOffset)(GLfloat factor, GLfloat units); + void (APIENTRY * GetPointerv)(GLenum pname, GLvoid* *params); + void (APIENTRY * DrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); + void (APIENTRY * DrawArrays)(GLenum mode, GLint first, GLsizei count); + + void (APIENTRY * PushClientAttrib)(GLbitfield mask); + void (APIENTRY * PopClientAttrib)(); + void (APIENTRY * PrioritizeTextures)(GLsizei n, const GLuint *textures, const GLfloat *priorities); + GLboolean (APIENTRY * AreTexturesResident)(GLsizei n, const GLuint *textures, GLboolean *residences); + void (APIENTRY * VertexPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY * TexCoordPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY * NormalPointer)(GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY * InterleavedArrays)(GLenum format, GLsizei stride, const GLvoid *pointer); + void (APIENTRY * IndexPointer)(GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY * EnableClientState)(GLenum array); + void (APIENTRY * EdgeFlagPointer)(GLsizei stride, const GLvoid *pointer); + void (APIENTRY * DisableClientState)(GLenum array); + void (APIENTRY * ColorPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); + void (APIENTRY * ArrayElement)(GLint i); + + // OpenGL ES 2.0 + void (APIENTRY * ActiveTexture)(GLenum texture); + void (APIENTRY * AttachShader)(GLuint program, GLuint shader); + void (APIENTRY * BindAttribLocation)(GLuint program, GLuint index, const GLchar* name); + void (APIENTRY * BindBuffer)(GLenum target, GLuint buffer); + void (APIENTRY * BindFramebuffer)(GLenum target, GLuint framebuffer); + void (APIENTRY * BindRenderbuffer)(GLenum target, GLuint renderbuffer); + void (APIENTRY * BlendColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void (APIENTRY * BlendEquation)(GLenum mode); + void (APIENTRY * BlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha); + void (APIENTRY * BlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); + void (APIENTRY * BufferData)(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage); + void (APIENTRY * BufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data); + GLenum (APIENTRY * CheckFramebufferStatus)(GLenum target); + void (APIENTRY * ClearDepthf)(GLclampf depth); + void (APIENTRY * CompileShader)(GLuint shader); + void (APIENTRY * CompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data); + void (APIENTRY * CompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data); + GLuint (APIENTRY * CreateProgram)(void); + GLuint (APIENTRY * CreateShader)(GLenum type); + void (APIENTRY * DeleteBuffers)(GLsizei n, const GLuint* buffers); + void (APIENTRY * DeleteFramebuffers)(GLsizei n, const GLuint* framebuffers); + void (APIENTRY * DeleteProgram)(GLuint program); + void (APIENTRY * DeleteRenderbuffers)(GLsizei n, const GLuint* renderbuffers); + void (APIENTRY * DeleteShader)(GLuint shader); + void (APIENTRY * DepthRangef)(GLclampf zNear, GLclampf zFar); + void (APIENTRY * DetachShader)(GLuint program, GLuint shader); + void (APIENTRY * DisableVertexAttribArray)(GLuint index); + void (APIENTRY * EnableVertexAttribArray)(GLuint index); + void (APIENTRY * FramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); + void (APIENTRY * FramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); + void (APIENTRY * GenBuffers)(GLsizei n, GLuint* buffers); + void (APIENTRY * GenerateMipmap)(GLenum target); + void (APIENTRY * GenFramebuffers)(GLsizei n, GLuint* framebuffers); + void (APIENTRY * GenRenderbuffers)(GLsizei n, GLuint* renderbuffers); + void (APIENTRY * GetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); + void (APIENTRY * GetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); + void (APIENTRY * GetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders); + int (APIENTRY * GetAttribLocation)(GLuint program, const GLchar* name); + void (APIENTRY * GetBufferParameteriv)(GLenum target, GLenum pname, GLint* params); + void (APIENTRY * GetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params); + void (APIENTRY * GetProgramiv)(GLuint program, GLenum pname, GLint* params); + void (APIENTRY * GetProgramInfoLog)(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog); + void (APIENTRY * GetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params); + void (APIENTRY * GetShaderiv)(GLuint shader, GLenum pname, GLint* params); + void (APIENTRY * GetShaderInfoLog)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog); + void (APIENTRY * GetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); + void (APIENTRY * GetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source); + void (APIENTRY * GetUniformfv)(GLuint program, GLint location, GLfloat* params); + void (APIENTRY * GetUniformiv)(GLuint program, GLint location, GLint* params); + int (APIENTRY * GetUniformLocation)(GLuint program, const GLchar* name); + void (APIENTRY * GetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params); + void (APIENTRY * GetVertexAttribiv)(GLuint index, GLenum pname, GLint* params); + void (APIENTRY * GetVertexAttribPointerv)(GLuint index, GLenum pname, GLvoid** pointer); + GLboolean (APIENTRY * IsBuffer)(GLuint buffer); + GLboolean (APIENTRY * IsFramebuffer)(GLuint framebuffer); + GLboolean (APIENTRY * IsProgram)(GLuint program); + GLboolean (APIENTRY * IsRenderbuffer)(GLuint renderbuffer); + GLboolean (APIENTRY * IsShader)(GLuint shader); + void (APIENTRY * LinkProgram)(GLuint program); + void (APIENTRY * ReleaseShaderCompiler)(void); + void (APIENTRY * RenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); + void (APIENTRY * SampleCoverage)(GLclampf value, GLboolean invert); + void (APIENTRY * ShaderBinary)(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length); + void (APIENTRY * ShaderSource)(GLuint shader, GLsizei count, const GLchar* *string, const GLint* length); + void (APIENTRY * StencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask); + void (APIENTRY * StencilMaskSeparate)(GLenum face, GLuint mask); + void (APIENTRY * StencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass); + void (APIENTRY * Uniform1f)(GLint location, GLfloat x); + void (APIENTRY * Uniform1fv)(GLint location, GLsizei count, const GLfloat* v); + void (APIENTRY * Uniform1i)(GLint location, GLint x); + void (APIENTRY * Uniform1iv)(GLint location, GLsizei count, const GLint* v); + void (APIENTRY * Uniform2f)(GLint location, GLfloat x, GLfloat y); + void (APIENTRY * Uniform2fv)(GLint location, GLsizei count, const GLfloat* v); + void (APIENTRY * Uniform2i)(GLint location, GLint x, GLint y); + void (APIENTRY * Uniform2iv)(GLint location, GLsizei count, const GLint* v); + void (APIENTRY * Uniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY * Uniform3fv)(GLint location, GLsizei count, const GLfloat* v); + void (APIENTRY * Uniform3i)(GLint location, GLint x, GLint y, GLint z); + void (APIENTRY * Uniform3iv)(GLint location, GLsizei count, const GLint* v); + void (APIENTRY * Uniform4f)(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY * Uniform4fv)(GLint location, GLsizei count, const GLfloat* v); + void (APIENTRY * Uniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w); + void (APIENTRY * Uniform4iv)(GLint location, GLsizei count, const GLint* v); + void (APIENTRY * UniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void (APIENTRY * UniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void (APIENTRY * UniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void (APIENTRY * UseProgram)(GLuint program); + void (APIENTRY * ValidateProgram)(GLuint program); + void (APIENTRY * VertexAttrib1f)(GLuint indx, GLfloat x); + void (APIENTRY * VertexAttrib1fv)(GLuint indx, const GLfloat* values); + void (APIENTRY * VertexAttrib2f)(GLuint indx, GLfloat x, GLfloat y); + void (APIENTRY * VertexAttrib2fv)(GLuint indx, const GLfloat* values); + void (APIENTRY * VertexAttrib3f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY * VertexAttrib3fv)(GLuint indx, const GLfloat* values); + void (APIENTRY * VertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY * VertexAttrib4fv)(GLuint indx, const GLfloat* values); + void (APIENTRY * VertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr); + +protected: + HMODULE m_lib; + LibType m_libraryType; + bool m_loaded; +}; + +class QWindowsOpenGL : public QAbstractWindowsOpenGL +{ +public: + QWindowsOpenGL(); + ~QWindowsOpenGL(); + +private: + bool load(const char *glName, const char *eglName); + void unload(); + + void resolve(); + + void resolveWGL(); + void resolveEGL(); + void resolveGLCommon(); + void resolveGL11(); + void resolveGLES2(); + + FARPROC resolveFunc(const char *name); + FARPROC resolveEglFunc(const char *name); + + bool testDesktopGL(); + + HMODULE m_eglLib; +}; + +static QString qgl_windowsErrorMessage(unsigned long errorCode) +{ + QString rc = QString::fromLatin1("#%1: ").arg(errorCode); + ushort *lpMsgBuf; + + const int len = FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errorCode, 0, (LPTSTR)&lpMsgBuf, 0, NULL); + if (len) { + rc += QString::fromUtf16(lpMsgBuf, len); + LocalFree(lpMsgBuf); + } else { + rc += QString::fromLatin1("<unknown error>"); + } + return rc; +} + +static HMODULE qgl_loadLib(const char *name, bool warnOnFail = true) +{ + HMODULE lib = LoadLibraryA(name); + + if (lib) + return lib; + + if (warnOnFail) { + QString msg = qgl_windowsErrorMessage(GetLastError()); + qCWarning(qglLc, "Failed to load %s: %s", name, qPrintable(msg)); + } + + return 0; +} + +QWindowsOpenGL::QWindowsOpenGL() + : m_eglLib(0) +{ + if (qEnvironmentVariableIsSet("QT_OPENGLPROXY_DEBUG")) + QLoggingCategory::setFilterRules(QStringLiteral("qt.gui.openglproxy=true")); + + enum RequestedLib { + Unknown, + Desktop, + GLES + } req = Unknown; + + // Check if the application has requested a certain implementation. + if (QCoreApplication::testAttribute(Qt::AA_UseDesktopOpenGL)) + req = Desktop; + else if (QCoreApplication::testAttribute(Qt::AA_UseOpenGLES)) + req = GLES; + + // Check if an implementation is forced through the environment variable. + QByteArray requested = qgetenv("QT_OPENGL"); + if (requested == QByteArrayLiteral("desktop")) + req = Desktop; + else if (requested == QByteArrayLiteral("angle")) + req = GLES; + + bool desktopTested = false; + if (req == Unknown) { + // No explicit request. Start testing. opengl32.dll is preferred. Angle is the fallback. + desktopTested = true; + if (testDesktopGL()) + req = Desktop; + else + req = GLES; + } + + Q_ASSERT(req != Unknown); + + if (req == GLES) { + qCDebug(qglLc, "Using Angle"); +#ifdef QT_DEBUG + m_loaded = load("libglesv2d.dll", "libegld.dll"); +#else + m_loaded = load("libglesv2.dll", "libegl.dll"); +#endif + if (m_loaded) { + m_libraryType = QWindowsOpenGL::GLES2; + } else { + // Could not load Angle. Try opengl32.dll. + if (!desktopTested && testDesktopGL()) + req = Desktop; + } + } + + if (req == Desktop) { + qCDebug(qglLc, "Using desktop OpenGL"); + m_loaded = load("opengl32.dll", 0); + if (m_loaded) + m_libraryType = QWindowsOpenGL::DesktopGL; + } + + if (m_loaded) + resolve(); + + // When no library is loaded, keep on running. All EGL/WGL/GL functions will + // return 0 in this case without further errors. It is up to the clients + // (application code, Qt Quick, etc.) to act when eglInitialize() and + // friends fail, i.e. when QOpenGLContext::create() returns false due to the + // platform plugin's failure to create a platform context. +} + +QWindowsOpenGL::~QWindowsOpenGL() +{ + unload(); +} + +bool QWindowsOpenGL::load(const char *glName, const char *eglName) +{ + qCDebug(qglLc, "Loading %s %s", glName, eglName ? eglName : ""); + + bool result = true; + + if (glName) { + m_lib = qgl_loadLib(glName); + result &= m_lib != 0; + } + + if (eglName) { + m_eglLib = qgl_loadLib(eglName); + result &= m_eglLib != 0; + } + + if (!result) + unload(); + + return result; +} + +void QWindowsOpenGL::unload() +{ + if (m_lib) { + FreeLibrary(m_lib); + m_lib = 0; + } + if (m_eglLib) { + FreeLibrary(m_eglLib); + m_eglLib = 0; + } + m_loaded = false; +} + +FARPROC QWindowsOpenGL::resolveFunc(const char *name) +{ + FARPROC proc = m_lib ? ::GetProcAddress(m_lib, name) : 0; + if (!proc) + qCDebug(qglLc, "Failed to resolve GL function %s", name); + return proc; +} + +FARPROC QWindowsOpenGL::resolveEglFunc(const char *name) +{ + FARPROC proc = m_eglLib ? ::GetProcAddress(m_eglLib, name) : 0; + if (!proc) + qCDebug(qglLc, "Failed to resolve EGL function %s", name); + return proc; +} + +void QWindowsOpenGL::resolveWGL() +{ + CopyContext = reinterpret_cast<BOOL (WINAPI *)(HGLRC, HGLRC, UINT)>(resolveFunc("wglCopyContext")); + CreateContext = reinterpret_cast<HGLRC (WINAPI *)(HDC)>(resolveFunc("wglCreateContext")); + CreateLayerContext = reinterpret_cast<HGLRC (WINAPI *)(HDC, int)>(resolveFunc("wglCreateLayerContext")); + DeleteContext = reinterpret_cast<BOOL (WINAPI *)(HGLRC)>(resolveFunc("wglDeleteContext")); + GetCurrentContext = reinterpret_cast<HGLRC (WINAPI *)()>(resolveFunc("wglGetCurrentContext")); + GetCurrentDC = reinterpret_cast<HDC (WINAPI *)()>(resolveFunc("wglGetCurrentDC")); + GetProcAddress = reinterpret_cast<PROC (WINAPI *)(LPCSTR)>(resolveFunc("wglGetProcAddress")); + MakeCurrent = reinterpret_cast<BOOL (WINAPI *)(HDC, HGLRC)>(resolveFunc("wglMakeCurrent")); + ShareLists = reinterpret_cast<BOOL (WINAPI *)(HGLRC, HGLRC)>(resolveFunc("wglShareLists")); + UseFontBitmapsW = reinterpret_cast<BOOL (WINAPI *)(HDC, DWORD, DWORD, DWORD)>(resolveFunc("wglUseFontBitmapsW")); + UseFontOutlinesW = reinterpret_cast<BOOL (WINAPI *)(HDC, DWORD, DWORD, DWORD, FLOAT, FLOAT, int, LPGLYPHMETRICSFLOAT)>(resolveFunc("wglUseFontOutlinesW")); + DescribeLayerPlane = reinterpret_cast<BOOL (WINAPI *)(HDC, int, int, UINT, LPLAYERPLANEDESCRIPTOR)>(resolveFunc("wglDescribeLayerPlane")); + SetLayerPaletteEntries = reinterpret_cast<int (WINAPI *)(HDC, int, int, int, CONST COLORREF *)>(resolveFunc("wglSetLayerPaletteEntries")); + GetLayerPaletteEntries = reinterpret_cast<int (WINAPI *)(HDC, int, int, int, COLORREF *)>(resolveFunc("wglGetLayerPaletteEntries")); + RealizeLayerPalette = reinterpret_cast<BOOL (WINAPI *)(HDC, int, BOOL)>(resolveFunc("wglRealizeLayerPalette")); + SwapLayerBuffers = reinterpret_cast<BOOL (WINAPI *)(HDC, UINT)>(resolveFunc("wglSwapLayerBuffers")); + SwapMultipleBuffers = reinterpret_cast<DWORD (WINAPI *)(UINT, CONST WGLSWAP *)>(resolveFunc("wglSwapMultipleBuffers")); +} + +void QWindowsOpenGL::resolveEGL() +{ + EGL_GetError = reinterpret_cast<EGLint (EGLAPIENTRY *)(void)>(resolveEglFunc("eglGetError")); + EGL_GetDisplay = reinterpret_cast<EGLDisplay (EGLAPIENTRY *)(EGLNativeDisplayType)>(resolveEglFunc("eglGetDisplay")); + EGL_Initialize = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLint *, EGLint *)>(resolveEglFunc("eglInitialize")); + EGL_Terminate = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay)>(resolveEglFunc("eglTerminate")); + EGL_QueryString = reinterpret_cast<const char * (EGLAPIENTRY *)(EGLDisplay, EGLint)>(resolveEglFunc("eglQueryString")); + EGL_GetConfigs = reinterpret_cast<EGLBoolean (EGLAPIENTRY * )(EGLDisplay, EGLConfig *, EGLint, EGLint *)>(resolveEglFunc("eglGetConfigs")); + EGL_ChooseConfig = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *)>(resolveEglFunc("eglChooseConfig")); + EGL_GetConfigAttrib = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLConfig, EGLint, EGLint *)>(resolveEglFunc("eglGetConfigAttrib")); + EGL_CreateWindowSurface = reinterpret_cast<EGLSurface (EGLAPIENTRY *)(EGLDisplay, EGLConfig, EGLNativeWindowType, const EGLint *)>(resolveEglFunc("eglCreateWindowSurface")); + EGL_CreatePbufferSurface = reinterpret_cast<EGLSurface (EGLAPIENTRY *)(EGLDisplay , EGLConfig, const EGLint *)>(resolveEglFunc("eglCreatePbufferSurface")); + EGL_CreatePixmapSurface = reinterpret_cast<EGLSurface (EGLAPIENTRY * )(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType , const EGLint *)>(resolveEglFunc("eglCreatePixmapSurface")); + EGL_DestroySurface = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface )>(resolveEglFunc("eglDestroySurface")); + EGL_QuerySurface = reinterpret_cast<EGLBoolean (EGLAPIENTRY * )(EGLDisplay , EGLSurface , EGLint , EGLint *)>(resolveEglFunc("eglQuerySurface")); + EGL_BindAPI = reinterpret_cast<EGLBoolean (EGLAPIENTRY * )(EGLenum )>(resolveEglFunc("eglBindAPI")); + EGL_QueryAPI = reinterpret_cast<EGLenum (EGLAPIENTRY *)(void)>(resolveEglFunc("eglQueryAPI")); + EGL_WaitClient = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(void)>(resolveEglFunc("eglWaitClient")); + EGL_ReleaseThread = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(void)>(resolveEglFunc("eglReleaseThread")); + EGL_CreatePbufferFromClientBuffer = reinterpret_cast<EGLSurface (EGLAPIENTRY * )(EGLDisplay , EGLenum , EGLClientBuffer , EGLConfig , const EGLint *)>(resolveEglFunc("eglCreatePbufferFromClientBuffer")); + EGL_SurfaceAttrib = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface , EGLint , EGLint )>(resolveEglFunc("eglSurfaceAttrib")); + EGL_BindTexImage = reinterpret_cast<EGLBoolean (EGLAPIENTRY * )(EGLDisplay, EGLSurface , EGLint )>(resolveEglFunc("eglBindTexImage")); + EGL_ReleaseTexImage = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLSurface , EGLint)>(resolveEglFunc("eglReleaseTexImage")); + EGL_SwapInterval = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLint )>(resolveEglFunc("eglSwapInterval")); + EGL_CreateContext = reinterpret_cast<EGLContext (EGLAPIENTRY *)(EGLDisplay , EGLConfig , EGLContext , const EGLint *)>(resolveEglFunc("eglCreateContext")); + EGL_DestroyContext = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLContext)>(resolveEglFunc("eglDestroyContext")); + EGL_MakeCurrent = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface , EGLSurface , EGLContext )>(resolveEglFunc("eglMakeCurrent")); + EGL_GetCurrentContext = reinterpret_cast<EGLContext (EGLAPIENTRY *)(void)>(resolveEglFunc("eglGetCurrentContext")); + EGL_GetCurrentSurface = reinterpret_cast<EGLSurface (EGLAPIENTRY *)(EGLint )>(resolveEglFunc("eglGetCurrentSurface")); + EGL_GetCurrentDisplay = reinterpret_cast<EGLDisplay (EGLAPIENTRY *)(void)>(resolveEglFunc("eglGetCurrentDisplay")); + EGL_QueryContext = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLContext , EGLint , EGLint *)>(resolveEglFunc("eglQueryContext")); + EGL_WaitGL = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(void)>(resolveEglFunc("eglWaitGL")); + EGL_WaitNative = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLint )>(resolveEglFunc("eglWaitNative")); + EGL_SwapBuffers = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface)>(resolveEglFunc("eglSwapBuffers")); + EGL_CopyBuffers = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface , EGLNativePixmapType )>(resolveEglFunc("eglCopyBuffers")); + EGL_GetProcAddress = reinterpret_cast<__eglMustCastToProperFunctionPointerType (EGLAPIENTRY * )(const char *)>(resolveEglFunc("eglGetProcAddress")); +} + +void QWindowsOpenGL::resolveGLCommon() +{ + Viewport = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei )>(resolveFunc("glViewport")); + IsEnabled = reinterpret_cast<GLboolean (APIENTRY *)(GLenum )>(resolveFunc("glIsEnabled")); + GetTexParameteriv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint *)>(resolveFunc("glGetTexParameteriv")); + GetTexParameterfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat *)>(resolveFunc("glGetTexParameterfv")); + GetString = reinterpret_cast<const GLubyte * (APIENTRY *)(GLenum )>(resolveFunc("glGetString")); + GetIntegerv = reinterpret_cast<void (APIENTRY *)(GLenum , GLint *)>(resolveFunc("glGetIntegerv")); + GetFloatv = reinterpret_cast<void (APIENTRY *)(GLenum , GLfloat *)>(resolveFunc("glGetFloatv")); + GetError = reinterpret_cast<GLenum (APIENTRY *)()>(resolveFunc("glGetError")); + GetBooleanv = reinterpret_cast<void (APIENTRY *)(GLenum , GLboolean *)>(resolveFunc("glGetBooleanv")); + ReadPixels = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei , GLenum , GLenum , GLvoid *)>(resolveFunc("glReadPixels")); + PixelStorei = reinterpret_cast<void (APIENTRY *)(GLenum , GLint )>(resolveFunc("glPixelStorei")); + DepthFunc = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolveFunc("glDepthFunc")); + StencilOp = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLenum )>(resolveFunc("glStencilOp")); + StencilFunc = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLuint )>(resolveFunc("glStencilFunc")); + BlendFunc = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum )>(resolveFunc("glBlendFunc")); + Flush = reinterpret_cast<void (APIENTRY *)()>(resolveFunc("glFlush")); + Finish = reinterpret_cast<void (APIENTRY *)()>(resolveFunc("glFinish")); + Enable = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolveFunc("glEnable")); + Disable = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolveFunc("glDisable")); + DepthMask = reinterpret_cast<void (APIENTRY *)(GLboolean )>(resolveFunc("glDepthMask")); + ColorMask = reinterpret_cast<void (APIENTRY *)(GLboolean , GLboolean , GLboolean , GLboolean )>(resolveFunc("glColorMask")); + StencilMask = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolveFunc("glStencilMask")); + ClearStencil = reinterpret_cast<void (APIENTRY *)(GLint )>(resolveFunc("glClearStencil")); + ClearColor = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat , GLfloat )>(resolveFunc("glClearColor")); + Clear = reinterpret_cast<void (APIENTRY *)(GLbitfield )>(resolveFunc("glClear")); + TexImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLsizei , GLsizei , GLint , GLenum , GLenum , const GLvoid *)>(resolveFunc("glTexImage2D")); + TexParameteriv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLint *)>(resolveFunc("glTexParameteriv")); + TexParameteri = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint )>(resolveFunc("glTexParameteri")); + TexParameterfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLfloat *)>(resolveFunc("glTexParameterfv")); + TexParameterf = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat )>(resolveFunc("glTexParameterf")); + Scissor = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei )>(resolveFunc("glScissor")); + LineWidth = reinterpret_cast<void (APIENTRY *)(GLfloat )>(resolveFunc("glLineWidth")); + Hint = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum )>(resolveFunc("glHint")); + FrontFace = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolveFunc("glFrontFace")); + CullFace = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolveFunc("glCullFace")); + + IsTexture = reinterpret_cast<GLboolean (APIENTRY *)(GLuint )>(resolveFunc("glIsTexture")); + GenTextures = reinterpret_cast<void (APIENTRY *)(GLsizei , GLuint *)>(resolveFunc("glGenTextures")); + DeleteTextures = reinterpret_cast<void (APIENTRY *)(GLsizei , const GLuint *)>(resolveFunc("glDeleteTextures")); + BindTexture = reinterpret_cast<void (APIENTRY *)(GLenum , GLuint )>(resolveFunc("glBindTexture")); + TexSubImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLint , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)>(resolveFunc("glTexSubImage2D")); + CopyTexSubImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLint , GLint , GLint , GLsizei , GLsizei )>(resolveFunc("glCopyTexSubImage2D")); + CopyTexImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLenum , GLint , GLint , GLsizei , GLsizei , GLint )>(resolveFunc("glCopyTexImage2D")); + PolygonOffset = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat )>(resolveFunc("glPolygonOffset")); + DrawElements = reinterpret_cast<void (APIENTRY *)(GLenum , GLsizei , GLenum , const GLvoid *)>(resolveFunc("glDrawElements")); + DrawArrays = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLsizei )>(resolveFunc("glDrawArrays")); +} + +void QWindowsOpenGL::resolveGL11() +{ + DepthRange = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble )>(resolveFunc("glDepthRange")); + GetTexImage = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLenum , GLenum , GLvoid *)>(resolveFunc("glGetTexImage")); + LogicOp = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolveFunc("glLogicOp")); + ClearDepth = reinterpret_cast<void (APIENTRY *)(GLdouble )>(resolveFunc("glClearDepth")); + PolygonMode = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum )>(resolveFunc("glPolygonMode")); + PointSize = reinterpret_cast<void (APIENTRY *)(GLfloat )>(resolveFunc("glPointSize")); + GetTexLevelParameteriv = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLenum , GLint *)>(resolveFunc("glGetTexLevelParameteriv")); + GetTexLevelParameterfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLenum , GLfloat *)>(resolveFunc("glGetTexLevelParameterfv")); + GetDoublev = reinterpret_cast<void (APIENTRY *)(GLenum , GLdouble *)>(resolveFunc("glGetDoublev")); + PixelStoref = reinterpret_cast<void (APIENTRY *)(GLenum , GLfloat )>(resolveFunc("glPixelStoref")); + ReadBuffer = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolveFunc("glReadBuffer")); + DrawBuffer = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolveFunc("glDrawBuffer")); + TexImage1D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLsizei , GLint , GLenum , GLenum , const GLvoid *)>(resolveFunc("glTexImage1D")); + + Translatef = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat )>(resolveFunc("glTranslatef")); + Translated = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble , GLdouble )>(resolveFunc("glTranslated")); + Scalef = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat )>(resolveFunc("glScalef")); + Scaled = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble , GLdouble )>(resolveFunc("glScaled")); + Rotatef = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat , GLfloat )>(resolveFunc("glRotatef")); + Rotated = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble , GLdouble , GLdouble )>(resolveFunc("glRotated")); + PushMatrix = reinterpret_cast<void (APIENTRY *)()>(resolveFunc("glPushMatrix")); + PopMatrix = reinterpret_cast<void (APIENTRY *)()>(resolveFunc("glPopMatrix")); + Ortho = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble , GLdouble , GLdouble , GLdouble , GLdouble )>(resolveFunc("glOrtho")); + MultMatrixd = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glMultMatrixd")); + MultMatrixf = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glMultMatrixf")); + MatrixMode = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolveFunc("glMatrixMode")); + LoadMatrixd = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glLoadMatrixd")); + LoadMatrixf = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glLoadMatrixf")); + LoadIdentity = reinterpret_cast<void (APIENTRY *)()>(resolveFunc("glLoadIdentity")); + Frustum = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble , GLdouble , GLdouble , GLdouble , GLdouble )>(resolveFunc("glFrustum")); + IsList = reinterpret_cast<GLboolean (APIENTRY *)(GLuint )>(resolveFunc("glIsList")); + GetTexGeniv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint *)>(resolveFunc("glGetTexGeniv")); + GetTexGenfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat *)>(resolveFunc("glGetTexGenfv")); + GetTexGendv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLdouble *)>(resolveFunc("glGetTexGendv")); + GetTexEnviv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint *)>(resolveFunc("glGetTexEnviv")); + GetTexEnvfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat *)>(resolveFunc("glGetTexEnvfv")); + GetPolygonStipple = reinterpret_cast<void (APIENTRY *)(GLubyte *)>(resolveFunc("glGetPolygonStipple")); + GetPixelMapusv = reinterpret_cast<void (APIENTRY *)(GLenum , GLushort *)>(resolveFunc("glGetPixelMapusv")); + GetPixelMapuiv = reinterpret_cast<void (APIENTRY *)(GLenum , GLuint *)>(resolveFunc("glGetPixelMapuiv")); + GetPixelMapfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLfloat *)>(resolveFunc("glGetPixelMapfv")); + GetMaterialiv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint *)>(resolveFunc("glGetMaterialiv")); + GetMaterialfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat *)>(resolveFunc("glGetMaterialfv")); + GetMapiv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint *)>(resolveFunc("glGetMapiv")); + GetMapfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat *)>(resolveFunc("glGetMapfv")); + GetMapdv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLdouble *)>(resolveFunc("glGetMapdv")); + GetLightiv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint *)>(resolveFunc("glGetLightiv")); + GetLightfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat *)>(resolveFunc("glGetLightfv")); + GetClipPlane = reinterpret_cast<void (APIENTRY *)(GLenum , GLdouble *)>(resolveFunc("glGetClipPlane")); + DrawPixels = reinterpret_cast<void (APIENTRY *)(GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)>(resolveFunc("glDrawPixels")); + CopyPixels = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei , GLenum )>(resolveFunc("glCopyPixels")); + PixelMapusv = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , const GLushort *)>(resolveFunc("glPixelMapusv")); + PixelMapuiv = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , const GLuint *)>(resolveFunc("glPixelMapuiv")); + PixelMapfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , const GLfloat *)>(resolveFunc("glPixelMapfv")); + PixelTransferi = reinterpret_cast<void (APIENTRY *)(GLenum , GLint )>(resolveFunc("glPixelTransferi")); + PixelTransferf = reinterpret_cast<void (APIENTRY *)(GLenum , GLfloat )>(resolveFunc("glPixelTransferf")); + PixelZoom = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat )>(resolveFunc("glPixelZoom")); + AlphaFunc = reinterpret_cast<void (APIENTRY *)(GLenum , GLfloat )>(resolveFunc("glAlphaFunc")); + EvalPoint2 = reinterpret_cast<void (APIENTRY *)(GLint , GLint )>(resolveFunc("glEvalPoint2")); + EvalMesh2 = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLint , GLint )>(resolveFunc("glEvalMesh2")); + EvalPoint1 = reinterpret_cast<void (APIENTRY *)(GLint )>(resolveFunc("glEvalPoint1")); + EvalMesh1 = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint )>(resolveFunc("glEvalMesh1")); + EvalCoord2fv = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glEvalCoord2fv")); + EvalCoord2f = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat )>(resolveFunc("glEvalCoord2f")); + EvalCoord2dv = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glEvalCoord2dv")); + EvalCoord2d = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble )>(resolveFunc("glEvalCoord2d")); + EvalCoord1fv = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glEvalCoord1fv")); + EvalCoord1f = reinterpret_cast<void (APIENTRY *)(GLfloat )>(resolveFunc("glEvalCoord1f")); + EvalCoord1dv = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glEvalCoord1dv")); + EvalCoord1d = reinterpret_cast<void (APIENTRY *)(GLdouble )>(resolveFunc("glEvalCoord1d")); + MapGrid2f = reinterpret_cast<void (APIENTRY *)(GLint , GLfloat , GLfloat , GLint , GLfloat , GLfloat )>(resolveFunc("glMapGrid2f")); + MapGrid2d = reinterpret_cast<void (APIENTRY *)(GLint , GLdouble , GLdouble , GLint , GLdouble , GLdouble )>(resolveFunc("glMapGrid2d")); + MapGrid1f = reinterpret_cast<void (APIENTRY *)(GLint , GLfloat , GLfloat )>(resolveFunc("glMapGrid1f")); + MapGrid1d = reinterpret_cast<void (APIENTRY *)(GLint , GLdouble , GLdouble )>(resolveFunc("glMapGrid1d")); + Map2f = reinterpret_cast<void (APIENTRY *)(GLenum , GLfloat , GLfloat , GLint , GLint , GLfloat , GLfloat , GLint , GLint , const GLfloat *)>(resolveFunc("glMap2f")); + Map2d = reinterpret_cast<void (APIENTRY *)(GLenum , GLdouble , GLdouble , GLint , GLint , GLdouble , GLdouble , GLint , GLint , const GLdouble *)>(resolveFunc("glMap2d")); + Map1f = reinterpret_cast<void (APIENTRY *)(GLenum , GLfloat , GLfloat , GLint , GLint , const GLfloat *)>(resolveFunc("glMap1f")); + Map1d = reinterpret_cast<void (APIENTRY *)(GLenum , GLdouble , GLdouble , GLint , GLint , const GLdouble *)>(resolveFunc("glMap1d")); + PushAttrib = reinterpret_cast<void (APIENTRY *)(GLbitfield )>(resolveFunc("glPushAttrib")); + PopAttrib = reinterpret_cast<void (APIENTRY *)()>(resolveFunc("glPopAttrib")); + Accum = reinterpret_cast<void (APIENTRY *)(GLenum , GLfloat )>(resolveFunc("glAccum")); + IndexMask = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolveFunc("glIndexMask")); + ClearIndex = reinterpret_cast<void (APIENTRY *)(GLfloat )>(resolveFunc("glClearIndex")); + ClearAccum = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat , GLfloat )>(resolveFunc("glClearAccum")); + PushName = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolveFunc("glPushName")); + PopName = reinterpret_cast<void (APIENTRY *)()>(resolveFunc("glPopName")); + PassThrough = reinterpret_cast<void (APIENTRY *)(GLfloat )>(resolveFunc("glPassThrough")); + LoadName = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolveFunc("glLoadName")); + InitNames = reinterpret_cast<void (APIENTRY *)()>(resolveFunc("glInitNames")); + RenderMode = reinterpret_cast<GLint (APIENTRY *)(GLenum )>(resolveFunc("glRenderMode")); + SelectBuffer = reinterpret_cast<void (APIENTRY *)(GLsizei , GLuint *)>(resolveFunc("glSelectBuffer")); + FeedbackBuffer = reinterpret_cast<void (APIENTRY *)(GLsizei , GLenum , GLfloat *)>(resolveFunc("glFeedbackBuffer")); + TexGeniv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLint *)>(resolveFunc("glTexGeniv")); + TexGeni = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint )>(resolveFunc("glTexGeni")); + TexGenfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLfloat *)>(resolveFunc("glTexGenfv")); + TexGenf = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat )>(resolveFunc("glTexGenf")); + TexGendv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLdouble *)>(resolveFunc("glTexGendv")); + TexGend = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLdouble )>(resolveFunc("glTexGend")); + TexEnviv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLint *)>(resolveFunc("glTexEnviv")); + TexEnvi = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint )>(resolveFunc("glTexEnvi")); + TexEnvfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLfloat *)>(resolveFunc("glTexEnvfv")); + TexEnvf = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat )>(resolveFunc("glTexEnvf")); + ShadeModel = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolveFunc("glShadeModel")); + PolygonStipple = reinterpret_cast<void (APIENTRY *)(const GLubyte *)>(resolveFunc("glPolygonStipple")); + Materialiv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLint *)>(resolveFunc("glMaterialiv")); + Materiali = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint )>(resolveFunc("glMateriali")); + Materialfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLfloat *)>(resolveFunc("glMaterialfv")); + Materialf = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat )>(resolveFunc("glMaterialf")); + LineStipple = reinterpret_cast<void (APIENTRY *)(GLint , GLushort )>(resolveFunc("glLineStipple")); + LightModeliv = reinterpret_cast<void (APIENTRY *)(GLenum , const GLint *)>(resolveFunc("glLightModeliv")); + LightModeli = reinterpret_cast<void (APIENTRY *)(GLenum , GLint )>(resolveFunc("glLightModeli")); + LightModelfv = reinterpret_cast<void (APIENTRY *)(GLenum , const GLfloat *)>(resolveFunc("glLightModelfv")); + LightModelf = reinterpret_cast<void (APIENTRY *)(GLenum , GLfloat )>(resolveFunc("glLightModelf")); + Lightiv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLint *)>(resolveFunc("glLightiv")); + Lighti = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint )>(resolveFunc("glLighti")); + Lightfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLfloat *)>(resolveFunc("glLightfv")); + Lightf = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat )>(resolveFunc("glLightf")); + Fogiv = reinterpret_cast<void (APIENTRY *)(GLenum , const GLint *)>(resolveFunc("glFogiv")); + Fogi = reinterpret_cast<void (APIENTRY *)(GLenum , GLint )>(resolveFunc("glFogi")); + Fogfv = reinterpret_cast<void (APIENTRY *)(GLenum , const GLfloat *)>(resolveFunc("glFogfv")); + Fogf = reinterpret_cast<void (APIENTRY *)(GLenum , GLfloat )>(resolveFunc("glFogf")); + ColorMaterial = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum )>(resolveFunc("glColorMaterial")); + ClipPlane = reinterpret_cast<void (APIENTRY *)(GLenum , const GLdouble *)>(resolveFunc("glClipPlane")); + Vertex4sv = reinterpret_cast<void (APIENTRY *)(const GLshort *)>(resolveFunc("glVertex4sv")); + Vertex4s = reinterpret_cast<void (APIENTRY *)(GLshort , GLshort , GLshort , GLshort )>(resolveFunc("glVertex4s")); + Vertex4iv = reinterpret_cast<void (APIENTRY *)(const GLint *)>(resolveFunc("glVertex4iv")); + Vertex4i = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLint , GLint )>(resolveFunc("glVertex4i")); + Vertex4fv = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glVertex4fv")); + Vertex4f = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat , GLfloat )>(resolveFunc("glVertex4f")); + Vertex4dv = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glVertex4dv")); + Vertex4d = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble , GLdouble , GLdouble )>(resolveFunc("glVertex4d")); + Vertex3sv = reinterpret_cast<void (APIENTRY *)(const GLshort *)>(resolveFunc("glVertex3sv")); + Vertex3s = reinterpret_cast<void (APIENTRY *)(GLshort , GLshort , GLshort )>(resolveFunc("glVertex3s")); + Vertex3iv = reinterpret_cast<void (APIENTRY *)(const GLint *)>(resolveFunc("glVertex3iv")); + Vertex3i = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLint )>(resolveFunc("glVertex3i")); + Vertex3fv = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glVertex3fv")); + Vertex3f = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat )>(resolveFunc("glVertex3f")); + Vertex3dv = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glVertex3dv")); + Vertex3d = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble , GLdouble )>(resolveFunc("glVertex3d")); + Vertex2sv = reinterpret_cast<void (APIENTRY *)(const GLshort *)>(resolveFunc("glVertex2sv")); + Vertex2s = reinterpret_cast<void (APIENTRY *)(GLshort , GLshort )>(resolveFunc("glVertex2s")); + Vertex2iv = reinterpret_cast<void (APIENTRY *)(const GLint *)>(resolveFunc("glVertex2iv")); + Vertex2i = reinterpret_cast<void (APIENTRY *)(GLint , GLint )>(resolveFunc("glVertex2i")); + Vertex2fv = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glVertex2fv")); + Vertex2f = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat )>(resolveFunc("glVertex2f")); + Vertex2dv = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glVertex2dv")); + Vertex2d = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble )>(resolveFunc("glVertex2d")); + TexCoord4sv = reinterpret_cast<void (APIENTRY *)(const GLshort *)>(resolveFunc("glTexCoord4sv")); + TexCoord4s = reinterpret_cast<void (APIENTRY *)(GLshort , GLshort , GLshort , GLshort )>(resolveFunc("glTexCoord4s")); + TexCoord4iv = reinterpret_cast<void (APIENTRY *)(const GLint *)>(resolveFunc("glTexCoord4iv")); + TexCoord4i = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLint , GLint )>(resolveFunc("glTexCoord4i")); + TexCoord4fv = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glTexCoord4fv")); + TexCoord4f = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat , GLfloat )>(resolveFunc("glTexCoord4f")); + TexCoord4dv = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glTexCoord4dv")); + TexCoord4d = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble , GLdouble , GLdouble )>(resolveFunc("glTexCoord4d")); + TexCoord3sv = reinterpret_cast<void (APIENTRY *)(const GLshort *)>(resolveFunc("glTexCoord3sv")); + TexCoord3s = reinterpret_cast<void (APIENTRY *)(GLshort , GLshort , GLshort )>(resolveFunc("glTexCoord3s")); + TexCoord3iv = reinterpret_cast<void (APIENTRY *)(const GLint *)>(resolveFunc("glTexCoord3iv")); + TexCoord3i = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLint )>(resolveFunc("glTexCoord3i")); + TexCoord3fv = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glTexCoord3fv")); + TexCoord3f = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat )>(resolveFunc("glTexCoord3f")); + TexCoord3dv = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glTexCoord3dv")); + TexCoord3d = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble , GLdouble )>(resolveFunc("glTexCoord3d")); + TexCoord2sv = reinterpret_cast<void (APIENTRY *)(const GLshort *)>(resolveFunc("glTexCoord2sv")); + TexCoord2s = reinterpret_cast<void (APIENTRY *)(GLshort , GLshort )>(resolveFunc("glTexCoord2s")); + TexCoord2iv = reinterpret_cast<void (APIENTRY *)(const GLint *)>(resolveFunc("glTexCoord2iv")); + TexCoord2i = reinterpret_cast<void (APIENTRY *)(GLint , GLint )>(resolveFunc("glTexCoord2i")); + TexCoord2fv = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glTexCoord2fv")); + TexCoord2f = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat )>(resolveFunc("glTexCoord2f")); + TexCoord2dv = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glTexCoord2dv")); + TexCoord2d = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble )>(resolveFunc("glTexCoord2d")); + TexCoord1sv = reinterpret_cast<void (APIENTRY *)(const GLshort *)>(resolveFunc("glTexCoord1sv")); + TexCoord1s = reinterpret_cast<void (APIENTRY *)(GLshort )>(resolveFunc("glTexCoord1s")); + TexCoord1iv = reinterpret_cast<void (APIENTRY *)(const GLint *)>(resolveFunc("glTexCoord1iv")); + TexCoord1i = reinterpret_cast<void (APIENTRY *)(GLint )>(resolveFunc("glTexCoord1i")); + TexCoord1fv = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glTexCoord1fv")); + TexCoord1f = reinterpret_cast<void (APIENTRY *)(GLfloat )>(resolveFunc("glTexCoord1f")); + TexCoord1dv = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glTexCoord1dv")); + TexCoord1d = reinterpret_cast<void (APIENTRY *)(GLdouble )>(resolveFunc("glTexCoord1d")); + Rectsv = reinterpret_cast<void (APIENTRY *)(const GLshort *, const GLshort *)>(resolveFunc("glRectsv")); + Rects = reinterpret_cast<void (APIENTRY *)(GLshort , GLshort , GLshort , GLshort )>(resolveFunc("glRects")); + Rectiv = reinterpret_cast<void (APIENTRY *)(const GLint *, const GLint *)>(resolveFunc("glRectiv")); + Recti = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLint , GLint )>(resolveFunc("glRecti")); + Rectfv = reinterpret_cast<void (APIENTRY *)(const GLfloat *, const GLfloat *)>(resolveFunc("glRectfv")); + Rectf = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat , GLfloat )>(resolveFunc("glRectf")); + Rectdv = reinterpret_cast<void (APIENTRY *)(const GLdouble *, const GLdouble *)>(resolveFunc("glRectdv")); + Rectd = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble , GLdouble , GLdouble )>(resolveFunc("glRectd")); + RasterPos4sv = reinterpret_cast<void (APIENTRY *)(const GLshort *)>(resolveFunc("glRasterPos4sv")); + RasterPos4s = reinterpret_cast<void (APIENTRY *)(GLshort , GLshort , GLshort , GLshort )>(resolveFunc("glRasterPos4s")); + RasterPos4iv = reinterpret_cast<void (APIENTRY *)(const GLint *)>(resolveFunc("glRasterPos4iv")); + RasterPos4i = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLint , GLint )>(resolveFunc("glRasterPos4i")); + RasterPos4fv = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glRasterPos4fv")); + RasterPos4f = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat , GLfloat )>(resolveFunc("glRasterPos4f")); + RasterPos4dv = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glRasterPos4dv")); + RasterPos4d = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble , GLdouble , GLdouble )>(resolveFunc("glRasterPos4d")); + RasterPos3sv = reinterpret_cast<void (APIENTRY *)(const GLshort *)>(resolveFunc("glRasterPos3sv")); + RasterPos3s = reinterpret_cast<void (APIENTRY *)(GLshort , GLshort , GLshort )>(resolveFunc("glRasterPos3s")); + RasterPos3iv = reinterpret_cast<void (APIENTRY *)(const GLint *)>(resolveFunc("glRasterPos3iv")); + RasterPos3i = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLint )>(resolveFunc("glRasterPos3i")); + RasterPos3fv = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glRasterPos3fv")); + RasterPos3f = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat )>(resolveFunc("glRasterPos3f")); + RasterPos3dv = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glRasterPos3dv")); + RasterPos3d = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble , GLdouble )>(resolveFunc("glRasterPos3d")); + RasterPos2sv = reinterpret_cast<void (APIENTRY *)(const GLshort *)>(resolveFunc("glRasterPos2sv")); + RasterPos2s = reinterpret_cast<void (APIENTRY *)(GLshort , GLshort )>(resolveFunc("glRasterPos2s")); + RasterPos2iv = reinterpret_cast<void (APIENTRY *)(const GLint *)>(resolveFunc("glRasterPos2iv")); + RasterPos2i = reinterpret_cast<void (APIENTRY *)(GLint , GLint )>(resolveFunc("glRasterPos2i")); + RasterPos2fv = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glRasterPos2fv")); + RasterPos2f = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat )>(resolveFunc("glRasterPos2f")); + RasterPos2dv = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glRasterPos2dv")); + RasterPos2d = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble )>(resolveFunc("glRasterPos2d")); + Normal3sv = reinterpret_cast<void (APIENTRY *)(const GLshort *)>(resolveFunc("glNormal3sv")); + Normal3s = reinterpret_cast<void (APIENTRY *)(GLshort , GLshort , GLshort )>(resolveFunc("glNormal3s")); + Normal3iv = reinterpret_cast<void (APIENTRY *)(const GLint *)>(resolveFunc("glNormal3iv")); + Normal3i = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLint )>(resolveFunc("glNormal3i")); + Normal3fv = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glNormal3fv")); + Normal3f = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat )>(resolveFunc("glNormal3f")); + Normal3dv = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glNormal3dv")); + Normal3d = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble , GLdouble )>(resolveFunc("glNormal3d")); + Normal3bv = reinterpret_cast<void (APIENTRY *)(const GLbyte *)>(resolveFunc("glNormal3bv")); + Normal3b = reinterpret_cast<void (APIENTRY *)(GLbyte , GLbyte , GLbyte )>(resolveFunc("glNormal3b")); + Indexsv = reinterpret_cast<void (APIENTRY *)(const GLshort *)>(resolveFunc("glIndexsv")); + Indexs = reinterpret_cast<void (APIENTRY *)(GLshort )>(resolveFunc("glIndexs")); + Indexiv = reinterpret_cast<void (APIENTRY *)(const GLint *)>(resolveFunc("glIndexiv")); + Indexi = reinterpret_cast<void (APIENTRY *)(GLint )>(resolveFunc("glIndexi")); + Indexfv = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glIndexfv")); + Indexf = reinterpret_cast<void (APIENTRY *)(GLfloat )>(resolveFunc("glIndexf")); + Indexdv = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glIndexdv")); + Indexd = reinterpret_cast<void (APIENTRY *)(GLdouble )>(resolveFunc("glIndexd")); + End = reinterpret_cast<void (APIENTRY *)()>(resolveFunc("glEnd")); + EdgeFlagv = reinterpret_cast<void (APIENTRY *)(const GLboolean *)>(resolveFunc("glEdgeFlagv")); + EdgeFlag = reinterpret_cast<void (APIENTRY *)(GLboolean )>(resolveFunc("glEdgeFlag")); + Color4usv = reinterpret_cast<void (APIENTRY *)(const GLushort *)>(resolveFunc("glColor4usv")); + Color4us = reinterpret_cast<void (APIENTRY *)(GLushort , GLushort , GLushort , GLushort )>(resolveFunc("glColor4us")); + Color4uiv = reinterpret_cast<void (APIENTRY *)(const GLuint *)>(resolveFunc("glColor4uiv")); + Color4ui = reinterpret_cast<void (APIENTRY *)(GLuint , GLuint , GLuint , GLuint )>(resolveFunc("glColor4ui")); + Color4ubv = reinterpret_cast<void (APIENTRY *)(const GLubyte *)>(resolveFunc("glColor4ubv")); + Color4ub = reinterpret_cast<void (APIENTRY *)(GLubyte , GLubyte , GLubyte , GLubyte )>(resolveFunc("glColor4ub")); + Color4sv = reinterpret_cast<void (APIENTRY *)(const GLshort *)>(resolveFunc("glColor4sv")); + Color4s = reinterpret_cast<void (APIENTRY *)(GLshort , GLshort , GLshort , GLshort )>(resolveFunc("glColor4s")); + Color4iv = reinterpret_cast<void (APIENTRY *)(const GLint *)>(resolveFunc("glColor4iv")); + Color4i = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLint , GLint )>(resolveFunc("glColor4i")); + Color4fv = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glColor4fv")); + Color4f = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat , GLfloat )>(resolveFunc("glColor4f")); + Color4dv = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glColor4dv")); + Color4d = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble , GLdouble , GLdouble )>(resolveFunc("glColor4d")); + Color4bv = reinterpret_cast<void (APIENTRY *)(const GLbyte *)>(resolveFunc("glColor4bv")); + Color4b = reinterpret_cast<void (APIENTRY *)(GLbyte , GLbyte , GLbyte , GLbyte )>(resolveFunc("glColor4b")); + Color3usv = reinterpret_cast<void (APIENTRY *)(const GLushort *)>(resolveFunc("glColor3usv")); + Color3us = reinterpret_cast<void (APIENTRY *)(GLushort , GLushort , GLushort )>(resolveFunc("glColor3us")); + Color3uiv = reinterpret_cast<void (APIENTRY *)(const GLuint *)>(resolveFunc("glColor3uiv")); + Color3ui = reinterpret_cast<void (APIENTRY *)(GLuint , GLuint , GLuint )>(resolveFunc("glColor3ui")); + Color3ubv = reinterpret_cast<void (APIENTRY *)(const GLubyte *)>(resolveFunc("glColor3ubv")); + Color3ub = reinterpret_cast<void (APIENTRY *)(GLubyte , GLubyte , GLubyte )>(resolveFunc("glColor3ub")); + Color3sv = reinterpret_cast<void (APIENTRY *)(const GLshort *)>(resolveFunc("glColor3sv")); + Color3s = reinterpret_cast<void (APIENTRY *)(GLshort , GLshort , GLshort )>(resolveFunc("glColor3s")); + Color3iv = reinterpret_cast<void (APIENTRY *)(const GLint *)>(resolveFunc("glColor3iv")); + Color3i = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLint )>(resolveFunc("glColor3i")); + Color3fv = reinterpret_cast<void (APIENTRY *)(const GLfloat *)>(resolveFunc("glColor3fv")); + Color3f = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat )>(resolveFunc("glColor3f")); + Color3dv = reinterpret_cast<void (APIENTRY *)(const GLdouble *)>(resolveFunc("glColor3dv")); + Color3d = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble , GLdouble )>(resolveFunc("glColor3d")); + Color3bv = reinterpret_cast<void (APIENTRY *)(const GLbyte *)>(resolveFunc("glColor3bv")); + Color3b = reinterpret_cast<void (APIENTRY *)(GLbyte , GLbyte , GLbyte )>(resolveFunc("glColor3b")); + Bitmap = reinterpret_cast<void (APIENTRY *)(GLsizei , GLsizei , GLfloat , GLfloat , GLfloat , GLfloat , const GLubyte *)>(resolveFunc("glBitmap")); + Begin = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolveFunc("glBegin")); + ListBase = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolveFunc("glListBase")); + GenLists = reinterpret_cast<GLuint (APIENTRY *)(GLsizei )>(resolveFunc("glGenLists")); + DeleteLists = reinterpret_cast<void (APIENTRY *)(GLuint , GLsizei )>(resolveFunc("glDeleteLists")); + CallLists = reinterpret_cast<void (APIENTRY *)(GLsizei , GLenum , const GLvoid *)>(resolveFunc("glCallLists")); + CallList = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolveFunc("glCallList")); + EndList = reinterpret_cast<void (APIENTRY *)()>(resolveFunc("glEndList")); + NewList = reinterpret_cast<void (APIENTRY *)(GLuint , GLenum )>(resolveFunc("glNewList")); + + Indexubv = reinterpret_cast<void (APIENTRY *)(const GLubyte *)>(resolveFunc("glIndexubv")); + Indexub = reinterpret_cast<void (APIENTRY *)(GLubyte )>(resolveFunc("glIndexub")); + TexSubImage1D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLsizei , GLenum , GLenum , const GLvoid *)>(resolveFunc("glTexSubImage1D")); + CopyTexSubImage1D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLint , GLint , GLsizei )>(resolveFunc("glCopyTexSubImage1D")); + CopyTexImage1D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLenum , GLint , GLint , GLsizei , GLint )>(resolveFunc("glCopyTexImage1D")); + GetPointerv = reinterpret_cast<void (APIENTRY *)(GLenum , GLvoid* *)>(resolveFunc("glGetPointerv")); + + PushClientAttrib = reinterpret_cast<void (APIENTRY *)(GLbitfield )>(resolveFunc("glPushClientAttrib")); + PopClientAttrib = reinterpret_cast<void (APIENTRY *)()>(resolveFunc("glPopClientAttrib")); + PrioritizeTextures = reinterpret_cast<void (APIENTRY *)(GLsizei , const GLuint *, const GLfloat *)>(resolveFunc("glPrioritizeTextures")); + AreTexturesResident = reinterpret_cast<GLboolean (APIENTRY *)(GLsizei , const GLuint *, GLboolean *)>(resolveFunc("glAreTexturesResident")); + VertexPointer = reinterpret_cast<void (APIENTRY *)(GLint , GLenum , GLsizei , const GLvoid *)>(resolveFunc("glVertexPointer")); + TexCoordPointer = reinterpret_cast<void (APIENTRY *)(GLint , GLenum , GLsizei , const GLvoid *)>(resolveFunc("glTexCoordPointer")); + NormalPointer = reinterpret_cast<void (APIENTRY *)(GLenum , GLsizei , const GLvoid *)>(resolveFunc("glNormalPointer")); + InterleavedArrays = reinterpret_cast<void (APIENTRY *)(GLenum , GLsizei , const GLvoid *)>(resolveFunc("glInterleavedArrays")); + IndexPointer = reinterpret_cast<void (APIENTRY *)(GLenum , GLsizei , const GLvoid *)>(resolveFunc("glIndexPointer")); + EnableClientState = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolveFunc("glEnableClientState")); + EdgeFlagPointer = reinterpret_cast<void (APIENTRY *)(GLsizei , const GLvoid *)>(resolveFunc("glEdgeFlagPointer")); + DisableClientState = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolveFunc("glDisableClientState")); + ColorPointer = reinterpret_cast<void (APIENTRY *)(GLint , GLenum , GLsizei , const GLvoid *)>(resolveFunc("glColorPointer")); + ArrayElement = reinterpret_cast<void (APIENTRY *)(GLint )>(resolveFunc("glArrayElement")); +} + +void QWindowsOpenGL::resolveGLES2() +{ + ActiveTexture = reinterpret_cast<void (APIENTRY *)(GLenum)>(resolveFunc("glActiveTexture")); + AttachShader = reinterpret_cast<void (APIENTRY *)(GLuint , GLuint )>(resolveFunc("glAttachShader")); + BindAttribLocation = reinterpret_cast<void (APIENTRY *)(GLuint , GLuint , const GLchar* )>(resolveFunc("glBindAttribLocation")); + BindBuffer = reinterpret_cast<void (APIENTRY *)(GLenum , GLuint )>(resolveFunc("glBindBuffer")); + BindFramebuffer = reinterpret_cast<void (APIENTRY *)(GLenum , GLuint )>(resolveFunc("glBindFramebuffer")); + BindRenderbuffer = reinterpret_cast<void (APIENTRY *)(GLenum , GLuint )>(resolveFunc("glBindRenderbuffer")); + BlendColor = reinterpret_cast<void (APIENTRY *)(GLclampf , GLclampf , GLclampf , GLclampf )>(resolveFunc("glBlendColor")); + BlendEquation = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolveFunc("glBlendEquation")); + BlendEquationSeparate = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum )>(resolveFunc("glBlendEquationSeparate")); + BlendFuncSeparate = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLenum , GLenum )>(resolveFunc("glBlendFuncSeparate")); + BufferData = reinterpret_cast<void (APIENTRY *)(GLenum , GLsizeiptr , const GLvoid* , GLenum )>(resolveFunc("glBufferData")); + BufferSubData = reinterpret_cast<void (APIENTRY *)(GLenum , GLintptr , GLsizeiptr , const GLvoid* )>(resolveFunc("glBufferSubData")); + CheckFramebufferStatus = reinterpret_cast<GLenum (APIENTRY *)(GLenum )>(resolveFunc("glCheckFramebufferStatus")); + ClearDepthf = reinterpret_cast<void (APIENTRY *)(GLclampf )>(resolveFunc("glClearDepthf")); + CompileShader = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolveFunc("glCompileShader")); + CompressedTexImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLenum , GLsizei , GLsizei, GLint, GLsizei, const GLvoid* )>(resolveFunc("glCompressedTexImage2D")); + CompressedTexSubImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid* )>(resolveFunc("glCompressedTexSubImage2D")); + CreateProgram = reinterpret_cast<GLuint (APIENTRY *)(void)>(resolveFunc("glCreateProgram")); + CreateShader = reinterpret_cast<GLuint (APIENTRY *)(GLenum )>(resolveFunc("glCreateShader")); + DeleteBuffers = reinterpret_cast<void (APIENTRY *)(GLsizei , const GLuint*)>(resolveFunc("glDeleteBuffers")); + DeleteFramebuffers = reinterpret_cast<void (APIENTRY *)(GLsizei , const GLuint* )>(resolveFunc("glDeleteFramebuffers")); + DeleteProgram = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolveFunc("glDeleteProgram")); + DeleteRenderbuffers = reinterpret_cast<void (APIENTRY *)(GLsizei , const GLuint* )>(resolveFunc("glDeleteRenderbuffers")); + DeleteShader = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolveFunc("glDeleteShader")); + DepthRangef = reinterpret_cast<void (APIENTRY *)(GLclampf , GLclampf )>(resolveFunc("glDepthRangef")); + DetachShader = reinterpret_cast<void (APIENTRY *)(GLuint , GLuint )>(resolveFunc("glDetachShader")); + DisableVertexAttribArray = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolveFunc("glDisableVertexAttribArray")); + EnableVertexAttribArray = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolveFunc("glEnableVertexAttribArray")); + FramebufferRenderbuffer = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLenum , GLuint )>(resolveFunc("glFramebufferRenderbuffer")); + FramebufferTexture2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLenum , GLuint , GLint )>(resolveFunc("glFramebufferTexture2D")); + GenBuffers = reinterpret_cast<void (APIENTRY *)(GLsizei , GLuint* )>(resolveFunc("glGenBuffers")); + GenerateMipmap = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolveFunc("glGenerateMipmap")); + GenFramebuffers = reinterpret_cast<void (APIENTRY *)(GLsizei , GLuint* )>(resolveFunc("glGenFramebuffers")); + GenRenderbuffers = reinterpret_cast<void (APIENTRY *)(GLsizei , GLuint* )>(resolveFunc("glGenRenderbuffers")); + GetActiveAttrib = reinterpret_cast<void (APIENTRY *)(GLuint , GLuint , GLsizei , GLsizei* , GLint* , GLenum* , GLchar* )>(resolveFunc("glGetActiveAttrib")); + GetActiveUniform = reinterpret_cast<void (APIENTRY *)(GLuint , GLuint , GLsizei , GLsizei* , GLint* , GLenum* , GLchar* )>(resolveFunc("glGetActiveUniform")); + GetAttachedShaders = reinterpret_cast<void (APIENTRY *)(GLuint , GLsizei , GLsizei*, GLuint* )>(resolveFunc("glGetAttachedShaders")); + GetAttribLocation = reinterpret_cast<int (APIENTRY *)(GLuint , const GLchar* )>(resolveFunc("glGetAttribLocation")); + GetBufferParameteriv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint* )>(resolveFunc("glGetBufferParameteriv")); + GetFramebufferAttachmentParameteriv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum, GLenum , GLint* )>(resolveFunc("glGetFramebufferAttachmentParameteriv")); + GetProgramiv = reinterpret_cast<void (APIENTRY *)(GLuint , GLenum , GLint* )>(resolveFunc("glGetProgramiv")); + GetProgramInfoLog = reinterpret_cast<void (APIENTRY *)(GLuint , GLsizei , GLsizei* , GLchar* )>(resolveFunc("glGetProgramInfoLog")); + GetRenderbufferParameteriv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint* )>(resolveFunc("glGetRenderbufferParameteriv")); + GetShaderiv = reinterpret_cast<void (APIENTRY *)(GLuint , GLenum , GLint* )>(resolveFunc("glGetShaderiv")); + GetShaderInfoLog = reinterpret_cast<void (APIENTRY *)(GLuint , GLsizei , GLsizei*, GLchar*)>(resolveFunc("glGetShaderInfoLog")); + GetShaderPrecisionFormat = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint* , GLint* )>(resolveFunc("glGetShaderPrecisionFormat")); + GetShaderSource = reinterpret_cast<void (APIENTRY *)(GLuint , GLsizei , GLsizei* , GLchar* )>(resolveFunc("glGetShaderSource")); + GetUniformfv = reinterpret_cast<void (APIENTRY *)(GLuint , GLint , GLfloat*)>(resolveFunc("glGetUniformfv")); + GetUniformiv = reinterpret_cast<void (APIENTRY *)(GLuint , GLint , GLint*)>(resolveFunc("glGetUniformiv")); + GetUniformLocation = reinterpret_cast<int (APIENTRY *)(GLuint , const GLchar* )>(resolveFunc("glGetUniformLocation")); + GetVertexAttribfv = reinterpret_cast<void (APIENTRY *)(GLuint , GLenum , GLfloat* )>(resolveFunc("glGetVertexAttribfv")); + GetVertexAttribiv = reinterpret_cast<void (APIENTRY *)(GLuint , GLenum , GLint* )>(resolveFunc("glGetVertexAttribiv")); + GetVertexAttribPointerv = reinterpret_cast<void (APIENTRY *)(GLuint , GLenum , GLvoid** pointer)>(resolveFunc("glGetVertexAttribPointerv")); + IsBuffer = reinterpret_cast<GLboolean (APIENTRY *)(GLuint )>(resolveFunc("glIsBuffer")); + IsFramebuffer = reinterpret_cast<GLboolean (APIENTRY *)(GLuint )>(resolveFunc("glIsFramebuffer")); + IsProgram = reinterpret_cast<GLboolean (APIENTRY *)(GLuint )>(resolveFunc("glIsProgram")); + IsRenderbuffer = reinterpret_cast<GLboolean (APIENTRY *)(GLuint )>(resolveFunc("glIsRenderbuffer")); + IsShader = reinterpret_cast<GLboolean (APIENTRY *)(GLuint )>(resolveFunc("glIsShader")); + LinkProgram = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolveFunc("glLinkProgram")); + ReleaseShaderCompiler = reinterpret_cast<void (APIENTRY *)(void)>(resolveFunc("glReleaseShaderCompiler")); + RenderbufferStorage = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLsizei , GLsizei )>(resolveFunc("glRenderbufferStorage")); + SampleCoverage = reinterpret_cast<void (APIENTRY *)(GLclampf , GLboolean )>(resolveFunc("glSampleCoverage")); + ShaderBinary = reinterpret_cast<void (APIENTRY *)(GLsizei , const GLuint*, GLenum , const GLvoid* , GLsizei )>(resolveFunc("glShaderBinary")); + ShaderSource = reinterpret_cast<void (APIENTRY *)(GLuint , GLsizei , const GLchar* *, const GLint* )>(resolveFunc("glShaderSource")); + StencilFuncSeparate = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint , GLuint )>(resolveFunc("glStencilFuncSeparate")); + StencilMaskSeparate = reinterpret_cast<void (APIENTRY *)(GLenum , GLuint )>(resolveFunc("glStencilMaskSeparate")); + StencilOpSeparate = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLenum , GLenum )>(resolveFunc("glStencilOpSeparate")); + Uniform1f = reinterpret_cast<void (APIENTRY *)(GLint , GLfloat )>(resolveFunc("glUniform1f")); + Uniform1fv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , const GLfloat* )>(resolveFunc("glUniform1fv")); + Uniform1i = reinterpret_cast<void (APIENTRY *)(GLint , GLint )>(resolveFunc("glUniform1i")); + Uniform1iv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , const GLint* )>(resolveFunc("glUniform1iv")); + Uniform2f = reinterpret_cast<void (APIENTRY *)(GLint , GLfloat , GLfloat )>(resolveFunc("glUniform2f")); + Uniform2fv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , const GLfloat* )>(resolveFunc("glUniform2fv")); + Uniform2i = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLint )>(resolveFunc("glUniform2i")); + Uniform2iv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , const GLint* )>(resolveFunc("glUniform2iv")); + Uniform3f = reinterpret_cast<void (APIENTRY *)(GLint , GLfloat , GLfloat , GLfloat )>(resolveFunc("glUniform3f")); + Uniform3fv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , const GLfloat* )>(resolveFunc("glUniform3fv")); + Uniform3i = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLint , GLint )>(resolveFunc("glUniform3i")); + Uniform3iv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , const GLint* )>(resolveFunc("glUniform3iv")); + Uniform4f = reinterpret_cast<void (APIENTRY *)(GLint , GLfloat , GLfloat , GLfloat , GLfloat )>(resolveFunc("glUniform4f")); + Uniform4fv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , const GLfloat* )>(resolveFunc("glUniform4fv")); + Uniform4i = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLint , GLint , GLint )>(resolveFunc("glUniform4i")); + Uniform4iv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , const GLint* )>(resolveFunc("glUniform4iv")); + UniformMatrix2fv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , GLboolean , const GLfloat* )>(resolveFunc("glUniformMatrix2fv")); + UniformMatrix3fv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , GLboolean , const GLfloat* )>(resolveFunc("glUniformMatrix3fv")); + UniformMatrix4fv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , GLboolean , const GLfloat* )>(resolveFunc("glUniformMatrix4fv")); + UseProgram = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolveFunc("glUseProgram")); + ValidateProgram = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolveFunc("glValidateProgram")); + VertexAttrib1f = reinterpret_cast<void (APIENTRY *)(GLuint , GLfloat )>(resolveFunc("glVertexAttrib1f")); + VertexAttrib1fv = reinterpret_cast<void (APIENTRY *)(GLuint , const GLfloat* )>(resolveFunc("glVertexAttrib1fv")); + VertexAttrib2f = reinterpret_cast<void (APIENTRY *)(GLuint , GLfloat , GLfloat )>(resolveFunc("glVertexAttrib2f")); + VertexAttrib2fv = reinterpret_cast<void (APIENTRY *)(GLuint , const GLfloat* )>(resolveFunc("glVertexAttrib2fv")); + VertexAttrib3f = reinterpret_cast<void (APIENTRY *)(GLuint , GLfloat , GLfloat , GLfloat )>(resolveFunc("glVertexAttrib3f")); + VertexAttrib3fv = reinterpret_cast<void (APIENTRY *)(GLuint , const GLfloat* )>(resolveFunc("glVertexAttrib3fv")); + VertexAttrib4f = reinterpret_cast<void (APIENTRY *)(GLuint , GLfloat , GLfloat , GLfloat , GLfloat )>(resolveFunc("glVertexAttrib4f")); + VertexAttrib4fv = reinterpret_cast<void (APIENTRY *)(GLuint , const GLfloat* )>(resolveFunc("glVertexAttrib4fv")); + VertexAttribPointer = reinterpret_cast<void (APIENTRY *)(GLuint , GLint, GLenum, GLboolean, GLsizei, const GLvoid* )>(resolveFunc("glVertexAttribPointer")); +} + +void QWindowsOpenGL::resolve() +{ + switch (libraryType()) { + case DesktopGL: + resolveWGL(); + resolveGLCommon(); + resolveGL11(); + break; + + case GLES2: + resolveEGL(); + resolveGLCommon(); + resolveGLES2(); + break; + + default: + Q_ASSERT_X(0, "QWindowsOpenGL", "Nothing to resolve"); + break; + } +} + +bool QWindowsOpenGL::testDesktopGL() +{ + HMODULE lib = 0; + HWND wnd = 0; + HDC dc = 0; + HGLRC context = 0; + LPCTSTR className = L"qtopenglproxytest"; + + HGLRC (WINAPI * CreateContext)(HDC dc) = 0; + BOOL (WINAPI * DeleteContext)(HGLRC context) = 0; + BOOL (WINAPI * MakeCurrent)(HDC dc, HGLRC context) = 0; + PROC (WINAPI * WGL_GetProcAddress)(LPCSTR name) = 0; + + bool result = false; + + // Test #1: Load opengl32.dll and try to resolve an OpenGL 2 function. + // This will typically fail on systems that do not have a real OpenGL driver. + lib = qgl_loadLib("opengl32.dll", false); + if (lib) { + CreateContext = reinterpret_cast<HGLRC (WINAPI *)(HDC)>(::GetProcAddress(lib, "wglCreateContext")); + if (!CreateContext) + goto cleanup; + DeleteContext = reinterpret_cast<BOOL (WINAPI *)(HGLRC)>(::GetProcAddress(lib, "wglDeleteContext")); + if (!DeleteContext) + goto cleanup; + MakeCurrent = reinterpret_cast<BOOL (WINAPI *)(HDC, HGLRC)>(::GetProcAddress(lib, "wglMakeCurrent")); + if (!MakeCurrent) + goto cleanup; + WGL_GetProcAddress = reinterpret_cast<PROC (WINAPI *)(LPCSTR)>(::GetProcAddress(lib, "wglGetProcAddress")); + if (!WGL_GetProcAddress) + goto cleanup; + + WNDCLASS wclass; + wclass.cbClsExtra = 0; + wclass.cbWndExtra = 0; + wclass.hInstance = (HINSTANCE) GetModuleHandle(0); + wclass.hIcon = 0; + wclass.hCursor = 0; + wclass.hbrBackground = (HBRUSH) (COLOR_BACKGROUND); + wclass.lpszMenuName = 0; + wclass.lpfnWndProc = DefWindowProc; + wclass.lpszClassName = className; + wclass.style = CS_OWNDC; + if (!RegisterClass(&wclass)) + goto cleanup; + wnd = CreateWindow(className, L"qtopenglproxytest", WS_OVERLAPPED, + 0, 0, 640, 480, 0, 0, wclass.hInstance, 0); + if (!wnd) + goto cleanup; + dc = GetDC(wnd); + if (!dc) + goto cleanup; + + PIXELFORMATDESCRIPTOR pfd; + memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_GENERIC_FORMAT; + pfd.iPixelType = PFD_TYPE_RGBA; + // Use the GDI functions. Under the hood this will call the wgl variants in opengl32.dll. + int pixelFormat = ChoosePixelFormat(dc, &pfd); + if (!pixelFormat) + goto cleanup; + if (!SetPixelFormat(dc, pixelFormat, &pfd)) + goto cleanup; + context = CreateContext(dc); + if (!context) + goto cleanup; + if (!MakeCurrent(dc, context)) + goto cleanup; + + // Now that there is finally a context current, try doing something useful. + if (WGL_GetProcAddress("glCreateShader")) { + result = true; + qCDebug(qglLc, "OpenGL 2 entry points available"); + } else { + qCDebug(qglLc, "OpenGL 2 entry points not found"); + } + } else { + qCDebug(qglLc, "Failed to load opengl32.dll"); + } + +cleanup: + if (MakeCurrent) + MakeCurrent(0, 0); + if (context) + DeleteContext(context); + if (dc && wnd) + ReleaseDC(wnd, dc); + if (wnd) + DestroyWindow(wnd); + UnregisterClass(className, GetModuleHandle(0)); + if (lib) + FreeLibrary(lib); + + return result; +} + +class QWindowsOpenGLList +{ +public: + QWindowsOpenGLList(); + ~QWindowsOpenGLList(); + QVector<QAbstractWindowsOpenGL *> list; +}; + +QWindowsOpenGLList::QWindowsOpenGLList() +{ + // For now there is always one OpenGL ( + winsys interface) loaded. + // This may change in the future. + list.append(new QWindowsOpenGL); +} + +QWindowsOpenGLList::~QWindowsOpenGLList() +{ + qDeleteAll(list); +} + +// Use Q_GLOBAL_STATIC and perform initialization in the constructor to be +// thread safe. +Q_GLOBAL_STATIC(QWindowsOpenGLList, gl) + +static inline QAbstractWindowsOpenGL *qgl_choose() +{ + return gl()->list[0]; +} + +// functionsReady() -> the DLL is there but some functions were not resolved. This is fatal. +// !functionsReady() -> could not load a GL implementation. No error message in this case. +#define GLWARN(g, func, prefix) \ + { \ + if (g->functionsReady()) \ + qFatal("Qt OpenGL: Attempted to call unresolved function %s%s. " \ + "This is likely caused by making OpenGL-only calls with an OpenGL ES implementation (Angle).", \ + prefix, #func); \ + } + +#define GLCALLV(func, ...) \ + { \ + QAbstractWindowsOpenGL *g = qgl_choose(); \ + if (g->func) \ + g->func(__VA_ARGS__); \ + else \ + GLWARN(g, func, "gl") \ + } + +#define GLCALL(func, ...) \ + { \ + QAbstractWindowsOpenGL *g = qgl_choose(); \ + if (g->func) \ + return g->func(__VA_ARGS__); \ + GLWARN(g, func, "gl") \ + return 0; \ + } + +#define WGLCALL(func, ...) \ + { \ + QAbstractWindowsOpenGL *g = qgl_choose(); \ + if (g->func) \ + return g->func(__VA_ARGS__); \ + GLWARN(g, func, "wgl") \ + return 0; \ + } + +#define EGLCALL(func, ...) \ + { \ + QAbstractWindowsOpenGL *g = qgl_choose(); \ + if (g->EGL_##func) \ + return g->EGL_##func(__VA_ARGS__); \ + GLWARN(g, func, "egl") \ + return 0; \ + } + + +extern "C" { + +// WGL + +Q_DECL_EXPORT BOOL WINAPI wglCopyContext(HGLRC src, HGLRC dst, UINT mask) +{ + WGLCALL(CopyContext, src, dst, mask); +} + +Q_DECL_EXPORT HGLRC WINAPI wglCreateContext(HDC dc) +{ + WGLCALL(CreateContext, dc); +} + +Q_DECL_EXPORT HGLRC WINAPI wglCreateLayerContext(HDC dc, int plane) +{ + WGLCALL(CreateLayerContext, dc, plane); +} + +Q_DECL_EXPORT BOOL WINAPI wglDeleteContext(HGLRC context) +{ + WGLCALL(DeleteContext, context); +} + +Q_DECL_EXPORT HGLRC WINAPI wglGetCurrentContext(VOID) +{ + WGLCALL(GetCurrentContext); +} + +Q_DECL_EXPORT HDC WINAPI wglGetCurrentDC(VOID) +{ + WGLCALL(GetCurrentDC); +} + +Q_DECL_EXPORT PROC WINAPI wglGetProcAddress(LPCSTR name) +{ + WGLCALL(GetProcAddress, name); +} + +Q_DECL_EXPORT BOOL WINAPI wglMakeCurrent(HDC dc, HGLRC context) +{ + WGLCALL(MakeCurrent, dc, context); +} + +Q_DECL_EXPORT BOOL WINAPI wglShareLists(HGLRC context1, HGLRC context2) +{ + WGLCALL(ShareLists, context1, context2); +} + +Q_DECL_EXPORT BOOL WINAPI wglUseFontBitmapsW(HDC dc, DWORD first, DWORD count, DWORD base) +{ + WGLCALL(UseFontBitmapsW, dc, first, count, base); +} + +Q_DECL_EXPORT BOOL WINAPI wglUseFontOutlinesW(HDC dc, DWORD first, DWORD count, DWORD base, FLOAT deviation, + FLOAT extrusion, int format, LPGLYPHMETRICSFLOAT gmf) +{ + WGLCALL(UseFontOutlinesW, dc, first, count, base, deviation, extrusion, format, gmf); +} + +Q_DECL_EXPORT BOOL WINAPI wglDescribeLayerPlane(HDC dc, int pixelFormat, int plane, UINT n, + LPLAYERPLANEDESCRIPTOR planeDescriptor) +{ + WGLCALL(DescribeLayerPlane, dc, pixelFormat, plane, n, planeDescriptor); +} + +Q_DECL_EXPORT int WINAPI wglSetLayerPaletteEntries(HDC dc, int plane, int start, int entries, + CONST COLORREF *colors) +{ + WGLCALL(SetLayerPaletteEntries, dc, plane, start, entries, colors); +} + +Q_DECL_EXPORT int WINAPI wglGetLayerPaletteEntries(HDC dc, int plane, int start, int entries, + COLORREF *color) +{ + WGLCALL(GetLayerPaletteEntries, dc, plane, start, entries, color); +} + +Q_DECL_EXPORT BOOL WINAPI wglRealizeLayerPalette(HDC dc, int plane, BOOL realize) +{ + WGLCALL(RealizeLayerPalette, dc, plane, realize); +} + +Q_DECL_EXPORT BOOL WINAPI wglSwapLayerBuffers(HDC dc, UINT planes) +{ + WGLCALL(SwapLayerBuffers, dc, planes); +} + +Q_DECL_EXPORT DWORD WINAPI wglSwapMultipleBuffers(UINT n, CONST WGLSWAP *buffers) +{ + WGLCALL(SwapMultipleBuffers, n, buffers); +} + +// EGL + +Q_DECL_EXPORT EGLint EGLAPIENTRY eglGetError(void) +{ + EGLCALL(GetError); +} + +Q_DECL_EXPORT EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id) +{ + EGLCALL(GetDisplay, display_id); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) +{ + EGLCALL(Initialize, dpy, major, minor); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy) +{ + EGLCALL(Terminate, dpy); +} + +Q_DECL_EXPORT const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name) +{ + EGLCALL(QueryString, dpy, name); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, + EGLint config_size, EGLint *num_config) +{ + EGLCALL(GetConfigs, dpy, configs, config_size, num_config); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, + EGLConfig *configs, EGLint config_size, + EGLint *num_config) +{ + EGLCALL(ChooseConfig, dpy, attrib_list, configs, config_size, num_config); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint *value) +{ + EGLCALL(GetConfigAttrib, dpy, config, attribute, value); +} + +Q_DECL_EXPORT EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, + EGLNativeWindowType win, + const EGLint *attrib_list) +{ + EGLCALL(CreateWindowSurface, dpy, config, win, attrib_list); +} + +Q_DECL_EXPORT EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list) +{ + EGLCALL(CreatePbufferSurface, dpy, config, attrib_list); +} + +Q_DECL_EXPORT EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, + EGLNativePixmapType pixmap, + const EGLint *attrib_list) +{ + EGLCALL(CreatePixmapSurface, dpy, config, pixmap, attrib_list); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surface) +{ + EGLCALL(DestroySurface, dpy, surface); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint *value) +{ + EGLCALL(QuerySurface, dpy, surface, attribute, value); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api) +{ + EGLCALL(BindAPI, api); +} + +Q_DECL_EXPORT EGLenum EGLAPIENTRY eglQueryAPI(void) +{ + EGLCALL(QueryAPI); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglWaitClient(void) +{ + EGLCALL(WaitClient); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglReleaseThread(void) +{ + EGLCALL(ReleaseThread); +} + +Q_DECL_EXPORT EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer( + EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, + EGLConfig config, const EGLint *attrib_list) +{ + EGLCALL(CreatePbufferFromClientBuffer, dpy, buftype, buffer, config, attrib_list); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint value) +{ + EGLCALL(SurfaceAttrib, dpy, surface, attribute, value); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + EGLCALL(BindTexImage, dpy, surface, buffer); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + EGLCALL(ReleaseTexImage, dpy, surface, buffer); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval) +{ + EGLCALL(SwapInterval, dpy, interval); +} + +Q_DECL_EXPORT EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config, + EGLContext share_context, + const EGLint *attrib_list) +{ + EGLCALL(CreateContext, dpy, config, share_context, attrib_list); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx) +{ + EGLCALL(DestroyContext, dpy, ctx); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, + EGLSurface read, EGLContext ctx) +{ + EGLCALL(MakeCurrent, dpy, draw, read, ctx); +} + +Q_DECL_EXPORT EGLContext EGLAPIENTRY eglGetCurrentContext(void) +{ + EGLCALL(GetCurrentContext); +} + +Q_DECL_EXPORT EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw) +{ + EGLCALL(GetCurrentSurface, readdraw); +} + +Q_DECL_EXPORT EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void) +{ + EGLCALL(GetCurrentDisplay); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx, + EGLint attribute, EGLint *value) +{ + EGLCALL(QueryContext, dpy, ctx, attribute, value); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglWaitGL(void) +{ + EGLCALL(WaitGL); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine) +{ + EGLCALL(WaitNative, engine); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) +{ + EGLCALL(SwapBuffers, dpy, surface); +} + +Q_DECL_EXPORT EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, + EGLNativePixmapType target) +{ + EGLCALL(CopyBuffers, dpy, surface, target); +} + +// OpenGL + +Q_DECL_EXPORT void APIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ + GLCALLV(Viewport, x, y, width, height); +} + +Q_DECL_EXPORT void APIENTRY glDepthRange(GLdouble nearVal, GLdouble farVal) +{ + if (qgl_choose()->libraryType() == QAbstractWindowsOpenGL::DesktopGL) { + GLCALLV(DepthRange, nearVal, farVal); + } else { + GLCALLV(DepthRangef, nearVal, farVal); + } +} + +Q_DECL_EXPORT GLboolean APIENTRY glIsEnabled(GLenum cap) +{ + GLCALL(IsEnabled, cap); +} + +Q_DECL_EXPORT void APIENTRY glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params) +{ + GLCALLV(GetTexLevelParameteriv, target, level, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params) +{ + GLCALLV(GetTexLevelParameterfv, target, level, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetTexParameteriv(GLenum target, GLenum pname, GLint *params) +{ + GLCALLV(GetTexParameteriv, target, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params) +{ + GLCALLV(GetTexParameterfv, target, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels) +{ + GLCALLV(GetTexImage, target, level, format, type, pixels); +} + +Q_DECL_EXPORT const GLubyte * APIENTRY glGetString(GLenum name) +{ + GLCALL(GetString, name); +} + +Q_DECL_EXPORT void APIENTRY glGetIntegerv(GLenum pname, GLint *params) +{ + GLCALLV(GetIntegerv, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetFloatv(GLenum pname, GLfloat *params) +{ + GLCALLV(GetFloatv, pname, params); +} + +Q_DECL_EXPORT GLenum APIENTRY glGetError() +{ + GLCALL(GetError); +} + +Q_DECL_EXPORT void APIENTRY glGetDoublev(GLenum pname, GLdouble *params) +{ + GLCALLV(GetDoublev, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetBooleanv(GLenum pname, GLboolean *params) +{ + GLCALLV(GetBooleanv, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) +{ + GLCALLV(ReadPixels, x, y, width, height, format, type, pixels); +} + +Q_DECL_EXPORT void APIENTRY glReadBuffer(GLenum mode) +{ + GLCALLV(ReadBuffer, mode); +} + +Q_DECL_EXPORT void APIENTRY glPixelStorei(GLenum pname, GLint param) +{ + GLCALLV(PixelStorei, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glPixelStoref(GLenum pname, GLfloat param) +{ + GLCALLV(PixelStoref, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glDepthFunc(GLenum func) +{ + GLCALLV(DepthFunc, func); +} + +Q_DECL_EXPORT void APIENTRY glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) +{ + GLCALLV(StencilOp, fail, zfail, zpass); +} + +Q_DECL_EXPORT void APIENTRY glStencilFunc(GLenum func, GLint ref, GLuint mask) +{ + GLCALLV(StencilFunc, func, ref, mask); +} + +Q_DECL_EXPORT void APIENTRY glLogicOp(GLenum opcode) +{ + GLCALLV(LogicOp, opcode); +} + +Q_DECL_EXPORT void APIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor) +{ + GLCALLV(BlendFunc, sfactor, dfactor); +} + +Q_DECL_EXPORT void APIENTRY glFlush() +{ + GLCALLV(Flush); +} + +Q_DECL_EXPORT void APIENTRY glFinish() +{ + GLCALLV(Finish); +} + +Q_DECL_EXPORT void APIENTRY glEnable(GLenum cap) +{ + GLCALLV(Enable, cap); +} + +Q_DECL_EXPORT void APIENTRY glDisable(GLenum cap) +{ + GLCALLV(Disable, cap); +} + +Q_DECL_EXPORT void APIENTRY glDepthMask(GLboolean flag) +{ + GLCALLV(DepthMask, flag); +} + +Q_DECL_EXPORT void APIENTRY glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ + GLCALLV(ColorMask, red, green, blue, alpha); +} + +Q_DECL_EXPORT void APIENTRY glStencilMask(GLuint mask) +{ + GLCALLV(StencilMask, mask); +} + +Q_DECL_EXPORT void APIENTRY glClearDepth(GLdouble depth) +{ + if (qgl_choose()->libraryType() == QAbstractWindowsOpenGL::DesktopGL) { + GLCALLV(ClearDepth, depth); + } else { + GLCALLV(ClearDepthf, depth); + } +} + +Q_DECL_EXPORT void APIENTRY glClearStencil(GLint s) +{ + GLCALLV(ClearStencil, s); +} + +Q_DECL_EXPORT void APIENTRY glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +{ + GLCALLV(ClearColor, red, green, blue, alpha); +} + +Q_DECL_EXPORT void APIENTRY glClear(GLbitfield mask) +{ + GLCALLV(Clear, mask); +} + +Q_DECL_EXPORT void APIENTRY glDrawBuffer(GLenum mode) +{ + GLCALLV(DrawBuffer, mode); +} + +Q_DECL_EXPORT void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + GLCALLV(TexImage2D, target, level, internalformat, width, height, border, format, type, pixels); +} + +Q_DECL_EXPORT void APIENTRY glTexImage1D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + GLCALLV(TexImage1D, target, level, internalformat, width, border, format, type, pixels); +} + +Q_DECL_EXPORT void APIENTRY glTexParameteriv(GLenum target, GLenum pname, const GLint *params) +{ + GLCALLV(TexParameteriv, target, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param) +{ + GLCALLV(TexParameteri, target, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) +{ + GLCALLV(TexParameterfv, target, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glTexParameterf(GLenum target, GLenum pname, GLfloat param) +{ + GLCALLV(TexParameterf, target, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height) +{ + GLCALLV(Scissor, x, y, width, height); +} + +Q_DECL_EXPORT void APIENTRY glPolygonMode(GLenum face, GLenum mode) +{ + GLCALLV(PolygonMode, face, mode); +} + +Q_DECL_EXPORT void APIENTRY glPointSize(GLfloat size) +{ + GLCALLV(PointSize, size); +} + +Q_DECL_EXPORT void APIENTRY glLineWidth(GLfloat width) +{ + GLCALLV(LineWidth, width); +} + +Q_DECL_EXPORT void APIENTRY glHint(GLenum target, GLenum mode) +{ + GLCALLV(Hint, target, mode); +} + +Q_DECL_EXPORT void APIENTRY glFrontFace(GLenum mode) +{ + GLCALLV(FrontFace, mode); +} + +Q_DECL_EXPORT void APIENTRY glCullFace(GLenum mode) +{ + GLCALLV(CullFace, mode); +} + +Q_DECL_EXPORT void APIENTRY glTranslatef(GLfloat x, GLfloat y, GLfloat z) +{ + GLCALLV(Translatef, x, y, z); +} + +Q_DECL_EXPORT void APIENTRY glTranslated(GLdouble x, GLdouble y, GLdouble z) +{ + GLCALLV(Translated, x, y, z); +} + +Q_DECL_EXPORT void APIENTRY glScalef(GLfloat x, GLfloat y, GLfloat z) +{ + GLCALLV(Scalef, x, y, z); +} + +Q_DECL_EXPORT void APIENTRY glScaled(GLdouble x, GLdouble y, GLdouble z) +{ + GLCALLV(Scaled, x, y, z); +} + +Q_DECL_EXPORT void APIENTRY glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) +{ + GLCALLV(Rotatef, angle, x, y, z); +} + +Q_DECL_EXPORT void APIENTRY glRotated(GLdouble angle, GLdouble x, GLdouble y, GLdouble z) +{ + GLCALLV(Rotated, angle, x, y, z); +} + +Q_DECL_EXPORT void APIENTRY glPushMatrix() +{ + GLCALLV(PushMatrix); +} + +Q_DECL_EXPORT void APIENTRY glPopMatrix() +{ + GLCALLV(PopMatrix); +} + +Q_DECL_EXPORT void APIENTRY glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) +{ + GLCALLV(Ortho, left, right, bottom, top, zNear, zFar); +} + +Q_DECL_EXPORT void APIENTRY glMultMatrixd(const GLdouble *m) +{ + GLCALLV(MultMatrixd, m); +} + +Q_DECL_EXPORT void APIENTRY glMultMatrixf(const GLfloat *m) +{ + GLCALLV(MultMatrixf, m); +} + +Q_DECL_EXPORT void APIENTRY glMatrixMode(GLenum mode) +{ + GLCALLV(MatrixMode, mode); +} + +Q_DECL_EXPORT void APIENTRY glLoadMatrixd(const GLdouble *m) +{ + GLCALLV(LoadMatrixd, m); +} + +Q_DECL_EXPORT void APIENTRY glLoadMatrixf(const GLfloat *m) +{ + GLCALLV(LoadMatrixf, m); +} + +Q_DECL_EXPORT void APIENTRY glLoadIdentity() +{ + GLCALLV(LoadIdentity); +} + +Q_DECL_EXPORT void APIENTRY glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) +{ + GLCALLV(Frustum, left, right, bottom, top, zNear, zFar); +} + +Q_DECL_EXPORT GLboolean APIENTRY glIsList(GLuint list) +{ + GLCALL(IsList, list); +} + +Q_DECL_EXPORT void APIENTRY glGetTexGeniv(GLenum coord, GLenum pname, GLint *params) +{ + GLCALLV(GetTexGeniv, coord, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetTexGenfv(GLenum coord, GLenum pname, GLfloat *params) +{ + GLCALLV(GetTexGenfv, coord, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetTexGendv(GLenum coord, GLenum pname, GLdouble *params) +{ + GLCALLV(GetTexGendv, coord, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetTexEnviv(GLenum target, GLenum pname, GLint *params) +{ + GLCALLV(GetTexEnviv, target, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetTexEnvfv(GLenum target, GLenum pname, GLfloat *params) +{ + GLCALLV(GetTexEnvfv, target, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetPolygonStipple(GLubyte *mask) +{ + GLCALLV(GetPolygonStipple, mask); +} + +Q_DECL_EXPORT void APIENTRY glGetPixelMapusv(GLenum map, GLushort *values) +{ + GLCALLV(GetPixelMapusv, map, values); +} + +Q_DECL_EXPORT void APIENTRY glGetPixelMapuiv(GLenum map, GLuint *values) +{ + GLCALLV(GetPixelMapuiv, map, values); +} + +Q_DECL_EXPORT void APIENTRY glGetPixelMapfv(GLenum map, GLfloat *values) +{ + GLCALLV(GetPixelMapfv, map, values); +} + +Q_DECL_EXPORT void APIENTRY glGetMaterialiv(GLenum face, GLenum pname, GLint *params) +{ + GLCALLV(GetMaterialiv, face, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetMaterialfv(GLenum face, GLenum pname, GLfloat *params) +{ + GLCALLV(GetMaterialfv, face, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetMapiv(GLenum target, GLenum query, GLint *v) +{ + GLCALLV(GetMapiv, target, query, v); +} + +Q_DECL_EXPORT void APIENTRY glGetMapfv(GLenum target, GLenum query, GLfloat *v) +{ + GLCALLV(GetMapfv, target, query, v); +} + +Q_DECL_EXPORT void APIENTRY glGetMapdv(GLenum target, GLenum query, GLdouble *v) +{ + GLCALLV(GetMapdv, target, query, v); +} + +Q_DECL_EXPORT void APIENTRY glGetLightiv(GLenum light, GLenum pname, GLint *params) +{ + GLCALLV(GetLightiv, light, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetLightfv(GLenum light, GLenum pname, GLfloat *params) +{ + GLCALLV(GetLightfv, light, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetClipPlane(GLenum plane, GLdouble *equation) +{ + GLCALLV(GetClipPlane, plane, equation); +} + +Q_DECL_EXPORT void APIENTRY glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) +{ + GLCALLV(DrawPixels, width, height, format, type, pixels); +} + +Q_DECL_EXPORT void APIENTRY glCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type) +{ + GLCALLV(CopyPixels, x, y, width, height, type); +} + +Q_DECL_EXPORT void APIENTRY glPixelMapusv(GLenum map, GLint mapsize, const GLushort *values) +{ + GLCALLV(PixelMapusv, map, mapsize, values); +} + +Q_DECL_EXPORT void APIENTRY glPixelMapuiv(GLenum map, GLint mapsize, const GLuint *values) +{ + GLCALLV(PixelMapuiv, map, mapsize, values); +} + +Q_DECL_EXPORT void APIENTRY glPixelMapfv(GLenum map, GLint mapsize, const GLfloat *values) +{ + GLCALLV(PixelMapfv, map, mapsize, values); +} + +Q_DECL_EXPORT void APIENTRY glPixelTransferi(GLenum pname, GLint param) +{ + GLCALLV(PixelTransferi, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glPixelTransferf(GLenum pname, GLfloat param) +{ + GLCALLV(PixelTransferf, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glPixelZoom(GLfloat xfactor, GLfloat yfactor) +{ + GLCALLV(PixelZoom, xfactor, yfactor); +} + +Q_DECL_EXPORT void APIENTRY glAlphaFunc(GLenum func, GLfloat ref) +{ + GLCALLV(AlphaFunc, func, ref); +} + +Q_DECL_EXPORT void APIENTRY glEvalPoint2(GLint i, GLint j) +{ + GLCALLV(EvalPoint2, i, j); +} + +Q_DECL_EXPORT void APIENTRY glEvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2) +{ + GLCALLV(EvalMesh2, mode, i1, i2, j1, j2); +} + +Q_DECL_EXPORT void APIENTRY glEvalPoint1(GLint i) +{ + GLCALLV(EvalPoint1, i); +} + +Q_DECL_EXPORT void APIENTRY glEvalMesh1(GLenum mode, GLint i1, GLint i2) +{ + GLCALLV(EvalMesh1, mode, i1, i2); +} + +Q_DECL_EXPORT void APIENTRY glEvalCoord2fv(const GLfloat *u) +{ + GLCALLV(EvalCoord2fv, u); +} + +Q_DECL_EXPORT void APIENTRY glEvalCoord2f(GLfloat u, GLfloat v) +{ + GLCALLV(EvalCoord2f, u, v); +} + +Q_DECL_EXPORT void APIENTRY glEvalCoord2dv(const GLdouble *u) +{ + GLCALLV(EvalCoord2dv, u); +} + +Q_DECL_EXPORT void APIENTRY glEvalCoord2d(GLdouble u, GLdouble v) +{ + GLCALLV(EvalCoord2d, u, v); +} + +Q_DECL_EXPORT void APIENTRY glEvalCoord1fv(const GLfloat *u) +{ + GLCALLV(EvalCoord1fv, u); +} + +Q_DECL_EXPORT void APIENTRY glEvalCoord1f(GLfloat u) +{ + GLCALLV(EvalCoord1f, u); +} + +Q_DECL_EXPORT void APIENTRY glEvalCoord1dv(const GLdouble *u) +{ + GLCALLV(EvalCoord1dv, u); +} + +Q_DECL_EXPORT void APIENTRY glEvalCoord1d(GLdouble u) +{ + GLCALLV(EvalCoord1d, u); +} + +Q_DECL_EXPORT void APIENTRY glMapGrid2f(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2) +{ + GLCALLV(MapGrid2f, un, u1, u2, vn, v1, v2); +} + +Q_DECL_EXPORT void APIENTRY glMapGrid2d(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2) +{ + GLCALLV(MapGrid2d, un, u1, u2, vn, v1, v2); +} + +Q_DECL_EXPORT void APIENTRY glMapGrid1f(GLint un, GLfloat u1, GLfloat u2) +{ + GLCALLV(MapGrid1f, un, u1, u2); +} + +Q_DECL_EXPORT void APIENTRY glMapGrid1d(GLint un, GLdouble u1, GLdouble u2) +{ + GLCALLV(MapGrid1d, un, u1, u2); +} + +Q_DECL_EXPORT void APIENTRY glMap2f(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points) +{ + GLCALLV(Map2f, target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points); +} + +Q_DECL_EXPORT void APIENTRY glMap2d(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points) +{ + GLCALLV(Map2d, target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points); +} + +Q_DECL_EXPORT void APIENTRY glMap1f(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points) +{ + GLCALLV(Map1f, target, u1, u2, stride, order, points); +} + +Q_DECL_EXPORT void APIENTRY glMap1d(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points) +{ + GLCALLV(Map1d, target, u1, u2, stride, order, points); +} + +Q_DECL_EXPORT void APIENTRY glPushAttrib(GLbitfield mask) +{ + GLCALLV(PushAttrib, mask); +} + +Q_DECL_EXPORT void APIENTRY glPopAttrib() +{ + GLCALLV(PopAttrib); +} + +Q_DECL_EXPORT void APIENTRY glAccum(GLenum op, GLfloat value) +{ + GLCALLV(Accum, op, value); +} + +Q_DECL_EXPORT void APIENTRY glIndexMask(GLuint mask) +{ + GLCALLV(IndexMask, mask); +} + +Q_DECL_EXPORT void APIENTRY glClearIndex(GLfloat c) +{ + GLCALLV(ClearIndex, c); +} + +Q_DECL_EXPORT void APIENTRY glClearAccum(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +{ + GLCALLV(ClearAccum, red, green, blue, alpha); +} + +Q_DECL_EXPORT void APIENTRY glPushName(GLuint name) +{ + GLCALLV(PushName, name); +} + +Q_DECL_EXPORT void APIENTRY glPopName() +{ + GLCALLV(PopName); +} + +Q_DECL_EXPORT void APIENTRY glPassThrough(GLfloat token) +{ + GLCALLV(PassThrough, token); +} + +Q_DECL_EXPORT void APIENTRY glLoadName(GLuint name) +{ + GLCALLV(LoadName, name); +} + +Q_DECL_EXPORT void APIENTRY glInitNames() +{ + GLCALLV(InitNames); +} + +Q_DECL_EXPORT GLint APIENTRY glRenderMode(GLenum mode) +{ + GLCALL(RenderMode, mode); +} + +Q_DECL_EXPORT void APIENTRY glSelectBuffer(GLsizei size, GLuint *buffer) +{ + GLCALLV(SelectBuffer, size, buffer); +} + +Q_DECL_EXPORT void APIENTRY glFeedbackBuffer(GLsizei size, GLenum type, GLfloat *buffer) +{ + GLCALLV(FeedbackBuffer, size, type, buffer); +} + +Q_DECL_EXPORT void APIENTRY glTexGeniv(GLenum coord, GLenum pname, const GLint *params) +{ + GLCALLV(TexGeniv, coord, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glTexGeni(GLenum coord, GLenum pname, GLint param) +{ + GLCALLV(TexGeni, coord, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glTexGenfv(GLenum coord, GLenum pname, const GLfloat *params) +{ + GLCALLV(TexGenfv, coord, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glTexGenf(GLenum coord, GLenum pname, GLfloat param) +{ + GLCALLV(TexGenf, coord, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glTexGendv(GLenum coord, GLenum pname, const GLdouble *params) +{ + GLCALLV(TexGendv, coord, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glTexGend(GLenum coord, GLenum pname, GLdouble param) +{ + GLCALLV(TexGend, coord, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glTexEnviv(GLenum target, GLenum pname, const GLint *params) +{ + GLCALLV(TexEnviv, target, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glTexEnvi(GLenum target, GLenum pname, GLint param) +{ + GLCALLV(TexEnvi, target, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glTexEnvfv(GLenum target, GLenum pname, const GLfloat *params) +{ + GLCALLV(TexEnvfv, target, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glTexEnvf(GLenum target, GLenum pname, GLfloat param) +{ + GLCALLV(TexEnvf, target, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glShadeModel(GLenum mode) +{ + GLCALLV(ShadeModel, mode); +} + +Q_DECL_EXPORT void APIENTRY glPolygonStipple(const GLubyte *mask) +{ + GLCALLV(PolygonStipple, mask); +} + +Q_DECL_EXPORT void APIENTRY glMaterialiv(GLenum face, GLenum pname, const GLint *params) +{ + GLCALLV(Materialiv, face, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glMateriali(GLenum face, GLenum pname, GLint param) +{ + GLCALLV(Materiali, face, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) +{ + GLCALLV(Materialfv, face, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glMaterialf(GLenum face, GLenum pname, GLfloat param) +{ + GLCALLV(Materialf, face, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glLineStipple(GLint factor, GLushort pattern) +{ + GLCALLV(LineStipple, factor, pattern); +} + +Q_DECL_EXPORT void APIENTRY glLightModeliv(GLenum pname, const GLint *params) +{ + GLCALLV(LightModeliv, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glLightModeli(GLenum pname, GLint param) +{ + GLCALLV(LightModeli, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glLightModelfv(GLenum pname, const GLfloat *params) +{ + GLCALLV(LightModelfv, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glLightModelf(GLenum pname, GLfloat param) +{ + GLCALLV(LightModelf, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glLightiv(GLenum light, GLenum pname, const GLint *params) +{ + GLCALLV(Lightiv, light, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glLighti(GLenum light, GLenum pname, GLint param) +{ + GLCALLV(Lighti, light, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glLightfv(GLenum light, GLenum pname, const GLfloat *params) +{ + GLCALLV(Lightfv, light, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glLightf(GLenum light, GLenum pname, GLfloat param) +{ + GLCALLV(Lightf, light, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glFogiv(GLenum pname, const GLint *params) +{ + GLCALLV(Fogiv, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glFogi(GLenum pname, GLint param) +{ + GLCALLV(Fogi, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glFogfv(GLenum pname, const GLfloat *params) +{ + GLCALLV(Fogfv, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glFogf(GLenum pname, GLfloat param) +{ + GLCALLV(Fogf, pname, param); +} + +Q_DECL_EXPORT void APIENTRY glColorMaterial(GLenum face, GLenum mode) +{ + GLCALLV(ColorMaterial, face, mode); +} + +Q_DECL_EXPORT void APIENTRY glClipPlane(GLenum plane, const GLdouble *equation) +{ + GLCALLV(ClipPlane, plane, equation); +} + +Q_DECL_EXPORT void APIENTRY glVertex4sv(const GLshort *v) +{ + GLCALLV(Vertex4sv, v); +} + +Q_DECL_EXPORT void APIENTRY glVertex4s(GLshort x, GLshort y, GLshort z, GLshort w) +{ + GLCALLV(Vertex4s, x, y, z, w); +} + +Q_DECL_EXPORT void APIENTRY glVertex4iv(const GLint *v) +{ + GLCALLV(Vertex4iv, v); +} + +Q_DECL_EXPORT void APIENTRY glVertex4i(GLint x, GLint y, GLint z, GLint w) +{ + GLCALLV(Vertex4i, x, y, z, w); +} + +Q_DECL_EXPORT void APIENTRY glVertex4fv(const GLfloat *v) +{ + GLCALLV(Vertex4fv, v); +} + +Q_DECL_EXPORT void APIENTRY glVertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GLCALLV(Vertex4f, x, y, z, w); +} + +Q_DECL_EXPORT void APIENTRY glVertex4dv(const GLdouble *v) +{ + GLCALLV(Vertex4dv, v); +} + +Q_DECL_EXPORT void APIENTRY glVertex4d(GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + GLCALLV(Vertex4d, x, y, z, w); +} + +Q_DECL_EXPORT void APIENTRY glVertex3sv(const GLshort *v) +{ + GLCALLV(Vertex3sv, v); +} + +Q_DECL_EXPORT void APIENTRY glVertex3s(GLshort x, GLshort y, GLshort z) +{ + GLCALLV(Vertex3s, x, y, z); +} + +Q_DECL_EXPORT void APIENTRY glVertex3iv(const GLint *v) +{ + GLCALLV(Vertex3iv, v); +} + +Q_DECL_EXPORT void APIENTRY glVertex3i(GLint x, GLint y, GLint z) +{ + GLCALLV(Vertex3i, x, y, z); +} + +Q_DECL_EXPORT void APIENTRY glVertex3fv(const GLfloat *v) +{ + GLCALLV(Vertex3fv, v); +} + +Q_DECL_EXPORT void APIENTRY glVertex3f(GLfloat x, GLfloat y, GLfloat z) +{ + GLCALLV(Vertex3f, x, y, z); +} + +Q_DECL_EXPORT void APIENTRY glVertex3dv(const GLdouble *v) +{ + GLCALLV(Vertex3dv, v); +} + +Q_DECL_EXPORT void APIENTRY glVertex3d(GLdouble x, GLdouble y, GLdouble z) +{ + GLCALLV(Vertex3d, x, y, z); +} + +Q_DECL_EXPORT void APIENTRY glVertex2sv(const GLshort *v) +{ + GLCALLV(Vertex2sv, v); +} + +Q_DECL_EXPORT void APIENTRY glVertex2s(GLshort x, GLshort y) +{ + GLCALLV(Vertex2s, x, y); +} + +Q_DECL_EXPORT void APIENTRY glVertex2iv(const GLint *v) +{ + GLCALLV(Vertex2iv, v); +} + +Q_DECL_EXPORT void APIENTRY glVertex2i(GLint x, GLint y) +{ + GLCALLV(Vertex2i, x, y); +} + +Q_DECL_EXPORT void APIENTRY glVertex2fv(const GLfloat *v) +{ + GLCALLV(Vertex2fv, v); +} + +Q_DECL_EXPORT void APIENTRY glVertex2f(GLfloat x, GLfloat y) +{ + GLCALLV(Vertex2f, x, y); +} + +Q_DECL_EXPORT void APIENTRY glVertex2dv(const GLdouble *v) +{ + GLCALLV(Vertex2dv, v); +} + +Q_DECL_EXPORT void APIENTRY glVertex2d(GLdouble x, GLdouble y) +{ + GLCALLV(Vertex2d, x, y); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord4sv(const GLshort *v) +{ + GLCALLV(TexCoord4sv, v); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord4s(GLshort s, GLshort t, GLshort r, GLshort q) +{ + GLCALLV(TexCoord4s, s, t, r, q); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord4iv(const GLint *v) +{ + GLCALLV(TexCoord4iv, v); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord4i(GLint s, GLint t, GLint r, GLint q) +{ + GLCALLV(TexCoord4i, s, t, r, q); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord4fv(const GLfloat *v) +{ + GLCALLV(TexCoord4fv, v); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord4f(GLfloat s, GLfloat t, GLfloat r, GLfloat q) +{ + GLCALLV(TexCoord4f, s, t, r, q); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord4dv(const GLdouble *v) +{ + GLCALLV(TexCoord4dv, v); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord4d(GLdouble s, GLdouble t, GLdouble r, GLdouble q) +{ + GLCALLV(TexCoord4d, s, t, r, q); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord3sv(const GLshort *v) +{ + GLCALLV(TexCoord3sv, v); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord3s(GLshort s, GLshort t, GLshort r) +{ + GLCALLV(TexCoord3s, s, t, r); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord3iv(const GLint *v) +{ + GLCALLV(TexCoord3iv, v); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord3i(GLint s, GLint t, GLint r) +{ + GLCALLV(TexCoord3i, s, t, r); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord3fv(const GLfloat *v) +{ + GLCALLV(TexCoord3fv, v); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord3f(GLfloat s, GLfloat t, GLfloat r) +{ + GLCALLV(TexCoord3f, s, t, r); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord3dv(const GLdouble *v) +{ + GLCALLV(TexCoord3dv, v); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord3d(GLdouble s, GLdouble t, GLdouble r) +{ + GLCALLV(TexCoord3d, s, t, r); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord2sv(const GLshort *v) +{ + GLCALLV(TexCoord2sv, v); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord2s(GLshort s, GLshort t) +{ + GLCALLV(TexCoord2s, s, t); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord2iv(const GLint *v) +{ + GLCALLV(TexCoord2iv, v); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord2i(GLint s, GLint t) +{ + GLCALLV(TexCoord2i, s, t); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord2fv(const GLfloat *v) +{ + GLCALLV(TexCoord2fv, v); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord2f(GLfloat s, GLfloat t) +{ + GLCALLV(TexCoord2f, s, t); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord2dv(const GLdouble *v) +{ + GLCALLV(TexCoord2dv, v); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord2d(GLdouble s, GLdouble t) +{ + GLCALLV(TexCoord2d, s, t); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord1sv(const GLshort *v) +{ + GLCALLV(TexCoord1sv, v); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord1s(GLshort s) +{ + GLCALLV(TexCoord1s, s); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord1iv(const GLint *v) +{ + GLCALLV(TexCoord1iv, v); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord1i(GLint s) +{ + GLCALLV(TexCoord1i, s); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord1fv(const GLfloat *v) +{ + GLCALLV(TexCoord1fv, v); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord1f(GLfloat s) +{ + GLCALLV(TexCoord1f, s); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord1dv(const GLdouble *v) +{ + GLCALLV(TexCoord1dv, v); +} + +Q_DECL_EXPORT void APIENTRY glTexCoord1d(GLdouble s) +{ + GLCALLV(TexCoord1d, s); +} + +Q_DECL_EXPORT void APIENTRY glRectsv(const GLshort *v1, const GLshort *v2) +{ + GLCALLV(Rectsv, v1, v2); +} + +Q_DECL_EXPORT void APIENTRY glRects(GLshort x1, GLshort y1, GLshort x2, GLshort y2) +{ + GLCALLV(Rects, x1, y1, x2, y2); +} + +Q_DECL_EXPORT void APIENTRY glRectiv(const GLint *v1, const GLint *v2) +{ + GLCALLV(Rectiv, v1, v2); +} + +Q_DECL_EXPORT void APIENTRY glRecti(GLint x1, GLint y1, GLint x2, GLint y2) +{ + GLCALLV(Recti, x1, y1, x2, y2); +} + +Q_DECL_EXPORT void APIENTRY glRectfv(const GLfloat *v1, const GLfloat *v2) +{ + GLCALLV(Rectfv, v1, v2); +} + +Q_DECL_EXPORT void APIENTRY glRectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) +{ + GLCALLV(Rectf, x1, y1, x2, y2); +} + +Q_DECL_EXPORT void APIENTRY glRectdv(const GLdouble *v1, const GLdouble *v2) +{ + GLCALLV(Rectdv, v1, v2); +} + +Q_DECL_EXPORT void APIENTRY glRectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2) +{ + GLCALLV(Rectd, x1, y1, x2, y2); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos4sv(const GLshort *v) +{ + GLCALLV(RasterPos4sv, v); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos4s(GLshort x, GLshort y, GLshort z, GLshort w) +{ + GLCALLV(RasterPos4s, x, y, z, w); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos4iv(const GLint *v) +{ + GLCALLV(RasterPos4iv, v); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos4i(GLint x, GLint y, GLint z, GLint w) +{ + GLCALLV(RasterPos4i, x, y, z, w); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos4fv(const GLfloat *v) +{ + GLCALLV(RasterPos4fv, v); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GLCALLV(RasterPos4f, x, y, z, w); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos4dv(const GLdouble *v) +{ + GLCALLV(RasterPos4dv, v); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos4d(GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + GLCALLV(RasterPos4d, x, y, z, w); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos3sv(const GLshort *v) +{ + GLCALLV(RasterPos3sv, v); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos3s(GLshort x, GLshort y, GLshort z) +{ + GLCALLV(RasterPos3s, x, y, z); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos3iv(const GLint *v) +{ + GLCALLV(RasterPos3iv, v); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos3i(GLint x, GLint y, GLint z) +{ + GLCALLV(RasterPos3i, x, y, z); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos3fv(const GLfloat *v) +{ + GLCALLV(RasterPos3fv, v); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos3f(GLfloat x, GLfloat y, GLfloat z) +{ + GLCALLV(RasterPos3f, x, y, z); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos3dv(const GLdouble *v) +{ + GLCALLV(RasterPos3dv, v); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos3d(GLdouble x, GLdouble y, GLdouble z) +{ + GLCALLV(RasterPos3d, x, y, z); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos2sv(const GLshort *v) +{ + GLCALLV(RasterPos2sv, v); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos2s(GLshort x, GLshort y) +{ + GLCALLV(RasterPos2s, x, y); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos2iv(const GLint *v) +{ + GLCALLV(RasterPos2iv, v); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos2i(GLint x, GLint y) +{ + GLCALLV(RasterPos2i, x, y); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos2fv(const GLfloat *v) +{ + GLCALLV(RasterPos2fv, v); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos2f(GLfloat x, GLfloat y) +{ + GLCALLV(RasterPos2f, x, y); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos2dv(const GLdouble *v) +{ + GLCALLV(RasterPos2dv, v); +} + +Q_DECL_EXPORT void APIENTRY glRasterPos2d(GLdouble x, GLdouble y) +{ + GLCALLV(RasterPos2d, x, y); +} + +Q_DECL_EXPORT void APIENTRY glNormal3sv(const GLshort *v) +{ + GLCALLV(Normal3sv, v); +} + +Q_DECL_EXPORT void APIENTRY glNormal3s(GLshort nx, GLshort ny, GLshort nz) +{ + GLCALLV(Normal3s, nx, ny, nz); +} + +Q_DECL_EXPORT void APIENTRY glNormal3iv(const GLint *v) +{ + GLCALLV(Normal3iv, v); +} + +Q_DECL_EXPORT void APIENTRY glNormal3i(GLint nx, GLint ny, GLint nz) +{ + GLCALLV(Normal3i, nx, ny, nz); +} + +Q_DECL_EXPORT void APIENTRY glNormal3fv(const GLfloat *v) +{ + GLCALLV(Normal3fv, v); +} + +Q_DECL_EXPORT void APIENTRY glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz) +{ + GLCALLV(Normal3f, nx, ny, nz); +} + +Q_DECL_EXPORT void APIENTRY glNormal3dv(const GLdouble *v) +{ + GLCALLV(Normal3dv, v); +} + +Q_DECL_EXPORT void APIENTRY glNormal3d(GLdouble nx, GLdouble ny, GLdouble nz) +{ + GLCALLV(Normal3d, nx, ny, nz); +} + +Q_DECL_EXPORT void APIENTRY glNormal3bv(const GLbyte *v) +{ + GLCALLV(Normal3bv, v); +} + +Q_DECL_EXPORT void APIENTRY glNormal3b(GLbyte nx, GLbyte ny, GLbyte nz) +{ + GLCALLV(Normal3b, nx, ny, nz); +} + +Q_DECL_EXPORT void APIENTRY glIndexsv(const GLshort *c) +{ + GLCALLV(Indexsv, c); +} + +Q_DECL_EXPORT void APIENTRY glIndexs(GLshort c) +{ + GLCALLV(Indexs, c); +} + +Q_DECL_EXPORT void APIENTRY glIndexiv(const GLint *c) +{ + GLCALLV(Indexiv, c); +} + +Q_DECL_EXPORT void APIENTRY glIndexi(GLint c) +{ + GLCALLV(Indexi, c); +} + +Q_DECL_EXPORT void APIENTRY glIndexfv(const GLfloat *c) +{ + GLCALLV(Indexfv, c); +} + +Q_DECL_EXPORT void APIENTRY glIndexf(GLfloat c) +{ + GLCALLV(Indexf, c); +} + +Q_DECL_EXPORT void APIENTRY glIndexdv(const GLdouble *c) +{ + GLCALLV(Indexdv, c); +} + +Q_DECL_EXPORT void APIENTRY glIndexd(GLdouble c) +{ + GLCALLV(Indexd, c); +} + +Q_DECL_EXPORT void APIENTRY glEnd() +{ + GLCALLV(End); +} + +Q_DECL_EXPORT void APIENTRY glEdgeFlagv(const GLboolean *flag) +{ + GLCALLV(EdgeFlagv, flag); +} + +Q_DECL_EXPORT void APIENTRY glEdgeFlag(GLboolean flag) +{ + GLCALLV(EdgeFlag, flag); +} + +Q_DECL_EXPORT void APIENTRY glColor4usv(const GLushort *v) +{ + GLCALLV(Color4usv, v); +} + +Q_DECL_EXPORT void APIENTRY glColor4us(GLushort red, GLushort green, GLushort blue, GLushort alpha) +{ + GLCALLV(Color4us, red, green, blue, alpha); +} + +Q_DECL_EXPORT void APIENTRY glColor4uiv(const GLuint *v) +{ + GLCALLV(Color4uiv, v); +} + +Q_DECL_EXPORT void APIENTRY glColor4ui(GLuint red, GLuint green, GLuint blue, GLuint alpha) +{ + GLCALLV(Color4ui, red, green, blue, alpha); +} + +Q_DECL_EXPORT void APIENTRY glColor4ubv(const GLubyte *v) +{ + GLCALLV(Color4ubv, v); +} + +Q_DECL_EXPORT void APIENTRY glColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) +{ + GLCALLV(Color4ub, red, green, blue, alpha); +} + +Q_DECL_EXPORT void APIENTRY glColor4sv(const GLshort *v) +{ + GLCALLV(Color4sv, v); +} + +Q_DECL_EXPORT void APIENTRY glColor4s(GLshort red, GLshort green, GLshort blue, GLshort alpha) +{ + GLCALLV(Color4s, red, green, blue, alpha); +} + +Q_DECL_EXPORT void APIENTRY glColor4iv(const GLint *v) +{ + GLCALLV(Color4iv, v); +} + +Q_DECL_EXPORT void APIENTRY glColor4i(GLint red, GLint green, GLint blue, GLint alpha) +{ + GLCALLV(Color4i, red, green, blue, alpha); +} + +Q_DECL_EXPORT void APIENTRY glColor4fv(const GLfloat *v) +{ + GLCALLV(Color4fv, v); +} + +Q_DECL_EXPORT void APIENTRY glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +{ + GLCALLV(Color4f, red, green, blue, alpha); +} + +Q_DECL_EXPORT void APIENTRY glColor4dv(const GLdouble *v) +{ + GLCALLV(Color4dv, v); +} + +Q_DECL_EXPORT void APIENTRY glColor4d(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha) +{ + GLCALLV(Color4d, red, green, blue, alpha); +} + +Q_DECL_EXPORT void APIENTRY glColor4bv(const GLbyte *v) +{ + GLCALLV(Color4bv, v); +} + +Q_DECL_EXPORT void APIENTRY glColor4b(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha) +{ + GLCALLV(Color4b, red, green, blue, alpha); +} + +Q_DECL_EXPORT void APIENTRY glColor3usv(const GLushort *v) +{ + GLCALLV(Color3usv, v); +} + +Q_DECL_EXPORT void APIENTRY glColor3us(GLushort red, GLushort green, GLushort blue) +{ + GLCALLV(Color3us, red, green, blue); +} + +Q_DECL_EXPORT void APIENTRY glColor3uiv(const GLuint *v) +{ + GLCALLV(Color3uiv, v); +} + +Q_DECL_EXPORT void APIENTRY glColor3ui(GLuint red, GLuint green, GLuint blue) +{ + GLCALLV(Color3ui, red, green, blue); +} + +Q_DECL_EXPORT void APIENTRY glColor3ubv(const GLubyte *v) +{ + GLCALLV(Color3ubv, v); +} + +Q_DECL_EXPORT void APIENTRY glColor3ub(GLubyte red, GLubyte green, GLubyte blue) +{ + GLCALLV(Color3ub, red, green, blue); +} + +Q_DECL_EXPORT void APIENTRY glColor3sv(const GLshort *v) +{ + GLCALLV(Color3sv, v); +} + +Q_DECL_EXPORT void APIENTRY glColor3s(GLshort red, GLshort green, GLshort blue) +{ + GLCALLV(Color3s, red, green, blue); +} + +Q_DECL_EXPORT void APIENTRY glColor3iv(const GLint *v) +{ + GLCALLV(Color3iv, v); +} + +Q_DECL_EXPORT void APIENTRY glColor3i(GLint red, GLint green, GLint blue) +{ + GLCALLV(Color3i, red, green, blue); +} + +Q_DECL_EXPORT void APIENTRY glColor3fv(const GLfloat *v) +{ + GLCALLV(Color3fv, v); +} + +Q_DECL_EXPORT void APIENTRY glColor3f(GLfloat red, GLfloat green, GLfloat blue) +{ + GLCALLV(Color3f, red, green, blue); +} + +Q_DECL_EXPORT void APIENTRY glColor3dv(const GLdouble *v) +{ + GLCALLV(Color3dv, v); +} + +Q_DECL_EXPORT void APIENTRY glColor3d(GLdouble red, GLdouble green, GLdouble blue) +{ + GLCALLV(Color3d, red, green, blue); +} + +Q_DECL_EXPORT void APIENTRY glColor3bv(const GLbyte *v) +{ + GLCALLV(Color3bv, v); +} + +Q_DECL_EXPORT void APIENTRY glColor3b(GLbyte red, GLbyte green, GLbyte blue) +{ + GLCALLV(Color3b, red, green, blue); +} + +Q_DECL_EXPORT void APIENTRY glBitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap) +{ + GLCALLV(Bitmap, width, height, xorig, yorig, xmove, ymove, bitmap); +} + +Q_DECL_EXPORT void APIENTRY glBegin(GLenum mode) +{ + GLCALLV(Begin, mode); +} + +Q_DECL_EXPORT void APIENTRY glListBase(GLuint base) +{ + GLCALLV(ListBase, base); +} + +Q_DECL_EXPORT GLuint APIENTRY glGenLists(GLsizei range) +{ + GLCALL(GenLists, range); +} + +Q_DECL_EXPORT void APIENTRY glDeleteLists(GLuint list, GLsizei range) +{ + GLCALLV(DeleteLists, list, range); +} + +Q_DECL_EXPORT void APIENTRY glCallLists(GLsizei n, GLenum type, const GLvoid *lists) +{ + GLCALLV(CallLists, n, type, lists); +} + +Q_DECL_EXPORT void APIENTRY glCallList(GLuint list) +{ + GLCALLV(CallList, list); +} + +Q_DECL_EXPORT void APIENTRY glEndList() +{ + GLCALLV(EndList); +} + +Q_DECL_EXPORT void APIENTRY glNewList(GLuint list, GLenum mode) +{ + GLCALLV(NewList, list, mode); +} + +Q_DECL_EXPORT void APIENTRY glIndexubv(const GLubyte *c) +{ + GLCALLV(Indexubv, c); +} + +Q_DECL_EXPORT void APIENTRY glIndexub(GLubyte c) +{ + GLCALLV(Indexub, c); +} + +Q_DECL_EXPORT GLboolean APIENTRY glIsTexture(GLuint texture) +{ + GLCALL(IsTexture, texture); +} + +Q_DECL_EXPORT void APIENTRY glGenTextures(GLsizei n, GLuint *textures) +{ + GLCALLV(GenTextures, n, textures); +} + +Q_DECL_EXPORT void APIENTRY glDeleteTextures(GLsizei n, const GLuint *textures) +{ + GLCALLV(DeleteTextures, n, textures); +} + +Q_DECL_EXPORT void APIENTRY glBindTexture(GLenum target, GLuint texture) +{ + GLCALLV(BindTexture, target, texture); +} + +Q_DECL_EXPORT void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) +{ + GLCALLV(TexSubImage2D, target, level, xoffset, yoffset, width, height, format, type, pixels); +} + +Q_DECL_EXPORT void APIENTRY glTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels) +{ + GLCALLV(TexSubImage1D, target, level, xoffset, width, format, type, pixels); +} + +Q_DECL_EXPORT void APIENTRY glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + GLCALLV(CopyTexSubImage2D, target, level, xoffset, yoffset, x, y, width, height); +} + +Q_DECL_EXPORT void APIENTRY glCopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) +{ + GLCALLV(CopyTexSubImage1D, target, level, xoffset, x, y, width); +} + +Q_DECL_EXPORT void APIENTRY glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +{ + GLCALLV(CopyTexImage2D, target, level, internalformat, x, y, width, height, border); +} + +Q_DECL_EXPORT void APIENTRY glCopyTexImage1D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border) +{ + GLCALLV(CopyTexImage1D, target, level, internalformat, x, y, width, border); +} + +Q_DECL_EXPORT void APIENTRY glPolygonOffset(GLfloat factor, GLfloat units) +{ + GLCALLV(PolygonOffset, factor, units); +} + +Q_DECL_EXPORT void APIENTRY glGetPointerv(GLenum pname, GLvoid* *params) +{ + GLCALLV(GetPointerv, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) +{ + GLCALLV(DrawElements, mode, count, type, indices); +} + +Q_DECL_EXPORT void APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count) +{ + GLCALLV(DrawArrays, mode, first, count); +} + +Q_DECL_EXPORT void APIENTRY glPushClientAttrib(GLbitfield mask) +{ + GLCALLV(PushClientAttrib, mask); +} + +Q_DECL_EXPORT void APIENTRY glPopClientAttrib() +{ + GLCALLV(PopClientAttrib); +} + +Q_DECL_EXPORT void APIENTRY glPrioritizeTextures(GLsizei n, const GLuint *textures, const GLfloat *priorities) +{ + GLCALLV(PrioritizeTextures, n, textures, priorities); +} + +Q_DECL_EXPORT GLboolean APIENTRY glAreTexturesResident(GLsizei n, const GLuint *textures, GLboolean *residences) +{ + GLCALL(AreTexturesResident, n, textures, residences); +} + +Q_DECL_EXPORT void APIENTRY glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + GLCALLV(VertexPointer, size, type, stride, pointer); +} + +Q_DECL_EXPORT void APIENTRY glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + GLCALLV(TexCoordPointer, size, type, stride, pointer); +} + +Q_DECL_EXPORT void APIENTRY glNormalPointer(GLenum type, GLsizei stride, const GLvoid *pointer) +{ + GLCALLV(NormalPointer, type, stride, pointer); +} + +Q_DECL_EXPORT void APIENTRY glInterleavedArrays(GLenum format, GLsizei stride, const GLvoid *pointer) +{ + GLCALLV(InterleavedArrays, format, stride, pointer); +} + +Q_DECL_EXPORT void APIENTRY glIndexPointer(GLenum type, GLsizei stride, const GLvoid *pointer) +{ + GLCALLV(IndexPointer, type, stride, pointer); +} + +Q_DECL_EXPORT void APIENTRY glEnableClientState(GLenum array) +{ + GLCALLV(EnableClientState, array); +} + +Q_DECL_EXPORT void APIENTRY glEdgeFlagPointer(GLsizei stride, const GLvoid *pointer) +{ + GLCALLV(EdgeFlagPointer, stride, pointer); +} + +Q_DECL_EXPORT void APIENTRY glDisableClientState(GLenum array) +{ + GLCALLV(DisableClientState, array); +} + +Q_DECL_EXPORT void APIENTRY glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + GLCALLV(ColorPointer, size, type, stride, pointer); +} + +Q_DECL_EXPORT void APIENTRY glArrayElement(GLint i) +{ + GLCALLV(ArrayElement, i); +} + +// OpenGL ES 2.0 + +Q_DECL_EXPORT void APIENTRY glActiveTexture(GLenum texture) +{ + GLCALLV(ActiveTexture,texture); +} + +Q_DECL_EXPORT void APIENTRY glAttachShader(GLuint program, GLuint shader) +{ + GLCALLV(AttachShader,program, shader); +} + +Q_DECL_EXPORT void APIENTRY glBindAttribLocation(GLuint program, GLuint index, const GLchar* name) +{ + GLCALLV(BindAttribLocation,program, index, name); +} + +Q_DECL_EXPORT void APIENTRY glBindBuffer(GLenum target, GLuint buffer) +{ + GLCALLV(BindBuffer,target, buffer); +} + +Q_DECL_EXPORT void APIENTRY glBindFramebuffer(GLenum target, GLuint framebuffer) +{ + GLCALLV(BindFramebuffer,target, framebuffer); +} + +Q_DECL_EXPORT void APIENTRY glBindRenderbuffer(GLenum target, GLuint renderbuffer) +{ + GLCALLV(BindRenderbuffer,target, renderbuffer); +} + +Q_DECL_EXPORT void APIENTRY glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + GLCALLV(BlendColor,red, green, blue, alpha); +} + +Q_DECL_EXPORT void APIENTRY glBlendEquation(GLenum mode) +{ + GLCALLV(BlendEquation,mode); +} + +Q_DECL_EXPORT void APIENTRY glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) +{ + GLCALLV(BlendEquationSeparate,modeRGB, modeAlpha); +} + +Q_DECL_EXPORT void APIENTRY glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +{ + GLCALLV(BlendFuncSeparate,srcRGB, dstRGB, srcAlpha, dstAlpha); +} + +Q_DECL_EXPORT void APIENTRY glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) +{ + GLCALLV(BufferData,target, size, data, usage); +} + +Q_DECL_EXPORT void APIENTRY glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) +{ + GLCALLV(BufferSubData,target, offset, size, data); +} + +Q_DECL_EXPORT GLenum APIENTRY glCheckFramebufferStatus(GLenum target) +{ + GLCALL(CheckFramebufferStatus,target); +} + +Q_DECL_EXPORT void APIENTRY glClearDepthf(GLclampf depth) +{ + glClearDepth(depth); +} + +Q_DECL_EXPORT void APIENTRY glCompileShader(GLuint shader) +{ + GLCALLV(CompileShader,shader); +} + +Q_DECL_EXPORT void APIENTRY glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) +{ + GLCALLV(CompressedTexImage2D,target, level, internalformat, width, height, border, imageSize, data); +} + +Q_DECL_EXPORT void APIENTRY glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) +{ + GLCALLV(CompressedTexSubImage2D,target, level, xoffset, yoffset, width, height, format, imageSize, data); +} + +Q_DECL_EXPORT GLuint APIENTRY glCreateProgram(void) +{ + GLCALL(CreateProgram); +} + +Q_DECL_EXPORT GLuint glCreateShader(GLenum type) +{ + GLCALL(CreateShader,type); +} + +Q_DECL_EXPORT void APIENTRY glDeleteBuffers(GLsizei n, const GLuint* buffers) +{ + GLCALLV(DeleteBuffers,n, buffers); +} + +Q_DECL_EXPORT void APIENTRY glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) +{ + GLCALLV(DeleteFramebuffers,n, framebuffers); +} + +Q_DECL_EXPORT void APIENTRY glDeleteProgram(GLuint program) +{ + GLCALLV(DeleteProgram,program); +} + +Q_DECL_EXPORT void APIENTRY glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) +{ + GLCALLV(DeleteRenderbuffers,n, renderbuffers); +} + +Q_DECL_EXPORT void APIENTRY glDeleteShader(GLuint shader) +{ + GLCALLV(DeleteShader,shader); +} + +Q_DECL_EXPORT void APIENTRY glDepthRangef(GLclampf zNear, GLclampf zFar) +{ + glDepthRange(zNear, zFar); +} + +Q_DECL_EXPORT void APIENTRY glDetachShader(GLuint program, GLuint shader) +{ + GLCALLV(DetachShader,program, shader); +} + +Q_DECL_EXPORT void APIENTRY glDisableVertexAttribArray(GLuint index) +{ + GLCALLV(DisableVertexAttribArray,index); +} + +Q_DECL_EXPORT void APIENTRY glEnableVertexAttribArray(GLuint index) +{ + GLCALLV(EnableVertexAttribArray,index); +} + +Q_DECL_EXPORT void APIENTRY glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +{ + GLCALLV(FramebufferRenderbuffer,target, attachment, renderbuffertarget, renderbuffer); +} + +Q_DECL_EXPORT void APIENTRY glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +{ + GLCALLV(FramebufferTexture2D,target, attachment, textarget, texture, level); +} + +Q_DECL_EXPORT void APIENTRY glGenBuffers(GLsizei n, GLuint* buffers) +{ + GLCALLV(GenBuffers,n, buffers); +} + +Q_DECL_EXPORT void APIENTRY glGenerateMipmap(GLenum target) +{ + GLCALLV(GenerateMipmap,target); +} + +Q_DECL_EXPORT void APIENTRY glGenFramebuffers(GLsizei n, GLuint* framebuffers) +{ + GLCALLV(GenFramebuffers,n, framebuffers); +} + +Q_DECL_EXPORT void APIENTRY glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) +{ + GLCALLV(GenRenderbuffers,n, renderbuffers); +} + +Q_DECL_EXPORT void APIENTRY glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +{ + GLCALLV(GetActiveAttrib,program, index, bufsize, length, size, type, name); +} + +Q_DECL_EXPORT void APIENTRY glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +{ + GLCALLV(GetActiveUniform,program, index, bufsize, length, size, type, name); +} + +Q_DECL_EXPORT void APIENTRY glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) +{ + GLCALLV(GetAttachedShaders,program, maxcount, count, shaders); +} + +Q_DECL_EXPORT int APIENTRY glGetAttribLocation(GLuint program, const GLchar* name) +{ + GLCALL(GetAttribLocation,program, name); +} + +Q_DECL_EXPORT void APIENTRY glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) +{ + GLCALLV(GetBufferParameteriv,target, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params) +{ + GLCALLV(GetFramebufferAttachmentParameteriv,target, attachment, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetProgramiv(GLuint program, GLenum pname, GLint* params) +{ + GLCALLV(GetProgramiv,program, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) +{ + GLCALLV(GetProgramInfoLog,program, bufsize, length, infolog); +} + +Q_DECL_EXPORT void APIENTRY glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) +{ + GLCALLV(GetRenderbufferParameteriv,target, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetShaderiv(GLuint shader, GLenum pname, GLint* params) +{ + GLCALLV(GetShaderiv,shader, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) +{ + GLCALLV(GetShaderInfoLog,shader, bufsize, length, infolog); +} + +Q_DECL_EXPORT void APIENTRY glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) +{ + GLCALLV(GetShaderPrecisionFormat,shadertype, precisiontype, range, precision); +} + +Q_DECL_EXPORT void APIENTRY glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) +{ + GLCALLV(GetShaderSource,shader, bufsize, length, source); +} + +Q_DECL_EXPORT void APIENTRY glGetUniformfv(GLuint program, GLint location, GLfloat* params) +{ + GLCALLV(GetUniformfv, program, location, params); +} + +Q_DECL_EXPORT void APIENTRY glGetUniformiv(GLuint program, GLint location, GLint* params) +{ + GLCALLV(GetUniformiv, program, location, params); +} + +Q_DECL_EXPORT int APIENTRY glGetUniformLocation(GLuint program, const GLchar* name) +{ + GLCALL(GetUniformLocation,program, name); +} + +Q_DECL_EXPORT void APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) +{ + GLCALLV(GetVertexAttribfv,index, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) +{ + GLCALLV(GetVertexAttribiv,index, pname, params); +} + +Q_DECL_EXPORT void APIENTRY glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer) +{ + GLCALLV(GetVertexAttribPointerv,index, pname, pointer); +} + +Q_DECL_EXPORT GLboolean APIENTRY glIsBuffer(GLuint buffer) +{ + GLCALL(IsBuffer,buffer); +} + +Q_DECL_EXPORT GLboolean APIENTRY glIsFramebuffer(GLuint framebuffer) +{ + GLCALL(IsFramebuffer,framebuffer); +} + +Q_DECL_EXPORT GLboolean APIENTRY glIsProgram(GLuint program) +{ + GLCALL(IsProgram,program); +} + +Q_DECL_EXPORT GLboolean APIENTRY glIsRenderbuffer(GLuint renderbuffer) +{ + GLCALL(IsRenderbuffer,renderbuffer); +} + +Q_DECL_EXPORT GLboolean APIENTRY glIsShader(GLuint shader) +{ + GLCALL(IsShader,shader); +} + +Q_DECL_EXPORT void APIENTRY glLinkProgram(GLuint program) +{ + GLCALLV(LinkProgram,program); +} + +Q_DECL_EXPORT void APIENTRY glReleaseShaderCompiler(void) +{ + GLCALLV(ReleaseShaderCompiler,); +} + +Q_DECL_EXPORT void APIENTRY glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +{ + GLCALLV(RenderbufferStorage,target, internalformat, width, height); +} + +Q_DECL_EXPORT void APIENTRY glSampleCoverage(GLclampf value, GLboolean invert) +{ + GLCALLV(SampleCoverage,value, invert); +} + +Q_DECL_EXPORT void APIENTRY glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) +{ + GLCALLV(ShaderBinary,n, shaders, binaryformat, binary, length); +} + +Q_DECL_EXPORT void APIENTRY glShaderSource(GLuint shader, GLsizei count, const GLchar* *string, const GLint* length) +{ + GLCALLV(ShaderSource,shader, count, string, length); +} + +Q_DECL_EXPORT void APIENTRY glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) +{ + GLCALLV(StencilFuncSeparate,face, func, ref, mask); +} + +Q_DECL_EXPORT void APIENTRY glStencilMaskSeparate(GLenum face, GLuint mask) +{ + GLCALLV(StencilMaskSeparate,face, mask); +} + +Q_DECL_EXPORT void APIENTRY glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +{ + GLCALLV(StencilOpSeparate,face, fail, zfail, zpass); +} + +Q_DECL_EXPORT void APIENTRY glUniform1f(GLint location, GLfloat x) +{ + GLCALLV(Uniform1f,location, x); +} + +Q_DECL_EXPORT void APIENTRY glUniform1fv(GLint location, GLsizei count, const GLfloat* v) +{ + GLCALLV(Uniform1fv,location, count, v); +} + +Q_DECL_EXPORT void APIENTRY glUniform1i(GLint location, GLint x) +{ + GLCALLV(Uniform1i,location, x); +} + +Q_DECL_EXPORT void APIENTRY glUniform1iv(GLint location, GLsizei count, const GLint* v) +{ + GLCALLV(Uniform1iv,location, count, v); +} + +Q_DECL_EXPORT void APIENTRY glUniform2f(GLint location, GLfloat x, GLfloat y) +{ + GLCALLV(Uniform2f,location, x, y); +} + +Q_DECL_EXPORT void APIENTRY glUniform2fv(GLint location, GLsizei count, const GLfloat* v) +{ + GLCALLV(Uniform2fv,location, count, v); +} + +Q_DECL_EXPORT void APIENTRY glUniform2i(GLint location, GLint x, GLint y) +{ + GLCALLV(Uniform2i,location, x, y); +} + +Q_DECL_EXPORT void APIENTRY glUniform2iv(GLint location, GLsizei count, const GLint* v) +{ + GLCALLV(Uniform2iv,location, count, v); +} + +Q_DECL_EXPORT void APIENTRY glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) +{ + GLCALLV(Uniform3f,location, x, y, z); +} + +Q_DECL_EXPORT void APIENTRY glUniform3fv(GLint location, GLsizei count, const GLfloat* v) +{ + GLCALLV(Uniform3fv,location, count, v); +} + +Q_DECL_EXPORT void APIENTRY glUniform3i(GLint location, GLint x, GLint y, GLint z) +{ + GLCALLV(Uniform3i,location, x, y, z); +} + +Q_DECL_EXPORT void APIENTRY glUniform3iv(GLint location, GLsizei count, const GLint* v) +{ + GLCALLV(Uniform3iv,location, count, v); +} + +Q_DECL_EXPORT void APIENTRY glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GLCALLV(Uniform4f,location, x, y, z, w); +} + +Q_DECL_EXPORT void APIENTRY glUniform4fv(GLint location, GLsizei count, const GLfloat* v) +{ + GLCALLV(Uniform4fv,location, count, v); +} + +Q_DECL_EXPORT void APIENTRY glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) +{ + GLCALLV(Uniform4i,location, x, y, z, w); +} + +Q_DECL_EXPORT void APIENTRY glUniform4iv(GLint location, GLsizei count, const GLint* v) +{ + GLCALLV(Uniform4iv,location, count, v); +} + +Q_DECL_EXPORT void APIENTRY glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + GLCALLV(UniformMatrix2fv,location, count, transpose, value); +} + +Q_DECL_EXPORT void APIENTRY glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + GLCALLV(UniformMatrix3fv,location, count, transpose, value); +} + +Q_DECL_EXPORT void APIENTRY glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + GLCALLV(UniformMatrix4fv,location, count, transpose, value); +} + +Q_DECL_EXPORT void APIENTRY glUseProgram(GLuint program) +{ + GLCALLV(UseProgram,program); +} + +Q_DECL_EXPORT void APIENTRY glValidateProgram(GLuint program) +{ + GLCALLV(ValidateProgram,program); +} + +Q_DECL_EXPORT void APIENTRY glVertexAttrib1f(GLuint indx, GLfloat x) +{ + GLCALLV(VertexAttrib1f,indx, x); +} + +Q_DECL_EXPORT void APIENTRY glVertexAttrib1fv(GLuint indx, const GLfloat* values) +{ + GLCALLV(VertexAttrib1fv,indx, values); +} + +Q_DECL_EXPORT void APIENTRY glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) +{ + GLCALLV(VertexAttrib2f,indx, x, y); +} + +Q_DECL_EXPORT void APIENTRY glVertexAttrib2fv(GLuint indx, const GLfloat* values) +{ + GLCALLV(VertexAttrib2fv,indx, values); +} + +Q_DECL_EXPORT void APIENTRY glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) +{ + GLCALLV(VertexAttrib3f,indx, x, y, z); +} + +Q_DECL_EXPORT void APIENTRY glVertexAttrib3fv(GLuint indx, const GLfloat* values) +{ + GLCALLV(VertexAttrib3fv,indx, values); +} + +Q_DECL_EXPORT void APIENTRY glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GLCALLV(VertexAttrib4f,indx, x, y, z, w); +} + +Q_DECL_EXPORT void APIENTRY glVertexAttrib4fv(GLuint indx, const GLfloat* values) +{ + GLCALLV(VertexAttrib4fv,indx, values); +} + +Q_DECL_EXPORT void APIENTRY glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) +{ + GLCALLV(VertexAttribPointer,indx, size, type, normalized, stride, ptr); +} + +// EGL + +Q_DECL_EXPORT __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress(const char *procname) +{ + // This is a bit more complicated since the GLES2 functions (that are not in OpenGL 1) + // must be made queriable in order to allow classes like QOpenGLFunctions to operate + // on the same code path for desktop GL and proxied ES. + typedef __eglMustCastToProperFunctionPointerType FuncType; + FuncType f = 0; + f = qgl_choose()->EGL_GetProcAddress(procname); + if (!f) { + static struct Tab { + const char *name; + FuncType func; + } tab[] = { + { "glActiveTexture", (FuncType) glActiveTexture }, + { "glAttachShader", (FuncType) glAttachShader }, + { "glBindAttribLocation", (FuncType) glBindAttribLocation }, + { "glBindBuffer", (FuncType) glBindBuffer }, + { "glBindFramebuffer", (FuncType) glBindFramebuffer }, + { "glBindRenderbuffer", (FuncType) glBindRenderbuffer }, + { "glBlendColor", (FuncType) glBlendColor }, + { "glBlendEquation", (FuncType) glBlendEquation }, + { "glBlendEquationSeparate", (FuncType) glBlendEquationSeparate }, + { "glBlendFuncSeparate", (FuncType) glBlendFuncSeparate }, + { "glBufferData", (FuncType) glBufferData }, + { "glBufferSubData", (FuncType) glBufferSubData }, + { "glCheckFramebufferStatus", (FuncType) glCheckFramebufferStatus }, + { "glCompileShader", (FuncType) glCompileShader }, + { "glCompressedTexImage2D", (FuncType) glCompressedTexImage2D }, + { "glCompressedTexSubImage2D", (FuncType) glCompressedTexSubImage2D }, + { "glCreateProgram", (FuncType) glCreateProgram }, + { "glCreateShader", (FuncType) glCreateShader }, + { "glDeleteBuffers", (FuncType) glDeleteBuffers }, + { "glDeleteFramebuffers", (FuncType) glDeleteFramebuffers }, + { "glDeleteProgram", (FuncType) glDeleteProgram }, + { "glDeleteRenderbuffers", (FuncType) glDeleteRenderbuffers }, + { "glDeleteShader", (FuncType) glDeleteShader }, + { "glDetachShader", (FuncType) glDetachShader }, + { "glDisableVertexAttribArray", (FuncType) glDisableVertexAttribArray }, + { "glEnableVertexAttribArray", (FuncType) glEnableVertexAttribArray }, + { "glFramebufferRenderbuffer", (FuncType) glFramebufferRenderbuffer }, + { "glFramebufferTexture2D", (FuncType) glFramebufferTexture2D }, + { "glGenBuffers", (FuncType) glGenBuffers }, + { "glGenerateMipmap", (FuncType) glGenerateMipmap }, + { "glGenFramebuffers", (FuncType) glGenFramebuffers }, + { "glGenRenderbuffers", (FuncType) glGenRenderbuffers }, + { "glGetActiveAttrib", (FuncType) glGetActiveAttrib }, + { "glGetActiveUniform", (FuncType) glGetActiveUniform }, + { "glGetAttachedShaders", (FuncType) glGetAttachedShaders }, + { "glGetAttribLocation", (FuncType) glGetAttribLocation }, + { "glGetBufferParameteriv", (FuncType) glGetBufferParameteriv }, + { "glGetFramebufferAttachmentParameteriv", (FuncType) glGetFramebufferAttachmentParameteriv }, + { "glGetProgramiv", (FuncType) glGetProgramiv }, + { "glGetProgramInfoLog", (FuncType) glGetProgramInfoLog }, + { "glGetRenderbufferParameteriv", (FuncType) glGetRenderbufferParameteriv }, + { "glGetShaderiv", (FuncType) glGetShaderiv }, + { "glGetShaderInfoLog", (FuncType) glGetShaderInfoLog }, + { "glGetShaderPrecisionFormat", (FuncType) glGetShaderPrecisionFormat }, + { "glGetShaderSource", (FuncType) glGetShaderSource }, + { "glGetUniformfv", (FuncType) glGetUniformfv }, + { "glGetUniformiv", (FuncType) glGetUniformiv }, + { "glGetUniformLocation", (FuncType) glGetUniformLocation }, + { "glGetVertexAttribfv", (FuncType) glGetVertexAttribfv }, + { "glGetVertexAttribiv", (FuncType) glGetVertexAttribiv }, + { "glGetVertexAttribPointerv", (FuncType) glGetVertexAttribPointerv }, + { "glIsBuffer", (FuncType) glIsBuffer }, + { "glIsFramebuffer", (FuncType) glIsFramebuffer }, + { "glIsProgram", (FuncType) glIsProgram }, + { "glIsRenderbuffer", (FuncType) glIsRenderbuffer }, + { "glIsShader", (FuncType) glIsShader }, + { "glLinkProgram", (FuncType) glLinkProgram }, + { "glReleaseShaderCompiler", (FuncType) glReleaseShaderCompiler }, + { "glRenderbufferStorage", (FuncType) glRenderbufferStorage }, + { "glSampleCoverage", (FuncType) glSampleCoverage }, + { "glShaderBinary", (FuncType) glShaderBinary }, + { "glShaderSource", (FuncType) glShaderSource }, + { "glStencilFuncSeparate", (FuncType) glStencilFuncSeparate }, + { "glStencilMaskSeparate", (FuncType) glStencilMaskSeparate }, + { "glStencilOpSeparate", (FuncType) glStencilOpSeparate }, + { "glUniform1f", (FuncType) glUniform1f }, + { "glUniform1fv", (FuncType) glUniform1fv }, + { "glUniform1i", (FuncType) glUniform1i }, + { "glUniform1iv", (FuncType) glUniform1iv }, + { "glUniform2f", (FuncType) glUniform2f }, + { "glUniform2fv", (FuncType) glUniform2fv }, + { "glUniform2i", (FuncType) glUniform2i }, + { "glUniform2iv", (FuncType) glUniform2iv }, + { "glUniform3f", (FuncType) glUniform3f }, + { "glUniform3fv", (FuncType) glUniform3fv }, + { "glUniform3i", (FuncType) glUniform3i }, + { "glUniform3iv", (FuncType) glUniform3iv }, + { "glUniform4f", (FuncType) glUniform4f }, + { "glUniform4fv", (FuncType) glUniform4fv }, + { "glUniform4i", (FuncType) glUniform4i }, + { "glUniform4iv", (FuncType) glUniform4iv }, + { "glUniformMatrix2fv", (FuncType) glUniformMatrix2fv }, + { "glUniformMatrix3fv", (FuncType) glUniformMatrix3fv }, + { "glUniformMatrix4fv", (FuncType) glUniformMatrix4fv }, + { "glUseProgram", (FuncType) glUseProgram }, + { "glValidateProgram", (FuncType) glValidateProgram }, + { "glVertexAttrib1f", (FuncType) glVertexAttrib1f }, + { "glVertexAttrib1fv", (FuncType) glVertexAttrib1fv }, + { "glVertexAttrib2f", (FuncType) glVertexAttrib2f }, + { "glVertexAttrib2fv", (FuncType) glVertexAttrib2fv }, + { "glVertexAttrib3f", (FuncType) glVertexAttrib3f }, + { "glVertexAttrib3fv", (FuncType) glVertexAttrib3fv }, + { "glVertexAttrib4f", (FuncType) glVertexAttrib4f }, + { "glVertexAttrib4fv", (FuncType) glVertexAttrib4fv }, + { "glVertexAttribPointer", (FuncType) glVertexAttribPointer } + }; + for (size_t i = 0; i < sizeof(tab) / sizeof(Tab); ++i) { + uint len = qstrlen(tab[i].name); + if (!qstrncmp(tab[i].name, procname, len) + && procname[len] == '\0') { + f = tab[i].func; + break; + } + } + if (!f) + qCDebug(qglLc, "eglGetProcAddress failed for %s", procname); + } + + return f; +} + +} // extern "C" + +// For QOpenGLFunctions +int qgl_proxyLibraryType(void) +{ + return qgl_choose()->libraryType(); +} + +HMODULE qgl_glHandle(void) +{ + return qgl_choose()->libraryHandle(); +} + +QAbstractWindowsOpenGL::QAbstractWindowsOpenGL() + : + CopyContext(0), + CreateContext(0), + CreateLayerContext(0), + DeleteContext(0), + GetCurrentContext(0), + GetCurrentDC(0), + GetProcAddress(0), + MakeCurrent(0), + ShareLists(0), + UseFontBitmapsW(0), + UseFontOutlinesW(0), + DescribeLayerPlane(0), + SetLayerPaletteEntries(0), + GetLayerPaletteEntries(0), + RealizeLayerPalette(0), + SwapLayerBuffers(0), + SwapMultipleBuffers(0), + + EGL_GetError(0), + EGL_GetDisplay(0), + EGL_Initialize(0), + EGL_Terminate(0), + EGL_QueryString(0), + EGL_GetConfigs(0), + EGL_ChooseConfig(0), + EGL_GetConfigAttrib(0), + EGL_CreateWindowSurface(0), + EGL_CreatePbufferSurface(0), + EGL_CreatePixmapSurface(0), + EGL_DestroySurface(0), + EGL_QuerySurface(0), + EGL_BindAPI(0), + EGL_QueryAPI(0), + EGL_WaitClient(0), + EGL_ReleaseThread(0), + EGL_CreatePbufferFromClientBuffer(0), + EGL_SurfaceAttrib(0), + EGL_BindTexImage(0), + EGL_ReleaseTexImage(0), + EGL_SwapInterval(0), + EGL_CreateContext(0), + EGL_DestroyContext(0), + EGL_MakeCurrent (0), + EGL_GetCurrentContext(0), + EGL_GetCurrentSurface(0), + EGL_GetCurrentDisplay(0), + EGL_QueryContext(0), + EGL_WaitGL(0), + EGL_WaitNative(0), + EGL_SwapBuffers(0), + EGL_CopyBuffers(0), + EGL_GetProcAddress(0), + + Viewport(0), + DepthRange(0), + IsEnabled(0), + GetTexLevelParameteriv(0), + GetTexLevelParameterfv(0), + GetTexParameteriv(0), + GetTexParameterfv(0), + GetTexImage(0), + GetString(0), + GetIntegerv(0), + GetFloatv(0), + GetError(0), + GetDoublev(0), + GetBooleanv(0), + ReadPixels(0), + ReadBuffer(0), + PixelStorei(0), + PixelStoref(0), + DepthFunc(0), + StencilOp(0), + StencilFunc(0), + LogicOp(0), + BlendFunc(0), + Flush(0), + Finish(0), + Enable(0), + Disable(0), + DepthMask(0), + ColorMask(0), + StencilMask(0), + ClearDepth(0), + ClearStencil(0), + ClearColor(0), + Clear(0), + DrawBuffer(0), + TexImage2D(0), + TexImage1D(0), + TexParameteriv(0), + TexParameteri(0), + TexParameterfv(0), + TexParameterf(0), + Scissor(0), + PolygonMode(0), + PointSize(0), + LineWidth(0), + Hint(0), + FrontFace(0), + CullFace(0), + + Translatef(0), + Translated(0), + Scalef(0), + Scaled(0), + Rotatef(0), + Rotated(0), + PushMatrix(0), + PopMatrix(0), + Ortho(0), + MultMatrixd(0), + MultMatrixf(0), + MatrixMode(0), + LoadMatrixd(0), + LoadMatrixf(0), + LoadIdentity(0), + Frustum(0), + IsList(0), + GetTexGeniv(0), + GetTexGenfv(0), + GetTexGendv(0), + GetTexEnviv(0), + GetTexEnvfv(0), + GetPolygonStipple(0), + GetPixelMapusv(0), + GetPixelMapuiv(0), + GetPixelMapfv(0), + GetMaterialiv(0), + GetMaterialfv(0), + GetMapiv(0), + GetMapfv(0), + GetMapdv(0), + GetLightiv(0), + GetLightfv(0), + GetClipPlane(0), + DrawPixels(0), + CopyPixels(0), + PixelMapusv(0), + PixelMapuiv(0), + PixelMapfv(0), + PixelTransferi(0), + PixelTransferf(0), + PixelZoom(0), + AlphaFunc(0), + EvalPoint2(0), + EvalMesh2(0), + EvalPoint1(0), + EvalMesh1(0), + EvalCoord2fv(0), + EvalCoord2f(0), + EvalCoord2dv(0), + EvalCoord2d(0), + EvalCoord1fv(0), + EvalCoord1f(0), + EvalCoord1dv(0), + EvalCoord1d(0), + MapGrid2f(0), + MapGrid2d(0), + MapGrid1f(0), + MapGrid1d(0), + Map2f(0), + Map2d(0), + Map1f(0), + Map1d(0), + PushAttrib(0), + PopAttrib(0), + Accum(0), + IndexMask(0), + ClearIndex(0), + ClearAccum(0), + PushName(0), + PopName(0), + PassThrough(0), + LoadName(0), + InitNames(0), + RenderMode(0), + SelectBuffer(0), + FeedbackBuffer(0), + TexGeniv(0), + TexGeni(0), + TexGenfv(0), + TexGenf(0), + TexGendv(0), + TexGend(0), + TexEnviv(0), + TexEnvi(0), + TexEnvfv(0), + TexEnvf(0), + ShadeModel(0), + PolygonStipple(0), + Materialiv(0), + Materiali(0), + Materialfv(0), + Materialf(0), + LineStipple(0), + LightModeliv(0), + LightModeli(0), + LightModelfv(0), + LightModelf(0), + Lightiv(0), + Lighti(0), + Lightfv(0), + Lightf(0), + Fogiv(0), + Fogi(0), + Fogfv(0), + Fogf(0), + ColorMaterial(0), + ClipPlane(0), + Vertex4sv(0), + Vertex4s(0), + Vertex4iv(0), + Vertex4i(0), + Vertex4fv(0), + Vertex4f(0), + Vertex4dv(0), + Vertex4d(0), + Vertex3sv(0), + Vertex3s(0), + Vertex3iv(0), + Vertex3i(0), + Vertex3fv(0), + Vertex3f(0), + Vertex3dv(0), + Vertex3d(0), + Vertex2sv(0), + Vertex2s(0), + Vertex2iv(0), + Vertex2i(0), + Vertex2fv(0), + Vertex2f(0), + Vertex2dv(0), + Vertex2d(0), + TexCoord4sv(0), + TexCoord4s(0), + TexCoord4iv(0), + TexCoord4i(0), + TexCoord4fv(0), + TexCoord4f(0), + TexCoord4dv(0), + TexCoord4d(0), + TexCoord3sv(0), + TexCoord3s(0), + TexCoord3iv(0), + TexCoord3i(0), + TexCoord3fv(0), + TexCoord3f(0), + TexCoord3dv(0), + TexCoord3d(0), + TexCoord2sv(0), + TexCoord2s(0), + TexCoord2iv(0), + TexCoord2i(0), + TexCoord2fv(0), + TexCoord2f(0), + TexCoord2dv(0), + TexCoord2d(0), + TexCoord1sv(0), + TexCoord1s(0), + TexCoord1iv(0), + TexCoord1i(0), + TexCoord1fv(0), + TexCoord1f(0), + TexCoord1dv(0), + TexCoord1d(0), + Rectsv(0), + Rects(0), + Rectiv(0), + Recti(0), + Rectfv(0), + Rectf(0), + Rectdv(0), + Rectd(0), + RasterPos4sv(0), + RasterPos4s(0), + RasterPos4iv(0), + RasterPos4i(0), + RasterPos4fv(0), + RasterPos4f(0), + RasterPos4dv(0), + RasterPos4d(0), + RasterPos3sv(0), + RasterPos3s(0), + RasterPos3iv(0), + RasterPos3i(0), + RasterPos3fv(0), + RasterPos3f(0), + RasterPos3dv(0), + RasterPos3d(0), + RasterPos2sv(0), + RasterPos2s(0), + RasterPos2iv(0), + RasterPos2i(0), + RasterPos2fv(0), + RasterPos2f(0), + RasterPos2dv(0), + RasterPos2d(0), + Normal3sv(0), + Normal3s(0), + Normal3iv(0), + Normal3i(0), + Normal3fv(0), + Normal3f(0), + Normal3dv(0), + Normal3d(0), + Normal3bv(0), + Normal3b(0), + Indexsv(0), + Indexs(0), + Indexiv(0), + Indexi(0), + Indexfv(0), + Indexf(0), + Indexdv(0), + Indexd(0), + End(0), + EdgeFlagv(0), + EdgeFlag(0), + Color4usv(0), + Color4us(0), + Color4uiv(0), + Color4ui(0), + Color4ubv(0), + Color4ub(0), + Color4sv(0), + Color4s(0), + Color4iv(0), + Color4i(0), + Color4fv(0), + Color4f(0), + Color4dv(0), + Color4d(0), + Color4bv(0), + Color4b(0), + Color3usv(0), + Color3us(0), + Color3uiv(0), + Color3ui(0), + Color3ubv(0), + Color3ub(0), + Color3sv(0), + Color3s(0), + Color3iv(0), + Color3i(0), + Color3fv(0), + Color3f(0), + Color3dv(0), + Color3d(0), + Color3bv(0), + Color3b(0), + Bitmap(0), + Begin(0), + ListBase(0), + GenLists(0), + DeleteLists(0), + CallLists(0), + CallList(0), + EndList(0), + NewList(0), + + Indexubv(0), + Indexub(0), + IsTexture(0), + GenTextures(0), + DeleteTextures(0), + BindTexture(0), + TexSubImage2D(0), + TexSubImage1D(0), + CopyTexSubImage2D(0), + CopyTexSubImage1D(0), + CopyTexImage2D(0), + CopyTexImage1D(0), + PolygonOffset(0), + GetPointerv(0), + DrawElements(0), + DrawArrays(0), + + PushClientAttrib(0), + PopClientAttrib(0), + PrioritizeTextures(0), + AreTexturesResident(0), + VertexPointer(0), + TexCoordPointer(0), + NormalPointer(0), + InterleavedArrays(0), + IndexPointer(0), + EnableClientState(0), + EdgeFlagPointer(0), + DisableClientState(0), + ColorPointer(0), + ArrayElement(0), + + ActiveTexture(0), + AttachShader(0), + BindAttribLocation(0), + BindBuffer(0), + BindFramebuffer(0), + BindRenderbuffer(0), + BlendColor(0), + BlendEquation(0), + BlendEquationSeparate(0), + BlendFuncSeparate(0), + BufferData(0), + BufferSubData(0), + CheckFramebufferStatus(0), + ClearDepthf(0), + CompileShader(0), + CompressedTexImage2D(0), + CompressedTexSubImage2D(0), + CreateProgram(0), + CreateShader(0), + DeleteBuffers(0), + DeleteFramebuffers(0), + DeleteProgram(0), + DeleteRenderbuffers(0), + DeleteShader(0), + DepthRangef(0), + DetachShader(0), + DisableVertexAttribArray(0), + EnableVertexAttribArray(0), + FramebufferRenderbuffer(0), + FramebufferTexture2D(0), + GenBuffers(0), + GenerateMipmap(0), + GenFramebuffers(0), + GenRenderbuffers(0), + GetActiveAttrib(0), + GetActiveUniform(0), + GetAttachedShaders(0), + GetAttribLocation(0), + GetBufferParameteriv(0), + GetFramebufferAttachmentParameteriv(0), + GetProgramiv(0), + GetProgramInfoLog(0), + GetRenderbufferParameteriv(0), + GetShaderiv(0), + GetShaderInfoLog(0), + GetShaderPrecisionFormat(0), + GetShaderSource(0), + GetUniformfv(0), + GetUniformiv(0), + GetUniformLocation(0), + GetVertexAttribfv(0), + GetVertexAttribiv(0), + GetVertexAttribPointerv(0), + IsBuffer(0), + IsFramebuffer(0), + IsProgram(0), + IsRenderbuffer(0), + IsShader(0), + LinkProgram(0), + ReleaseShaderCompiler(0), + RenderbufferStorage(0), + SampleCoverage(0), + ShaderBinary(0), + ShaderSource(0), + StencilFuncSeparate(0), + StencilMaskSeparate(0), + StencilOpSeparate(0), + Uniform1f(0), + Uniform1fv(0), + Uniform1i(0), + Uniform1iv(0), + Uniform2f(0), + Uniform2fv(0), + Uniform2i(0), + Uniform2iv(0), + Uniform3f(0), + Uniform3fv(0), + Uniform3i(0), + Uniform3iv(0), + Uniform4f(0), + Uniform4fv(0), + Uniform4i(0), + Uniform4iv(0), + UniformMatrix2fv(0), + UniformMatrix3fv(0), + UniformMatrix4fv(0), + UseProgram(0), + ValidateProgram(0), + VertexAttrib1f(0), + VertexAttrib1fv(0), + VertexAttrib2f(0), + VertexAttrib2fv(0), + VertexAttrib3f(0), + VertexAttrib3fv(0), + VertexAttrib4f(0), + VertexAttrib4fv(0), + VertexAttribPointer(0), + + m_lib(0), + m_libraryType(DesktopGL), + m_loaded(false) +{ +} diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp index ecc38b902c..06f40eafd0 100644 --- a/src/gui/opengl/qopenglshaderprogram.cpp +++ b/src/gui/opengl/qopenglshaderprogram.cpp @@ -175,13 +175,15 @@ public: #endif { #ifndef QT_OPENGL_ES_2 - QSurfaceFormat f = ctx->format(); - - // Geometry shaders require OpenGL >= 3.2 - if (shaderType & QOpenGLShader::Geometry) - supportsGeometryShaders = (f.version() >= qMakePair<int, int>(3, 2)); - else if (shaderType & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation)) - supportsTessellationShaders = (f.version() >= qMakePair<int, int>(4, 0)); + if (!QOpenGLFunctions::isES()) { + QSurfaceFormat f = ctx->format(); + + // Geometry shaders require OpenGL >= 3.2 + if (shaderType & QOpenGLShader::Geometry) + supportsGeometryShaders = (f.version() >= qMakePair<int, int>(3, 2)); + else if (shaderType & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation)) + supportsTessellationShaders = (f.version() >= qMakePair<int, int>(4, 0)); + } #endif } ~QOpenGLShaderPrivate(); @@ -441,7 +443,8 @@ bool QOpenGLShader::compileSourceCode(const char *source) } #ifdef QOpenGL_REDEFINE_HIGHP - if (d->shaderType == Fragment && !ctx_d->workaround_missingPrecisionQualifiers) { + if (d->shaderType == Fragment && !ctx_d->workaround_missingPrecisionQualifiers + && QOpenGLFunctions::isES()) { src.append(redefineHighp); srclen.append(GLint(sizeof(redefineHighp) - 1)); } @@ -650,7 +653,8 @@ bool QOpenGLShaderProgram::init() #ifndef QT_OPENGL_ES_2 // Resolve OpenGL 4 functions for tessellation shader support QSurfaceFormat format = context->format(); - if (format.version() >= qMakePair<int, int>(4, 0)) { + if (!QOpenGLFunctions::isES() + && format.version() >= qMakePair<int, int>(4, 0)) { d->tessellationFuncs = context->versionFunctions<QOpenGLFunctions_4_0_Core>(); d->tessellationFuncs->initializeOpenGLFunctions(); } @@ -3248,14 +3252,16 @@ bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context) #ifndef QT_OPENGL_ES_2 // Geometry shaders require OpenGL 3.2 or newer QSurfaceFormat format = context->format(); - return (format.version() >= qMakePair<int, int>(3, 2)); + return (!QOpenGLFunctions::isES()) + && (format.version() >= qMakePair<int, int>(3, 2)); #else // No geometry shader support in OpenGL ES2 return false; #endif } else if (type == TessellationControl || type == TessellationEvaluation) { #if !defined(QT_OPENGL_ES_2) - return (format.version() >= qMakePair<int, int>(4, 0)); + return (!QOpenGLFunctions::isES()) + && (format.version() >= qMakePair<int, int>(4, 0)); #else // No tessellation shader support in OpenGL ES2 return false; diff --git a/src/gui/opengl/qopengltexture.cpp b/src/gui/opengl/qopengltexture.cpp index d9b2e82d0b..8bdbdba6f7 100644 --- a/src/gui/opengl/qopengltexture.cpp +++ b/src/gui/opengl/qopengltexture.cpp @@ -319,42 +319,70 @@ void QOpenGLTexturePrivate::allocateMutableStorage() return; case QOpenGLTexture::Target1D: - for (int level = 0; level < mipLevels; ++level) - texFuncs->glTextureImage1D(textureId, target, level, format, - mipLevelSize(level, dimensions[0]), - 0, - QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, 0); + if (features.testFlag(QOpenGLTexture::Texture1D)) { + for (int level = 0; level < mipLevels; ++level) + texFuncs->glTextureImage1D(textureId, target, bindingTarget, level, format, + mipLevelSize(level, dimensions[0]), + 0, + QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, 0); + } else { + qWarning("1D textures are not supported"); + return; + } break; case QOpenGLTexture::Target1DArray: - if (features.testFlag(QOpenGLTexture::TextureArrays)) { + if (features.testFlag(QOpenGLTexture::Texture1D) + && features.testFlag(QOpenGLTexture::TextureArrays)) { for (int level = 0; level < mipLevels; ++level) - texFuncs->glTextureImage2D(textureId, target, level, format, + texFuncs->glTextureImage2D(textureId, target, bindingTarget, level, format, mipLevelSize(level, dimensions[0]), layers, 0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, 0); } else { - qWarning("Array textures are not supported"); + qWarning("1D array textures are not supported"); return; } break; case QOpenGLTexture::Target2D: - case QOpenGLTexture::TargetCubeMap: case QOpenGLTexture::TargetRectangle: for (int level = 0; level < mipLevels; ++level) - texFuncs->glTextureImage2D(textureId, target, level, format, + texFuncs->glTextureImage2D(textureId, target, bindingTarget, level, format, mipLevelSize(level, dimensions[0]), mipLevelSize(level, dimensions[1]), 0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, 0); break; + case QOpenGLTexture::TargetCubeMap: { + // Cubemaps are the odd one out. We have to allocate storage for each + // face and miplevel using the special cubemap face targets rather than + // GL_TARGET_CUBEMAP. + const QOpenGLTexture::CubeMapFace faceTargets[] = { + QOpenGLTexture::CubeMapPositiveX, QOpenGLTexture::CubeMapNegativeX, + QOpenGLTexture::CubeMapPositiveY, QOpenGLTexture::CubeMapNegativeY, + QOpenGLTexture::CubeMapPositiveZ, QOpenGLTexture::CubeMapNegativeZ + }; + + for (int faceTarget = 0; faceTarget < 6; ++faceTarget) { + for (int level = 0; level < mipLevels; ++level) { + texFuncs->glTextureImage2D(textureId, faceTargets[faceTarget], bindingTarget, + level, format, + mipLevelSize(level, dimensions[0]), + mipLevelSize(level, dimensions[1]), + 0, + QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, 0); + } + } + break; + } + case QOpenGLTexture::Target2DArray: if (features.testFlag(QOpenGLTexture::TextureArrays)) { for (int level = 0; level < mipLevels; ++level) - texFuncs->glTextureImage3D(textureId, target, level, format, + texFuncs->glTextureImage3D(textureId, target, bindingTarget, level, format, mipLevelSize(level, dimensions[0]), mipLevelSize(level, dimensions[1]), layers, @@ -370,7 +398,7 @@ void QOpenGLTexturePrivate::allocateMutableStorage() // Cubemap arrays must specify number of layer-faces (6 * layers) as depth parameter if (features.testFlag(QOpenGLTexture::TextureCubeMapArrays)) { for (int level = 0; level < mipLevels; ++level) - texFuncs->glTextureImage3D(textureId, target, level, format, + texFuncs->glTextureImage3D(textureId, target, bindingTarget, level, format, mipLevelSize(level, dimensions[0]), mipLevelSize(level, dimensions[1]), 6 * layers, @@ -385,7 +413,7 @@ void QOpenGLTexturePrivate::allocateMutableStorage() case QOpenGLTexture::Target3D: if (features.testFlag(QOpenGLTexture::Texture3D)) { for (int level = 0; level < mipLevels; ++level) - texFuncs->glTextureImage3D(textureId, target, level, format, + texFuncs->glTextureImage3D(textureId, target, bindingTarget, level, format, mipLevelSize(level, dimensions[0]), mipLevelSize(level, dimensions[1]), mipLevelSize(level, dimensions[2]), @@ -399,7 +427,7 @@ void QOpenGLTexturePrivate::allocateMutableStorage() case QOpenGLTexture::Target2DMultisample: if (features.testFlag(QOpenGLTexture::TextureMultisample)) { - texFuncs->glTextureImage2DMultisample(textureId, target, samples, format, + texFuncs->glTextureImage2DMultisample(textureId, target, bindingTarget, samples, format, dimensions[0], dimensions[1], fixedSamplePositions); } else { @@ -411,7 +439,7 @@ void QOpenGLTexturePrivate::allocateMutableStorage() case QOpenGLTexture::Target2DMultisampleArray: if (features.testFlag(QOpenGLTexture::TextureMultisample) && features.testFlag(QOpenGLTexture::TextureArrays)) { - texFuncs->glTextureImage3DMultisample(textureId, target, samples, format, + texFuncs->glTextureImage3DMultisample(textureId, target, bindingTarget, samples, format, dimensions[0], dimensions[1], layers, fixedSamplePositions); } else { @@ -433,16 +461,22 @@ void QOpenGLTexturePrivate::allocateImmutableStorage() return; case QOpenGLTexture::Target1D: - texFuncs->glTextureStorage1D(textureId, target, mipLevels, format, - dimensions[0]); + if (features.testFlag(QOpenGLTexture::Texture1D)) { + texFuncs->glTextureStorage1D(textureId, target, bindingTarget, mipLevels, format, + dimensions[0]); + } else { + qWarning("1D textures are not supported"); + return; + } break; case QOpenGLTexture::Target1DArray: - if (features.testFlag(QOpenGLTexture::TextureArrays)) { - texFuncs->glTextureStorage2D(textureId, target, mipLevels, format, + if (features.testFlag(QOpenGLTexture::Texture1D) + && features.testFlag(QOpenGLTexture::TextureArrays)) { + texFuncs->glTextureStorage2D(textureId, target, bindingTarget, mipLevels, format, dimensions[0], layers); } else { - qWarning("Array textures are not supported"); + qWarning("1D array textures are not supported"); return; } break; @@ -450,13 +484,13 @@ void QOpenGLTexturePrivate::allocateImmutableStorage() case QOpenGLTexture::Target2D: case QOpenGLTexture::TargetCubeMap: case QOpenGLTexture::TargetRectangle: - texFuncs->glTextureStorage2D(textureId, target, mipLevels, format, + texFuncs->glTextureStorage2D(textureId, target, bindingTarget, mipLevels, format, dimensions[0], dimensions[1]); break; case QOpenGLTexture::Target2DArray: if (features.testFlag(QOpenGLTexture::TextureArrays)) { - texFuncs->glTextureStorage3D(textureId, target, mipLevels, format, + texFuncs->glTextureStorage3D(textureId, target, bindingTarget, mipLevels, format, dimensions[0], dimensions[1], layers); } else { qWarning("Array textures are not supported"); @@ -467,7 +501,7 @@ void QOpenGLTexturePrivate::allocateImmutableStorage() case QOpenGLTexture::TargetCubeMapArray: // Cubemap arrays must specify number of layer-faces (6 * layers) as depth parameter if (features.testFlag(QOpenGLTexture::TextureCubeMapArrays)) { - texFuncs->glTextureStorage3D(textureId, target, mipLevels, format, + texFuncs->glTextureStorage3D(textureId, target, bindingTarget, mipLevels, format, dimensions[0], dimensions[1], 6 * layers); } else { qWarning("Cubemap Array textures are not supported"); @@ -477,7 +511,7 @@ void QOpenGLTexturePrivate::allocateImmutableStorage() case QOpenGLTexture::Target3D: if (features.testFlag(QOpenGLTexture::Texture3D)) { - texFuncs->glTextureStorage3D(textureId, target, mipLevels, format, + texFuncs->glTextureStorage3D(textureId, target, bindingTarget, mipLevels, format, dimensions[0], dimensions[1], dimensions[2]); } else { qWarning("3D textures are not supported"); @@ -487,7 +521,7 @@ void QOpenGLTexturePrivate::allocateImmutableStorage() case QOpenGLTexture::Target2DMultisample: if (features.testFlag(QOpenGLTexture::TextureMultisample)) { - texFuncs->glTextureStorage2DMultisample(textureId, target, samples, format, + texFuncs->glTextureStorage2DMultisample(textureId, target, bindingTarget, samples, format, dimensions[0], dimensions[1], fixedSamplePositions); } else { @@ -499,7 +533,7 @@ void QOpenGLTexturePrivate::allocateImmutableStorage() case QOpenGLTexture::Target2DMultisampleArray: if (features.testFlag(QOpenGLTexture::TextureMultisample) && features.testFlag(QOpenGLTexture::TextureArrays)) { - texFuncs->glTextureStorage3DMultisample(textureId, target, samples, format, + texFuncs->glTextureStorage3DMultisample(textureId, target, bindingTarget, samples, format, dimensions[0], dimensions[1], layers, fixedSamplePositions); } else { @@ -514,20 +548,20 @@ void QOpenGLTexturePrivate::allocateImmutableStorage() void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::CubeMapFace cubeFace, QOpenGLTexture::PixelFormat sourceFormat, QOpenGLTexture::PixelType sourceType, - void *data, const QOpenGLPixelTransferOptions * const options) + const void *data, const QOpenGLPixelTransferOptions * const options) { switch (target) { case QOpenGLTexture::Target1D: Q_UNUSED(layer); Q_UNUSED(cubeFace); - texFuncs->glTextureSubImage1D(textureId, target, mipLevel, + texFuncs->glTextureSubImage1D(textureId, target, bindingTarget, mipLevel, 0, mipLevelSize( mipLevel, dimensions[0] ), sourceFormat, sourceType, data, options); break; case QOpenGLTexture::Target1DArray: Q_UNUSED(cubeFace); - texFuncs->glTextureSubImage2D(textureId, target, mipLevel, + texFuncs->glTextureSubImage2D(textureId, target, bindingTarget, mipLevel, 0, layer, mipLevelSize(mipLevel, dimensions[0]), 1, @@ -536,7 +570,7 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub case QOpenGLTexture::Target2D: Q_UNUSED(layer); Q_UNUSED(cubeFace); - texFuncs->glTextureSubImage2D(textureId, target, mipLevel, + texFuncs->glTextureSubImage2D(textureId, target, bindingTarget, mipLevel, 0, 0, mipLevelSize(mipLevel, dimensions[0]), mipLevelSize(mipLevel, dimensions[1]), @@ -545,7 +579,7 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub case QOpenGLTexture::Target2DArray: Q_UNUSED(cubeFace); - texFuncs->glTextureSubImage3D(textureId, target, mipLevel, + texFuncs->glTextureSubImage3D(textureId, target, bindingTarget, mipLevel, 0, 0, layer, mipLevelSize(mipLevel, dimensions[0]), mipLevelSize(mipLevel, dimensions[1]), @@ -555,7 +589,7 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub case QOpenGLTexture::Target3D: Q_UNUSED(cubeFace); - texFuncs->glTextureSubImage3D(textureId, target, mipLevel, + texFuncs->glTextureSubImage3D(textureId, target, bindingTarget, mipLevel, 0, 0, layer, mipLevelSize(mipLevel, dimensions[0]), mipLevelSize(mipLevel, dimensions[1]), @@ -565,7 +599,7 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub case QOpenGLTexture::TargetCubeMap: Q_UNUSED(layer); - texFuncs->glTextureSubImage2D(textureId, cubeFace, mipLevel, + texFuncs->glTextureSubImage2D(textureId, cubeFace, bindingTarget, mipLevel, 0, 0, mipLevelSize(mipLevel, dimensions[0]), mipLevelSize(mipLevel, dimensions[1]), @@ -575,7 +609,7 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub case QOpenGLTexture::TargetCubeMapArray: { int faceIndex = cubeFace - QOpenGLTexture::CubeMapPositiveX; int layerFace = 6 * layer + faceIndex; - texFuncs->glTextureSubImage3D(textureId, target, mipLevel, + texFuncs->glTextureSubImage3D(textureId, target, bindingTarget, mipLevel, 0, 0, layerFace, mipLevelSize(mipLevel, dimensions[0]), mipLevelSize(mipLevel, dimensions[1]), @@ -588,7 +622,7 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub Q_UNUSED(mipLevel); Q_UNUSED(layer); Q_UNUSED(cubeFace); - texFuncs->glTextureSubImage2D(textureId, target, 0, + texFuncs->glTextureSubImage2D(textureId, target, bindingTarget, 0, 0, 0, dimensions[0], dimensions[1], @@ -611,21 +645,21 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub } void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTexture::CubeMapFace cubeFace, - int dataSize, void *data, + int dataSize, const void *data, const QOpenGLPixelTransferOptions * const options) { switch (target) { case QOpenGLTexture::Target1D: Q_UNUSED(layer); Q_UNUSED(cubeFace); - texFuncs->glCompressedTextureSubImage1D(textureId, target, mipLevel, + texFuncs->glCompressedTextureSubImage1D(textureId, target, bindingTarget, mipLevel, 0, mipLevelSize( mipLevel, dimensions[0] ), format, dataSize, data, options); break; case QOpenGLTexture::Target1DArray: Q_UNUSED(cubeFace); - texFuncs->glCompressedTextureSubImage2D(textureId, target, mipLevel, + texFuncs->glCompressedTextureSubImage2D(textureId, target, bindingTarget, mipLevel, 0, layer, mipLevelSize(mipLevel, dimensions[0]), 1, @@ -634,7 +668,7 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe case QOpenGLTexture::Target2D: Q_UNUSED(layer); Q_UNUSED(cubeFace); - texFuncs->glCompressedTextureSubImage2D(textureId, target, mipLevel, + texFuncs->glCompressedTextureSubImage2D(textureId, target, bindingTarget, mipLevel, 0, 0, mipLevelSize(mipLevel, dimensions[0]), mipLevelSize(mipLevel, dimensions[1]), @@ -643,7 +677,7 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe case QOpenGLTexture::Target2DArray: Q_UNUSED(cubeFace); - texFuncs->glCompressedTextureSubImage3D(textureId, target, mipLevel, + texFuncs->glCompressedTextureSubImage3D(textureId, target, bindingTarget, mipLevel, 0, 0, layer, mipLevelSize(mipLevel, dimensions[0]), mipLevelSize(mipLevel, dimensions[1]), @@ -653,7 +687,7 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe case QOpenGLTexture::Target3D: Q_UNUSED(cubeFace); - texFuncs->glCompressedTextureSubImage3D(textureId, target, mipLevel, + texFuncs->glCompressedTextureSubImage3D(textureId, target, bindingTarget, mipLevel, 0, 0, layer, mipLevelSize(mipLevel, dimensions[0]), mipLevelSize(mipLevel, dimensions[1]), @@ -663,7 +697,7 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe case QOpenGLTexture::TargetCubeMap: Q_UNUSED(layer); - texFuncs->glCompressedTextureSubImage2D(textureId, cubeFace, mipLevel, + texFuncs->glCompressedTextureSubImage2D(textureId, cubeFace, bindingTarget, mipLevel, 0, 0, mipLevelSize(mipLevel, dimensions[0]), mipLevelSize(mipLevel, dimensions[1]), @@ -673,7 +707,7 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe case QOpenGLTexture::TargetCubeMapArray: { int faceIndex = cubeFace - QOpenGLTexture::CubeMapPositiveX; int layerFace = 6 * layer + faceIndex; - texFuncs->glCompressedTextureSubImage3D(textureId, target, mipLevel, + texFuncs->glCompressedTextureSubImage3D(textureId, target, bindingTarget, mipLevel, 0, 0, layerFace, mipLevelSize(mipLevel, dimensions[0]), mipLevelSize(mipLevel, dimensions[1]), @@ -686,7 +720,7 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe Q_UNUSED(mipLevel); Q_UNUSED(layer); Q_UNUSED(cubeFace); - texFuncs->glCompressedTextureSubImage2D(textureId, target, 0, + texFuncs->glCompressedTextureSubImage2D(textureId, target, bindingTarget, 0, 0, 0, dimensions[0], dimensions[1], @@ -715,7 +749,7 @@ void QOpenGLTexturePrivate::setWrapMode(QOpenGLTexture::WrapMode mode) case QOpenGLTexture::Target1DArray: case QOpenGLTexture::TargetBuffer: wrapModes[0] = mode; - texFuncs->glTextureParameteri(textureId, target, GL_TEXTURE_WRAP_S, mode); + texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_S, mode); break; case QOpenGLTexture::Target2D: @@ -726,15 +760,15 @@ void QOpenGLTexturePrivate::setWrapMode(QOpenGLTexture::WrapMode mode) case QOpenGLTexture::Target2DMultisampleArray: case QOpenGLTexture::TargetRectangle: wrapModes[0] = wrapModes[1] = mode; - texFuncs->glTextureParameteri(textureId, target, GL_TEXTURE_WRAP_S, mode); - texFuncs->glTextureParameteri(textureId, target, GL_TEXTURE_WRAP_T, mode); + texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_S, mode); + texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_T, mode); break; case QOpenGLTexture::Target3D: wrapModes[0] = wrapModes[1] = wrapModes[2] = mode; - texFuncs->glTextureParameteri(textureId, target, GL_TEXTURE_WRAP_S, mode); - texFuncs->glTextureParameteri(textureId, target, GL_TEXTURE_WRAP_T, mode); - texFuncs->glTextureParameteri(textureId, target, GL_TEXTURE_WRAP_R, mode); + texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_S, mode); + texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_T, mode); + texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_R, mode); break; } } @@ -748,7 +782,7 @@ void QOpenGLTexturePrivate::setWrapMode(QOpenGLTexture::CoordinateDirection dire switch (direction) { case QOpenGLTexture::DirectionS: wrapModes[0] = mode; - texFuncs->glTextureParameteri(textureId, target, GL_TEXTURE_WRAP_S, mode); + texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_S, mode); break; case QOpenGLTexture::DirectionT: @@ -768,12 +802,12 @@ void QOpenGLTexturePrivate::setWrapMode(QOpenGLTexture::CoordinateDirection dire switch (direction) { case QOpenGLTexture::DirectionS: wrapModes[0] = mode; - texFuncs->glTextureParameteri(textureId, target, GL_TEXTURE_WRAP_S, mode); + texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_S, mode); break; case QOpenGLTexture::DirectionT: wrapModes[1] = mode; - texFuncs->glTextureParameteri(textureId, target, GL_TEXTURE_WRAP_T, mode); + texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_T, mode); break; case QOpenGLTexture::DirectionR: @@ -786,17 +820,17 @@ void QOpenGLTexturePrivate::setWrapMode(QOpenGLTexture::CoordinateDirection dire switch (direction) { case QOpenGLTexture::DirectionS: wrapModes[0] = mode; - texFuncs->glTextureParameteri(textureId, target, direction, mode); + texFuncs->glTextureParameteri(textureId, target, bindingTarget, direction, mode); break; case QOpenGLTexture::DirectionT: wrapModes[1] = mode; - texFuncs->glTextureParameteri(textureId, target, direction, mode); + texFuncs->glTextureParameteri(textureId, target, bindingTarget, direction, mode); break; case QOpenGLTexture::DirectionR: wrapModes[2] = mode; - texFuncs->glTextureParameteri(textureId, target, direction, mode); + texFuncs->glTextureParameteri(textureId, target, bindingTarget, direction, mode); break; } break; @@ -1367,6 +1401,7 @@ QOpenGLTexture *QOpenGLTexturePrivate::createTextureView(QOpenGLTexture::Target \value NPOTTextures Basic support for non-power-of-two textures \value NPOTTextureRepeat Full support for non-power-of-two textures including texture repeat modes + \value Texture1D Support for the 1 dimensional texture target */ /*! @@ -2135,6 +2170,65 @@ bool QOpenGLTexture::isTextureView() const If using a compressed format() then you should use setCompressedData() instead of this function. + \since 5.3 + \sa setCompressedData() +*/ +void QOpenGLTexture::setData(int mipLevel, int layer, CubeMapFace cubeFace, + PixelFormat sourceFormat, PixelType sourceType, + const void *data, const QOpenGLPixelTransferOptions * const options) +{ + Q_D(QOpenGLTexture); + 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"); + return; + } + d->setData(mipLevel, layer, cubeFace, sourceFormat, sourceType, data, options); +} + +/*! + \since 5.3 + \overload +*/ +void QOpenGLTexture::setData(int mipLevel, int layer, + PixelFormat sourceFormat, PixelType sourceType, + const void *data, const QOpenGLPixelTransferOptions * const options) +{ + Q_D(QOpenGLTexture); + Q_ASSERT(d->textureId); + d->setData(mipLevel, layer, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); +} + +/*! + \since 5.3 + \overload +*/ +void QOpenGLTexture::setData(int mipLevel, + PixelFormat sourceFormat, PixelType sourceType, + const void *data, const QOpenGLPixelTransferOptions * const options) +{ + Q_D(QOpenGLTexture); + Q_ASSERT(d->textureId); + d->setData(mipLevel, 0, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); +} + +/*! + \since 5.3 + \overload +*/ +void QOpenGLTexture::setData(PixelFormat sourceFormat, PixelType sourceType, + const void *data, const QOpenGLPixelTransferOptions * const options) +{ + Q_D(QOpenGLTexture); + Q_ASSERT(d->textureId); + d->setData(0, 0, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); +} + +/*! + \obsolete + \overload + \sa setCompressedData() */ void QOpenGLTexture::setData(int mipLevel, int layer, CubeMapFace cubeFace, @@ -2152,6 +2246,7 @@ void QOpenGLTexture::setData(int mipLevel, int layer, CubeMapFace cubeFace, } /*! + \obsolete \overload */ void QOpenGLTexture::setData(int mipLevel, int layer, @@ -2164,6 +2259,7 @@ void QOpenGLTexture::setData(int mipLevel, int layer, } /*! + \obsolete \overload */ void QOpenGLTexture::setData(int mipLevel, @@ -2176,6 +2272,7 @@ void QOpenGLTexture::setData(int mipLevel, } /*! + \obsolete \overload */ void QOpenGLTexture::setData(PixelFormat sourceFormat, PixelType sourceType, @@ -2202,7 +2299,7 @@ void QOpenGLTexture::setData(const QImage& image, MipMapGeneration genMipMaps) QImage glImage = image.convertToFormat(QImage::Format_RGBA8888); QOpenGLPixelTransferOptions uploadOptions; uploadOptions.setAlignment(1); - setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, glImage.bits(), &uploadOptions); + setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, glImage.constBits(), &uploadOptions); } /*! @@ -2212,6 +2309,59 @@ void QOpenGLTexture::setData(const QImage& image, MipMapGeneration genMipMaps) If not using a compressed format() then you should use setData() instead of this function. + + \since 5.3 +*/ +void QOpenGLTexture::setCompressedData(int mipLevel, int layer, CubeMapFace cubeFace, + int dataSize, const void *data, + const QOpenGLPixelTransferOptions * const options) +{ + Q_D(QOpenGLTexture); + 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"); + return; + } + d->setCompressedData(mipLevel, layer, cubeFace, dataSize, data, options); +} + +/*! + \overload +*/ +void QOpenGLTexture::setCompressedData(int mipLevel, int layer, int dataSize, const void *data, + const QOpenGLPixelTransferOptions * const options) +{ + Q_D(QOpenGLTexture); + Q_ASSERT(d->textureId); + d->setCompressedData(mipLevel, layer, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); +} + +/*! + \overload +*/ +void QOpenGLTexture::setCompressedData(int mipLevel, int dataSize, const void *data, + const QOpenGLPixelTransferOptions * const options) +{ + Q_D(QOpenGLTexture); + Q_ASSERT(d->textureId); + d->setCompressedData(mipLevel, 0, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); +} + +/*! + \overload +*/ +void QOpenGLTexture::setCompressedData(int dataSize, const void *data, + const QOpenGLPixelTransferOptions * const options) +{ + Q_D(QOpenGLTexture); + Q_ASSERT(d->textureId); + d->setCompressedData(0, 0, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); +} + +/*! + \obsolete + \overload */ void QOpenGLTexture::setCompressedData(int mipLevel, int layer, CubeMapFace cubeFace, int dataSize, void *data, @@ -2228,6 +2378,7 @@ void QOpenGLTexture::setCompressedData(int mipLevel, int layer, CubeMapFace cube } /*! + \obsolete \overload */ void QOpenGLTexture::setCompressedData(int mipLevel, int layer, int dataSize, void *data, @@ -2239,6 +2390,7 @@ void QOpenGLTexture::setCompressedData(int mipLevel, int layer, int dataSize, vo } /*! + \obsolete \overload */ void QOpenGLTexture::setCompressedData(int mipLevel, int dataSize, void *data, @@ -2250,6 +2402,7 @@ void QOpenGLTexture::setCompressedData(int mipLevel, int dataSize, void *data, } /*! + \obsolete \overload */ void QOpenGLTexture::setCompressedData(int dataSize, void *data, @@ -2275,74 +2428,87 @@ bool QOpenGLTexture::hasFeature(Feature feature) QSurfaceFormat f = ctx->format(); bool supported = false; - switch (feature) { + #if !defined(QT_OPENGL_ES_2) - case ImmutableMultisampleStorage: - case TextureBuffer: - case StencilTexturing: - supported = f.version() >= qMakePair(4, 3); - break; + if (!QOpenGLFunctions::isES()) { + switch (feature) { + case ImmutableMultisampleStorage: + case TextureBuffer: + case StencilTexturing: + supported = f.version() >= qMakePair(4, 3); + break; - case ImmutableStorage: - supported = f.version() >= qMakePair(4, 2); - break; + case ImmutableStorage: + supported = f.version() >= qMakePair(4, 2); + break; - case TextureCubeMapArrays: - supported = f.version() >= qMakePair(4, 0); - break; + case TextureCubeMapArrays: + supported = f.version() >= qMakePair(4, 0); + break; - case Swizzle: - supported = f.version() >= qMakePair(3, 3); - break; + case Swizzle: + supported = f.version() >= qMakePair(3, 3); + break; - case TextureMultisample: - supported = f.version() >= qMakePair(3, 2); - break; + case TextureMultisample: + supported = f.version() >= qMakePair(3, 2); + break; - case TextureArrays: - supported = f.version() >= qMakePair(3, 0); - break; + case TextureArrays: + supported = f.version() >= qMakePair(3, 0); + break; - case TextureRectangle: - supported = f.version() >= qMakePair(2, 1); - break; + case TextureRectangle: + supported = f.version() >= qMakePair(2, 1); + break; - case Texture3D: - supported = f.version() >= qMakePair(1, 3); - break; + case Texture3D: + supported = f.version() >= qMakePair(1, 3); + break; - case AnisotropicFiltering: - supported = ctx->hasExtension(QByteArrayLiteral("GL_EXT_texture_filter_anisotropic")); - break; + case AnisotropicFiltering: + supported = ctx->hasExtension(QByteArrayLiteral("GL_EXT_texture_filter_anisotropic")); + break; - case NPOTTextures: - case NPOTTextureRepeat: - supported = ctx->hasExtension(QByteArrayLiteral("GL_ARB_texture_non_power_of_two")); - break; + case NPOTTextures: + case NPOTTextureRepeat: + supported = ctx->hasExtension(QByteArrayLiteral("GL_ARB_texture_non_power_of_two")); + break; - case MaxFeatureFlag: - break; - } + case Texture1D: + supported = f.version() >= qMakePair(1, 1); + break; -#else - case Texture3D: - supported = ctx->hasExtension(QByteArrayLiteral("GL_OES_texture_3D")); - 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")); + case MaxFeatureFlag: + break; + + default: + break; } - default: - break; } + + if (QOpenGLFunctions::isES()) #endif + { + switch (feature) { + case Texture3D: + supported = ctx->hasExtension(QByteArrayLiteral("GL_OES_texture_3D")); + 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: + break; + } + } return supported; } @@ -2356,17 +2522,20 @@ bool QOpenGLTexture::hasFeature(Feature feature) void QOpenGLTexture::setMipBaseLevel(int baseLevel) { #if !defined(QT_OPENGL_ES_2) - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->textureId); - Q_ASSERT(d->texFuncs); - Q_ASSERT(baseLevel <= d->maxLevel); - d->baseLevel = baseLevel; - d->texFuncs->glTextureParameteri(d->textureId, d->target, GL_TEXTURE_BASE_LEVEL, baseLevel); + if (!QOpenGLFunctions::isES()) { + Q_D(QOpenGLTexture); + d->create(); + Q_ASSERT(d->textureId); + Q_ASSERT(d->texFuncs); + Q_ASSERT(baseLevel <= d->maxLevel); + d->baseLevel = baseLevel; + d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_BASE_LEVEL, baseLevel); + return; + } #else Q_UNUSED(baseLevel); - qWarning("QOpenGLTexture: Mipmap base level is not supported"); #endif + qWarning("QOpenGLTexture: Mipmap base level is not supported"); } /*! @@ -2390,17 +2559,20 @@ int QOpenGLTexture::mipBaseLevel() const void QOpenGLTexture::setMipMaxLevel(int maxLevel) { #if !defined(QT_OPENGL_ES_2) - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->textureId); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->baseLevel <= maxLevel); - d->maxLevel = maxLevel; - d->texFuncs->glTextureParameteri(d->textureId, d->target, GL_TEXTURE_MAX_LEVEL, maxLevel); + if (!QOpenGLFunctions::isES()) { + Q_D(QOpenGLTexture); + d->create(); + Q_ASSERT(d->textureId); + Q_ASSERT(d->texFuncs); + Q_ASSERT(d->baseLevel <= maxLevel); + d->maxLevel = maxLevel; + d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MAX_LEVEL, maxLevel); + return; + } #else Q_UNUSED(maxLevel); - qWarning("QOpenGLTexture: Mipmap max level is not supported"); #endif + qWarning("QOpenGLTexture: Mipmap max level is not supported"); } /*! @@ -2424,18 +2596,21 @@ int QOpenGLTexture::mipMaxLevel() const void QOpenGLTexture::setMipLevelRange(int baseLevel, int maxLevel) { #if !defined(QT_OPENGL_ES_2) - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->textureId); - Q_ASSERT(d->texFuncs); - Q_ASSERT(baseLevel <= maxLevel); - d->texFuncs->glTextureParameteri(d->textureId, d->target, GL_TEXTURE_BASE_LEVEL, baseLevel); - d->texFuncs->glTextureParameteri(d->textureId, d->target, GL_TEXTURE_MAX_LEVEL, maxLevel); + if (!QOpenGLFunctions::isES()) { + Q_D(QOpenGLTexture); + d->create(); + Q_ASSERT(d->textureId); + Q_ASSERT(d->texFuncs); + Q_ASSERT(baseLevel <= maxLevel); + d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_BASE_LEVEL, baseLevel); + d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MAX_LEVEL, maxLevel); + return; + } #else Q_UNUSED(baseLevel); Q_UNUSED(maxLevel); - qWarning("QOpenGLTexture: Mipmap level range is not supported"); #endif + qWarning("QOpenGLTexture: Mipmap level range is not supported"); } /*! @@ -2487,7 +2662,7 @@ void QOpenGLTexture::generateMipMaps() Q_D(QOpenGLTexture); Q_ASSERT(d->texFuncs); Q_ASSERT(d->textureId); - d->texFuncs->glGenerateTextureMipmap(d->textureId, d->target); + d->texFuncs->glGenerateTextureMipmap(d->textureId, d->target, d->bindingTarget); } /*! @@ -2511,7 +2686,7 @@ void QOpenGLTexture::generateMipMaps(int baseLevel, bool resetBaseLevel) if (resetBaseLevel) oldBaseLevel = mipBaseLevel(); setMipBaseLevel(baseLevel); - d->texFuncs->glGenerateTextureMipmap(d->textureId, d->target); + d->texFuncs->glGenerateTextureMipmap(d->textureId, d->target, d->bindingTarget); if (resetBaseLevel) setMipBaseLevel(oldBaseLevel); } @@ -2531,21 +2706,24 @@ void QOpenGLTexture::generateMipMaps(int baseLevel, bool resetBaseLevel) void QOpenGLTexture::setSwizzleMask(SwizzleComponent component, SwizzleValue value) { #if !defined(Q_OS_MAC) && !defined(QT_OPENGL_ES_2) - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - if (!d->features.testFlag(Swizzle)) { - qWarning("QOpenGLTexture::setSwizzleMask() requires OpenGL >= 3.3"); + if (!QOpenGLFunctions::isES()) { + Q_D(QOpenGLTexture); + d->create(); + Q_ASSERT(d->texFuncs); + Q_ASSERT(d->textureId); + if (!d->features.testFlag(Swizzle)) { + qWarning("QOpenGLTexture::setSwizzleMask() requires OpenGL >= 3.3"); + return; + } + d->swizzleMask[component - SwizzleRed] = value; + d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, component, value); return; } - d->swizzleMask[component - SwizzleRed] = value; - d->texFuncs->glTextureParameteri(d->textureId, d->target, component, value); #else Q_UNUSED(component); Q_UNUSED(value); - qWarning("QOpenGLTexture: Texture swizzling is not supported"); #endif + qWarning("QOpenGLTexture: Texture swizzling is not supported"); } /*! @@ -2555,27 +2733,30 @@ void QOpenGLTexture::setSwizzleMask(SwizzleValue r, SwizzleValue g, SwizzleValue b, SwizzleValue a) { #if !defined(Q_OS_MAC) && !defined(QT_OPENGL_ES_2) - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - if (!d->features.testFlag(Swizzle)) { - qWarning("QOpenGLTexture::setSwizzleMask() requires OpenGL >= 3.3"); + if (!QOpenGLFunctions::isES()) { + Q_D(QOpenGLTexture); + d->create(); + Q_ASSERT(d->texFuncs); + Q_ASSERT(d->textureId); + if (!d->features.testFlag(Swizzle)) { + qWarning("QOpenGLTexture::setSwizzleMask() requires OpenGL >= 3.3"); + return; + } + GLint swizzleMask[] = {GLint(r), GLint(g), GLint(b), GLint(a)}; + d->swizzleMask[0] = r; + d->swizzleMask[1] = g; + d->swizzleMask[2] = b; + d->swizzleMask[3] = a; + d->texFuncs->glTextureParameteriv(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); return; } - GLint swizzleMask[] = {GLint(r), GLint(g), GLint(b), GLint(a)}; - d->swizzleMask[0] = r; - d->swizzleMask[1] = g; - d->swizzleMask[2] = b; - d->swizzleMask[3] = a; - d->texFuncs->glTextureParameteriv(d->textureId, d->target, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); #else Q_UNUSED(r); Q_UNUSED(g); Q_UNUSED(b); Q_UNUSED(a); - qWarning("QOpenGLTexture: Texture swizzling is not supported"); #endif + qWarning("QOpenGLTexture: Texture swizzling is not supported"); } /*! @@ -2591,9 +2772,9 @@ QOpenGLTexture::SwizzleValue QOpenGLTexture::swizzleMask(SwizzleComponent compon If using a texture that has a combined depth/stencil format this function sets which component of the texture is accessed to \a mode. - When the parameter is set to ?DepthMode, then accessing it from the + When the parameter is set to DepthMode, then accessing it from the shader will access the depth component as a single float, as normal. But when - the parameter is set to StencilMode?, the shader will access the stencil component. + the parameter is set to StencilMode, the shader will access the stencil component. \note This function has no effect on Mac and Qt built for OpenGL ES 2. \sa depthStencilMode() @@ -2601,20 +2782,23 @@ QOpenGLTexture::SwizzleValue QOpenGLTexture::swizzleMask(SwizzleComponent compon void QOpenGLTexture::setDepthStencilMode(QOpenGLTexture::DepthStencilMode mode) { #if !defined(Q_OS_MAC) && !defined(QT_OPENGL_ES_2) - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - if (!d->features.testFlag(StencilTexturing)) { - qWarning("QOpenGLTexture::setDepthStencilMode() requires OpenGL >= 4.3"); + if (!QOpenGLFunctions::isES()) { + Q_D(QOpenGLTexture); + d->create(); + Q_ASSERT(d->texFuncs); + Q_ASSERT(d->textureId); + if (!d->features.testFlag(StencilTexturing)) { + qWarning("QOpenGLTexture::setDepthStencilMode() requires OpenGL >= 4.3"); + return; + } + d->depthStencilMode = mode; + d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_DEPTH_STENCIL_TEXTURE_MODE, mode); return; } - d->depthStencilMode = mode; - d->texFuncs->glTextureParameteri(d->textureId, d->target, GL_DEPTH_STENCIL_TEXTURE_MODE, mode); #else Q_UNUSED(mode); - qWarning("QOpenGLTexture: DepthStencil Mode is not supported"); #endif + qWarning("QOpenGLTexture: DepthStencil Mode is not supported"); } /*! @@ -2640,7 +2824,7 @@ void QOpenGLTexture::setMinificationFilter(QOpenGLTexture::Filter filter) Q_ASSERT(d->texFuncs); Q_ASSERT(d->textureId); d->minFilter = filter; - d->texFuncs->glTextureParameteri(d->textureId, d->target, GL_TEXTURE_MIN_FILTER, filter); + d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MIN_FILTER, filter); } /*! @@ -2666,7 +2850,7 @@ void QOpenGLTexture::setMagnificationFilter(QOpenGLTexture::Filter filter) Q_ASSERT(d->texFuncs); Q_ASSERT(d->textureId); d->magFilter = filter; - d->texFuncs->glTextureParameteri(d->textureId, d->target, GL_TEXTURE_MAG_FILTER, filter); + d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MAG_FILTER, filter); } /*! @@ -2695,8 +2879,8 @@ void QOpenGLTexture::setMinMagFilters(QOpenGLTexture::Filter minificationFilter, Q_ASSERT(d->textureId); d->minFilter = minificationFilter; d->magFilter = magnificationFilter; - d->texFuncs->glTextureParameteri(d->textureId, d->target, GL_TEXTURE_MIN_FILTER, minificationFilter); - d->texFuncs->glTextureParameteri(d->textureId, d->target, GL_TEXTURE_MAG_FILTER, magnificationFilter); + d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MIN_FILTER, minificationFilter); + d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MAG_FILTER, magnificationFilter); } /*! @@ -2727,7 +2911,7 @@ void QOpenGLTexture::setMaximumAnisotropy(float anisotropy) return; } d->maxAnisotropy = anisotropy; - d->texFuncs->glTextureParameteri(d->textureId, d->target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); + d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); } /*! @@ -2788,23 +2972,26 @@ QOpenGLTexture::WrapMode QOpenGLTexture::wrapMode(QOpenGLTexture::CoordinateDire void QOpenGLTexture::setBorderColor(QColor color) { #if !defined(QT_OPENGL_ES_2) - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - float values[4]; - values[0] = color.redF(); - values[1] = color.greenF(); - values[2] = color.blueF(); - values[3] = color.alphaF(); - d->borderColor.clear(); - for (int i = 0; i < 4; ++i) - d->borderColor.append(QVariant(values[i])); - d->texFuncs->glTextureParameterfv(d->textureId, d->target, GL_TEXTURE_BORDER_COLOR, values); + if (!QOpenGLFunctions::isES()) { + Q_D(QOpenGLTexture); + d->create(); + Q_ASSERT(d->texFuncs); + Q_ASSERT(d->textureId); + float values[4]; + values[0] = color.redF(); + values[1] = color.greenF(); + values[2] = color.blueF(); + values[3] = color.alphaF(); + d->borderColor.clear(); + for (int i = 0; i < 4; ++i) + d->borderColor.append(QVariant(values[i])); + d->texFuncs->glTextureParameterfv(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_BORDER_COLOR, values); + return; + } #else Q_UNUSED(color); - qWarning("QOpenGLTexture: Border color is not supported"); #endif + qWarning("QOpenGLTexture: Border color is not supported"); } /*! @@ -2813,26 +3000,29 @@ void QOpenGLTexture::setBorderColor(QColor color) void QOpenGLTexture::setBorderColor(float r, float g, float b, float a) { #if !defined(QT_OPENGL_ES_2) - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - float values[4]; - values[0] = r; - values[1] = g; - values[2] = b; - values[3] = a; - d->borderColor.clear(); - for (int i = 0; i < 4; ++i) - d->borderColor.append(QVariant(values[i])); - d->texFuncs->glTextureParameterfv(d->textureId, d->target, GL_TEXTURE_BORDER_COLOR, values); + if (!QOpenGLFunctions::isES()) { + Q_D(QOpenGLTexture); + d->create(); + Q_ASSERT(d->texFuncs); + Q_ASSERT(d->textureId); + float values[4]; + values[0] = r; + values[1] = g; + values[2] = b; + values[3] = a; + d->borderColor.clear(); + for (int i = 0; i < 4; ++i) + d->borderColor.append(QVariant(values[i])); + d->texFuncs->glTextureParameterfv(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_BORDER_COLOR, values); + return; + } #else Q_UNUSED(r); Q_UNUSED(g); Q_UNUSED(b); Q_UNUSED(a); - qWarning("QOpenGLTexture: Border color is not supported"); #endif + qWarning("QOpenGLTexture: Border color is not supported"); } /*! @@ -2841,26 +3031,29 @@ void QOpenGLTexture::setBorderColor(float r, float g, float b, float a) void QOpenGLTexture::setBorderColor(int r, int g, int b, int a) { #if !defined(QT_OPENGL_ES_2) - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - int values[4]; - values[0] = r; - values[1] = g; - values[2] = b; - values[3] = a; - d->borderColor.clear(); - for (int i = 0; i < 4; ++i) - d->borderColor.append(QVariant(values[i])); - d->texFuncs->glTextureParameteriv(d->textureId, d->target, GL_TEXTURE_BORDER_COLOR, values); + if (!QOpenGLFunctions::isES()) { + Q_D(QOpenGLTexture); + d->create(); + Q_ASSERT(d->texFuncs); + Q_ASSERT(d->textureId); + int values[4]; + values[0] = r; + values[1] = g; + values[2] = b; + values[3] = a; + d->borderColor.clear(); + for (int i = 0; i < 4; ++i) + d->borderColor.append(QVariant(values[i])); + d->texFuncs->glTextureParameteriv(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_BORDER_COLOR, values); + return; + } #else Q_UNUSED(r); Q_UNUSED(g); Q_UNUSED(b); Q_UNUSED(a); - qWarning("QOpenGLTexture: Border color is not supported"); #endif + qWarning("QOpenGLTexture: Border color is not supported"); // TODO Handle case of using glTextureParameterIiv() based on format } @@ -2871,26 +3064,29 @@ void QOpenGLTexture::setBorderColor(int r, int g, int b, int a) void QOpenGLTexture::setBorderColor(uint r, uint g, uint b, uint a) { #if !defined(QT_OPENGL_ES_2) - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - int values[4]; - values[0] = int(r); - values[1] = int(g); - values[2] = int(b); - values[3] = int(a); - d->borderColor.clear(); - for (int i = 0; i < 4; ++i) - d->borderColor.append(QVariant(values[i])); - d->texFuncs->glTextureParameteriv(d->textureId, d->target, GL_TEXTURE_BORDER_COLOR, values); + if (!QOpenGLFunctions::isES()) { + Q_D(QOpenGLTexture); + d->create(); + Q_ASSERT(d->texFuncs); + Q_ASSERT(d->textureId); + int values[4]; + values[0] = int(r); + values[1] = int(g); + values[2] = int(b); + values[3] = int(a); + d->borderColor.clear(); + for (int i = 0; i < 4; ++i) + d->borderColor.append(QVariant(values[i])); + d->texFuncs->glTextureParameteriv(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_BORDER_COLOR, values); + return; + } #else Q_UNUSED(r); Q_UNUSED(g); Q_UNUSED(b); Q_UNUSED(a); - qWarning("QOpenGLTexture: Border color is not supported"); #endif + qWarning("QOpenGLTexture: Border color is not supported"); // TODO Handle case of using glTextureParameterIuiv() based on format } @@ -2974,17 +3170,20 @@ void QOpenGLTexture::borderColor(unsigned int *border) const void QOpenGLTexture::setMinimumLevelOfDetail(float value) { #if !defined(QT_OPENGL_ES_2) - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - Q_ASSERT(value < d->maxLevelOfDetail); - d->minLevelOfDetail = value; - d->texFuncs->glTextureParameterf(d->textureId, d->target, GL_TEXTURE_MIN_LOD, value); + if (!QOpenGLFunctions::isES()) { + Q_D(QOpenGLTexture); + d->create(); + Q_ASSERT(d->texFuncs); + Q_ASSERT(d->textureId); + Q_ASSERT(value < d->maxLevelOfDetail); + d->minLevelOfDetail = value; + d->texFuncs->glTextureParameterf(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MIN_LOD, value); + return; + } #else Q_UNUSED(value); - qWarning("QOpenGLTexture: Detail level is not supported"); #endif + qWarning("QOpenGLTexture: Detail level is not supported"); } /*! @@ -3008,17 +3207,20 @@ float QOpenGLTexture::minimumLevelOfDetail() const void QOpenGLTexture::setMaximumLevelOfDetail(float value) { #if !defined(QT_OPENGL_ES_2) - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - Q_ASSERT(value > d->minLevelOfDetail); - d->maxLevelOfDetail = value; - d->texFuncs->glTextureParameterf(d->textureId, d->target, GL_TEXTURE_MAX_LOD, value); + if (!QOpenGLFunctions::isES()) { + Q_D(QOpenGLTexture); + d->create(); + Q_ASSERT(d->texFuncs); + Q_ASSERT(d->textureId); + Q_ASSERT(value > d->minLevelOfDetail); + d->maxLevelOfDetail = value; + d->texFuncs->glTextureParameterf(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MAX_LOD, value); + return; + } #else Q_UNUSED(value); - qWarning("QOpenGLTexture: Detail level is not supported"); #endif + qWarning("QOpenGLTexture: Detail level is not supported"); } /*! @@ -3041,20 +3243,23 @@ float QOpenGLTexture::maximumLevelOfDetail() const void QOpenGLTexture::setLevelOfDetailRange(float min, float max) { #if !defined(QT_OPENGL_ES_2) - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - Q_ASSERT(min < max); - d->minLevelOfDetail = min; - d->maxLevelOfDetail = max; - d->texFuncs->glTextureParameterf(d->textureId, d->target, GL_TEXTURE_MIN_LOD, min); - d->texFuncs->glTextureParameterf(d->textureId, d->target, GL_TEXTURE_MAX_LOD, max); + if (!QOpenGLFunctions::isES()) { + Q_D(QOpenGLTexture); + d->create(); + Q_ASSERT(d->texFuncs); + Q_ASSERT(d->textureId); + Q_ASSERT(min < max); + d->minLevelOfDetail = min; + d->maxLevelOfDetail = max; + d->texFuncs->glTextureParameterf(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MIN_LOD, min); + d->texFuncs->glTextureParameterf(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MAX_LOD, max); + return; + } #else Q_UNUSED(min); Q_UNUSED(max); - qWarning("QOpenGLTexture: Detail level is not supported"); #endif + qWarning("QOpenGLTexture: Detail level is not supported"); } /*! @@ -3077,16 +3282,19 @@ QPair<float, float> QOpenGLTexture::levelOfDetailRange() const void QOpenGLTexture::setLevelofDetailBias(float bias) { #if !defined(QT_OPENGL_ES_2) - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - d->levelOfDetailBias = bias; - d->texFuncs->glTextureParameterf(d->textureId, d->target, GL_TEXTURE_LOD_BIAS, bias); + if (!QOpenGLFunctions::isES()) { + Q_D(QOpenGLTexture); + d->create(); + Q_ASSERT(d->texFuncs); + Q_ASSERT(d->textureId); + d->levelOfDetailBias = bias; + d->texFuncs->glTextureParameterf(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_LOD_BIAS, bias); + return; + } #else Q_UNUSED(bias); - qWarning("QOpenGLTexture: Detail level is not supported"); #endif + qWarning("QOpenGLTexture: Detail level is not supported"); } /*! diff --git a/src/gui/opengl/qopengltexture.h b/src/gui/opengl/qopengltexture.h index 5c0f8101a6..0c272456f6 100644 --- a/src/gui/opengl/qopengltexture.h +++ b/src/gui/opengl/qopengltexture.h @@ -337,28 +337,53 @@ public: }; // Pixel transfer + // ### Qt 6: remove the non-const void * overloads + QT_DEPRECATED void setData(int mipLevel, int layer, CubeMapFace cubeFace, + PixelFormat sourceFormat, PixelType sourceType, + void *data, const QOpenGLPixelTransferOptions * const options = 0); + QT_DEPRECATED void setData(int mipLevel, int layer, + PixelFormat sourceFormat, PixelType sourceType, + void *data, const QOpenGLPixelTransferOptions * const options = 0); + QT_DEPRECATED void setData(int mipLevel, + PixelFormat sourceFormat, PixelType sourceType, + void *data, const QOpenGLPixelTransferOptions * const options = 0); + QT_DEPRECATED void setData(PixelFormat sourceFormat, PixelType sourceType, + void *data, const QOpenGLPixelTransferOptions * const options = 0); + void setData(int mipLevel, int layer, CubeMapFace cubeFace, PixelFormat sourceFormat, PixelType sourceType, - void *data, const QOpenGLPixelTransferOptions * const options = 0); + const void *data, const QOpenGLPixelTransferOptions * const options = 0); void setData(int mipLevel, int layer, PixelFormat sourceFormat, PixelType sourceType, - void *data, const QOpenGLPixelTransferOptions * const options = 0); + const void *data, const QOpenGLPixelTransferOptions * const options = 0); void setData(int mipLevel, PixelFormat sourceFormat, PixelType sourceType, - void *data, const QOpenGLPixelTransferOptions * const options = 0); + const void *data, const QOpenGLPixelTransferOptions * const options = 0); void setData(PixelFormat sourceFormat, PixelType sourceType, - void *data, const QOpenGLPixelTransferOptions * const options = 0); + const void *data, const QOpenGLPixelTransferOptions * const options = 0); // Compressed data upload + // ### Qt 6: remove the non-const void * overloads + QT_DEPRECATED void setCompressedData(int mipLevel, int layer, CubeMapFace cubeFace, + int dataSize, void *data, + const QOpenGLPixelTransferOptions * const options = 0); + QT_DEPRECATED void setCompressedData(int mipLevel, int layer, + int dataSize, void *data, + const QOpenGLPixelTransferOptions * const options = 0); + QT_DEPRECATED void setCompressedData(int mipLevel, int dataSize, void *data, + const QOpenGLPixelTransferOptions * const options = 0); + QT_DEPRECATED void setCompressedData(int dataSize, void *data, + const QOpenGLPixelTransferOptions * const options = 0); + void setCompressedData(int mipLevel, int layer, CubeMapFace cubeFace, - int dataSize, void *data, + int dataSize, const void *data, const QOpenGLPixelTransferOptions * const options = 0); void setCompressedData(int mipLevel, int layer, - int dataSize, void *data, + int dataSize, const void *data, const QOpenGLPixelTransferOptions * const options = 0); - void setCompressedData(int mipLevel, int dataSize, void *data, + void setCompressedData(int mipLevel, int dataSize, const void *data, const QOpenGLPixelTransferOptions * const options = 0); - void setCompressedData(int dataSize, void *data, + void setCompressedData(int dataSize, const void *data, const QOpenGLPixelTransferOptions * const options = 0); // Helpful overloads for setData @@ -379,8 +404,9 @@ public: AnisotropicFiltering = 0x00000400, NPOTTextures = 0x00000800, NPOTTextureRepeat = 0x00001000, + Texture1D = 0x00002000, #ifndef Q_QDOC - MaxFeatureFlag = 0x00002000 + MaxFeatureFlag = 0x00004000 #endif }; Q_DECLARE_FLAGS(Features, Feature) diff --git a/src/gui/opengl/qopengltexture_p.h b/src/gui/opengl/qopengltexture_p.h index 009561533b..a732805f55 100644 --- a/src/gui/opengl/qopengltexture_p.h +++ b/src/gui/opengl/qopengltexture_p.h @@ -89,9 +89,9 @@ public: void allocateImmutableStorage(); void setData(int mipLevel, int layer, QOpenGLTexture::CubeMapFace cubeFace, QOpenGLTexture::PixelFormat sourceFormat, QOpenGLTexture::PixelType sourceType, - void *data, const QOpenGLPixelTransferOptions * const options); + const void *data, const QOpenGLPixelTransferOptions * const options); void setCompressedData(int mipLevel, int layer, QOpenGLTexture::CubeMapFace cubeFace, - int dataSize, void *data, + int dataSize, const void *data, const QOpenGLPixelTransferOptions * const options); void setWrapMode(QOpenGLTexture::WrapMode mode); diff --git a/src/gui/opengl/qopengltextureblitter.cpp b/src/gui/opengl/qopengltextureblitter.cpp new file mode 100644 index 0000000000..b776444347 --- /dev/null +++ b/src/gui/opengl/qopengltextureblitter.cpp @@ -0,0 +1,393 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopengltextureblitter_p.h" + +#include <QtGui/QOpenGLBuffer> +#include <QtGui/QOpenGLShaderProgram> +#include <QtGui/QOpenGLVertexArrayObject> +#include <QtGui/QOpenGLContext> + +QT_BEGIN_NAMESPACE + +static const char vertex_shader150[] = + "#version 150 core\n" + "in vec3 vertexCoord;" + "in vec2 textureCoord;" + "out vec2 uv;" + "uniform mat4 vertexTransform;" + "uniform mat3 textureTransform;" + "void main() {" + " uv = (textureTransform * vec3(textureCoord,1.0)).xy;" + " gl_Position = vertexTransform * vec4(vertexCoord,1.0);" + "}"; + +static const char fragment_shader150[] = + "#version 150 core\n" + "in vec2 uv;" + "out vec4 fragcolor;" + "uniform sampler2D textureSampler;" + "uniform bool swizzle;" + "void main() {" + " if (swizzle) {" + " fragcolor = texture(textureSampler, uv).bgra;" + " } else {" + " fragcolor = texture(textureSampler,uv);" + " }" + "}"; + +static const char vertex_shader[] = + "attribute highp vec3 vertexCoord;" + "attribute highp vec2 textureCoord;" + "varying highp vec2 uv;" + "uniform highp mat4 vertexTransform;" + "uniform highp mat3 textureTransform;" + "void main() {" + " uv = (textureTransform * vec3(textureCoord,1.0)).xy;" + " gl_Position = vertexTransform * vec4(vertexCoord,1.0);" + "}"; + +static const char fragment_shader[] = + "varying highp vec2 uv;" + "uniform sampler2D textureSampler;" + "uniform bool swizzle;" + "void main() {" + " if (swizzle) {" + " gl_FragColor = texture2D(textureSampler, uv).bgra;" + " } else {" + " gl_FragColor = texture2D(textureSampler,uv);" + " }" + "}"; + +static const GLfloat vertex_buffer_data[] = { + -1,-1, 0, + -1, 1, 0, + 1,-1, 0, + -1, 1, 0, + 1,-1, 0, + 1, 1, 0 +}; + +static const GLfloat texture_buffer_data[] = { + 0, 0, + 0, 1, + 1, 0, + 0, 1, + 1, 0, + 1, 1 +}; + +class TextureBinder +{ +public: + TextureBinder(GLuint textureId) + { + glBindTexture(GL_TEXTURE_2D, textureId); + } + ~TextureBinder() + { + glBindTexture(GL_TEXTURE_2D, 0); + } +}; + +class QOpenGLTextureBlitterPrivate +{ +public: + enum TextureMatrixUniform { + User, + Identity, + IdentityFlipped + }; + + QOpenGLTextureBlitterPrivate() + : program(0) + , vertexCoordAttribPos(0) + , vertexTransformUniformPos(0) + , textureCoordAttribPos(0) + , textureTransformUniformPos(0) + , swizzle(false) + , swizzleOld(false) + , textureMatrixUniformState(User) + , vao(new QOpenGLVertexArrayObject()) + { } + + void blit(GLuint texture, const QMatrix4x4 &vertexTransform, const QMatrix3x3 &textureTransform); + void blit(GLuint texture, const QMatrix4x4 &vertexTransform, QOpenGLTextureBlitter::Origin origin); + + void prepareProgram(const QMatrix4x4 &vertexTransform) + { + vertexBuffer.bind(); + program->setAttributeBuffer(vertexCoordAttribPos, GL_FLOAT, 0, 3, 0); + program->enableAttributeArray(vertexCoordAttribPos); + vertexBuffer.release(); + + program->setUniformValue(vertexTransformUniformPos, vertexTransform); + + textureBuffer.bind(); + program->setAttributeBuffer(textureCoordAttribPos, GL_FLOAT, 0, 2, 0); + program->enableAttributeArray(textureCoordAttribPos); + textureBuffer.release(); + + if (swizzle != swizzleOld) { + program->setUniformValue(swizzleUniformPos, swizzle); + swizzleOld = swizzle; + } + } + + QOpenGLBuffer vertexBuffer; + QOpenGLBuffer textureBuffer; + QScopedPointer<QOpenGLShaderProgram> program; + GLuint vertexCoordAttribPos; + GLuint vertexTransformUniformPos; + GLuint textureCoordAttribPos; + GLuint textureTransformUniformPos; + GLuint swizzleUniformPos; + bool swizzle; + bool swizzleOld; + TextureMatrixUniform textureMatrixUniformState; + QScopedPointer<QOpenGLVertexArrayObject> vao; +}; + +void QOpenGLTextureBlitterPrivate::blit(GLuint texture, + const QMatrix4x4 &vertexTransform, + const QMatrix3x3 &textureTransform) +{ + TextureBinder binder(texture); + prepareProgram(vertexTransform); + + program->setUniformValue(textureTransformUniformPos, textureTransform); + textureMatrixUniformState = User; + + glDrawArrays(GL_TRIANGLES, 0, 6); +} + +void QOpenGLTextureBlitterPrivate::blit(GLuint texture, + const QMatrix4x4 &vertexTransform, + QOpenGLTextureBlitter::Origin origin) +{ + TextureBinder binder(texture); + prepareProgram(vertexTransform); + + if (origin == QOpenGLTextureBlitter::OriginTopLeft) { + if (textureMatrixUniformState != IdentityFlipped) { + QMatrix3x3 flipped; + flipped(1,1) = -1; + flipped(1,2) = 1; + program->setUniformValue(textureTransformUniformPos, flipped); + textureMatrixUniformState = IdentityFlipped; + } + } else if (textureMatrixUniformState != Identity) { + program->setUniformValue(textureTransformUniformPos, QMatrix3x3()); + textureMatrixUniformState = Identity; + } + + glDrawArrays(GL_TRIANGLES, 0, 6); +} + +QOpenGLTextureBlitter::QOpenGLTextureBlitter() + : d_ptr(new QOpenGLTextureBlitterPrivate) +{ +} + +QOpenGLTextureBlitter::~QOpenGLTextureBlitter() +{ +} + +bool QOpenGLTextureBlitter::create() +{ + QOpenGLContext *currentContext = QOpenGLContext::currentContext(); + if (!currentContext) + return false; + + Q_D(QOpenGLTextureBlitter); + + d->vao->create(); + d->vao->bind(); + + if (d->program) + return true; + + d->program.reset(new QOpenGLShaderProgram()); + + QSurfaceFormat format = currentContext->format(); + + if (format.profile() == QSurfaceFormat::CoreProfile && format.version() >= qMakePair(3,2)) { + d->program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertex_shader150); + d->program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragment_shader150); + } else { + d->program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertex_shader); + d->program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragment_shader); + } + d->program->link(); + if (!d->program->isLinked()) { + qWarning() << Q_FUNC_INFO << "Could not link shader program:\n" << d->program->log(); + return false; + } + + d->program->bind(); + + d->vertexBuffer.create(); + d->vertexBuffer.bind(); + d->vertexBuffer.allocate(vertex_buffer_data, sizeof(vertex_buffer_data) * sizeof(vertex_buffer_data[0])); + d->vertexBuffer.release(); + + d->textureBuffer.create(); + d->textureBuffer.bind(); + d->textureBuffer.allocate(texture_buffer_data, sizeof(texture_buffer_data) * sizeof(texture_buffer_data[0])); + d->textureBuffer.release(); + + d->vertexCoordAttribPos = d->program->attributeLocation("vertexCoord"); + d->vertexTransformUniformPos = d->program->uniformLocation("vertexTransform"); + d->textureCoordAttribPos = d->program->attributeLocation("textureCoord"); + d->textureTransformUniformPos = d->program->uniformLocation("textureTransform"); + d->swizzleUniformPos = d->program->uniformLocation("swizzle"); + + d->program->setUniformValue(d->swizzleUniformPos,false); + + d->vao->release(); + + return true; +} + +void QOpenGLTextureBlitter::destroy() +{ + Q_D(QOpenGLTextureBlitter); + d->program.reset(); + d->vertexBuffer.destroy(); + d->textureBuffer.destroy(); + d->vao.reset(); +} + +void QOpenGLTextureBlitter::bind() +{ + Q_D(QOpenGLTextureBlitter); + + d->vao->bind(); + + d->program->bind(); + + d->vertexBuffer.bind(); + d->program->setAttributeBuffer(d->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0); + d->program->enableAttributeArray(d->vertexCoordAttribPos); + d->vertexBuffer.release(); + + d->textureBuffer.bind(); + d->program->setAttributeBuffer(d->textureCoordAttribPos, GL_FLOAT, 0, 2, 0); + d->program->enableAttributeArray(d->textureCoordAttribPos); + d->textureBuffer.release(); +} + +void QOpenGLTextureBlitter::release() +{ + Q_D(QOpenGLTextureBlitter); + d->program->release(); + d->vao->release(); +} + +void QOpenGLTextureBlitter::setSwizzleRB(bool swizzle) +{ + Q_D(QOpenGLTextureBlitter); + d->swizzle = swizzle; +} + +void QOpenGLTextureBlitter::blit(GLuint texture, + const QMatrix4x4 &targetTransform, + Origin sourceOrigin) +{ + Q_D(QOpenGLTextureBlitter); + d->blit(texture,targetTransform, sourceOrigin); +} + +void QOpenGLTextureBlitter::blit(GLuint texture, + const QMatrix4x4 &targetTransform, + const QMatrix3x3 &sourceTransform) +{ + Q_D(QOpenGLTextureBlitter); + d->blit(texture, targetTransform, sourceTransform); +} + +QMatrix4x4 QOpenGLTextureBlitter::targetTransform(const QRectF &target, + const QRect &viewport) +{ + qreal x_scale = target.width() / viewport.width(); + qreal y_scale = target.height() / viewport.height(); + + const QPointF relative_to_viewport = target.topLeft() - viewport.topLeft(); + qreal x_translate = x_scale - 1 + ((relative_to_viewport.x() / viewport.width()) * 2); + qreal y_translate = -y_scale + 1 - ((relative_to_viewport.y() / viewport.height()) * 2); + + QMatrix4x4 matrix; + matrix(0,3) = x_translate; + matrix(1,3) = y_translate; + + matrix(0,0) = x_scale; + matrix(1,1) = y_scale; + + return matrix; +} + +QMatrix3x3 QOpenGLTextureBlitter::sourceTransform(const QRectF &subTexture, + const QSize &textureSize, + Origin origin) +{ + qreal x_scale = subTexture.width() / textureSize.width(); + qreal y_scale = subTexture.height() / textureSize.height(); + + const QPointF topLeft = subTexture.topLeft(); + qreal x_translate = topLeft.x() / textureSize.width(); + qreal y_translate = topLeft.y() / textureSize.height(); + + if (origin == OriginTopLeft) { + y_scale = -y_scale; + y_translate = 1 - y_translate; + } + + QMatrix3x3 matrix; + matrix(0,2) = x_translate; + matrix(1,2) = y_translate; + + matrix(0,0) = x_scale; + matrix(1,1) = y_scale; + + return matrix; +} + +QT_END_NAMESPACE diff --git a/src/gui/opengl/qopengltextureblitter_p.h b/src/gui/opengl/qopengltextureblitter_p.h new file mode 100644 index 0000000000..b2ccc13391 --- /dev/null +++ b/src/gui/opengl/qopengltextureblitter_p.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGLTEXTUREBLITTER_P_H +#define QOPENGLTEXTUREBLITTER_P_H + +#include <QtGui/qopengl.h> +#include <QtGui/QMatrix3x3> + +QT_BEGIN_NAMESPACE + +class QOpenGLTextureBlitterPrivate; + + +class Q_GUI_EXPORT QOpenGLTextureBlitter +{ +public: + QOpenGLTextureBlitter(); + ~QOpenGLTextureBlitter(); + + enum Origin { + OriginBottomLeft, + OriginTopLeft + }; + + bool create(); + void destroy(); + + void bind(); + void release(); + + void setSwizzleRB(bool swizzle); + + void blit(GLuint texture, const QMatrix4x4 &targetTransform, Origin sourceOrigin); + void blit(GLuint texture, const QMatrix4x4 &targetTransform, const QMatrix3x3 &sourceTransform); + + static QMatrix4x4 targetTransform(const QRectF &target, const QRect &viewport); + static QMatrix3x3 sourceTransform(const QRectF &subTexture, const QSize &textureSize, Origin origin); + +private: + Q_DISABLE_COPY(QOpenGLTextureBlitter); + Q_DECLARE_PRIVATE(QOpenGLTextureBlitter); + QScopedPointer<QOpenGLTextureBlitterPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif //QOPENGLTEXTUREBLITTER_P_H diff --git a/src/gui/opengl/qopengltextureglyphcache.cpp b/src/gui/opengl/qopengltextureglyphcache.cpp index 3b62d1d63a..0d9a2359bd 100644 --- a/src/gui/opengl/qopengltextureglyphcache.cpp +++ b/src/gui/opengl/qopengltextureglyphcache.cpp @@ -328,8 +328,11 @@ void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed if (mask.format() == QImage::Format_RGB32 // We need to make the alpha component equal to the average of the RGB values. // This is needed when drawing sub-pixel antialiased text on translucent targets. -#if defined(QT_OPENGL_ES_2) || Q_BYTE_ORDER == Q_BIG_ENDIAN +#if Q_BYTE_ORDER == Q_BIG_ENDIAN || mask.format() == QImage::Format_ARGB32_Premultiplied +#else + || (mask.format() == QImage::Format_ARGB32_Premultiplied + && QOpenGLFunctions::isES()) #endif ) { for (int y = 0; y < maskHeight; ++y) { @@ -345,10 +348,11 @@ void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed avg = qAlpha(src[x]); src[x] = qRgba(r, g, b, avg); -#if defined(QT_OPENGL_ES_2) || Q_BYTE_ORDER == Q_BIG_ENDIAN // swizzle the bits to accommodate for the GL_RGBA upload. - src[x] = ARGB2RGBA(src[x]); +#if Q_BYTE_ORDER != Q_BIG_ENDIAN + if (QOpenGLFunctions::isES()) #endif + src[x] = ARGB2RGBA(src[x]); } } } @@ -356,11 +360,16 @@ void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture); if (mask.depth() == 32) { -#if defined(QT_OPENGL_ES_2) || Q_BYTE_ORDER == Q_BIG_ENDIAN - glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_RGBA, GL_UNSIGNED_BYTE, mask.bits()); +#ifdef QT_OPENGL_ES_2 + GLenum fmt = GL_RGBA; #else - glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits()); + GLenum fmt = QOpenGLFunctions::isES() ? GL_RGBA : GL_BGRA; +#endif // QT_OPENGL_ES_2 + +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + fmt = GL_RGBA; #endif + glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, fmt, GL_UNSIGNED_BYTE, mask.bits()); } else { // glTexSubImage2D() might cause some garbage to appear in the texture if the mask width is // not a multiple of four bytes. The bug appeared on a computer with 32-bit Windows Vista diff --git a/src/gui/opengl/qopengltexturehelper.cpp b/src/gui/opengl/qopengltexturehelper.cpp index 676c0802de..1f44a81276 100644 --- a/src/gui/opengl/qopengltexturehelper.cpp +++ b/src/gui/opengl/qopengltexturehelper.cpp @@ -42,14 +42,15 @@ #include "qopengltexturehelper_p.h" #include <QOpenGLContext> +#include <QOpenGLFunctions> QT_BEGIN_NAMESPACE QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context) { // Resolve EXT_direct_state_access entry points if present -#if !defined(QT_OPENGL_ES_2) - if (context->hasExtension(QByteArrayLiteral("GL_EXT_direct_state_access"))) { + if (!QOpenGLFunctions::isES() + && context->hasExtension(QByteArrayLiteral("GL_EXT_direct_state_access"))) { TextureParameteriEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLenum , GLint )>(context->getProcAddress(QByteArrayLiteral("glTextureParameteriEXT"))); TextureParameterivEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLenum , const GLint *)>(context->getProcAddress(QByteArrayLiteral("glTextureParameterivEXT"))); TextureParameterfEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLenum , GLfloat )>(context->getProcAddress(QByteArrayLiteral("glTextureParameterfEXT"))); @@ -97,7 +98,6 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context) CompressedTextureImage2D = &QOpenGLTextureHelper::dsa_CompressedTextureImage2D; CompressedTextureImage3D = &QOpenGLTextureHelper::dsa_CompressedTextureImage3D; } else { -#endif // Use our own DSA emulation TextureParameteri = &QOpenGLTextureHelper::qt_TextureParameteri; TextureParameteriv = &QOpenGLTextureHelper::qt_TextureParameteriv; @@ -119,37 +119,28 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context) CompressedTextureImage1D = &QOpenGLTextureHelper::qt_CompressedTextureImage1D; CompressedTextureImage2D = &QOpenGLTextureHelper::qt_CompressedTextureImage2D; CompressedTextureImage3D = &QOpenGLTextureHelper::qt_CompressedTextureImage3D; -#if defined(QT_OPENGL_ES_2) - if (context->hasExtension(QByteArrayLiteral("GL_OES_texture_3D"))) { - TexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glTexImage3DOES"))); - TexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glTexSubImage3DOES"))); - CompressedTexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexImage3DOES"))); - CompressedTexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage3DOES"))); - } -#endif - -#if !defined(QT_OPENGL_ES_2) } -#endif // Some DSA functions are part of NV_texture_multisample instead -#if !defined(QT_OPENGL_ES_2) - if (context->hasExtension(QByteArrayLiteral("GL_NV_texture_multisample"))) { + if (!QOpenGLFunctions::isES() + && context->hasExtension(QByteArrayLiteral("GL_NV_texture_multisample"))) { TextureImage3DMultisampleNV = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLsizei , GLint , GLsizei , GLsizei , GLsizei , GLboolean )>(context->getProcAddress(QByteArrayLiteral("glTextureImage3DMultisampleNV"))); TextureImage2DMultisampleNV = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLsizei , GLint , GLsizei , GLsizei , GLboolean )>(context->getProcAddress(QByteArrayLiteral("glTextureImage2DMultisampleNV"))); TextureImage3DMultisample = &QOpenGLTextureHelper::dsa_TextureImage3DMultisample; TextureImage2DMultisample = &QOpenGLTextureHelper::dsa_TextureImage2DMultisample; } else { -#endif TextureImage3DMultisample = &QOpenGLTextureHelper::qt_TextureImage3DMultisample; TextureImage2DMultisample = &QOpenGLTextureHelper::qt_TextureImage2DMultisample; -#if !defined(QT_OPENGL_ES_2) } -#endif + + // wglGetProcAddress should not be used to (and indeed will not) load OpenGL <= 1.1 functions. + // Hence, we resolve them "the hard way" #if defined(Q_OS_WIN) && !defined(QT_OPENGL_ES_2) - HMODULE handle = GetModuleHandleA("opengl32.dll"); + HMODULE handle = static_cast<HMODULE>(QOpenGLFunctions::platformGLHandle()); + if (!handle) + handle = GetModuleHandleA("opengl32.dll"); // OpenGL 1.0 GetIntegerv = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint *)>(GetProcAddress(handle, QByteArrayLiteral("glGetIntegerv"))); @@ -200,18 +191,27 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context) TexSubImage1D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLenum , GLenum , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glTexSubImage1D"))); #endif - // OpenGL 1.2 - TexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLsizei , GLsizei , GLint , GLenum , GLenum , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glTexImage3D"))); - TexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLint , GLsizei , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glTexSubImage3D"))); + if (QOpenGLFunctions::isES() && context->hasExtension(QByteArrayLiteral("GL_OES_texture_3D"))) { + TexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glTexImage3DOES"))); + TexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glTexSubImage3DOES"))); + CompressedTexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexImage3DOES"))); + CompressedTexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage3DOES"))); + } else { + // OpenGL 1.2 + TexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLsizei , GLsizei , GLint , GLenum , GLenum , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glTexImage3D"))); + TexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLint , GLsizei , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glTexSubImage3D"))); + + // OpenGL 1.3 + CompressedTexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLenum , GLsizei , GLsizei , GLsizei , GLint , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexImage3D"))); + CompressedTexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLint , GLsizei , GLsizei , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage3D"))); + } // OpenGL 1.3 GetCompressedTexImage = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glGetCompressedTexImage"))); CompressedTexSubImage1D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage1D"))); CompressedTexSubImage2D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLsizei , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage2D"))); - CompressedTexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLint , GLsizei , GLsizei , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage3D"))); CompressedTexImage1D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLenum , GLsizei , GLint , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexImage1D"))); CompressedTexImage2D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLenum , GLsizei , GLsizei , GLint , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexImage2D"))); - CompressedTexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLenum , GLsizei , GLsizei , GLsizei , GLint , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexImage3D"))); ActiveTexture = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum )>(context->getProcAddress(QByteArrayLiteral("glActiveTexture"))); // OpenGL 3.0 @@ -233,4 +233,404 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context) TextureView = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLuint , GLenum , GLuint , GLuint , GLuint , GLuint )>(context->getProcAddress(QByteArrayLiteral("glTextureView"))); } +void QOpenGLTextureHelper::dsa_TextureParameteri(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLint param) +{ + Q_UNUSED(bindingTarget); + TextureParameteriEXT(texture, target, pname, param); +} + +void QOpenGLTextureHelper::dsa_TextureParameteriv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLint *params) +{ + Q_UNUSED(bindingTarget); + TextureParameterivEXT(texture, target, pname, params); +} + +void QOpenGLTextureHelper::dsa_TextureParameterf(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLfloat param) +{ + Q_UNUSED(bindingTarget); + TextureParameterfEXT(texture, target, pname, param); +} + +void QOpenGLTextureHelper::dsa_TextureParameterfv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLfloat *params) +{ + Q_UNUSED(bindingTarget); + TextureParameterfvEXT(texture, target, pname, params); +} + +void QOpenGLTextureHelper::dsa_GenerateTextureMipmap(GLuint texture, GLenum target, GLenum bindingTarget) +{ + Q_UNUSED(bindingTarget); + GenerateTextureMipmapEXT(texture, target); +} + +void QOpenGLTextureHelper::dsa_TextureStorage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth) +{ + Q_UNUSED(bindingTarget); + TextureStorage3DEXT(texture, target, levels, internalFormat, width, height, depth); +} + +void QOpenGLTextureHelper::dsa_TextureStorage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height) +{ + Q_UNUSED(bindingTarget); + TextureStorage2DEXT(texture, target, levels, internalFormat, width, height); +} + +void QOpenGLTextureHelper::dsa_TextureStorage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width) +{ + Q_UNUSED(bindingTarget); + TextureStorage1DEXT(texture, target, levels, internalFormat, width); +} + +void QOpenGLTextureHelper::dsa_TextureStorage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations) +{ + Q_UNUSED(bindingTarget); + TextureStorage3DMultisampleEXT(texture, target, samples, internalFormat, width, height, depth, fixedSampleLocations); +} + +void QOpenGLTextureHelper::dsa_TextureStorage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations) +{ + Q_UNUSED(bindingTarget); + TextureStorage2DMultisampleEXT(texture, target, samples, internalFormat, width, height, fixedSampleLocations); +} + +void QOpenGLTextureHelper::dsa_TextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + Q_UNUSED(bindingTarget); + TextureImage3DEXT(texture, target, level, internalFormat, width, height, depth, border, format, type, pixels); +} + +void QOpenGLTextureHelper::dsa_TextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + Q_UNUSED(bindingTarget); + TextureImage2DEXT(texture, target, level, internalFormat, width, height, border, format, type, pixels); +} + +void QOpenGLTextureHelper::dsa_TextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + Q_UNUSED(bindingTarget); + TextureImage1DEXT(texture, target, level, internalFormat, width, border, format, type, pixels); +} + +void QOpenGLTextureHelper::dsa_TextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) +{ + Q_UNUSED(bindingTarget); + TextureSubImage3DEXT(texture, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); +} + +void QOpenGLTextureHelper::dsa_TextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) +{ + Q_UNUSED(bindingTarget); + TextureSubImage2DEXT(texture, target, level, xoffset, yoffset, width, height, format, type, pixels); +} + +void QOpenGLTextureHelper::dsa_TextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels) +{ + Q_UNUSED(bindingTarget); + TextureSubImage1DEXT(texture, target, level, xoffset, width, format, type, pixels); +} + +void QOpenGLTextureHelper::dsa_TextureImage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations) +{ + Q_UNUSED(bindingTarget); + TextureImage3DMultisampleNV(texture, target, samples, internalFormat, width, height, depth, fixedSampleLocations); +} + +void QOpenGLTextureHelper::dsa_TextureImage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations) +{ + Q_UNUSED(bindingTarget); + TextureImage2DMultisampleNV(texture, target, samples, internalFormat, width, height, fixedSampleLocations); +} + +void QOpenGLTextureHelper::dsa_CompressedTextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits) +{ + Q_UNUSED(bindingTarget); + CompressedTextureSubImage1DEXT(texture, target, level, xoffset, width, format, imageSize, bits); +} + +void QOpenGLTextureHelper::dsa_CompressedTextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits) +{ + Q_UNUSED(bindingTarget); + CompressedTextureSubImage2DEXT(texture, target, level, xoffset, yoffset, width, height, format, imageSize, bits); +} + +void QOpenGLTextureHelper::dsa_CompressedTextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits) +{ + Q_UNUSED(bindingTarget); + CompressedTextureSubImage3DEXT(texture, target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, bits); +} + +void QOpenGLTextureHelper::dsa_CompressedTextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits) +{ + Q_UNUSED(bindingTarget); + CompressedTextureImage1DEXT(texture, target, level, internalFormat, width, border, imageSize, bits); +} + +void QOpenGLTextureHelper::dsa_CompressedTextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits) +{ + Q_UNUSED(bindingTarget); + CompressedTextureImage2DEXT(texture, target, level, internalFormat, width, height, border, imageSize, bits); +} + +void QOpenGLTextureHelper::dsa_CompressedTextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits) +{ + Q_UNUSED(bindingTarget); + CompressedTextureImage3DEXT(texture, target, level, internalFormat, width, height, depth, border, imageSize, bits); +} + +void QOpenGLTextureHelper::qt_TextureParameteri(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLint param) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glTexParameteri(target, pname, param); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_TextureParameteriv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLint *params) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glTexParameteriv(target, pname, params); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_TextureParameterf(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLfloat param) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glTexParameterf(target, pname, param); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_TextureParameterfv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLfloat *params) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glTexParameterfv(target, pname, params); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_GenerateTextureMipmap(GLuint texture, GLenum target, GLenum bindingTarget) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glGenerateMipmap(target); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_TextureStorage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glTexStorage3D(target, levels, internalFormat, width, height, depth); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_TextureStorage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glTexStorage2D(target, levels, internalFormat, width, height); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_TextureStorage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glTexStorage1D(target, levels, internalFormat, width); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_TextureStorage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glTexStorage3DMultisample(target, samples, internalFormat, width, height, depth, fixedSampleLocations); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_TextureStorage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glTexStorage2DMultisample(target, samples, internalFormat, width, height, fixedSampleLocations); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_TextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, pixels); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_TextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + // For cubemaps we can't use the standard DSA emulation as it is illegal to + // try to bind a texture to one of the cubemap face targets. So we force the + // target and binding target to the cubemap values in this case. + GLint oldTexture; + + switch (target) { + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &oldTexture); + glBindTexture(GL_TEXTURE_CUBE_MAP, texture); + glTexImage2D(target, level, internalFormat, width, height, border, format, type, pixels); + glBindTexture(GL_TEXTURE_CUBE_MAP, oldTexture); + break; + + default: + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glTexImage2D(target, level, internalFormat, width, height, border, format, type, pixels); + glBindTexture(target, oldTexture); + break; + } +} + +void QOpenGLTextureHelper::qt_TextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glTexImage1D(target, level, internalFormat, width, border, format, type, pixels); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_TextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_TextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) +{ + // For cubemaps we can't use the standard DSA emulation as it is illegal to + // try to bind a texture to one of the cubemap face targets. So we force the + // target and binding target to the cubemap values in this case. + GLint oldTexture; + + switch (target) { + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &oldTexture); + glBindTexture(GL_TEXTURE_CUBE_MAP, texture); + glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); + glBindTexture(GL_TEXTURE_CUBE_MAP, oldTexture); + break; + + default: + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); + glBindTexture(target, oldTexture); + break; + } +} + +void QOpenGLTextureHelper::qt_TextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glTexSubImage1D(target, level, xoffset, width, format, type, pixels); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_TextureImage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glTexImage3DMultisample(target, samples, internalFormat, width, height, depth, fixedSampleLocations); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_TextureImage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glTexImage2DMultisample(target, samples, internalFormat, width, height, fixedSampleLocations); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_CompressedTextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glCompressedTexSubImage1D(target, level, xoffset, width, format, imageSize, bits); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_CompressedTextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, bits); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_CompressedTextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, bits); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_CompressedTextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glCompressedTexImage1D(target, level, internalFormat, width, border, imageSize, bits); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_CompressedTextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glCompressedTexImage2D(target, level, internalFormat, width, height, border, imageSize, bits); + glBindTexture(target, oldTexture); +} + +void QOpenGLTextureHelper::qt_CompressedTextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits) +{ + GLint oldTexture; + glGetIntegerv(bindingTarget, &oldTexture); + glBindTexture(target, texture); + glCompressedTexImage3D(target, level, internalFormat, width, height, depth, border, imageSize, bits); + glBindTexture(target, oldTexture); +} + QT_END_NAMESPACE diff --git a/src/gui/opengl/qopengltexturehelper_p.h b/src/gui/opengl/qopengltexturehelper_p.h index fa4bd8120a..782486b90d 100644 --- a/src/gui/opengl/qopengltexturehelper_p.h +++ b/src/gui/opengl/qopengltexturehelper_p.h @@ -59,135 +59,135 @@ class QOpenGLTextureHelper public: QOpenGLTextureHelper(QOpenGLContext *context); - // DSA API - inline void glTextureParameteri(GLuint texture, GLenum target, GLenum pname, GLint param) + // DSA-like API. Will either use real DSA or our emulation + inline void glTextureParameteri(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLint param) { - (this->*TextureParameteri)(texture, target, pname, param); + (this->*TextureParameteri)(texture, target, bindingTarget, pname, param); } - inline void glTextureParameteriv(GLuint texture, GLenum target, GLenum pname, const GLint *params) + inline void glTextureParameteriv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLint *params) { - (this->*TextureParameteriv)(texture, target, pname, params); + (this->*TextureParameteriv)(texture, target, bindingTarget, pname, params); } - inline void glTextureParameterf(GLuint texture, GLenum target, GLenum pname, GLfloat param) + inline void glTextureParameterf(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLfloat param) { - (this->*TextureParameterf)(texture, target, pname, param); + (this->*TextureParameterf)(texture, target, bindingTarget, pname, param); } - inline void glTextureParameterfv(GLuint texture, GLenum target, GLenum pname, const GLfloat *params) + inline void glTextureParameterfv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLfloat *params) { - (this->*TextureParameterfv)(texture, target, pname, params); + (this->*TextureParameterfv)(texture, target, bindingTarget, pname, params); } - inline void glGenerateTextureMipmap(GLuint texture, GLenum target) + inline void glGenerateTextureMipmap(GLuint texture, GLenum target, GLenum bindingTarget) { - (this->*GenerateTextureMipmap)(texture, target); + (this->*GenerateTextureMipmap)(texture, target, bindingTarget); } - inline void glTextureStorage3D(GLuint texture, GLenum target, GLsizei levels, GLenum internalFormat, + inline void glTextureStorage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth) { - (this->*TextureStorage3D)(texture, target, levels, internalFormat, width, height, depth); + (this->*TextureStorage3D)(texture, target, bindingTarget, levels, internalFormat, width, height, depth); } - inline void glTextureStorage2D(GLuint texture, GLenum target, GLsizei levels, GLenum internalFormat, + inline void glTextureStorage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height) { - (this->*TextureStorage2D)(texture, target, levels, internalFormat, width, height); + (this->*TextureStorage2D)(texture, target, bindingTarget, levels, internalFormat, width, height); } - inline void glTextureStorage1D(GLuint texture, GLenum target, GLsizei levels, GLenum internalFormat, + inline void glTextureStorage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width) { - (this->*TextureStorage1D)(texture, target, levels, internalFormat, width); + (this->*TextureStorage1D)(texture, target, bindingTarget, levels, internalFormat, width); } - inline void glTextureStorage3DMultisample(GLuint texture, GLenum target, GLsizei samples, GLenum internalFormat, + inline void glTextureStorage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations) { - (this->*TextureStorage3DMultisample)(texture, target, samples, internalFormat, width, height, depth, fixedSampleLocations); + (this->*TextureStorage3DMultisample)(texture, target, bindingTarget, samples, internalFormat, width, height, depth, fixedSampleLocations); } - inline void glTextureStorage2DMultisample(GLuint texture, GLenum target, GLsizei samples, GLenum internalFormat, + inline void glTextureStorage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations) { - (this->*TextureStorage2DMultisample)(texture, target, samples, internalFormat, width, height, fixedSampleLocations); + (this->*TextureStorage2DMultisample)(texture, target, bindingTarget, samples, internalFormat, width, height, fixedSampleLocations); } - inline void glTextureImage3D(GLuint texture, GLenum target, GLint level, GLenum internalFormat, + inline void glTextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) { - (this->*TextureImage3D)(texture, target, level, internalFormat, width, height, depth, border, format, type, pixels); + (this->*TextureImage3D)(texture, target, bindingTarget, level, internalFormat, width, height, depth, border, format, type, pixels); } - inline void glTextureImage2D(GLuint texture, GLenum target, GLint level, GLenum internalFormat, + inline void glTextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) { - (this->*TextureImage2D)(texture, target, level, internalFormat, width, height, border, format, type, pixels); + (this->*TextureImage2D)(texture, target, bindingTarget, level, internalFormat, width, height, border, format, type, pixels); } - inline void glTextureImage1D(GLuint texture, GLenum target, GLint level, GLenum internalFormat, + inline void glTextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels) { - (this->*TextureImage1D)(texture, target, level, internalFormat, width, border, format, type, pixels); + (this->*TextureImage1D)(texture, target, bindingTarget, level, internalFormat, width, border, format, type, pixels); } - inline void glTextureSubImage3D(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + inline void glTextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels, const QOpenGLPixelTransferOptions * const options = 0) { if (options) { QOpenGLPixelTransferOptions oldOptions = savePixelUploadOptions(); setPixelUploadOptions(*options); - (this->*TextureSubImage3D)(texture, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); + (this->*TextureSubImage3D)(texture, target, bindingTarget, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); setPixelUploadOptions(oldOptions); } else { - (this->*TextureSubImage3D)(texture, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); + (this->*TextureSubImage3D)(texture, target, bindingTarget, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); } } - inline void glTextureSubImage2D(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, + inline void glTextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels, const QOpenGLPixelTransferOptions * const options = 0) { if (options) { QOpenGLPixelTransferOptions oldOptions = savePixelUploadOptions(); setPixelUploadOptions(*options); - (this->*TextureSubImage2D)(texture, target, level, xoffset, yoffset, width, height, format, type, pixels); + (this->*TextureSubImage2D)(texture, target, bindingTarget, level, xoffset, yoffset, width, height, format, type, pixels); setPixelUploadOptions(oldOptions); } else { - (this->*TextureSubImage2D)(texture, target, level, xoffset, yoffset, width, height, format, type, pixels); + (this->*TextureSubImage2D)(texture, target, bindingTarget, level, xoffset, yoffset, width, height, format, type, pixels); } } - inline void glTextureSubImage1D(GLuint texture, GLenum target, GLint level, GLint xoffset, + inline void glTextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels, const QOpenGLPixelTransferOptions * const options = 0) { if (options) { QOpenGLPixelTransferOptions oldOptions = savePixelUploadOptions(); setPixelUploadOptions(*options); - (this->*TextureSubImage1D)(texture, target, level, xoffset, width, format, type, pixels); + (this->*TextureSubImage1D)(texture, target, bindingTarget, level, xoffset, width, format, type, pixels); setPixelUploadOptions(oldOptions); } else { - (this->*TextureSubImage1D)(texture, target, level, xoffset, width, format, type, pixels); + (this->*TextureSubImage1D)(texture, target, bindingTarget, level, xoffset, width, format, type, pixels); } } - inline void glTextureImage3DMultisample(GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, + inline void glTextureImage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations) { - (this->*TextureImage3DMultisample)(texture, target, samples, internalFormat, width, height, depth, fixedSampleLocations); + (this->*TextureImage3DMultisample)(texture, target, bindingTarget, samples, internalFormat, width, height, depth, fixedSampleLocations); } - inline void glTextureImage2DMultisample(GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, + inline void glTextureImage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations) { - (this->*TextureImage2DMultisample)(texture, target, samples, internalFormat, width, height, fixedSampleLocations); + (this->*TextureImage2DMultisample)(texture, target, bindingTarget, samples, internalFormat, width, height, fixedSampleLocations); } - inline void glCompressedTextureSubImage1D(GLuint texture, GLenum target, GLint level, + inline void glCompressedTextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits, const QOpenGLPixelTransferOptions * const options = 0) @@ -195,14 +195,14 @@ public: if (options) { QOpenGLPixelTransferOptions oldOptions = savePixelUploadOptions(); setPixelUploadOptions(*options); - (this->*CompressedTextureSubImage1D)(texture, target, level, xoffset, width, format, imageSize, bits); + (this->*CompressedTextureSubImage1D)(texture, target, bindingTarget, level, xoffset, width, format, imageSize, bits); setPixelUploadOptions(oldOptions); } else { - (this->*CompressedTextureSubImage1D)(texture, target, level, xoffset, width, format, imageSize, bits); + (this->*CompressedTextureSubImage1D)(texture, target, bindingTarget, level, xoffset, width, format, imageSize, bits); } } - inline void glCompressedTextureSubImage2D(GLuint texture, GLenum target, GLint level, + inline void glCompressedTextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits, @@ -211,14 +211,14 @@ public: if (options) { QOpenGLPixelTransferOptions oldOptions = savePixelUploadOptions(); setPixelUploadOptions(*options); - (this->*CompressedTextureSubImage2D)(texture, target, level, xoffset, yoffset, width, height, format, imageSize, bits); + (this->*CompressedTextureSubImage2D)(texture, target, bindingTarget, level, xoffset, yoffset, width, height, format, imageSize, bits); setPixelUploadOptions(oldOptions); } else { - (this->*CompressedTextureSubImage2D)(texture, target, level, xoffset, yoffset, width, height, format, imageSize, bits); + (this->*CompressedTextureSubImage2D)(texture, target, bindingTarget, level, xoffset, yoffset, width, height, format, imageSize, bits); } } - inline void glCompressedTextureSubImage3D(GLuint texture, GLenum target, GLint level, + inline void glCompressedTextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits, @@ -227,443 +227,200 @@ public: if (options) { QOpenGLPixelTransferOptions oldOptions = savePixelUploadOptions(); setPixelUploadOptions(*options); - (this->*CompressedTextureSubImage3D)(texture, target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, bits); + (this->*CompressedTextureSubImage3D)(texture, target, bindingTarget, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, bits); setPixelUploadOptions(oldOptions); } else { - (this->*CompressedTextureSubImage3D)(texture, target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, bits); + (this->*CompressedTextureSubImage3D)(texture, target, bindingTarget, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, bits); } } - inline void glCompressedTextureImage1D(GLuint texture, GLenum target, GLint level, + inline void glCompressedTextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits) { - (this->*CompressedTextureImage1D)(texture, target, level, internalFormat, width, border, imageSize, bits); + (this->*CompressedTextureImage1D)(texture, target, bindingTarget, level, internalFormat, width, border, imageSize, bits); } - inline void glCompressedTextureImage2D(GLuint texture, GLenum target, GLint level, + inline void glCompressedTextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits) { - (this->*CompressedTextureImage2D)(texture, target, level, internalFormat, width, height, border, imageSize, bits); + (this->*CompressedTextureImage2D)(texture, target, bindingTarget, level, internalFormat, width, height, border, imageSize, bits); } - inline void glCompressedTextureImage3D(GLuint texture, GLenum target, GLint level, + inline void glCompressedTextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits) { - (this->*CompressedTextureImage3D)(texture, target, level, internalFormat, width, height, depth, border, imageSize, bits); + (this->*CompressedTextureImage3D)(texture, target, bindingTarget, level, internalFormat, width, height, depth, border, imageSize, bits); } private: -#if !defined(QT_OPENGL_ES_2) // DSA wrapper (so we can use pointer to member function as switch) - inline void dsa_TextureParameteri(GLuint texture, GLenum target, GLenum pname, GLint param) - { - TextureParameteriEXT(texture, target, pname, param); - } + void dsa_TextureParameteri(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLint param); - inline void dsa_TextureParameteriv(GLuint texture, GLenum target, GLenum pname, const GLint *params) - { - TextureParameterivEXT(texture, target, pname, params); - } + void dsa_TextureParameteriv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLint *params); - inline void dsa_TextureParameterf(GLuint texture, GLenum target, GLenum pname, GLfloat param) - { - TextureParameterfEXT(texture, target, pname, param); - } + void dsa_TextureParameterf(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLfloat param); - inline void dsa_TextureParameterfv(GLuint texture, GLenum target, GLenum pname, const GLfloat *params) - { - TextureParameterfvEXT(texture, target, pname, params); - } + void dsa_TextureParameterfv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLfloat *params); - inline void dsa_GenerateTextureMipmap(GLuint texture, GLenum target) - { - GenerateTextureMipmapEXT(texture, target); - } + void dsa_GenerateTextureMipmap(GLuint texture, GLenum target, GLenum bindingTarget); - inline void dsa_TextureStorage3D(GLuint texture, GLenum target, GLsizei levels, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei depth) - { - TextureStorage3DEXT(texture, target, levels, internalFormat, width, height, depth); - } + void dsa_TextureStorage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, + GLsizei width, GLsizei height, GLsizei depth); - inline void dsa_TextureStorage2D(GLuint texture, GLenum target, GLsizei levels, GLenum internalFormat, - GLsizei width, GLsizei height) - { - TextureStorage2DEXT(texture, target, levels, internalFormat, width, height); - } + void dsa_TextureStorage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, + GLsizei width, GLsizei height); - inline void dsa_TextureStorage1D(GLuint texture, GLenum target, GLsizei levels, GLenum internalFormat, - GLsizei width) - { - TextureStorage1DEXT(texture, target, levels, internalFormat, width); - } + void dsa_TextureStorage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, + GLsizei width); - inline void dsa_TextureStorage3DMultisample(GLuint texture, GLenum target, GLsizei samples, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations) - { - TextureStorage3DMultisampleEXT(texture, target, samples, internalFormat, width, height, depth, fixedSampleLocations); - } + void dsa_TextureStorage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, + GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); - inline void dsa_TextureStorage2DMultisample(GLuint texture, GLenum target, GLsizei samples, GLenum internalFormat, - GLsizei width, GLsizei height, GLboolean fixedSampleLocations) - { - TextureStorage2DMultisampleEXT(texture, target, samples, internalFormat, width, height, fixedSampleLocations); - } + void dsa_TextureStorage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, + GLsizei width, GLsizei height, GLboolean fixedSampleLocations); - inline void dsa_TextureImage3D(GLuint texture, GLenum target, GLint level, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) - { - TextureImage3DEXT(texture, target, level, internalFormat, width, height, depth, border, format, type, pixels); - } + void dsa_TextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, + GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - inline void dsa_TextureImage2D(GLuint texture, GLenum target, GLint level, GLenum internalFormat, - GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) - { - TextureImage2DEXT(texture, target, level, internalFormat, width, height, border, format, type, pixels); - } + void dsa_TextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, + GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - inline void dsa_TextureImage1D(GLuint texture, GLenum target, GLint level, GLenum internalFormat, - GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels) - { - TextureImage1DEXT(texture, target, level, internalFormat, width, border, format, type, pixels); - } + void dsa_TextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, + GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - inline void dsa_TextureSubImage3D(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) - { - TextureSubImage3DEXT(texture, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); - } + void dsa_TextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); - inline void dsa_TextureSubImage2D(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) - { - TextureSubImage2DEXT(texture, target, level, xoffset, yoffset, width, height, format, type, pixels); - } + void dsa_TextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); - inline void dsa_TextureSubImage1D(GLuint texture, GLenum target, GLint level, GLint xoffset, - GLsizei width, GLenum format, GLenum type, const GLvoid *pixels) - { - TextureSubImage1DEXT(texture, target, level, xoffset, width, format, type, pixels); - } + void dsa_TextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, + GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); - inline void dsa_TextureImage3DMultisample(GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, - GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations) - { - TextureImage3DMultisampleNV(texture, target, samples, internalFormat, width, height, depth, fixedSampleLocations); - } + void dsa_TextureImage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, + GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); - inline void dsa_TextureImage2DMultisample(GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, - GLsizei width, GLsizei height, GLboolean fixedSampleLocations) - { - TextureImage2DMultisampleNV(texture, target, samples, internalFormat, width, height, fixedSampleLocations); - } + void dsa_TextureImage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, + GLsizei width, GLsizei height, GLboolean fixedSampleLocations); - inline void dsa_CompressedTextureSubImage1D(GLuint texture, GLenum target, GLint level, - GLint xoffset, GLsizei width, - GLenum format, GLsizei imageSize, const GLvoid *bits) - { - CompressedTextureSubImage1DEXT(texture, target, level, xoffset, width, format, imageSize, bits); - } + void dsa_CompressedTextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, + GLint xoffset, GLsizei width, + GLenum format, GLsizei imageSize, const GLvoid *bits); - inline void dsa_CompressedTextureSubImage2D(GLuint texture, GLenum target, GLint level, - GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, - GLenum format, GLsizei imageSize, const GLvoid *bits) - { - CompressedTextureSubImage2DEXT(texture, target, level, xoffset, yoffset, width, height, format, imageSize, bits); - } + void dsa_CompressedTextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLsizei imageSize, const GLvoid *bits); - inline void dsa_CompressedTextureSubImage3D(GLuint texture, GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLsizei imageSize, const GLvoid *bits) - { - CompressedTextureSubImage3DEXT(texture, target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, bits); - } + void dsa_CompressedTextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLsizei imageSize, const GLvoid *bits); - inline void dsa_CompressedTextureImage1D(GLuint texture, GLenum target, GLint level, - GLenum internalFormat, GLsizei width, - GLint border, GLsizei imageSize, const GLvoid *bits) - { - CompressedTextureImage1DEXT(texture, target, level, internalFormat, width, border, imageSize, bits); - } + void dsa_CompressedTextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, + GLenum internalFormat, GLsizei width, + GLint border, GLsizei imageSize, const GLvoid *bits); - inline void dsa_CompressedTextureImage2D(GLuint texture, GLenum target, GLint level, - GLenum internalFormat, GLsizei width, GLsizei height, - GLint border, GLsizei imageSize, const GLvoid *bits) - { - CompressedTextureImage2DEXT(texture, target, level, internalFormat, width, height, border, imageSize, bits); - } + void dsa_CompressedTextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, + GLenum internalFormat, GLsizei width, GLsizei height, + GLint border, GLsizei imageSize, const GLvoid *bits); - inline void dsa_CompressedTextureImage3D(GLuint texture, GLenum target, GLint level, - GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, - GLint border, GLsizei imageSize, const GLvoid *bits) - { - CompressedTextureImage3DEXT(texture, target, level, internalFormat, width, height, depth, border, imageSize, bits); - } -#endif + void dsa_CompressedTextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, + GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLsizei imageSize, const GLvoid *bits); + // DSA emulation API + void qt_TextureParameteri(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLint param); - // DSA-like API - inline void qt_TextureParameteri(GLuint texture, GLenum target, GLenum pname, GLint param) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glTexParameteri(target, pname, param); - glBindTexture(target, oldTexture); - } + void qt_TextureParameteriv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLint *params); - inline void qt_TextureParameteriv(GLuint texture, GLenum target, GLenum pname, const GLint *params) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glTexParameteriv(target, pname, params); - glBindTexture(target, oldTexture); - } + void qt_TextureParameterf(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLfloat param); - inline void qt_TextureParameterf(GLuint texture, GLenum target, GLenum pname, GLfloat param) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glTexParameterf(target, pname, param); - glBindTexture(target, oldTexture); - } + void qt_TextureParameterfv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLfloat *params); - inline void qt_TextureParameterfv(GLuint texture, GLenum target, GLenum pname, const GLfloat *params) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glTexParameterfv(target, pname, params); - glBindTexture(target, oldTexture); - } + void qt_GenerateTextureMipmap(GLuint texture, GLenum target, GLenum bindingTarget); - inline void qt_GenerateTextureMipmap(GLuint texture, GLenum target) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glGenerateMipmap(target); - glBindTexture(target, oldTexture); - } - - inline void qt_TextureStorage3D(GLuint texture, GLenum target, GLsizei levels, - GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glTexStorage3D(target, levels, internalFormat, width, height, depth); - glBindTexture(target, oldTexture); - } + void qt_TextureStorage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, + GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth); - inline void qt_TextureStorage2D(GLuint texture, GLenum target, GLsizei levels, - GLenum internalFormat, GLsizei width, GLsizei height) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glTexStorage2D(target, levels, internalFormat, width, height); - glBindTexture(target, oldTexture); - } + void qt_TextureStorage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, + GLenum internalFormat, GLsizei width, GLsizei height); - inline void qt_TextureStorage1D(GLuint texture, GLenum target, GLsizei levels, - GLenum internalFormat, GLsizei width) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glTexStorage1D(target, levels, internalFormat, width); - glBindTexture(target, oldTexture); - } + void qt_TextureStorage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, + GLenum internalFormat, GLsizei width); - inline void qt_TextureStorage3DMultisample(GLuint texture, GLenum target, GLsizei samples, - GLenum internalFormat, GLsizei width, GLsizei height, - GLsizei depth, GLboolean fixedSampleLocations) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glTexStorage3DMultisample(target, samples, internalFormat, width, height, depth, fixedSampleLocations); - glBindTexture(target, oldTexture); - } + void qt_TextureStorage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, + GLenum internalFormat, GLsizei width, GLsizei height, + GLsizei depth, GLboolean fixedSampleLocations); - inline void qt_TextureStorage2DMultisample(GLuint texture, GLenum target, GLsizei samples, - GLenum internalFormat, GLsizei width, GLsizei height, - GLboolean fixedSampleLocations) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glTexStorage2DMultisample(target, samples, internalFormat, width, height, fixedSampleLocations); - glBindTexture(target, oldTexture); - } + void qt_TextureStorage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, + GLenum internalFormat, GLsizei width, GLsizei height, + GLboolean fixedSampleLocations); - inline void qt_TextureImage3D(GLuint texture, GLenum target, GLint level, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei depth, - GLint border, GLenum format, GLenum type, - const GLvoid *pixels) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, pixels); - glBindTexture(target, oldTexture); - } + void qt_TextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, + GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, + const GLvoid *pixels); - inline void qt_TextureImage2D(GLuint texture, GLenum target, GLint level, GLenum internalFormat, - GLsizei width, GLsizei height, - GLint border, GLenum format, GLenum type, - const GLvoid *pixels) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glTexImage2D(target, level, internalFormat, width, height, border, format, type, pixels); - glBindTexture(target, oldTexture); - } + void qt_TextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, + GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, + const GLvoid *pixels); - inline void qt_TextureImage1D(GLuint texture, GLenum target, GLint level, GLenum internalFormat, - GLsizei width, GLint border, GLenum format, GLenum type, - const GLvoid *pixels) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glTexImage1D(target, level, internalFormat, width, border, format, type, pixels); - glBindTexture(target, oldTexture); - } + void qt_TextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, + GLsizei width, GLint border, GLenum format, GLenum type, + const GLvoid *pixels); - inline void qt_TextureSubImage3D(GLuint texture, GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *pixels) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); - glBindTexture(target, oldTexture); - } + void qt_TextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *pixels); - inline void qt_TextureSubImage2D(GLuint texture, GLenum target, GLint level, - GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, - GLenum format, GLenum type, const GLvoid *pixels) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); - glBindTexture(target, oldTexture); - } + void qt_TextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLenum type, const GLvoid *pixels); - inline void qt_TextureSubImage1D(GLuint texture, GLenum target, GLint level, - GLint xoffset, GLsizei width, - GLenum format, GLenum type, const GLvoid *pixels) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glTexSubImage1D(target, level, xoffset, width, format, type, pixels); - glBindTexture(target, oldTexture); - } + void qt_TextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, + GLint xoffset, GLsizei width, + GLenum format, GLenum type, const GLvoid *pixels); - inline void qt_TextureImage3DMultisample(GLuint texture, GLenum target, GLsizei samples, - GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, - GLboolean fixedSampleLocations) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glTexImage3DMultisample(target, samples, internalFormat, width, height, depth, fixedSampleLocations); - glBindTexture(target, oldTexture); - } + void qt_TextureImage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, + GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, + GLboolean fixedSampleLocations); - inline void qt_TextureImage2DMultisample(GLuint texture, GLenum target, GLsizei samples, - GLint internalFormat, GLsizei width, GLsizei height, - GLboolean fixedSampleLocations) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glTexImage2DMultisample(target, samples, internalFormat, width, height, fixedSampleLocations); - glBindTexture(target, oldTexture); - } + void qt_TextureImage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, + GLint internalFormat, GLsizei width, GLsizei height, + GLboolean fixedSampleLocations); - inline void qt_CompressedTextureSubImage1D(GLuint texture, GLenum target, GLint level, - GLint xoffset, GLsizei width, GLenum format, - GLsizei imageSize, const GLvoid *bits) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glCompressedTexSubImage1D(target, level, xoffset, width, format, imageSize, bits); - glBindTexture(target, oldTexture); - } + void qt_CompressedTextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, + GLint xoffset, GLsizei width, GLenum format, + GLsizei imageSize, const GLvoid *bits); - inline void qt_CompressedTextureSubImage2D(GLuint texture, GLenum target, GLint level, - GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, - GLenum format, GLsizei imageSize, const GLvoid *bits) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, bits); - glBindTexture(target, oldTexture); - } + void qt_CompressedTextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLsizei imageSize, const GLvoid *bits); - inline void qt_CompressedTextureSubImage3D(GLuint texture, GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLsizei imageSize, const GLvoid *bits) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, bits); - glBindTexture(target, oldTexture); - } + void qt_CompressedTextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLsizei imageSize, const GLvoid *bits); - inline void qt_CompressedTextureImage1D(GLuint texture, GLenum target, GLint level, GLenum internalFormat, - GLsizei width, GLint border, - GLsizei imageSize, const GLvoid *bits) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glCompressedTexImage1D(target, level, internalFormat, width, border, imageSize, bits); - glBindTexture(target, oldTexture); - } + void qt_CompressedTextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, + GLsizei width, GLint border, + GLsizei imageSize, const GLvoid *bits); - inline void qt_CompressedTextureImage2D(GLuint texture, GLenum target, GLint level, GLenum internalFormat, - GLsizei width, GLsizei height, GLint border, - GLsizei imageSize, const GLvoid *bits) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glCompressedTexImage2D(target, level, internalFormat, width, height, border, imageSize, bits); - glBindTexture(target, oldTexture); - } + void qt_CompressedTextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, + GLsizei width, GLsizei height, GLint border, + GLsizei imageSize, const GLvoid *bits); - inline void qt_CompressedTextureImage3D(GLuint texture, GLenum target, GLint level, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei depth, GLint border, - GLsizei imageSize, const GLvoid *bits) - { - GLint oldTexture; - glGetIntegerv(target, &oldTexture); - glBindTexture(target, texture); - glCompressedTexImage3D(target, level, internalFormat, width, height, depth, border, imageSize, bits); - glBindTexture(target, oldTexture); - } + void qt_CompressedTextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, + GLsizei width, GLsizei height, GLsizei depth, GLint border, + GLsizei imageSize, const GLvoid *bits); public: // Raw OpenGL functions, resolved and used by our DSA-like static functions if no EXT_direct_state_access is available @@ -936,31 +693,33 @@ public: } private: - // Typedefs and pointers to member functions used to switch between EXT_direct_state_access and our own emulated DSA - typedef void (QOpenGLTextureHelper::*TextureParameteriMemberFunc)(GLuint texture, GLenum target, GLenum pname, GLint param); - typedef void (QOpenGLTextureHelper::*TextureParameterivMemberFunc)(GLuint texture, GLenum target, GLenum pname, const GLint *params); - typedef void (QOpenGLTextureHelper::*TextureParameterfMemberFunc)(GLuint texture, GLenum target, GLenum pname, GLfloat param); - typedef void (QOpenGLTextureHelper::*TextureParameterfvMemberFunc)(GLuint texture, GLenum target, GLenum pname, const GLfloat *params); - typedef void (QOpenGLTextureHelper::*GenerateTextureMipmapMemberFunc)(GLuint texture, GLenum target); - typedef void (QOpenGLTextureHelper::*TextureStorage3DMemberFunc)(GLuint texture, GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth); - typedef void (QOpenGLTextureHelper::*TextureStorage2DMemberFunc)(GLuint texture, GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height); - typedef void (QOpenGLTextureHelper::*TextureStorage1DMemberFunc)(GLuint texture, GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width); - typedef void (QOpenGLTextureHelper::*TextureStorage3DMultisampleMemberFunc)(GLuint texture, GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); - typedef void (QOpenGLTextureHelper::*TextureStorage2DMultisampleMemberFunc)(GLuint texture, GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); - typedef void (QOpenGLTextureHelper::*TextureImage3DMemberFunc)(GLuint texture, GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - typedef void (QOpenGLTextureHelper::*TextureImage2DMemberFunc)(GLuint texture, GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - typedef void (QOpenGLTextureHelper::*TextureImage1DMemberFunc)(GLuint texture, GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - typedef void (QOpenGLTextureHelper::*TextureSubImage3DMemberFunc)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); - typedef void (QOpenGLTextureHelper::*TextureSubImage2DMemberFunc)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); - typedef void (QOpenGLTextureHelper::*TextureSubImage1DMemberFunc)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); - typedef void (QOpenGLTextureHelper::*TextureImage3DMultisampleMemberFunc)(GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); - typedef void (QOpenGLTextureHelper::*TextureImage2DMultisampleMemberFunc)(GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); - typedef void (QOpenGLTextureHelper::*CompressedTextureSubImage1DMemberFunc)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); - typedef void (QOpenGLTextureHelper::*CompressedTextureSubImage2DMemberFunc)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); - typedef void (QOpenGLTextureHelper::*CompressedTextureSubImage3DMemberFunc)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); - typedef void (QOpenGLTextureHelper::*CompressedTextureImage1DMemberFunc)(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); - typedef void (QOpenGLTextureHelper::*CompressedTextureImage2DMemberFunc)(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); - typedef void (QOpenGLTextureHelper::*CompressedTextureImage3DMemberFunc)(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); + // Typedefs and pointers to member functions used to switch between EXT_direct_state_access and our own emulated DSA. + // The argument match the corresponding GL function, but there's an extra "GLenum bindingTarget" which gets used with + // the DSA emulation -- it contains the right GL_BINDING_TEXTURE_X to use. + typedef void (QOpenGLTextureHelper::*TextureParameteriMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLint param); + typedef void (QOpenGLTextureHelper::*TextureParameterivMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLint *params); + typedef void (QOpenGLTextureHelper::*TextureParameterfMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLfloat param); + typedef void (QOpenGLTextureHelper::*TextureParameterfvMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLfloat *params); + typedef void (QOpenGLTextureHelper::*GenerateTextureMipmapMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget); + typedef void (QOpenGLTextureHelper::*TextureStorage3DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth); + typedef void (QOpenGLTextureHelper::*TextureStorage2DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height); + typedef void (QOpenGLTextureHelper::*TextureStorage1DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width); + typedef void (QOpenGLTextureHelper::*TextureStorage3DMultisampleMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); + typedef void (QOpenGLTextureHelper::*TextureStorage2DMultisampleMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); + typedef void (QOpenGLTextureHelper::*TextureImage3DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); + typedef void (QOpenGLTextureHelper::*TextureImage2DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); + typedef void (QOpenGLTextureHelper::*TextureImage1DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); + typedef void (QOpenGLTextureHelper::*TextureSubImage3DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); + typedef void (QOpenGLTextureHelper::*TextureSubImage2DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); + typedef void (QOpenGLTextureHelper::*TextureSubImage1DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); + typedef void (QOpenGLTextureHelper::*TextureImage3DMultisampleMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); + typedef void (QOpenGLTextureHelper::*TextureImage2DMultisampleMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); + typedef void (QOpenGLTextureHelper::*CompressedTextureSubImage1DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); + typedef void (QOpenGLTextureHelper::*CompressedTextureSubImage2DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); + typedef void (QOpenGLTextureHelper::*CompressedTextureSubImage3DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); + typedef void (QOpenGLTextureHelper::*CompressedTextureImage1DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); + typedef void (QOpenGLTextureHelper::*CompressedTextureImage2DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); + typedef void (QOpenGLTextureHelper::*CompressedTextureImage3DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); TextureParameteriMemberFunc TextureParameteri; @@ -988,7 +747,6 @@ private: CompressedTextureImage2DMemberFunc CompressedTextureImage2D; CompressedTextureImage3DMemberFunc CompressedTextureImage3D; -#if !defined(QT_OPENGL_ES_2) // Raw function pointers for core and DSA functions // EXT_direct_state_access used when DSA is available @@ -1019,7 +777,6 @@ private: // Plus some missing ones that are in the NV_texture_multisample extension instead void (QOPENGLF_APIENTRYP TextureImage3DMultisampleNV)(GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); void (QOPENGLF_APIENTRYP TextureImage2DMultisampleNV)(GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); -#endif // OpenGL 1.0 void (QOPENGLF_APIENTRYP GetIntegerv)(GLenum pname, GLint *params); diff --git a/src/gui/opengl/qopengltimerquery.cpp b/src/gui/opengl/qopengltimerquery.cpp index c5c3d42e5d..deb88b7778 100644 --- a/src/gui/opengl/qopengltimerquery.cpp +++ b/src/gui/opengl/qopengltimerquery.cpp @@ -44,6 +44,7 @@ #include "qopenglqueryhelper_p.h" #include <QtCore/private/qobject_p.h> #include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLFunctions> QT_BEGIN_NAMESPACE @@ -123,6 +124,11 @@ public: bool QOpenGLTimerQueryPrivate::create() { + if (QOpenGLFunctions::isES()) { + qWarning("QOpenGLTimerQuery: Not supported on dynamic GL ES"); + return false; + } + QOpenGLContext *ctx = QOpenGLContext::currentContext(); if (timer && context == ctx) diff --git a/src/gui/opengl/qopenglvertexarrayobject.cpp b/src/gui/opengl/qopenglvertexarrayobject.cpp index ee8abde77b..e26c6ec25a 100644 --- a/src/gui/opengl/qopenglvertexarrayobject.cpp +++ b/src/gui/opengl/qopenglvertexarrayobject.cpp @@ -43,6 +43,7 @@ #include <QtCore/private/qobject_p.h> #include <QtGui/qopenglcontext.h> +#include <QtGui/qopenglfunctions.h> #if !defined(QT_OPENGL_ES_2) #include <QtGui/qopenglfunctions_3_0.h> @@ -156,6 +157,13 @@ bool QOpenGLVertexArrayObjectPrivate::create() return false; } +#if !defined(QT_OPENGL_ES_2) + if (QOpenGLFunctions::isES()) { + qWarning("QOpenGLVertexArrayObject: Not supported on dynamic GL ES"); + return false; + } +#endif + Q_Q(QOpenGLVertexArrayObject); if (context) QObject::disconnect(context, SIGNAL(aboutToBeDestroyed()), q, SLOT(_q_contextAboutToBeDestroyed())); diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index aadcc0f686..6bf80eddbd 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -87,14 +87,15 @@ SOURCES += \ painting/qpaintbuffer.cpp \ painting/qpathsimplifier.cpp -SSE2_SOURCES += painting/qdrawhelper_sse2.cpp -SSSE3_SOURCES += painting/qdrawhelper_ssse3.cpp +contains(QT_CPU_FEATURES.$$QT_ARCH, sse2) { + SOURCES += painting/qdrawhelper_sse2.cpp + SSSE3_SOURCES += painting/qdrawhelper_ssse3.cpp +} IWMMXT_SOURCES += painting/qdrawhelper_iwmmxt.cpp -AVX_SOURCES += painting/qdrawhelper_avx.cpp -!ios { - NEON_SOURCES += painting/qdrawhelper_neon.cpp - NEON_HEADERS += painting/qdrawhelper_neon_p.h +!ios:contains(QT_CPU_FEATURES.$$QT_ARCH, neon) { + SOURCES += painting/qdrawhelper_neon.cpp + HEADERS += painting/qdrawhelper_neon_p.h NEON_ASM += ../3rdparty/pixman/pixman-arm-neon-asm.S painting/qdrawhelper_neon_asm.S } diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp index 8bbe6b6f42..b35fa38ce0 100644 --- a/src/gui/painting/qbrush.cpp +++ b/src/gui/painting/qbrush.cpp @@ -56,44 +56,49 @@ QT_BEGIN_NAMESPACE const uchar *qt_patternForBrush(int brushStyle, bool invert) { Q_ASSERT(brushStyle > Qt::SolidPattern && brushStyle < Qt::LinearGradientPattern); - if(invert) { - static const uchar dense1_pat[] = { 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff }; - static const uchar dense2_pat[] = { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff }; - static const uchar dense3_pat[] = { 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55, 0xee }; - static const uchar dense4_pat[] = { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 }; - static const uchar dense5_pat[] = { 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa, 0x11 }; - static const uchar dense6_pat[] = { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 }; - static const uchar dense7_pat[] = { 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00 }; - static const uchar hor_pat[] = { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }; - static const uchar ver_pat[] = { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }; - static const uchar cross_pat[] = { 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0x10 }; - static const uchar bdiag_pat[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; - static const uchar fdiag_pat[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; - static const uchar dcross_pat[] = { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }; - static const uchar *const pat_tbl[] = { - dense1_pat, dense2_pat, dense3_pat, dense4_pat, dense5_pat, - dense6_pat, dense7_pat, - hor_pat, ver_pat, cross_pat, bdiag_pat, fdiag_pat, dcross_pat }; - return pat_tbl[brushStyle - Qt::Dense1Pattern]; - } - static const uchar dense1_pat[] = { 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00 }; - static const uchar dense2_pat[] = { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 }; - static const uchar dense3_pat[] = { 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa, 0x11 }; - static const uchar dense4_pat[] = { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa }; - static const uchar dense5_pat[] = { 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55, 0xee }; - static const uchar dense6_pat[] = { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff }; - static const uchar dense7_pat[] = { 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff }; - static const uchar hor_pat[] = { 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff }; - static const uchar ver_pat[] = { 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef }; - static const uchar cross_pat[] = { 0xef, 0xef, 0xef, 0x00, 0xef, 0xef, 0xef, 0xef }; - static const uchar bdiag_pat[] = { 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe }; - static const uchar fdiag_pat[] = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f }; - static const uchar dcross_pat[] = { 0x7e, 0xbd, 0xdb, 0xe7, 0xe7, 0xdb, 0xbd, 0x7e }; - static const uchar *const pat_tbl[] = { - dense1_pat, dense2_pat, dense3_pat, dense4_pat, dense5_pat, - dense6_pat, dense7_pat, - hor_pat, ver_pat, cross_pat, bdiag_pat, fdiag_pat, dcross_pat }; - return pat_tbl[brushStyle - Qt::Dense1Pattern]; + static const uchar pat_tbl[][2][8] = { + { + /* dense1 */ { 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00 }, + /*~dense1 */ { 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff }, + }, { + /* dense2 */ { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 }, + /*~dense2 */ { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff }, + }, { + /* dense3 */ { 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa, 0x11 }, + /*~dense3 */ { 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55, 0xee }, + }, { + /* dense4 */ { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa }, + /*~dense4 */ { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 }, + }, { + /* dense5 */ { 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55, 0xee }, + /*~dense5 */ { 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa, 0x11 }, + }, { + /* dense6 */ { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff }, + /*~dense6 */ { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 }, + }, { + /* dense7 */ { 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff }, + /*~dense7 */ { 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00 }, + }, { + /* hor */ { 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff }, + /*~hor */ { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }, + }, { + /* ver */ { 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef }, + /*~ver */ { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, + }, { + /* cross */ { 0xef, 0xef, 0xef, 0x00, 0xef, 0xef, 0xef, 0xef }, + /*~cross */ { 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0x10 }, + }, { + /* bdiag */ { 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe }, + /*~bdiag */ { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, + }, { + /* fdiag */ { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f }, + /*~fdiag */ { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, + }, { + /* dcross */ { 0x7e, 0xbd, 0xdb, 0xe7, 0xe7, 0xdb, 0xbd, 0x7e }, + /*~dcross */ { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }, + }, + }; + return pat_tbl[brushStyle - Qt::Dense1Pattern][invert]; } QPixmap qt_pixmapForBrush(int brushStyle, bool invert) diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index 706273c151..b9d3ca888e 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -2499,6 +2499,41 @@ QDataStream &operator>>(QDataStream &stream, QColor &color) } #endif // QT_NO_DATASTREAM +// A table of precalculated results of 0x00ff00ff/alpha use by qUnpremultiply: +const uint qt_inv_premul_factor[256] = { + 0, 16711935, 8355967, 5570645, 4177983, 3342387, 2785322, 2387419, + 2088991, 1856881, 1671193, 1519266, 1392661, 1285533, 1193709, 1114129, + 1044495, 983055, 928440, 879575, 835596, 795806, 759633, 726605, + 696330, 668477, 642766, 618960, 596854, 576273, 557064, 539094, + 522247, 506422, 491527, 477483, 464220, 451673, 439787, 428511, + 417798, 407608, 397903, 388649, 379816, 371376, 363302, 355573, + 348165, 341059, 334238, 327685, 321383, 315319, 309480, 303853, + 298427, 293191, 288136, 283253, 278532, 273966, 269547, 265268, + 261123, 257106, 253211, 249431, 245763, 242201, 238741, 235379, + 232110, 228930, 225836, 222825, 219893, 217038, 214255, 211543, + 208899, 206320, 203804, 201348, 198951, 196611, 194324, 192091, + 189908, 187774, 185688, 183647, 181651, 179698, 177786, 175915, + 174082, 172287, 170529, 168807, 167119, 165464, 163842, 162251, + 160691, 159161, 157659, 156186, 154740, 153320, 151926, 150557, + 149213, 147893, 146595, 145321, 144068, 142837, 141626, 140436, + 139266, 138115, 136983, 135869, 134773, 133695, 132634, 131590, + 130561, 129549, 128553, 127572, 126605, 125653, 124715, 123792, + 122881, 121984, 121100, 120229, 119370, 118524, 117689, 116866, + 116055, 115254, 114465, 113686, 112918, 112160, 111412, 110675, + 109946, 109228, 108519, 107818, 107127, 106445, 105771, 105106, + 104449, 103800, 103160, 102527, 101902, 101284, 100674, 100071, + 99475, 98887, 98305, 97730, 97162, 96600, 96045, 95496, + 94954, 94417, 93887, 93362, 92844, 92331, 91823, 91322, + 90825, 90334, 89849, 89368, 88893, 88422, 87957, 87497, + 87041, 86590, 86143, 85702, 85264, 84832, 84403, 83979, + 83559, 83143, 82732, 82324, 81921, 81521, 81125, 80733, + 80345, 79961, 79580, 79203, 78829, 78459, 78093, 77729, + 77370, 77013, 76660, 76310, 75963, 75619, 75278, 74941, + 74606, 74275, 73946, 73620, 73297, 72977, 72660, 72346, + 72034, 71725, 71418, 71114, 70813, 70514, 70218, 69924, + 69633, 69344, 69057, 68773, 68491, 68211, 67934, 67659, + 67386, 67116, 66847, 66581, 66317, 66055, 65795, 65537 +}; /***************************************************************************** QColor global functions (documentation only) @@ -2581,6 +2616,26 @@ QDataStream &operator>>(QDataStream &stream, QColor &color) */ /*! + \fn QRgb qPremultiply(QRgb rgb) + \since 5.3 + \relates QColor + + Converts an unpremultiplied ARGB quadruplet \a rgb into a premultiplied ARGB quadruplet. + + \sa qUnpremultiply() +*/ + +/*! + \fn QRgb qUnpremultiply(QRgb rgb) + \since 5.3 + \relates QColor + + Converts a premultiplied ARGB quadruplet \a rgb into an unpremultiplied ARGB quadruplet. + + \sa qPremultiply() +*/ + +/*! \fn QColor QColor::convertTo(Spec colorSpec) const Creates a copy of \e this color in the format specified by \a colorSpec. diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index c71d75cf94..66481d4287 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -53,6 +53,13 @@ # endif #endif +#include <qglobal.h> +#ifdef Q_OS_IOS +// We don't build the NEON drawhelpers as they are implemented partly +// in GAS syntax assembly, which is not supported by the iOS toolchain. +#undef __ARM_NEON__ +#endif + #include <qstylehints.h> #include <qguiapplication.h> #include <qatomic.h> @@ -84,74 +91,254 @@ enum { // must be multiple of 4 for easier SIMD implementations static const int buffer_size = 2048; +#ifdef Q_COMPILER_CONSTEXPR + +template<QImage::Format> Q_DECL_CONSTEXPR uint redWidth(); +template<QImage::Format> Q_DECL_CONSTEXPR uint redShift(); +template<QImage::Format> Q_DECL_CONSTEXPR uint greenWidth(); +template<QImage::Format> Q_DECL_CONSTEXPR uint greenShift(); +template<QImage::Format> Q_DECL_CONSTEXPR uint blueWidth(); +template<QImage::Format> Q_DECL_CONSTEXPR uint blueShift(); +template<QImage::Format> Q_DECL_CONSTEXPR uint alphaWidth(); +template<QImage::Format> Q_DECL_CONSTEXPR uint alphaShift(); + +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB16>() { return 5; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB444>() { return 4; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB555>() { return 5; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB666>() { return 6; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; } +template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB16>() { return 11; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB444>() { return 8; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB555>() { return 10; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB666>() { return 12; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB888>() { return 16; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB4444_Premultiplied>() { return 8; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB8555_Premultiplied>() { return 18; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB8565_Premultiplied>() { return 19; } +template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB6666_Premultiplied>() { return 12; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB16>() { return 6; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB444>() { return 4; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB555>() { return 5; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB666>() { return 6; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB8565_Premultiplied>() { return 6; } +template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB16>() { return 5; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB444>() { return 4; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB555>() { return 5; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB666>() { return 6; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB4444_Premultiplied>() { return 4; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB8555_Premultiplied>() { return 13; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB8565_Premultiplied>() { return 13; } +template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB6666_Premultiplied>() { return 6; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB16>() { return 5; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB444>() { return 4; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB555>() { return 5; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB666>() { return 6; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB888>() { return 8; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; } +template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB16>() { return 0; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB444>() { return 0; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB555>() { return 0; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB666>() { return 0; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB888>() { return 0; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB4444_Premultiplied>() { return 0; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB8555_Premultiplied>() { return 8; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB8565_Premultiplied>() { return 8; } +template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB6666_Premultiplied>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB8555_Premultiplied>() { return 8; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB8565_Premultiplied>() { return 8; } +template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB4444_Premultiplied>() { return 12; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB8555_Premultiplied>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB8565_Premultiplied>() { return 0; } +template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB6666_Premultiplied>() { return 18; } + +template<QImage::Format> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel(); +template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB16>() { return QPixelLayout::BPP16; } +template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB444>() { return QPixelLayout::BPP16; } +template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB555>() { return QPixelLayout::BPP16; } +template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB666>() { return QPixelLayout::BPP24; } +template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB888>() { return QPixelLayout::BPP24; } +template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB4444_Premultiplied>() { return QPixelLayout::BPP16; } +template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8555_Premultiplied>() { return QPixelLayout::BPP24; } +template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8565_Premultiplied>() { return QPixelLayout::BPP24; } +template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB6666_Premultiplied>() { return QPixelLayout::BPP24; } + + +template<QImage::Format Format> +static const uint *QT_FASTCALL convertToRGB32(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1); + Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1); + Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1); + Q_CONSTEXPR uchar redLeftShift = 8 - redWidth<Format>(); + Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth<Format>(); + Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth<Format>(); + Q_CONSTEXPR uchar redRightShift = 2 * redWidth<Format>() - 8; + Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth<Format>() - 8; + Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth<Format>() - 8; + + for (int i = 0; i < count; ++i) { + uint red = (src[i] >> redShift<Format>()) & redMask; + uint green = (src[i] >> greenShift<Format>()) & greenMask; + uint blue = (src[i] >> blueShift<Format>()) & blueMask; + + red = ((red << redLeftShift) | (red >> redRightShift)) << 16; + green = ((green << greenLeftShift) | (green >> greenRightShift)) << 8; + blue = (blue << blueLeftShift) | (blue >> blueRightShift); + buffer[i] = 0xff000000 | red | green | blue; + } -// To convert in place, let 'dest' and 'src' be the same. -static const uint *QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, const uint *src, int count, - const QPixelLayout *, const QRgb *clut) -{ - for (int i = 0; i < count; ++i) - buffer[i] = PREMUL(clut[src[i]]); return buffer; } -static const uint *QT_FASTCALL convertPassThrough(uint *, const uint *src, int, - const QPixelLayout *, const QRgb *) +template<QImage::Format Format> +static const uint *QT_FASTCALL convertARGBPMToARGB32PM(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) { - return src; + Q_CONSTEXPR uint alphaMask = ((1 << alphaWidth<Format>()) - 1); + Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1); + Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1); + Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1); + + Q_CONSTEXPR uchar alphaLeftShift = 8 - alphaWidth<Format>(); + Q_CONSTEXPR uchar redLeftShift = 8 - redWidth<Format>(); + Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth<Format>(); + Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth<Format>(); + + Q_CONSTEXPR uchar alphaRightShift = 2 * alphaWidth<Format>() - 8; + Q_CONSTEXPR uchar redRightShift = 2 * redWidth<Format>() - 8; + Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth<Format>() - 8; + Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth<Format>() - 8; + + for (int i = 0; i < count; ++i) { + uint alpha = (src[i] >> alphaShift<Format>()) & alphaMask; + uint red = (src[i] >> redShift<Format>()) & redMask; + uint green = (src[i] >> greenShift<Format>()) & greenMask; + uint blue = (src[i] >> blueShift<Format>()) & blueMask; + + alpha = (alpha << alphaLeftShift) | (alpha >> alphaRightShift); + red = qMin(alpha, (red << redLeftShift) | (red >> redRightShift)); + green = qMin(alpha, (green << greenLeftShift) | (green >> greenRightShift)); + blue = qMin(alpha, (blue << blueLeftShift) | (blue >> blueRightShift)); + buffer[i] = (alpha << 24) | (red << 16) | (green << 8) | blue; + } + + return buffer; } -static const uint *QT_FASTCALL convertRGB16ToARGB32PM(uint *buffer, const uint *src, int count, +template<QImage::Format Format> +static const uint *QT_FASTCALL convertRGBFromARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) { - for (int i = 0; i < count; ++i) - buffer[i] = qConvertRgb16To32(src[i]); + Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1); + Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1); + Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1); + + Q_CONSTEXPR uchar redRightShift = 24 - redWidth<Format>(); + Q_CONSTEXPR uchar greenRightShift = 16 - greenWidth<Format>(); + Q_CONSTEXPR uchar blueRightShift = 8 - blueWidth<Format>(); + + for (int i = 0; i < count; ++i) { + const uint color = qUnpremultiply(src[i]); + const uint red = ((color >> redRightShift) & redMask) << redShift<Format>(); + const uint green = ((color >> greenRightShift) & greenMask) << greenShift<Format>(); + const uint blue = ((color >> blueRightShift) & blueMask) << blueShift<Format>(); + buffer[i] = red | green | blue; + } return buffer; } -static const uint *QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, const uint *src, int count, - const QPixelLayout *, const QRgb *) +template<QImage::Format Format> +static const uint *QT_FASTCALL convertRGBFromRGB32(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) { - for (int i = 0; i < count; ++i) - buffer[i] = PREMUL(src[i]); + Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1); + Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1); + Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1); + + Q_CONSTEXPR uchar redRightShift = 24 - redWidth<Format>(); + Q_CONSTEXPR uchar greenRightShift = 16 - greenWidth<Format>(); + Q_CONSTEXPR uchar blueRightShift = 8 - blueWidth<Format>(); + + for (int i = 0; i < count; ++i) { + const uint red = ((src[i] >> redRightShift) & redMask) << redShift<Format>(); + const uint green = ((src[i] >> greenRightShift) & greenMask) << greenShift<Format>(); + const uint blue = ((src[i] >> blueRightShift) & blueMask) << blueShift<Format>(); + buffer[i] = red | green | blue; + } return buffer; } -static const uint *QT_FASTCALL convertToRGB32(uint *buffer, const uint *src, int count, - const QPixelLayout *layout, const QRgb *) +template<QImage::Format Format> +static const uint *QT_FASTCALL convertARGBPMFromARGB32PM(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) { - Q_ASSERT(layout->redWidth >= 4); - Q_ASSERT(layout->greenWidth >= 4); - Q_ASSERT(layout->blueWidth >= 4); - Q_ASSERT(layout->alphaWidth == 0); - - const uint redMask = ((1 << layout->redWidth) - 1); - const uint greenMask = ((1 << layout->greenWidth) - 1); - const uint blueMask = ((1 << layout->blueWidth) - 1); - - const uchar redLeftShift = 8 - layout->redWidth; - const uchar greenLeftShift = 8 - layout->greenWidth; - const uchar blueLeftShift = 8 - layout->blueWidth; + Q_CONSTEXPR uint alphaMask = ((1 << alphaWidth<Format>()) - 1); + Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1); + Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1); + Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1); - const uchar redRightShift = 2 * layout->redWidth - 8; - const uchar greenRightShift = 2 * layout->greenWidth - 8; - const uchar blueRightShift = 2 * layout->blueWidth - 8; + Q_CONSTEXPR uchar alphaRightShift = 32 - alphaWidth<Format>(); + Q_CONSTEXPR uchar redRightShift = 24 - redWidth<Format>(); + Q_CONSTEXPR uchar greenRightShift = 16 - greenWidth<Format>(); + Q_CONSTEXPR uchar blueRightShift = 8 - blueWidth<Format>(); for (int i = 0; i < count; ++i) { - uint red = (src[i] >> layout->redShift) & redMask; - uint green = (src[i] >> layout->greenShift) & greenMask; - uint blue = (src[i] >> layout->blueShift) & blueMask; - - red = ((red << redLeftShift) | (red >> redRightShift)) << 16; - green = ((green << greenLeftShift) | (green >> greenRightShift)) << 8; - blue = (blue << blueLeftShift) | (blue >> blueRightShift); - buffer[i] = 0xff000000 | red | green | blue; + const uint alpha = ((src[i] >> alphaRightShift) & alphaMask) << alphaShift<Format>(); + const uint red = ((src[i] >> redRightShift) & redMask) << redShift<Format>(); + const uint green = ((src[i] >> greenRightShift) & greenMask) << greenShift<Format>(); + const uint blue = ((src[i] >> blueRightShift) & blueMask) << blueShift<Format>(); + buffer[i] = alpha | red | green | blue; } - return buffer; } +template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutRGB() +{ + return QPixelLayout{ + redWidth<Format>(), redShift<Format>(), + greenWidth<Format>(), greenShift<Format>(), + blueWidth<Format>(), blueShift<Format>(), + 0, 0, + false, bitsPerPixel<Format>(), + convertToRGB32<Format>, + convertRGBFromARGB32PM<Format>, + convertRGBFromRGB32<Format> + }; +} + +template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutARGBPM() +{ + return QPixelLayout{ + redWidth<Format>(), redShift<Format>(), + greenWidth<Format>(), greenShift<Format>(), + blueWidth<Format>(), blueShift<Format>(), + alphaWidth<Format>(), alphaShift<Format>(), + true, bitsPerPixel<Format>(), + convertARGBPMToARGB32PM<Format>, + convertARGBPMFromARGB32PM<Format>, + 0 + }; +} + +#else // CONSTEXPR + static const uint *QT_FASTCALL convertToARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *layout, const QRgb *) { @@ -200,25 +387,42 @@ static const uint *QT_FASTCALL convertToARGB32PM(uint *buffer, const uint *src, red = (red << redLeftShift) | (red >> redRightShift); green = (green << greenLeftShift) | (green >> greenRightShift); blue = (blue << blueLeftShift) | (blue >> blueRightShift); - buffer[i] = PREMUL((alpha << 24) | (red << 16) | (green << 8) | blue); + buffer[i] = qPremultiply((alpha << 24) | (red << 16) | (green << 8) | blue); } } return buffer; } -static const uint *QT_FASTCALL convertRGB16FromARGB32PM(uint *buffer, const uint *src, int count, - const QPixelLayout *, const QRgb *) +static const uint *QT_FASTCALL convertToRGB32(uint *buffer, const uint *src, int count, + const QPixelLayout *layout, const QRgb *) { - for (int i = 0; i < count; ++i) - buffer[i] = qConvertRgb32To16(INV_PREMUL(src[i])); - return buffer; -} + Q_ASSERT(layout->redWidth >= 4); + Q_ASSERT(layout->greenWidth >= 4); + Q_ASSERT(layout->blueWidth >= 4); + Q_ASSERT(layout->alphaWidth == 0); -static const uint *QT_FASTCALL convertARGB32FromARGB32PM(uint *buffer, const uint *src, int count, - const QPixelLayout *, const QRgb *) -{ - for (int i = 0; i < count; ++i) - buffer[i] = INV_PREMUL(src[i]); + const uint redMask = ((1 << layout->redWidth) - 1); + const uint greenMask = ((1 << layout->greenWidth) - 1); + const uint blueMask = ((1 << layout->blueWidth) - 1); + + const uchar redLeftShift = 8 - layout->redWidth; + const uchar greenLeftShift = 8 - layout->greenWidth; + const uchar blueLeftShift = 8 - layout->blueWidth; + + const uchar redRightShift = 2 * layout->redWidth - 8; + const uchar greenRightShift = 2 * layout->greenWidth - 8; + const uchar blueRightShift = 2 * layout->blueWidth - 8; + + for (int i = 0; i < count; ++i) { + uint red = (src[i] >> layout->redShift) & redMask; + uint green = (src[i] >> layout->greenShift) & greenMask; + uint blue = (src[i] >> layout->blueShift) & blueMask; + + red = (red << redLeftShift) | (red >> redRightShift); + green = (green << greenLeftShift) | (green >> greenRightShift); + blue = (blue << blueLeftShift) | (blue >> blueRightShift); + buffer[i] = 0xff000000 | (red << 16) | (green << 8) | blue; + } return buffer; } @@ -242,7 +446,7 @@ static const uint *QT_FASTCALL convertFromARGB32PM(uint *buffer, const uint *src if (!layout->premultiplied) { for (int i = 0; i < count; ++i) - buffer[i] = qAlpha(src[i]) == 255 ? src[i] : INV_PREMUL(src[i]); + buffer[i] = qUnpremultiply(src[i]); src = buffer; } for (int i = 0; i < count; ++i) { @@ -255,13 +459,14 @@ static const uint *QT_FASTCALL convertFromARGB32PM(uint *buffer, const uint *src return buffer; } -static const uint *QT_FASTCALL convertRGBFromARGB32PM(uint *buffer, const uint *src, int count, - const QPixelLayout *layout, const QRgb *) +static const uint *QT_FASTCALL convertFromRGB32(uint *buffer, const uint *src, int count, + const QPixelLayout *layout, const QRgb *) { Q_ASSERT(layout->redWidth <= 8); Q_ASSERT(layout->greenWidth <= 8); Q_ASSERT(layout->blueWidth <= 8); Q_ASSERT(layout->alphaWidth == 0); + Q_ASSERT(!layout->premultiplied); const uint redMask = (1 << layout->redWidth) - 1; const uint greenMask = (1 << layout->greenWidth) - 1; @@ -272,16 +477,118 @@ static const uint *QT_FASTCALL convertRGBFromARGB32PM(uint *buffer, const uint * const uchar blueRightShift = 8 - layout->blueWidth; for (int i = 0; i < count; ++i) { - uint color = INV_PREMUL(src[i]); - uint red = ((color >> redRightShift) & redMask) << layout->redShift; - uint green = ((color >> greenRightShift) & greenMask) << layout->greenShift; - uint blue = ((color >> blueRightShift) & blueMask) << layout->blueShift; - uint alpha = 0xff << layout->alphaShift; - buffer[i] = red | green | blue | alpha; + uint red = ((src[i] >> redRightShift) & redMask) << layout->redShift; + uint green = ((src[i] >> greenRightShift) & greenMask) << layout->greenShift; + uint blue = ((src[i] >> blueRightShift) & blueMask) << layout->blueShift; + buffer[i] = red | green | blue; } return buffer; } +static const uint *QT_FASTCALL convertRGB16ToRGB32(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qConvertRgb16To32(src[i]); + return buffer; +} + +static const uint *QT_FASTCALL convertRGB16FromRGB32(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qConvertRgb32To16(src[i]); + return buffer; +} + +static const uint *QT_FASTCALL convertRGB16FromARGB32PM(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qConvertRgb32To16(qUnpremultiply(src[i])); + return buffer; +} +#endif + +// To convert in place, let 'dest' and 'src' be the same. +static const uint *QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *clut) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qPremultiply(clut[src[i]]); + return buffer; +} + +static const uint *QT_FASTCALL convertPassThrough(uint *, const uint *src, int, + const QPixelLayout *, const QRgb *) +{ + return src; +} + +static const uint *QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qPremultiply(src[i]); + return buffer; +} + +static const uint *QT_FASTCALL convertRGBA8888PMToARGB32PM(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = RGBA2ARGB(src[i]); + return buffer; +} + +static const uint *QT_FASTCALL convertRGBA8888ToARGB32PM(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qPremultiply(RGBA2ARGB(src[i])); + return buffer; +} + +static const uint *QT_FASTCALL convertARGB32FromARGB32PM(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = qUnpremultiply(src[i]); + return buffer; +} + +static const uint *QT_FASTCALL convertRGBA8888PMFromARGB32PM(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = ARGB2RGBA(src[i]); + return buffer; +} + +static const uint *QT_FASTCALL convertRGBA8888FromARGB32PM(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = ARGB2RGBA(qUnpremultiply(src[i])); + return buffer; +} + +static const uint *QT_FASTCALL convertRGBXFromRGB32(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = ARGB2RGBA(0xff000000 | src[i]); + return buffer; +} + +static const uint *QT_FASTCALL convertRGBXFromARGB32PM(uint *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = ARGB2RGBA(0xff000000 | qUnpremultiply(src[i])); + return buffer; +} + template <QPixelLayout::BPP bpp> static uint QT_FASTCALL fetchPixel(const uchar *src, int index); @@ -392,30 +699,44 @@ inline void QT_FASTCALL storePixels<QPixelLayout::BPP32>(uchar *dest, const uint // convertFromArgb32() assumes that no color channel is more than 8 bits. // QImage::rgbSwapped() assumes that the red and blue color channels have the same number of bits. QPixelLayout qPixelLayouts[QImage::NImageFormats] = { - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPPNone, 0, 0 }, // Format_Invalid - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1MSB, convertIndexedToARGB32PM, 0 }, // Format_Mono - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1LSB, convertIndexedToARGB32PM, 0 }, // Format_MonoLSB - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertIndexedToARGB32PM, 0 }, // Format_Indexed8 - { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP32, convertPassThrough, convertPassThrough }, // Format_RGB32 - { 8, 16, 8, 8, 8, 0, 8, 24, false, QPixelLayout::BPP32, convertARGB32ToARGB32PM, convertARGB32FromARGB32PM }, // Format_ARGB32 - { 8, 16, 8, 8, 8, 0, 8, 24, true, QPixelLayout::BPP32, convertPassThrough, convertPassThrough }, // Format_ARGB32_Premultiplied - { 5, 11, 6, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, convertRGB16ToARGB32PM, convertRGB16FromARGB32PM }, // Format_RGB16 - { 5, 19, 6, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM }, // Format_ARGB8565_Premultiplied - { 6, 12, 6, 6, 6, 0, 0, 0, false, QPixelLayout::BPP24, convertToRGB32, convertFromARGB32PM }, // Format_RGB666 - { 6, 12, 6, 6, 6, 0, 6, 18, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM }, // Format_ARGB6666_Premultiplied - { 5, 10, 5, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32, convertFromARGB32PM }, // Format_RGB555 - { 5, 18, 5, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM }, // Format_ARGB8555_Premultiplied - { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP24, convertToRGB32, convertFromARGB32PM }, // Format_RGB888 - { 4, 8, 4, 4, 4, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32, convertFromARGB32PM }, // Format_RGB444 - { 4, 8, 4, 4, 4, 0, 4, 12, true, QPixelLayout::BPP16, convertToARGB32PM, convertFromARGB32PM }, // Format_ARGB4444_Premultiplied + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPPNone, 0, 0, 0 }, // Format_Invalid + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1MSB, convertIndexedToARGB32PM, 0, 0 }, // Format_Mono + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1LSB, convertIndexedToARGB32PM, 0, 0 }, // Format_MonoLSB + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertIndexedToARGB32PM, 0, 0 }, // Format_Indexed8 + // Technically using convertPassThrough to convert from ARGB32PM to RGB32 is wrong, + // but everywhere this generic conversion would be wrong is currently overloaed. + { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough }, // Format_RGB32 + { 8, 16, 8, 8, 8, 0, 8, 24, false, QPixelLayout::BPP32, convertARGB32ToARGB32PM, convertARGB32FromARGB32PM, 0 }, // Format_ARGB32 + { 8, 16, 8, 8, 8, 0, 8, 24, true, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, 0 }, // Format_ARGB32_Premultiplied +#ifdef Q_COMPILER_CONSTEXPR + pixelLayoutRGB<QImage::Format_RGB16>(), + pixelLayoutARGBPM<QImage::Format_ARGB8565_Premultiplied>(), + pixelLayoutRGB<QImage::Format_RGB666>(), + pixelLayoutARGBPM<QImage::Format_ARGB6666_Premultiplied>(), + pixelLayoutRGB<QImage::Format_RGB555>(), + pixelLayoutARGBPM<QImage::Format_ARGB8555_Premultiplied>(), + pixelLayoutRGB<QImage::Format_RGB888>(), + pixelLayoutRGB<QImage::Format_RGB444>(), + pixelLayoutARGBPM<QImage::Format_ARGB4444_Premultiplied>(), +#else + { 5, 11, 6, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, convertRGB16ToRGB32, convertRGB16FromARGB32PM, convertRGB16FromRGB32 }, // Format_RGB16 + { 5, 19, 6, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM, 0 }, // Format_ARGB8565_Premultiplied + { 6, 12, 6, 6, 6, 0, 0, 0, false, QPixelLayout::BPP24, convertToRGB32, convertFromARGB32PM, convertFromRGB32 }, // Format_RGB666 + { 6, 12, 6, 6, 6, 0, 6, 18, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM, 0 }, // Format_ARGB6666_Premultiplied + { 5, 10, 5, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32, convertFromARGB32PM, convertFromRGB32 }, // Format_RGB555 + { 5, 18, 5, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM, 0 }, // Format_ARGB8555_Premultiplied + { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP24, convertToRGB32, convertFromARGB32PM, convertFromRGB32 }, // Format_RGB888 + { 4, 8, 4, 4, 4, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32, convertFromARGB32PM, convertFromRGB32 }, // Format_RGB444 + { 4, 8, 4, 4, 4, 0, 4, 12, true, QPixelLayout::BPP16, convertToARGB32PM, convertFromARGB32PM, 0 }, // Format_ARGB4444_Premultiplied +#endif #if Q_BYTE_ORDER == Q_BIG_ENDIAN - { 8, 24, 8, 16, 8, 8, 0, 0, false, QPixelLayout::BPP32, convertToRGB32, convertRGBFromARGB32PM }, // Format_RGBX8888 - { 8, 24, 8, 16, 8, 8, 8, 0, false, QPixelLayout::BPP32, convertToARGB32PM, convertFromARGB32PM }, // Format_RGBA8888 - { 8, 24, 8, 16, 8, 8, 8, 0, true, QPixelLayout::BPP32, convertToARGB32PM, convertFromARGB32PM }, // Format_RGBA8888_Premultiplied + { 8, 24, 8, 16, 8, 8, 0, 0, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBX8888 + { 8, 24, 8, 16, 8, 8, 8, 0, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, 0 }, // Format_RGBA8888 + { 8, 24, 8, 16, 8, 8, 8, 0, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, 0 }, // Format_RGBA8888_Premultiplied #else - { 8, 0, 8, 8, 8, 16, 0, 24, false, QPixelLayout::BPP32, convertToRGB32, convertRGBFromARGB32PM }, // Format_RGBX8888 - { 8, 0, 8, 8, 8, 16, 8, 24, false, QPixelLayout::BPP32, convertToARGB32PM, convertFromARGB32PM }, // Format_RGBA8888 (ABGR32) - { 8, 0, 8, 8, 8, 16, 8, 24, true, QPixelLayout::BPP32, convertToARGB32PM, convertFromARGB32PM } // Format_RGBA8888_Premultiplied + { 8, 0, 8, 8, 8, 16, 0, 24, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBX8888 + { 8, 0, 8, 8, 8, 16, 8, 24, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, 0 }, // Format_RGBA8888 (ABGR32) + { 8, 0, 8, 8, 8, 16, 8, 24, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, 0 } // Format_RGBA8888_Premultiplied #endif }; @@ -532,9 +853,9 @@ static DestFetchProc destFetchProc[QImage::NImageFormats] = */ static inline QRgb findNearestColor(QRgb color, QRasterBuffer *rbuf) { - QRgb color_0 = PREMUL(rbuf->destColor0); - QRgb color_1 = PREMUL(rbuf->destColor1); - color = PREMUL(color); + QRgb color_0 = qPremultiply(rbuf->destColor0); + QRgb color_1 = qPremultiply(rbuf->destColor1); + color = qPremultiply(color); int r = qRed(color); int g = qGreen(color); @@ -630,7 +951,12 @@ static void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer, int x, int y, con uchar *dest = rasterBuffer->scanLine(y); while (length) { int l = qMin(length, buffer_size); - const uint *ptr = layout->convertFromARGB32PM(buf, buffer, l, layout, 0); + const uint *ptr = 0; + if (layout->convertFromRGB32) { + Q_ASSERT(!layout->premultiplied && !layout->alphaWidth); + ptr = layout->convertFromRGB32(buf, buffer, l, layout, 0); + } else + ptr = layout->convertFromARGB32PM(buf, buffer, l, layout, 0); store(dest, ptr, x, l); length -= l; buffer += l; @@ -891,7 +1217,7 @@ static inline uint interpolate_4_pixels_16(uint tl, uint tr, uint bl, uint br, i { uint distxy = distx * disty; //idistx * disty = (16-distx) * disty = 16*disty - distxy - //idistx * idisty = (16-distx) * (16-disty) = 16*16 - 16*distx -16*dity + distxy + //idistx * idisty = (16-distx) * (16-disty) = 16*16 - 16*distx -16*disty + distxy uint tlrb = (tl & 0x00ff00ff) * (16*16 - 16*distx - 16*disty + distxy); uint tlag = ((tl & 0xff00ff00) >> 8) * (16*16 - 16*distx - 16*disty + distxy); uint trrb = ((tr & 0x00ff00ff) * (distx*16 - distxy)); @@ -973,6 +1299,44 @@ static inline uint interpolate_4_pixels_16(uint tl, uint tr, uint bl, uint br, i } #endif +#if defined(__SSE2__) +static inline uint interpolate_4_pixels(uint tl, uint tr, uint bl, uint br, uint distx, uint disty) +{ + // First interpolate right and left pixels in parallel. + __m128i vl = _mm_unpacklo_epi32(_mm_cvtsi32_si128(tl), _mm_cvtsi32_si128(bl)); + __m128i vr = _mm_unpacklo_epi32(_mm_cvtsi32_si128(tr), _mm_cvtsi32_si128(br)); + vl = _mm_unpacklo_epi8(vl, _mm_setzero_si128()); + vr = _mm_unpacklo_epi8(vr, _mm_setzero_si128()); + vl = _mm_mullo_epi16(vl, _mm_set1_epi16(256 - distx)); + vr = _mm_mullo_epi16(vr, _mm_set1_epi16(distx)); + __m128i vtb = _mm_add_epi16(vl, vr); + vtb = _mm_srli_epi16(vtb, 8); + // vtb now contains the result of the first two interpolate calls vtb = unpacked((xbot << 64) | xtop) + + // Now the last interpolate between top and bottom interpolations. + const __m128i vidisty = _mm_shufflelo_epi16(_mm_cvtsi32_si128(256 - disty), _MM_SHUFFLE(0, 0, 0, 0)); + const __m128i vdisty = _mm_shufflelo_epi16(_mm_cvtsi32_si128(disty), _MM_SHUFFLE(0, 0, 0, 0)); + const __m128i vmuly = _mm_unpacklo_epi16(vidisty, vdisty); + vtb = _mm_unpacklo_epi16(vtb, _mm_srli_si128(vtb, 8)); + // vtb now contains the colors of top and bottom interleaved { ta, ba, tr, br, tg, bg, tb, bb } + vtb = _mm_madd_epi16(vtb, vmuly); // Multiply and horizontal add. + vtb = _mm_srli_epi32(vtb, 8); + vtb = _mm_packs_epi32(vtb, _mm_setzero_si128()); + vtb = _mm_packus_epi16(vtb, _mm_setzero_si128()); + return _mm_cvtsi128_si32(vtb); +} +#else +static inline uint interpolate_4_pixels(uint tl, uint tr, uint bl, uint br, uint distx, uint disty) +{ + uint idistx = 256 - distx; + uint idisty = 256 - disty; + uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx); + uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx); + return INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty); +} +#endif + + template<TextureBlendType blendType> void fetchTransformedBilinear_pixelBounds(int max, int l1, int l2, int &v1, int &v2); @@ -1177,7 +1541,6 @@ static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, c const uint *s1 = (const uint *)data->texture.scanLine(y1); const uint *s2 = (const uint *)data->texture.scanLine(y2); int disty = (fy & 0x0000ffff) >> 8; - int idisty = 256 - disty; while (b < end) { int x1 = (fx >> 16); int x2; @@ -1186,13 +1549,8 @@ static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, c uint tr = s1[x2]; uint bl = s2[x1]; uint br = s2[x2]; - int distx = (fx & 0x0000ffff) >> 8; - int idistx = 256 - distx; - - uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx); - uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx); - *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty); + *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty); fx += fdx; ++b; @@ -1356,12 +1714,8 @@ static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, c int distx = (fx & 0x0000ffff) >> 8; int disty = (fy & 0x0000ffff) >> 8; - int idistx = 256 - distx; - int idisty = 256 - disty; - uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx); - uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx); - *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty); + *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty); fx += fdx; fy += fdy; @@ -1418,8 +1772,6 @@ static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, c int distx = int((px - x1) * 256); int disty = int((py - y1) * 256); - int idistx = 256 - distx; - int idisty = 256 - disty; fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2); @@ -1432,9 +1784,7 @@ static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, c uint bl = s2[x1]; uint br = s2[x2]; - uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx); - uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx); - *b = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty); + *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty); fx += fdx; fy += fdy; @@ -1606,17 +1956,13 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper if ((fdx < 0 && fdx > -(fixed_scale / 8)) || fabs(data->m22) < (1./8.)) { // scale up more than 8x int disty = (fy & 0x0000ffff) >> 8; - int idisty = 256 - disty; for (int i = 0; i < len; ++i) { uint tl = buf1[i * 2 + 0]; uint tr = buf1[i * 2 + 1]; uint bl = buf2[i * 2 + 0]; uint br = buf2[i * 2 + 1]; int distx = (fracX & 0x0000ffff) >> 8; - int idistx = 256 - distx; - uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx); - uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx); - b[i] = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty); + b[i] = interpolate_4_pixels(tl, tr, bl, br, distx, disty); fracX += fdx; } } else { //scale down @@ -1677,12 +2023,8 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper int distx = (fracX & 0x0000ffff) >> 8; int disty = (fracY & 0x0000ffff) >> 8; - int idistx = 256 - distx; - int idisty = 256 - disty; - uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx); - uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx); - b[i] = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty); + b[i] = interpolate_4_pixels(tl, tr, bl, br, distx, disty); fracX += fdx; fracY += fdy; } @@ -1764,17 +2106,13 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper for (int i = 0; i < len; ++i) { int distx = distxs[i]; int disty = distys[i]; - int idistx = 256 - distx; - int idisty = 256 - disty; uint tl = buf1[i * 2 + 0]; uint tr = buf1[i * 2 + 1]; uint bl = buf2[i * 2 + 0]; uint br = buf2[i * 2 + 1]; - uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx); - uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx); - b[i] = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty); + b[i] = interpolate_4_pixels(tl, tr, bl, br, distx, disty); } length -= len; b += len; @@ -5071,13 +5409,15 @@ static void blend_transformed_tiled_argb(int count, const QSpan *spans, void *us int l = qMin(length, buffer_size); const uint *end = buffer + l; uint *b = buffer; + int px16 = x % (image_width << 16); + int py16 = y % (image_height << 16); + int px_delta = fdx % (image_width << 16); + int py_delta = fdy % (image_height << 16); while (b < end) { - int px = x >> 16; - int py = y >> 16; - px %= image_width; - py %= image_height; - if (px < 0) px += image_width; - if (py < 0) py += image_height; + if (px16 < 0) px16 += image_width << 16; + if (py16 < 0) py16 += image_height << 16; + int px = px16 >> 16; + int py = py16 >> 16; int y_offset = py * scanline_offset; Q_ASSERT(px >= 0 && px < image_width); @@ -5086,6 +5426,12 @@ static void blend_transformed_tiled_argb(int count, const QSpan *spans, void *us *b = image_bits[y_offset + px]; x += fdx; y += fdy; + px16 += px_delta; + if (px16 >= image_width << 16) + px16 -= image_width << 16; + py16 += py_delta; + if (py16 >= image_height << 16) + py16 -= image_height << 16; ++b; } func(target, buffer, l, coverage); @@ -5916,7 +6262,7 @@ static void qt_rectfill_nonpremul_argb32(QRasterBuffer *rasterBuffer, quint32 color) { qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()), - INV_PREMUL(color), x, y, width, height, rasterBuffer->bytesPerLine()); + qUnpremultiply(color), x, y, width, height, rasterBuffer->bytesPerLine()); } static void qt_rectfill_rgba(QRasterBuffer *rasterBuffer, @@ -5932,7 +6278,7 @@ static void qt_rectfill_nonpremul_rgba(QRasterBuffer *rasterBuffer, quint32 color) { qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()), - ARGB2RGBA(INV_PREMUL(color)), x, y, width, height, rasterBuffer->bytesPerLine()); + ARGB2RGBA(qUnpremultiply(color)), x, y, width, height, rasterBuffer->bytesPerLine()); } @@ -6140,110 +6486,73 @@ inline void qt_memfill_template(quint16 *dest, quint16 value, int count) } #endif -static void qt_memfill_quint16(quint16 *dest, quint16 color, int count) +#if !defined(__SSE2__) +void qt_memfill16(quint16 *dest, quint16 color, int count) { qt_memfill_template<quint16>(dest, color, count); } - -typedef void (*qt_memfill32_func)(quint32 *dest, quint32 value, int count); -typedef void (*qt_memfill16_func)(quint16 *dest, quint16 value, int count); -static void qt_memfill32_setup(quint32 *dest, quint32 value, int count); -static void qt_memfill16_setup(quint16 *dest, quint16 value, int count); - -qt_memfill32_func qt_memfill32 = qt_memfill32_setup; -qt_memfill16_func qt_memfill16 = qt_memfill16_setup; +#endif +#if !defined(__SSE2__) && !defined(__ARM_NEON__) +void qt_memfill32(quint32 *dest, quint32 color, int count) +{ +# ifdef QT_COMPILER_SUPPORTS_MIPS_DSP + extern "C" qt_memfill32_asm_mips_dsp(quint32 *, quint32, int); + qt_memfill32_asm_mips_dsp(dest, color, count); +# else + qt_memfill_template<quint32>(dest, color, count); +# endif +} +#endif void qInitDrawhelperAsm() { - - qt_memfill32 = qt_memfill_template<quint32>; - qt_memfill16 = qt_memfill_quint16; //qt_memfill_template<quint16>; - CompositionFunction *functionForModeAsm = 0; CompositionFunctionSolid *functionForModeSolidAsm = 0; const uint features = qCpuFeatures(); - if (false) { - Q_UNUSED(features); -#ifdef QT_COMPILER_SUPPORTS_AVX - } else if (features & AVX) { - qt_memfill32 = qt_memfill32_avx; - qt_memfill16 = qt_memfill16_avx; - qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_avx; - qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_avx; - qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_avx; - qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_avx; - qDrawHelper[QImage::Format_RGBX8888].bitmapBlit = qt_bitmapblit32_avx; - qDrawHelper[QImage::Format_RGBA8888].bitmapBlit = qt_bitmapblit32_avx; - qDrawHelper[QImage::Format_RGBA8888_Premultiplied].bitmapBlit = qt_bitmapblit32_avx; - - extern void qt_scale_image_argb32_on_argb32_avx(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - const QRectF &targetRect, - const QRectF &sourceRect, - const QRect &clip, - int const_alpha); - qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_avx; - qScaleFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_avx; -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qScaleFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32_avx; - qScaleFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32_avx; -#endif -#endif -#ifdef QT_COMPILER_SUPPORTS_SSE2 - } else if (features & SSE2) { - qt_memfill32 = qt_memfill32_sse2; - qt_memfill16 = qt_memfill16_sse2; - qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_sse2; - qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_sse2; - qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_sse2; - qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse2; - qDrawHelper[QImage::Format_RGBX8888].bitmapBlit = qt_bitmapblit32_sse2; - qDrawHelper[QImage::Format_RGBA8888].bitmapBlit = qt_bitmapblit32_sse2; - qDrawHelper[QImage::Format_RGBA8888_Premultiplied].bitmapBlit = qt_bitmapblit32_sse2; - - extern void qt_scale_image_argb32_on_argb32_sse2(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - const QRectF &targetRect, - const QRectF &sourceRect, - const QRect &clip, - int const_alpha); - qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2; - qScaleFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2; -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qScaleFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2; - qScaleFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2; -#endif -#endif - } - -#ifdef QT_COMPILER_SUPPORTS_SSE2 - if (features & SSE2) { - extern void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha); - extern void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha); - - qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2; - qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2; - qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2; - qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2; -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_sse2; - qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_sse2; - qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_sse2; - qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_sse2; -#endif - - extern const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length); - - qt_fetch_radial_gradient = qt_fetch_radial_gradient_sse2; - } + Q_UNUSED(features); +#ifdef __SSE2__ + qDrawHelper[QImage::Format_RGB32].bitmapBlit = qt_bitmapblit32_sse2; + qDrawHelper[QImage::Format_ARGB32].bitmapBlit = qt_bitmapblit32_sse2; + qDrawHelper[QImage::Format_ARGB32_Premultiplied].bitmapBlit = qt_bitmapblit32_sse2; + qDrawHelper[QImage::Format_RGB16].bitmapBlit = qt_bitmapblit16_sse2; + qDrawHelper[QImage::Format_RGBX8888].bitmapBlit = qt_bitmapblit32_sse2; + qDrawHelper[QImage::Format_RGBA8888].bitmapBlit = qt_bitmapblit32_sse2; + qDrawHelper[QImage::Format_RGBA8888_Premultiplied].bitmapBlit = qt_bitmapblit32_sse2; + + extern void qt_scale_image_argb32_on_argb32_sse2(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + const QRectF &targetRect, + const QRectF &sourceRect, + const QRect &clip, + int const_alpha); + qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2; + qScaleFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2; + qScaleFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2; + qScaleFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32_sse2; + + extern void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); + extern void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); + + qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2; + qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2; + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_sse2; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_sse2; + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_sse2; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_sse2; + + extern const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length); + + qt_fetch_radial_gradient = qt_fetch_radial_gradient_sse2; #ifdef QT_COMPILER_SUPPORTS_SSSE3 if (features & SSSE3) { @@ -6254,65 +6563,13 @@ void qInitDrawhelperAsm() qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3; qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_ssse3; -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_ssse3; qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_ssse3; -#endif } #endif // SSSE3 -#ifdef QT_COMPILER_SUPPORTS_AVX - if (features & AVX) { - extern void qt_blend_rgb32_on_rgb32_avx(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha); - extern void qt_blend_argb32_on_argb32_avx(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha); - - qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_avx; - qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_avx; - qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_avx; - qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_avx; -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_avx; - qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_avx; - qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_avx; - qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_avx; -#endif - - extern const uint * QT_FASTCALL qt_fetch_radial_gradient_avx(uint *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length); - - qt_fetch_radial_gradient = qt_fetch_radial_gradient_avx; - } -#endif // AVX - -#endif // SSE2 - -#ifdef QT_COMPILER_SUPPORTS_SSE2 - if (features & SSE2) { - functionForModeAsm = qt_functionForMode_SSE2; - functionForModeSolidAsm = qt_functionForModeSolid_SSE2; - } -#endif -#ifdef QT_COMPILER_SUPPORTS_AVX - if (features & AVX) { - extern void QT_FASTCALL comp_func_SourceOver_avx(uint *destPixels, - const uint *srcPixels, - int length, - uint const_alpha); - extern void QT_FASTCALL comp_func_solid_SourceOver_avx(uint *destPixels, int length, uint color, uint const_alpha); - extern void QT_FASTCALL comp_func_Plus_avx(uint *dst, const uint *src, int length, uint const_alpha); - extern void QT_FASTCALL comp_func_Source_avx(uint *dst, const uint *src, int length, uint const_alpha); - - functionForModeAsm[0] = comp_func_SourceOver_avx; - functionForModeAsm[QPainter::CompositionMode_Source] = comp_func_Source_avx; - functionForModeAsm[QPainter::CompositionMode_Plus] = comp_func_Plus_avx; - functionForModeSolidAsm[0] = comp_func_solid_SourceOver_avx; - } + functionForModeAsm = qt_functionForMode_SSE2; + functionForModeSolidAsm = qt_functionForModeSolid_SSE2; #endif // SSE2 #ifdef QT_COMPILER_SUPPORTS_IWMMXT @@ -6323,45 +6580,42 @@ void qInitDrawhelperAsm() } #endif // IWMMXT -#if defined(QT_COMPILER_SUPPORTS_NEON) && !defined(Q_OS_IOS) - if (features & NEON) { - qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon; - qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon; - qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon; - qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon; - qBlendFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_rgb16_neon; - qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB16] = qt_blend_rgb16_on_argb32_neon; - qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16_neon; +#if defined(__ARM_NEON__) && !defined(Q_OS_IOS) + qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon; + qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon; + qBlendFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_rgb16_neon; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB16] = qt_blend_rgb16_on_argb32_neon; + qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16_neon; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_neon; - qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_neon; - qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_neon; - qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_neon; + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_neon; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32_neon; + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_neon; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_neon; #endif - qScaleFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_rgb16_neon; - qScaleFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_scale_image_rgb16_on_rgb16_neon; + qScaleFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_rgb16_neon; + qScaleFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_scale_image_rgb16_on_rgb16_neon; - qTransformFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_rgb16_neon; - qTransformFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_transform_image_rgb16_on_rgb16_neon; + qTransformFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_rgb16_neon; + qTransformFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_transform_image_rgb16_on_rgb16_neon; - qDrawHelper[QImage::Format_RGB16].alphamapBlit = qt_alphamapblit_quint16_neon; + qDrawHelper[QImage::Format_RGB16].alphamapBlit = qt_alphamapblit_quint16_neon; - functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon; - functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon; - functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_neon; - destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon; - destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon; + functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon; + functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon; + functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_neon; + destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon; + destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon; - qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon; - qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon; - qt_memfill32 = qt_memfill32_neon; + qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon; + qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon; - extern const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length); + extern const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length); - qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon; - } + qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon; #endif #if defined(QT_COMPILER_SUPPORTS_MIPS_DSP) @@ -6385,8 +6639,6 @@ void qInitDrawhelperAsm() functionForModeSolid_C[QPainter::CompositionMode_Xor] = comp_func_solid_XOR_mips_dsp; functionForModeSolid_C[QPainter::CompositionMode_SourceOut] = comp_func_solid_SourceOut_mips_dsp; - qt_memfill32 = qt_memfill32_asm_mips_dsp; - qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mips_dsp; qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mips_dsp; qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_mips_dsp; @@ -6427,16 +6679,4 @@ void qInitDrawhelperAsm() functionForMode = functionForModeAsm; } -static void qt_memfill32_setup(quint32 *dest, quint32 value, int count) -{ - qInitDrawhelperAsm(); - qt_memfill32(dest, value, count); -} - -static void qt_memfill16_setup(quint16 *dest, quint16 value, int count) -{ - qInitDrawhelperAsm(); - qt_memfill16(dest, value, count); -} - QT_END_NAMESPACE diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp index 541b3ef619..a40166d5be 100644 --- a/src/gui/painting/qdrawhelper_neon.cpp +++ b/src/gui/painting/qdrawhelper_neon.cpp @@ -43,7 +43,7 @@ #include <private/qblendfunctions_p.h> #include <private/qmath_p.h> -#ifdef QT_COMPILER_SUPPORTS_NEON +#ifdef __ARM_NEON__ #include <private/qdrawhelper_neon_p.h> #include <private/qpaintengine_raster_p.h> @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE -void qt_memfill32_neon(quint32 *dest, quint32 value, int count) +void qt_memfill32(quint32 *dest, quint32 value, int count) { const int epilogueSize = count % 16; if (count >= 16) { @@ -998,5 +998,5 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Opera QT_END_NAMESPACE -#endif // QT_COMPILER_SUPPORTS_NEON +#endif // __ARM_NEON__ diff --git a/src/gui/painting/qdrawhelper_neon_p.h b/src/gui/painting/qdrawhelper_neon_p.h index 475df639f8..cad6fe22e9 100644 --- a/src/gui/painting/qdrawhelper_neon_p.h +++ b/src/gui/painting/qdrawhelper_neon_p.h @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE -#ifdef QT_COMPILER_SUPPORTS_NEON +#ifdef __ARM_NEON__ void qt_blend_argb32_on_argb32_neon(uchar *destPixels, int dbpl, const uchar *srcPixels, int sbpl, @@ -139,7 +139,7 @@ void QT_FASTCALL qt_destStoreRGB16_neon(QRasterBuffer *rasterBuffer, void QT_FASTCALL comp_func_solid_SourceOver_neon(uint *destPixels, int length, uint color, uint const_alpha); void QT_FASTCALL comp_func_Plus_neon(uint *dst, const uint *src, int length, uint const_alpha); -#endif // QT_COMPILER_SUPPORTS_NEON +#endif // __ARM_NEON__ QT_END_NAMESPACE diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 418294c56d..bbeb73f0af 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -171,6 +171,8 @@ extern MemRotateFunc qMemRotateFunctions[QImage::NImageFormats][3]; extern DrawHelper qDrawHelper[QImage::NImageFormats]; void qBlendTexture(int count, const QSpan *spans, void *userData); +extern void qt_memfill32(quint32 *dest, quint32 value, int count); +extern void qt_memfill16(quint16 *dest, quint16 value, int count); typedef void (QT_FASTCALL *CompositionFunction)(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha); typedef void (QT_FASTCALL *CompositionFunctionSolid)(uint *dest, int length, uint color, uint const_alpha); @@ -386,8 +388,6 @@ static inline qreal qRadialDeterminant(qreal a, qreal b, qreal c) return (b * b) - (4 * a * c); } -extern void (*qt_memfill32)(quint32 *dest, quint32 value, int count); - template <class RadialFetchFunc> Q_STATIC_TEMPLATE_FUNCTION const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const Operator *op, const QSpanData *data, int y, int x, int length) @@ -599,14 +599,6 @@ static Q_ALWAYS_INLINE uint BYTE_MUL(uint x, uint a) { return (uint(t)) | (uint(t >> 24)); } -static Q_ALWAYS_INLINE uint PREMUL(uint x) { - uint a = x >> 24; - quint64 t = (((quint64(x)) | ((quint64(x)) << 24)) & 0x00ff00ff00ff00ff) * a; - t = (t + ((t >> 8) & 0xff00ff00ff00ff) + 0x80008000800080) >> 8; - t &= 0x000000ff00ff00ff; - return (uint(t)) | (uint(t >> 24)) | (a << 24); -} - #else // 32-bit versions static Q_ALWAYS_INLINE uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) { @@ -639,20 +631,9 @@ static Q_ALWAYS_INLINE uint BYTE_MUL(uint x, uint a) { # pragma pop #endif -static Q_ALWAYS_INLINE uint PREMUL(uint x) { - uint a = x >> 24; - uint t = (x & 0xff00ff) * a; - t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8; - t &= 0xff00ff; - - x = ((x >> 8) & 0xff) * a; - x = (x + ((x >> 8) & 0xff) + 0x80); - x &= 0xff00; - x |= t | (a << 24); - return x; -} #endif + #if Q_BYTE_ORDER == Q_BIG_ENDIAN static Q_ALWAYS_INLINE quint32 RGBA2ARGB(quint32 x) { quint32 rgb = x >> 8; @@ -691,12 +672,9 @@ static Q_ALWAYS_INLINE uint BYTE_MUL_RGB16_32(uint x, uint a) { return t; } -#define INV_PREMUL(p) \ - (qAlpha(p) == 0 ? 0 : \ - ((qAlpha(p) << 24) \ - | (((255*qRed(p))/ qAlpha(p)) << 16) \ - | (((255*qGreen(p)) / qAlpha(p)) << 8) \ - | ((255*qBlue(p)) / qAlpha(p)))) +// FIXME: Remove when all Qt modules have stopped using PREMUL and INV_PREMUL +#define PREMUL(x) qPremultiply(x) +#define INV_PREMUL(p) qUnpremultiply(p) struct quint24 { quint24(uint value); @@ -726,7 +704,6 @@ template<> inline void qt_memfill(quint32 *dest, quint32 color, int count) template<> inline void qt_memfill(quint16 *dest, quint16 color, int count) { - extern void (*qt_memfill16)(quint16 *dest, quint16 value, int count); qt_memfill16(dest, color, count); } @@ -1031,6 +1008,7 @@ struct QPixelLayout BPP bpp; ConvertFunc convertToARGB32PM; ConvertFunc convertFromARGB32PM; + ConvertFunc convertFromRGB32; }; typedef const uint *(QT_FASTCALL *FetchPixelsFunc)(uint *buffer, const uchar *src, int index, int count); diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp index a9dc5a7fb7..f5523f7113 100644 --- a/src/gui/painting/qdrawhelper_sse2.cpp +++ b/src/gui/painting/qdrawhelper_sse2.cpp @@ -238,7 +238,7 @@ void QT_FASTCALL comp_func_Source_sse2(uint *dst, const uint *src, int length, u } } -void qt_memfill32_sse2(quint32 *dest, quint32 value, int count) +void qt_memfill32(quint32 *dest, quint32 value, int count) { if (count < 7) { switch (count) { @@ -259,33 +259,39 @@ void qt_memfill32_sse2(quint32 *dest, quint32 value, int count) case 12: *dest++ = value; --count; } + const int rest = count & 0x3; + if (rest) { + switch (rest) { + case 3: dest[count - 3] = value; + case 2: dest[count - 2] = value; + case 1: dest[count - 1] = value; + } + } + int count128 = count / 4; __m128i *dst128 = reinterpret_cast<__m128i*>(dest); + __m128i *end128 = dst128 + count128; const __m128i value128 = _mm_set_epi32(value, value, value, value); - int n = (count128 + 3) / 4; + while (dst128 + 3 < end128) { + _mm_stream_si128(dst128 + 0, value128); + _mm_stream_si128(dst128 + 1, value128); + _mm_stream_si128(dst128 + 2, value128); + _mm_stream_si128(dst128 + 3, value128); + dst128 += 4; + } + switch (count128 & 0x3) { - case 0: do { _mm_stream_si128(dst128++, value128); case 3: _mm_stream_si128(dst128++, value128); case 2: _mm_stream_si128(dst128++, value128); case 1: _mm_stream_si128(dst128++, value128); - } while (--n > 0); - } - - const int rest = count & 0x3; - if (rest) { - switch (rest) { - case 3: dest[count - 3] = value; - case 2: dest[count - 2] = value; - case 1: dest[count - 1] = value; - } } } void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha) { if ((const_alpha & qAlpha(color)) == 255) { - qt_memfill32_sse2(destPixels, color, length); + qt_memfill32(destPixels, color, length); } else { if (const_alpha != 255) color = BYTE_MUL(color, const_alpha); @@ -397,7 +403,7 @@ CompositionFunction qt_functionForMode_SSE2[numCompositionFunctions] = { }; #endif -void qt_memfill16_sse2(quint16 *dest, quint16 value, int count) +void qt_memfill16(quint16 *dest, quint16 value, int count) { if (count < 3) { switch (count) { @@ -413,7 +419,7 @@ void qt_memfill16_sse2(quint16 *dest, quint16 value, int count) } const quint32 value32 = (value << 16) | value; - qt_memfill32_sse2(reinterpret_cast<quint32*>(dest), value32, count / 2); + qt_memfill32(reinterpret_cast<quint32*>(dest), value32, count / 2); if (count & 0x1) dest[count - 1] = value; diff --git a/src/gui/painting/qdrawhelper_x86_p.h b/src/gui/painting/qdrawhelper_x86_p.h index d64b9cec39..699c586cb0 100644 --- a/src/gui/painting/qdrawhelper_x86_p.h +++ b/src/gui/painting/qdrawhelper_x86_p.h @@ -57,9 +57,9 @@ QT_BEGIN_NAMESPACE -#ifdef QT_COMPILER_SUPPORTS_SSE2 -void qt_memfill32_sse2(quint32 *dest, quint32 value, int count); -void qt_memfill16_sse2(quint16 *dest, quint16 value, int count); +#ifdef __SSE2__ +void qt_memfill32(quint32 *dest, quint32 value, int count); +void qt_memfill16(quint16 *dest, quint16 value, int count); void qt_bitmapblit32_sse2(QRasterBuffer *rasterBuffer, int x, int y, quint32 color, const uchar *src, int width, int height, int stride); @@ -77,26 +77,7 @@ void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl, extern CompositionFunction qt_functionForMode_SSE2[]; extern CompositionFunctionSolid qt_functionForModeSolid_SSE2[]; -#endif // QT_COMPILER_SUPPORTS_SSE2 - -#ifdef QT_COMPILER_SUPPORTS_AVX -void qt_memfill32_avx(quint32 *dest, quint32 value, int count); -void qt_memfill16_avx(quint16 *dest, quint16 value, int count); -void qt_bitmapblit32_avx(QRasterBuffer *rasterBuffer, int x, int y, - quint32 color, - const uchar *src, int width, int height, int stride); -void qt_bitmapblit16_avx(QRasterBuffer *rasterBuffer, int x, int y, - quint32 color, - const uchar *src, int width, int height, int stride); -void qt_blend_argb32_on_argb32_avx(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha); -void qt_blend_rgb32_on_rgb32_avx(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha); -#endif // QT_COMPILER_SUPPORTS_AVX +#endif // __SSE2__ #ifdef QT_COMPILER_SUPPORTS_IWMMXT void qt_blend_color_argb_iwmmxt(int count, const QSpan *spans, void *userData); diff --git a/src/gui/painting/qdrawingprimitive_sse2_p.h b/src/gui/painting/qdrawingprimitive_sse2_p.h index 0e0c06f56c..cdf68b932d 100644 --- a/src/gui/painting/qdrawingprimitive_sse2_p.h +++ b/src/gui/painting/qdrawingprimitive_sse2_p.h @@ -44,7 +44,7 @@ #include <private/qsimd_p.h> -#ifdef QT_COMPILER_SUPPORTS_SSE2 +#ifdef __SSE2__ // // W A R N I N G @@ -242,6 +242,6 @@ QT_BEGIN_NAMESPACE QT_END_NAMESPACE -#endif // QT_COMPILER_SUPPORTS_SSE2 +#endif // __SSE2__ #endif // QDRAWINGPRIMITIVE_SSE2_P_H diff --git a/src/gui/painting/qemulationpaintengine.cpp b/src/gui/painting/qemulationpaintengine.cpp index bb87b4fd6e..0fb907b6c5 100644 --- a/src/gui/painting/qemulationpaintengine.cpp +++ b/src/gui/painting/qemulationpaintengine.cpp @@ -169,7 +169,7 @@ void QEmulationPaintEngine::drawTextItem(const QPointF &p, const QTextItem &text { if (state()->bgMode == Qt::OpaqueMode) { const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); - QRectF rect(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent + 1).toReal()); + QRectF rect(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent).toReal()); fillBGRect(rect); } diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index f855e9e32d..421d706230 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -70,13 +70,11 @@ QTextItemIntCopy::QTextItemIntCopy(const QTextItem &item) m_item.chars = chars; m_item.logClusters = logClusters; - const int size = QGlyphLayout::spaceNeededForGlyphLayout(m_item.glyphs.numGlyphs); - char *glyphLayoutData = new char[size]; + char *glyphLayoutData = new char[m_item.glyphs.numGlyphs * QGlyphLayout::SpaceNeeded]; QGlyphLayout glyphs(glyphLayoutData, m_item.glyphs.numGlyphs); memcpy(glyphs.offsets, m_item.glyphs.offsets, m_item.glyphs.numGlyphs * sizeof(QFixedPoint)); memcpy(glyphs.glyphs, m_item.glyphs.glyphs, m_item.glyphs.numGlyphs * sizeof(glyph_t)); - memcpy(glyphs.advances_x, m_item.glyphs.advances_x, m_item.glyphs.numGlyphs * sizeof(QFixed)); - memcpy(glyphs.advances_y, m_item.glyphs.advances_y, m_item.glyphs.numGlyphs * sizeof(QFixed)); + memcpy(glyphs.advances, m_item.glyphs.advances, m_item.glyphs.numGlyphs * sizeof(QFixed)); memcpy(glyphs.justifications, m_item.glyphs.justifications, m_item.glyphs.numGlyphs * sizeof(QGlyphJustification)); memcpy(glyphs.attributes, m_item.glyphs.attributes, m_item.glyphs.numGlyphs * sizeof(QGlyphAttributes)); m_item.glyphs = glyphs; diff --git a/src/gui/painting/qpaintengine.cpp b/src/gui/painting/qpaintengine.cpp index f1eaea0f6b..acab08e794 100644 --- a/src/gui/painting/qpaintengine.cpp +++ b/src/gui/painting/qpaintengine.cpp @@ -387,6 +387,7 @@ void QPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDraw \value OpenGL2 \value PaintBuffer \value Blitter + \value Direct2D Windows only, Direct2D based engine */ /*! diff --git a/src/gui/painting/qpaintengine.h b/src/gui/painting/qpaintengine.h index 18b6d84146..7b928ba5f6 100644 --- a/src/gui/painting/qpaintengine.h +++ b/src/gui/painting/qpaintengine.h @@ -207,6 +207,7 @@ public: OpenGL2, PaintBuffer, Blitter, + Direct2D, User = 50, // first user type id MaxUser = 100 // last user type id diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index bdd0d9cd4c..9a2e49618c 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -1823,7 +1823,7 @@ void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color) Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); - d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity)); + d->solid_color_filler.solid.color = qPremultiply(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity)); if ((d->solid_color_filler.solid.color & 0xff000000) == 0 && s->composition_mode == QPainter::CompositionMode_SourceOver) { return; @@ -2272,7 +2272,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe | ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00); break; default: - d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity)); + d->solid_color_filler.solid.color = qPremultiply(ARGB_COMBINE_ALPHA(color, s->intOpacity)); break; } @@ -3662,7 +3662,7 @@ QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color) QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB); QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied); - QRgb fg = PREMUL(color.rgba()); + QRgb fg = qPremultiply(color.rgba()); QRgb bg = 0; int height = sourceImage.height(); @@ -3702,8 +3702,8 @@ QImage::Format QRasterBuffer::prepare(QImage *image) drawHelper = qDrawHelper + format; if (image->depth() == 1 && image->colorTable().size() == 2) { monoDestinationWithClut = true; - destColor0 = PREMUL(image->colorTable()[0]); - destColor1 = PREMUL(image->colorTable()[1]); + destColor0 = qPremultiply(image->colorTable()[0]); + destColor1 = qPremultiply(image->colorTable()[1]); } return format; @@ -4260,8 +4260,8 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint } if (colorInterpolation) { - first_color = PREMUL(first_color); - second_color = PREMUL(second_color); + first_color = qPremultiply(first_color); + second_color = qPremultiply(second_color); } int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1)); @@ -4282,7 +4282,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint if (colorInterpolation) colorTable[i] = first_color; else - colorTable[i] = PREMUL(first_color); + colorTable[i] = qPremultiply(first_color); } if (i < second_index) { @@ -4311,7 +4311,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint if (colorInterpolation) colorTable[i] = color; else - colorTable[i] = PREMUL(color); + colorTable[i] = qPremultiply(color); } } @@ -4319,7 +4319,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint if (colorInterpolation) colorTable[i] = second_color; else - colorTable[i] = PREMUL(second_color); + colorTable[i] = qPremultiply(second_color); } return; @@ -4327,7 +4327,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity); if (stopCount == 1) { - current_color = PREMUL(current_color); + current_color = qPremultiply(current_color); for (int i = 0; i < size; ++i) colorTable[i] = current_color; return; @@ -4344,7 +4344,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1) // Up to first point - colorTable[pos++] = PREMUL(current_color); + colorTable[pos++] = qPremultiply(current_color); while (dpos <= begin_pos) { colorTable[pos] = colorTable[pos - 1]; ++pos; @@ -4366,8 +4366,8 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity); if (colorInterpolation) { - current_color = PREMUL(current_color); - next_color = PREMUL(next_color); + current_color = qPremultiply(current_color); + next_color = qPremultiply(next_color); } qreal diff = stops[current_stop+1].first - stops[current_stop].first; @@ -4384,7 +4384,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint if (colorInterpolation) colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist); else - colorTable[pos] = PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)); + colorTable[pos] = qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)); ++pos; dpos += incr; @@ -4408,8 +4408,8 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint if (colorInterpolation) { if (skip != 1) - current_color = PREMUL(current_color); - next_color = PREMUL(next_color); + current_color = qPremultiply(current_color); + next_color = qPremultiply(next_color); } qreal diff = stops[current_stop+1].first - stops[current_stop].first; @@ -4421,7 +4421,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint } // After last point - current_color = PREMUL(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity)); + current_color = qPremultiply(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity)); while (pos < size - 1) { colorTable[pos] = current_color; ++pos; @@ -4455,7 +4455,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode type = Solid; QColor c = qbrush_color(brush); QRgb rgba = c.rgba(); - solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha)); + solid.color = qPremultiply(ARGB_COMBINE_ALPHA(rgba, alpha)); if ((solid.color & 0xff000000) == 0 && compositionMode == QPainter::CompositionMode_SourceOver) { type = None; diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 41a2e39fc9..1fc044aa44 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5617,8 +5617,7 @@ void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, QFixedPoint *positio textItem.glyphs.numGlyphs = glyphCount; textItem.glyphs.glyphs = const_cast<glyph_t *>(glyphArray); textItem.glyphs.offsets = positions; - textItem.glyphs.advances_x = advances.data(); - textItem.glyphs.advances_y = advances.data(); + textItem.glyphs.advances = advances.data(); textItem.glyphs.justifications = glyphJustifications.data(); textItem.glyphs.attributes = glyphAttributes.data(); @@ -5846,11 +5845,8 @@ void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justif int numGlyphs = len; QVarLengthGlyphLayoutArray glyphs(len); QFontEngine *fontEngine = d->state->font.d->engineForScript(QChar::Script_Common); - if (!fontEngine->stringToCMap(str.data(), len, &glyphs, &numGlyphs, 0)) { - glyphs.resize(numGlyphs); - if (!fontEngine->stringToCMap(str.data(), len, &glyphs, &numGlyphs, 0)) - Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice"); - } + if (!fontEngine->stringToCMap(str.data(), len, &glyphs, &numGlyphs, 0)) + Q_UNREACHABLE(); QTextItemInt gf(glyphs, &d->state->font, str.data(), len, fontEngine); drawTextItem(p, gf); @@ -6354,7 +6350,7 @@ void QPainterPrivate::drawTextItem(const QPointF &p, const QTextItem &_ti, QText QTextItemInt &ti = const_cast<QTextItemInt &>(static_cast<const QTextItemInt &>(_ti)); if (!extended && state->bgMode == Qt::OpaqueMode) { - QRectF rect(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent + 1).toReal()); + QRectF rect(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent).toReal()); q->fillRect(rect, state->bgBrush); } diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp index 156e411154..aa2b9bea54 100644 --- a/src/gui/painting/qpainterpath.cpp +++ b/src/gui/painting/qpainterpath.cpp @@ -1738,8 +1738,8 @@ QList<QPolygonF> QPainterPath::toFillPolygons(const QMatrix &matrix) const //same as qt_polygon_isect_line in qpolygon.cpp static void qt_painterpath_isect_line(const QPointF &p1, - const QPointF &p2, - const QPointF &pos, + const QPointF &p2, + const QPointF &pos, int *winding) { qreal x1 = p1.x(); @@ -2551,6 +2551,26 @@ QPainterPathStroker::QPainterPathStroker() } /*! + Creates a new stroker based on \a pen. + + \since 5.3 + */ +QPainterPathStroker::QPainterPathStroker(const QPen &pen) + : d_ptr(new QPainterPathStrokerPrivate) +{ + setWidth(pen.widthF()); + setCapStyle(pen.capStyle()); + setJoinStyle(pen.joinStyle()); + setMiterLimit(pen.miterLimit()); + setDashOffset(pen.dashOffset()); + + if (pen.style() == Qt::CustomDashLine) + setDashPattern(pen.dashPattern()); + else + setDashPattern(pen.style()); +} + +/*! Destroys the stroker. */ QPainterPathStroker::~QPainterPathStroker() diff --git a/src/gui/painting/qpainterpath.h b/src/gui/painting/qpainterpath.h index e22c1729f3..c922867eb9 100644 --- a/src/gui/painting/qpainterpath.h +++ b/src/gui/painting/qpainterpath.h @@ -57,6 +57,7 @@ class QPainterPathPrivate; struct QPainterPathPrivateDeleter; class QPainterPathData; class QPainterPathStrokerPrivate; +class QPen; class QPolygonF; class QRegion; class QVectorPath; @@ -243,6 +244,7 @@ class Q_GUI_EXPORT QPainterPathStroker Q_DECLARE_PRIVATE(QPainterPathStroker) public: QPainterPathStroker(); + QPainterPathStroker(const QPen &pen); ~QPainterPathStroker(); void setWidth(qreal width); diff --git a/src/gui/painting/qpen.cpp b/src/gui/painting/qpen.cpp index 6a3eacd67a..c0b3769c2d 100644 --- a/src/gui/painting/qpen.cpp +++ b/src/gui/painting/qpen.cpp @@ -455,15 +455,19 @@ QVector<qreal> QPen::dashPattern() const switch (d->style) { case Qt::DashLine: + dd->dashPattern.reserve(2); dd->dashPattern << dash << space; break; case Qt::DotLine: + dd->dashPattern.reserve(2); dd->dashPattern << dot << space; break; case Qt::DashDotLine: + dd->dashPattern.reserve(4); dd->dashPattern << dash << space << dot << space; break; case Qt::DashDotDotLine: + dd->dashPattern.reserve(6); dd->dashPattern << dash << space << dot << space << dot << space; break; default: diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index feec0c7f3d..15459dd748 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -44,6 +44,16 @@ #include <qpixmap.h> #include <private/qwindow_p.h> +#include <qopengl.h> +#include <qopenglcontext.h> +#include <QtGui/QMatrix4x4> +#include <QtGui/QOpenGLShaderProgram> +#include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLFunctions> +#ifndef QT_NO_OPENGL +#include <QtGui/private/qopengltextureblitter_p.h> +#endif + QT_BEGIN_NAMESPACE class QPlatformBackingStorePrivate @@ -51,13 +61,109 @@ class QPlatformBackingStorePrivate public: QPlatformBackingStorePrivate(QWindow *w) : window(w) +#ifndef QT_NO_OPENGL + , blitter(0) +#endif { } + ~QPlatformBackingStorePrivate() + { +#ifndef QT_NO_OPENGL + if (blitter) + blitter->destroy(); + delete blitter; +#endif + } QWindow *window; QSize size; +#ifndef QT_NO_OPENGL + mutable GLuint textureId; + mutable QSize textureSize; + QOpenGLTextureBlitter *blitter; +#endif }; +#ifndef QT_NO_OPENGL + +struct QBackingstoreTextureInfo +{ + GLuint textureId; + QRect rect; +}; + +Q_DECLARE_TYPEINFO(QBackingstoreTextureInfo, Q_MOVABLE_TYPE); + +class QPlatformTextureListPrivate : public QObjectPrivate +{ +public: + QPlatformTextureListPrivate() + : locked(false) + { + } + + QList<QBackingstoreTextureInfo> textures; + bool locked; +}; + +QPlatformTextureList::QPlatformTextureList(QObject *parent) +: QObject(*new QPlatformTextureListPrivate, parent) +{ +} + +QPlatformTextureList::~QPlatformTextureList() +{ +} + +int QPlatformTextureList::count() const +{ + Q_D(const QPlatformTextureList); + return d->textures.count(); +} + +GLuint QPlatformTextureList::textureId(int index) const +{ + Q_D(const QPlatformTextureList); + return d->textures.at(index).textureId; +} + +QRect QPlatformTextureList::geometry(int index) const +{ + Q_D(const QPlatformTextureList); + return d->textures.at(index).rect; +} + +void QPlatformTextureList::lock(bool on) +{ + Q_D(QPlatformTextureList); + if (on != d->locked) { + d->locked = on; + emit locked(on); + } +} + +bool QPlatformTextureList::isLocked() const +{ + Q_D(const QPlatformTextureList); + return d->locked; +} + +void QPlatformTextureList::appendTexture(GLuint textureId, const QRect &geometry) +{ + Q_D(QPlatformTextureList); + QBackingstoreTextureInfo bi; + bi.textureId = textureId; + bi.rect = geometry; + d->textures.append(bi); +} + +void QPlatformTextureList::clear() +{ + Q_D(QPlatformTextureList); + d->textures.clear(); +} +#endif // QT_NO_OPENGL + /*! \class QPlatformBackingStore \since 5.0 @@ -79,6 +185,147 @@ public: Note that the \a offset parameter is currently unused. */ +#ifndef QT_NO_OPENGL +/*! + Flushes the given \a region from the specified \a window onto the + screen, and composes it with the specified \a textures. + + The default implementation retrieves the contents using toTexture() + and composes using OpenGL. May be reimplemented in subclasses if there + is a more efficient native way to do it. + + Note that the \a offset parameter is currently unused. + */ + +void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, + const QPoint &offset, + QPlatformTextureList *textures, QOpenGLContext *context) +{ + Q_UNUSED(offset); + + context->makeCurrent(window); + glViewport(0, 0, window->width(), window->height()); + + if (!d_ptr->blitter) { + d_ptr->blitter = new QOpenGLTextureBlitter; + d_ptr->blitter->create(); + } + + d_ptr->blitter->bind(); + + QRect windowRect(QPoint(), window->size()); + for (int i = 0; i < textures->count(); ++i) { + GLuint textureId = textures->textureId(i); + glBindTexture(GL_TEXTURE_2D, textureId); + + QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), windowRect); + d_ptr->blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginBottomLeft); + } + + GLuint textureId = toTexture(region); + if (!textureId) + return; + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(windowRect, windowRect); + d_ptr->blitter->setSwizzleRB(true); + d_ptr->blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft); + d_ptr->blitter->setSwizzleRB(false); + + glDisable(GL_BLEND); + d_ptr->blitter->release(); + context->swapBuffers(window); +} + +/*! + Implemented in subclasses to return the content of the backingstore as a QImage. + + If QPlatformIntegration::RasterGLSurface is supported, either this function or + toTexture() must be implemented. + + \sa toTexture() + */ +QImage QPlatformBackingStore::toImage() const +{ + return QImage(); +} + +/*! + May be reimplemented in subclasses to return the content of the + backingstore as an OpenGL texture. \a dirtyRegion is the part of the + backingstore which may have changed since the last call to this function. The + caller of this function must ensure that there is a current context. + + The ownership of the texture is not transferred. The caller must not store + the return value between calls, but instead call this function before each use. + + The default implementation returns a cached texture if \a dirtyRegion is + empty and the window has not been resized, otherwise it retrieves the + content using toImage() and performs a texture upload. + */ + +GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion) const +{ + QImage image = toImage(); + QSize imageSize = image.size(); + if (imageSize.isEmpty()) + return 0; + + bool resized = d_ptr->textureSize != imageSize; + if (dirtyRegion.isEmpty() && !resized) + return d_ptr->textureId; + + if (image.format() != QImage::Format_RGB32 && image.format() != QImage::Format_RGBA8888) + image = image.convertToFormat(QImage::Format_RGBA8888); + + if (resized) { + if (d_ptr->textureId) + glDeleteTextures(1, &d_ptr->textureId); + glGenTextures(1, &d_ptr->textureId); + glBindTexture(GL_TEXTURE_2D, d_ptr->textureId); +#ifndef QT_OPENGL_ES_2 + if (!QOpenGLFunctions::isES()) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + } +#endif + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageSize.width(), imageSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, + const_cast<uchar*>(image.constBits())); + d_ptr->textureSize = imageSize; + } else { + glBindTexture(GL_TEXTURE_2D, d_ptr->textureId); + QRect imageRect = image.rect(); + QRect rect = dirtyRegion.boundingRect() & imageRect; + // if the rect is wide enough it's cheaper to just + // extend it instead of doing an image copy + if (rect.width() >= imageRect.width() / 2) { + rect.setX(0); + rect.setWidth(imageRect.width()); + } + + // if the sub-rect is full-width we can pass the image data directly to + // OpenGL instead of copying, since there's no gap between scanlines + + if (rect.width() == imageRect.width()) { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, + image.constScanLine(rect.y())); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, + image.copy(rect).constBits()); + } + } + + return d_ptr->textureId; +} +#endif // QT_NO_OPENGL + /*! \fn QPaintDevice* QPlatformBackingStore::paintDevice() diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h index 1b19b2c379..76fd3d40b4 100644 --- a/src/gui/painting/qplatformbackingstore.h +++ b/src/gui/painting/qplatformbackingstore.h @@ -52,9 +52,11 @@ // #include <QtCore/qrect.h> +#include <QtCore/qobject.h> #include <QtGui/qwindow.h> #include <QtGui/qregion.h> +#include <QtGui/qopengl.h> QT_BEGIN_NAMESPACE @@ -65,6 +67,33 @@ class QPoint; class QImage; class QPlatformBackingStorePrivate; class QPlatformWindow; +class QPlatformTextureList; +class QPlatformTextureListPrivate; +class QOpenGLContext; + +#ifndef QT_NO_OPENGL +class Q_GUI_EXPORT QPlatformTextureList : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QPlatformTextureList) +public: + explicit QPlatformTextureList(QObject *parent = 0); + ~QPlatformTextureList(); + + int count() const; + bool isEmpty() const { return count() == 0; } + GLuint textureId(int index) const; + QRect geometry(int index) const; + void lock(bool on); + bool isLocked() const; + + void appendTexture(GLuint textureId, const QRect &geometry); + void clear(); + + Q_SIGNALS: + void locked(bool); +}; +#endif class Q_GUI_EXPORT QPlatformBackingStore { @@ -79,6 +108,11 @@ public: // 'window' can be a child window, in which case 'region' is in child window coordinates and // offset is the (child) window's offset in relation to the window surface. virtual void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) = 0; +#ifndef QT_NO_OPENGL + virtual void composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, QOpenGLContext *context); + virtual QImage toImage() const; + virtual GLuint toTexture(const QRegion &dirtyRegion) const; +#endif virtual void resize(const QSize &size, const QRegion &staticContents) = 0; diff --git a/src/gui/painting/qrgb.h b/src/gui/painting/qrgb.h index 3c2bc5b97a..d8e19302d1 100644 --- a/src/gui/painting/qrgb.h +++ b/src/gui/painting/qrgb.h @@ -43,6 +43,7 @@ #define QRGB_H #include <QtCore/qglobal.h> +#include <QtCore/qprocessordetection.h> QT_BEGIN_NAMESPACE @@ -79,6 +80,48 @@ 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); } + +#if Q_PROCESSOR_WORDSIZE == 8 // 64-bit version +inline QRgb qPremultiply(QRgb x) +{ + const uint a = qAlpha(x); + quint64 t = (((quint64(x)) | ((quint64(x)) << 24)) & 0x00ff00ff00ff00ff) * a; + t = (t + ((t >> 8) & 0xff00ff00ff00ff) + 0x80008000800080) >> 8; + t &= 0x000000ff00ff00ff; + return (uint(t)) | (uint(t >> 24)) | (a << 24); +} +#else // 32-bit version +inline QRgb qPremultiply(QRgb x) +{ + const uint a = qAlpha(x); + uint t = (x & 0xff00ff) * a; + t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8; + t &= 0xff00ff; + + x = ((x >> 8) & 0xff) * a; + x = (x + ((x >> 8) & 0xff) + 0x80); + x &= 0xff00; + x |= t | (a << 24); + return x; +} +#endif + +Q_GUI_EXPORT extern const uint qt_inv_premul_factor[]; + +inline QRgb qUnpremultiply(QRgb p) +{ + const uint alpha = qAlpha(p); + // Alpha 255 and 0 are the two most common values, which makes them beneficial to short-cut. + if (alpha == 255) + return p; + if (alpha == 0) + return 0; + // (p*(0x00ff00ff/alpha)) >> 16 == (p*255)/alpha for all p and alpha <= 256. + const uint invAlpha = qt_inv_premul_factor[alpha]; + // We add 0x8000 to get even rounding. The rounding also ensures that qPremultiply(qUnpremultiply(p)) == p for all p. + return qRgba((qRed(p)*invAlpha + 0x8000)>>16, (qGreen(p)*invAlpha + 0x8000)>>16, (qBlue(p)*invAlpha + 0x8000)>>16, alpha); +} + QT_END_NAMESPACE #endif // QRGB_H diff --git a/src/gui/text/qdistancefield.cpp b/src/gui/text/qdistancefield.cpp index e584b66a25..f2b88c4692 100644 --- a/src/gui/text/qdistancefield.cpp +++ b/src/gui/text/qdistancefield.cpp @@ -739,13 +739,19 @@ bool qt_fontHasNarrowOutlines(QFontEngine *fontEngine) if (!fe) return false; - QGlyphLayout glyphs; + const QChar uc(QLatin1Char('O')); + glyph_t glyph; - glyphs.glyphs = &glyph; + + QGlyphLayout glyphs; glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; int numGlyphs = 1; - QChar uc = QLatin1Char('O'); - fe->stringToCMap(&uc, 1, &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly); + + if (!fe->stringToCMap(&uc, 1, &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(numGlyphs == 1); + QImage im = fe->alphaMapForGlyph(glyph, QFixed(), QTransform()); Q_ASSERT(fe->ref.load() == 0); diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index 49b5a9ba46..83f2d7190b 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -2073,6 +2073,18 @@ QString QFont::toString() const QString::number((int) rawMode()); } +/*! + Returns the hash value for \a font. If specified, \a seed is used + to initialize the hash. + + \relates QFont + \since 5.3 +*/ +uint qHash(const QFont &font, uint seed) Q_DECL_NOTHROW +{ + return qHash(QFontPrivate::get(font)->request, seed); +} + /*! Sets this font to match the description \a descrip. The description @@ -2533,8 +2545,10 @@ bool QFontInfo::fixedPitch() const QChar ch[2] = { QLatin1Char('i'), QLatin1Char('m') }; QGlyphLayoutArray<2> g; int l = 2; - engine->stringToCMap(ch, 2, &g, &l, 0); - engine->fontDef.fixedPitch = g.advances_x[0] == g.advances_x[1]; + if (!engine->stringToCMap(ch, 2, &g, &l, 0)) + Q_UNREACHABLE(); + Q_ASSERT(l == 2); + engine->fontDef.fixedPitch = g.advances[0] == g.advances[1]; engine->fontDef.fixedPitchComputed = true; } #endif diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h index 6d36f7839b..a207a1d60e 100644 --- a/src/gui/text/qfont.h +++ b/src/gui/text/qfont.h @@ -315,6 +315,8 @@ private: Q_DECLARE_SHARED(QFont) +Q_GUI_EXPORT uint qHash(const QFont &font, uint seed = 0) Q_DECL_NOTHROW; + inline bool QFont::bold() const { return weight() > Normal; } diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h index 5b7f918e21..6165554388 100644 --- a/src/gui/text/qfont_p.h +++ b/src/gui/text/qfont_p.h @@ -55,6 +55,7 @@ #include "QtGui/qfont.h" #include "QtCore/qmap.h" +#include "QtCore/qhash.h" #include "QtCore/qobject.h" #include "QtCore/qstringlist.h" #include <QtGui/qfontdatabase.h> @@ -133,6 +134,22 @@ struct QFontDef } }; +inline uint qHash(const QFontDef &fd, uint seed = 0) Q_DECL_NOTHROW +{ + return qHash(qRound64(fd.pixelSize*10000)) // use only 4 fractional digits + ^ qHash(fd.weight) + ^ qHash(fd.style) + ^ qHash(fd.stretch) + ^ qHash(fd.styleHint) + ^ qHash(fd.styleStrategy) + ^ qHash(fd.ignorePitch) + ^ qHash(fd.fixedPitch) + ^ qHash(fd.family, seed) + ^ qHash(fd.styleName) + ^ qHash(fd.hintingPreference) + ; +} + class QFontEngineData { public: diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h index 708b8cbd58..9986ef6c60 100644 --- a/src/gui/text/qfontdatabase.h +++ b/src/gui/text/qfontdatabase.h @@ -167,8 +167,6 @@ private: friend class QFontPrivate; friend class QFontDialog; friend class QFontDialogPrivate; - friend class QFontEngineMultiXLFD; - friend class QFontEngineMultiQWS; friend class QFontEngineMultiQPA; QFontDatabasePrivate *d; diff --git a/src/gui/text/qfontdatabase_qpa.cpp b/src/gui/text/qfontdatabase_qpa.cpp index 6f4971e267..1972f5d58c 100644 --- a/src/gui/text/qfontdatabase_qpa.cpp +++ b/src/gui/text/qfontdatabase_qpa.cpp @@ -182,10 +182,17 @@ QFontEngine *loadSingleEngine(int script, QFontCache::Key key(def,script); QFontEngine *engine = QFontCache::instance()->findEngine(key); if (!engine) { - engine = pfdb->fontEngine(def, QChar::Script(script), size->handle); + engine = pfdb->fontEngine(def, size->handle); if (engine) { - QFontCache::Key key(def,script); - QFontCache::instance()->instance()->insertEngine(key,engine); + // Also check for OpenType tables when using complex scripts + if (!engine->supportsScript(QChar::Script(script))) { + qWarning(" OpenType support missing for script %d", script); + if (engine->ref.load() == 0) + delete engine; + return 0; + } + + QFontCache::instance()->insertEngine(key, engine); } } return engine; @@ -221,10 +228,10 @@ QFontEngine *loadEngine(int script, const QFontDef &request, pfMultiEngine->setFallbackFamiliesList(fallbacks); engine = pfMultiEngine; - // Cache Multi font engine as well in case we got the FT single + // Cache Multi font engine as well in case we got the single // font engine when we are actually looking for a Multi one QFontCache::Key key(request, script, 1); - QFontCache::instance()->instance()->insertEngine(key, engine); + QFontCache::instance()->insertEngine(key, engine); } return engine; diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 9eea2e786f..14ce5d2396 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -48,6 +48,7 @@ #include "qvarlengtharray.h" #include <qmath.h> #include <qendian.h> +#include <private/qstringiterator_p.h> #ifdef QT_ENABLE_HARFBUZZ_NG # include "qharfbuzzng_p.h" @@ -89,18 +90,48 @@ static HB_Bool hb_stringToGlyphs(HB_Font font, const HB_UChar16 *string, hb_uint { QFontEngine *fe = (QFontEngine *)font->userData; + const QChar *str = reinterpret_cast<const QChar *>(string); + QGlyphLayout qglyphs; qglyphs.numGlyphs = *numGlyphs; qglyphs.glyphs = glyphs; - - QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly); - if (rightToLeft) - shaperFlags |= QFontEngine::RightToLeft; - int nGlyphs = *numGlyphs; - bool result = fe->stringToCMap(reinterpret_cast<const QChar *>(string), length, &qglyphs, &nGlyphs, shaperFlags); + bool result = fe->stringToCMap(str, length, &qglyphs, &nGlyphs, QFontEngine::GlyphIndicesOnly); *numGlyphs = nGlyphs; + if (rightToLeft && result && !fe->symbol) { + uint glyph_pos = 0; + for (uint i = 0; i < length; ++i, ++glyph_pos) { + uint ucs4 = str[i].unicode(); + if (Q_UNLIKELY(QChar::isHighSurrogate(ucs4) && i + 1 < length)) { + uint low = str[i + 1].unicode(); + if (Q_LIKELY(QChar::isLowSurrogate(low))) { + ucs4 = QChar::surrogateToUcs4(ucs4, low); + ++i; + } + } + + uint mirrored = QChar::mirroredChar(ucs4); + if (Q_UNLIKELY(mirrored != ucs4)) { + QChar chars[2]; + uint numChars = 0; + if (Q_UNLIKELY(QChar::requiresSurrogates(mirrored))) { + chars[numChars++] = QChar(QChar::highSurrogate(mirrored)); + chars[numChars++] = QChar(QChar::lowSurrogate(mirrored)); + } else { + chars[numChars++] = QChar(mirrored); + } + + qglyphs.numGlyphs = numChars; + qglyphs.glyphs = glyphs + glyph_pos; + nGlyphs = numChars; + if (!fe->stringToCMap(chars, numChars, &qglyphs, &nGlyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nGlyphs == 1); + } + } + } + return result; } @@ -108,13 +139,10 @@ static void hb_getAdvances(HB_Font font, const HB_Glyph *glyphs, hb_uint32 numGl { QFontEngine *fe = (QFontEngine *)font->userData; - QVarLengthArray<QFixed> advances_y(numGlyphs); - QGlyphLayout qglyphs; qglyphs.numGlyphs = numGlyphs; qglyphs.glyphs = const_cast<glyph_t *>(glyphs); - qglyphs.advances_x = reinterpret_cast<QFixed *>(advances); - qglyphs.advances_y = advances_y.data(); // not used + qglyphs.advances = reinterpret_cast<QFixed *>(advances); fe->recalcAdvances(&qglyphs, (flags & HB_ShaperFlag_UseDesignMetrics) ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlags(0)); } @@ -278,6 +306,10 @@ void *QFontEngine::harfbuzzFont() const return hb_qt_font_get_for_engine(const_cast<QFontEngine *>(this)); #endif if (!font_) { + HB_Face hbFace = (HB_Face)harfbuzzFace(); + if (hbFace->font_for_init != 0) + q_check_ptr(qHBLoadFace(hbFace)); + HB_FontRec *hbFont = (HB_FontRec *) malloc(sizeof(HB_FontRec)); Q_CHECK_PTR(hbFont); hbFont->klass = &hb_fontClass; @@ -308,8 +340,6 @@ void *QFontEngine::harfbuzzFace() const if (!face_) { HB_Face hbFace = qHBNewFace(const_cast<QFontEngine *>(this), hb_getSFntTable); Q_CHECK_PTR(hbFace); - if (hbFace->font_for_init != 0) - hbFace = qHBLoadFace(hbFace); hbFace->isSymbolFont = symbol; face_ = (void *)hbFace; @@ -349,6 +379,8 @@ bool QFontEngine::supportsScript(QChar::Script script) const } #endif HB_Face hbFace = (HB_Face)harfbuzzFace(); + if (hbFace->font_for_init != 0) + q_check_ptr(qHBLoadFace(hbFace)); return hbFace->supported_scripts[script_to_hbscript(script)]; } @@ -364,23 +396,39 @@ glyph_metrics_t QFontEngine::boundingBox(glyph_t glyph, const QTransform &matrix QFixed QFontEngine::xHeight() const { - QGlyphLayoutArray<8> glyphs; - int nglyphs = 7; QChar x((ushort)'x'); - stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly); - glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyphs.glyphs[0]); + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph); return bb.height; } QFixed QFontEngine::averageCharWidth() const { - QGlyphLayoutArray<8> glyphs; - int nglyphs = 7; QChar x((ushort)'x'); - stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly); - glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyphs.glyphs[0]); + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph); return bb.xoff; } @@ -411,8 +459,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform while(i--) { if (glyphs.attributes[i].dontPrint) continue; - xpos += glyphs.advances_x[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6); - ypos += glyphs.advances_y[i]; + xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6); totalKashidas += glyphs.justifications[i].nKashidas; } positions.resize(glyphs.numGlyphs+totalKashidas); @@ -424,8 +471,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform ++i; continue; } - xpos -= glyphs.advances_x[i]; - ypos -= glyphs.advances_y[i]; + xpos -= glyphs.advances[i]; QFixed gpos_x = xpos + glyphs.offsets[i].x; QFixed gpos_y = ypos + glyphs.offsets[i].y; @@ -441,12 +487,22 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform ++current; if (glyphs.justifications[i].nKashidas) { QChar ch(0x640); // Kashida character - QGlyphLayoutArray<8> g; - int nglyphs = 7; - stringToCMap(&ch, 1, &g, &nglyphs, 0); + + glyph_t kashidaGlyph; + QFixed kashidaWidth; + + QGlyphLayout g; + g.numGlyphs = 1; + g.glyphs = &kashidaGlyph; + g.advances = &kashidaWidth; + + int nglyphs = 1; + if (!stringToCMap(&ch, 1, &g, &nglyphs, 0)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + for (uint k = 0; k < glyphs.justifications[i].nKashidas; ++k) { - xpos -= g.advances_x[0]; - ypos -= g.advances_y[0]; + xpos -= kashidaWidth; QFixed gpos_x = xpos + glyphs.offsets[i].x; QFixed gpos_y = ypos + glyphs.offsets[i].y; @@ -458,7 +514,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform } positions[current].x = gpos_x; positions[current].y = gpos_y; - glyphs_out[current] = g.glyphs[0]; + glyphs_out[current] = kashidaGlyph; ++current; } } else { @@ -476,8 +532,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform positions[current].x = xpos + glyphs.offsets[i].x; positions[current].y = ypos + glyphs.offsets[i].y; glyphs_out[current] = glyphs.glyphs[i]; - xpos += glyphs.advances_x[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6); - ypos += glyphs.advances_y[i]; + xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6); ++current; } ++i; @@ -492,8 +547,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform positions[current].x = QFixed::fromReal(gpos.x()); positions[current].y = QFixed::fromReal(gpos.y()); glyphs_out[current] = glyphs.glyphs[i]; - xpos += glyphs.advances_x[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6); - ypos += glyphs.advances_y[i]; + xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6); ++current; } ++i; @@ -656,8 +710,7 @@ void QFontEngine::addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout &glyp for (int i=0; i < glyphs.numGlyphs; ++i) { glyph_metrics_t metrics = boundingBox(glyphs.glyphs[i]); if (metrics.width.value() == 0 || metrics.height.value() == 0) { - advanceX += glyphs.advances_x[i]; - advanceY += glyphs.advances_y[i]; + advanceX += glyphs.advances[i]; continue; } const QImage alphaMask = alphaMapForGlyph(glyphs.glyphs[i]); @@ -692,8 +745,7 @@ void QFontEngine::addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout &glyp advanceX += offset.x; advanceY += offset.y; qt_addBitmapToPath((advanceX + metrics.x).toReal(), (advanceY + metrics.y).toReal(), bitmap_data, bitmap.bytesPerLine(), w, h, path); - advanceX += glyphs.advances_x[i]; - advanceY += glyphs.advances_y[i]; + advanceX += glyphs.advances[i]; } } @@ -704,16 +756,12 @@ void QFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int n qreal y = positions[0].y.toReal(); QVarLengthGlyphLayoutArray g(nGlyphs); - for (int i = 0; i < nGlyphs; ++i) { + for (int i = 0; i < nGlyphs - 1; ++i) { g.glyphs[i] = glyphs[i]; - if (i < nGlyphs - 1) { - g.advances_x[i] = positions[i+1].x - positions[i].x; - g.advances_y[i] = positions[i+1].y - positions[i].y; - } else { - g.advances_x[i] = QFixed::fromReal(maxCharWidth()); - g.advances_y[i] = 0; - } + g.advances[i] = positions[i + 1].x - positions[i].x; } + g.glyphs[nGlyphs - 1] = glyphs[nGlyphs - 1]; + g.advances[nGlyphs - 1] = QFixed::fromReal(maxCharWidth()); addBitmapFontToPath(x, y, g, path, flags); } @@ -973,10 +1021,10 @@ void QFontEngine::doKerning(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags if (flags & DesignMetrics) { for(int i = 0; i < glyphs->numGlyphs - 1; ++i) - glyphs->advances_x[i] += kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs); + glyphs->advances[i] += kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs); } else { for(int i = 0; i < glyphs->numGlyphs - 1; ++i) - glyphs->advances_x[i] += qRound(kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs)); + glyphs->advances[i] += qRound(kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs)); } } @@ -1320,17 +1368,22 @@ QFontEngineBox::~QFontEngineBox() { } -bool QFontEngineBox::stringToCMap(const QChar *, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const +bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const { if (*nglyphs < len) { *nglyphs = len; return false; } - memset(glyphs->glyphs, 0, len * sizeof(glyph_t)); + int ucs4Length = 0; + QStringIterator it(str, str + len); + while (it.hasNext()) { + it.advance(); + glyphs->glyphs[ucs4Length++] = 0; + } - *nglyphs = len; - glyphs->numGlyphs = len; + *nglyphs = ucs4Length; + glyphs->numGlyphs = ucs4Length; if (!(flags & GlyphIndicesOnly)) recalcAdvances(glyphs, flags); @@ -1340,10 +1393,8 @@ bool QFontEngineBox::stringToCMap(const QChar *, int len, QGlyphLayout *glyphs, void QFontEngineBox::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const { - for (int i = 0; i < glyphs->numGlyphs; i++) { - glyphs->advances_x[i] = _size; - glyphs->advances_y[i] = 0; - } + for (int i = 0; i < glyphs->numGlyphs; i++) + glyphs->advances[i] = _size; } void QFontEngineBox::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) @@ -1503,11 +1554,9 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len, bool surrogate = (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()); uint ucs4 = surrogate ? QChar::surrogateToUcs4(str[i], str[i+1]) : str[i].unicode(); if (glyphs->glyphs[glyph_pos] == 0 && str[i].category() != QChar::Separator_Line) { - QFixedPoint tmpAdvance; - if (!(flags & GlyphIndicesOnly)) { - tmpAdvance.x = glyphs->advances_x[glyph_pos]; - tmpAdvance.y = glyphs->advances_y[glyph_pos]; - } + QFixed tmpAdvance; + if (!(flags & GlyphIndicesOnly)) + tmpAdvance = glyphs->advances[glyph_pos]; for (int x = 1, n = qMin(engines.size(), 256); x < n; ++x) { if (engines.at(x) == 0 && !shouldLoadFontEngineForCharacter(x, ucs4)) continue; @@ -1522,11 +1571,12 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len, continue; if (!(flags & GlyphIndicesOnly)) - glyphs->advances_x[glyph_pos] = glyphs->advances_y[glyph_pos] = 0; + glyphs->advances[glyph_pos] = QFixed(); int num = 2; - QGlyphLayout offs = glyphs->mid(glyph_pos, num); - engine->stringToCMap(str + i, surrogate ? 2 : 1, &offs, &num, flags); - Q_ASSERT(num == 1); // surrogates only give 1 glyph + QGlyphLayout g = glyphs->mid(glyph_pos, num); + if (!engine->stringToCMap(str + i, surrogate ? 2 : 1, &g, &num, flags)) + Q_UNREACHABLE(); + Q_ASSERT(num == 1); if (glyphs->glyphs[glyph_pos]) { // set the high byte to indicate which engine the glyph came from glyphs->glyphs[glyph_pos] |= (x << 24); @@ -1535,10 +1585,8 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len, } // ensure we use metrics from the 1st font when we use the fallback image. - if (!(flags & GlyphIndicesOnly) && glyphs->glyphs[glyph_pos] == 0) { - glyphs->advances_x[glyph_pos] = tmpAdvance.x; - glyphs->advances_y[glyph_pos] = tmpAdvance.y; - } + if (!(flags & GlyphIndicesOnly) && glyphs->glyphs[glyph_pos] == 0) + glyphs->advances[glyph_pos] = tmpAdvance; } if (surrogate) @@ -1639,10 +1687,8 @@ void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &gl int start = 0; int end, i; if (flags & QTextItem::RightToLeft) { - for (int gl = 0; gl < glyphs.numGlyphs; gl++) { - x += glyphs.advances_x[gl].toReal(); - y += glyphs.advances_y[gl].toReal(); - } + for (int gl = 0; gl < glyphs.numGlyphs; gl++) + x += glyphs.advances[gl].toReal(); } for (end = 0; end < glyphs.numGlyphs; ++end) { const int e = highByte(glyphs.glyphs[end]); @@ -1650,10 +1696,8 @@ void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &gl continue; if (flags & QTextItem::RightToLeft) { - for (i = start; i < end; ++i) { - x -= glyphs.advances_x[i].toReal(); - y -= glyphs.advances_y[i].toReal(); - } + for (i = start; i < end; ++i) + x -= glyphs.advances[i].toReal(); } // set the high byte to zero @@ -1666,10 +1710,8 @@ void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &gl glyphs.glyphs[i] = hi | glyphs.glyphs[i]; if (!(flags & QTextItem::RightToLeft)) { - for (i = start; i < end; ++i) { - x += glyphs.advances_x[i].toReal(); - y += glyphs.advances_y[i].toReal(); - } + for (i = start; i < end; ++i) + x += glyphs.advances[i].toReal(); } // change engine @@ -1678,10 +1720,8 @@ void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &gl } if (flags & QTextItem::RightToLeft) { - for (i = start; i < end; ++i) { - x -= glyphs.advances_x[i].toReal(); - y -= glyphs.advances_y[i].toReal(); - } + for (i = start; i < end; ++i) + x -= glyphs.advances[i].toReal(); } // set the high byte to zero @@ -1847,16 +1887,11 @@ bool QFontEngineMulti::canRender(const QChar *string, int len) QGlyphLayout g; g.numGlyphs = nglyphs; g.glyphs = glyphs.data(); - if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly)) { - glyphs.resize(nglyphs); - g.numGlyphs = nglyphs; - g.glyphs = glyphs.data(); - if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly)) - Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice"); - } + if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly)) + Q_UNREACHABLE(); for (int i = 0; i < nglyphs; i++) { - if (g.glyphs[i] == 0) + if (glyphs[i] == 0) return false; } diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index 05bd014bd7..665932e4a5 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -723,7 +723,7 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, FT_Set_Transform(face, &matrix, 0); freetype->matrix = matrix; // fake bold - if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face)) + if ((fontDef.weight >= QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face)) embolden = true; // underline metrics line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale)); @@ -1196,7 +1196,7 @@ int QFontEngineFT::synthesized() const int s = 0; if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC)) s = SynthesizedItalic; - if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD)) + if ((fontDef.weight >= QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD)) s |= SynthesizedBold; if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face)) s |= SynthesizedStretch; @@ -1283,13 +1283,22 @@ qreal QFontEngineFT::minRightBearing() const { if (rbearing == SHRT_MIN) { lbearing = rbearing = 0; - const QChar *ch = (const QChar *)(const void*)char_table; - QGlyphLayoutArray<char_table_entries> glyphs; + + const QChar *ch = reinterpret_cast<const QChar *>(char_table); + + glyph_t glyphs[char_table_entries]; + + QGlyphLayout g; + g.glyphs = glyphs; + g.numGlyphs = char_table_entries; int ng = char_table_entries; - stringToCMap(ch, char_table_entries, &glyphs, &ng, GlyphIndicesOnly); + if (!stringToCMap(ch, char_table_entries, &g, &ng, GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(ng == char_table_entries); + while (--ng) { - if (glyphs.glyphs[ng]) { - glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]); + if (glyphs[ng]) { + glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs[ng]); lbearing = qMin(lbearing, gi.x); rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width)); } @@ -1525,7 +1534,6 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs return false; } - bool mirrored = flags & QFontEngine::RightToLeft; int glyph_pos = 0; if (freetype->symbol_map) { FT_Face face = freetype->face; @@ -1561,8 +1569,6 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs FT_Face face = freetype->face; for (int i = 0; i < len; ++i) { unsigned int uc = getChar(str, i, len); - if (mirrored) - uc = QChar::mirroredChar(uc); glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0; if (!glyphs->glyphs[glyph_pos]) { { @@ -1607,24 +1613,23 @@ void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlag // Since we are passing Format_None to loadGlyph, use same default format logic as loadGlyph GlyphFormat acceptableFormat = (defaultFormat != Format_None) ? defaultFormat : Format_Mono; if (g && g->format == acceptableFormat) { - glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance); + glyphs->advances[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance); } else { if (!face) face = lockFace(); g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true); - glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10) - : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round(); + glyphs->advances[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10) + : QFixed::fromFixed(face->glyph->metrics.horiAdvance); if (!cacheEnabled) delete g; } - glyphs->advances_y[i] = 0; } if (face) unlockFace(); if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { for (int i = 0; i < glyphs->numGlyphs; ++i) - glyphs->advances_x[i] = glyphs->advances_x[i].round(); + glyphs->advances[i] = glyphs->advances[i].round(); } } diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index a04f4bd0ac..532ebaf8ff 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -121,7 +121,6 @@ public: }; enum ShaperFlag { - RightToLeft = 0x0001, DesignMetrics = 0x0002, GlyphIndicesOnly = 0x0004 }; diff --git a/src/gui/text/qfontengine_qpa.cpp b/src/gui/text/qfontengine_qpa.cpp index 28b95bd509..cb40a5388a 100644 --- a/src/gui/text/qfontengine_qpa.cpp +++ b/src/gui/text/qfontengine_qpa.cpp @@ -353,13 +353,10 @@ bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset); - bool mirrored = flags & QFontEngine::RightToLeft; int glyph_pos = 0; if (symbol) { for (int i = 0; i < len; ++i) { unsigned int uc = getChar(str, i, len); - if (mirrored) - uc = QChar::mirroredChar(uc); glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); if(!glyphs->glyphs[glyph_pos] && uc < 0x100) glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000); @@ -368,8 +365,6 @@ bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph } else { for (int i = 0; i < len; ++i) { unsigned int uc = getChar(str, i, len); - if (mirrored) - uc = QChar::mirroredChar(uc); glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); #if 0 && defined(DEBUG_FONTENGINE) QChar c(uc); @@ -399,8 +394,7 @@ void QFontEngineQPA::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFla glyphs->glyphs[i] = 0; continue; } - glyphs->advances_x[i] = g->advance; - glyphs->advances_y[i] = 0; + glyphs->advances[i] = g->advance; } } diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp index 1a66657cbd..2f4709afe4 100644 --- a/src/gui/text/qfontmetrics.cpp +++ b/src/gui/text/qfontmetrics.cpp @@ -458,12 +458,19 @@ int QFontMetrics::leftBearing(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - // ### can nglyphs != 1 happen at all? Not currently I think + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + qreal lb; - engine->getGlyphBearings(glyphs.glyphs[0], &lb); + engine->getGlyphBearings(glyph, &lb); return qRound(lb); } @@ -493,12 +500,19 @@ int QFontMetrics::rightBearing(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - // ### can nglyphs != 1 happen at all? Not currently I think + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + qreal rb; - engine->getGlyphBearings(glyphs.glyphs[0], 0, &rb); + engine->getGlyphBearings(glyph, 0, &rb); return qRound(rb); } @@ -538,15 +552,12 @@ int QFontMetrics::width(const QString &text, int len, int flags) const int numGlyphs = len; QVarLengthGlyphLayoutArray glyphs(numGlyphs); QFontEngine *engine = d->engineForScript(QChar::Script_Common); - if (!engine->stringToCMap(text.data(), len, &glyphs, &numGlyphs, 0)) { - glyphs.resize(numGlyphs); - if (!engine->stringToCMap(text.data(), len, &glyphs, &numGlyphs, 0)) - Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice"); - } + if (!engine->stringToCMap(text.data(), len, &glyphs, &numGlyphs, 0)) + Q_UNREACHABLE(); QFixed width; for (int i = 0; i < numGlyphs; ++i) - width += glyphs.advances_x[i]; + width += glyphs.advances[i]; return qRound(width); } @@ -594,10 +605,20 @@ int QFontMetrics::width(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<8> glyphs; - int nglyphs = 7; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0); - return qRound(glyphs.advances_x[0]); + QFixed advance; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyph_t glyph; + glyphs.glyphs = &glyph; + glyphs.advances = &advance; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + return qRound(advance); } /*! \obsolete @@ -639,10 +660,20 @@ int QFontMetrics::charWidth(const QString &text, int pos) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<8> glyphs; - int nglyphs = 7; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0); - width = qRound(glyphs.advances_x[0]); + QFixed advance; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyph_t glyph; + glyphs.glyphs = &glyph; + glyphs.advances = &advance; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + width = qRound(advance); } return width; } @@ -708,10 +739,18 @@ QRect QFontMetrics::boundingRect(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - glyph_metrics_t gm = engine->boundingBox(glyphs.glyphs[0]); + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + glyph_metrics_t gm = engine->boundingBox(glyph); return QRect(qRound(gm.x), qRound(gm.y), qRound(gm.width), qRound(gm.height)); } @@ -1326,12 +1365,19 @@ qreal QFontMetricsF::leftBearing(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - // ### can nglyphs != 1 happen at all? Not currently I think + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + qreal lb; - engine->getGlyphBearings(glyphs.glyphs[0], &lb); + engine->getGlyphBearings(glyph, &lb); return lb; } @@ -1361,12 +1407,19 @@ qreal QFontMetricsF::rightBearing(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - // ### can nglyphs != 1 happen at all? Not currently I think + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + qreal rb; - engine->getGlyphBearings(glyphs.glyphs[0], 0, &rb); + engine->getGlyphBearings(glyph, 0, &rb); return rb; } @@ -1431,10 +1484,20 @@ qreal QFontMetricsF::width(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<8> glyphs; - int nglyphs = 7; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0); - return glyphs.advances_x[0].toReal(); + QFixed advance; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyph_t glyph; + glyphs.glyphs = &glyph; + glyphs.advances = &advance; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + return advance.toReal(); } /*! @@ -1496,10 +1559,18 @@ QRectF QFontMetricsF::boundingRect(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - glyph_metrics_t gm = engine->boundingBox(glyphs.glyphs[0]); + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + glyph_metrics_t gm = engine->boundingBox(glyph); return QRectF(gm.x.toReal(), gm.y.toReal(), gm.width.toReal(), gm.height.toReal()); } diff --git a/src/gui/text/qfontsubset.cpp b/src/gui/text/qfontsubset.cpp index 152e15a54d..2109b16bb5 100644 --- a/src/gui/text/qfontsubset.cpp +++ b/src/gui/text/qfontsubset.cpp @@ -201,12 +201,22 @@ static void checkRanges(QPdf::ByteStream &ts, QByteArray &ranges, int &nranges) QVector<int> QFontSubset::getReverseMap() const { QVector<int> reverseMap(0x10000, 0); - QGlyphLayoutArray<10> glyphs; + + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.glyphs = &glyph; + glyphs.numGlyphs = 1; + for (uint uc = 0; uc < 0x10000; ++uc) { QChar ch(uc); - int nglyphs = 10; - fontEngine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - int idx = glyph_indices.indexOf(glyphs.glyphs[0]); + + int nglyphs = 1; + if (!fontEngine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + int idx = glyph_indices.indexOf(glyph); if (idx >= 0 && !reverseMap.at(idx)) reverseMap[idx] = uc; } diff --git a/src/gui/text/qharfbuzzng.cpp b/src/gui/text/qharfbuzzng.cpp index d2e7df9c10..c09f27b665 100644 --- a/src/gui/text/qharfbuzzng.cpp +++ b/src/gui/text/qharfbuzzng.cpp @@ -397,13 +397,7 @@ _hb_qt_font_get_glyph(hb_font_t * /*font*/, void *font_data, QFontEngine *fe = (QFontEngine *)font_data; Q_ASSERT(fe); - glyph_t glyphs[2] = { 0, 0 }; - - QGlyphLayout g; - g.numGlyphs = 2; - g.glyphs = glyphs; - - QChar chars[4]; + QChar chars[2]; int numChars = 0; if (Q_UNLIKELY(QChar::requiresSurrogates(unicode))) { chars[numChars++] = QChar(QChar::highSurrogate(unicode)); @@ -422,11 +416,14 @@ _hb_qt_font_get_glyph(hb_font_t * /*font*/, void *font_data, } #endif - int numGlyphs = g.numGlyphs; - bool ok = fe->stringToCMap(chars, numChars, &g, &numGlyphs, QFontEngine::GlyphIndicesOnly); - Q_ASSERT(ok); Q_UNUSED(ok) + QGlyphLayout g; + g.numGlyphs = numChars; + g.glyphs = glyph; - *glyph = g.glyphs[0]; + int numGlyphs = numChars; + if (!fe->stringToCMap(chars, numChars, &g, &numGlyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(numGlyphs == 1); return true; } @@ -439,18 +436,16 @@ _hb_qt_font_get_glyph_h_advance(hb_font_t *font, void *font_data, QFontEngine *fe = (QFontEngine *)font_data; Q_ASSERT(fe); - QFixed advance_x; - QFixed advance_y; + QFixed advance; QGlyphLayout g; g.numGlyphs = 1; g.glyphs = &glyph; - g.advances_x = &advance_x; - g.advances_y = &advance_y; + g.advances = &advance; fe->recalcAdvances(&g, QFontEngine::ShaperFlags(hb_qt_font_get_use_design_metrics(font))); - return g.advances_x[0].value(); + return advance.value(); } static hb_position_t @@ -490,18 +485,16 @@ _hb_qt_font_get_glyph_h_kerning(hb_font_t *font, void *font_data, Q_ASSERT(fe); glyph_t glyphs[2] = { first_glyph, second_glyph }; - QFixed advance_x; - QFixed advance_y; + QFixed advance; QGlyphLayout g; g.numGlyphs = 2; g.glyphs = glyphs; - g.advances_x = &advance_x; - g.advances_y = &advance_y; + g.advances = &advance; fe->doKerning(&g, QFontEngine::ShaperFlags(hb_qt_font_get_use_design_metrics(font))); - return g.advances_x[0].value(); + return advance.value(); } static hb_position_t @@ -710,7 +703,11 @@ _hb_qt_font_create(QFontEngine *fe) const int x_ppem = (fe->fontDef.pixelSize * fe->fontDef.stretch) / 100; hb_font_set_funcs(font, hb_qt_get_font_funcs(), (void *)fe, NULL); +#ifdef Q_OS_MAC + hb_font_set_scale(font, QFixed(x_ppem).value(), QFixed(y_ppem).value()); +#else hb_font_set_scale(font, QFixed(x_ppem).value(), -QFixed(y_ppem).value()); +#endif hb_font_set_ppem(font, x_ppem, y_ppem); return font; diff --git a/src/gui/text/qplatformfontdatabase.cpp b/src/gui/text/qplatformfontdatabase.cpp index 37610a9099..7936831e13 100644 --- a/src/gui/text/qplatformfontdatabase.cpp +++ b/src/gui/text/qplatformfontdatabase.cpp @@ -289,13 +289,11 @@ QFontEngineMulti *QPlatformFontDatabase::fontEngineMulti(QFontEngine *fontEngine Returns the font engine that can be used to render the font described by the font definition, \a fontDef, in the specified \a script. */ -QFontEngine *QPlatformFontDatabase::fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle) +QFontEngine *QPlatformFontDatabase::fontEngine(const QFontDef &fontDef, void *handle) { - Q_UNUSED(script); - Q_UNUSED(handle); QByteArray *fileDataPtr = static_cast<QByteArray *>(handle); QFontEngineQPA *engine = new QFontEngineQPA(fontDef,*fileDataPtr); - //qDebug() << fontDef.pixelSize << fontDef.weight << fontDef.style << fontDef.stretch << fontDef.styleHint << fontDef.styleStrategy << fontDef.family << script; + //qDebug() << fontDef.pixelSize << fontDef.weight << fontDef.style << fontDef.stretch << fontDef.styleHint << fontDef.styleStrategy << fontDef.family; return engine; } diff --git a/src/gui/text/qplatformfontdatabase.h b/src/gui/text/qplatformfontdatabase.h index 6053f11051..5f2c9a74ba 100644 --- a/src/gui/text/qplatformfontdatabase.h +++ b/src/gui/text/qplatformfontdatabase.h @@ -97,7 +97,7 @@ public: virtual ~QPlatformFontDatabase(); virtual void populateFontDatabase(); virtual QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script); - virtual QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle); + virtual QFontEngine *fontEngine(const QFontDef &fontDef, void *handle); virtual QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; virtual QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); virtual void releaseHandle(void *handle); diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp index b1b910422c..449278df06 100644 --- a/src/gui/text/qrawfont.cpp +++ b/src/gui/text/qrawfont.cpp @@ -479,16 +479,8 @@ QVector<quint32> QRawFont::glyphIndexesForString(const QString &text) const QGlyphLayout glyphs; glyphs.numGlyphs = numGlyphs; glyphs.glyphs = glyphIndexes.data(); - if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly)) { - glyphIndexes.resize(numGlyphs); - - glyphs.numGlyphs = numGlyphs; - glyphs.glyphs = glyphIndexes.data(); - if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly)) { - Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice"); - return QVector<quint32>(); - } - } + if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); glyphIndexes.resize(numGlyphs); return glyphIndexes; @@ -565,13 +557,12 @@ bool QRawFont::advancesForGlyphIndexes(const quint32 *glyphIndexes, QPointF *adv if (!d->isValid() || numGlyphs <= 0) return false; + QVarLengthArray<QFixed> tmpAdvances(numGlyphs); + QGlyphLayout glyphs; glyphs.glyphs = const_cast<glyph_t *>(glyphIndexes); glyphs.numGlyphs = numGlyphs; - QVarLengthArray<QFixed> advances_x(numGlyphs); - QVarLengthArray<QFixed> advances_y(numGlyphs); - glyphs.advances_x = advances_x.data(); - glyphs.advances_y = advances_y.data(); + glyphs.advances = tmpAdvances.data(); bool design = layoutFlags & UseDesignMetrics; @@ -580,7 +571,7 @@ bool QRawFont::advancesForGlyphIndexes(const quint32 *glyphIndexes, QPointF *adv d->fontEngine->doKerning(&glyphs, design ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlag(0)); for (int i=0; i<numGlyphs; ++i) - advances[i] = QPointF(glyphs.advances_x[i].toReal(), glyphs.advances_y[i].toReal()); + advances[i] = QPointF(tmpAdvances[i].toReal(), 0.0); return true; } diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp index d12f3cccd8..ac9762b183 100644 --- a/src/gui/text/qtextcursor.cpp +++ b/src/gui/text/qtextcursor.cpp @@ -174,7 +174,6 @@ void QTextCursorPrivate::remove() } else { priv->remove(pos1, pos2-pos1, op); adjusted_anchor = anchor = position; - priv->finishEdit(); } } diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index 4a34f0d3c3..fa54776b6d 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -551,6 +551,39 @@ void QTextDocument::setDefaultTextOption(const QTextOption &option) } /*! + \property QTextDocument::baseUrl + \since 5.3 + \brief the base URL used to resolve relative resource URLs within the document. + + Resource URLs are resolved to be within the same directory as the target of the base + URL meaning any portion of the path after the last '/' will be ignored. + + \table + \header \li Base URL \li Relative URL \li Resolved URL + \row \li file:///path/to/content \li images/logo.png \li file:///path/to/images/logo.png + \row \li file:///path/to/content/ \li images/logo.png \li file:///path/to/content/images/logo.png + \row \li file:///path/to/content/index.html \li images/logo.png \li file:///path/to/content/images/logo.png + \row \li file:///path/to/content/images/ \li ../images/logo.png \li file:///path/to/content/images/logo.png + \endtable +*/ +QUrl QTextDocument::baseUrl() const +{ + Q_D(const QTextDocument); + return d->baseUrl; +} + +void QTextDocument::setBaseUrl(const QUrl &url) +{ + Q_D(QTextDocument); + if (d->baseUrl != url) { + d->baseUrl = url; + if (d->lout) + d->lout->documentChanged(0, 0, d->length()); + emit baseUrlChanged(url); + } +} + +/*! \since 4.8 The default cursor movement style is used by all QTextCursor objects @@ -1849,11 +1882,12 @@ void QTextDocument::print(QPagedPaintDevice *printer) const QVariant QTextDocument::resource(int type, const QUrl &name) const { Q_D(const QTextDocument); - QVariant r = d->resources.value(name); + const QUrl url = d->baseUrl.resolved(name); + QVariant r = d->resources.value(url); if (!r.isValid()) { - r = d->cachedResources.value(name); + r = d->cachedResources.value(url); if (!r.isValid()) - r = const_cast<QTextDocument *>(this)->loadResource(type, name); + r = const_cast<QTextDocument *>(this)->loadResource(type, url); } return r; } @@ -1924,27 +1958,29 @@ QVariant QTextDocument::loadResource(int type, const QUrl &name) } // if resource was not loaded try to load it here - if (!qobject_cast<QTextDocument *>(p) && r.isNull() && name.isRelative()) { - QUrl currentURL = d->url; + if (!qobject_cast<QTextDocument *>(p) && r.isNull()) { QUrl resourceUrl = name; - // For the second case QUrl can merge "#someanchor" with "foo.html" - // correctly to "foo.html#someanchor" - if (!(currentURL.isRelative() - || (currentURL.scheme() == QLatin1String("file") - && !QFileInfo(currentURL.toLocalFile()).isAbsolute())) - || (name.hasFragment() && name.path().isEmpty())) { - resourceUrl = currentURL.resolved(name); - } else { - // this is our last resort when current url and new url are both relative - // we try to resolve against the current working directory in the local - // file system. - QFileInfo fi(currentURL.toLocalFile()); - if (fi.exists()) { - resourceUrl = - QUrl::fromLocalFile(fi.absolutePath() + QDir::separator()).resolved(name); - } else if (currentURL.isEmpty()) { - resourceUrl.setScheme(QLatin1String("file")); + if (name.isRelative()) { + QUrl currentURL = d->url; + // For the second case QUrl can merge "#someanchor" with "foo.html" + // correctly to "foo.html#someanchor" + if (!(currentURL.isRelative() + || (currentURL.scheme() == QLatin1String("file") + && !QFileInfo(currentURL.toLocalFile()).isAbsolute())) + || (name.hasFragment() && name.path().isEmpty())) { + resourceUrl = currentURL.resolved(name); + } else { + // this is our last resort when current url and new url are both relative + // we try to resolve against the current working directory in the local + // file system. + QFileInfo fi(currentURL.toLocalFile()); + if (fi.exists()) { + resourceUrl = + QUrl::fromLocalFile(fi.absolutePath() + QDir::separator()).resolved(name); + } else if (currentURL.isEmpty()) { + resourceUrl.setScheme(QLatin1String("file")); + } } } @@ -2124,13 +2160,21 @@ bool QTextHtmlExporter::emitCharFormatStyle(const QTextCharFormat &format) html += QLatin1String("pt;"); attributesEmitted = true; } else if (format.hasProperty(QTextFormat::FontSizeAdjustment)) { - static const char * const sizeNames[] = { - "small", "medium", "large", "x-large", "xx-large" + static const char sizeNameData[] = + "small" "\0" + "medium" "\0" + "xx-large" ; + static const quint8 sizeNameOffsets[] = { + 0, // "small" + sizeof("small"), // "medium" + sizeof("small") + sizeof("medium") + 3, // "large" ) + sizeof("small") + sizeof("medium") + 1, // "x-large" )> compressed into "xx-large" + sizeof("small") + sizeof("medium"), // "xx-large" ) }; const char *name = 0; const int idx = format.intProperty(QTextFormat::FontSizeAdjustment) + 1; if (idx >= 0 && idx <= 4) { - name = sizeNames[idx]; + name = sizeNameData + sizeNameOffsets[idx]; } if (name) { html += QLatin1String(" font-size:"); diff --git a/src/gui/text/qtextdocument.h b/src/gui/text/qtextdocument.h index d8f52e9f98..854cb29ed9 100644 --- a/src/gui/text/qtextdocument.h +++ b/src/gui/text/qtextdocument.h @@ -47,6 +47,7 @@ #include <QtCore/qrect.h> #include <QtCore/qvariant.h> #include <QtGui/qfont.h> +#include <QtCore/qurl.h> QT_BEGIN_NAMESPACE @@ -63,7 +64,6 @@ class QTextFormat; class QTextFrame; class QTextBlock; class QTextCodec; -class QUrl; class QVariant; class QRectF; class QTextOption; @@ -116,6 +116,7 @@ class Q_GUI_EXPORT QTextDocument : public QObject Q_PROPERTY(int maximumBlockCount READ maximumBlockCount WRITE setMaximumBlockCount) Q_PROPERTY(qreal documentMargin READ documentMargin WRITE setDocumentMargin) QDOC_PROPERTY(QTextOption defaultTextOption READ defaultTextOption WRITE setDefaultTextOption) + Q_PROPERTY(QUrl baseUrl READ baseUrl WRITE setBaseUrl NOTIFY baseUrlChanged) public: explicit QTextDocument(QObject *parent = 0); @@ -258,6 +259,9 @@ public: QTextOption defaultTextOption() const; void setDefaultTextOption(const QTextOption &option); + QUrl baseUrl() const; + void setBaseUrl(const QUrl &url); + Qt::CursorMoveStyle defaultCursorMoveStyle() const; void setDefaultCursorMoveStyle(Qt::CursorMoveStyle style); @@ -270,7 +274,7 @@ Q_SIGNALS: void modificationChanged(bool m); void cursorPositionChanged(const QTextCursor &cursor); void blockCountChanged(int newBlockCount); - + void baseUrlChanged(const QUrl &url); void documentLayoutChanged(); public Q_SLOTS: diff --git a/src/gui/text/qtextdocument_p.h b/src/gui/text/qtextdocument_p.h index 8d4cab30ae..fa22131c9e 100644 --- a/src/gui/text/qtextdocument_p.h +++ b/src/gui/text/qtextdocument_p.h @@ -355,6 +355,7 @@ public: QString url; qreal indentWidth; qreal documentMargin; + QUrl baseUrl; void mergeCachedResources(const QTextDocumentPrivate *priv); diff --git a/src/gui/text/qtextdocumentfragment.cpp b/src/gui/text/qtextdocumentfragment.cpp index df67fb581a..3bd1e2a801 100644 --- a/src/gui/text/qtextdocumentfragment.cpp +++ b/src/gui/text/qtextdocumentfragment.cpp @@ -489,7 +489,7 @@ void QTextHtmlImporter::import() && currentNode->id != Html_unknown) { hasBlock = false; - } else if (hasBlock) { + } else if (blockTagClosed && hasBlock) { // when collapsing subsequent block tags we need to clear the block format QTextBlockFormat blockFormat = currentNode->blockFormat; blockFormat.setIndent(indent); diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index febdaaa86c..eb31c520ed 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -241,7 +241,8 @@ using namespace std; static const char *directions[] = { "DirL", "DirR", "DirEN", "DirES", "DirET", "DirAN", "DirCS", "DirB", "DirS", "DirWS", "DirON", - "DirLRE", "DirLRO", "DirAL", "DirRLE", "DirRLO", "DirPDF", "DirNSM", "DirBN" + "DirLRE", "DirLRO", "DirAL", "DirRLE", "DirRLO", "DirPDF", "DirNSM", "DirBN", + "DirLRI", "DirRLI", "DirFSI", "DirPDI" }; #endif @@ -928,21 +929,8 @@ void QTextEngine::shapeText(int item) const int nGlyphs = initialGlyphs.numGlyphs; QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly); - if (si.analysis.bidiLevel % 2) - shaperFlags |= QFontEngine::RightToLeft; - - if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags)) { - nGlyphs = qMax(nGlyphs, itemLength); // ### needed for QFontEngine::stringToCMap() to not fail twice - if (!ensureSpace(nGlyphs)) { - Q_UNREACHABLE(); // ### report OOM error somehow - return; - } - initialGlyphs = availableGlyphs(&si); - if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags)) { - Q_UNREACHABLE(); // ### if this happens there is a bug in the fontengine - return; - } - } + if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags)) + Q_UNREACHABLE(); uint lastEngine = ~0u; for (int i = 0, glyph_pos = 0; i < itemLength; ++i, ++glyph_pos) { @@ -1014,17 +1002,17 @@ void QTextEngine::shapeText(int item) const for (int i = 1; i < si.num_glyphs; ++i) { if (glyphs.attributes[i].clusterStart) { if (letterSpacingIsAbsolute) - glyphs.advances_x[i-1] += letterSpacing; + glyphs.advances[i - 1] += letterSpacing; else { - QFixed &advance = glyphs.advances_x[i-1]; + QFixed &advance = glyphs.advances[i - 1]; advance += (letterSpacing - 100) * advance / 100; } } } if (letterSpacingIsAbsolute) - glyphs.advances_x[si.num_glyphs-1] += letterSpacing; + glyphs.advances[si.num_glyphs - 1] += letterSpacing; else { - QFixed &advance = glyphs.advances_x[si.num_glyphs-1]; + QFixed &advance = glyphs.advances[si.num_glyphs - 1]; advance += (letterSpacing - 100) * advance / 100; } } @@ -1036,13 +1024,13 @@ void QTextEngine::shapeText(int item) const if (i + 1 == si.num_glyphs ||(glyphs.attributes[i+1].justification != QGlyphAttributes::Space && glyphs.attributes[i+1].justification != QGlyphAttributes::Arabic_Space)) - glyphs.advances_x[i] += wordSpacing; + glyphs.advances[i] += wordSpacing; } } } for (int i = 0; i < si.num_glyphs; ++i) - si.width += glyphs.advances_x[i] * !glyphs.attributes[i].dontPrint; + si.width += glyphs.advances[i] * !glyphs.attributes[i].dontPrint; } #ifdef QT_ENABLE_HARFBUZZ_NG @@ -1139,8 +1127,7 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *st for (uint i = 0; i < num_glyphs; ++i) { g.glyphs[i] = infos[i].codepoint; - g.advances_x[i] = QFixed::fromFixed(positions[i].x_advance); - g.advances_y[i] = QFixed::fromFixed(positions[i].y_advance); + g.advances[i] = QFixed::fromFixed(positions[i].x_advance); g.offsets[i].x = QFixed::fromFixed(positions[i].x_offset); g.offsets[i].y = QFixed::fromFixed(positions[i].y_offset); @@ -1163,6 +1150,13 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *st g.glyphs[i] |= (engineIdx << 24); } +#ifdef Q_OS_MAC + if (actualFontEngine->fontDef.styleStrategy & QFont::ForceIntegerMetrics) { + for (uint i = 0; i < num_glyphs; ++i) + g.advances[i] = g.advances[i].round(); + } +#endif + glyphs_shaped += num_glyphs; } @@ -1238,7 +1232,8 @@ int QTextEngine::shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *stri if (fontEngine->type() == QFontEngine::Multi) { actualFontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx); - shaper_item.glyphIndicesPresent = true; + if ((si.analysis.bidiLevel % 2) == 0) + shaper_item.glyphIndicesPresent = true; } shaper_item.font = (HB_Font)actualFontEngine->harfbuzzFont(); @@ -1256,7 +1251,7 @@ int QTextEngine::shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *stri shaper_item.glyphs = reinterpret_cast<HB_Glyph *>(g.glyphs); shaper_item.attributes = reinterpret_cast<HB_GlyphAttributes *>(g.attributes); - shaper_item.advances = reinterpret_cast<HB_Fixed *>(g.advances_x); + shaper_item.advances = reinterpret_cast<HB_Fixed *>(g.advances); shaper_item.offsets = reinterpret_cast<HB_FixedPoint *>(g.offsets); if (engineIdx != 0 && shaper_item.glyphIndicesPresent) { @@ -1360,9 +1355,9 @@ void QTextEngine::shape(int item) const if (layoutData->items[item].analysis.flags == QScriptAnalysis::Object) { ensureSpace(1); if (block.docHandle()) { - QTextFormat format = formats()->format(formatIndex(&layoutData->items[item])); docLayout()->resizeInlineObject(QTextInlineObject(item, const_cast<QTextEngine *>(this)), - layoutData->items[item].position + block.position(), format); + layoutData->items[item].position + block.position(), + format(&layoutData->items[item])); } } else if (layoutData->items[item].analysis.flags == QScriptAnalysis::Tab) { // set up at least the ascent/descent/leading of the script item for the tab @@ -1394,7 +1389,7 @@ void QTextEngine::invalidate() minWidth = 0; maxWidth = 0; if (specialData) - specialData->resolvedFormatIndices.clear(); + specialData->resolvedFormats.clear(); resetFontEngineCache(); } @@ -1468,8 +1463,18 @@ void QTextEngine::itemize() const { QVarLengthArray<uchar> scripts(length); QUnicodeTools::initScripts(string, length, scripts.data()); - for (int i = 0; i < length; ++i) - analysis[i].script = scripts.at(i); + for (int i = 0; i < length; ++i) { + ushort script = scripts.at(i); + switch (script) { + case QChar::Script_Hiragana: + case QChar::Script_Katakana: + script = QChar::Script_Han; + break; + default: + break; + } + analysis[i].script = script; + } } const ushort *uc = string; @@ -1563,10 +1568,9 @@ void QTextEngine::itemize() const #ifndef QT_NO_RAWFONT if (useRawFont && specialData) { int lastIndex = 0; - const QTextFormatCollection *collection = formats(); for (int i = 0; i < specialData->addFormats.size(); ++i) { const QTextLayout::FormatRange &range = specialData->addFormats.at(i); - const QTextCharFormat format = collection->charFormat(specialData->addFormatIndices.at(i)); + const QTextCharFormat &format = range.format; if (format.hasProperty(QTextFormat::FontCapitalization)) { itemizer.generate(lastIndex, range.start - lastIndex, QFont::MixedCase); itemizer.generate(range.start, range.length, format.fontCapitalization()); @@ -1674,7 +1678,7 @@ QFixed QTextEngine::width(int from, int len) const // qDebug("char: start=%d end=%d / glyph: start = %d, end = %d", charFrom, charEnd, glyphStart, glyphEnd); for (int i = glyphStart; i < glyphEnd; i++) - w += glyphs.advances_x[i] * !glyphs.attributes[i].dontPrint; + w += glyphs.advances[i] * !glyphs.attributes[i].dontPrint; } } } @@ -1963,11 +1967,22 @@ static void set(QJustificationPoint *point, int type, const QGlyphLayout &glyph, if (type >= QGlyphAttributes::Arabic_Normal) { QChar ch(0x640); // Kashida character - QGlyphLayoutArray<8> glyphs; - int nglyphs = 7; - fe->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0); - if (glyphs.glyphs[0] && glyphs.advances_x[0] != 0) { - point->kashidaWidth = glyphs.advances_x[0]; + + glyph_t kashidaGlyph; + QFixed kashidaWidth; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &kashidaGlyph; + glyphs.advances = &kashidaWidth; + + int nglyphs = 1; + if (!fe->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + if (kashidaGlyph != 0 && kashidaWidth != 0) { + point->kashidaWidth = kashidaWidth; } else { point->type = QGlyphAttributes::NoJustification; point->kashidaWidth = 0; @@ -2209,7 +2224,7 @@ QTextEngine::LayoutData::LayoutData(const QString &str, void **stack_memory, int int space_charAttributes = sizeof(QCharAttributes)*string.length()/sizeof(void*) + 1; int space_logClusters = sizeof(unsigned short)*string.length()/sizeof(void*) + 1; - available_glyphs = ((int)allocated - space_charAttributes - space_logClusters)*(int)sizeof(void*)/(int)QGlyphLayout::spaceNeededForGlyphLayout(1); + available_glyphs = ((int)allocated - space_charAttributes - space_logClusters)*(int)sizeof(void*)/(int)QGlyphLayout::SpaceNeeded; if (available_glyphs < str.length()) { // need to allocate on the heap @@ -2251,7 +2266,7 @@ bool QTextEngine::LayoutData::reallocate(int totalGlyphs) int space_charAttributes = sizeof(QCharAttributes)*string.length()/sizeof(void*) + 1; int space_logClusters = sizeof(unsigned short)*string.length()/sizeof(void*) + 1; - int space_glyphs = QGlyphLayout::spaceNeededForGlyphLayout(totalGlyphs)/sizeof(void*) + 2; + int space_glyphs = (totalGlyphs * QGlyphLayout::SpaceNeeded) / sizeof(void *) + 2; int newAllocated = space_charAttributes + space_glyphs + space_logClusters; // These values can be negative if the length of string/glyphs causes overflow, @@ -2298,8 +2313,7 @@ void QGlyphLayout::grow(char *address, int totalGlyphs) // move the existing data memmove(newLayout.attributes, oldLayout.attributes, numGlyphs * sizeof(QGlyphAttributes)); memmove(newLayout.justifications, oldLayout.justifications, numGlyphs * sizeof(QGlyphJustification)); - memmove(newLayout.advances_y, oldLayout.advances_y, numGlyphs * sizeof(QFixed)); - memmove(newLayout.advances_x, oldLayout.advances_x, numGlyphs * sizeof(QFixed)); + memmove(newLayout.advances, oldLayout.advances, numGlyphs * sizeof(QFixed)); memmove(newLayout.glyphs, oldLayout.glyphs, numGlyphs * sizeof(glyph_t)); } @@ -2328,8 +2342,12 @@ void QTextEngine::freeMemory() int QTextEngine::formatIndex(const QScriptItem *si) const { - if (specialData && !specialData->resolvedFormatIndices.isEmpty()) - return specialData->resolvedFormatIndices.at(si - &layoutData->items[0]); + if (specialData && !specialData->resolvedFormats.isEmpty()) { + QTextFormatCollection *collection = formats(); + Q_ASSERT(collection); + return collection->indexForFormat(specialData->resolvedFormats.at(si - &layoutData->items[0])); + } + QTextDocumentPrivate *p = block.docHandle(); if (!p) return -1; @@ -2442,23 +2460,6 @@ void QTextEngine::setPreeditArea(int position, const QString &preeditText) clearLineData(); } -QList<QTextLayout::FormatRange> QTextEngine::additionalFormats() const -{ - QList<QTextLayout::FormatRange> formatList; - if (!specialData) - return formatList; - - formatList = specialData->addFormats; - if (!specialData->addFormatIndices.isEmpty()) { - const QTextFormatCollection *formats = this->formats(); - Q_ASSERT(formats); - for (int i = 0; i < specialData->addFormatIndices.size(); ++i) - formatList[i].format = formats->charFormat(specialData->addFormatIndices.at(i)); - } - - return formatList; -} - void QTextEngine::setAdditionalFormats(const QList<QTextLayout::FormatRange> &formatList) { if (formatList.isEmpty()) { @@ -2469,7 +2470,6 @@ void QTextEngine::setAdditionalFormats(const QList<QTextLayout::FormatRange> &fo specialData = 0; } else { specialData->addFormats.clear(); - specialData->addFormatIndices.clear(); } } else { if (!specialData) { @@ -2484,19 +2484,17 @@ void QTextEngine::setAdditionalFormats(const QList<QTextLayout::FormatRange> &fo void QTextEngine::indexAdditionalFormats() { - specialData->addFormatIndices.resize(specialData->addFormats.count()); - - QTextFormatCollection *formats = this->formats(); - - if (!formats) { + QTextFormatCollection *collection = formats(); + if (!collection) { Q_ASSERT(!block.docHandle()); specialData->formats.reset(new QTextFormatCollection); - formats = specialData->formats.data(); + collection = specialData->formats.data(); } + // replace with shared copies for (int i = 0; i < specialData->addFormats.count(); ++i) { - specialData->addFormatIndices[i] = formats->indexForFormat(specialData->addFormats.at(i).format); - specialData->addFormats[i].format = QTextCharFormat(); + QTextCharFormat &format = specialData->addFormats[i].format; + format = collection->charFormat(collection->indexForFormat(format)); } } @@ -2510,7 +2508,8 @@ static inline bool nextCharJoins(const QString &string, int pos) ++pos; if (pos == string.length()) return false; - return string.at(pos).joining() != QChar::OtherJoining; + QChar::JoiningType joining = string.at(pos).joiningType(); + return joining != QChar::Joining_None && joining != QChar::Joining_Transparent; } static inline bool prevCharJoins(const QString &string, int pos) @@ -2519,19 +2518,15 @@ static inline bool prevCharJoins(const QString &string, int pos) --pos; if (pos == 0) return false; - QChar::Joining joining = string.at(pos - 1).joining(); - return (joining == QChar::Dual || joining == QChar::Center); + QChar::JoiningType joining = string.at(pos - 1).joiningType(); + return joining == QChar::Joining_Dual || joining == QChar::Joining_Causing; } static inline bool isRetainableControlCode(QChar c) { - return (c.unicode() == 0x202a // LRE - || c.unicode() == 0x202b // LRE - || c.unicode() == 0x202c // PDF - || c.unicode() == 0x202d // LRO - || c.unicode() == 0x202e // RLO - || c.unicode() == 0x200e // LRM - || c.unicode() == 0x200f); // RLM + return (c.unicode() >= 0x202a && c.unicode() <= 0x202e) // LRE, RLE, PDF, LRO, RLO + || (c.unicode() >= 0x200e && c.unicode() <= 0x200f) // LRM, RLM + || (c.unicode() >= 0x2066 && c.unicode() <= 0x2069); // LRM, RLM } static QString stringMidRetainingBidiCC(const QString &string, @@ -2619,14 +2614,14 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int if (feForEllipsis->type() == QFontEngine::Mac) feForEllipsis = fe; - if (feForEllipsis->canRender(&ellipsisChar, 1)) { - int nGlyphs = 1; - feForEllipsis->stringToCMap(&ellipsisChar, 1, &ellipsisGlyph, &nGlyphs, 0); - } + int nGlyphs = 1; + if (!feForEllipsis->stringToCMap(&ellipsisChar, 1, &ellipsisGlyph, &nGlyphs, 0)) + Q_UNREACHABLE(); + Q_ASSERT(nGlyphs == 1); } if (ellipsisGlyph.glyphs[0]) { - ellipsisWidth = ellipsisGlyph.advances_x[0]; + ellipsisWidth = ellipsisGlyph.advances[0]; ellipsisText = ellipsisChar; } else { QString dotDotDot(QLatin1String("...")); @@ -2634,10 +2629,11 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int QGlyphLayoutArray<3> glyphs; int nGlyphs = 3; if (!fe->stringToCMap(dotDotDot.constData(), 3, &glyphs, &nGlyphs, 0)) - // should never happen... - return layoutData->string; + Q_UNREACHABLE(); + Q_ASSERT(nGlyphs == 3); + for (int i = 0; i < nGlyphs; ++i) - ellipsisWidth += glyphs.advances_x[i]; + ellipsisWidth += glyphs.advances[i]; ellipsisText = dotDotDot; } } @@ -2786,7 +2782,7 @@ void QTextEngine::splitItem(int item, int pos) const QFixed w = 0; const QGlyphLayout g = shapedGlyphs(&oldItem); for(int j = 0; j < breakGlyph; ++j) - w += g.advances_x[j] * !g.attributes[j].dontPrint; + w += g.advances[j] * !g.attributes[j].dontPrint; newItem.width = oldItem.width - w; oldItem.width = w; @@ -2859,9 +2855,9 @@ QFixed QTextEngine::calculateTabWidth(int item, QFixed x) const QGlyphLayout glyphs = this->shapedGlyphs(&item); const int end = qMin(item.position + item.num_glyphs, tabSectionEnd) - item.position; for (int i=0; i < end; i++) - length += glyphs.advances_x[i] * !glyphs.attributes[i].dontPrint; + length += glyphs.advances[i] * !glyphs.attributes[i].dontPrint; if (end + item.position == tabSectionEnd && tabSpec.type == QTextOption::DelimiterTab) // remove half of matching char - length -= glyphs.advances_x[end] / 2 * !glyphs.attributes[end].dontPrint; + length -= glyphs.advances[end] / 2 * !glyphs.attributes[end].dontPrint; } switch (tabSpec.type) { @@ -2915,14 +2911,13 @@ public: void QTextEngine::resolveAdditionalFormats() const { if (!specialData || specialData->addFormats.isEmpty() - || !specialData->resolvedFormatIndices.isEmpty()) + || !specialData->resolvedFormats.isEmpty()) return; QTextFormatCollection *collection = formats(); - specialData->resolvedFormatIndices.clear(); - QVector<int> indices(layoutData->items.count()); - + specialData->resolvedFormats.clear(); + QVector<QTextCharFormat> resolvedFormats(layoutData->items.count()); QVarLengthArray<int, 64> addFormatSortedByStart; addFormatSortedByStart.reserve(specialData->addFormats.count()); @@ -2958,21 +2953,24 @@ void QTextEngine::resolveAdditionalFormats() const currentFormats.remove(currentFormatIterator - currentFormats.begin()); ++endIt; } - QTextCharFormat format; + + QTextCharFormat &format = resolvedFormats[i]; if (block.docHandle()) { // when we have a docHandle, formatIndex might still return a valid index based // on the preeditPosition. for all other cases, we cleared the resolved format indices format = collection->charFormat(formatIndex(si)); } - - foreach (int cur, currentFormats) { - Q_ASSERT(specialData->addFormats.at(cur).start <= si->position - && specialData->addFormats.at(cur).start + specialData->addFormats.at(cur).length >= end); - format.merge(collection->format(specialData->addFormatIndices.at(cur))); + if (!currentFormats.isEmpty()) { + foreach (int cur, currentFormats) { + const QTextLayout::FormatRange &range = specialData->addFormats.at(cur); + Q_ASSERT(range.start <= si->position && range.start + range.length >= end); + format.merge(range.format); + } + format = collection->charFormat(collection->indexForFormat(format)); // get shared copy } - indices[i] = collection->indexForFormat(format); } - specialData->resolvedFormatIndices = indices; + + specialData->resolvedFormats = resolvedFormats; } QFixed QTextEngine::leadingSpaceWidth(const QScriptLine &line) @@ -3026,7 +3024,7 @@ QFixed QTextEngine::offsetInLigature(const QScriptItem *si, int pos, int max, in break; } if (clusterLength) - return glyphs.advances_x[glyph_pos] * offsetInCluster / clusterLength; + return glyphs.advances[glyph_pos] * offsetInCluster / clusterLength; } return 0; diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index fb71ab40b8..1616a78937 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -190,11 +190,15 @@ Q_DECLARE_TYPEINFO(QGlyphJustification, Q_PRIMITIVE_TYPE); struct QGlyphLayout { + enum { + SpaceNeeded = sizeof(glyph_t) + sizeof(QFixed) + sizeof(QFixedPoint) + + sizeof(QGlyphAttributes) + sizeof(QGlyphJustification) + }; + // init to 0 not needed, done when shaping QFixedPoint *offsets; // 8 bytes per element glyph_t *glyphs; // 4 bytes per element - QFixed *advances_x; // 4 bytes per element - QFixed *advances_y; // 4 bytes per element + QFixed *advances; // 4 bytes per element QGlyphJustification *justifications; // 4 bytes per element QGlyphAttributes *attributes; // 2 bytes per element @@ -208,9 +212,7 @@ struct QGlyphLayout int offset = totalGlyphs * sizeof(QFixedPoint); glyphs = reinterpret_cast<glyph_t *>(address + offset); offset += totalGlyphs * sizeof(glyph_t); - advances_x = reinterpret_cast<QFixed *>(address + offset); - offset += totalGlyphs * sizeof(QFixed); - advances_y = reinterpret_cast<QFixed *>(address + offset); + advances = reinterpret_cast<QFixed *>(address + offset); offset += totalGlyphs * sizeof(QFixed); justifications = reinterpret_cast<QGlyphJustification *>(address + offset); offset += totalGlyphs * sizeof(QGlyphJustification); @@ -221,8 +223,7 @@ struct QGlyphLayout inline QGlyphLayout mid(int position, int n = -1) const { QGlyphLayout copy = *this; copy.glyphs += position; - copy.advances_x += position; - copy.advances_y += position; + copy.advances += position; copy.offsets += position; copy.justifications += position; copy.attributes += position; @@ -233,27 +234,20 @@ struct QGlyphLayout return copy; } - static inline int spaceNeededForGlyphLayout(int totalGlyphs) { - return totalGlyphs * (sizeof(glyph_t) + sizeof(QGlyphAttributes) - + sizeof(QFixed) + sizeof(QFixed) + sizeof(QFixedPoint) - + sizeof(QGlyphJustification)); - } - inline QFixed effectiveAdvance(int item) const - { return (advances_x[item] + QFixed::fromFixed(justifications[item].space_18d6)) * !attributes[item].dontPrint; } + { return (advances[item] + QFixed::fromFixed(justifications[item].space_18d6)) * !attributes[item].dontPrint; } inline void clear(int first = 0, int last = -1) { if (last == -1) last = numGlyphs; if (first == 0 && last == numGlyphs && reinterpret_cast<char *>(offsets + numGlyphs) == reinterpret_cast<char *>(glyphs)) { - memset(offsets, 0, spaceNeededForGlyphLayout(numGlyphs)); + memset(offsets, 0, (numGlyphs * SpaceNeeded)); } else { const int num = last - first; memset(offsets + first, 0, num * sizeof(QFixedPoint)); memset(glyphs + first, 0, num * sizeof(glyph_t)); - memset(advances_x + first, 0, num * sizeof(QFixed)); - memset(advances_y + first, 0, num * sizeof(QFixed)); + memset(advances + first, 0, num * sizeof(QFixed)); memset(justifications + first, 0, num * sizeof(QGlyphJustification)); memset(attributes + first, 0, num * sizeof(QGlyphAttributes)); } @@ -272,7 +266,7 @@ private: typedef QVarLengthArray<void *> Array; public: QVarLengthGlyphLayoutArray(int totalGlyphs) - : Array(spaceNeededForGlyphLayout(totalGlyphs) / sizeof(void *) + 1) + : Array((totalGlyphs * SpaceNeeded) / sizeof(void *) + 1) , QGlyphLayout(reinterpret_cast<char *>(Array::data()), totalGlyphs) { memset(Array::data(), 0, Array::size() * sizeof(void *)); @@ -280,7 +274,7 @@ public: void resize(int totalGlyphs) { - Array::resize(spaceNeededForGlyphLayout(totalGlyphs) / sizeof(void *) + 1); + Array::resize((totalGlyphs * SpaceNeeded) / sizeof(void *) + 1); *((QGlyphLayout *)this) = QGlyphLayout(reinterpret_cast<char *>(Array::data()), totalGlyphs); memset(Array::data(), 0, Array::size() * sizeof(void *)); @@ -297,10 +291,7 @@ public: } private: - void *buffer[(N * (sizeof(glyph_t) + sizeof(QGlyphAttributes) - + sizeof(QFixed) + sizeof(QFixed) + sizeof(QFixedPoint) - + sizeof(QGlyphJustification))) - / sizeof(void *) + 1]; + void *buffer[(N * SpaceNeeded) / sizeof(void *) + 1]; }; struct QScriptItem; @@ -449,7 +440,6 @@ public: typedef QList<ItemDecoration> ItemDecorationList; - QTextEngine(LayoutData *data); QTextEngine(); QTextEngine(const QString &str, const QFont &f); ~QTextEngine(); @@ -553,6 +543,7 @@ public: mutable QScriptLineArray lines; +private: struct FontEngineCache { FontEngineCache(); mutable QFontEngine *prevFontEngine; @@ -570,6 +561,7 @@ public: }; mutable FontEngineCache feCache; +public: QString text; mutable QFont fnt; #ifndef QT_NO_RAWFONT @@ -611,7 +603,8 @@ public: void setPreeditArea(int position, const QString &text); inline bool hasFormats() const { return block.docHandle() || (specialData && !specialData->addFormats.isEmpty()); } - QList<QTextLayout::FormatRange> additionalFormats() const; + inline QList<QTextLayout::FormatRange> additionalFormats() const + { return specialData ? specialData->addFormats : QList<QTextLayout::FormatRange>(); } void setAdditionalFormats(const QList<QTextLayout::FormatRange> &formatList); private: @@ -621,8 +614,7 @@ private: int preeditPosition; QString preeditText; QList<QTextLayout::FormatRange> addFormats; - QVector<int> addFormatIndices; - QVector<int> resolvedFormatIndices; + QVector<QTextCharFormat> resolvedFormats; // only used when no docHandle is available QScopedPointer<QTextFormatCollection> formats; }; diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp index 2389427da0..4854af0d01 100644 --- a/src/gui/text/qtextformat.cpp +++ b/src/gui/text/qtextformat.cpp @@ -524,7 +524,7 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt) \value BlockFormat The object formats a text block \value CharFormat The object formats a single character \value ListFormat The object formats a list - \value TableFormat The object formats a table + \omitvalue TableFormat Unused Value, a table's FormatType is FrameFormat. \value FrameFormat The object formats a frame \value UserFormat @@ -706,6 +706,15 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt) */ /*! + \fn bool QTextFormat::isEmpty() const + \since 5.3 + + Returns true if the format does not store any properties; false otherwise. + + \sa propertyCount(), properties() +*/ + +/*! \fn bool QTextFormat::isCharFormat() const Returns \c true if this text format is a \c CharFormat; otherwise @@ -1870,36 +1879,93 @@ QStringList QTextCharFormat::anchorNames() const */ /*! + \enum QTextCharFormat::FontPropertiesInheritanceBehavior + \since 5.3 + + This enum specifies how the setFont() function should behave with + respect to unset font properties. + + \value FontPropertiesSpecifiedOnly If a property is not explicitly set, do not + change the text format's property value. + \value FontPropertiesAll If a property is not explicitly set, override the + text format's property with a default value. + + \sa setFont() +*/ + +/*! + \overload + Sets the text format's \a font. + + \sa font() */ void QTextCharFormat::setFont(const QFont &font) { - setFontFamily(font.family()); + setFont(font, FontPropertiesAll); +} - const qreal pointSize = font.pointSizeF(); - if (pointSize > 0) { - setFontPointSize(pointSize); - } else { - const int pixelSize = font.pixelSize(); - if (pixelSize > 0) - setProperty(QTextFormat::FontPixelSize, pixelSize); +/*! + \since 5.3 + + Sets the text format's \a font. + + If \a behavior is QTextCharFormat::FontPropertiesAll, the font property that + has not been explicitly set is treated like as it were set with default value; + If \a behavior is QTextCharFormat::FontPropertiesAll, the font property that + has not been explicitly set is ignored and the respective property value + remains unchanged. + + \sa font() +*/ +void QTextCharFormat::setFont(const QFont &font, FontPropertiesInheritanceBehavior behavior) +{ + const uint mask = behavior == FontPropertiesAll ? uint(QFont::AllPropertiesResolved) + : font.resolve(); + + if (mask & QFont::FamilyResolved) + setFontFamily(font.family()); + if (mask & QFont::SizeResolved) { + const qreal pointSize = font.pointSizeF(); + if (pointSize > 0) { + setFontPointSize(pointSize); + } else { + const int pixelSize = font.pixelSize(); + if (pixelSize > 0) + setProperty(QTextFormat::FontPixelSize, pixelSize); + } } - setFontWeight(font.weight()); - setFontItalic(font.italic()); - setUnderlineStyle(font.underline() ? SingleUnderline : NoUnderline); - setFontOverline(font.overline()); - setFontStrikeOut(font.strikeOut()); - setFontFixedPitch(font.fixedPitch()); - setFontCapitalization(font.capitalization()); - setFontWordSpacing(font.wordSpacing()); - setFontLetterSpacingType(font.letterSpacingType()); - setFontLetterSpacing(font.letterSpacing()); - setFontStretch(font.stretch()); - setFontStyleHint(font.styleHint()); - setFontStyleStrategy(font.styleStrategy()); - setFontHintingPreference(font.hintingPreference()); - setFontKerning(font.kerning()); + if (mask & QFont::WeightResolved) + setFontWeight(font.weight()); + if (mask & QFont::StyleResolved) + setFontItalic(font.style() != QFont::StyleNormal); + if (mask & QFont::UnderlineResolved) + setUnderlineStyle(font.underline() ? SingleUnderline : NoUnderline); + if (mask & QFont::OverlineResolved) + setFontOverline(font.overline()); + if (mask & QFont::StrikeOutResolved) + setFontStrikeOut(font.strikeOut()); + if (mask & QFont::FixedPitchResolved) + setFontFixedPitch(font.fixedPitch()); + if (mask & QFont::CapitalizationResolved) + setFontCapitalization(font.capitalization()); + if (mask & QFont::LetterSpacingResolved) + setFontWordSpacing(font.wordSpacing()); + if (mask & QFont::LetterSpacingResolved) { + setFontLetterSpacingType(font.letterSpacingType()); + setFontLetterSpacing(font.letterSpacing()); + } + if (mask & QFont::StretchResolved) + setFontStretch(font.stretch()); + if (mask & QFont::StyleHintResolved) + setFontStyleHint(font.styleHint()); + if (mask & QFont::StyleStrategyResolved) + setFontStyleStrategy(font.styleStrategy()); + if (mask & QFont::HintingPreferenceResolved) + setFontHintingPreference(font.hintingPreference()); + if (mask & QFont::KerningResolved) + setFontKerning(font.kerning()); } /*! @@ -3376,19 +3442,6 @@ bool QTextFormatCollection::hasFormatCached(const QTextFormat &format) const return false; } -QTextFormat QTextFormatCollection::objectFormat(int objectIndex) const -{ - if (objectIndex == -1) - return QTextFormat(); - return format(objFormats.at(objectIndex)); -} - -void QTextFormatCollection::setObjectFormat(int objectIndex, const QTextFormat &f) -{ - const int formatIndex = indexForFormat(f); - objFormats[objectIndex] = formatIndex; -} - int QTextFormatCollection::objectFormatIndex(int objectIndex) const { if (objectIndex == -1) diff --git a/src/gui/text/qtextformat.h b/src/gui/text/qtextformat.h index 2098369811..5369001a03 100644 --- a/src/gui/text/qtextformat.h +++ b/src/gui/text/qtextformat.h @@ -141,7 +141,9 @@ public: BlockFormat = 1, CharFormat = 2, ListFormat = 3, +#if QT_DEPRECATED_SINCE(5, 3) TableFormat = 4, +#endif FrameFormat = 5, UserFormat = 100 @@ -295,6 +297,7 @@ public: void merge(const QTextFormat &other); inline bool isValid() const { return type() != InvalidFormat; } + inline bool isEmpty() const { return propertyCount() == 0; } int type() const; @@ -407,7 +410,13 @@ public: QTextCharFormat(); bool isValid() const { return isCharFormat(); } - void setFont(const QFont &font); + + enum FontPropertiesInheritanceBehavior { + FontPropertiesSpecifiedOnly, + FontPropertiesAll + }; + void setFont(const QFont &font, FontPropertiesInheritanceBehavior behavior); + void setFont(const QFont &font); // ### Qt6: Merge with above QFont font() const; inline void setFontFamily(const QString &family) diff --git a/src/gui/text/qtextformat_p.h b/src/gui/text/qtextformat_p.h index 6b2958a4b6..e3998d4f3f 100644 --- a/src/gui/text/qtextformat_p.h +++ b/src/gui/text/qtextformat_p.h @@ -68,8 +68,10 @@ public: QTextFormatCollection(const QTextFormatCollection &rhs); QTextFormatCollection &operator=(const QTextFormatCollection &rhs); - QTextFormat objectFormat(int objectIndex) const; - void setObjectFormat(int objectIndex, const QTextFormat &format); + inline QTextFormat objectFormat(int objectIndex) const + { return format(objectFormatIndex(objectIndex)); } + inline void setObjectFormat(int objectIndex, const QTextFormat &format) + { setObjectFormatIndex(objectIndex, indexForFormat(format)); } int objectFormatIndex(int objectIndex) const; void setObjectFormatIndex(int objectIndex, int formatIndex); diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp index 3cb61b9eae..e8a02c44b2 100644 --- a/src/gui/text/qtexthtmlparser.cpp +++ b/src/gui/text/qtexthtmlparser.cpp @@ -1361,33 +1361,7 @@ void QTextHtmlParserNode::applyCssDeclarations(const QVector<QCss::Declaration> QFont f; int adjustment = -255; extractor.extractFont(&f, &adjustment); - if (f.resolve() & QFont::SizeResolved) { - if (f.pointSize() > 0) { - charFormat.setFontPointSize(f.pointSize()); - } else if (f.pixelSize() > 0) { - charFormat.setProperty(QTextFormat::FontPixelSize, f.pixelSize()); - } - } - if (f.resolve() & QFont::StyleResolved) - charFormat.setFontItalic(f.style() != QFont::StyleNormal); - - if (f.resolve() & QFont::WeightResolved) - charFormat.setFontWeight(f.weight()); - - if (f.resolve() & QFont::FamilyResolved) - charFormat.setFontFamily(f.family()); - - if (f.resolve() & QFont::UnderlineResolved) - charFormat.setUnderlineStyle(f.underline() ? QTextCharFormat::SingleUnderline : QTextCharFormat::NoUnderline); - - if (f.resolve() & QFont::OverlineResolved) - charFormat.setFontOverline(f.overline()); - - if (f.resolve() & QFont::StrikeOutResolved) - charFormat.setFontStrikeOut(f.strikeOut()); - - if (f.resolve() & QFont::CapitalizationResolved) - charFormat.setFontCapitalization(f.capitalization()); + charFormat.setFont(f, QTextCharFormat::FontPropertiesSpecifiedOnly); if (adjustment >= -1) charFormat.setProperty(QTextFormat::FontSizeAdjustment, adjustment); diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 66341e186a..0c9866c6cf 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -239,9 +239,7 @@ int QTextInlineObject::formatIndex() const */ QTextFormat QTextInlineObject::format() const { - if (!eng->block.docHandle()) - return QTextFormat(); - return eng->formats()->format(eng->formatIndex(&eng->layoutData->items[itm])); + return eng->format(&eng->layoutData->items[itm]); } /*! @@ -1693,7 +1691,7 @@ static inline void addNextCluster(int &pos, int end, QScriptLine &line, int &gly } while (pos < end && logClusters[pos] == glyphPosition); do { // calculate the textWidth for the rest of the current cluster. if (!glyphs.attributes[glyphPosition].dontPrint) - line.textWidth += glyphs.advances_x[glyphPosition]; + line.textWidth += glyphs.advances[glyphPosition]; ++glyphPosition; } while (glyphPosition < current.num_glyphs && !glyphs.attributes[glyphPosition].clusterStart); @@ -1812,9 +1810,10 @@ void QTextLine::layout_helper(int maxGlyphs) lbh.whiteSpaceOrObject = true; lbh.tmpData.length++; - QTextFormat format = eng->formats()->format(eng->formatIndex(&eng->layoutData->items[item])); - if (eng->block.docHandle()) - eng->docLayout()->positionInlineObject(QTextInlineObject(item, eng), eng->block.position() + current.position, format); + if (eng->block.docHandle()) { + QTextInlineObject inlineObject(item, eng); + eng->docLayout()->positionInlineObject(inlineObject, eng->block.position() + current.position, inlineObject.format()); + } lbh.tmpData.textWidth += current.width; @@ -1871,9 +1870,9 @@ void QTextLine::layout_helper(int maxGlyphs) // and thus become invisible again. // if (line.length) - lbh.softHyphenWidth = lbh.glyphs.advances_x[lbh.logClusters[lbh.currentPosition - 1]]; + lbh.softHyphenWidth = lbh.glyphs.advances[lbh.logClusters[lbh.currentPosition - 1]]; else if (breakany) - lbh.tmpData.textWidth += lbh.glyphs.advances_x[lbh.logClusters[lbh.currentPosition - 1]]; + lbh.tmpData.textWidth += lbh.glyphs.advances[lbh.logClusters[lbh.currentPosition - 1]]; } // The actual width of the text needs to take the right bearing into account. The @@ -2249,14 +2248,12 @@ QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const if (relativeFrom != (iterator.itemStart - si.position) && !rtl) { for (int i=itemGlyphsStart; i<glyphsStart; ++i) { QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6); - pos += QPointF((glyphLayout.advances_x[i] + justification).toReal(), - glyphLayout.advances_y[i].toReal()); + pos.rx() += (glyphLayout.advances[i] + justification).toReal(); } } else if (relativeTo != (iterator.itemEnd - si.position - 1) && rtl) { for (int i=itemGlyphsEnd; i>glyphsEnd; --i) { QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6); - pos += QPointF((glyphLayout.advances_x[i] + justification).toReal(), - glyphLayout.advances_y[i].toReal()); + pos.rx() += (glyphLayout.advances[i] + justification).toReal(); } } @@ -2295,10 +2292,8 @@ QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const glyphRuns.append(glyphRunWithInfo(multiFontEngine->engine(which), subLayout, pos, subFlags, x, width)); - for (int i = 0; i < subLayout.numGlyphs; i++) { - pos += QPointF(subLayout.advances_x[i].toReal(), - subLayout.advances_y[i].toReal()); - } + for (int i = 0; i < subLayout.numGlyphs; ++i) + pos.rx() += subLayout.advances[i].toReal(); if (rtl) end = start; diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp index d1a39c6ab6..bd1e970583 100644 --- a/src/gui/text/qtextobject.cpp +++ b/src/gui/text/qtextobject.cpp @@ -1233,6 +1233,56 @@ QString QTextBlock::text() const return text; } +/*! + \since 5.3 + + Returns the block's text format options as a list of continuous ranges + of QTextCharFormat. The range's character format is used when inserting text + within the range boundaries. + + \sa charFormat(), blockFormat() +*/ +QList<QTextLayout::FormatRange> QTextBlock::textFormats() const +{ + QList<QTextLayout::FormatRange> formats; + if (!p || !n) + return formats; + + const QTextFormatCollection *formatCollection = p->formatCollection(); + + int start = 0; + int cur = start; + int format = -1; + + const int pos = position(); + QTextDocumentPrivate::FragmentIterator it = p->find(pos); + QTextDocumentPrivate::FragmentIterator end = p->find(pos + length() - 1); // -1 to omit the block separator char + for (; it != end; ++it) { + const QTextFragmentData * const frag = it.value(); + if (format != it.value()->format) { + if (cur - start > 0) { + QTextLayout::FormatRange range; + range.start = start; + range.length = cur - start; + range.format = formatCollection->charFormat(format); + formats.append(range); + } + + format = frag->format; + start = cur; + } + cur += frag->size_array[0]; + } + if (cur - start > 0) { + QTextLayout::FormatRange range; + range.start = start; + range.length = cur - start; + range.format = formatCollection->charFormat(format); + formats.append(range); + } + + return formats; +} /*! Returns the text document this text block belongs to, or 0 if the diff --git a/src/gui/text/qtextobject.h b/src/gui/text/qtextobject.h index 87f2cf6197..6a127f0315 100644 --- a/src/gui/text/qtextobject.h +++ b/src/gui/text/qtextobject.h @@ -44,6 +44,7 @@ #include <QtCore/qobject.h> #include <QtGui/qtextformat.h> +#include <QtGui/qtextlayout.h> #include <QtGui/qglyphrun.h> QT_BEGIN_NAMESPACE @@ -55,7 +56,6 @@ class QTextDocumentPrivate; class QTextCursor; class QTextBlock; class QTextFragment; -class QTextLayout; class QTextList; class Q_GUI_EXPORT QTextObject : public QObject @@ -223,6 +223,8 @@ public: QString text() const; + QList<QTextLayout::FormatRange> textFormats() const; + const QTextDocument *document() const; QTextList *textList() const; diff --git a/src/gui/util/qabstractlayoutstyleinfo.cpp b/src/gui/util/qabstractlayoutstyleinfo.cpp new file mode 100644 index 0000000000..4f7c635594 --- /dev/null +++ b/src/gui/util/qabstractlayoutstyleinfo.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qabstractlayoutstyleinfo_p.h" + +QT_BEGIN_NAMESPACE + +bool QAbstractLayoutStyleInfo::hasChanged() const +{ + if (m_changed == Unknown) + m_changed = hasChangedCore() ? Changed : Unchanged; + return m_changed == Changed; +} + +QT_END_NAMESPACE diff --git a/src/gui/util/qabstractlayoutstyleinfo_p.h b/src/gui/util/qabstractlayoutstyleinfo_p.h new file mode 100644 index 0000000000..52f151c5d2 --- /dev/null +++ b/src/gui/util/qabstractlayoutstyleinfo_p.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTLAYOUTSTYLEINFO_P_H +#define QABSTRACTLAYOUTSTYLEINFO_P_H + +#include <QtCore/qnamespace.h> +#include "qlayoutpolicy_p.h" + +QT_BEGIN_NAMESPACE + + +class Q_GUI_EXPORT QAbstractLayoutStyleInfo { +public: + typedef enum { + Unknown = 0, + Changed, + Unchanged + } ChangedState; + + QAbstractLayoutStyleInfo() : m_isWindow(false), m_changed(Changed) {} + virtual ~QAbstractLayoutStyleInfo() {} + virtual qreal combinedLayoutSpacing(QLayoutPolicy::ControlTypes /*controls1*/, + QLayoutPolicy::ControlTypes /*controls2*/, Qt::Orientation /*orientation*/) const { + return -1; + } + + virtual qreal perItemSpacing(QLayoutPolicy::ControlType /*control1*/, + QLayoutPolicy::ControlType /*control2*/, + Qt::Orientation /*orientation*/) const { + return -1; + } + + virtual qreal spacing(Qt::Orientation orientation) const = 0; + + virtual bool hasChangedCore() const = 0; + + void updateChanged(ChangedState change) { + m_changed = change; + } + + bool hasChanged() const; + + virtual void invalidate() { updateChanged(Changed);} + + virtual qreal windowMargin(Qt::Orientation orientation) const = 0; + + bool isWindow() const { + return m_isWindow; + } + +protected: + unsigned m_isWindow : 1; + mutable unsigned m_changed : 2; +}; + +QT_END_NAMESPACE + +#endif // QABSTRACTLAYOUTSTYLEINFO_P_H diff --git a/src/gui/util/qgridlayoutengine.cpp b/src/gui/util/qgridlayoutengine.cpp new file mode 100644 index 0000000000..10b4a2ee35 --- /dev/null +++ b/src/gui/util/qgridlayoutengine.cpp @@ -0,0 +1,1635 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qglobal.h" + +#ifndef QT_NO_GRAPHICSVIEW + +#include <math.h> + +#include "qgridlayoutengine_p.h" +#include "qvarlengtharray.h" + +#include <QtDebug> +#include <QtCore/qmath.h> + +QT_BEGIN_NAMESPACE + +template <typename T> +static void insertOrRemoveItems(QVector<T> &items, int index, int delta) +{ + int count = items.count(); + if (index < count) { + if (delta > 0) { + items.insert(index, delta, T()); + } else if (delta < 0) { + items.remove(index, qMin(-delta, count - index)); + } + } +} + +static qreal growthFactorBelowPreferredSize(qreal desired, qreal sumAvailable, qreal sumDesired) +{ + Q_ASSERT(sumDesired != 0.0); + return desired * qPow(sumAvailable / sumDesired, desired / sumDesired); +} + +static qreal fixedDescent(qreal descent, qreal ascent, qreal targetSize) +{ + if (descent < 0.0) + return -1.0; + + Q_ASSERT(descent >= 0.0); + Q_ASSERT(ascent >= 0.0); + Q_ASSERT(targetSize >= ascent + descent); + + qreal extra = targetSize - (ascent + descent); + return descent + (extra / 2.0); +} + +static qreal compare(const QGridLayoutBox &box1, const QGridLayoutBox &box2, int which) +{ + qreal size1 = box1.q_sizes(which); + qreal size2 = box2.q_sizes(which); + + if (which == MaximumSize) { + return size2 - size1; + } else { + return size1 - size2; + } +} + +void QGridLayoutBox::add(const QGridLayoutBox &other, int stretch, qreal spacing) +{ + Q_ASSERT(q_minimumDescent < 0.0); + + q_minimumSize += other.q_minimumSize + spacing; + q_preferredSize += other.q_preferredSize + spacing; + q_maximumSize += ((stretch == 0) ? other.q_preferredSize : other.q_maximumSize) + spacing; +} + +void QGridLayoutBox::combine(const QGridLayoutBox &other) +{ + q_minimumDescent = qMax(q_minimumDescent, other.q_minimumDescent); + q_minimumAscent = qMax(q_minimumAscent, other.q_minimumAscent); + + q_minimumSize = qMax(q_minimumAscent + q_minimumDescent, + qMax(q_minimumSize, other.q_minimumSize)); + qreal maxMax; + if (q_maximumSize == FLT_MAX && other.q_maximumSize != FLT_MAX) + maxMax = other.q_maximumSize; + else if (other.q_maximumSize == FLT_MAX && q_maximumSize != FLT_MAX) + maxMax = q_maximumSize; + else + maxMax = qMax(q_maximumSize, other.q_maximumSize); + + q_maximumSize = qMax(q_minimumSize, maxMax); + q_preferredSize = qBound(q_minimumSize, qMax(q_preferredSize, other.q_preferredSize), + q_maximumSize); +} + +void QGridLayoutBox::normalize() +{ + q_maximumSize = qMax(qreal(0.0), q_maximumSize); + q_minimumSize = qBound(qreal(0.0), q_minimumSize, q_maximumSize); + q_preferredSize = qBound(q_minimumSize, q_preferredSize, q_maximumSize); + q_minimumDescent = qMin(q_minimumDescent, q_minimumSize); + + Q_ASSERT((q_minimumDescent < 0.0) == (q_minimumAscent < 0.0)); +} + +#ifdef QGRIDLAYOUTENGINE_DEBUG +void QGridLayoutBox::dump(int indent) const +{ + qDebug("%*sBox (%g <= %g <= %g [%g/%g])", indent, "", q_minimumSize, q_preferredSize, + q_maximumSize, q_minimumAscent, q_minimumDescent); +} +#endif + +bool operator==(const QGridLayoutBox &box1, const QGridLayoutBox &box2) +{ + for (int i = 0; i < NSizes; ++i) { + if (box1.q_sizes(i) != box2.q_sizes(i)) + return false; + } + return box1.q_minimumDescent == box2.q_minimumDescent + && box1.q_minimumAscent == box2.q_minimumAscent; +} + +void QGridLayoutRowData::reset(int count) +{ + ignore.fill(false, count); + boxes.fill(QGridLayoutBox(), count); + multiCellMap.clear(); + stretches.fill(0, count); + spacings.fill(0.0, count); + hasIgnoreFlag = false; +} + +void QGridLayoutRowData::distributeMultiCells(const QGridLayoutRowInfo &rowInfo) +{ + MultiCellMap::const_iterator i = multiCellMap.constBegin(); + for (; i != multiCellMap.constEnd(); ++i) { + int start = i.key().first; + int span = i.key().second; + int end = start + span; + const QGridLayoutBox &box = i.value().q_box; + int stretch = i.value().q_stretch; + + QGridLayoutBox totalBox = this->totalBox(start, end); + QVarLengthArray<QGridLayoutBox> extras(span); + QVarLengthArray<qreal> dummy(span); + QVarLengthArray<qreal> newSizes(span); + + for (int j = 0; j < NSizes; ++j) { + qreal extra = compare(box, totalBox, j); + if (extra > 0.0) { + calculateGeometries(start, end, box.q_sizes(j), dummy.data(), newSizes.data(), + 0, totalBox, rowInfo); + + for (int k = 0; k < span; ++k) + extras[k].q_sizes(j) = newSizes[k]; + } + } + + for (int k = 0; k < span; ++k) { + boxes[start + k].combine(extras[k]); + if (stretch != 0) + stretches[start + k] = qMax(stretches[start + k], stretch); + } + } + multiCellMap.clear(); +} + +void QGridLayoutRowData::calculateGeometries(int start, int end, qreal targetSize, qreal *positions, + qreal *sizes, qreal *descents, + const QGridLayoutBox &totalBox, + const QGridLayoutRowInfo &rowInfo) +{ + Q_ASSERT(end > start); + + targetSize = qMax(totalBox.q_minimumSize, targetSize); + + int n = end - start; + QVarLengthArray<qreal> newSizes(n); + QVarLengthArray<qreal> factors(n); + qreal sumFactors = 0.0; + int sumStretches = 0; + qreal sumAvailable; + + for (int i = 0; i < n; ++i) { + if (stretches[start + i] > 0) + sumStretches += stretches[start + i]; + } + + if (targetSize < totalBox.q_preferredSize) { + stealBox(start, end, MinimumSize, positions, sizes); + + sumAvailable = targetSize - totalBox.q_minimumSize; + if (sumAvailable > 0.0) { + qreal sumDesired = totalBox.q_preferredSize - totalBox.q_minimumSize; + + for (int i = 0; i < n; ++i) { + if (ignore.testBit(start + i)) { + factors[i] = 0.0; + continue; + } + + const QGridLayoutBox &box = boxes.at(start + i); + qreal desired = box.q_preferredSize - box.q_minimumSize; + factors[i] = growthFactorBelowPreferredSize(desired, sumAvailable, sumDesired); + sumFactors += factors[i]; + } + + for (int i = 0; i < n; ++i) { + Q_ASSERT(sumFactors > 0.0); + qreal delta = sumAvailable * factors[i] / sumFactors; + newSizes[i] = sizes[i] + delta; + } + } + } else { + bool isLargerThanMaximum = (targetSize > totalBox.q_maximumSize); + if (isLargerThanMaximum) { + stealBox(start, end, MaximumSize, positions, sizes); + sumAvailable = targetSize - totalBox.q_maximumSize; + } else { + stealBox(start, end, PreferredSize, positions, sizes); + sumAvailable = targetSize - totalBox.q_preferredSize; + } + + if (sumAvailable > 0.0) { + qreal sumCurrentAvailable = sumAvailable; + bool somethingHasAMaximumSize = false; + + qreal sumSizes = 0.0; + for (int i = 0; i < n; ++i) + sumSizes += sizes[i]; + + for (int i = 0; i < n; ++i) { + if (ignore.testBit(start + i)) { + newSizes[i] = 0.0; + factors[i] = 0.0; + continue; + } + + const QGridLayoutBox &box = boxes.at(start + i); + qreal boxSize; + + qreal desired; + if (isLargerThanMaximum) { + boxSize = box.q_maximumSize; + desired = rowInfo.boxes.value(start + i).q_maximumSize - boxSize; + } else { + boxSize = box.q_preferredSize; + desired = box.q_maximumSize - boxSize; + } + if (desired == 0.0) { + newSizes[i] = sizes[i]; + factors[i] = 0.0; + } else { + Q_ASSERT(desired > 0.0); + + int stretch = stretches[start + i]; + if (sumStretches == 0) { + if (hasIgnoreFlag || sizes[i] == 0.0) { + factors[i] = (stretch < 0) ? 1.0 : 0.0; + } else { + factors[i] = (stretch < 0) ? sizes[i] : 0.0; + } + } else if (stretch == sumStretches) { + factors[i] = 1.0; + } else if (stretch <= 0) { + factors[i] = 0.0; + } else { + qreal ultimateSize; + qreal ultimateSumSizes; + qreal x = ((stretch * sumSizes) + - (sumStretches * boxSize)) + / (sumStretches - stretch); + if (x >= 0.0) { + ultimateSize = boxSize + x; + ultimateSumSizes = sumSizes + x; + } else { + ultimateSize = boxSize; + ultimateSumSizes = (sumStretches * boxSize) + / stretch; + } + + /* + We multiply these by 1.5 to give some space for a smooth transition + (at the expense of the stretch factors, which are not fully respected + during the transition). + */ + ultimateSize = ultimateSize * 3 / 2; + ultimateSumSizes = ultimateSumSizes * 3 / 2; + + qreal beta = ultimateSumSizes - sumSizes; + if (!beta) { + factors[i] = 1; + } else { + qreal alpha = qMin(sumCurrentAvailable, beta); + qreal ultimateFactor = (stretch * ultimateSumSizes / sumStretches) + - (boxSize); + qreal transitionalFactor = sumCurrentAvailable * (ultimateSize - boxSize) / beta; + + factors[i] = ((alpha * ultimateFactor) + + ((beta - alpha) * transitionalFactor)) / beta; + } + + } + sumFactors += factors[i]; + if (desired < sumCurrentAvailable) + somethingHasAMaximumSize = true; + + newSizes[i] = -1.0; + } + } + + bool keepGoing = somethingHasAMaximumSize; + while (keepGoing) { + keepGoing = false; + + for (int i = 0; i < n; ++i) { + if (newSizes[i] >= 0.0) + continue; + + qreal maxBoxSize; + if (isLargerThanMaximum) + maxBoxSize = rowInfo.boxes.value(start + i).q_maximumSize; + else + maxBoxSize = boxes.at(start + i).q_maximumSize; + + qreal avail = sumCurrentAvailable * factors[i] / sumFactors; + if (sizes[i] + avail >= maxBoxSize) { + newSizes[i] = maxBoxSize; + sumCurrentAvailable -= maxBoxSize - sizes[i]; + sumFactors -= factors[i]; + keepGoing = (sumCurrentAvailable > 0.0); + if (!keepGoing) + break; + } + } + } + + for (int i = 0; i < n; ++i) { + if (newSizes[i] < 0.0) { + qreal delta = (sumFactors == 0.0) ? 0.0 + : sumCurrentAvailable * factors[i] / sumFactors; + newSizes[i] = sizes[i] + delta; + } + } + } + } + + if (sumAvailable > 0) { + qreal offset = 0; + for (int i = 0; i < n; ++i) { + qreal delta = newSizes[i] - sizes[i]; + positions[i] += offset; + sizes[i] += delta; + offset += delta; + } + +#if 0 // some "pixel allocation" + int surplus = targetSize - (positions[n - 1] + sizes[n - 1]); + Q_ASSERT(surplus >= 0 && surplus <= n); + + int prevSurplus = -1; + while (surplus > 0 && surplus != prevSurplus) { + prevSurplus = surplus; + + int offset = 0; + for (int i = 0; i < n; ++i) { + const QGridLayoutBox &box = boxes.at(start + i); + int delta = (!ignore.testBit(start + i) && surplus > 0 + && factors[i] > 0 && sizes[i] < box.q_maximumSize) + ? 1 : 0; + + positions[i] += offset; + sizes[i] += delta; + offset += delta; + surplus -= delta; + } + } + Q_ASSERT(surplus == 0); +#endif + } + + if (descents) { + for (int i = 0; i < n; ++i) { + if (ignore.testBit(start + i)) + continue; + const QGridLayoutBox &box = boxes.at(start + i); + descents[i] = fixedDescent(box.q_minimumDescent, box.q_minimumAscent, sizes[i]); + } + } +} + +QGridLayoutBox QGridLayoutRowData::totalBox(int start, int end) const +{ + QGridLayoutBox result; + if (start < end) { + result.q_maximumSize = 0.0; + qreal nextSpacing = 0.0; + for (int i = start; i < end; ++i) { + if (ignore.testBit(i)) + continue; + result.add(boxes.at(i), stretches.at(i), nextSpacing); + nextSpacing = spacings.at(i); + } + } + return result; +} + +void QGridLayoutRowData::stealBox(int start, int end, int which, qreal *positions, qreal *sizes) +{ + qreal offset = 0.0; + qreal nextSpacing = 0.0; + + for (int i = start; i < end; ++i) { + qreal avail = 0.0; + + if (!ignore.testBit(i)) { + const QGridLayoutBox &box = boxes.at(i); + avail = box.q_sizes(which); + offset += nextSpacing; + nextSpacing = spacings.at(i); + } + + *positions++ = offset; + *sizes++ = avail; + offset += avail; + } +} + +#ifdef QGRIDLAYOUTENGINE_DEBUG +void QGridLayoutRowData::dump(int indent) const +{ + qDebug("%*sData", indent, ""); + + for (int i = 0; i < ignore.count(); ++i) { + qDebug("%*s Row %d (stretch %d, spacing %g)", indent, "", i, stretches.at(i), + spacings.at(i)); + if (ignore.testBit(i)) + qDebug("%*s Ignored", indent, ""); + boxes.at(i).dump(indent + 2); + } + + MultiCellMap::const_iterator it = multiCellMap.constBegin(); + while (it != multiCellMap.constEnd()) { + qDebug("%*s Multi-cell entry <%d, %d> (stretch %d)", indent, "", it.key().first, + it.key().second, it.value().q_stretch); + it.value().q_box.dump(indent + 2); + } +} +#endif + +QGridLayoutItem::QGridLayoutItem(int row, int column, int rowSpan, int columnSpan, + Qt::Alignment alignment) + : q_alignment(alignment) +{ + q_firstRows[Hor] = column; + q_firstRows[Ver] = row; + q_rowSpans[Hor] = columnSpan; + q_rowSpans[Ver] = rowSpan; + q_stretches[Hor] = -1; + q_stretches[Ver] = -1; +} + +int QGridLayoutItem::firstRow(Qt::Orientation orientation) const +{ + return q_firstRows[orientation == Qt::Vertical]; +} + +int QGridLayoutItem::firstColumn(Qt::Orientation orientation) const +{ + return q_firstRows[orientation == Qt::Horizontal]; +} + +int QGridLayoutItem::lastRow(Qt::Orientation orientation) const +{ + return firstRow(orientation) + rowSpan(orientation) - 1; +} + +int QGridLayoutItem::lastColumn(Qt::Orientation orientation) const +{ + return firstColumn(orientation) + columnSpan(orientation) - 1; +} + +int QGridLayoutItem::rowSpan(Qt::Orientation orientation) const +{ + return q_rowSpans[orientation == Qt::Vertical]; +} + +int QGridLayoutItem::columnSpan(Qt::Orientation orientation) const +{ + return q_rowSpans[orientation == Qt::Horizontal]; +} + +void QGridLayoutItem::setFirstRow(int row, Qt::Orientation orientation) +{ + q_firstRows[orientation == Qt::Vertical] = row; +} + +void QGridLayoutItem::setRowSpan(int rowSpan, Qt::Orientation orientation) +{ + q_rowSpans[orientation == Qt::Vertical] = rowSpan; +} + +int QGridLayoutItem::stretchFactor(Qt::Orientation orientation) const +{ + int stretch = q_stretches[orientation == Qt::Vertical]; + if (stretch >= 0) + return stretch; + + QLayoutPolicy::Policy policy = sizePolicy(orientation); + + if (policy & QLayoutPolicy::ExpandFlag) { + return 1; + } else if (policy & QLayoutPolicy::GrowFlag) { + return -1; // because we max it up + } else { + return 0; + } +} + +void QGridLayoutItem::setStretchFactor(int stretch, Qt::Orientation orientation) +{ + Q_ASSERT(stretch >= 0); // ### deal with too big stretches + q_stretches[orientation == Qt::Vertical] = stretch; +} + +QLayoutPolicy::ControlTypes QGridLayoutItem::controlTypes(LayoutSide /*side*/) const +{ + return QLayoutPolicy::DefaultType; +} + +QGridLayoutBox QGridLayoutItem::box(Qt::Orientation orientation, qreal constraint) const +{ + QGridLayoutBox result; + QLayoutPolicy::Policy policy = sizePolicy(orientation); + + if (orientation == Qt::Horizontal) { + QSizeF constraintSize(-1.0, constraint); + + result.q_preferredSize = sizeHint(Qt::PreferredSize, constraintSize).width(); + + if (policy & QLayoutPolicy::ShrinkFlag) { + result.q_minimumSize = sizeHint(Qt::MinimumSize, constraintSize).width(); + } else { + result.q_minimumSize = result.q_preferredSize; + } + + if (policy & (QLayoutPolicy::GrowFlag | QLayoutPolicy::ExpandFlag)) { + result.q_maximumSize = sizeHint(Qt::MaximumSize, constraintSize).width(); + } else { + result.q_maximumSize = result.q_preferredSize; + } + } else { + QSizeF constraintSize(constraint, -1.0); + + result.q_preferredSize = sizeHint(Qt::PreferredSize, constraintSize).height(); + + if (policy & QLayoutPolicy::ShrinkFlag) { + result.q_minimumSize = sizeHint(Qt::MinimumSize, constraintSize).height(); + } else { + result.q_minimumSize = result.q_preferredSize; + } + + if (policy & (QLayoutPolicy::GrowFlag | QLayoutPolicy::ExpandFlag)) { + result.q_maximumSize = sizeHint(Qt::MaximumSize, constraintSize).height(); + } else { + result.q_maximumSize = result.q_preferredSize; + } + + if (alignment() & Qt::AlignBaseline) { + result.q_minimumDescent = sizeHint(Qt::MinimumDescent, constraintSize).height(); + if (result.q_minimumDescent != -1.0) { + const qreal minSizeHint = sizeHint(Qt::MinimumSize, constraintSize).height(); + result.q_minimumDescent -= (minSizeHint - result.q_minimumSize); + result.q_minimumAscent = result.q_minimumSize - result.q_minimumDescent; + } + } + } + if (policy & QLayoutPolicy::IgnoreFlag) + result.q_preferredSize = result.q_minimumSize; + + return result; +} + +QRectF QGridLayoutItem::geometryWithin(qreal x, qreal y, qreal width, qreal height, + qreal rowDescent, Qt::Alignment align) const +{ + const qreal cellWidth = width; + const qreal cellHeight = height; + + QSizeF size = effectiveMaxSize(QSizeF(-1,-1)); + if (hasDynamicConstraint()) { + if (dynamicConstraintOrientation() == Qt::Vertical) { + if (size.width() > cellWidth) + size = effectiveMaxSize(QSizeF(cellWidth, -1)); + } else if (size.height() > cellHeight) { + size = effectiveMaxSize(QSizeF(-1, cellHeight)); + } + } + size = size.boundedTo(QSizeF(cellWidth, cellHeight)); + width = size.width(); + height = size.height(); + + switch (align & Qt::AlignHorizontal_Mask) { + case Qt::AlignHCenter: + x += (cellWidth - width)/2; + break; + case Qt::AlignRight: + x += cellWidth - width; + break; + default: + break; + } + + switch (align & Qt::AlignVertical_Mask) { + case Qt::AlignVCenter: + y += (cellHeight - height)/2; + break; + case Qt::AlignBottom: + y += cellHeight - height; + break; + case Qt::AlignBaseline: { + width = qMin(effectiveMaxSize(QSizeF(-1,-1)).width(), width); + QGridLayoutBox vBox = box(Qt::Vertical); + const qreal descent = vBox.q_minimumDescent; + const qreal ascent = vBox.q_minimumSize - descent; + y += (cellHeight - rowDescent - ascent); + height = ascent + descent; + break; } + default: + break; + } + return QRectF(x, y, width, height); +} + +void QGridLayoutItem::transpose() +{ + qSwap(q_firstRows[Hor], q_firstRows[Ver]); + qSwap(q_rowSpans[Hor], q_rowSpans[Ver]); + qSwap(q_stretches[Hor], q_stretches[Ver]); +} + +void QGridLayoutItem::insertOrRemoveRows(int row, int delta, Qt::Orientation orientation) +{ + int oldFirstRow = firstRow(orientation); + if (oldFirstRow >= row) { + setFirstRow(oldFirstRow + delta, orientation); + } else if (lastRow(orientation) >= row) { + setRowSpan(rowSpan(orientation) + delta, orientation); + } +} +/*! + \internal + returns the effective maximumSize, will take the sizepolicy into + consideration. (i.e. if sizepolicy does not have QLayoutPolicy::Grow, then + maxSizeHint will be the preferredSize) + Note that effectiveSizeHint does not take sizePolicy into consideration, + (since it only evaluates the hints, as the name implies) +*/ +QSizeF QGridLayoutItem::effectiveMaxSize(const QSizeF &constraint) const +{ + QSizeF size = constraint; + bool vGrow = (sizePolicy(Qt::Vertical) & QLayoutPolicy::GrowFlag) == QLayoutPolicy::GrowFlag; + bool hGrow = (sizePolicy(Qt::Horizontal) & QLayoutPolicy::GrowFlag) == QLayoutPolicy::GrowFlag; + if (!vGrow || !hGrow) { + QSizeF pref = sizeHint(Qt::PreferredSize, constraint); + if (!vGrow) + size.setHeight(pref.height()); + if (!hGrow) + size.setWidth(pref.width()); + } + + if (!size.isValid()) { + QSizeF maxSize = sizeHint(Qt::MaximumSize, size); + if (size.width() == -1) + size.setWidth(maxSize.width()); + if (size.height() == -1) + size.setHeight(maxSize.height()); + } + return size; +} + +#ifdef QGRIDLAYOUTENGINE_DEBUG +void QGridLayoutItem::dump(int indent) const +{ + qDebug("%*s (%d, %d) %d x %d", indent, "", firstRow(), firstColumn(), //### + rowSpan(), columnSpan()); + + if (q_stretches[Hor] >= 0) + qDebug("%*s Horizontal stretch: %d", indent, "", q_stretches[Hor]); + if (q_stretches[Ver] >= 0) + qDebug("%*s Vertical stretch: %d", indent, "", q_stretches[Ver]); + if (q_alignment != 0) + qDebug("%*s Alignment: %x", indent, "", uint(q_alignment)); + qDebug("%*s Horizontal size policy: %x Vertical size policy: %x", + indent, "", sizePolicy(Qt::Horizontal), sizePolicy(Qt::Vertical)); +} +#endif + +void QGridLayoutRowInfo::insertOrRemoveRows(int row, int delta) +{ + count += delta; + + insertOrRemoveItems(stretches, row, delta); + insertOrRemoveItems(spacings, row, delta); + insertOrRemoveItems(alignments, row, delta); + insertOrRemoveItems(boxes, row, delta); +} + +#ifdef QGRIDLAYOUTENGINE_DEBUG +void QGridLayoutRowInfo::dump(int indent) const +{ + qDebug("%*sInfo (count: %d)", indent, "", count); + for (int i = 0; i < count; ++i) { + QString message; + + if (stretches.value(i).value() >= 0) + message += QString::fromLatin1(" stretch %1").arg(stretches.value(i).value()); + if (spacings.value(i).value() >= 0.0) + message += QString::fromLatin1(" spacing %1").arg(spacings.value(i).value()); + if (alignments.value(i) != 0) + message += QString::fromLatin1(" alignment %1").arg(int(alignments.value(i)), 16); + + if (!message.isEmpty() || boxes.value(i) != QGridLayoutBox()) { + qDebug("%*s Row %d:%s", indent, "", i, qPrintable(message)); + if (boxes.value(i) != QGridLayoutBox()) + boxes.value(i).dump(indent + 1); + } + } +} +#endif + +QGridLayoutEngine::QGridLayoutEngine(Qt::Alignment defaultAlignment) +{ + m_visualDirection = Qt::LeftToRight; + m_defaultAlignment = defaultAlignment; + invalidate(); +} + +int QGridLayoutEngine::rowCount(Qt::Orientation orientation) const +{ + return q_infos[orientation == Qt::Vertical].count; +} + +int QGridLayoutEngine::columnCount(Qt::Orientation orientation) const +{ + return q_infos[orientation == Qt::Horizontal].count; +} + +int QGridLayoutEngine::itemCount() const +{ + return q_items.count(); +} + +QGridLayoutItem *QGridLayoutEngine::itemAt(int index) const +{ + Q_ASSERT(index >= 0 && index < itemCount()); + return q_items.at(index); +} + +int QGridLayoutEngine::effectiveFirstRow(Qt::Orientation orientation) const +{ + ensureEffectiveFirstAndLastRows(); + return q_cachedEffectiveFirstRows[orientation == Qt::Vertical]; +} + +int QGridLayoutEngine::effectiveLastRow(Qt::Orientation orientation) const +{ + ensureEffectiveFirstAndLastRows(); + return q_cachedEffectiveLastRows[orientation == Qt::Vertical]; +} + +void QGridLayoutEngine::setSpacing(qreal spacing, Qt::Orientations orientations) +{ + if (orientations & Qt::Horizontal) + q_defaultSpacings[Hor].setUserValue(spacing); + if (orientations & Qt::Vertical) + q_defaultSpacings[Ver].setUserValue(spacing); + + invalidate(); +} + +qreal QGridLayoutEngine::spacing(Qt::Orientation orientation, const QAbstractLayoutStyleInfo *styleInfo) const +{ + if (!q_defaultSpacings[orientation == Qt::Vertical].isUser()) { + qreal defaultSpacing = styleInfo->spacing(orientation); + q_defaultSpacings[orientation == Qt::Vertical].setCachedValue(defaultSpacing); + } + return q_defaultSpacings[orientation == Qt::Vertical].value(); +} + +void QGridLayoutEngine::setRowSpacing(int row, qreal spacing, Qt::Orientation orientation) +{ + Q_ASSERT(row >= 0); + + QGridLayoutRowInfo &rowInfo = q_infos[orientation == Qt::Vertical]; + if (row >= rowInfo.spacings.count()) + rowInfo.spacings.resize(row + 1); + if (spacing >= 0) + rowInfo.spacings[row].setUserValue(spacing); + else + rowInfo.spacings[row] = QLayoutParameter<qreal>(); + invalidate(); +} + +qreal QGridLayoutEngine::rowSpacing(int row, Qt::Orientation orientation) const +{ + QLayoutParameter<qreal> spacing = q_infos[orientation == Qt::Vertical].spacings.value(row); + if (!spacing.isDefault()) + return spacing.value(); + return q_defaultSpacings[orientation == Qt::Vertical].value(); +} + +void QGridLayoutEngine::setRowStretchFactor(int row, int stretch, Qt::Orientation orientation) +{ + Q_ASSERT(row >= 0); + Q_ASSERT(stretch >= 0); + + maybeExpandGrid(row, -1, orientation); + + QGridLayoutRowInfo &rowInfo = q_infos[orientation == Qt::Vertical]; + if (row >= rowInfo.stretches.count()) + rowInfo.stretches.resize(row + 1); + rowInfo.stretches[row].setUserValue(stretch); +} + +int QGridLayoutEngine::rowStretchFactor(int row, Qt::Orientation orientation) const +{ + QStretchParameter stretch = q_infos[orientation == Qt::Vertical].stretches.value(row); + if (!stretch.isDefault()) + return stretch.value(); + return 0; +} + +void QGridLayoutEngine::setRowSizeHint(Qt::SizeHint which, int row, qreal size, + Qt::Orientation orientation) +{ + Q_ASSERT(row >= 0); + Q_ASSERT(size >= 0.0); + + maybeExpandGrid(row, -1, orientation); + + QGridLayoutRowInfo &rowInfo = q_infos[orientation == Qt::Vertical]; + if (row >= rowInfo.boxes.count()) + rowInfo.boxes.resize(row + 1); + rowInfo.boxes[row].q_sizes(which) = size; +} + +qreal QGridLayoutEngine::rowSizeHint(Qt::SizeHint which, int row, Qt::Orientation orientation) const +{ + return q_infos[orientation == Qt::Vertical].boxes.value(row).q_sizes(which); +} + +void QGridLayoutEngine::setRowAlignment(int row, Qt::Alignment alignment, + Qt::Orientation orientation) +{ + Q_ASSERT(row >= 0); + + maybeExpandGrid(row, -1, orientation); + + QGridLayoutRowInfo &rowInfo = q_infos[orientation == Qt::Vertical]; + if (row >= rowInfo.alignments.count()) + rowInfo.alignments.resize(row + 1); + rowInfo.alignments[row] = alignment; +} + +Qt::Alignment QGridLayoutEngine::rowAlignment(int row, Qt::Orientation orientation) const +{ + Q_ASSERT(row >= 0); + return q_infos[orientation == Qt::Vertical].alignments.value(row); +} + +Qt::Alignment QGridLayoutEngine::effectiveAlignment(const QGridLayoutItem *layoutItem) const +{ + Qt::Alignment align = layoutItem->alignment(); + if (!(align & Qt::AlignVertical_Mask)) { + // no vertical alignment, respect the row alignment + int y = layoutItem->firstRow(); + align |= (rowAlignment(y, Qt::Vertical) & Qt::AlignVertical_Mask); + if (!(align & Qt::AlignVertical_Mask)) + align |= (m_defaultAlignment & Qt::AlignVertical_Mask); + } + if (!(align & Qt::AlignHorizontal_Mask)) { + // no horizontal alignment, respect the column alignment + int x = layoutItem->firstColumn(); + align |= (rowAlignment(x, Qt::Horizontal) & Qt::AlignHorizontal_Mask); + } + + return align; +} + +/*! + \internal + The \a index is only used by QGraphicsLinearLayout to ensure that itemAt() reflects the order + of visual arrangement. Strictly speaking it does not have to, but most people expect it to. + (And if it didn't we would have to add itemArrangedAt(int index) or something..) + */ +void QGridLayoutEngine::insertItem(QGridLayoutItem *item, int index) +{ + maybeExpandGrid(item->lastRow(), item->lastColumn()); + + if (index == -1) + q_items.append(item); + else + q_items.insert(index, item); + + for (int i = item->firstRow(); i <= item->lastRow(); ++i) { + for (int j = item->firstColumn(); j <= item->lastColumn(); ++j) { + if (itemAt(i, j)) + qWarning("QGridLayoutEngine::addItem: Cell (%d, %d) already taken", i, j); + setItemAt(i, j, item); + } + } +} + +void QGridLayoutEngine::addItem(QGridLayoutItem *item) +{ + insertItem(item, -1); +} + +void QGridLayoutEngine::removeItem(QGridLayoutItem *item) +{ + Q_ASSERT(q_items.contains(item)); + + invalidate(); + + for (int i = item->firstRow(); i <= item->lastRow(); ++i) { + for (int j = item->firstColumn(); j <= item->lastColumn(); ++j) { + if (itemAt(i, j) == item) + setItemAt(i, j, 0); + } + } + + q_items.removeAll(item); +} + + +QGridLayoutItem *QGridLayoutEngine::itemAt(int row, int column, Qt::Orientation orientation) const +{ + if (orientation == Qt::Horizontal) + qSwap(row, column); + if (uint(row) >= uint(rowCount()) || uint(column) >= uint(columnCount())) + return 0; + return q_grid.at((row * internalGridColumnCount()) + column); +} + +void QGridLayoutEngine::invalidate() +{ + q_cachedEffectiveFirstRows[Hor] = -1; + q_cachedEffectiveFirstRows[Ver] = -1; + q_cachedEffectiveLastRows[Hor] = -1; + q_cachedEffectiveLastRows[Ver] = -1; + q_totalBoxesValid = false; + q_sizeHintValid[Hor] = false; + q_sizeHintValid[Ver] = false; + q_cachedSize = QSizeF(); + q_cachedConstraintOrientation = UnknownConstraint; +} + +static void visualRect(QRectF *geom, Qt::LayoutDirection dir, const QRectF &contentsRect) +{ + if (dir == Qt::RightToLeft) + geom->moveRight(contentsRect.right() - (geom->left() - contentsRect.left())); +} + +void QGridLayoutEngine::setGeometries(const QRectF &contentsGeometry, const QAbstractLayoutStyleInfo *styleInfo) +{ + if (rowCount() < 1 || columnCount() < 1) + return; + + ensureGeometries(contentsGeometry.size(), styleInfo); + + for (int i = q_items.count() - 1; i >= 0; --i) { + QGridLayoutItem *item = q_items.at(i); + + qreal x = q_xx[item->firstColumn()]; + qreal y = q_yy[item->firstRow()]; + qreal width = q_widths[item->lastColumn()]; + qreal height = q_heights[item->lastRow()]; + + if (item->columnSpan() != 1) + width += q_xx[item->lastColumn()] - x; + if (item->rowSpan() != 1) + height += q_yy[item->lastRow()] - y; + + QRectF geom = item->geometryWithin(contentsGeometry.x() + x, contentsGeometry.y() + y, + width, height, q_descents[item->lastRow()], effectiveAlignment(item)); + visualRect(&geom, visualDirection(), contentsGeometry); + item->setGeometry(geom); + } +} + +// ### candidate for deletion +QRectF QGridLayoutEngine::cellRect(const QRectF &contentsGeometry, int row, int column, int rowSpan, + int columnSpan, const QAbstractLayoutStyleInfo *styleInfo) const +{ + if (uint(row) >= uint(rowCount()) || uint(column) >= uint(columnCount()) + || rowSpan < 1 || columnSpan < 1) + return QRectF(); + + ensureGeometries(contentsGeometry.size(), styleInfo); + + int lastColumn = qMax(column + columnSpan, columnCount()) - 1; + int lastRow = qMax(row + rowSpan, rowCount()) - 1; + + qreal x = q_xx[column]; + qreal y = q_yy[row]; + qreal width = q_widths[lastColumn]; + qreal height = q_heights[lastRow]; + + if (columnSpan != 1) + width += q_xx[lastColumn] - x; + if (rowSpan != 1) + height += q_yy[lastRow] - y; + + return QRectF(contentsGeometry.x() + x, contentsGeometry.y() + y, width, height); +} + +QSizeF QGridLayoutEngine::sizeHint(Qt::SizeHint which, const QSizeF &constraint, + const QAbstractLayoutStyleInfo *styleInfo) const +{ + + + if (hasDynamicConstraint() && rowCount() > 0 && columnCount() > 0) { + QGridLayoutBox sizehint_totalBoxes[NOrientations]; + bool sizeHintCalculated = false; + if (constraintOrientation() == Qt::Vertical) { + //We have items whose height depends on their width + if (constraint.width() >= 0) { + ensureColumnAndRowData(&q_columnData, &sizehint_totalBoxes[Hor], NULL, NULL, Qt::Horizontal, styleInfo); + QVector<qreal> sizehint_xx; + QVector<qreal> sizehint_widths; + + sizehint_xx.resize(columnCount()); + sizehint_widths.resize(columnCount()); + qreal width = constraint.width(); + //Calculate column widths and positions, and put results in q_xx.data() and q_widths.data() so that we can use this information as + //constraints to find the row heights + q_columnData.calculateGeometries(0, columnCount(), width, sizehint_xx.data(), sizehint_widths.data(), + 0, sizehint_totalBoxes[Hor], q_infos[Hor]); + ensureColumnAndRowData(&q_rowData, &sizehint_totalBoxes[Ver], sizehint_xx.data(), sizehint_widths.data(), Qt::Vertical, styleInfo); + sizeHintCalculated = true; + } + } else { + if (constraint.height() >= 0) { + //We have items whose width depends on their height + ensureColumnAndRowData(&q_rowData, &sizehint_totalBoxes[Ver], NULL, NULL, Qt::Vertical, styleInfo); + QVector<qreal> sizehint_yy; + QVector<qreal> sizehint_heights; + + sizehint_yy.resize(rowCount()); + sizehint_heights.resize(rowCount()); + qreal height = constraint.height(); + //Calculate row heights and positions, and put results in q_yy.data() and q_heights.data() so that we can use this information as + //constraints to find the column widths + q_rowData.calculateGeometries(0, rowCount(), height, sizehint_yy.data(), sizehint_heights.data(), + 0, sizehint_totalBoxes[Ver], q_infos[Ver]); + ensureColumnAndRowData(&q_columnData, &sizehint_totalBoxes[Hor], sizehint_yy.data(), sizehint_heights.data(), Qt::Horizontal, styleInfo); + sizeHintCalculated = true; + } + } + if (sizeHintCalculated) + return QSizeF(sizehint_totalBoxes[Hor].q_sizes(which), sizehint_totalBoxes[Ver].q_sizes(which)); + } + + //No items with height for width, so it doesn't matter which order we do these in + ensureColumnAndRowData(&q_columnData, &q_totalBoxes[Hor], NULL, NULL, Qt::Horizontal, styleInfo); + ensureColumnAndRowData(&q_rowData, &q_totalBoxes[Ver], NULL, NULL, Qt::Vertical, styleInfo); + return QSizeF(q_totalBoxes[Hor].q_sizes(which), q_totalBoxes[Ver].q_sizes(which)); +} + +QLayoutPolicy::ControlTypes QGridLayoutEngine::controlTypes(LayoutSide side) const +{ + Qt::Orientation orientation = (side == Top || side == Bottom) ? Qt::Vertical : Qt::Horizontal; + int row = (side == Top || side == Left) ? effectiveFirstRow(orientation) + : effectiveLastRow(orientation); + QLayoutPolicy::ControlTypes result = 0; + + for (int column = columnCount(orientation) - 1; column >= 0; --column) { + if (QGridLayoutItem *item = itemAt(row, column, orientation)) + result |= item->controlTypes(side); + } + return result; +} + +void QGridLayoutEngine::transpose() +{ + invalidate(); + + for (int i = q_items.count() - 1; i >= 0; --i) + q_items.at(i)->transpose(); + + qSwap(q_defaultSpacings[Hor], q_defaultSpacings[Ver]); + qSwap(q_infos[Hor], q_infos[Ver]); + + regenerateGrid(); +} + +void QGridLayoutEngine::setVisualDirection(Qt::LayoutDirection direction) +{ + m_visualDirection = direction; +} + +Qt::LayoutDirection QGridLayoutEngine::visualDirection() const +{ + return m_visualDirection; +} + +#ifdef QGRIDLAYOUTENGINE_DEBUG +void QGridLayoutEngine::dump(int indent) const +{ + qDebug("%*sEngine", indent, ""); + + qDebug("%*s Items (%d)", indent, "", q_items.count()); + int i; + for (i = 0; i < q_items.count(); ++i) + q_items.at(i)->dump(indent + 2); + + qDebug("%*s Grid (%d x %d)", indent, "", internalGridRowCount(), + internalGridColumnCount()); + for (int row = 0; row < internalGridRowCount(); ++row) { + QString message = QLatin1String("[ "); + for (int column = 0; column < internalGridColumnCount(); ++column) { + message += QString::number(q_items.indexOf(itemAt(row, column))).rightJustified(3); + message += QLatin1Char(' '); + } + message += QLatin1Char(']'); + qDebug("%*s %s", indent, "", qPrintable(message)); + } + + if (q_defaultSpacings[Hor].value() >= 0.0 || q_defaultSpacings[Ver].value() >= 0.0) + qDebug("%*s Default spacings: %g %g", indent, "", q_defaultSpacings[Hor].value(), + q_defaultSpacings[Ver].value()); + + qDebug("%*s Column and row info", indent, ""); + q_infos[Hor].dump(indent + 2); + q_infos[Ver].dump(indent + 2); + + qDebug("%*s Column and row data", indent, ""); + q_columnData.dump(indent + 2); + q_rowData.dump(indent + 2); + + qDebug("%*s Geometries output", indent, ""); + QVector<qreal> *cellPos = &q_yy; + for (int pass = 0; pass < 2; ++pass) { + QString message; + for (i = 0; i < cellPos->count(); ++i) { + message += QLatin1String((message.isEmpty() ? "[" : ", ")); + message += QString::number(cellPos->at(i)); + } + message += QLatin1Char(']'); + qDebug("%*s %s %s", indent, "", (pass == 0 ? "rows:" : "columns:"), qPrintable(message)); + cellPos = &q_xx; + } +} +#endif + +void QGridLayoutEngine::maybeExpandGrid(int row, int column, Qt::Orientation orientation) +{ + invalidate(); // ### move out of here? + + if (orientation == Qt::Horizontal) + qSwap(row, column); + + if (row < rowCount() && column < columnCount()) + return; + + int oldGridRowCount = internalGridRowCount(); + int oldGridColumnCount = internalGridColumnCount(); + + q_infos[Ver].count = qMax(row + 1, rowCount()); + q_infos[Hor].count = qMax(column + 1, columnCount()); + + int newGridRowCount = internalGridRowCount(); + int newGridColumnCount = internalGridColumnCount(); + + int newGridSize = newGridRowCount * newGridColumnCount; + if (newGridSize != q_grid.count()) { + q_grid.resize(newGridSize); + + if (newGridColumnCount != oldGridColumnCount) { + for (int i = oldGridRowCount - 1; i >= 1; --i) { + for (int j = oldGridColumnCount - 1; j >= 0; --j) { + int oldIndex = (i * oldGridColumnCount) + j; + int newIndex = (i * newGridColumnCount) + j; + + Q_ASSERT(newIndex > oldIndex); + q_grid[newIndex] = q_grid[oldIndex]; + q_grid[oldIndex] = 0; + } + } + } + } +} + +void QGridLayoutEngine::regenerateGrid() +{ + q_grid.fill(0); + + for (int i = q_items.count() - 1; i >= 0; --i) { + QGridLayoutItem *item = q_items.at(i); + + for (int j = item->firstRow(); j <= item->lastRow(); ++j) { + for (int k = item->firstColumn(); k <= item->lastColumn(); ++k) { + setItemAt(j, k, item); + } + } + } +} + +void QGridLayoutEngine::setItemAt(int row, int column, QGridLayoutItem *item) +{ + Q_ASSERT(row >= 0 && row < rowCount()); + Q_ASSERT(column >= 0 && column < columnCount()); + q_grid[(row * internalGridColumnCount()) + column] = item; +} + +void QGridLayoutEngine::insertOrRemoveRows(int row, int delta, Qt::Orientation orientation) +{ + int oldRowCount = rowCount(orientation); + Q_ASSERT(uint(row) <= uint(oldRowCount)); + + invalidate(); + + // appending rows (or columns) is easy + if (row == oldRowCount && delta > 0) { + maybeExpandGrid(oldRowCount + delta - 1, -1, orientation); + return; + } + + q_infos[orientation == Qt::Vertical].insertOrRemoveRows(row, delta); + + for (int i = q_items.count() - 1; i >= 0; --i) + q_items.at(i)->insertOrRemoveRows(row, delta, orientation); + + q_grid.resize(internalGridRowCount() * internalGridColumnCount()); + regenerateGrid(); +} + +void QGridLayoutEngine::fillRowData(QGridLayoutRowData *rowData, + const qreal *colPositions, const qreal *colSizes, + Qt::Orientation orientation, + const QAbstractLayoutStyleInfo *styleInfo) const +{ + const int ButtonMask = QLayoutPolicy::ButtonBox | QLayoutPolicy::PushButton; + const QGridLayoutRowInfo &rowInfo = q_infos[orientation == Qt::Vertical]; + const QGridLayoutRowInfo &columnInfo = q_infos[orientation == Qt::Horizontal]; + LayoutSide top = (orientation == Qt::Vertical) ? Top : Left; + LayoutSide bottom = (orientation == Qt::Vertical) ? Bottom : Right; + + const QLayoutParameter<qreal> &defaultSpacing = q_defaultSpacings[orientation == Qt::Vertical]; + qreal innerSpacing = styleInfo->spacing(orientation); + if (innerSpacing >= 0.0) + defaultSpacing.setCachedValue(innerSpacing); + + for (int row = 0; row < rowInfo.count; ++row) { + bool rowIsEmpty = true; + bool rowIsIdenticalToPrevious = (row > 0); + + for (int column = 0; column < columnInfo.count; ++column) { + QGridLayoutItem *item = itemAt(row, column, orientation); + + if (rowIsIdenticalToPrevious && item != itemAt(row - 1, column, orientation)) + rowIsIdenticalToPrevious = false; + + if (item) + rowIsEmpty = false; + } + + if ((rowIsEmpty || rowIsIdenticalToPrevious) + && rowInfo.spacings.value(row).isDefault() + && rowInfo.stretches.value(row).isDefault() + && rowInfo.boxes.value(row) == QGridLayoutBox()) + rowData->ignore.setBit(row, true); + + if (rowInfo.spacings.value(row).isUser()) { + rowData->spacings[row] = rowInfo.spacings.at(row).value(); + } else if (!defaultSpacing.isDefault()) { + rowData->spacings[row] = defaultSpacing.value(); + } + + rowData->stretches[row] = rowInfo.stretches.value(row).value(); + } + + struct RowAdHocData { + int q_row; + unsigned int q_hasButtons : 8; + unsigned int q_hasNonButtons : 8; + + inline RowAdHocData() : q_row(-1), q_hasButtons(false), q_hasNonButtons(false) {} + inline void init(int row) { + this->q_row = row; + q_hasButtons = false; + q_hasNonButtons = false; + } + inline bool hasOnlyButtons() const { return q_hasButtons && !q_hasNonButtons; } + inline bool hasOnlyNonButtons() const { return q_hasNonButtons && !q_hasButtons; } + }; + RowAdHocData lastRowAdHocData; + RowAdHocData nextToLastRowAdHocData; + RowAdHocData nextToNextToLastRowAdHocData; + + rowData->hasIgnoreFlag = false; + for (int row = 0; row < rowInfo.count; ++row) { + if (rowData->ignore.testBit(row)) + continue; + + QGridLayoutBox &rowBox = rowData->boxes[row]; + if (styleInfo->isWindow()) { + nextToNextToLastRowAdHocData = nextToLastRowAdHocData; + nextToLastRowAdHocData = lastRowAdHocData; + lastRowAdHocData.init(row); + } + + bool userRowStretch = rowInfo.stretches.value(row).isUser(); + int &rowStretch = rowData->stretches[row]; + + bool hasIgnoreFlag = true; + for (int column = 0; column < columnInfo.count; ++column) { + QGridLayoutItem *item = itemAt(row, column, orientation); + if (item) { + int itemRow = item->firstRow(orientation); + int itemColumn = item->firstColumn(orientation); + + if (itemRow == row && itemColumn == column) { + int itemStretch = item->stretchFactor(orientation); + if (!(item->sizePolicy(orientation) & QLayoutPolicy::IgnoreFlag)) + hasIgnoreFlag = false; + int itemRowSpan = item->rowSpan(orientation); + + int effectiveRowSpan = 1; + for (int i = 1; i < itemRowSpan; ++i) { + if (!rowData->ignore.testBit(i + itemRow)) + ++effectiveRowSpan; + } + + QGridLayoutBox *box; + if (effectiveRowSpan == 1) { + box = &rowBox; + if (!userRowStretch && itemStretch != 0) + rowStretch = qMax(rowStretch, itemStretch); + } else { + QGridLayoutMultiCellData &multiCell = + rowData->multiCellMap[qMakePair(row, effectiveRowSpan)]; + box = &multiCell.q_box; + multiCell.q_stretch = itemStretch; + } + // Items with constraints need to be passed the constraint + if (colSizes && colPositions && item->hasDynamicConstraint() && orientation == item->dynamicConstraintOrientation()) { + /* Get the width of the item by summing up the widths of the columns that it spans. + * We need to have already calculated the widths of the columns by calling + * q_columns->calculateGeometries() before hand and passing the value in the colSizes + * and colPositions parameters. + * The variable name is still colSizes even when it actually has the row sizes + */ + qreal length = colSizes[item->lastColumn(orientation)]; + if (item->columnSpan(orientation) != 1) + length += colPositions[item->lastColumn(orientation)] - colPositions[item->firstColumn(orientation)]; + box->combine(item->box(orientation, length)); + } else { + box->combine(item->box(orientation)); + } + + if (effectiveRowSpan == 1) { + QLayoutPolicy::ControlTypes controls = item->controlTypes(top); + if (controls & ButtonMask) + lastRowAdHocData.q_hasButtons = true; + if (controls & ~ButtonMask) + lastRowAdHocData.q_hasNonButtons = true; + } + } + } + } + if (row < rowInfo.boxes.count()) { + QGridLayoutBox rowBoxInfo = rowInfo.boxes.at(row); + rowBoxInfo.normalize(); + rowBox.q_minimumSize = qMax(rowBox.q_minimumSize, rowBoxInfo.q_minimumSize); + rowBox.q_maximumSize = qMax(rowBox.q_minimumSize, + (rowBoxInfo.q_maximumSize != FLT_MAX ? + rowBoxInfo.q_maximumSize : rowBox.q_maximumSize)); + rowBox.q_preferredSize = qBound(rowBox.q_minimumSize, + qMax(rowBox.q_preferredSize, rowBoxInfo.q_preferredSize), + rowBox.q_maximumSize); + } + if (hasIgnoreFlag) + rowData->hasIgnoreFlag = true; + } + + /* + Heuristic: Detect button boxes that don't use QLayoutPolicy::ButtonBox. + This is somewhat ad hoc but it usually does the trick. + */ + bool lastRowIsButtonBox = (lastRowAdHocData.hasOnlyButtons() + && nextToLastRowAdHocData.hasOnlyNonButtons()); + bool lastTwoRowsIsButtonBox = (lastRowAdHocData.hasOnlyButtons() + && nextToLastRowAdHocData.hasOnlyButtons() + && nextToNextToLastRowAdHocData.hasOnlyNonButtons() + && orientation == Qt::Vertical); + + if (defaultSpacing.isDefault()) { + int prevRow = -1; + for (int row = 0; row < rowInfo.count; ++row) { + if (rowData->ignore.testBit(row)) + continue; + + if (prevRow != -1 && !rowInfo.spacings.value(prevRow).isUser()) { + qreal &rowSpacing = rowData->spacings[prevRow]; + for (int column = 0; column < columnInfo.count; ++column) { + QGridLayoutItem *item1 = itemAt(prevRow, column, orientation); + QGridLayoutItem *item2 = itemAt(row, column, orientation); + + if (item1 && item2 && item1 != item2) { + QLayoutPolicy::ControlTypes controls1 = item1->controlTypes(bottom); + QLayoutPolicy::ControlTypes controls2 = item2->controlTypes(top); + + if (controls2 & QLayoutPolicy::PushButton) { + if ((row == nextToLastRowAdHocData.q_row && lastTwoRowsIsButtonBox) + || (row == lastRowAdHocData.q_row && lastRowIsButtonBox)) { + controls2 &= ~QLayoutPolicy::PushButton; + controls2 |= QLayoutPolicy::ButtonBox; + } + } + + qreal spacing = styleInfo->combinedLayoutSpacing(controls1, controls2, + orientation); + if (orientation == Qt::Horizontal) { + qreal width1 = rowData->boxes.at(prevRow).q_minimumSize; + qreal width2 = rowData->boxes.at(row).q_minimumSize; + QRectF rect1 = item1->geometryWithin(0.0, 0.0, width1, FLT_MAX, -1.0, effectiveAlignment(item1)); + QRectF rect2 = item2->geometryWithin(0.0, 0.0, width2, FLT_MAX, -1.0, effectiveAlignment(item2)); + spacing -= (width1 - (rect1.x() + rect1.width())) + rect2.x(); + } else { + const QGridLayoutBox &box1 = rowData->boxes.at(prevRow); + const QGridLayoutBox &box2 = rowData->boxes.at(row); + qreal height1 = box1.q_minimumSize; + qreal height2 = box2.q_minimumSize; + qreal rowDescent1 = fixedDescent(box1.q_minimumDescent, + box1.q_minimumAscent, height1); + qreal rowDescent2 = fixedDescent(box2.q_minimumDescent, + box2.q_minimumAscent, height2); + QRectF rect1 = item1->geometryWithin(0.0, 0.0, FLT_MAX, height1, + rowDescent1, effectiveAlignment(item1)); + QRectF rect2 = item2->geometryWithin(0.0, 0.0, FLT_MAX, height2, + rowDescent2, effectiveAlignment(item2)); + spacing -= (height1 - (rect1.y() + rect1.height())) + rect2.y(); + } + rowSpacing = qMax(spacing, rowSpacing); + } + } + } + prevRow = row; + } + } else if (lastRowIsButtonBox || lastTwoRowsIsButtonBox) { + /* + Even for styles that define a uniform spacing, we cheat a + bit and use the window margin as the spacing. This + significantly improves the look of dialogs. + */ + int prevRow = lastRowIsButtonBox ? nextToLastRowAdHocData.q_row + : nextToNextToLastRowAdHocData.q_row; + if (!defaultSpacing.isUser() && !rowInfo.spacings.value(prevRow).isUser()) { + qreal windowMargin = styleInfo->windowMargin(orientation); + qreal &rowSpacing = rowData->spacings[prevRow]; + rowSpacing = qMax(windowMargin, rowSpacing); + } + } +} + +void QGridLayoutEngine::ensureEffectiveFirstAndLastRows() const +{ + if (q_cachedEffectiveFirstRows[Hor] == -1 && !q_items.isEmpty()) { + int rowCount = this->rowCount(); + int columnCount = this->columnCount(); + + q_cachedEffectiveFirstRows[Ver] = rowCount; + q_cachedEffectiveFirstRows[Hor] = columnCount; + q_cachedEffectiveLastRows[Ver] = -1; + q_cachedEffectiveLastRows[Hor] = -1; + + for (int i = q_items.count() - 1; i >= 0; --i) { + const QGridLayoutItem *item = q_items.at(i); + + for (int j = 0; j < NOrientations; ++j) { + Qt::Orientation orientation = (j == Hor) ? Qt::Horizontal : Qt::Vertical; + if (item->firstRow(orientation) < q_cachedEffectiveFirstRows[j]) + q_cachedEffectiveFirstRows[j] = item->firstRow(orientation); + if (item->lastRow(orientation) > q_cachedEffectiveLastRows[j]) + q_cachedEffectiveLastRows[j] = item->lastRow(orientation); + } + } + } +} + +void QGridLayoutEngine::ensureColumnAndRowData(QGridLayoutRowData *rowData, QGridLayoutBox *totalBox, + const qreal *colPositions, const qreal *colSizes, + Qt::Orientation orientation, + const QAbstractLayoutStyleInfo *styleInfo) const +{ + const int o = (orientation == Qt::Vertical ? Ver : Hor); + if (q_sizeHintValid[o] && !colPositions && !colSizes) { + if (totalBox != &q_totalBoxes[o]) + *totalBox = q_totalBoxes[o]; + return; + } + rowData->reset(rowCount(orientation)); + fillRowData(rowData, colPositions, colSizes, orientation, styleInfo); + const QGridLayoutRowInfo &rowInfo = q_infos[orientation == Qt::Vertical]; + rowData->distributeMultiCells(rowInfo); + *totalBox = rowData->totalBox(0, rowCount(orientation)); + + if (!colPositions && !colSizes) { + q_totalBoxes[o] = *totalBox; + q_sizeHintValid[o] = true; + } +} + +/** + returns false if the layout has contradicting constraints (i.e. some items with a horizontal + constraint and other items with a vertical constraint) + */ +bool QGridLayoutEngine::ensureDynamicConstraint() const +{ + if (q_cachedConstraintOrientation == UnknownConstraint) { + for (int i = q_items.count() - 1; i >= 0; --i) { + QGridLayoutItem *item = q_items.at(i); + if (item->hasDynamicConstraint()) { + Qt::Orientation itemConstraintOrientation = item->dynamicConstraintOrientation(); + if (q_cachedConstraintOrientation == UnknownConstraint) { + q_cachedConstraintOrientation = itemConstraintOrientation; + } else if (q_cachedConstraintOrientation != itemConstraintOrientation) { + q_cachedConstraintOrientation = UnfeasibleConstraint; + qWarning("QGridLayoutEngine: Unfeasible, cannot mix horizontal and" + " vertical constraint in the same layout"); + return false; + } + } + } + if (q_cachedConstraintOrientation == UnknownConstraint) + q_cachedConstraintOrientation = NoConstraint; + } + return true; +} + +bool QGridLayoutEngine::hasDynamicConstraint() const +{ + if (!ensureDynamicConstraint()) + return false; + return q_cachedConstraintOrientation != NoConstraint; +} + +/* + * return value is only valid if hasConstraint() returns \c true + */ +Qt::Orientation QGridLayoutEngine::constraintOrientation() const +{ + (void)ensureDynamicConstraint(); + return (Qt::Orientation)q_cachedConstraintOrientation; +} + +void QGridLayoutEngine::ensureGeometries(const QSizeF &size, + const QAbstractLayoutStyleInfo *styleInfo) const +{ + if (!styleInfo->hasChanged() && q_totalBoxesValid && q_cachedSize == size) + return; + + q_totalBoxesValid = true; + q_cachedSize = size; + + q_xx.resize(columnCount()); + q_widths.resize(columnCount()); + q_yy.resize(rowCount()); + q_heights.resize(rowCount()); + q_descents.resize(rowCount()); + + if (constraintOrientation() != Qt::Horizontal) { + //We might have items whose width depends on their height + ensureColumnAndRowData(&q_columnData, &q_totalBoxes[Hor], NULL, NULL, Qt::Horizontal, styleInfo); + //Calculate column widths and positions, and put results in q_xx.data() and q_widths.data() so that we can use this information as + //constraints to find the row heights + q_columnData.calculateGeometries(0, columnCount(), size.width(), q_xx.data(), q_widths.data(), + 0, q_totalBoxes[Hor], q_infos[Hor] ); + ensureColumnAndRowData(&q_rowData, &q_totalBoxes[Ver], q_xx.data(), q_widths.data(), Qt::Vertical, styleInfo); + //Calculate row heights and positions, and put results in q_yy.data() and q_heights.data() + q_rowData.calculateGeometries(0, rowCount(), size.height(), q_yy.data(), q_heights.data(), + q_descents.data(), q_totalBoxes[Ver], q_infos[Ver]); + } else { + //We have items whose height depends on their width + ensureColumnAndRowData(&q_rowData, &q_totalBoxes[Ver], NULL, NULL, Qt::Vertical, styleInfo); + //Calculate row heights and positions, and put results in q_yy.data() and q_heights.data() so that we can use this information as + //constraints to find the column widths + q_rowData.calculateGeometries(0, rowCount(), size.height(), q_yy.data(), q_heights.data(), + q_descents.data(), q_totalBoxes[Ver], q_infos[Ver]); + ensureColumnAndRowData(&q_columnData, &q_totalBoxes[Hor], q_yy.data(), q_heights.data(), Qt::Horizontal, styleInfo); + //Calculate row heights and positions, and put results in q_yy.data() and q_heights.data() + q_columnData.calculateGeometries(0, columnCount(), size.width(), q_xx.data(), q_widths.data(), + 0, q_totalBoxes[Hor], q_infos[Hor]); + } +} + +QT_END_NAMESPACE + +#endif //QT_NO_GRAPHICSVIEW diff --git a/src/gui/util/qgridlayoutengine_p.h b/src/gui/util/qgridlayoutengine_p.h new file mode 100644 index 0000000000..9650e7fffe --- /dev/null +++ b/src/gui/util/qgridlayoutengine_p.h @@ -0,0 +1,473 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGRIDLAYOUTENGINE_P_H +#define QGRIDLAYOUTENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the graphics view layout classes. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qalgorithms.h" +#include "qbitarray.h" +#include "qlist.h" +#include "qmap.h" +#include "qpair.h" +#include <QtCore/qvector.h> +#include <QtCore/qsize.h> +#include <QtCore/qrect.h> +#include <float.h> +#include "qlayoutpolicy_p.h" +#include "qabstractlayoutstyleinfo_p.h" + +// #define QGRIDLAYOUTENGINE_DEBUG + +QT_BEGIN_NAMESPACE + +class QStyle; +class QWidget; + +// ### deal with Descent in a similar way +enum { + MinimumSize = Qt::MinimumSize, + PreferredSize = Qt::PreferredSize, + MaximumSize = Qt::MaximumSize, + NSizes +}; + +// do not reorder +enum { + Hor, + Ver, + NOrientations +}; + +// do not reorder +enum LayoutSide { + Left, + Top, + Right, + Bottom +}; + +enum { + NoConstraint, + HorizontalConstraint, // Width depends on the height + VerticalConstraint, // Height depends on the width + UnknownConstraint, // need to update cache + UnfeasibleConstraint // not feasible, it be has some items with Vertical and others with Horizontal constraints +}; + +template <typename T> +class QLayoutParameter +{ +public: + enum State { Default, User, Cached }; + + inline QLayoutParameter() : q_value(T()), q_state(Default) {} + inline QLayoutParameter(T value, State state = Default) : q_value(value), q_state(state) {} + + inline void setUserValue(T value) { + q_value = value; + q_state = User; + } + inline void setCachedValue(T value) const { + if (q_state != User) { + q_value = value; + q_state = Cached; + } + } + inline T value() const { return q_value; } + inline T value(T defaultValue) const { return isUser() ? q_value : defaultValue; } + inline bool isDefault() const { return q_state == Default; } + inline bool isUser() const { return q_state == User; } + inline bool isCached() const { return q_state == Cached; } + +private: + mutable T q_value; + mutable State q_state; +}; + +class QStretchParameter : public QLayoutParameter<int> +{ +public: + QStretchParameter() : QLayoutParameter<int>(-1) {} + +}; + +class Q_GUI_EXPORT QGridLayoutBox +{ +public: + inline QGridLayoutBox() + : q_minimumSize(0), q_preferredSize(0), q_maximumSize(FLT_MAX), + q_minimumDescent(-1), q_minimumAscent(-1) {} + + void add(const QGridLayoutBox &other, int stretch, qreal spacing); + void combine(const QGridLayoutBox &other); + void normalize(); + +#ifdef QGRIDLAYOUTENGINE_DEBUG + void dump(int indent = 0) const; +#endif + // This code could use the union-struct-array trick, but a compiler + // bug prevents this from working. + qreal q_minimumSize; + qreal q_preferredSize; + qreal q_maximumSize; + qreal q_minimumDescent; + qreal q_minimumAscent; + inline qreal &q_sizes(int which) + { + qreal *t; + switch (which) { + case Qt::MinimumSize: + t = &q_minimumSize; + break; + case Qt::PreferredSize: + t = &q_preferredSize; + break; + case Qt::MaximumSize: + t = &q_maximumSize; + break; + case Qt::MinimumDescent: + t = &q_minimumDescent; + break; + case (Qt::MinimumDescent + 1): + t = &q_minimumAscent; + break; + default: + t = 0; + break; + } + return *t; + } + inline const qreal &q_sizes(int which) const + { + const qreal *t; + switch (which) { + case Qt::MinimumSize: + t = &q_minimumSize; + break; + case Qt::PreferredSize: + t = &q_preferredSize; + break; + case Qt::MaximumSize: + t = &q_maximumSize; + break; + case Qt::MinimumDescent: + t = &q_minimumDescent; + break; + case (Qt::MinimumDescent + 1): + t = &q_minimumAscent; + break; + default: + t = 0; + break; + } + return *t; + } +}; + +bool operator==(const QGridLayoutBox &box1, const QGridLayoutBox &box2); +inline bool operator!=(const QGridLayoutBox &box1, const QGridLayoutBox &box2) + { return !operator==(box1, box2); } + +class QGridLayoutMultiCellData +{ +public: + inline QGridLayoutMultiCellData() : q_stretch(-1) {} + + QGridLayoutBox q_box; + int q_stretch; +}; + +typedef QMap<QPair<int, int>, QGridLayoutMultiCellData> MultiCellMap; + +class QGridLayoutRowInfo; + +class QGridLayoutRowData +{ +public: + void reset(int count); + void distributeMultiCells(const QGridLayoutRowInfo &rowInfo); + void calculateGeometries(int start, int end, qreal targetSize, qreal *positions, qreal *sizes, + qreal *descents, const QGridLayoutBox &totalBox, + const QGridLayoutRowInfo &rowInfo); + QGridLayoutBox totalBox(int start, int end) const; + void stealBox(int start, int end, int which, qreal *positions, qreal *sizes); + +#ifdef QGRIDLAYOUTENGINE_DEBUG + void dump(int indent = 0) const; +#endif + + QBitArray ignore; // ### rename q_ + QVector<QGridLayoutBox> boxes; + MultiCellMap multiCellMap; + QVector<int> stretches; + QVector<qreal> spacings; + bool hasIgnoreFlag; +}; + +class QGridLayoutRowInfo +{ +public: + inline QGridLayoutRowInfo() : count(0) {} + + void insertOrRemoveRows(int row, int delta); + +#ifdef QGRIDLAYOUTENGINE_DEBUG + void dump(int indent = 0) const; +#endif + + int count; + QVector<QStretchParameter> stretches; + QVector<QLayoutParameter<qreal> > spacings; + QVector<Qt::Alignment> alignments; + QVector<QGridLayoutBox> boxes; +}; + + +class Q_GUI_EXPORT QGridLayoutItem +{ +public: + QGridLayoutItem(int row, int column, int rowSpan = 1, int columnSpan = 1, + Qt::Alignment alignment = 0); + virtual ~QGridLayoutItem() {} + + inline int firstRow() const { return q_firstRows[Ver]; } + inline int firstColumn() const { return q_firstRows[Hor]; } + inline int rowSpan() const { return q_rowSpans[Ver]; } + inline int columnSpan() const { return q_rowSpans[Hor]; } + inline int lastRow() const { return firstRow() + rowSpan() - 1; } + inline int lastColumn() const { return firstColumn() + columnSpan() - 1; } + + int firstRow(Qt::Orientation orientation) const; + int firstColumn(Qt::Orientation orientation) const; + int lastRow(Qt::Orientation orientation) const; + int lastColumn(Qt::Orientation orientation) const; + int rowSpan(Qt::Orientation orientation) const; + int columnSpan(Qt::Orientation orientation) const; + void setFirstRow(int row, Qt::Orientation orientation = Qt::Vertical); + void setRowSpan(int rowSpan, Qt::Orientation orientation = Qt::Vertical); + + int stretchFactor(Qt::Orientation orientation) const; + void setStretchFactor(int stretch, Qt::Orientation orientation); + + inline Qt::Alignment alignment() const { return q_alignment; } + inline void setAlignment(Qt::Alignment alignment) { q_alignment = alignment; } + + virtual QLayoutPolicy::Policy sizePolicy(Qt::Orientation orientation) const = 0; + virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const = 0; + + virtual void setGeometry(const QRectF &rect) = 0; + /* + returns true if the size policy returns true for either hasHeightForWidth() + or hasWidthForHeight() + */ + virtual bool hasDynamicConstraint() const { return false; } + virtual Qt::Orientation dynamicConstraintOrientation() const { return Qt::Horizontal; } + + + virtual QLayoutPolicy::ControlTypes controlTypes(LayoutSide side) const; + + QRectF geometryWithin(qreal x, qreal y, qreal width, qreal height, qreal rowDescent, Qt::Alignment align) const; + QGridLayoutBox box(Qt::Orientation orientation, qreal constraint = -1.0) const; + + + void transpose(); + void insertOrRemoveRows(int row, int delta, Qt::Orientation orientation = Qt::Vertical); + QSizeF effectiveMaxSize(const QSizeF &constraint) const; + +#ifdef QGRIDLAYOUTENGINE_DEBUG + void dump(int indent = 0) const; +#endif + +private: + int q_firstRows[NOrientations]; + int q_rowSpans[NOrientations]; + int q_stretches[NOrientations]; + Qt::Alignment q_alignment; + +}; + +class Q_GUI_EXPORT QGridLayoutEngine +{ +public: + QGridLayoutEngine(Qt::Alignment defaultAlignment = Qt::Alignment(0)); + inline ~QGridLayoutEngine() { qDeleteAll(q_items); } + + int rowCount(Qt::Orientation orientation) const; + int columnCount(Qt::Orientation orientation) const; + inline int rowCount() const { return q_infos[Ver].count; } + inline int columnCount() const { return q_infos[Hor].count; } + // returns the number of items inserted, which may be less than (rowCount * columnCount) + int itemCount() const; + QGridLayoutItem *itemAt(int index) const; + + int effectiveFirstRow(Qt::Orientation orientation = Qt::Vertical) const; + int effectiveLastRow(Qt::Orientation orientation = Qt::Vertical) const; + + void setSpacing(qreal spacing, Qt::Orientations orientations); + qreal spacing(Qt::Orientation orientation, const QAbstractLayoutStyleInfo *styleInfo) const; + // ### setSpacingAfterRow(), spacingAfterRow() + void setRowSpacing(int row, qreal spacing, Qt::Orientation orientation = Qt::Vertical); + qreal rowSpacing(int row, Qt::Orientation orientation = Qt::Vertical) const; + + void setRowStretchFactor(int row, int stretch, Qt::Orientation orientation = Qt::Vertical); + int rowStretchFactor(int row, Qt::Orientation orientation = Qt::Vertical) const; + + void setRowSizeHint(Qt::SizeHint which, int row, qreal size, + Qt::Orientation orientation = Qt::Vertical); + qreal rowSizeHint(Qt::SizeHint which, int row, + Qt::Orientation orientation = Qt::Vertical) const; + + void setRowAlignment(int row, Qt::Alignment alignment, Qt::Orientation orientation); + Qt::Alignment rowAlignment(int row, Qt::Orientation orientation) const; + + Qt::Alignment effectiveAlignment(const QGridLayoutItem *layoutItem) const; + + + void insertItem(QGridLayoutItem *item, int index); + void addItem(QGridLayoutItem *item); + void removeItem(QGridLayoutItem *item); + void deleteItems() + { + const QList<QGridLayoutItem *> oldItems = q_items; + q_items.clear(); // q_items are used as input when the grid is regenerated in removeRows + // The following calls to removeRows are suboptimal + int rows = rowCount(Qt::Vertical); + removeRows(0, rows, Qt::Vertical); + rows = rowCount(Qt::Horizontal); + removeRows(0, rows, Qt::Horizontal); + qDeleteAll(oldItems); + } + + QGridLayoutItem *itemAt(int row, int column, Qt::Orientation orientation = Qt::Vertical) const; + inline void insertRow(int row, Qt::Orientation orientation = Qt::Vertical) + { insertOrRemoveRows(row, +1, orientation); } + inline void removeRows(int row, int count, Qt::Orientation orientation) + { insertOrRemoveRows(row, -count, orientation); } + + void invalidate(); + void setGeometries(const QRectF &contentsGeometry, const QAbstractLayoutStyleInfo *styleInfo); + QRectF cellRect(const QRectF &contentsGeometry, int row, int column, int rowSpan, int columnSpan, + const QAbstractLayoutStyleInfo *styleInfo) const; + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint, + const QAbstractLayoutStyleInfo *styleInfo) const; + + // heightForWidth / widthForHeight support + QSizeF dynamicallyConstrainedSizeHint(Qt::SizeHint which, const QSizeF &constraint) const; + bool ensureDynamicConstraint() const; + bool hasDynamicConstraint() const; + Qt::Orientation constraintOrientation() const; + + + QLayoutPolicy::ControlTypes controlTypes(LayoutSide side) const; + void transpose(); + void setVisualDirection(Qt::LayoutDirection direction); + Qt::LayoutDirection visualDirection() const; +#ifdef QGRIDLAYOUTENGINE_DEBUG + void dump(int indent = 0) const; +#endif + +private: + static int grossRoundUp(int n) { return ((n + 2) | 0x3) - 2; } + + void maybeExpandGrid(int row, int column, Qt::Orientation orientation = Qt::Vertical); + void regenerateGrid(); + inline int internalGridRowCount() const { return grossRoundUp(rowCount()); } + inline int internalGridColumnCount() const { return grossRoundUp(columnCount()); } + void setItemAt(int row, int column, QGridLayoutItem *item); + void insertOrRemoveRows(int row, int delta, Qt::Orientation orientation = Qt::Vertical); + void fillRowData(QGridLayoutRowData *rowData, + const qreal *colPositions, const qreal *colSizes, + Qt::Orientation orientation, + const QAbstractLayoutStyleInfo *styleInfo) const; + void ensureEffectiveFirstAndLastRows() const; + void ensureColumnAndRowData(QGridLayoutRowData *rowData, QGridLayoutBox *totalBox, + const qreal *colPositions, const qreal *colSizes, + Qt::Orientation orientation, + const QAbstractLayoutStyleInfo *styleInfo) const; + + void ensureGeometries(const QSizeF &size, const QAbstractLayoutStyleInfo *styleInfo) const; +protected: + QList<QGridLayoutItem *> q_items; +private: + // User input + QVector<QGridLayoutItem *> q_grid; + QLayoutParameter<qreal> q_defaultSpacings[NOrientations]; + QGridLayoutRowInfo q_infos[NOrientations]; + Qt::LayoutDirection m_visualDirection; + Qt::Alignment m_defaultAlignment; + + // Lazily computed from the above user input + mutable int q_cachedEffectiveFirstRows[NOrientations]; + mutable int q_cachedEffectiveLastRows[NOrientations]; + mutable quint8 q_cachedConstraintOrientation : 3; + + // Layout item input + mutable QGridLayoutRowData q_columnData; + mutable QGridLayoutRowData q_rowData; + mutable QGridLayoutBox q_totalBoxes[NOrientations]; + + // Output + mutable QSizeF q_cachedSize; + mutable bool q_totalBoxesValid; + mutable bool q_sizeHintValid[NOrientations]; + mutable QVector<qreal> q_xx; + mutable QVector<qreal> q_yy; + mutable QVector<qreal> q_widths; + mutable QVector<qreal> q_heights; + mutable QVector<qreal> q_descents; + + friend class QGridLayoutItem; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/gui/util/qlayoutpolicy.cpp b/src/gui/util/qlayoutpolicy.cpp new file mode 100644 index 0000000000..9a154768eb --- /dev/null +++ b/src/gui/util/qlayoutpolicy.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Layouts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlayoutpolicy_p.h" +#include <QtCore/qdebug.h> +#include <QtCore/qdatastream.h> + +QT_BEGIN_NAMESPACE + +void QLayoutPolicy::setControlType(ControlType type) +{ + /* + The control type is a flag type, with values 0x1, 0x2, 0x4, 0x8, 0x10, + etc. In memory, we pack it onto the available bits (CTSize) in + setControlType(), and unpack it here. + + Example: + + 0x00000001 maps to 0 + 0x00000002 maps to 1 + 0x00000004 maps to 2 + 0x00000008 maps to 3 + etc. + */ + + int i = 0; + while (true) { + if (type & (0x1 << i)) { + bits.ctype = i; + return; + } + ++i; + } +} + +QLayoutPolicy::ControlType QLayoutPolicy::controlType() const +{ + return QLayoutPolicy::ControlType(1 << bits.ctype); +} + +#ifndef QT_NO_DATASTREAM + +/*! + \relates QLayoutPolicy + + Writes the size \a policy to the data stream \a stream. + + \sa{Serializing Qt Data Types}{Format of the QDataStream operators} +*/ +QDataStream &operator<<(QDataStream &stream, const QLayoutPolicy &policy) +{ + // The order here is for historical reasons. (compatibility with Qt4) + quint32 data = (policy.bits.horPolicy | // [0, 3] + policy.bits.verPolicy << 4 | // [4, 7] + policy.bits.hfw << 8 | // [8] + policy.bits.ctype << 9 | // [9, 13] + policy.bits.wfh << 14 | // [14] + //policy.bits.padding << 15 | // [15] + policy.bits.verStretch << 16 | // [16, 23] + policy.bits.horStretch << 24); // [24, 31] + return stream << data; +} + +#define VALUE_OF_BITS(data, bitstart, bitcount) ((data >> bitstart) & ((1 << bitcount) -1)) + +/*! + \relates QLayoutPolicy + + Reads the size \a policy from the data stream \a stream. + + \sa{Serializing Qt Data Types}{Format of the QDataStream operators} +*/ +QDataStream &operator>>(QDataStream &stream, QLayoutPolicy &policy) +{ + quint32 data; + stream >> data; + policy.bits.horPolicy = VALUE_OF_BITS(data, 0, 4); + policy.bits.verPolicy = VALUE_OF_BITS(data, 4, 4); + policy.bits.hfw = VALUE_OF_BITS(data, 8, 1); + policy.bits.ctype = VALUE_OF_BITS(data, 9, 5); + policy.bits.wfh = VALUE_OF_BITS(data, 14, 1); + policy.bits.padding = 0; + policy.bits.verStretch = VALUE_OF_BITS(data, 16, 8); + policy.bits.horStretch = VALUE_OF_BITS(data, 24, 8); + return stream; +} +#endif // QT_NO_DATASTREAM + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const QLayoutPolicy &p) +{ + dbg.nospace() << "QLayoutPolicy(horizontalPolicy = " << p.horizontalPolicy() + << ", verticalPolicy = " << p.verticalPolicy() << ')'; + return dbg.space(); +} +#endif + +QT_END_NAMESPACE diff --git a/src/gui/util/qlayoutpolicy_p.h b/src/gui/util/qlayoutpolicy_p.h new file mode 100644 index 0000000000..664afef1a4 --- /dev/null +++ b/src/gui/util/qlayoutpolicy_p.h @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Layouts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLAYOUTPOLICY_H +#define QLAYOUTPOLICY_H + +#include <QtCore/qobject.h> +#include <QtCore/qnamespace.h> + +#ifndef QT_NO_DATASTREAM +# include <QtCore/qdatastream.h> +#endif + +QT_BEGIN_NAMESPACE + + +class QVariant; + +class Q_GUI_EXPORT QLayoutPolicy +{ + Q_ENUMS(Policy) + +public: + enum PolicyFlag { + GrowFlag = 1, + ExpandFlag = 2, + ShrinkFlag = 4, + IgnoreFlag = 8 + }; + + enum Policy { + Fixed = 0, + Minimum = GrowFlag, + Maximum = ShrinkFlag, + Preferred = GrowFlag | ShrinkFlag, + MinimumExpanding = GrowFlag | ExpandFlag, + Expanding = GrowFlag | ShrinkFlag | ExpandFlag, + Ignored = ShrinkFlag | GrowFlag | IgnoreFlag + }; + + enum ControlType { + DefaultType = 0x00000001, + ButtonBox = 0x00000002, + CheckBox = 0x00000004, + ComboBox = 0x00000008, + Frame = 0x00000010, + GroupBox = 0x00000020, + Label = 0x00000040, + Line = 0x00000080, + LineEdit = 0x00000100, + PushButton = 0x00000200, + RadioButton = 0x00000400, + Slider = 0x00000800, + SpinBox = 0x00001000, + TabWidget = 0x00002000, + ToolButton = 0x00004000 + }; + Q_DECLARE_FLAGS(ControlTypes, ControlType) + + QLayoutPolicy() : data(0) { } + + QLayoutPolicy(Policy horizontal, Policy vertical, ControlType type = DefaultType) + : data(0) { + bits.horPolicy = horizontal; + bits.verPolicy = vertical; + setControlType(type); + } + Policy horizontalPolicy() const { return static_cast<Policy>(bits.horPolicy); } + Policy verticalPolicy() const { return static_cast<Policy>(bits.verPolicy); } + ControlType controlType() const; + + void setHorizontalPolicy(Policy d) { bits.horPolicy = d; } + void setVerticalPolicy(Policy d) { bits.verPolicy = d; } + void setControlType(ControlType type); + + Qt::Orientations expandingDirections() const { + Qt::Orientations result; + if (verticalPolicy() & ExpandFlag) + result |= Qt::Vertical; + if (horizontalPolicy() & ExpandFlag) + result |= Qt::Horizontal; + return result; + } + + void setHeightForWidth(bool b) { bits.hfw = b; } + bool hasHeightForWidth() const { return bits.hfw; } + void setWidthForHeight(bool b) { bits.wfh = b; } + bool hasWidthForHeight() const { return bits.wfh; } + + bool operator==(const QLayoutPolicy& s) const { return data == s.data; } + bool operator!=(const QLayoutPolicy& s) const { return data != s.data; } + + int horizontalStretch() const { return static_cast<int>(bits.horStretch); } + int verticalStretch() const { return static_cast<int>(bits.verStretch); } + void setHorizontalStretch(int stretchFactor) { bits.horStretch = static_cast<quint32>(qBound(0, stretchFactor, 255)); } + void setVerticalStretch(int stretchFactor) { bits.verStretch = static_cast<quint32>(qBound(0, stretchFactor, 255)); } + + void transpose(); + + +private: +#ifndef QT_NO_DATASTREAM + friend QDataStream &operator<<(QDataStream &, const QLayoutPolicy &); + friend QDataStream &operator>>(QDataStream &, QLayoutPolicy &); +#endif + QLayoutPolicy(int i) : data(i) { } + + union { + struct { + quint32 horStretch : 8; + quint32 verStretch : 8; + quint32 horPolicy : 4; + quint32 verPolicy : 4; + quint32 ctype : 5; + quint32 hfw : 1; + quint32 wfh : 1; + quint32 padding : 1; // feel free to use + } bits; + quint32 data; + }; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QLayoutPolicy::ControlTypes) + +#ifndef QT_NO_DATASTREAM +QDataStream &operator<<(QDataStream &, const QLayoutPolicy &); +QDataStream &operator>>(QDataStream &, QLayoutPolicy &); +#endif + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const QLayoutPolicy &); +#endif + +inline void QLayoutPolicy::transpose() { + Policy hData = horizontalPolicy(); + Policy vData = verticalPolicy(); + int hStretch = horizontalStretch(); + int vStretch = verticalStretch(); + setHorizontalPolicy(vData); + setVerticalPolicy(hData); + setHorizontalStretch(vStretch); + setVerticalStretch(hStretch); +} + +QT_END_NAMESPACE + +#endif // QLAYOUTPOLICY_H diff --git a/src/gui/util/qvalidator.cpp b/src/gui/util/qvalidator.cpp index ed3b3b6dd6..dbb8575397 100644 --- a/src/gui/util/qvalidator.cpp +++ b/src/gui/util/qvalidator.cpp @@ -401,7 +401,7 @@ static qlonglong pow10(int exp) QValidator::State QIntValidator::validate(QString & input, int&) const { QByteArray buff; - if (!locale().d->validateChars(input, QLocalePrivate::IntegerMode, &buff)) { + if (!locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, &buff)) { return Invalid; } @@ -418,7 +418,7 @@ QValidator::State QIntValidator::validate(QString & input, int&) const return Intermediate; bool ok, overflow; - qlonglong entered = QLocalePrivate::bytearrayToLongLong(buff.constData(), 10, &ok, &overflow); + qlonglong entered = QLocaleData::bytearrayToLongLong(buff.constData(), 10, &ok, &overflow); if (overflow || !ok) return Invalid; @@ -440,11 +440,11 @@ QValidator::State QIntValidator::validate(QString & input, int&) const void QIntValidator::fixup(QString &input) const { QByteArray buff; - if (!locale().d->validateChars(input, QLocalePrivate::IntegerMode, &buff)) { + if (!locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, &buff)) { return; } bool ok, overflow; - qlonglong entered = QLocalePrivate::bytearrayToLongLong(buff.constData(), 10, &ok, &overflow); + qlonglong entered = QLocaleData::bytearrayToLongLong(buff.constData(), 10, &ok, &overflow); if (ok && !overflow) input = locale().toString(entered); } @@ -532,7 +532,7 @@ public: QDoubleValidator::Notation notation; - QValidator::State validateWithLocale(QString & input, QLocalePrivate::NumberMode numMode, const QLocale &locale) const; + QValidator::State validateWithLocale(QString & input, QLocaleData::NumberMode numMode, const QLocale &locale) const; }; @@ -639,24 +639,24 @@ QValidator::State QDoubleValidator::validate(QString & input, int &) const { Q_D(const QDoubleValidator); - QLocalePrivate::NumberMode numMode = QLocalePrivate::DoubleStandardMode; + QLocaleData::NumberMode numMode = QLocaleData::DoubleStandardMode; switch (d->notation) { case StandardNotation: - numMode = QLocalePrivate::DoubleStandardMode; + numMode = QLocaleData::DoubleStandardMode; break; case ScientificNotation: - numMode = QLocalePrivate::DoubleScientificMode; + numMode = QLocaleData::DoubleScientificMode; break; } return d->validateWithLocale(input, numMode, locale()); } -QValidator::State QDoubleValidatorPrivate::validateWithLocale(QString &input, QLocalePrivate::NumberMode numMode, const QLocale &locale) const +QValidator::State QDoubleValidatorPrivate::validateWithLocale(QString &input, QLocaleData::NumberMode numMode, const QLocale &locale) const { Q_Q(const QDoubleValidator); QByteArray buff; - if (!locale.d->validateChars(input, numMode, &buff, q->dec)) + if (!locale.d->m_data->validateChars(input, numMode, &buff, q->dec)) return QValidator::Invalid; if (buff.isEmpty()) @@ -669,7 +669,7 @@ QValidator::State QDoubleValidatorPrivate::validateWithLocale(QString &input, QL return QValidator::Invalid; bool ok, overflow; - double i = QLocalePrivate::bytearrayToDouble(buff.constData(), &ok, &overflow); + double i = QLocaleData::bytearrayToDouble(buff.constData(), &ok, &overflow); if (overflow) return QValidator::Invalid; if (!ok) diff --git a/src/gui/util/util.pri b/src/gui/util/util.pri index dfb221667e..79c83599b9 100644 --- a/src/gui/util/util.pri +++ b/src/gui/util/util.pri @@ -3,8 +3,14 @@ HEADERS += \ util/qdesktopservices.h \ util/qhexstring_p.h \ - util/qvalidator.h + util/qvalidator.h \ + util/qgridlayoutengine_p.h \ + util/qabstractlayoutstyleinfo_p.h \ + util/qlayoutpolicy_p.h SOURCES += \ util/qdesktopservices.cpp \ - util/qvalidator.cpp + util/qvalidator.cpp \ + util/qgridlayoutengine.cpp \ + util/qabstractlayoutstyleinfo.cpp \ + util/qlayoutpolicy.cpp |