summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQt Continuous Integration System <qt-info@nokia.com>2010-08-17 04:51:29 (GMT)
committerQt Continuous Integration System <qt-info@nokia.com>2010-08-17 04:51:29 (GMT)
commit95502f28e3ef5ca8512a13d304988d6d0cf30524 (patch)
tree4947497562ace7c7ea79dc145f6d340487eb49b3
parent50eefbaad10c217eeff5ac0d4b3581176e88e492 (diff)
parent6da59aa96e2ccb4ab494147ceb4fb6f7a129a366 (diff)
downloadQt-95502f28e3ef5ca8512a13d304988d6d0cf30524.zip
Qt-95502f28e3ef5ca8512a13d304988d6d0cf30524.tar.gz
Qt-95502f28e3ef5ca8512a13d304988d6d0cf30524.tar.bz2
Merge branch '4.7' of scm.dev.nokia.troll.no:qt/oslo-staging-2 into 4.7-integration
* '4.7' of scm.dev.nokia.troll.no:qt/oslo-staging-2: Keyboard navigation regression in QTreeView Implement the general blending of ARGB32_pm with SSSE3 QtDeclarative debugging: Add an option not to stream the properties of an object.
-rw-r--r--src/declarative/debugger/qdeclarativedebug.cpp4
-rw-r--r--src/declarative/qml/qdeclarativeenginedebug.cpp16
-rw-r--r--src/declarative/qml/qdeclarativeenginedebug_p.h2
-rw-r--r--src/gui/itemviews/qabstractitemview.cpp8
-rw-r--r--src/gui/painting/painting.pri1
-rw-r--r--src/gui/painting/qdrawhelper.cpp11
-rw-r--r--src/gui/painting/qdrawhelper_ssse3.cpp263
-rw-r--r--tests/auto/qtreeview/tst_qtreeview.cpp125
-rw-r--r--tests/benchmarks/gui/image/blendbench/main.cpp43
9 files changed, 463 insertions, 10 deletions
diff --git a/src/declarative/debugger/qdeclarativedebug.cpp b/src/declarative/debugger/qdeclarativedebug.cpp
index b950aef..154df51 100644
--- a/src/declarative/debugger/qdeclarativedebug.cpp
+++ b/src/declarative/debugger/qdeclarativedebug.cpp
@@ -507,7 +507,7 @@ QDeclarativeDebugObjectQuery *QDeclarativeEngineDebug::queryObject(const QDeclar
QByteArray message;
QDataStream ds(&message, QIODevice::WriteOnly);
ds << QByteArray("FETCH_OBJECT") << queryId << object.debugId()
- << false;
+ << false << true;
d->client->sendMessage(message);
} else {
query->m_state = QDeclarativeDebugQuery::Error;
@@ -530,7 +530,7 @@ QDeclarativeDebugObjectQuery *QDeclarativeEngineDebug::queryObjectRecursive(cons
QByteArray message;
QDataStream ds(&message, QIODevice::WriteOnly);
ds << QByteArray("FETCH_OBJECT") << queryId << object.debugId()
- << true;
+ << true << true;
d->client->sendMessage(message);
} else {
query->m_state = QDeclarativeDebugQuery::Error;
diff --git a/src/declarative/qml/qdeclarativeenginedebug.cpp b/src/declarative/qml/qdeclarativeenginedebug.cpp
index 1837366..ed98e3c 100644
--- a/src/declarative/qml/qdeclarativeenginedebug.cpp
+++ b/src/declarative/qml/qdeclarativeenginedebug.cpp
@@ -182,7 +182,7 @@ QVariant QDeclarativeEngineDebugServer::valueContents(const QVariant &value) con
}
void QDeclarativeEngineDebugServer::buildObjectDump(QDataStream &message,
- QObject *object, bool recur)
+ QObject *object, bool recur, bool dumpProperties)
{
message << objectData(object);
@@ -209,6 +209,8 @@ void QDeclarativeEngineDebugServer::buildObjectDump(QDataStream &message,
continue;
QDeclarativeBoundSignal *signal = QDeclarativeBoundSignal::cast(child);
if (signal) {
+ if (!dumpProperties)
+ continue;
QDeclarativeObjectProperty prop;
prop.type = QDeclarativeObjectProperty::SignalProperty;
prop.hasNotifySignal = false;
@@ -229,12 +231,17 @@ void QDeclarativeEngineDebugServer::buildObjectDump(QDataStream &message,
fakeProperties << prop;
} else {
if (recur)
- buildObjectDump(message, child, recur);
+ buildObjectDump(message, child, recur, dumpProperties);
else
message << objectData(child);
}
}
+ if (!dumpProperties) {
+ message << 0;
+ return;
+ }
+
message << (object->metaObject()->propertyCount() + fakeProperties.count());
for (int ii = 0; ii < object->metaObject()->propertyCount(); ++ii)
@@ -372,8 +379,9 @@ void QDeclarativeEngineDebugServer::messageReceived(const QByteArray &message)
int queryId;
int objectId;
bool recurse;
+ bool dumpProperties = true;
- ds >> queryId >> objectId >> recurse;
+ ds >> queryId >> objectId >> recurse >> dumpProperties;
QObject *object = QDeclarativeDebugService::objectForId(objectId);
@@ -382,7 +390,7 @@ void QDeclarativeEngineDebugServer::messageReceived(const QByteArray &message)
rs << QByteArray("FETCH_OBJECT_R") << queryId;
if (object)
- buildObjectDump(rs, object, recurse);
+ buildObjectDump(rs, object, recurse, dumpProperties);
sendMessage(reply);
} else if (type == "WATCH_OBJECT") {
diff --git a/src/declarative/qml/qdeclarativeenginedebug_p.h b/src/declarative/qml/qdeclarativeenginedebug_p.h
index ea35b40..aa450f3 100644
--- a/src/declarative/qml/qdeclarativeenginedebug_p.h
+++ b/src/declarative/qml/qdeclarativeenginedebug_p.h
@@ -103,7 +103,7 @@ private Q_SLOTS:
private:
void buildObjectList(QDataStream &, QDeclarativeContext *);
- void buildObjectDump(QDataStream &, QObject *, bool);
+ void buildObjectDump(QDataStream &, QObject *, bool, bool);
QDeclarativeObjectData objectData(QObject *);
QDeclarativeObjectProperty propertyData(QObject *, int);
QVariant valueContents(const QVariant &defaultValue) const;
diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp
index 97499f3..4ffd284 100644
--- a/src/gui/itemviews/qabstractitemview.cpp
+++ b/src/gui/itemviews/qabstractitemview.cpp
@@ -2270,9 +2270,11 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event)
} else {
d->selectionModel->setCurrentIndex(newCurrent, command);
d->pressedPosition = visualRect(newCurrent).center() + d->offset();
- // We copy the same behaviour as for mousePressEvent().
- QRect rect(d->pressedPosition - d->offset(), QSize(1, 1));
- setSelection(rect, command);
+ if (newCurrent.isValid()) {
+ // We copy the same behaviour as for mousePressEvent().
+ QRect rect(d->pressedPosition - d->offset(), QSize(1, 1));
+ setSelection(rect, command);
+ }
}
event->accept();
return;
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri
index dfa4a48..793d380 100644
--- a/src/gui/painting/painting.pri
+++ b/src/gui/painting/painting.pri
@@ -212,6 +212,7 @@ if(mmx|3dnow|sse|sse2|iwmmxt) {
SSE3DNOW_SOURCES += painting/qdrawhelper_sse3dnow.cpp
SSE_SOURCES += painting/qdrawhelper_sse.cpp
SSE2_SOURCES += painting/qdrawhelper_sse2.cpp
+ SSSE3_SOURCES += painting/qdrawhelper_ssse3.cpp
IWMMXT_SOURCES += painting/qdrawhelper_iwmmxt.cpp
}
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 1ff3d7b..276da93 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -7840,6 +7840,17 @@ void qInitDrawhelperAsm()
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 defined(QT_HAVE_SSSE3)
+ if (features & SSSE3) {
+ extern void qt_blend_argb32_on_argb32_ssse3(uchar *destPixels, int dbpl,
+ const uchar *srcPixels, int sbpl,
+ int w, int h,
+ int const_alpha);
+ 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;
+ }
+#endif // QT_HAVE_SSSE3
} else
#endif
{
diff --git a/src/gui/painting/qdrawhelper_ssse3.cpp b/src/gui/painting/qdrawhelper_ssse3.cpp
new file mode 100644
index 0000000..bc4a7eb8
--- /dev/null
+++ b/src/gui/painting/qdrawhelper_ssse3.cpp
@@ -0,0 +1,263 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifdef QT_HAVE_SSSE3
+
+#include <private/qsimd_p.h>
+#include <private/qdrawhelper_x86_p.h>
+#include <private/qdrawingprimitive_sse2_p.h>
+
+QT_BEGIN_NAMESPACE
+
+inline static void blend_pixel(quint32 &dst, const quint32 src)
+{
+ if (src >= 0xff000000)
+ dst = src;
+ else if (src != 0)
+ dst = src + BYTE_MUL(dst, qAlpha(~src));
+}
+
+
+/* The instruction palignr uses direct arguments, so we have to generate the code fo the different
+ shift (4, 8, 12). Checking the alignment inside the loop is unfortunatelly way too slow.
+ */
+#define BLENDING_LOOP(palignrOffset, length)\
+ for (; x < length-3; x += 4) { \
+ const __m128i srcVectorLastLoaded = _mm_load_si128((__m128i *)&src[x - minusOffsetToAlignSrcOn16Bytes + 4]);\
+ const __m128i srcVector = _mm_alignr_epi8(srcVectorLastLoaded, srcVectorPrevLoaded, palignrOffset); \
+ const __m128i srcVectorAlpha = _mm_and_si128(srcVector, alphaMask); \
+ if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, alphaMask)) == 0xffff) { \
+ _mm_store_si128((__m128i *)&dst[x], srcVector); \
+ } else if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, nullVector)) != 0xffff) { \
+ __m128i alphaChannel = _mm_shuffle_epi8(srcVector, alphaShuffleMask); \
+ alphaChannel = _mm_sub_epi16(one, alphaChannel); \
+ const __m128i dstVector = _mm_load_si128((__m128i *)&dst[x]); \
+ __m128i destMultipliedByOneMinusAlpha; \
+ BYTE_MUL_SSE2(destMultipliedByOneMinusAlpha, dstVector, alphaChannel, colorMask, half); \
+ const __m128i result = _mm_add_epi8(srcVector, destMultipliedByOneMinusAlpha); \
+ _mm_store_si128((__m128i *)&dst[x], result); \
+ } \
+ srcVectorPrevLoaded = srcVectorLastLoaded;\
+ }
+
+
+#define BLEND_SOURCE_OVER_ARGB32_FIRST_ROW_SSSE3(dst, src, length, nullVector, half, one, colorMask, alphaMask) { \
+ int x = 0; \
+\
+ /* First, get dst aligned. */ \
+ const int offsetToAlignOn16Bytes = (4 - ((reinterpret_cast<quintptr>(dst) >> 2) & 0x3)) & 0x3;\
+ const int prologLength = qMin(length, offsetToAlignOn16Bytes);\
+\
+ for (; x < prologLength; ++x) {\
+ blend_pixel(dst[x], src[x]); \
+ } \
+\
+ const int minusOffsetToAlignSrcOn16Bytes = (reinterpret_cast<quintptr>(&(src[x])) >> 2) & 0x3;\
+\
+ if (!minusOffsetToAlignSrcOn16Bytes) {\
+ /* src is aligned, usual algorithm but with aligned operations.\
+ See the SSE2 version for more documentation on the algorithm itself. */\
+ const __m128i alphaShuffleMask = _mm_set_epi8(0xff,15,0xff,15,0xff,11,0xff,11,0xff,7,0xff,7,0xff,3,0xff,3);\
+ for (; x < length-3; x += 4) { \
+ const __m128i srcVector = _mm_load_si128((__m128i *)&src[x]); \
+ const __m128i srcVectorAlpha = _mm_and_si128(srcVector, alphaMask); \
+ if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, alphaMask)) == 0xffff) { \
+ _mm_store_si128((__m128i *)&dst[x], srcVector); \
+ } else if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, nullVector)) != 0xffff) { \
+ __m128i alphaChannel = _mm_shuffle_epi8(srcVector, alphaShuffleMask); \
+ alphaChannel = _mm_sub_epi16(one, alphaChannel); \
+ const __m128i dstVector = _mm_load_si128((__m128i *)&dst[x]); \
+ __m128i destMultipliedByOneMinusAlpha; \
+ BYTE_MUL_SSE2(destMultipliedByOneMinusAlpha, dstVector, alphaChannel, colorMask, half); \
+ const __m128i result = _mm_add_epi8(srcVector, destMultipliedByOneMinusAlpha); \
+ _mm_store_si128((__m128i *)&dst[x], result); \
+ } \
+ } /* end for() */\
+ } else if ((length - x) >= 8) {\
+ /* We are at the first line, so "x - minusOffsetToAlignSrcOn16Bytes" could go before src, and\
+ generate an invalid access. */\
+\
+ /* We use two vectors to extract the src: prevLoaded for the first pixels, lastLoaded for the current pixels. */\
+ __m128i srcVectorPrevLoaded;\
+ if (minusOffsetToAlignSrcOn16Bytes <= prologLength) {\
+ srcVectorPrevLoaded = _mm_load_si128((__m128i *)&src[x - minusOffsetToAlignSrcOn16Bytes]);\
+ } else {\
+ quint32 temp[4] Q_DECL_ALIGN(16);\
+ switch (prologLength) {\
+ case 3:\
+ temp[1] = src[x - 3];\
+ case 2:\
+ temp[2] = src[x - 2];\
+ case 1:\
+ temp[3] = src[x - 1];\
+ default:\
+ break;\
+ }\
+ srcVectorPrevLoaded = _mm_load_si128((__m128i *)temp);\
+ }\
+ const int palignrOffset = minusOffsetToAlignSrcOn16Bytes << 2;\
+\
+ const __m128i alphaShuffleMask = _mm_set_epi8(0xff,15,0xff,15,0xff,11,0xff,11,0xff,7,0xff,7,0xff,3,0xff,3);\
+ switch (palignrOffset) {\
+ case 4:\
+ BLENDING_LOOP(4, length)\
+ break;\
+ case 8:\
+ BLENDING_LOOP(8, length)\
+ break;\
+ case 12:\
+ BLENDING_LOOP(12, length)\
+ break;\
+ }\
+ }\
+ for (; x < length; ++x) \
+ blend_pixel(dst[x], src[x]); \
+}
+
+// Basically blend src over dst with the const alpha defined as constAlphaVector.
+// nullVector, half, one, colorMask are constant accross the whole image/texture, and should be defined as:
+//const __m128i nullVector = _mm_set1_epi32(0);
+//const __m128i half = _mm_set1_epi16(0x80);
+//const __m128i one = _mm_set1_epi16(0xff);
+//const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+//const __m128i alphaMask = _mm_set1_epi32(0xff000000);
+//
+// The computation being done is:
+// result = s + d * (1-alpha)
+// with shortcuts if fully opaque or fully transparent.
+#define BLEND_SOURCE_OVER_ARGB32_MAIN_SSSE3(dst, src, length, nullVector, half, one, colorMask, alphaMask) { \
+ int x = 0; \
+\
+ /* First, get dst aligned. */ \
+ ALIGNMENT_PROLOGUE_16BYTES(dst, x, length) { \
+ blend_pixel(dst[x], src[x]); \
+ } \
+\
+ const int minusOffsetToAlignSrcOn16Bytes = (reinterpret_cast<quintptr>(&(src[x])) >> 2) & 0x3;\
+\
+ if (!minusOffsetToAlignSrcOn16Bytes) {\
+ /* src is aligned, usual algorithm but with aligned operations.\
+ See the SSE2 version for more documentation on the algorithm itself. */\
+ const __m128i alphaShuffleMask = _mm_set_epi8(0xff,15,0xff,15,0xff,11,0xff,11,0xff,7,0xff,7,0xff,3,0xff,3);\
+ for (; x < length-3; x += 4) { \
+ const __m128i srcVector = _mm_load_si128((__m128i *)&src[x]); \
+ const __m128i srcVectorAlpha = _mm_and_si128(srcVector, alphaMask); \
+ if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, alphaMask)) == 0xffff) { \
+ _mm_store_si128((__m128i *)&dst[x], srcVector); \
+ } else if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, nullVector)) != 0xffff) { \
+ __m128i alphaChannel = _mm_shuffle_epi8(srcVector, alphaShuffleMask); \
+ alphaChannel = _mm_sub_epi16(one, alphaChannel); \
+ const __m128i dstVector = _mm_load_si128((__m128i *)&dst[x]); \
+ __m128i destMultipliedByOneMinusAlpha; \
+ BYTE_MUL_SSE2(destMultipliedByOneMinusAlpha, dstVector, alphaChannel, colorMask, half); \
+ const __m128i result = _mm_add_epi8(srcVector, destMultipliedByOneMinusAlpha); \
+ _mm_store_si128((__m128i *)&dst[x], result); \
+ } \
+ } /* end for() */\
+ } else if ((length - x) >= 8) {\
+ /* We use two vectors to extract the src: prevLoaded for the first pixels, lastLoaded for the current pixels. */\
+ __m128i srcVectorPrevLoaded = _mm_load_si128((__m128i *)&src[x - minusOffsetToAlignSrcOn16Bytes]);\
+ const int palignrOffset = minusOffsetToAlignSrcOn16Bytes << 2;\
+\
+ const __m128i alphaShuffleMask = _mm_set_epi8(0xff,15,0xff,15,0xff,11,0xff,11,0xff,7,0xff,7,0xff,3,0xff,3);\
+ switch (palignrOffset) {\
+ case 4:\
+ BLENDING_LOOP(4, length)\
+ break;\
+ case 8:\
+ BLENDING_LOOP(8, length)\
+ break;\
+ case 12:\
+ BLENDING_LOOP(12, length)\
+ break;\
+ }\
+ }\
+ for (; x < length; ++x) \
+ blend_pixel(dst[x], src[x]); \
+}
+
+void qt_blend_argb32_on_argb32_ssse3(uchar *destPixels, int dbpl,
+ const uchar *srcPixels, int sbpl,
+ int w, int h,
+ int const_alpha)
+{
+ const quint32 *src = (const quint32 *) srcPixels;
+ quint32 *dst = (quint32 *) destPixels;
+ if (const_alpha == 256) {
+ const __m128i alphaMask = _mm_set1_epi32(0xff000000);
+ const __m128i nullVector = _mm_setzero_si128();
+ const __m128i half = _mm_set1_epi16(0x80);
+ const __m128i one = _mm_set1_epi16(0xff);
+ const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+
+ // We have to unrol the first row in order to deal with the load on unaligned data
+ // prior to the src pointer.
+ BLEND_SOURCE_OVER_ARGB32_FIRST_ROW_SSSE3(dst, src, w, nullVector, half, one, colorMask, alphaMask);
+ dst = (quint32 *)(((uchar *) dst) + dbpl);
+ src = (const quint32 *)(((const uchar *) src) + sbpl);
+
+ for (int y = 1; y < h; ++y) {
+ BLEND_SOURCE_OVER_ARGB32_MAIN_SSSE3(dst, src, w, nullVector, half, one, colorMask, alphaMask);
+ dst = (quint32 *)(((uchar *) dst) + dbpl);
+ src = (const quint32 *)(((const uchar *) src) + sbpl);
+ }
+ } else if (const_alpha != 0) {
+ // dest = (s + d * sia) * ca + d * cia
+ // = s * ca + d * (sia * ca + cia)
+ // = s * ca + d * (1 - sa*ca)
+ const_alpha = (const_alpha * 255) >> 8;
+ const __m128i nullVector = _mm_setzero_si128();
+ const __m128i half = _mm_set1_epi16(0x80);
+ const __m128i one = _mm_set1_epi16(0xff);
+ const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+ const __m128i constAlphaVector = _mm_set1_epi16(const_alpha);
+ for (int y = 0; y < h; ++y) {
+ BLEND_SOURCE_OVER_ARGB32_WITH_CONST_ALPHA_SSE2(dst, src, w, nullVector, half, one, colorMask, constAlphaVector)
+ dst = (quint32 *)(((uchar *) dst) + dbpl);
+ src = (const quint32 *)(((const uchar *) src) + sbpl);
+ }
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_HAVE_SSSE3
diff --git a/tests/auto/qtreeview/tst_qtreeview.cpp b/tests/auto/qtreeview/tst_qtreeview.cpp
index 75a4c62..7e2e800 100644
--- a/tests/auto/qtreeview/tst_qtreeview.cpp
+++ b/tests/auto/qtreeview/tst_qtreeview.cpp
@@ -239,6 +239,7 @@ private slots:
void doubleClickedWithSpans();
void taskQTBUG_6450_selectAllWith1stColumnHidden();
void taskQTBUG_9216_setSizeAndUniformRowHeightsWrongRepaint();
+ void taskQTBUG_11466_keyboardNavigationRegression();
};
class QtTestModel: public QAbstractItemModel
@@ -3785,5 +3786,129 @@ void tst_QTreeView::keyboardNavigationWithDisabled()
QCOMPARE(view.currentIndex(), model.index(6, 0));
}
+class Model_11466 : public QAbstractItemModel
+{
+ Q_OBJECT
+public:
+ Model_11466(QObject *parent) :
+ m_block(false)
+ {
+ // set up the model to have two top level items and a few others
+ m_selectionModel = new QItemSelectionModel(this, this); // owned by this
+
+ connect(m_selectionModel, SIGNAL(currentChanged(const QModelIndex &,const QModelIndex &)),
+ this, SLOT(slotCurrentChanged(const QModelIndex &,const QModelIndex &)));
+ };
+
+ int rowCount(const QModelIndex &parent) const
+ {
+ if (parent.isValid())
+ return (parent.internalId() == 0) ? 4 : 0;
+ return 2; // two top level items
+ }
+
+ int columnCount(const QModelIndex &parent) const
+ {
+ return 2;
+ }
+
+ QVariant data(const QModelIndex &index, int role) const
+ {
+ if (role == Qt::DisplayRole && index.isValid()) {
+ qint64 parentRowPlusOne = index.internalId();
+ QString str;
+ QTextStream stream(&str);
+ if (parentRowPlusOne > 0)
+ stream << parentRowPlusOne << " -> " << index.row() << " : " << index.column();
+ else
+ stream << index.row() << " : " << index.column();
+ return QVariant(str);
+ }
+ return QVariant();
+ }
+
+ QModelIndex parent(const QModelIndex &index) const
+ {
+ if (index.isValid()) {
+ qint64 parentRowPlusOne = index.internalId();
+ if (parentRowPlusOne > 0) {
+ int row = static_cast<int>(parentRowPlusOne - 1);
+ return createIndex(row, 0, (quint32)0);
+ }
+ }
+ return QModelIndex();
+ }
+
+ void bindView(QTreeView *view)
+ {
+ // sets the view to this model with a shared selection model
+ QItemSelectionModel *oldModel = view->selectionModel();
+ if (oldModel != m_selectionModel)
+ delete oldModel;
+ view->setModel(this); // this creates a new selection model for the view, but we dont want it either ...
+ oldModel = view->selectionModel();
+ view->setSelectionModel(m_selectionModel);
+ delete oldModel;
+ }
+
+ QModelIndex index(int row, int column, const QModelIndex &parent) const
+ {
+ return createIndex(row, column, parent.isValid() ? (quint32)(parent.row() + 1) : (quint32)0);
+ }
+
+public slots:
+ void slotCurrentChanged(const QModelIndex &current,const QModelIndex &)
+ {
+ if (m_block)
+ return;
+
+ if (current.isValid()) {
+ int selectedRow = current.row();
+ quint32 parentRowPlusOne = static_cast<quint32>(current.internalId());
+
+ for (int i = 0; i < 2; ++i) {
+ // announce the removal of all non top level items
+ beginRemoveRows(createIndex(i, 0, 0), 0, 3);
+ // nothing to actually do for the removal
+ endRemoveRows();
+
+ // put them back in again
+ beginInsertRows(createIndex(i, 0, 0), 0, 3);
+ // nothing to actually do for the insertion
+ endInsertRows();
+ }
+ // reselect the current item ...
+ QModelIndex selectedIndex = createIndex(selectedRow, 0, parentRowPlusOne);
+
+ m_block = true; // recursion block
+ m_selectionModel->select(selectedIndex, QItemSelectionModel::ClearAndSelect|QItemSelectionModel::Current|QItemSelectionModel::Rows);
+ m_selectionModel->setCurrentIndex(selectedIndex, QItemSelectionModel::NoUpdate);
+ m_block = false;
+ } else {
+ m_selectionModel->clear();
+ }
+ }
+
+private:
+ bool m_block;
+ QItemSelectionModel *m_selectionModel;
+};
+
+void tst_QTreeView::taskQTBUG_11466_keyboardNavigationRegression()
+{
+ QTreeView treeView;
+ treeView.setSelectionBehavior(QAbstractItemView::SelectRows);
+ treeView.setSelectionMode(QAbstractItemView::SingleSelection);
+ Model_11466 model(&treeView);
+ model.bindView(&treeView);
+ treeView.expandAll();
+ treeView.show();
+ QTest::qWaitForWindowShown(&treeView);
+
+ QTest::keyPress(treeView.viewport(), Qt::Key_Down);
+ QTest::qWait(10);
+ QTRY_COMPARE(treeView.currentIndex(), treeView.selectionModel()->selection().indexes().first());
+}
+
QTEST_MAIN(tst_QTreeView)
#include "tst_qtreeview.moc"
diff --git a/tests/benchmarks/gui/image/blendbench/main.cpp b/tests/benchmarks/gui/image/blendbench/main.cpp
index f53654b..d420d6c 100644
--- a/tests/benchmarks/gui/image/blendbench/main.cpp
+++ b/tests/benchmarks/gui/image/blendbench/main.cpp
@@ -106,6 +106,9 @@ private slots:
void blendBenchAlpha_data();
void blendBenchAlpha();
+
+ void unalignedBlendArgb32_data();
+ void unalignedBlendArgb32();
};
void BlendBench::blendBench_data()
@@ -179,6 +182,46 @@ void BlendBench::blendBenchAlpha()
}
}
+void BlendBench::unalignedBlendArgb32_data()
+{
+ // The performance of blending can depend of the alignment of the data
+ // on 16 bytes. Some SIMD instruction set have significantly better
+ // memory access when the memory is aligned on 16 bytes boundary.
+
+ // offset in 32 bits words
+ QTest::addColumn<int>("offset");
+ QTest::newRow("aligned on 16 bytes") << 0;
+ QTest::newRow("unaligned by 4 bytes") << 1;
+ QTest::newRow("unaligned by 8 bytes") << 2;
+ QTest::newRow("unaligned by 12 bytes") << 3;
+}
+
+void BlendBench::unalignedBlendArgb32()
+{
+ const int dimension = 1024;
+
+ // We use dst aligned by design. We don't want to test all the combination of alignemnt for src and dst.
+ // Moreover, it make sense for us to align dst in the implementation because it is accessed more often.
+ uchar *dstMemory = static_cast<uchar*>(qMallocAligned((dimension * dimension * sizeof(quint32)), 16));
+ QImage destination(dstMemory, dimension, dimension, QImage::Format_ARGB32_Premultiplied);
+ destination.fill(0x12345678); // avoid special cases of alpha
+
+ uchar *srcMemory = static_cast<uchar*>(qMallocAligned((dimension * dimension * sizeof(quint32)) + 16, 16));
+ QFETCH(int, offset);
+ srcMemory += (offset * sizeof(quint32));
+
+ QImage src(srcMemory, dimension, dimension, QImage::Format_ARGB32_Premultiplied);
+ src.fill(0x87654321);
+
+ QPainter painter(&destination);
+ QBENCHMARK {
+ painter.drawImage(QPoint(), src);
+ }
+
+ qFreeAligned(srcMemory);
+ qFreeAligned(dstMemory);
+}
+
QTEST_MAIN(BlendBench)
#include "main.moc"