summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/accessible/qaccessiblecache.cpp2
-rw-r--r--src/gui/doc/snippets/image/supportedformat.cpp8
-rw-r--r--src/gui/doc/src/coordsys.qdoc2
-rw-r--r--src/gui/doc/src/paintsystem.qdoc4
-rw-r--r--src/gui/image/image.pri15
-rw-r--r--src/gui/image/qbmphandler.cpp107
-rw-r--r--src/gui/image/qimage.cpp2485
-rw-r--r--src/gui/image/qimage.h15
-rw-r--r--src/gui/image/qimage_compat.cpp (renamed from src/gui/painting/qdrawhelper_avx.cpp)42
-rw-r--r--src/gui/image/qimage_conversions.cpp2183
-rw-r--r--src/gui/image/qimage_neon.cpp4
-rw-r--r--src/gui/image/qimage_p.h13
-rw-r--r--src/gui/image/qimagereader.cpp29
-rw-r--r--src/gui/image/qjpeghandler.cpp10
-rw-r--r--src/gui/image/qpixmap.cpp22
-rw-r--r--src/gui/image/qpixmap.h7
-rw-r--r--src/gui/image/qpixmap_raster.cpp11
-rw-r--r--src/gui/image/qpixmap_raster_p.h1
-rw-r--r--src/gui/image/qplatformpixmap.h9
-rw-r--r--src/gui/image/qpnghandler.pri2
-rw-r--r--src/gui/image/qxbmhandler.cpp24
-rw-r--r--src/gui/kernel/qdrag.cpp6
-rw-r--r--src/gui/kernel/qevent.cpp18
-rw-r--r--src/gui/kernel/qevent.h2
-rw-r--r--src/gui/kernel/qguiapplication.cpp59
-rw-r--r--src/gui/kernel/qguiapplication_p.h6
-rw-r--r--src/gui/kernel/qguivariant.cpp2
-rw-r--r--src/gui/kernel/qkeysequence.cpp2
-rw-r--r--src/gui/kernel/qplatformintegration.cpp2
-rw-r--r--src/gui/kernel/qplatformintegration.h3
-rw-r--r--src/gui/kernel/qplatformtheme.cpp65
-rw-r--r--src/gui/kernel/qplatformtheme.h6
-rw-r--r--src/gui/kernel/qplatformwindow.cpp15
-rw-r--r--src/gui/kernel/qshortcutmap.cpp2
-rw-r--r--src/gui/kernel/qstylehints.cpp117
-rw-r--r--src/gui/kernel/qstylehints.h8
-rw-r--r--src/gui/kernel/qsurfaceformat.cpp124
-rw-r--r--src/gui/kernel/qsurfaceformat.h12
-rw-r--r--src/gui/kernel/qwindowsysteminterface.cpp20
-rw-r--r--src/gui/kernel/qwindowsysteminterface.h16
-rw-r--r--src/gui/kernel/qwindowsysteminterface_p.h11
-rw-r--r--src/gui/math3d/qvector2d.h82
-rw-r--r--src/gui/math3d/qvector3d.h86
-rw-r--r--src/gui/math3d/qvector4d.h90
-rw-r--r--src/gui/opengl/qopenglframebufferobject.cpp140
-rw-r--r--src/gui/opengl/qopenglframebufferobject.h1
-rw-r--r--src/gui/opengl/qopenglframebufferobject_p.h1
-rw-r--r--src/gui/painting/painting.pri13
-rw-r--r--src/gui/painting/qbrush.cpp81
-rw-r--r--src/gui/painting/qdrawhelper.cpp433
-rw-r--r--src/gui/painting/qdrawhelper_neon.cpp6
-rw-r--r--src/gui/painting/qdrawhelper_neon_p.h4
-rw-r--r--src/gui/painting/qdrawhelper_p.h22
-rw-r--r--src/gui/painting/qdrawhelper_sse2.cpp8
-rw-r--r--src/gui/painting/qdrawhelper_x86_p.h27
-rw-r--r--src/gui/painting/qdrawingprimitive_sse2_p.h4
-rw-r--r--src/gui/painting/qpaintengine.cpp1
-rw-r--r--src/gui/painting/qpaintengine.h1
-rw-r--r--src/gui/painting/qpainterpath.cpp24
-rw-r--r--src/gui/painting/qpainterpath.h2
-rw-r--r--src/gui/painting/qpen.cpp4
-rw-r--r--src/gui/text/qfontengine_ft.cpp4
-rw-r--r--src/gui/text/qtextcursor.cpp1
-rw-r--r--src/gui/text/qtextdocument.cpp94
-rw-r--r--src/gui/text/qtextdocument.h8
-rw-r--r--src/gui/text/qtextdocument_p.h1
-rw-r--r--src/gui/text/qtextengine.cpp16
-rw-r--r--src/gui/text/qtextengine_p.h1
-rw-r--r--src/gui/text/qtextformat.cpp22
-rw-r--r--src/gui/text/qtextformat.h1
-rw-r--r--src/gui/text/qtextformat_p.h6
-rw-r--r--src/gui/util/qabstractlayoutstyleinfo.cpp (renamed from src/gui/image/qimage_avx.cpp)24
-rw-r--r--src/gui/util/qabstractlayoutstyleinfo_p.h97
-rw-r--r--src/gui/util/qgridlayoutengine.cpp1636
-rw-r--r--src/gui/util/qgridlayoutengine_p.h473
-rw-r--r--src/gui/util/qlayoutpolicy.cpp136
-rw-r--r--src/gui/util/qlayoutpolicy_p.h185
-rw-r--r--src/gui/util/util.pri10
78 files changed, 6254 insertions, 2982 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/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 70fe7b783f..d6037fb2d6 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;
}
}
@@ -1898,2100 +1861,6 @@ 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_PM,
- 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;
- }
- }
-}
-
/*!
Returns a copy of the image in the given \a format.
@@ -4008,8 +1877,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,15 +1895,13 @@ 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);
}
-
-
static inline int pixel_distance(QRgb p1, QRgb p2) {
int r1 = qRed(p1);
int g1 = qGreen(p1);
@@ -4131,7 +1999,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();
@@ -4810,6 +2678,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 +2687,69 @@ 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;
+ for (int y = h-1; y >= 0; y--) {
+ quint8* a0 = (quint8*)(data + y*bpl);
+ // Swap bytes
+ quint8* a = a0+dxs;
+ while (a >= a0) {
+ *a = qt_get_bitflip_array()[*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 +2771,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 +2853,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 +2909,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 +2922,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 +2940,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++;
+ }
+ }
+ 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++;
}
- store(q, buffer, x, l);
- x += l;
}
+ break;
+ default:
+ rgbSwapped_generic(d->width, d->height, this, this, &qPixelLayouts[d->format]);
+ break;
}
- return res;
}
/*!
@@ -6433,10 +4420,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..e8f195c18e 100644
--- a/src/gui/image/qimage.h
+++ b/src/gui/image/qimage.h
@@ -245,8 +245,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 +309,10 @@ 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();
private:
friend class QWSOnScreenSurface;
diff --git a/src/gui/painting/qdrawhelper_avx.cpp b/src/gui/image/qimage_compat.cpp
index 7da6ce6a20..9886d392fb 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,24 @@
**
****************************************************************************/
-#include <private/qsimd_p.h>
-
-#ifdef QT_COMPILER_SUPPORTS_AVX
-#define QDRAWHELPER_AVX
-
-#ifndef __AVX__
-#error "AVX not enabled in this file, cannot proceed"
+#ifdef QIMAGE_H
+# error "This file cannot be used with precompiled headers"
#endif
+#define QT_COMPILING_QIMAGE_COMPAT_CPP
-#define qt_blend_argb32_on_argb32_ssse3 qt_blend_argb32_on_argb32_avx
-#include "qdrawhelper_ssse3.cpp"
+#include "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
+QT_BEGIN_NAMESPACE
-#include "qdrawhelper_sse2.cpp"
+// These implementations must be the same as the inline versions in qimage.h
+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..9b79f4ccc0
--- /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() // called from QPixmap code
+{
+ 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 = PREMUL(*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(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.
+//
+
+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_PM,
+ 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/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_raster.cpp b/src/gui/image/qpixmap_raster.cpp
index f9a017c281..37259adcd2 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)
@@ -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/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..a474d70190 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -274,6 +274,24 @@ 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);
+}
/*!
\fn QPointF QMouseEvent::localPos() const
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index d22e423248..b6b1e0c76b 100644
--- a/src/gui/kernel/qevent.h
+++ b/src/gui/kernel/qevent.h
@@ -135,6 +135,8 @@ public:
QT_DEPRECATED inline QPointF posF() const { return l; }
#endif
+ Qt::MouseEventSource source() const;
+
protected:
QPointF l, w, s;
Qt::MouseButton b;
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 0711a37edd..a753e6018c 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 <QtDebug>
#ifndef QT_NO_ACCESSIBILITY
#include "qaccessible.h"
@@ -887,11 +888,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);
@@ -918,15 +922,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) {
@@ -937,7 +947,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;
@@ -997,6 +1007,8 @@ void QGuiApplicationPrivate::createPlatformIntegration()
platformName = platformNameEnv;
}
+ QString platformThemeName = QString::fromLocal8Bit(qgetenv("QT_QPA_PLATFORMTHEME"));
+
// Get command line params
int j = argc ? 1 : 0;
@@ -1012,6 +1024,9 @@ void QGuiApplicationPrivate::createPlatformIntegration()
} 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]);
@@ -1025,7 +1040,7 @@ void QGuiApplicationPrivate::createPlatformIntegration()
argc = j;
}
- init_platform(QLatin1String(platformName), platformPluginPath, argc, argv);
+ init_platform(QLatin1String(platformName), platformPluginPath, platformThemeName, argc, argv);
}
@@ -1571,6 +1586,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())
@@ -1625,6 +1641,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
QMouseEvent dblClickEvent(doubleClickType, localPoint, localPoint, globalPoint,
button, buttons, e->modifiers);
dblClickEvent.setTimestamp(e->timestamp);
+ setMouseEventSource(&dblClickEvent, e->source);
QGuiApplication::sendSpontaneousEvent(window, &dblClickEvent);
}
}
@@ -2041,7 +2058,8 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
synthIt->pos,
synthIt->screenPos,
Qt::NoButton,
- e->modifiers);
+ e->modifiers,
+ Qt::MouseEventSynthesizedByQt);
fake.synthetic = true;
processMouseEvent(&fake);
}
@@ -3146,9 +3164,16 @@ void QGuiApplicationPrivate::_q_updateFocusObject(QObject *object)
emit q->focusObjectChanged(object);
}
+enum {
+ MouseCapsMask = 0xFF,
+ MouseSourceMaskDst = 0xFF00,
+ MouseSourceMaskSrc = MouseCapsMask,
+ MouseSourceShift = 8,
+};
+
int QGuiApplicationPrivate::mouseEventCaps(QMouseEvent *event)
{
- return event->caps;
+ return event->caps & MouseCapsMask;
}
QVector2D QGuiApplicationPrivate::mouseEventVelocity(QMouseEvent *event)
@@ -3158,16 +3183,26 @@ 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)
{
- event->caps = other->caps;
- event->velocity = other->velocity;
+ 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;
+}
#include "moc_qguiapplication.cpp"
diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h
index 218036033e..95ee8eb295 100644
--- a/src/gui/kernel/qguiapplication_p.h
+++ b/src/gui/kernel/qguiapplication_p.h
@@ -171,7 +171,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;
@@ -268,7 +268,9 @@ 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);
const QDrawHelperGammaTables *gammaTables();
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/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/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..e3676b1be8 100644
--- a/src/gui/kernel/qplatformintegration.h
+++ b/src/gui/kernel/qplatformintegration.h
@@ -148,7 +148,8 @@ public:
SynthesizeMouseFromTouchEvents,
PasswordMaskCharacter,
SetFocusOnTouchRelease,
- ShowIsMaximized
+ ShowIsMaximized,
+ MousePressAndHoldInterval
};
virtual QVariant styleHint(StyleHint hint) const;
diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp
index 3548ec0199..90edf4c49f 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 QMessageDialogOptions::StandardButton
+ */
+
+QString QPlatformTheme::standardButtonText(int button) const
+{
+ return QPlatformTheme::defaultStandardButtonText(button);
+}
+
+QString QPlatformTheme::defaultStandardButtonText(int button)
+{
+ switch (button) {
+ case QMessageDialogOptions::Ok:
+ return QCoreApplication::translate("QPlatformTheme", "OK");
+ case QMessageDialogOptions::Save:
+ return QCoreApplication::translate("QPlatformTheme", "Save");
+ case QMessageDialogOptions::SaveAll:
+ return QCoreApplication::translate("QPlatformTheme", "Save All");
+ case QMessageDialogOptions::Open:
+ return QCoreApplication::translate("QPlatformTheme", "Open");
+ case QMessageDialogOptions::Yes:
+ return QCoreApplication::translate("QPlatformTheme", "&Yes");
+ case QMessageDialogOptions::YesToAll:
+ return QCoreApplication::translate("QPlatformTheme", "Yes to &All");
+ case QMessageDialogOptions::No:
+ return QCoreApplication::translate("QPlatformTheme", "&No");
+ case QMessageDialogOptions::NoToAll:
+ return QCoreApplication::translate("QPlatformTheme", "N&o to All");
+ case QMessageDialogOptions::Abort:
+ return QCoreApplication::translate("QPlatformTheme", "Abort");
+ case QMessageDialogOptions::Retry:
+ return QCoreApplication::translate("QPlatformTheme", "Retry");
+ case QMessageDialogOptions::Ignore:
+ return QCoreApplication::translate("QPlatformTheme", "Ignore");
+ case QMessageDialogOptions::Close:
+ return QCoreApplication::translate("QPlatformTheme", "Close");
+ case QMessageDialogOptions::Cancel:
+ return QCoreApplication::translate("QPlatformTheme", "Cancel");
+ case QMessageDialogOptions::Discard:
+ return QCoreApplication::translate("QPlatformTheme", "Discard");
+ case QMessageDialogOptions::Help:
+ return QCoreApplication::translate("QPlatformTheme", "Help");
+ case QMessageDialogOptions::Apply:
+ return QCoreApplication::translate("QPlatformTheme", "Apply");
+ case QMessageDialogOptions::Reset:
+ return QCoreApplication::translate("QPlatformTheme", "Reset");
+ case QMessageDialogOptions::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..fe29627c5a 100644
--- a/src/gui/kernel/qplatformwindow.cpp
+++ b/src/gui/kernel/qplatformwindow.cpp
@@ -521,14 +521,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/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/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/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/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp
index c06ba40b47..a1c4cf2a29 100644
--- a/src/gui/opengl/qopenglframebufferobject.cpp
+++ b/src/gui/opengl/qopenglframebufferobject.cpp
@@ -446,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);
@@ -492,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);
@@ -506,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();
@@ -905,12 +916,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)
@@ -920,7 +935,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;
@@ -938,7 +956,7 @@ bool QOpenGLFramebufferObject::bind()
bool QOpenGLFramebufferObject::release()
{
if (!isValid())
- return false;
+ return false;
QOpenGLContext *current = QOpenGLContext::currentContext();
if (!current)
@@ -967,6 +985,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
{
@@ -975,6 +995,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..a431618f6d 100644
--- a/src/gui/opengl/qopenglframebufferobject.h
+++ b/src/gui/opengl/qopenglframebufferobject.h
@@ -97,6 +97,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..1c7d2e1e5d 100644
--- a/src/gui/opengl/qopenglframebufferobject_p.h
+++ b/src/gui/opengl/qopenglframebufferobject_p.h
@@ -116,6 +116,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/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/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index d3e5b645c4..39193dd093 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>
@@ -102,7 +109,7 @@ static const uint *QT_FASTCALL convertPassThrough(uint *, const uint *src, int,
return src;
}
-static const uint *QT_FASTCALL convertRGB16ToARGB32PM(uint *buffer, const uint *src, int count,
+static const uint *QT_FASTCALL convertRGB16ToRGB32(uint *buffer, const uint *src, int count,
const QPixelLayout *, const QRgb *)
{
for (int i = 0; i < count; ++i)
@@ -118,6 +125,22 @@ static const uint *QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, const uint
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] = PREMUL(RGBA2ARGB(src[i]));
+ return buffer;
+}
+
static const uint *QT_FASTCALL convertToRGB32(uint *buffer, const uint *src, int count,
const QPixelLayout *layout, const QRgb *)
{
@@ -206,6 +229,14 @@ static const uint *QT_FASTCALL convertToARGB32PM(uint *buffer, const uint *src,
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 *)
{
@@ -222,6 +253,38 @@ static const uint *QT_FASTCALL convertARGB32FromARGB32PM(uint *buffer, const uin
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(INV_PREMUL(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 | INV_PREMUL(src[i]));
+ return buffer;
+}
+
static const uint *QT_FASTCALL convertFromARGB32PM(uint *buffer, const uint *src, int count,
const QPixelLayout *layout, const QRgb *)
{
@@ -242,7 +305,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] = INV_PREMUL(src[i]);
src = buffer;
}
for (int i = 0; i < count; ++i) {
@@ -255,13 +318,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,12 +336,10 @@ 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;
}
@@ -392,30 +454,32 @@ 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
+ { 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
#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
};
@@ -630,7 +694,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;
@@ -5071,13 +5140,13 @@ 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;
+ int px = px16 >> 16;
+ int py = py16 >> 16;
int y_offset = py * scanline_offset;
Q_ASSERT(px >= 0 && px < image_width);
@@ -5086,6 +5155,14 @@ 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;
+ if (px16 < 0) px16 += image_width << 16;
+ if (py16 < 0) py16 += image_height << 16;
++b;
}
func(target, buffer, l, coverage);
@@ -6140,110 +6217,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 +6294,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 +6311,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 +6370,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 +6410,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..3c945338a6 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)
@@ -691,12 +691,16 @@ 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))))
+static Q_ALWAYS_INLINE uint INV_PREMUL(uint p) {
+ const uint alpha = qAlpha(p);
+ 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 = 0x00ff00ffU / alpha;
+ return qRgba((qRed(p)*invAlpha)>>16, (qGreen(p)*invAlpha)>>16, (qBlue(p)*invAlpha)>>16, alpha);
+}
struct quint24 {
quint24(uint value);
@@ -726,7 +730,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 +1034,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..d11ba0b26c 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) {
@@ -285,7 +285,7 @@ void qt_memfill32_sse2(quint32 *dest, quint32 value, int count)
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 +397,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 +413,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/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/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/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp
index 42cf15ee3b..22d2585898 100644
--- a/src/gui/text/qfontengine_ft.cpp
+++ b/src/gui/text/qfontengine_ft.cpp
@@ -716,7 +716,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));
@@ -1187,7 +1187,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;
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/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index 06c5e24920..109b7e600f 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
@@ -2536,7 +2537,8 @@ static inline bool nextCharJoins(const QString &string, int pos)
++pos;
if (pos == string.length())
return false;
- return string.at(pos).joining() != QChar::OtherJoining;
+ // ### U+A872 has joining type L
+ return string.at(pos) == QChar(0xA872) || string.at(pos).joining() != QChar::OtherJoining;
}
static inline bool prevCharJoins(const QString &string, int pos)
@@ -2551,13 +2553,9 @@ static inline bool prevCharJoins(const QString &string, int pos)
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,
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index fb71ab40b8..f2e16cf546 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -449,7 +449,6 @@ public:
typedef QList<ItemDecoration> ItemDecorationList;
- QTextEngine(LayoutData *data);
QTextEngine();
QTextEngine(const QString &str, const QFont &f);
~QTextEngine();
diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp
index 2389427da0..641a2ceb8a 100644
--- a/src/gui/text/qtextformat.cpp
+++ b/src/gui/text/qtextformat.cpp
@@ -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
@@ -3376,19 +3385,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..c04ac3876b 100644
--- a/src/gui/text/qtextformat.h
+++ b/src/gui/text/qtextformat.h
@@ -295,6 +295,7 @@ public:
void merge(const QTextFormat &other);
inline bool isValid() const { return type() != InvalidFormat; }
+ inline bool isEmpty() const { return propertyCount() == 0; }
int type() const;
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/image/qimage_avx.cpp b/src/gui/util/qabstractlayoutstyleinfo.cpp
index d04ec5b3de..4f7c635594 100644
--- a/src/gui/image/qimage_avx.cpp
+++ b/src/gui/util/qabstractlayoutstyleinfo.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2012 Intel Corporation
+** 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.
@@ -39,19 +39,15 @@
**
****************************************************************************/
-#include <private/qsimd_p.h>
+#include "qabstractlayoutstyleinfo_p.h"
-#ifdef QT_COMPILER_SUPPORTS_AVX
+QT_BEGIN_NAMESPACE
-#ifndef __AVX__
-#error "AVX not enabled in this file, cannot proceed"
-#endif
+bool QAbstractLayoutStyleInfo::hasChanged() const
+{
+ if (m_changed == Unknown)
+ m_changed = hasChangedCore() ? Changed : Unchanged;
+ return m_changed == Changed;
+}
-#define convert_ARGB_to_ARGB_PM_inplace_sse2 convert_ARGB_to_ARGB_PM_inplace_avx
-#include "qimage_sse2.cpp"
-
-#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/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..be38e92f21
--- /dev/null
+++ b/src/gui/util/qgridlayoutengine.cpp
@@ -0,0 +1,1636 @@
+/****************************************************************************
+**
+** 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
+{
+ QGridLayoutBox vBox = box(Qt::Vertical);
+ if (!(align & Qt::AlignBaseline) || vBox.q_minimumDescent < 0.0 || rowDescent < 0.0) {
+ qreal cellWidth = width;
+ 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;
+ default:
+ break;
+ }
+ return QRectF(x, y, width, height);
+ } else {
+ width = qMin(effectiveMaxSize(QSizeF(-1,-1)).width(), width);
+ qreal descent = vBox.q_minimumDescent;
+ qreal ascent = vBox.q_minimumSize - descent;
+ return QRectF(x, y + height - rowDescent - ascent, width, ascent + descent);
+ }
+}
+
+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)
+{
+ Q_ASSERT(spacing >= 0.0);
+ 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/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