summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@digia.com>2014-01-03 14:46:07 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-01-08 18:08:47 +0100
commitb28764c641e4fef19d5e800b7537439fb2054914 (patch)
treeec179914c4d94d59490c2a978dbae4b24f353cad
parentaf9910e450ae0374cb4d1479d416469c9f800b73 (diff)
Inplace versions of QImage rgbSwapped() and mirrored() for rvalue refs
Adds inplace version of QImage::rgbSwapped() and QImage::mirrored() that can be used on temporary QImage objects when supported by the compiler. [ChangeLog][QtGui][QImage]Rvalue qualified mirrored and rgbSwapped methods for inline conversions Change-Id: I4ffb658bf620dfc472d9db14c1aa70291c1fd842 Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
-rw-r--r--src/gui/image/image.pri3
-rw-r--r--src/gui/image/qimage.cpp338
-rw-r--r--src/gui/image/qimage.h15
-rw-r--r--src/gui/image/qimage_compat.cpp62
-rw-r--r--tests/auto/gui/image/qimage/qimage.pro1
-rw-r--r--tests/auto/gui/image/qimage/tst_qimage.cpp251
6 files changed, 560 insertions, 110 deletions
diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri
index 5b9bc4b56f..fce7c6f4ec 100644
--- a/src/gui/image/image.pri
+++ b/src/gui/image/image.pri
@@ -54,6 +54,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 \
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index 61d524841d..27068020cd 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -1105,8 +1105,7 @@ void QImage::detach()
if (d->ref.load() != 1 || d->ro_data)
*this = copy();
- if (d)
- ++d->detach_no;
+ ++d->detach_no;
}
}
@@ -4791,6 +4790,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.
@@ -4799,7 +4799,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 = bitflip[*a];
+ a--;
+ }
+ // Shift bits if unaligned
+ if (shift != 0) {
+ a = a0+dxs;
+ quint8 c = 0;
+ if (monolsb) {
+ while (a >= a0) {
+ quint8 nc = *a << shift;
+ *a = (*a >> (8-shift)) | c;
+ --a;
+ c = nc;
+ }
+ } else {
+ while (a >= a0) {
+ quint8 nc = *a >> shift;
+ *a = (*a << (8-shift)) | c;
+ --a;
+ c = nc;
+ }
+ }
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+QImage QImage::mirrored_helper(bool horizontal, bool vertical) const
{
if (!d)
return QImage();
@@ -4821,92 +4883,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.
@@ -4915,16 +4965,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:
@@ -4933,7 +5021,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:
@@ -4946,15 +5034,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);
@@ -4963,48 +5052,77 @@ QImage QImage::rgbSwapped() const
const ushort *p = (const ushort*)constScanLine(i);
const ushort *end = p + d->width;
while (p < end) {
- *q = ((*p << 11) & 0xf800) | ((*p >> 11) & 0x1f) | (*p & 0x07e0);
+ ushort c = *p;
+ *q = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
p++;
q++;
}
}
- return res;
+ break;
default:
+ res = QImage(d->width, d->height, d->format);
+ rgbSwapped_generic(d->width, d->height, this, &res, &qPixelLayouts[d->format]);
break;
}
+ return res;
+}
- res = QImage(d->width, d->height, d->format);
- QIMAGE_SANITYCHECK_MEMORY(res);
- const QPixelLayout *layout = &qPixelLayouts[d->format];
- Q_ASSERT(layout->redWidth == layout->blueWidth);
- FetchPixelsFunc fetch = qFetchPixels[layout->bpp];
- StorePixelsFunc store = qStorePixels[layout->bpp];
+/*!
+ \internal
+*/
+void QImage::rgbSwapped_inplace()
+{
+ if (isNull())
+ return;
- const uint redBlueMask = (1 << layout->redWidth) - 1;
- const uint alphaGreenMask = (((1 << layout->alphaWidth) - 1) << layout->alphaShift)
- | (((1 << layout->greenWidth) - 1) << layout->greenShift);
+ detach();
- const int buffer_size = 2048;
- uint buffer[buffer_size];
- for (int i = 0; i < d->height; ++i) {
- uchar *q = res.scanLine(i);
- const uchar *p = constScanLine(i);
- int x = 0;
- while (x < d->width) {
- int l = qMin(d->width - x, buffer_size);
- const uint *ptr = fetch(buffer, p, x, l);
- for (int j = 0; j < l; ++j) {
- uint red = (ptr[j] >> layout->redShift) & redBlueMask;
- uint blue = (ptr[j] >> layout->blueShift) & redBlueMask;
- buffer[j] = (ptr[j] & alphaGreenMask)
- | (red << layout->blueShift)
- | (blue << layout->redShift);
+ switch (d->format) {
+ case Format_Invalid:
+ case NImageFormats:
+ Q_ASSERT(false);
+ break;
+ case Format_Mono:
+ case Format_MonoLSB:
+ case Format_Indexed8:
+ for (int i = 0; i < d->colortable.size(); i++) {
+ QRgb c = d->colortable.at(i);
+ d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
+ }
+ break;
+ case Format_RGB32:
+ case Format_ARGB32:
+ case Format_ARGB32_Premultiplied:
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ case Format_RGBX8888:
+ case Format_RGBA8888:
+ case Format_RGBA8888_Premultiplied:
+#endif
+ for (int i = 0; i < d->height; i++) {
+ uint *p = (uint*)scanLine(i);
+ uint *end = p + d->width;
+ while (p < end) {
+ uint c = *p;
+ *p = ((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00);
+ p++;
}
- store(q, buffer, x, l);
- x += l;
}
+ break;
+ case Format_RGB16:
+ for (int i = 0; i < d->height; i++) {
+ ushort *p = (ushort*)scanLine(i);
+ ushort *end = p + d->width;
+ while (p < end) {
+ ushort c = *p;
+ *p = ((c << 11) & 0xf800) | ((c >> 11) & 0x1f) | (c & 0x07e0);
+ p++;
+ }
+ }
+ break;
+ default:
+ rgbSwapped_generic(d->width, d->height, this, this, &qPixelLayouts[d->format]);
+ break;
}
- return res;
}
/*!
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/image/qimage_compat.cpp b/src/gui/image/qimage_compat.cpp
new file mode 100644
index 0000000000..9886d392fb
--- /dev/null
+++ b/src/gui/image/qimage_compat.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifdef QIMAGE_H
+# error "This file cannot be used with precompiled headers"
+#endif
+#define QT_COMPILING_QIMAGE_COMPAT_CPP
+
+#include "qimage.h"
+
+QT_BEGIN_NAMESPACE
+
+// 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);
+}
+
+QImage QImage::rgbSwapped() const
+{
+ return rgbSwapped_helper();
+}
+
+QT_END_NAMESPACE
diff --git a/tests/auto/gui/image/qimage/qimage.pro b/tests/auto/gui/image/qimage/qimage.pro
index 467a59ec9f..117e34653d 100644
--- a/tests/auto/gui/image/qimage/qimage.pro
+++ b/tests/auto/gui/image/qimage/qimage.pro
@@ -4,5 +4,6 @@ TARGET = tst_qimage
SOURCES += tst_qimage.cpp
QT += core-private gui-private testlib
+contains(QT_CONFIG, c++11): CONFIG += c++11
TESTDATA += images/*
diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp
index 7fdb2f4cba..5016abff4f 100644
--- a/tests/auto/gui/image/qimage/tst_qimage.cpp
+++ b/tests/auto/gui/image/qimage/tst_qimage.cpp
@@ -149,6 +149,17 @@ private slots:
void rgbSwapped_data();
void rgbSwapped();
+ void mirrored_data();
+ void mirrored();
+
+ void inplaceRgbSwapped_data();
+ void inplaceRgbSwapped();
+
+ void inplaceMirrored_data();
+ void inplaceMirrored();
+
+ void inplaceDoubleConversion();
+
void deepCopyWhenPaintingActive();
void scaled_QTBUG19157();
@@ -2106,6 +2117,246 @@ void tst_QImage::rgbSwapped()
QCOMPARE(memcmp(image.constBits(), imageSwappedTwice.constBits(), image.byteCount()), 0);
}
+void tst_QImage::mirrored_data()
+{
+ QTest::addColumn<QImage::Format>("format");
+ QTest::addColumn<bool>("swap_vertical");
+ QTest::addColumn<bool>("swap_horizontal");
+
+ QTest::newRow("Format_RGB32, vertical") << QImage::Format_RGB32 << true << false;
+ QTest::newRow("Format_ARGB32, vertical") << QImage::Format_ARGB32 << true << false;
+ QTest::newRow("Format_ARGB32_Premultiplied, vertical") << QImage::Format_ARGB32_Premultiplied << true << false;
+ QTest::newRow("Format_RGB16, vertical") << QImage::Format_RGB16 << true << false;
+ QTest::newRow("Format_ARGB8565_Premultiplied, vertical") << QImage::Format_ARGB8565_Premultiplied << true << false;
+ QTest::newRow("Format_ARGB6666_Premultiplied, vertical") << QImage::Format_ARGB6666_Premultiplied << true << false;
+ QTest::newRow("Format_ARGB4444_Premultiplied, vertical") << QImage::Format_ARGB4444_Premultiplied << true << false;
+ QTest::newRow("Format_RGB666, vertical") << QImage::Format_RGB666 << true << false;
+ QTest::newRow("Format_RGB555, vertical") << QImage::Format_RGB555 << true << false;
+ QTest::newRow("Format_ARGB8555_Premultiplied, vertical") << QImage::Format_ARGB8555_Premultiplied << true << false;
+ QTest::newRow("Format_RGB888, vertical") << QImage::Format_RGB888 << true << false;
+ QTest::newRow("Format_RGB444, vertical") << QImage::Format_RGB444 << true << false;
+ QTest::newRow("Format_RGBX8888, vertical") << QImage::Format_RGBX8888 << true << false;
+ QTest::newRow("Format_RGBA8888_Premultiplied, vertical") << QImage::Format_RGBA8888_Premultiplied << true << false;
+ QTest::newRow("Format_Indexed8, vertical") << QImage::Format_Indexed8 << true << false;
+ QTest::newRow("Format_Mono, vertical") << QImage::Format_Mono << true << false;
+
+ QTest::newRow("Format_ARGB32_Premultiplied, horizontal") << QImage::Format_ARGB32_Premultiplied << false << true;
+ QTest::newRow("Format_RGB888, horizontal") << QImage::Format_RGB888 << false << true;
+ QTest::newRow("Format_RGB16, horizontal") << QImage::Format_RGB16 << false << true;
+ QTest::newRow("Format_Indexed8, horizontal") << QImage::Format_Indexed8 << false << true;
+ QTest::newRow("Format_Mono, horizontal") << QImage::Format_Mono << false << true;
+
+ QTest::newRow("Format_ARGB32_Premultiplied, horizontal+vertical") << QImage::Format_ARGB32_Premultiplied << true << true;
+ QTest::newRow("Format_RGB888, horizontal+vertical") << QImage::Format_RGB888 << true << true;
+ QTest::newRow("Format_RGB16, horizontal+vertical") << QImage::Format_RGB16 << true << true;
+ QTest::newRow("Format_Indexed8, horizontal+vertical") << QImage::Format_Indexed8 << true << true;
+ QTest::newRow("Format_Mono, horizontal+vertical") << QImage::Format_Mono << true << true;
+}
+
+void tst_QImage::mirrored()
+{
+ QFETCH(QImage::Format, format);
+ QFETCH(bool, swap_vertical);
+ QFETCH(bool, swap_horizontal);
+
+ QImage image(16, 16, format);
+
+ switch (format) {
+ case QImage::Format_Mono:
+ for (int i = 0; i < image.height(); ++i) {
+ ushort* scanLine = (ushort*)image.scanLine(i);
+ *scanLine = (i % 2) ? 0x5555U : 0xCCCCU;
+ }
+ break;
+ case QImage::Format_Indexed8:
+ for (int i = 0; i < image.height(); ++i) {
+ for (int j = 0; j < image.width(); ++j) {
+ image.setColor(i*16+j, qRgb(j*16, i*16, 0));
+ image.setPixel(j, i, i*16+j);
+ }
+ }
+ break;
+ default:
+ for (int i = 0; i < image.height(); ++i)
+ for (int j = 0; j < image.width(); ++j)
+ image.setPixel(j, i, qRgb(j*16, i*16, 0));
+ break;
+ }
+
+ QImage imageMirrored = image.mirrored(swap_horizontal, swap_vertical);
+
+ for (int i = 0; i < image.height(); ++i) {
+ int mirroredI = swap_vertical ? (image.height() - i - 1) : i;
+ for (int j = 0; j < image.width(); ++j) {
+ QRgb referenceColor = image.pixel(j, i);
+ int mirroredJ = swap_horizontal ? (image.width() - j - 1) : j;
+ QRgb mirroredColor = imageMirrored.pixel(mirroredJ, mirroredI);
+ QCOMPARE(mirroredColor, referenceColor);
+ }
+ }
+
+ QImage imageMirroredTwice = imageMirrored.mirrored(swap_horizontal, swap_vertical);
+
+ QCOMPARE(image, imageMirroredTwice);
+
+ if (format != QImage::Format_Mono)
+ QCOMPARE(memcmp(image.constBits(), imageMirroredTwice.constBits(), image.byteCount()), 0);
+ else {
+ for (int i = 0; i < image.height(); ++i)
+ for (int j = 0; j < image.width(); ++j)
+ QCOMPARE(image.pixel(j,i), imageMirroredTwice.pixel(j,i));
+ }
+}
+
+void tst_QImage::inplaceRgbSwapped_data()
+{
+ QTest::addColumn<QImage::Format>("format");
+
+ QTest::newRow("Format_ARGB32_Premultiplied") << QImage::Format_ARGB32_Premultiplied;
+ QTest::newRow("Format_RGBA8888") << QImage::Format_RGBA8888;
+ QTest::newRow("Format_RGB888") << QImage::Format_RGB888;
+ QTest::newRow("Format_RGB16") << QImage::Format_RGB16;
+ QTest::newRow("Format_Indexed8") << QImage::Format_Indexed8;
+}
+
+void tst_QImage::inplaceRgbSwapped()
+{
+#if defined(Q_COMPILER_REF_QUALIFIERS)
+ QFETCH(QImage::Format, format);
+
+ QImage image(64, 1, format);
+ image.fill(0);
+
+ QVector<QRgb> testColor(image.width());
+ for (int i = 0; i < image.width(); ++i)
+ testColor[i] = qRgb(i * 2, i * 3, 255 - i * 4);
+
+ if (format == QImage::Format_Indexed8) {
+ for (int i = 0; i < image.width(); ++i) {
+ image.setColor(i, testColor[i]);
+ image.setPixel(i, 0, i);
+ }
+ } else {
+ for (int i = 0; i < image.width(); ++i)
+ image.setPixel(i, 0, testColor[i]);
+ }
+
+ const uchar* orginalPtr = image.constScanLine(0);
+ QImage imageSwapped = std::move(image).rgbSwapped();
+
+ for (int i = 0; i < imageSwapped.width(); ++i) {
+ QRgb referenceColor = testColor[i];
+ QRgb swappedColor = imageSwapped.pixel(i, 0);
+ QCOMPARE(qRed(swappedColor) & 0xf8, qBlue(referenceColor) & 0xf8);
+ QCOMPARE(qGreen(swappedColor) & 0xf8, qGreen(referenceColor) & 0xf8);
+ QCOMPARE(qBlue(swappedColor) & 0xf8, qRed(referenceColor) & 0xf8);
+ }
+
+ QCOMPARE(imageSwapped.constScanLine(0), orginalPtr);
+#endif
+}
+
+
+void tst_QImage::inplaceMirrored_data()
+{
+ QTest::addColumn<QImage::Format>("format");
+ QTest::addColumn<bool>("swap_vertical");
+ QTest::addColumn<bool>("swap_horizontal");
+
+ QTest::newRow("Format_ARGB32, vertical") << QImage::Format_ARGB32 << true << false;
+ QTest::newRow("Format_RGB888, vertical") << QImage::Format_RGB888 << true << false;
+ QTest::newRow("Format_RGB16, vertical") << QImage::Format_RGB16 << true << false;
+ QTest::newRow("Format_Indexed8, vertical") << QImage::Format_Indexed8 << true << false;
+ QTest::newRow("Format_Mono, vertical") << QImage::Format_Mono << true << false;
+
+ QTest::newRow("Format_ARGB32, horizontal") << QImage::Format_ARGB32 << false << true;
+ QTest::newRow("Format_RGB888, horizontal") << QImage::Format_RGB888 << false << true;
+ QTest::newRow("Format_RGB16, horizontal") << QImage::Format_RGB16 << false << true;
+ QTest::newRow("Format_Indexed8, horizontal") << QImage::Format_Indexed8 << false << true;
+ QTest::newRow("Format_Mono, horizontal") << QImage::Format_Mono << false << true;
+
+ QTest::newRow("Format_ARGB32, horizontal+vertical") << QImage::Format_ARGB32 << true << true;
+ QTest::newRow("Format_RGB888, horizontal+vertical") << QImage::Format_RGB888 << true << true;
+ QTest::newRow("Format_RGB16, horizontal+vertical") << QImage::Format_RGB16 << true << true;
+ QTest::newRow("Format_Indexed8, horizontal+vertical") << QImage::Format_Indexed8 << true << true;
+ QTest::newRow("Format_Mono, horizontal+vertical") << QImage::Format_Mono << true << true;
+}
+
+void tst_QImage::inplaceMirrored()
+{
+#if defined(Q_COMPILER_REF_QUALIFIERS)
+ QFETCH(QImage::Format, format);
+ QFETCH(bool, swap_vertical);
+ QFETCH(bool, swap_horizontal);
+
+ QImage image(16, 16, format);
+
+ switch (format) {
+ case QImage::Format_Mono:
+ for (int i = 0; i < image.height(); ++i) {
+ ushort* scanLine = (ushort*)image.scanLine(i);
+ *scanLine = (i % 2) ? 0x0fffU : 0xf000U;
+ }
+ break;
+ case QImage::Format_Indexed8:
+ for (int i = 0; i < image.height(); ++i) {
+ for (int j = 0; j < image.width(); ++j) {
+ image.setColor(i*16+j, qRgb(j*16, i*16, 0));
+ image.setPixel(j, i, i*16+j);
+ }
+ }
+ break;
+ default:
+ for (int i = 0; i < image.height(); ++i)
+ for (int j = 0; j < image.width(); ++j)
+ image.setPixel(j, i, qRgb(j*16, i*16, 0));
+ }
+
+ const uchar* originalPtr = image.constScanLine(0);
+
+ QImage imageMirrored = std::move(image).mirrored(swap_horizontal, swap_vertical);
+ if (format != QImage::Format_Mono) {
+ for (int i = 0; i < imageMirrored.height(); ++i) {
+ int mirroredI = swap_vertical ? (imageMirrored.height() - i - 1) : i;
+ for (int j = 0; j < imageMirrored.width(); ++j) {
+ int mirroredJ = swap_horizontal ? (imageMirrored.width() - j - 1) : j;
+ QRgb mirroredColor = imageMirrored.pixel(mirroredJ, mirroredI);
+ QCOMPARE(qRed(mirroredColor) & 0xF8, j * 16);
+ QCOMPARE(qGreen(mirroredColor) & 0xF8, i * 16);
+ }
+ }
+ } else {
+ for (int i = 0; i < imageMirrored.height(); ++i) {
+ ushort* scanLine = (ushort*)imageMirrored.scanLine(i);
+ ushort expect;
+ if (swap_vertical && swap_horizontal)
+ expect = (i % 2) ? 0x000fU : 0xfff0U;
+ else if (swap_vertical)
+ expect = (i % 2) ? 0xf000U : 0x0fffU;
+ else
+ expect = (i % 2) ? 0xfff0U : 0x000fU;
+ QCOMPARE(*scanLine, expect);
+ }
+ }
+ QCOMPARE(imageMirrored.constScanLine(0), originalPtr);
+#endif
+}
+
+void tst_QImage::inplaceDoubleConversion()
+{
+#if defined(Q_COMPILER_REF_QUALIFIERS)
+ QImage image1(32, 32, QImage::Format_ARGB32);
+ QImage image2(32, 32, QImage::Format_ARGB32);
+ image1.fill(0);
+ image2.fill(0);
+ const uchar* originalPtr1 = image1.constScanLine(0);
+ const uchar* originalPtr2 = image2.constScanLine(0);
+
+ QCOMPARE(std::move(image1).rgbSwapped().mirrored().constScanLine(0), originalPtr1);
+ QCOMPARE(std::move(image2).mirrored().rgbSwapped().constScanLine(0), originalPtr2);
+#endif
+}
+
void tst_QImage::deepCopyWhenPaintingActive()
{
QImage image(64, 64, QImage::Format_ARGB32_Premultiplied);