From 66eec88591be2e8369e73dc5c86148cb4b09fad8 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 13 Dec 2010 17:20:12 +0100 Subject: clarify setStatus() behavior Reviewed-by: mariusSO --- src/corelib/io/qdatastream.cpp | 3 +++ src/corelib/io/qtextstream.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp index 58f0190..dffb3c6 100644 --- a/src/corelib/io/qdatastream.cpp +++ b/src/corelib/io/qdatastream.cpp @@ -495,6 +495,9 @@ void QDataStream::resetStatus() /*! Sets the status of the data stream to the \a status given. + Subsequent calls to setStatus() are ignored until resetStatus() + is called. + \sa Status status() resetStatus() */ void QDataStream::setStatus(Status status) diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index 6091ec0..f4731f9 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -1593,6 +1593,9 @@ void QTextStream::resetStatus() Sets the status of the text stream to the \a status given. + Subsequent calls to setStatus() are ignored until resetStatus() + is called. + \sa Status status() resetStatus() */ void QTextStream::setStatus(Status status) -- cgit v0.12 From ca062f6ed45acf83720faec8a211d9bf91705b2c Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 16 Dec 2010 14:17:22 +0100 Subject: don't report flush error when we didn't flush in the first place this went unnoticed, as the return value is ignored - so far. Reviewed-by: mariusSO --- src/corelib/io/qtextstream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index f4731f9..560766a 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -693,7 +693,7 @@ bool QTextStreamPrivate::flushWriteBuffer() // flush the file #ifndef QT_NO_QOBJECT QFile *file = qobject_cast(device); - bool flushed = file && file->flush(); + bool flushed = !file || file->flush(); #else bool flushed = true; #endif -- cgit v0.12 From 9233143bb25e33c07f73b7d35b0d6cbd14ef1686 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 13 Dec 2010 17:57:55 +0100 Subject: add write error handling to QDataStream add new status flag WriteFailed. use it in all write functions. Task-number: QTBUG-376 Reviewed-by: mariusSO --- src/corelib/io/qdatastream.cpp | 55 +++++++++++++++++++----------- src/corelib/io/qdatastream.h | 3 +- tests/auto/qdatastream/tst_qdatastream.cpp | 51 +++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 20 deletions(-) diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp index dffb3c6..52ee252 100644 --- a/src/corelib/io/qdatastream.cpp +++ b/src/corelib/io/qdatastream.cpp @@ -243,6 +243,11 @@ QT_BEGIN_NAMESPACE } #endif +#define CHECK_STREAM_WRITE_PRECOND(retVal) \ + CHECK_STREAM_PRECOND(retVal) \ + if (q_status != Ok) \ + return retVal; + enum { DefaultStreamVersion = QDataStream::Qt_4_6 }; @@ -995,8 +1000,9 @@ int QDataStream::readRawData(char *s, int len) QDataStream &QDataStream::operator<<(qint8 i) { - CHECK_STREAM_PRECOND(*this) - dev->putChar(i); + CHECK_STREAM_WRITE_PRECOND(*this) + if (!dev->putChar(i)) + q_status = WriteFailed; return *this; } @@ -1018,11 +1024,12 @@ QDataStream &QDataStream::operator<<(qint8 i) QDataStream &QDataStream::operator<<(qint16 i) { - CHECK_STREAM_PRECOND(*this) + CHECK_STREAM_WRITE_PRECOND(*this) if (!noswap) { i = qbswap(i); } - dev->write((char *)&i, sizeof(qint16)); + if (dev->write((char *)&i, sizeof(qint16)) != sizeof(qint16)) + q_status = WriteFailed; return *this; } @@ -1035,11 +1042,12 @@ QDataStream &QDataStream::operator<<(qint16 i) QDataStream &QDataStream::operator<<(qint32 i) { - CHECK_STREAM_PRECOND(*this) + CHECK_STREAM_WRITE_PRECOND(*this) if (!noswap) { i = qbswap(i); } - dev->write((char *)&i, sizeof(qint32)); + if (dev->write((char *)&i, sizeof(qint32)) != sizeof(qint32)) + q_status = WriteFailed; return *this; } @@ -1060,7 +1068,7 @@ QDataStream &QDataStream::operator<<(qint32 i) QDataStream &QDataStream::operator<<(qint64 i) { - CHECK_STREAM_PRECOND(*this) + CHECK_STREAM_WRITE_PRECOND(*this) if (version() < 6) { quint32 i1 = i & 0xffffffff; quint32 i2 = i >> 32; @@ -1069,7 +1077,8 @@ QDataStream &QDataStream::operator<<(qint64 i) if (!noswap) { i = qbswap(i); } - dev->write((char *)&i, sizeof(qint64)); + if (dev->write((char *)&i, sizeof(qint64)) != sizeof(qint64)) + q_status = WriteFailed; } return *this; } @@ -1089,8 +1098,9 @@ QDataStream &QDataStream::operator<<(qint64 i) QDataStream &QDataStream::operator<<(bool i) { - CHECK_STREAM_PRECOND(*this) - dev->putChar(qint8(i)); + CHECK_STREAM_WRITE_PRECOND(*this) + if (!dev->putChar(qint8(i))) + q_status = WriteFailed; return *this; } @@ -1111,7 +1121,7 @@ QDataStream &QDataStream::operator<<(float f) return *this; } - CHECK_STREAM_PRECOND(*this) + CHECK_STREAM_WRITE_PRECOND(*this) float g = f; // fixes float-on-stack problem if (!noswap) { union { @@ -1122,7 +1132,8 @@ QDataStream &QDataStream::operator<<(float f) x.val2 = qbswap(x.val2); g = x.val1; } - dev->write((char *)&g, sizeof(float)); + if (dev->write((char *)&g, sizeof(float)) != sizeof(float)) + q_status = WriteFailed; return *this; } @@ -1144,10 +1155,11 @@ QDataStream &QDataStream::operator<<(double f) return *this; } - CHECK_STREAM_PRECOND(*this) + CHECK_STREAM_WRITE_PRECOND(*this) #ifndef Q_DOUBLE_FORMAT if (noswap) { - dev->write((char *)&f, sizeof(double)); + if (dev->write((char *)&f, sizeof(double)) != sizeof(double)) + q_status = WriteFailed; } else { union { double val1; @@ -1155,7 +1167,8 @@ QDataStream &QDataStream::operator<<(double f) } x; x.val1 = f; x.val2 = qbswap(x.val2); - dev->write((char *)&x.val2, sizeof(double)); + if (dev->write((char *)&x.val2, sizeof(double)) != sizeof(double)) + q_status = WriteFailed; } #else union { @@ -1184,7 +1197,8 @@ QDataStream &QDataStream::operator<<(double f) b[Q_DF(1)] = *p++; b[Q_DF(0)] = *p; } - dev->write(b, 8); + if (dev->write(b, 8) != 8) + q_status = WriteFailed; #endif return *this; } @@ -1224,7 +1238,7 @@ QDataStream &QDataStream::operator<<(const char *s) QDataStream &QDataStream::writeBytes(const char *s, uint len) { - CHECK_STREAM_PRECOND(*this) + CHECK_STREAM_WRITE_PRECOND(*this) *this << (quint32)len; // write length specifier if (len) writeRawData(s, len); @@ -1242,8 +1256,11 @@ QDataStream &QDataStream::writeBytes(const char *s, uint len) int QDataStream::writeRawData(const char *s, int len) { - CHECK_STREAM_PRECOND(-1) - return dev->write(s, len); + CHECK_STREAM_WRITE_PRECOND(-1) + int ret = dev->write(s, len); + if (ret != len) + q_status = WriteFailed; + return ret; } /*! diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h index 774c4bc..05248ac 100644 --- a/src/corelib/io/qdatastream.h +++ b/src/corelib/io/qdatastream.h @@ -101,7 +101,8 @@ public: enum Status { Ok, ReadPastEnd, - ReadCorruptData + ReadCorruptData, + WriteFailed }; enum FloatingPointPrecision { diff --git a/tests/auto/qdatastream/tst_qdatastream.cpp b/tests/auto/qdatastream/tst_qdatastream.cpp index c03bc71..898fb84 100644 --- a/tests/auto/qdatastream/tst_qdatastream.cpp +++ b/tests/auto/qdatastream/tst_qdatastream.cpp @@ -168,6 +168,8 @@ private slots: void stream_atEnd_data(); void stream_atEnd(); + void stream_writeError(); + void stream_QByteArray2(); void setVersion_data(); @@ -2345,6 +2347,55 @@ void tst_QDataStream::stream_atEnd() } } +class FakeBuffer : public QBuffer +{ +protected: + qint64 writeData(const char *c, qint64 i) { return m_lock ? 0 : QBuffer::writeData(c, i); } +public: + FakeBuffer(bool locked = false) : m_lock(locked) {} + void setLocked(bool locked) { m_lock = locked; } +private: + bool m_lock; +}; + +#define TEST_WRITE_ERROR(op) \ + { \ + FakeBuffer fb(false); \ + QVERIFY(fb.open(QBuffer::ReadWrite)); \ + QDataStream fs(&fb); \ + fs.writeRawData("hello", 5); \ + /* first write some initial content */ \ + QCOMPARE(fs.status(), QDataStream::Ok); \ + QCOMPARE(fb.data(), QByteArray("hello")); \ + /* then test that writing can cause an error */ \ + fb.setLocked(true); \ + fs op; \ + QCOMPARE(fs.status(), QDataStream::WriteFailed); \ + QCOMPARE(fb.data(), QByteArray("hello")); \ + /* finally test that writing after an error doesn't change the stream any more */ \ + fb.setLocked(false); \ + fs op; \ + QCOMPARE(fs.status(), QDataStream::WriteFailed); \ + QCOMPARE(fb.data(), QByteArray("hello")); \ + } + +void tst_QDataStream::stream_writeError() +{ + TEST_WRITE_ERROR(<< true) + TEST_WRITE_ERROR(<< (qint8)1) + TEST_WRITE_ERROR(<< (quint8)1) + TEST_WRITE_ERROR(<< (qint16)1) + TEST_WRITE_ERROR(<< (quint16)1) + TEST_WRITE_ERROR(<< (qint32)1) + TEST_WRITE_ERROR(<< (quint32)1) + TEST_WRITE_ERROR(<< (qint64)1) + TEST_WRITE_ERROR(<< (quint64)1) + TEST_WRITE_ERROR(<< "hello") + TEST_WRITE_ERROR(<< (float)1.0) + TEST_WRITE_ERROR(<< (double)1.0) + TEST_WRITE_ERROR(.writeRawData("test", 4)) +} + void tst_QDataStream::stream_QByteArray2() { QByteArray ba; -- cgit v0.12 From 135a6e32522775b182e870130eb12502753c913c Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 16 Dec 2010 12:36:41 +0100 Subject: add write error handling to QTextStream add new status flag WriteFailed. use it in flushWriteBuffer(). remove the boolean return values from write(), putString() and putNumber(), as they were ignored anyway - flushWriteBuffer() does it correctly now. Task-number: QTBUG-376 Reviewed-by: mariusSO --- src/corelib/io/qtextstream.cpp | 42 ++++++++++++++++++------------ src/corelib/io/qtextstream.h | 3 ++- tests/auto/qtextstream/tst_qtextstream.cpp | 37 ++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 18 deletions(-) diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index 560766a..242c672 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -396,19 +396,19 @@ public: npsInvalidPrefix }; - inline bool write(const QString &data); inline bool getChar(QChar *ch); inline void ungetChar(const QChar &ch); NumberParsingStatus getNumber(qulonglong *l); bool getReal(double *f); - bool putNumber(qulonglong number, bool negative); - inline bool putString(const QString &ch, bool number = false); + inline void write(const QString &data); + inline void putString(const QString &ch, bool number = false); + void putNumber(qulonglong number, bool negative); // buffers bool fillReadBuffer(qint64 maxBytes = -1); void resetReadBuffer(); - bool flushWriteBuffer(); + void flushWriteBuffer(); QString writeBuffer; QString readBuffer; int readBufferOffset; @@ -642,14 +642,20 @@ void QTextStreamPrivate::resetReadBuffer() /*! \internal */ -bool QTextStreamPrivate::flushWriteBuffer() +void QTextStreamPrivate::flushWriteBuffer() { // no buffer next to the QString itself; this function should only // be called internally, for devices. if (string || !device) - return false; + return; + + // Stream went bye-bye already. Appending further data may succeed again, + // but would create a corrupted stream anyway. + if (status != QTextStream::Ok) + return; + if (writeBuffer.isEmpty()) - return true; + return; #if defined (Q_OS_WIN) // handle text translation and bypass the Text flag in the device. @@ -681,8 +687,10 @@ bool QTextStreamPrivate::flushWriteBuffer() qDebug("QTextStreamPrivate::flushWriteBuffer(), device->write(\"%s\") == %d", qt_prettyDebug(data.constData(), qMin(data.size(),32), data.size()).constData(), int(bytesWritten)); #endif - if (bytesWritten <= 0) - return false; + if (bytesWritten <= 0) { + status = QTextStream::WriteFailed; + return; + } #if defined (Q_OS_WIN) // replace the text flag @@ -702,7 +710,8 @@ bool QTextStreamPrivate::flushWriteBuffer() qDebug("QTextStreamPrivate::flushWriteBuffer() wrote %d bytes", int(bytesWritten)); #endif - return flushed && bytesWritten == qint64(data.size()); + if (!flushed || bytesWritten != qint64(data.size())) + status = QTextStream::WriteFailed; } QString QTextStreamPrivate::read(int maxlen) @@ -908,7 +917,7 @@ inline void QTextStreamPrivate::restoreToSavedConverterState() /*! \internal */ -inline bool QTextStreamPrivate::write(const QString &data) +inline void QTextStreamPrivate::write(const QString &data) { if (string) { // ### What about seek()?? @@ -916,9 +925,8 @@ inline bool QTextStreamPrivate::write(const QString &data) } else { writeBuffer += data; if (writeBuffer.size() > QTEXTSTREAM_BUFFERSIZE) - return flushWriteBuffer(); + flushWriteBuffer(); } - return true; } /*! \internal @@ -959,7 +967,7 @@ inline void QTextStreamPrivate::ungetChar(const QChar &ch) /*! \internal */ -inline bool QTextStreamPrivate::putString(const QString &s, bool number) +inline void QTextStreamPrivate::putString(const QString &s, bool number) { QString tmp = s; @@ -993,7 +1001,7 @@ inline bool QTextStreamPrivate::putString(const QString &s, bool number) qt_prettyDebug(a.constData(), a.size(), qMax(16, a.size())).constData(), qt_prettyDebug(b.constData(), b.size(), qMax(16, b.size())).constData()); #endif - return write(tmp); + write(tmp); } /*! @@ -2270,7 +2278,7 @@ QTextStream &QTextStream::operator>>(char *c) /*! \internal */ -bool QTextStreamPrivate::putNumber(qulonglong number, bool negative) +void QTextStreamPrivate::putNumber(qulonglong number, bool negative) { QString result; @@ -2310,7 +2318,7 @@ bool QTextStreamPrivate::putNumber(qulonglong number, bool negative) result.prepend(QLatin1Char('0')); } } - return putString(result, true); + putString(result, true); } /*! diff --git a/src/corelib/io/qtextstream.h b/src/corelib/io/qtextstream.h index d82da59..c635691 100644 --- a/src/corelib/io/qtextstream.h +++ b/src/corelib/io/qtextstream.h @@ -89,7 +89,8 @@ public: enum Status { Ok, ReadPastEnd, - ReadCorruptData + ReadCorruptData, + WriteFailed }; enum NumberFlag { ShowBase = 0x1, diff --git a/tests/auto/qtextstream/tst_qtextstream.cpp b/tests/auto/qtextstream/tst_qtextstream.cpp index 4c78ef0..005f686 100644 --- a/tests/auto/qtextstream/tst_qtextstream.cpp +++ b/tests/auto/qtextstream/tst_qtextstream.cpp @@ -228,6 +228,7 @@ private slots: void status_real_read(); void status_integer_read(); void status_word_read(); + void status_write_error(); // use case tests void useCase1(); @@ -4176,6 +4177,42 @@ void tst_QTextStream::status_word_read() QCOMPARE(s.status(), QTextStream::ReadPastEnd); } +class FakeBuffer : public QBuffer +{ +protected: + qint64 writeData(const char *c, qint64 i) { return m_lock ? 0 : QBuffer::writeData(c, i); } +public: + FakeBuffer(bool locked = false) : m_lock(locked) {} + void setLocked(bool locked) { m_lock = locked; } +private: + bool m_lock; +}; + +void tst_QTextStream::status_write_error() +{ + FakeBuffer fb(false); + QVERIFY(fb.open(QBuffer::ReadWrite)); + QTextStream fs(&fb); + fs.setCodec(QTextCodec::codecForName("latin1")); + /* first write some initial content */ + fs << "hello"; + fs.flush(); + QCOMPARE(fs.status(), QTextStream::Ok); + QCOMPARE(fb.data(), QByteArray("hello")); + /* then test that writing can cause an error */ + fb.setLocked(true); + fs << "error"; + fs.flush(); + QCOMPARE(fs.status(), QTextStream::WriteFailed); + QCOMPARE(fb.data(), QByteArray("hello")); + /* finally test that writing after an error doesn't change the stream any more */ + fb.setLocked(false); + fs << "can't do that"; + fs.flush(); + QCOMPARE(fs.status(), QTextStream::WriteFailed); + QCOMPARE(fb.data(), QByteArray("hello")); +} + void tst_QTextStream::task180679_alignAccountingStyle() { { -- cgit v0.12 From ce3dabc8863440a56540d86537848621581afa7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Thu, 16 Dec 2010 13:43:02 +0100 Subject: Make parent constructor argument optional Task-number: QTBUG-16100 Reviewed-by: Oswald Buddenhagen --- src/gui/widgets/qvalidator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widgets/qvalidator.h b/src/gui/widgets/qvalidator.h index 63734ca..af1b80f 100644 --- a/src/gui/widgets/qvalidator.h +++ b/src/gui/widgets/qvalidator.h @@ -101,7 +101,7 @@ class Q_GUI_EXPORT QIntValidator : public QValidator public: explicit QIntValidator(QObject * parent = 0); - QIntValidator(int bottom, int top, QObject * parent); + QIntValidator(int bottom, int top, QObject *parent = 0); ~QIntValidator(); QValidator::State validate(QString &, int &) const; -- cgit v0.12 From 5daf1ab79e3dd906664a7af00b311ba7c3f51138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Thu, 16 Dec 2010 16:24:11 +0100 Subject: Test doesn't need to depend on temp path Instead, use the current directory for creating test data. Reviewed-by: Oswald Buddenhagen --- tests/auto/qcompleter/tst_qcompleter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qcompleter/tst_qcompleter.cpp b/tests/auto/qcompleter/tst_qcompleter.cpp index 650c328..abc86ec 100644 --- a/tests/auto/qcompleter/tst_qcompleter.cpp +++ b/tests/auto/qcompleter/tst_qcompleter.cpp @@ -1455,7 +1455,7 @@ void tst_QCompleter::task247560_keyboardNavigation() void tst_QCompleter::QTBUG_14292_filesystem() { - QDir tmpDir = QDir::temp(); + QDir tmpDir = QDir::currentPath(); qsrand(QTime::currentTime().msec()); QString d = "tst_QCompleter_" + QString::number(qrand()); QVERIFY(tmpDir.mkdir(d)); -- cgit v0.12 From a97cf9553ff841dcfd45bbc85ff05b0aafd4a548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Thu, 16 Dec 2010 16:31:34 +0100 Subject: tst_QCompleter: Clean up after one's self The utility class FileSystem uses the RAII idiom to clean up directories created for the purpose of the test. Rubber-stamped-by: Oswald Buddenhagen --- tests/auto/qcompleter/tst_qcompleter.cpp | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/tests/auto/qcompleter/tst_qcompleter.cpp b/tests/auto/qcompleter/tst_qcompleter.cpp index abc86ec..62e64be 100644 --- a/tests/auto/qcompleter/tst_qcompleter.cpp +++ b/tests/auto/qcompleter/tst_qcompleter.cpp @@ -49,6 +49,7 @@ #include #include "../../shared/util.h" +#include "../../shared/filesystem.h" //TESTED_CLASS= //TESTED_FILES= @@ -1455,24 +1456,16 @@ void tst_QCompleter::task247560_keyboardNavigation() void tst_QCompleter::QTBUG_14292_filesystem() { + FileSystem fs; QDir tmpDir = QDir::currentPath(); + qsrand(QTime::currentTime().msec()); QString d = "tst_QCompleter_" + QString::number(qrand()); - QVERIFY(tmpDir.mkdir(d)); - -#if 0 - struct Cleanup { - QString dir; - ~Cleanup() { - qDebug() << dir << - QFile::remove(dir); } - } cleanup; - cleanup.dir = tmpDir.absolutePath()+"/" +d; -#endif + QVERIFY(fs.createDirectory(tmpDir.filePath(d))); QVERIFY(tmpDir.cd(d)); - QVERIFY(tmpDir.mkdir("hello")); - QVERIFY(tmpDir.mkdir("holla")); + QVERIFY(fs.createDirectory(tmpDir.filePath("hello"))); + QVERIFY(fs.createDirectory(tmpDir.filePath("holla"))); QLineEdit edit; QCompleter comp; @@ -1500,12 +1493,12 @@ void tst_QCompleter::QTBUG_14292_filesystem() QCOMPARE(comp.popup()->model()->rowCount(), 1); QTest::keyClick(&edit, 'r'); QTRY_VERIFY(!comp.popup()->isVisible()); - QVERIFY(tmpDir.mkdir("hero")); + QVERIFY(fs.createDirectory(tmpDir.filePath("hero"))); QTRY_VERIFY(comp.popup()->isVisible()); QCOMPARE(comp.popup()->model()->rowCount(), 1); QTest::keyClick(comp.popup(), Qt::Key_Escape); QTRY_VERIFY(!comp.popup()->isVisible()); - QVERIFY(tmpDir.mkdir("nothingThere")); + QVERIFY(fs.createDirectory(tmpDir.filePath("nothingThere"))); //there is no reason creating a file should open a popup, it did in Qt 4.7.0 QTest::qWait(60); QVERIFY(!comp.popup()->isVisible()); @@ -1522,7 +1515,7 @@ void tst_QCompleter::QTBUG_14292_filesystem() QTest::qWaitForWindowShown(&w); QTRY_VERIFY(!edit.hasFocus() && !comp.popup()->hasFocus()); - QVERIFY(tmpDir.mkdir("hemo")); + QVERIFY(fs.createDirectory(tmpDir.filePath("hemo"))); //there is no reason creating a file should open a popup, it did in Qt 4.7.0 QTest::qWait(60); QVERIFY(!comp.popup()->isVisible()); -- cgit v0.12 From c60a2a5e5136cfec74429114c6c74401fdda65a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Thu, 16 Dec 2010 14:09:35 +0100 Subject: Windows Vista and 7 also have animated progress bars Which means they get paint events all the time. Reviewed-by: Jens Bache-Wiig --- tests/auto/qprogressbar/tst_qprogressbar.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/auto/qprogressbar/tst_qprogressbar.cpp b/tests/auto/qprogressbar/tst_qprogressbar.cpp index 7d94e3c..e042fb8 100644 --- a/tests/auto/qprogressbar/tst_qprogressbar.cpp +++ b/tests/auto/qprogressbar/tst_qprogressbar.cpp @@ -179,10 +179,15 @@ void tst_QProgressBar::format() bar.repainted = false; bar.setFormat("%v of %m (%p%)"); qApp->processEvents(); + #ifndef Q_WS_MAC - // The Mac scroll bar is animated, which means we get paint events all the time. + // Animated scroll bars get paint events all the time +#ifdef Q_OS_WIN + if (QSysInfo::WindowsVersion < QSysInfo::WV_VISTA) +#endif QVERIFY(!bar.repainted); #endif + QCOMPARE(bar.text(), QString("1 of 10 (10%)")); bar.setRange(5, 5); bar.setValue(5); -- cgit v0.12 From 4d5029365ccc045522cb87582c2b2e1a36ed0d24 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 16 Dec 2010 17:06:23 +0100 Subject: document WriteFailed status codes (whoops) --- src/corelib/io/qdatastream.cpp | 1 + src/corelib/io/qtextstream.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp index 52ee252..73ce490 100644 --- a/src/corelib/io/qdatastream.cpp +++ b/src/corelib/io/qdatastream.cpp @@ -223,6 +223,7 @@ QT_BEGIN_NAMESPACE \value ReadPastEnd The data stream has read past the end of the data in the underlying device. \value ReadCorruptData The data stream has read corrupt data. + \value WriteFailed The data stream cannot write to the underlying device. */ /***************************************************************************** diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index 242c672..3bdbf32 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -224,6 +224,7 @@ static const int QTEXTSTREAM_BUFFERSIZE = 16384; \value ReadPastEnd The text stream has read past the end of the data in the underlying device. \value ReadCorruptData The text stream has read corrupt data. + \value WriteFailed The text stream cannot write to the underlying device. \sa status() */ -- cgit v0.12 From 558fe9383ba0aecbec09cc411c0ebab132aac137 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 16 Dec 2010 17:28:24 +0100 Subject: make QXmlStreamWriterPrivate::write(const char *s) ascii-only it's only ever called with ascii data, and the input encoding semantics weren't all that clear anyway. Reviewed-by: denis --- src/corelib/xml/qxmlstream.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp index 91c3a19..50703a4 100644 --- a/src/corelib/xml/qxmlstream.cpp +++ b/src/corelib/xml/qxmlstream.cpp @@ -3083,16 +3083,11 @@ void QXmlStreamWriterPrivate::writeEscaped(const QString &s, bool escapeWhitespa qWarning("QXmlStreamWriter: No device"); } - +// ASCII only! void QXmlStreamWriterPrivate::write(const char *s) { if (device) { -#ifndef QT_NO_TEXTCODEC - if (codec->mibEnum() != 106) - device->write(encoder->fromUnicode(QLatin1String(s))); - else -#endif - device->write(s, strlen(s)); + device->write(s, strlen(s)); } else if (stringDevice) { stringDevice->append(QLatin1String(s)); } else -- cgit v0.12 From 86246bfe354aaf03065cd78d7d5410e5097ada48 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 16 Dec 2010 17:30:52 +0100 Subject: remove some code duplication writeEscaped() can simply call write() once it's done escaping Reviewed-by: denis --- src/corelib/xml/qxmlstream.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp index 50703a4..b29bd92 100644 --- a/src/corelib/xml/qxmlstream.cpp +++ b/src/corelib/xml/qxmlstream.cpp @@ -3070,17 +3070,7 @@ void QXmlStreamWriterPrivate::writeEscaped(const QString &s, bool escapeWhitespa escaped += QChar(c); } } - if (device) { -#ifdef QT_NO_TEXTCODEC - device->write(escaped.toLatin1(), escaped.size()); -#else - device->write(encoder->fromUnicode(escaped)); -#endif - } - else if (stringDevice) - stringDevice->append(escaped); - else - qWarning("QXmlStreamWriter: No device"); + write(escaped); } // ASCII only! -- cgit v0.12 From 468328468904d116a5ff70fd4c71c34e453e8593 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 16 Dec 2010 17:44:01 +0100 Subject: optimize writing string constants and byte arrays don't throw away the already known length just to call strlen() on it over and over again. Reviewed-by: denis --- src/corelib/xml/qxmlstream.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp index b29bd92..3d8af9b 100644 --- a/src/corelib/xml/qxmlstream.cpp +++ b/src/corelib/xml/qxmlstream.cpp @@ -2965,7 +2965,8 @@ public: void write(const QStringRef &); void write(const QString &); void writeEscaped(const QString &, bool escapeWhitespace = false); - void write(const char *s); + void write(const char *s, int len); + template void write(const char (&s)[N]) { write(s, N - 1); } bool finishStartElement(bool contents = true); void writeStartElement(const QString &namespaceUri, const QString &name); QIODevice *device; @@ -3074,12 +3075,12 @@ void QXmlStreamWriterPrivate::writeEscaped(const QString &s, bool escapeWhitespa } // ASCII only! -void QXmlStreamWriterPrivate::write(const char *s) +void QXmlStreamWriterPrivate::write(const char *s, int len) { if (device) { - device->write(s, strlen(s)); + device->write(s, len); } else if (stringDevice) { - stringDevice->append(QLatin1String(s)); + stringDevice->append(QString::fromLatin1(s, len)); } else qWarning("QXmlStreamWriter: No device"); } @@ -3157,7 +3158,7 @@ void QXmlStreamWriterPrivate::indent(int level) { write("\n"); for (int i = level; i > 0; --i) - write(autoFormattingIndent.constData()); + write(autoFormattingIndent.constData(), autoFormattingIndent.length()); } @@ -3744,7 +3745,7 @@ void QXmlStreamWriter::writeStartDocument(const QString &version) #ifdef QT_NO_TEXTCODEC d->write("iso-8859-1"); #else - d->write(d->codec->name().constData()); + d->write(d->codec->name().constData(), d->codec->name().length()); #endif } d->write("\"?>"); @@ -3767,12 +3768,13 @@ void QXmlStreamWriter::writeStartDocument(const QString &version, bool standalon #ifdef QT_NO_TEXTCODEC d->write("iso-8859-1"); #else - d->write(d->codec->name().constData()); + d->write(d->codec->name().constData(), d->codec->name().length()); #endif } - d->write("\" standalone=\""); - d->write(standalone ? "yes" : "no"); - d->write("\"?>"); + if (standalone) + d->write("\" standalone=\"yes\"?>"); + else + d->write("\" standalone=\"no\"?>"); } -- cgit v0.12 From 8789d4bd9eaba3a90fb3a94edb71ad0c1e01dc66 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 16 Dec 2010 20:32:21 +0100 Subject: add error handling to QXmlStreamWriter introduce QXmlStreamWriter::hasError(). set the error flag when any write error occurs. ignore subsequent writes after the first error. Reviewed-by: denis --- src/corelib/xml/qxmlstream.cpp | 37 ++++++++++++-- src/corelib/xml/qxmlstream.h | 2 + tests/auto/qxmlstream/tst_qxmlstream.cpp | 82 ++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 5 deletions(-) diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp index 3d8af9b..64a9857 100644 --- a/src/corelib/xml/qxmlstream.cpp +++ b/src/corelib/xml/qxmlstream.cpp @@ -2941,6 +2941,9 @@ QStringRef QXmlStreamReader::documentEncoding() const By default, QXmlStreamWriter encodes XML in UTF-8. Different encodings can be enforced using setCodec(). + If an error occurs while writing to the underlying device, hasError() + starts returning true and subsequent writes are ignored. + The \l{QXmlStream Bookmarks Example} illustrates how to use a stream writer to write an XML bookmark file (XBEL) that was previously read in by a QXmlStreamReader. @@ -2976,6 +2979,7 @@ public: uint inEmptyElement :1; uint lastWasStartElement :1; uint wroteSomething :1; + uint hasError :1; uint autoFormatting :1; QByteArray autoFormattingIndent; NamespaceDeclaration emptyNamespace; @@ -3008,6 +3012,7 @@ QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q) #endif inStartElement = inEmptyElement = false; wroteSomething = false; + hasError = false; lastWasStartElement = false; lastNamespaceDeclaration = 1; autoFormatting = false; @@ -3017,11 +3022,15 @@ QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q) void QXmlStreamWriterPrivate::write(const QStringRef &s) { if (device) { + if (hasError) + return; #ifdef QT_NO_TEXTCODEC - device->write(s.toString().toLatin1(), s.size()); + QByteArray bytes = s.toLatin1(); #else - device->write(encoder->fromUnicode(s.constData(), s.size())); + QByteArray bytes = encoder->fromUnicode(s.constData(), s.size()); #endif + if (device->write(bytes) != bytes.size()) + hasError = true; } else if (stringDevice) s.appendTo(stringDevice); @@ -3032,11 +3041,15 @@ void QXmlStreamWriterPrivate::write(const QStringRef &s) void QXmlStreamWriterPrivate::write(const QString &s) { if (device) { + if (hasError) + return; #ifdef QT_NO_TEXTCODEC - device->write(s.toLatin1(), s.size()); + QByteArray bytes = s.toLatin1(); #else - device->write(encoder->fromUnicode(s)); + QByteArray bytes = encoder->fromUnicode(s); #endif + if (device->write(bytes) != bytes.size()) + hasError = true; } else if (stringDevice) stringDevice->append(s); @@ -3078,7 +3091,10 @@ void QXmlStreamWriterPrivate::writeEscaped(const QString &s, bool escapeWhitespa void QXmlStreamWriterPrivate::write(const char *s, int len) { if (device) { - device->write(s, len); + if (hasError) + return; + if (device->write(s, len) != len) + hasError = true; } else if (stringDevice) { stringDevice->append(QString::fromLatin1(s, len)); } else @@ -3359,6 +3375,17 @@ int QXmlStreamWriter::autoFormattingIndent() const return d->autoFormattingIndent.count(' ') - d->autoFormattingIndent.count('\t'); } +/*! + Returns \c true if the stream failed to write to the underlying device. + + The error status is never reset. Writes happening after the error + occurred are ignored, even if the error condition is cleared. + */ +bool QXmlStreamWriter::hasError() const +{ + Q_D(const QXmlStreamWriter); + return d->hasError; +} /*! \overload diff --git a/src/corelib/xml/qxmlstream.h b/src/corelib/xml/qxmlstream.h index d7143bd..244d3d4 100644 --- a/src/corelib/xml/qxmlstream.h +++ b/src/corelib/xml/qxmlstream.h @@ -474,6 +474,8 @@ public: void writeCurrentToken(const QXmlStreamReader &reader); #endif + bool hasError() const; + private: Q_DISABLE_COPY(QXmlStreamWriter) Q_DECLARE_PRIVATE(QXmlStreamWriter) diff --git a/tests/auto/qxmlstream/tst_qxmlstream.cpp b/tests/auto/qxmlstream/tst_qxmlstream.cpp index 19e4b90..9e4f3ec 100644 --- a/tests/auto/qxmlstream/tst_qxmlstream.cpp +++ b/tests/auto/qxmlstream/tst_qxmlstream.cpp @@ -574,6 +574,7 @@ private slots: void checkCommentIndentation() const; void checkCommentIndentation_data() const; void qtbug9196_crash() const; + void hasError() const; private: static QByteArray readFile(const QString &filename); @@ -1560,5 +1561,86 @@ void tst_QXmlStream::qtbug9196_crash() const } } +class FakeBuffer : public QBuffer +{ +protected: + qint64 writeData(const char *c, qint64 i) + { + qint64 ai = qMin(m_capacity, i); + m_capacity -= ai; + return ai ? QBuffer::writeData(c, ai) : 0; + } +public: + void setCapacity(int capacity) { m_capacity = capacity; } +private: + qint64 m_capacity; +}; + +void tst_QXmlStream::hasError() const +{ + { + FakeBuffer fb; + QVERIFY(fb.open(QBuffer::ReadWrite)); + fb.setCapacity(1000); + QXmlStreamWriter writer(&fb); + writer.writeStartDocument(); + writer.writeEndDocument(); + QVERIFY(!writer.hasError()); + QCOMPARE(fb.data(), QByteArray("\n")); + } + + { + // Failure caused by write(QString) + FakeBuffer fb; + QVERIFY(fb.open(QBuffer::ReadWrite)); + fb.setCapacity(strlen(" Date: Mon, 20 Dec 2010 11:55:32 +0100 Subject: define FSCTL_SET_REPARSE_POINT in test header ... as was already done in windows engine implementation for FSCTL_*GET*_REPARSE_POINT. --- tests/shared/filesystem.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/shared/filesystem.h b/tests/shared/filesystem.h index 8274346..4775671 100644 --- a/tests/shared/filesystem.h +++ b/tests/shared/filesystem.h @@ -55,6 +55,9 @@ #define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) #endif #define REPARSE_MOUNTPOINT_HEADER_SIZE 8 +#ifndef FSCTL_SET_REPARSE_POINT +#define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) +#endif #endif struct FileSystem -- cgit v0.12 From 09317dda494a51d101723131c5a01af4149ac5de Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 20 Dec 2010 13:04:23 +0100 Subject: Micro-optimization for QSpanData::setup() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't call QColor::rgba() in a macro arg that gets evaluated multiple times. Reviewed-by: Samuel Rødal --- src/gui/painting/qpaintengine_raster.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 97dfddf..3186749 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -5152,7 +5152,8 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode case Qt::SolidPattern: { type = Solid; QColor c = qbrush_color(brush); - solid.color = PREMUL(ARGB_COMBINE_ALPHA(c.rgba(), alpha)); + QRgb rgba = c.rgba(); + solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha)); if ((solid.color & 0xff000000) == 0 && compositionMode == QPainter::CompositionMode_SourceOver) { type = None; -- cgit v0.12 From 48e7c71d1165f0c60f56e0b769b35df2658e8e96 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 20 Dec 2010 13:05:27 +0100 Subject: Make the QRasterPaintEngineState copy constructor cheaper. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use initializer syntax to avoid default-constructing a throwaway QBrush and QPen. Reviewed-by: Samuel Rødal --- src/gui/painting/qpaintengine_raster.cpp | 34 ++++++++++++-------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 3186749..7fc90b8 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -662,31 +662,23 @@ QRasterPaintEngineState::QRasterPaintEngineState() QRasterPaintEngineState::QRasterPaintEngineState(QRasterPaintEngineState &s) : QPainterState(s) + , stroker(s.stroker) + , lastBrush(s.lastBrush) + , brushData(s.brushData) + , lastPen(s.lastPen) + , penData(s.penData) + , fillFlags(s.fillFlags) + , strokeFlags(s.strokeFlags) + , pixmapFlags(s.pixmapFlags) + , intOpacity(s.intOpacity) + , txscale(s.txscale) + , flag_bits(s.flag_bits) + , clip(s.clip) + , dirty(s.dirty) { - stroker = s.stroker; - - lastBrush = s.lastBrush; - brushData = s.brushData; brushData.tempImage = 0; - - lastPen = s.lastPen; - penData = s.penData; penData.tempImage = 0; - - fillFlags = s.fillFlags; - strokeFlags = s.strokeFlags; - pixmapFlags = s.pixmapFlags; - - intOpacity = s.intOpacity; - - txscale = s.txscale; - - flag_bits = s.flag_bits; - - clip = s.clip; flags.has_clip_ownership = false; - - dirty = s.dirty; } /*! -- cgit v0.12 From daba2c507ad42c66dafa6a29cffa94e9641e0c58 Mon Sep 17 00:00:00 2001 From: Harald Fernengel Date: Mon, 20 Dec 2010 14:26:39 +0100 Subject: Delay creation of the process manager The *nix process manager would create a pipe on every startup. In order to improve startup speed, the QProcessManager is now created when first needed. Reviewed-by: Robert Griebl --- src/corelib/io/qprocess_unix.cpp | 30 ++++++++++++++++++++++++++---- src/corelib/kernel/qcoreapplication.cpp | 18 ++++++++++++------ src/corelib/kernel/qcoreapplication.h | 1 + src/corelib/kernel/qcoreapplication_p.h | 2 ++ 4 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 216c382..e52d132 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -169,17 +169,27 @@ private: Q_GLOBAL_STATIC(QMutex, processManagerGlobalMutex) -static QProcessManager *processManager() { +static QProcessManager *processManagerInstance = 0; + +static QProcessManager *processManager() +{ // The constructor of QProcessManager should be called only once // so we cannot use Q_GLOBAL_STATIC directly for QProcessManager QMutex *mutex = processManagerGlobalMutex(); QMutexLocker locker(mutex); - static QProcessManager processManager; - return &processManager; + + if (!processManagerInstance) + QProcessPrivate::initializeProcessManager(); + + Q_ASSERT(processManagerInstance); + return processManagerInstance; } QProcessManager::QProcessManager() { + // can only be called from main thread + Q_ASSERT(!qApp || qApp->thread() == QThread::currentThread()); + #if defined (QPROCESS_DEBUG) qDebug() << "QProcessManager::QProcessManager()"; #endif @@ -198,6 +208,8 @@ QProcessManager::QProcessManager() ::sigaction(SIGCHLD, &action, &oldAction); if (oldAction.sa_handler != qt_sa_sigchld_handler) qt_sa_old_sigchld_handler = oldAction.sa_handler; + + processManagerInstance = this; } QProcessManager::~QProcessManager() @@ -226,6 +238,8 @@ QProcessManager::~QProcessManager() if (oldAction.sa_handler != qt_sa_sigchld_handler) { ::sigaction(SIGCHLD, &oldAction, 0); } + + processManagerInstance = 0; } void QProcessManager::run() @@ -1289,7 +1303,15 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a void QProcessPrivate::initializeProcessManager() { - (void) processManager(); + if (qApp && qApp->thread() != QThread::currentThread()) { + // The process manager must be initialized in the main thread + // Note: The call below will re-enter this function, but in the right thread, + // so the else statement below will be executed. + QMetaObject::invokeMethod(qApp, "_q_initializeProcessManager", Qt::BlockingQueuedConnection); + } else { + static QProcessManager processManager; + Q_UNUSED(processManager); + } } QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 0f95ee0..799433b 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -336,6 +336,16 @@ void QCoreApplicationPrivate::createEventDispatcher() #endif } +void QCoreApplicationPrivate::_q_initializeProcessManager() +{ +#ifndef QT_NO_PROCESS +# ifdef Q_OS_UNIX + QProcessPrivate::initializeProcessManager(); +# endif +#endif +} + + QThread *QCoreApplicationPrivate::theMainThread = 0; QThread *QCoreApplicationPrivate::mainThread() { @@ -600,12 +610,6 @@ void QCoreApplication::init() } #endif -#if defined(Q_OS_UNIX) && !(defined(QT_NO_PROCESS)) - // Make sure the process manager thread object is created in the main - // thread. - QProcessPrivate::initializeProcessManager(); -#endif - #ifdef QT_EVAL extern void qt_core_eval_init(uint); qt_core_eval_init(d->application_type); @@ -2666,3 +2670,5 @@ int QCoreApplication::loopLevel() */ QT_END_NAMESPACE + +#include "moc_qcoreapplication.cpp" diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h index f1c7c26..17e784e 100644 --- a/src/corelib/kernel/qcoreapplication.h +++ b/src/corelib/kernel/qcoreapplication.h @@ -205,6 +205,7 @@ protected: QCoreApplication(QCoreApplicationPrivate &p); private: + Q_PRIVATE_SLOT(d_func(), void _q_initializeProcessManager()) static bool sendSpontaneousEvent(QObject *receiver, QEvent *event); bool notifyInternal(QObject *receiver, QEvent *event); diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h index 2355c37..aafa821 100644 --- a/src/corelib/kernel/qcoreapplication_p.h +++ b/src/corelib/kernel/qcoreapplication_p.h @@ -82,6 +82,8 @@ public: bool sendThroughObjectEventFilters(QObject *, QEvent *); bool notify_helper(QObject *, QEvent *); + void _q_initializeProcessManager(); + virtual QString appName() const; virtual void createEventDispatcher(); static void removePostedEvent(QEvent *); -- cgit v0.12 From e679392978c21266ec0bf6f960ab8c5f0621e18b Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 30 Sep 2010 17:29:40 +0200 Subject: Add QElapsedTimer::nsecsElapsed() const Allow sub-millisecond resolution on systems where it is possible. On UNIX, with monotonic clock support we get full nanosecond resolution, microsecond otherwise. On Windows we convert the performance counters to nanoseconds if availble, otherwise we only have millisecond resolution. On Mac, the mach time is converted to nanoseconds. On Symbian, we have microsecond resolution. Reviewed-by: joao --- src/corelib/tools/qelapsedtimer.h | 1 + src/corelib/tools/qelapsedtimer_generic.cpp | 16 ++++++++++++++++ src/corelib/tools/qelapsedtimer_mac.cpp | 6 ++++++ src/corelib/tools/qelapsedtimer_symbian.cpp | 22 +++++++++++----------- src/corelib/tools/qelapsedtimer_unix.cpp | 11 +++++++++++ src/corelib/tools/qelapsedtimer_win.cpp | 20 +++++++++++++------- tests/auto/qelapsedtimer/tst_qelapsedtimer.cpp | 7 ++++++- 7 files changed, 64 insertions(+), 19 deletions(-) diff --git a/src/corelib/tools/qelapsedtimer.h b/src/corelib/tools/qelapsedtimer.h index b996f6a..4118389 100644 --- a/src/corelib/tools/qelapsedtimer.h +++ b/src/corelib/tools/qelapsedtimer.h @@ -68,6 +68,7 @@ public: void invalidate(); bool isValid() const; + qint64 nsecsElapsed() const; qint64 elapsed() const; bool hasExpired(qint64 timeout) const; diff --git a/src/corelib/tools/qelapsedtimer_generic.cpp b/src/corelib/tools/qelapsedtimer_generic.cpp index 85986e6..740f496 100644 --- a/src/corelib/tools/qelapsedtimer_generic.cpp +++ b/src/corelib/tools/qelapsedtimer_generic.cpp @@ -103,6 +103,22 @@ qint64 QElapsedTimer::restart() return t1 - old; } +/*! \since 4.8 + + Returns the number of nanoseconds since this QElapsedTimer was last + started. Calling this function in a QElapsedTimer that was invalidated + will result in undefined results. + + On platforms that do not provide nanosecond resolution, the value returned + will be the best estimate available. + + \sa start(), restart(), hasExpired(), invalidate() +*/ +qint64 QElapsedTimer::nsecsElapsed() const +{ + return elapsed() * 1000000; +} + /*! Returns the number of milliseconds since this QElapsedTimer was last started. Calling this function in a QElapsedTimer that was invalidated diff --git a/src/corelib/tools/qelapsedtimer_mac.cpp b/src/corelib/tools/qelapsedtimer_mac.cpp index 8fceb49..e51f8b3 100644 --- a/src/corelib/tools/qelapsedtimer_mac.cpp +++ b/src/corelib/tools/qelapsedtimer_mac.cpp @@ -97,6 +97,12 @@ qint64 QElapsedTimer::restart() return absoluteToMSecs(t1 - old); } +qint64 QElapsedTimer::nsecsElapsed() const +{ + uint64_t cpu_time = mach_absolute_time(); + return absoluteToNSecs(cpu_time - t1); +} + qint64 QElapsedTimer::elapsed() const { uint64_t cpu_time = mach_absolute_time(); diff --git a/src/corelib/tools/qelapsedtimer_symbian.cpp b/src/corelib/tools/qelapsedtimer_symbian.cpp index 038b102..7cd5f1e 100644 --- a/src/corelib/tools/qelapsedtimer_symbian.cpp +++ b/src/corelib/tools/qelapsedtimer_symbian.cpp @@ -64,11 +64,6 @@ static quint64 getMicrosecondFromTick() return nanokernel_tick_period * (val | (quint64(highdword) << 32)); } -static quint64 getMillisecondFromTick() -{ - return getMicrosecondFromTick() / 1000; -} - timeval qt_gettime() { timeval tv; @@ -91,36 +86,41 @@ bool QElapsedTimer::isMonotonic() void QElapsedTimer::start() { - t1 = getMillisecondFromTick(); + t1 = getMicrosecondFromTick(); t2 = 0; } qint64 QElapsedTimer::restart() { qint64 oldt1 = t1; - t1 = getMillisecondFromTick(); + t1 = getMicrosecondFromTick(); t2 = 0; return t1 - oldt1; } +qint64 QElapsedTimer::nsecsElapsed() const +{ + return (getMicrosecondFromTick() - t1) * 1000; +} + qint64 QElapsedTimer::elapsed() const { - return getMillisecondFromTick() - t1; + return (getMicrosecondFromTick() - t1) / 1000; } qint64 QElapsedTimer::msecsSinceReference() const { - return t1; + return t1 / 1000; } qint64 QElapsedTimer::msecsTo(const QElapsedTimer &other) const { - return other.t1 - t1; + return (other.t1 - t1) / 1000; } qint64 QElapsedTimer::secsTo(const QElapsedTimer &other) const { - return msecsTo(other) / 1000; + return msecsTo(other) / 1000000; } bool operator<(const QElapsedTimer &v1, const QElapsedTimer &v2) diff --git a/src/corelib/tools/qelapsedtimer_unix.cpp b/src/corelib/tools/qelapsedtimer_unix.cpp index 633fa00..7407e1b 100644 --- a/src/corelib/tools/qelapsedtimer_unix.cpp +++ b/src/corelib/tools/qelapsedtimer_unix.cpp @@ -167,6 +167,17 @@ qint64 QElapsedTimer::restart() return elapsedAndRestart(t1, t2, &t1, &t2); } +qint64 QElapsedTimer::nsecsElapsed() const +{ + qint64 sec, frac; + do_gettime(&sec, &frac); + sec = sec - t1; + frac = frac - t2; + if (!monotonicClockAvailable) + frac *= 1000; + return sec * Q_INT64_C(1000000000) + frac; +} + qint64 QElapsedTimer::elapsed() const { qint64 sec, frac; diff --git a/src/corelib/tools/qelapsedtimer_win.cpp b/src/corelib/tools/qelapsedtimer_win.cpp index c77acaa..3f4acc1 100644 --- a/src/corelib/tools/qelapsedtimer_win.cpp +++ b/src/corelib/tools/qelapsedtimer_win.cpp @@ -79,14 +79,14 @@ static void resolveLibs() done = true; } -static inline qint64 ticksToMilliseconds(qint64 ticks) +static inline qint64 ticksToNanoseconds(qint64 ticks) { if (counterFrequency > 0) { // QueryPerformanceCounter uses an arbitrary frequency - return ticks * 1000 / counterFrequency; + return ticks * 1000000000 / counterFrequency; } else { // GetTickCount(64) return milliseconds - return ticks; + return ticks * 1000000; } } @@ -144,24 +144,30 @@ qint64 QElapsedTimer::restart() qint64 oldt1 = t1; t1 = getTickCount(); t2 = 0; - return ticksToMilliseconds(t1 - oldt1); + return ticksToNanoseconds(t1 - oldt1) / 1000000; +} + +qint64 QElapsedTimer::nsecsElapsed() const +{ + qint64 elapsed = getTickCount() - t1; + return ticksToNanoseconds(elapsed); } qint64 QElapsedTimer::elapsed() const { qint64 elapsed = getTickCount() - t1; - return ticksToMilliseconds(elapsed); + return ticksToNanoseconds(elapsed) / 1000000; } qint64 QElapsedTimer::msecsSinceReference() const { - return ticksToMilliseconds(t1); + return ticksToNanoseconds(t1) / 1000000; } qint64 QElapsedTimer::msecsTo(const QElapsedTimer &other) const { qint64 difference = other.t1 - t1; - return ticksToMilliseconds(difference); + return ticksToNanoseconds(difference) / 1000000; } qint64 QElapsedTimer::secsTo(const QElapsedTimer &other) const diff --git a/tests/auto/qelapsedtimer/tst_qelapsedtimer.cpp b/tests/auto/qelapsedtimer/tst_qelapsedtimer.cpp index 87df57d..bc61f52 100644 --- a/tests/auto/qelapsedtimer/tst_qelapsedtimer.cpp +++ b/tests/auto/qelapsedtimer/tst_qelapsedtimer.cpp @@ -122,11 +122,13 @@ void tst_QElapsedTimer::basics() quint64 value1 = t1.msecsSinceReference(); qDebug() << value1 << t1; + qint64 nsecs = t1.nsecsElapsed(); qint64 elapsed = t1.restart(); QVERIFY(elapsed < minResolution); + QVERIFY(nsecs / 1000000 < minResolution); quint64 value2 = t1.msecsSinceReference(); - qDebug() << value2 << t1 << elapsed; + qDebug() << value2 << t1 << elapsed << nsecs; // in theory, elapsed == value2 - value1 // However, since QElapsedTimer keeps internally the full resolution, @@ -150,7 +152,10 @@ void tst_QElapsedTimer::elapsed() // don't check: t1.secsTo(t2) // QVERIFY(t1 - t2 < 0); + QVERIFY(t1.nsecsElapsed() > 0); QVERIFY(t1.elapsed() > 0); + // the number of elapsed nanoseconds and milliseconds should match + QVERIFY(t1.nsecsElapsed() - t1.elapsed() * 1000000 < 1000000); QVERIFY(t1.hasExpired(minResolution)); QVERIFY(!t1.hasExpired(8*minResolution)); QVERIFY(!t2.hasExpired(minResolution)); -- cgit v0.12 From df5403e48df3ab57924a6b85d9cbaa95e3c5e766 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 16 Sep 2010 10:36:22 +0200 Subject: Removed QMutexPrivate::self() declaration This function is not used or implemented anywhere. Reviewed-by: joao --- src/corelib/thread/qmutex_p.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index 6126423..57a6062 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -65,7 +65,6 @@ public: QMutexPrivate(QMutex::RecursionMode mode); ~QMutexPrivate(); - ulong self(); bool wait(int timeout = -1); void wakeUp(); -- cgit v0.12 From 33b015ae5fe561e48130b07e1ae320131cec3505 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 28 Sep 2010 11:39:17 +0200 Subject: Add a benchmark for contended and uncontended QMutex performance This benchmark also includes the same benchmark for the native type for comparison. Reviewed-by: joao --- tests/benchmarks/corelib/thread/qmutex/qmutex.pro | 2 +- .../corelib/thread/qmutex/tst_qmutex.cpp | 272 ++++++++++++++++++++- 2 files changed, 261 insertions(+), 13 deletions(-) diff --git a/tests/benchmarks/corelib/thread/qmutex/qmutex.pro b/tests/benchmarks/corelib/thread/qmutex/qmutex.pro index eda2f11..8fda5fa 100644 --- a/tests/benchmarks/corelib/thread/qmutex/qmutex.pro +++ b/tests/benchmarks/corelib/thread/qmutex/qmutex.pro @@ -1,6 +1,6 @@ load(qttest_p4) TEMPLATE = app TARGET = tst_bench_qmutex - +QT -= gui SOURCES += tst_qmutex.cpp diff --git a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp index fded508..9ed5d55 100644 --- a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp +++ b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp @@ -39,34 +39,85 @@ ** ****************************************************************************/ -#include -#include +#include +#include #include -//TESTED_FILES= +#ifdef Q_OS_UNIX +# include +# include +typedef pthread_mutex_t NativeMutexType; +void NativeMutexInitialize(NativeMutexType *mutex) +{ + pthread_mutex_init(mutex, NULL); +} +void NativeMutexDestroy(NativeMutexType *mutex) +{ + pthread_mutex_destroy(mutex); +} +void NativeMutexLock(NativeMutexType *mutex) +{ + pthread_mutex_lock(mutex); +} +void NativeMutexUnlock(NativeMutexType *mutex) +{ + pthread_mutex_unlock(mutex); +} +#elif defined(Q_OS_WIN) +# define _WIN32_WINNT 0x0400 +# include +typedef CRITICAL_SECTION NativeMutexType; +void NativeMutexInitialize(NativeMutexType *mutex) +{ + InitializeCriticalSection(mutex); +} +void NativeMutexDestroy(NativeMutexType *mutex) +{ + DeleteCriticalSection(mutex); +} +void NativeMutexLock(NativeMutexType *mutex) +{ + EnterCriticalSection(mutex); +} +void NativeMutexUnlock(NativeMutexType *mutex) +{ + LeaveCriticalSection(mutex); +} +#endif +//TESTED_FILES= class tst_QMutex : public QObject { Q_OBJECT + int threadCount; + public: - tst_QMutex(); - virtual ~tst_QMutex(); + tst_QMutex() + { + // at least 2 threads, even on single cpu/core machines + threadCount = qMax(2, QThread::idealThreadCount()); + qDebug("thread count: %d", threadCount); + } private slots: void noThread_data(); void noThread(); -}; -tst_QMutex::tst_QMutex() -{ -} + void uncontendedNative(); + void uncontendedQMutex(); + void uncontendedQMutexLocker(); -tst_QMutex::~tst_QMutex() -{ -} + void contendedNative_data(); + void contendedQMutex_data() { contendedNative_data(); } + void contendedQMutexLocker_data() { contendedNative_data(); } + + void contendedNative(); + void contendedQMutex(); + void contendedQMutexLocker(); +}; void tst_QMutex::noThread_data() { @@ -127,5 +178,202 @@ void tst_QMutex::noThread() QCOMPARE(int(count), N); } +void tst_QMutex::uncontendedNative() +{ + NativeMutexType mutex; + NativeMutexInitialize(&mutex); + QBENCHMARK { + NativeMutexLock(&mutex); + NativeMutexUnlock(&mutex); + } + NativeMutexDestroy(&mutex); +} + +void tst_QMutex::uncontendedQMutex() +{ + QMutex mutex; + QBENCHMARK { + mutex.lock(); + mutex.unlock(); + } +} + +void tst_QMutex::uncontendedQMutexLocker() +{ + QMutex mutex; + QBENCHMARK { + QMutexLocker locker(&mutex); + } +} + +void tst_QMutex::contendedNative_data() +{ + QTest::addColumn("iterations"); + QTest::addColumn("msleepDuration"); + QTest::newRow("-1") << 100 << -1; + QTest::newRow("0") << 100 << 0; + QTest::newRow("1") << 10 << 1; + QTest::newRow("2") << 10 << 2; +} + +class NativeMutexThread : public QThread +{ + QSemaphore *semaphore1, *semaphore2; + NativeMutexType *mutex; + int iterations, msleepDuration; +public: + bool done; + NativeMutexThread(QSemaphore *semaphore1, QSemaphore *semaphore2, NativeMutexType *mutex, int iterations, int msleepDuration) + : semaphore1(semaphore1), semaphore2(semaphore2), mutex(mutex), iterations(iterations), msleepDuration(msleepDuration), done(false) + { } + void run() { + forever { + semaphore1->acquire(); + if (done) + break; + for (int i = 0; i < iterations; ++i) { + NativeMutexLock(mutex); + if (msleepDuration >= 0) + msleep(msleepDuration); + NativeMutexUnlock(mutex); + } + semaphore2->release(); + } + } +}; + +void tst_QMutex::contendedNative() +{ + QFETCH(int, iterations); + QFETCH(int, msleepDuration); + + QSemaphore semaphore1, semaphore2; + NativeMutexType mutex; + NativeMutexInitialize(&mutex); + + QVector threads(threadCount); + for (int i = 0; i < threads.count(); ++i) { + threads[i] = new NativeMutexThread(&semaphore1, &semaphore2, &mutex, iterations, msleepDuration); + threads[i]->start(); + } + + QBENCHMARK { + semaphore1.release(threadCount); + semaphore2.acquire(threadCount); + } + + for (int i = 0; i < threads.count(); ++i) + threads[i]->done = true; + semaphore1.release(threadCount); + for (int i = 0; i < threads.count(); ++i) + threads[i]->wait(); + qDeleteAll(threads); + + NativeMutexDestroy(&mutex); +} + +class QMutexThread : public QThread +{ + QSemaphore *semaphore1, *semaphore2; + QMutex *mutex; + int iterations, msleepDuration; +public: + bool done; + QMutexThread(QSemaphore *semaphore1, QSemaphore *semaphore2, QMutex *mutex, int iterations, int msleepDuration) + : semaphore1(semaphore1), semaphore2(semaphore2), mutex(mutex), iterations(iterations), msleepDuration(msleepDuration), done(false) + { } + void run() { + forever { + semaphore1->acquire(); + if (done) + break; + for (int i = 0; i < iterations; ++i) { + mutex->lock(); + if (msleepDuration >= 0) + msleep(msleepDuration); + mutex->unlock(); + } + semaphore2->release(); + } + } +}; + +void tst_QMutex::contendedQMutex() +{ + QFETCH(int, iterations); + QFETCH(int, msleepDuration); + QSemaphore semaphore1, semaphore2; + QMutex mutex; + + QVector threads(threadCount); + for (int i = 0; i < threads.count(); ++i) { + threads[i] = new QMutexThread(&semaphore1, &semaphore2, &mutex, iterations, msleepDuration); + threads[i]->start(); + } + + QBENCHMARK { + semaphore1.release(threadCount); + semaphore2.acquire(threadCount); + } + + for (int i = 0; i < threads.count(); ++i) + threads[i]->done = true; + semaphore1.release(threadCount); + for (int i = 0; i < threads.count(); ++i) + threads[i]->wait(); + qDeleteAll(threads); +} + +class QMutexLockerThread : public QThread +{ + QSemaphore *semaphore1, *semaphore2; + QMutex *mutex; + int iterations, msleepDuration; +public: + bool done; + QMutexLockerThread(QSemaphore *semaphore1, QSemaphore *semaphore2, QMutex *mutex, int iterations, int msleepDuration) + : semaphore1(semaphore1), semaphore2(semaphore2), mutex(mutex), iterations(iterations), msleepDuration(msleepDuration), done(false) + { } + void run() { + forever { + semaphore1->acquire(); + if (done) + break; + for (int i = 0; i < iterations; ++i) { + QMutexLocker locker(mutex); + if (msleepDuration >= 0) + msleep(msleepDuration); + } + semaphore2->release(); + } + } +}; + +void tst_QMutex::contendedQMutexLocker() +{ + QFETCH(int, iterations); + QFETCH(int, msleepDuration); + QSemaphore semaphore1, semaphore2; + QMutex mutex; + + QVector threads(threadCount); + for (int i = 0; i < threads.count(); ++i) { + threads[i] = new QMutexLockerThread(&semaphore1, &semaphore2, &mutex, iterations, msleepDuration); + threads[i]->start(); + } + + QBENCHMARK { + semaphore1.release(threadCount); + semaphore2.acquire(threadCount); + } + + for (int i = 0; i < threads.count(); ++i) + threads[i]->done = true; + semaphore1.release(threadCount); + for (int i = 0; i < threads.count(); ++i) + threads[i]->wait(); + qDeleteAll(threads); +} + QTEST_MAIN(tst_QMutex) #include "tst_qmutex.moc" -- cgit v0.12 From 2a508c6279af71c16d04ad4e764f101ea32a1c05 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Wed, 29 Sep 2010 13:42:19 +0200 Subject: Test contention performance for long (10ms) critical sections The performance should be about the same for all cases (meaning that our spinning overhead should not add too much overhead). Reviewed-by: joao --- tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp index 9ed5d55..b918014 100644 --- a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp +++ b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp @@ -214,6 +214,7 @@ void tst_QMutex::contendedNative_data() QTest::newRow("0") << 100 << 0; QTest::newRow("1") << 10 << 1; QTest::newRow("2") << 10 << 2; + QTest::newRow("10") << 10 << 10; } class NativeMutexThread : public QThread -- cgit v0.12 From 00c4e6d3d4e9196dc1c418c9269fcbed2f49dc87 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 1 Oct 2010 10:49:00 +0200 Subject: Add baseline test data to measure test overhead Also give the existing test data meaningful names Reviewed-by: joao --- tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp index b918014..7a6b45c 100644 --- a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp +++ b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp @@ -210,11 +210,12 @@ void tst_QMutex::contendedNative_data() { QTest::addColumn("iterations"); QTest::addColumn("msleepDuration"); - QTest::newRow("-1") << 100 << -1; - QTest::newRow("0") << 100 << 0; - QTest::newRow("1") << 10 << 1; - QTest::newRow("2") << 10 << 2; - QTest::newRow("10") << 10 << 10; + QTest::newRow("baseline") << 0 << -1; + QTest::newRow("no msleep") << 1000 << -1; + QTest::newRow("msleep(0)") << 1000 << 0; + QTest::newRow("msleep(1)") << 10 << 1; + QTest::newRow("msleep(2)") << 10 << 2; + QTest::newRow("msleep(10)") << 10 << 10; } class NativeMutexThread : public QThread -- cgit v0.12 From 9a18739c538013a7f2111e68e9255379cfbd9a57 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 12 Oct 2010 13:11:38 +0200 Subject: Ensure that every thread does contend in the contention tests 2 semaphore barrier is not enough to ensure that every thread does run as part of the benchmark. It is possible that a single thread, given enough time, could do all the work while the other threads remain dormant. Prevent this by making sure that the each thread rendevous with both the semaphore barriers at the start of their run(), yields after unlocking, and then rendevous again at the end. Reviewed-by: joao --- .../corelib/thread/qmutex/tst_qmutex.cpp | 93 ++++++++++++++-------- 1 file changed, 60 insertions(+), 33 deletions(-) diff --git a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp index 7a6b45c..cbfffe5 100644 --- a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp +++ b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp @@ -95,6 +95,9 @@ class tst_QMutex : public QObject int threadCount; public: + // barriers for the contended tests + static QSemaphore semaphore1, semaphore2, semaphore3, semaphore4; + tst_QMutex() { // at least 2 threads, even on single cpu/core machines @@ -119,6 +122,11 @@ private slots: void contendedQMutexLocker(); }; +QSemaphore tst_QMutex::semaphore1; +QSemaphore tst_QMutex::semaphore2; +QSemaphore tst_QMutex::semaphore3; +QSemaphore tst_QMutex::semaphore4; + void tst_QMutex::noThread_data() { QTest::addColumn("t"); @@ -220,17 +228,17 @@ void tst_QMutex::contendedNative_data() class NativeMutexThread : public QThread { - QSemaphore *semaphore1, *semaphore2; NativeMutexType *mutex; int iterations, msleepDuration; public: bool done; - NativeMutexThread(QSemaphore *semaphore1, QSemaphore *semaphore2, NativeMutexType *mutex, int iterations, int msleepDuration) - : semaphore1(semaphore1), semaphore2(semaphore2), mutex(mutex), iterations(iterations), msleepDuration(msleepDuration), done(false) + NativeMutexThread(NativeMutexType *mutex, int iterations, int msleepDuration) + : mutex(mutex), iterations(iterations), msleepDuration(msleepDuration), done(false) { } void run() { forever { - semaphore1->acquire(); + tst_QMutex::semaphore1.release(); + tst_QMutex::semaphore2.acquire(); if (done) break; for (int i = 0; i < iterations; ++i) { @@ -238,8 +246,11 @@ public: if (msleepDuration >= 0) msleep(msleepDuration); NativeMutexUnlock(mutex); + + QThread::yieldCurrentThread(); } - semaphore2->release(); + tst_QMutex::semaphore3.release(); + tst_QMutex::semaphore4.acquire(); } } }; @@ -249,24 +260,26 @@ void tst_QMutex::contendedNative() QFETCH(int, iterations); QFETCH(int, msleepDuration); - QSemaphore semaphore1, semaphore2; NativeMutexType mutex; NativeMutexInitialize(&mutex); QVector threads(threadCount); for (int i = 0; i < threads.count(); ++i) { - threads[i] = new NativeMutexThread(&semaphore1, &semaphore2, &mutex, iterations, msleepDuration); + threads[i] = new NativeMutexThread(&mutex, iterations, msleepDuration); threads[i]->start(); } QBENCHMARK { - semaphore1.release(threadCount); - semaphore2.acquire(threadCount); + semaphore1.acquire(threadCount); + semaphore2.release(threadCount); + semaphore3.acquire(threadCount); + semaphore4.release(threadCount); } for (int i = 0; i < threads.count(); ++i) threads[i]->done = true; - semaphore1.release(threadCount); + semaphore1.acquire(threadCount); + semaphore2.release(threadCount); for (int i = 0; i < threads.count(); ++i) threads[i]->wait(); qDeleteAll(threads); @@ -276,17 +289,17 @@ void tst_QMutex::contendedNative() class QMutexThread : public QThread { - QSemaphore *semaphore1, *semaphore2; QMutex *mutex; int iterations, msleepDuration; public: bool done; - QMutexThread(QSemaphore *semaphore1, QSemaphore *semaphore2, QMutex *mutex, int iterations, int msleepDuration) - : semaphore1(semaphore1), semaphore2(semaphore2), mutex(mutex), iterations(iterations), msleepDuration(msleepDuration), done(false) + QMutexThread(QMutex *mutex, int iterations, int msleepDuration) + : mutex(mutex), iterations(iterations), msleepDuration(msleepDuration), done(false) { } void run() { forever { - semaphore1->acquire(); + tst_QMutex::semaphore1.release(); + tst_QMutex::semaphore2.acquire(); if (done) break; for (int i = 0; i < iterations; ++i) { @@ -294,8 +307,11 @@ public: if (msleepDuration >= 0) msleep(msleepDuration); mutex->unlock(); + + QThread::yieldCurrentThread(); } - semaphore2->release(); + tst_QMutex::semaphore3.release(); + tst_QMutex::semaphore4.acquire(); } } }; @@ -304,23 +320,26 @@ void tst_QMutex::contendedQMutex() { QFETCH(int, iterations); QFETCH(int, msleepDuration); - QSemaphore semaphore1, semaphore2; + QMutex mutex; QVector threads(threadCount); for (int i = 0; i < threads.count(); ++i) { - threads[i] = new QMutexThread(&semaphore1, &semaphore2, &mutex, iterations, msleepDuration); + threads[i] = new QMutexThread(&mutex, iterations, msleepDuration); threads[i]->start(); } QBENCHMARK { - semaphore1.release(threadCount); - semaphore2.acquire(threadCount); + semaphore1.acquire(threadCount); + semaphore2.release(threadCount); + semaphore3.acquire(threadCount); + semaphore4.release(threadCount); } for (int i = 0; i < threads.count(); ++i) threads[i]->done = true; - semaphore1.release(threadCount); + semaphore1.acquire(threadCount); + semaphore2.release(threadCount); for (int i = 0; i < threads.count(); ++i) threads[i]->wait(); qDeleteAll(threads); @@ -328,25 +347,30 @@ void tst_QMutex::contendedQMutex() class QMutexLockerThread : public QThread { - QSemaphore *semaphore1, *semaphore2; QMutex *mutex; int iterations, msleepDuration; public: bool done; - QMutexLockerThread(QSemaphore *semaphore1, QSemaphore *semaphore2, QMutex *mutex, int iterations, int msleepDuration) - : semaphore1(semaphore1), semaphore2(semaphore2), mutex(mutex), iterations(iterations), msleepDuration(msleepDuration), done(false) + QMutexLockerThread(QMutex *mutex, int iterations, int msleepDuration) + : mutex(mutex), iterations(iterations), msleepDuration(msleepDuration), done(false) { } void run() { forever { - semaphore1->acquire(); + tst_QMutex::semaphore1.release(); + tst_QMutex::semaphore2.acquire(); if (done) break; for (int i = 0; i < iterations; ++i) { - QMutexLocker locker(mutex); - if (msleepDuration >= 0) - msleep(msleepDuration); + { + QMutexLocker locker(mutex1); + if (msleepDuration >= 0) + msleep(msleepDuration); + } + + QThread::yieldCurrentThread(); } - semaphore2->release(); + tst_QMutex::semaphore3.release(); + tst_QMutex::semaphore4.acquire(); } } }; @@ -355,23 +379,26 @@ void tst_QMutex::contendedQMutexLocker() { QFETCH(int, iterations); QFETCH(int, msleepDuration); - QSemaphore semaphore1, semaphore2; + QMutex mutex; QVector threads(threadCount); for (int i = 0; i < threads.count(); ++i) { - threads[i] = new QMutexLockerThread(&semaphore1, &semaphore2, &mutex, iterations, msleepDuration); + threads[i] = new QMutexLockerThread(&mutex, iterations, msleepDuration); threads[i]->start(); } QBENCHMARK { - semaphore1.release(threadCount); - semaphore2.acquire(threadCount); + semaphore1.acquire(threadCount); + semaphore2.release(threadCount); + semaphore3.acquire(threadCount); + semaphore4.release(threadCount); } for (int i = 0; i < threads.count(); ++i) threads[i]->done = true; - semaphore1.release(threadCount); + semaphore1.acquire(threadCount); + semaphore2.release(threadCount); for (int i = 0; i < threads.count(); ++i) threads[i]->wait(); qDeleteAll(threads); -- cgit v0.12 From 2d87a865b26250dcecbcf73178f8091e0724106d Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Wed, 13 Oct 2010 12:33:27 +0200 Subject: test contention when using 2 mutexes add test data and adapt the test harness to allow testing contention performance when using 2 mutexes (2 mutexes are often used inside of Qt, so we want to ensure that this also performs well). Reviewed-by: joao --- .../corelib/thread/qmutex/tst_qmutex.cpp | 81 ++++++++++++++-------- 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp index cbfffe5..b0c5702 100644 --- a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp +++ b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp @@ -218,22 +218,31 @@ void tst_QMutex::contendedNative_data() { QTest::addColumn("iterations"); QTest::addColumn("msleepDuration"); - QTest::newRow("baseline") << 0 << -1; - QTest::newRow("no msleep") << 1000 << -1; - QTest::newRow("msleep(0)") << 1000 << 0; - QTest::newRow("msleep(1)") << 10 << 1; - QTest::newRow("msleep(2)") << 10 << 2; - QTest::newRow("msleep(10)") << 10 << 10; + QTest::addColumn("use2mutexes"); + + QTest::newRow("baseline") << 0 << -1 << false; + + QTest::newRow("no msleep, 1 mutex") << 1000 << -1 << false; + QTest::newRow("no msleep, 2 mutexes") << 1000 << -1 << true; + QTest::newRow("msleep(0), 1 mutex") << 1000 << 0 << false; + QTest::newRow("msleep(0), 2 mutexes") << 1000 << 0 << true; + QTest::newRow("msleep(1), 1 mutex") << 10 << 1 << false; + QTest::newRow("msleep(1), 2 mutexes") << 10 << 1 << true; + QTest::newRow("msleep(2), 1 mutex") << 10 << 2 << false; + QTest::newRow("msleep(2), 2 mutexes") << 10 << 2 << true; + QTest::newRow("msleep(10), 1 mutex") << 10 << 10 << false; + QTest::newRow("msleep(10), 2 mutexes") << 10 << 10 << true; } class NativeMutexThread : public QThread { - NativeMutexType *mutex; + NativeMutexType *mutex1, *mutex2; int iterations, msleepDuration; + bool use2mutexes; public: bool done; - NativeMutexThread(NativeMutexType *mutex, int iterations, int msleepDuration) - : mutex(mutex), iterations(iterations), msleepDuration(msleepDuration), done(false) + NativeMutexThread(NativeMutexType *mutex1, NativeMutexType *mutex2, int iterations, int msleepDuration, bool use2mutexes) + : mutex1(mutex1), mutex2(mutex2), iterations(iterations), msleepDuration(msleepDuration), use2mutexes(use2mutexes), done(false) { } void run() { forever { @@ -242,10 +251,14 @@ public: if (done) break; for (int i = 0; i < iterations; ++i) { - NativeMutexLock(mutex); + NativeMutexLock(mutex1); + if (use2mutexes) + NativeMutexLock(mutex2); if (msleepDuration >= 0) msleep(msleepDuration); - NativeMutexUnlock(mutex); + if (use2mutexes) + NativeMutexUnlock(mutex2); + NativeMutexUnlock(mutex1); QThread::yieldCurrentThread(); } @@ -259,13 +272,15 @@ void tst_QMutex::contendedNative() { QFETCH(int, iterations); QFETCH(int, msleepDuration); + QFETCH(bool, use2mutexes); - NativeMutexType mutex; - NativeMutexInitialize(&mutex); + NativeMutexType mutex1, mutex2; + NativeMutexInitialize(&mutex1); + NativeMutexInitialize(&mutex2); QVector threads(threadCount); for (int i = 0; i < threads.count(); ++i) { - threads[i] = new NativeMutexThread(&mutex, iterations, msleepDuration); + threads[i] = new NativeMutexThread(&mutex1, &mutex2, iterations, msleepDuration, use2mutexes); threads[i]->start(); } @@ -284,17 +299,19 @@ void tst_QMutex::contendedNative() threads[i]->wait(); qDeleteAll(threads); - NativeMutexDestroy(&mutex); + NativeMutexDestroy(&mutex1); + NativeMutexDestroy(&mutex2); } class QMutexThread : public QThread { - QMutex *mutex; + QMutex *mutex1, *mutex2; int iterations, msleepDuration; + bool use2mutexes; public: bool done; - QMutexThread(QMutex *mutex, int iterations, int msleepDuration) - : mutex(mutex), iterations(iterations), msleepDuration(msleepDuration), done(false) + QMutexThread(QMutex *mutex1, QMutex *mutex2, int iterations, int msleepDuration, bool use2mutexes) + : mutex1(mutex1), mutex2(mutex2), iterations(iterations), msleepDuration(msleepDuration), use2mutexes(use2mutexes), done(false) { } void run() { forever { @@ -303,10 +320,14 @@ public: if (done) break; for (int i = 0; i < iterations; ++i) { - mutex->lock(); + mutex1->lock(); + if (use2mutexes) + mutex2->lock(); if (msleepDuration >= 0) msleep(msleepDuration); - mutex->unlock(); + if (use2mutexes) + mutex2->unlock(); + mutex1->unlock(); QThread::yieldCurrentThread(); } @@ -320,12 +341,13 @@ void tst_QMutex::contendedQMutex() { QFETCH(int, iterations); QFETCH(int, msleepDuration); + QFETCH(bool, use2mutexes); - QMutex mutex; + QMutex mutex1, mutex2; QVector threads(threadCount); for (int i = 0; i < threads.count(); ++i) { - threads[i] = new QMutexThread(&mutex, iterations, msleepDuration); + threads[i] = new QMutexThread(&mutex1, &mutex2, iterations, msleepDuration, use2mutexes); threads[i]->start(); } @@ -347,12 +369,13 @@ void tst_QMutex::contendedQMutex() class QMutexLockerThread : public QThread { - QMutex *mutex; + QMutex *mutex1, *mutex2; int iterations, msleepDuration; + bool use2mutexes; public: bool done; - QMutexLockerThread(QMutex *mutex, int iterations, int msleepDuration) - : mutex(mutex), iterations(iterations), msleepDuration(msleepDuration), done(false) + QMutexLockerThread(QMutex *mutex1, QMutex *mutex2, int iterations, int msleepDuration, bool use2mutexes) + : mutex1(mutex1), mutex2(mutex2), iterations(iterations), msleepDuration(msleepDuration), use2mutexes(use2mutexes), done(false) { } void run() { forever { @@ -362,7 +385,8 @@ public: break; for (int i = 0; i < iterations; ++i) { { - QMutexLocker locker(mutex1); + QMutexLocker locker1(mutex1); + QMutexLocker locker2(use2mutexes ? mutex2 : 0); if (msleepDuration >= 0) msleep(msleepDuration); } @@ -379,12 +403,13 @@ void tst_QMutex::contendedQMutexLocker() { QFETCH(int, iterations); QFETCH(int, msleepDuration); + QFETCH(bool, use2mutexes); - QMutex mutex; + QMutex mutex1, mutex2; QVector threads(threadCount); for (int i = 0; i < threads.count(); ++i) { - threads[i] = new QMutexLockerThread(&mutex, iterations, msleepDuration); + threads[i] = new QMutexLockerThread(&mutex1, &mutex2, iterations, msleepDuration, use2mutexes); threads[i]->start(); } -- cgit v0.12 From d9e35493d494df60d771a928a8d0dbde2b66906e Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 16 Sep 2010 10:50:25 +0200 Subject: Move contender count maintenance to QMutexPrivate Make the cross-platform implementation of QMutex in qmutex.cpp only use testAndSetAcquire(0, 1) and testAndSetRelease(1, 0) like in the new inline functions in qmutex.h This will allow us to open up for more platform-specific optimizations to improve performance of contended QMutexes. Reviewed-by: joao --- src/corelib/thread/qmutex.cpp | 43 ++++++++------------------------------ src/corelib/thread/qmutex_unix.cpp | 5 +++++ src/corelib/thread/qmutex_win.cpp | 8 ++++++- 3 files changed, 21 insertions(+), 35 deletions(-) diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index b85a22d..403468a 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -157,15 +157,12 @@ void QMutex::lock() return; } - bool isLocked = d->contenders.fetchAndAddAcquire(1) == 0; + bool isLocked = d->contenders.testAndSetAcquire(0, 1); if (!isLocked) { // didn't get the lock, wait for it isLocked = d->wait(); Q_ASSERT_X(isLocked, "QMutex::lock", "Internal error, infinite wait has timed out."); - - // don't need to wait for the lock anymore - d->contenders.deref(); } d->owner = self; @@ -174,8 +171,7 @@ void QMutex::lock() return; } - - bool isLocked = d->contenders == 0 && d->contenders.testAndSetAcquire(0, 1); + bool isLocked = d->contenders.testAndSetAcquire(0, 1); if (!isLocked) { lockInternal(); } @@ -211,7 +207,7 @@ bool QMutex::tryLock() return true; } - bool isLocked = d->contenders == 0 && d->contenders.testAndSetAcquire(0, 1); + bool isLocked = d->contenders.testAndSetAcquire(0, 1); if (!isLocked) { // some other thread has the mutex locked, or we tried to // recursively lock an non-recursive mutex @@ -224,13 +220,7 @@ bool QMutex::tryLock() return isLocked; } - bool isLocked = d->contenders == 0 && d->contenders.testAndSetAcquire(0, 1); - if (!isLocked) { - // some other thread has the mutex locked, or we tried to - // recursively lock an non-recursive mutex - return isLocked; - } - return isLocked; + return d->contenders.testAndSetAcquire(0, 1); } /*! \overload @@ -269,13 +259,10 @@ bool QMutex::tryLock(int timeout) return true; } - bool isLocked = d->contenders.fetchAndAddAcquire(1) == 0; + bool isLocked = d->contenders.testAndSetAcquire(0, 1); if (!isLocked) { // didn't get the lock, wait for it isLocked = d->wait(timeout); - - // don't need to wait for the lock anymore - d->contenders.deref(); if (!isLocked) return false; } @@ -286,17 +273,9 @@ bool QMutex::tryLock(int timeout) return true; } - bool isLocked = d->contenders.fetchAndAddAcquire(1) == 0; - if (!isLocked) { - // didn't get the lock, wait for it - isLocked = d->wait(timeout); - - // don't need to wait for the lock anymore - d->contenders.deref(); - if (!isLocked) - return false; - } - return true; + return (d->contenders.testAndSetAcquire(0, 1) + // didn't get the lock, wait for it + || d->wait(timeout)); } @@ -310,7 +289,6 @@ bool QMutex::tryLock(int timeout) void QMutex::unlock() { QMutexPrivate *d = static_cast(this->d); - if (d->recursive) { if (!--d->count) { d->owner = 0; @@ -460,16 +438,13 @@ void QMutex::lockInternal() do { if (spinCount++ > maximumSpinCount) { // puts("spinning useless, sleeping"); - bool isLocked = d->contenders.fetchAndAddAcquire(1) == 0; + bool isLocked = d->contenders.testAndSetAcquire(0, 1); if (!isLocked) { // didn't get the lock, wait for it isLocked = d->wait(); Q_ASSERT_X(isLocked, "QMutex::lock", "Internal error, infinite wait has timed out."); - - // don't need to wait for the lock anymore - d->contenders.deref(); } // decrease the lastSpinCount since we didn't actually get the lock by spinning spinCount = -d->lastSpinCount / SpinCountPenalizationDivisor; diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index 7e7ef22..dcf8b9f 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -77,6 +77,10 @@ QMutexPrivate::~QMutexPrivate() bool QMutexPrivate::wait(int timeout) { + if (contenders.fetchAndAddAcquire(1) == 0) { + // lock acquired without waiting + return true; + } report_error(pthread_mutex_lock(&mutex), "QMutex::lock", "mutex lock"); int errorCode = 0; while (!wakeup) { @@ -101,6 +105,7 @@ bool QMutexPrivate::wait(int timeout) } wakeup = false; report_error(pthread_mutex_unlock(&mutex), "QMutex::lock", "mutex unlock"); + contenders.deref(); return errorCode == 0; } diff --git a/src/corelib/thread/qmutex_win.cpp b/src/corelib/thread/qmutex_win.cpp index a810000..c278f04 100644 --- a/src/corelib/thread/qmutex_win.cpp +++ b/src/corelib/thread/qmutex_win.cpp @@ -60,7 +60,13 @@ QMutexPrivate::~QMutexPrivate() bool QMutexPrivate::wait(int timeout) { - return WaitForSingleObject(event, timeout < 0 ? INFINITE : timeout) == WAIT_OBJECT_0; + if (contenders.fetchAndAddAcquire(1) == 0) { + // lock acquired without waiting + return true; + } + bool returnValue = (WaitForSingleObject(event, timeout < 0 ? INFINITE : timeout) == WAIT_OBJECT_0); + contenders.deref(); + return returnValue; } void QMutexPrivate::wakeUp() -- cgit v0.12 From feb0b0cd47808a77a048c6a13686d39a0540a488 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 1 Oct 2010 09:44:55 +0200 Subject: Remove unnecessary testAndSetAcquire from QMutex::lockInternal() QMutexPrivate::wait() will take care of doing another test for the lock before putting the thread to sleep, so we can avoid another if(). Reviewed-by: joao --- src/corelib/thread/qmutex.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 403468a..19e2457 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -437,15 +437,12 @@ void QMutex::lockInternal() do { if (spinCount++ > maximumSpinCount) { - // puts("spinning useless, sleeping"); - bool isLocked = d->contenders.testAndSetAcquire(0, 1); - if (!isLocked) { - - // didn't get the lock, wait for it - isLocked = d->wait(); - Q_ASSERT_X(isLocked, "QMutex::lock", - "Internal error, infinite wait has timed out."); - } + // didn't get the lock, wait for it + bool isLocked = d->wait(); + Q_ASSERT_X(isLocked, "QMutex::lock", + "Internal error, infinite wait has timed out."); + Q_UNUSED(isLocked); + // decrease the lastSpinCount since we didn't actually get the lock by spinning spinCount = -d->lastSpinCount / SpinCountPenalizationDivisor; break; -- cgit v0.12 From 87bab705ded31559941020d3c500f43f571f9c16 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 1 Oct 2010 09:45:42 +0200 Subject: Disable spinning under lock contention on single CPU machines Spinning is just wasted time on these systems. Reviewed-by: joao --- src/corelib/thread/qmutex.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 19e2457..54b3ed4 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -429,6 +429,16 @@ void QMutex::unlock() void QMutex::lockInternal() { QMutexPrivate *d = static_cast(this->d); + + if (QThread::idealThreadCount() == 1) { + // don't spin on single cpu machines + bool isLocked = d->wait(); + Q_ASSERT_X(isLocked, "QMutex::lock", + "Internal error, infinite wait has timed out."); + Q_UNUSED(isLocked); + return; + } + int spinCount = 0; int lastSpinCount = d->lastSpinCount; -- cgit v0.12 From cf17b743d2fe84ab259b7232ab07b58a1872e18e Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 16 Sep 2010 15:46:43 +0200 Subject: Improve QMutex contention performance on Mac OS X Use a Mach semaphore to implement QMutexPrivate::wait() and ::wakeup(). This makes QMutex perform more or less identically the same as pthread_mutex_t when contended. Reviewed-by: joao --- src/corelib/thread/qmutex_p.h | 8 +++++- src/corelib/thread/qmutex_unix.cpp | 53 +++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index 57a6062..e23be94 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -58,6 +58,10 @@ #include #include +#if defined(Q_OS_MAC) +# include +#endif + QT_BEGIN_NAMESPACE class QMutexPrivate : public QMutexData { @@ -72,7 +76,9 @@ public: Qt::HANDLE owner; uint count; -#if defined(Q_OS_UNIX) +#if defined(Q_OS_MAC) + semaphore_t mach_semaphore; +#elif defined(Q_OS_UNIX) volatile bool wakeup; pthread_mutex_t mutex; pthread_cond_t cond; diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index dcf8b9f..ce1bfc2 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -53,28 +53,77 @@ #undef wakeup #endif +#if defined(Q_OS_MAC) +# include +# include +#endif + QT_BEGIN_NAMESPACE +#if !defined(Q_OS_MAC) static void report_error(int code, const char *where, const char *what) { if (code != 0) qWarning("%s: %s failure: %s", where, what, qPrintable(qt_error_string(code))); } +#endif QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) - : QMutexData(mode), lastSpinCount(0), owner(0), count(0), wakeup(false) + : QMutexData(mode), lastSpinCount(0), owner(0), count(0) { +#if defined(Q_OS_MAC) + kern_return_t r = semaphore_create(mach_task_self(), &mach_semaphore, SYNC_POLICY_FIFO, 0); + if (r != KERN_SUCCESS) + qWarning("QMutex: failed to create semaphore, error %d", r); +#else + wakeup = false; report_error(pthread_mutex_init(&mutex, NULL), "QMutex", "mutex init"); report_error(pthread_cond_init(&cond, NULL), "QMutex", "cv init"); +#endif } QMutexPrivate::~QMutexPrivate() { +#if defined(Q_OS_MAC) + kern_return_t r = semaphore_destroy(mach_task_self(), mach_semaphore); + if (r != KERN_SUCCESS) + qWarning("QMutex: failed to destroy semaphore, error %d", r); +#else report_error(pthread_cond_destroy(&cond), "QMutex", "cv destroy"); report_error(pthread_mutex_destroy(&mutex), "QMutex", "mutex destroy"); +#endif } +#if defined(Q_OS_MAC) + +bool QMutexPrivate::wait(int timeout) +{ + if (contenders.fetchAndAddAcquire(1) == 0) { + // lock acquired without waiting + return true; + } + bool returnValue; + if (timeout < 0) { + returnValue = semaphore_wait(mach_semaphore) == KERN_SUCCESS; + } else { + mach_timespec_t ts; + ts.tv_nsec = ((timeout % 1000) * 1000) * 1000; + ts.tv_sec = (timeout / 1000); + kern_return_t r = semaphore_timedwait(mach_semaphore, ts); + returnValue = r == KERN_SUCCESS; + } + contenders.deref(); + return returnValue; +} + +void QMutexPrivate::wakeUp() +{ + semaphore_signal(mach_semaphore); +} + +#else // !Q_OS_MAC + bool QMutexPrivate::wait(int timeout) { if (contenders.fetchAndAddAcquire(1) == 0) { @@ -117,6 +166,8 @@ void QMutexPrivate::wakeUp() report_error(pthread_mutex_unlock(&mutex), "QMutex::unlock", "mutex unlock"); } +#endif // !Q_OS_MAC + QT_END_NAMESPACE #endif // QT_NO_THREAD -- cgit v0.12 From 8a7b5aca7b6575013a4e4ee9b99808d25edf6fdf Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Mon, 27 Sep 2010 15:19:45 +0200 Subject: Improve QMutex contention performance on Linux Use futex(2) to implement QMutexPrivate::wait() and ::wakeup(). This makes QMutex perform more or less identically the same as pthread_mutex_t when contended. We have to use the contender count in a different way due to the way that futex() waiting works. Waiting on a futex atomically checks that the value has not changed from the expected value and then puts the thread to sleep. So, on Linux, the contender QAtomicInt will only ever be one of three values: 0 for unlocked, 1 for locked, 2 for contended. This does mean that there is a slight chance for unfairness due to the fetch-and-store to zero in the wakeUp() function, but unfortunately this cannot be avoid as the code is now. Reviewed-by: joao --- src/corelib/thread/qmutex_p.h | 2 +- src/corelib/thread/qmutex_unix.cpp | 43 +++++++++++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index e23be94..2d45cfb 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -78,7 +78,7 @@ public: #if defined(Q_OS_MAC) semaphore_t mach_semaphore; -#elif defined(Q_OS_UNIX) +#elif defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) volatile bool wakeup; pthread_mutex_t mutex; pthread_cond_t cond; diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index ce1bfc2..e872187 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -56,11 +56,15 @@ #if defined(Q_OS_MAC) # include # include +#elif defined(Q_OS_LINUX) +# include +# include +# include #endif QT_BEGIN_NAMESPACE -#if !defined(Q_OS_MAC) +#if !defined(Q_OS_MAC) && !defined(Q_OS_LINUX) static void report_error(int code, const char *where, const char *what) { if (code != 0) @@ -76,7 +80,7 @@ QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) kern_return_t r = semaphore_create(mach_task_self(), &mach_semaphore, SYNC_POLICY_FIFO, 0); if (r != KERN_SUCCESS) qWarning("QMutex: failed to create semaphore, error %d", r); -#else +#elif !defined(Q_OS_LINUX) wakeup = false; report_error(pthread_mutex_init(&mutex, NULL), "QMutex", "mutex init"); report_error(pthread_cond_init(&cond, NULL), "QMutex", "cv init"); @@ -89,7 +93,7 @@ QMutexPrivate::~QMutexPrivate() kern_return_t r = semaphore_destroy(mach_task_self(), mach_semaphore); if (r != KERN_SUCCESS) qWarning("QMutex: failed to destroy semaphore, error %d", r); -#else +#elif !defined(Q_OS_LINUX) report_error(pthread_cond_destroy(&cond), "QMutex", "cv destroy"); report_error(pthread_mutex_destroy(&mutex), "QMutex", "mutex destroy"); #endif @@ -122,7 +126,36 @@ void QMutexPrivate::wakeUp() semaphore_signal(mach_semaphore); } -#else // !Q_OS_MAC +#elif defined(Q_OS_LINUX) + +static inline int _q_futex(volatile int *addr, int op, int val, const struct timespec *timeout, int *addr2, int val2) +{ + return syscall(SYS_futex, addr, op, val, timeout, addr2, val2); +} + +bool QMutexPrivate::wait(int timeout) +{ + while (contenders.fetchAndStoreAcquire(2) > 0) { + struct timespec ts, *pts = 0; + if (timeout >= 0) { + ts.tv_nsec = ((timeout % 1000) * 1000) * 1000; + ts.tv_sec = (timeout / 1000); + pts = &ts; + } + int r = _q_futex(&contenders._q_value, FUTEX_WAIT, 2, pts, 0, 0); + if (r != 0 && errno == ETIMEDOUT) + return false; + } + return true; +} + +void QMutexPrivate::wakeUp() +{ + (void) contenders.fetchAndStoreRelease(0); + (void) _q_futex(&contenders._q_value, FUTEX_WAKE, 1, 0, 0, 0); +} + +#else // !Q_OS_MAC && !Q_OS_LINUX bool QMutexPrivate::wait(int timeout) { @@ -166,7 +199,7 @@ void QMutexPrivate::wakeUp() report_error(pthread_mutex_unlock(&mutex), "QMutex::unlock", "mutex unlock"); } -#endif // !Q_OS_MAC +#endif // !Q_OS_MAC && !Q_OS_LINUX QT_END_NAMESPACE -- cgit v0.12 From 3b6a84de5c5ed2e1970ad2b396292babb9173227 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 1 Oct 2010 09:50:22 +0200 Subject: Optimize adaptive spinning mutex code Change the adaptive spinning code to be elapsed time based instead of iteration based. The new approach will quickly reduce the amount of allowed spinning time when it detects that lock contention is resolved by waiting instead of spinning. We get better results by dynamically adjusting for elapsed running time instead of trying to fine tune iteration counts that won't work for all CPU types, speeds, etc. From observation, lock performance suffers if the spin time is higher than the minimum wait time. Because of this, QMutex never increases the spin time, it only reduces the spin time to the minimum observed wait time. For very long wait times, we disable spinning completely (and always resolve contention by waiting). Use QThread::yieldCurrentThread() when spinning on a contended mutex. Comment from the code: be a good citizen... yielding lets something else run if there is something to run, but may also relieve memory pressure if not. Reviewed-by: joao --- src/corelib/thread/qmutex.cpp | 36 ++++++++++++++++++++---------------- src/corelib/thread/qmutex_p.h | 4 +++- src/corelib/thread/qmutex_unix.cpp | 2 +- src/corelib/thread/qmutex_win.cpp | 2 +- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 54b3ed4..72f87b7 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -45,6 +45,7 @@ #ifndef QT_NO_THREAD #include "qatomic.h" +#include "qelapsedtimer.h" #include "qthread.h" #include "qmutex_p.h" @@ -439,31 +440,34 @@ void QMutex::lockInternal() return; } - int spinCount = 0; - int lastSpinCount = d->lastSpinCount; - - enum { AdditionalSpins = 20, SpinCountPenalizationDivisor = 4 }; - const int maximumSpinCount = lastSpinCount + AdditionalSpins; - + QElapsedTimer elapsedTimer; + elapsedTimer.start(); do { - if (spinCount++ > maximumSpinCount) { - // didn't get the lock, wait for it + if (elapsedTimer.hasExpired(d->maximumSpinTime)) { + // didn't get the lock, wait for it, since we're not going to gain anything by spinning more + int spinTime = elapsedTimer.restart(); bool isLocked = d->wait(); Q_ASSERT_X(isLocked, "QMutex::lock", "Internal error, infinite wait has timed out."); Q_UNUSED(isLocked); - // decrease the lastSpinCount since we didn't actually get the lock by spinning - spinCount = -d->lastSpinCount / SpinCountPenalizationDivisor; - break; + int maximumSpinTime = d->maximumSpinTime; + int waitTime = elapsedTimer.elapsed(); + // adjust the spin count when spinning does not benefit contention performance + if (spinTime + waitTime > QMutexPrivate::MaximumSpinTimeThreshold) { + // long waits, stop spinning + d->maximumSpinTime = 0; + } else if (waitTime < maximumSpinTime) { + // never spin more than the minimum wait time (otherwise we may perform worse) + d->maximumSpinTime = waitTime; + } + return; } + // be a good citizen... yielding lets something else run if there is something to run, but may also relieve memory pressure if not + QThread::yieldCurrentThread(); } while (d->contenders != 0 || !d->contenders.testAndSetAcquire(0, 1)); - // adjust the last spin lock count - lastSpinCount = d->lastSpinCount; - d->lastSpinCount = spinCount >= 0 - ? qMax(lastSpinCount, spinCount) - : lastSpinCount + spinCount; + // spinning is working, do not change the spin time } /*! diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index 2d45cfb..6de42ad 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -72,7 +72,9 @@ public: bool wait(int timeout = -1); void wakeUp(); - volatile int lastSpinCount; + // half of a frame (in ms) at 60fps + enum { MaximumSpinTimeThreshold = 8 }; + volatile int maximumSpinTime; Qt::HANDLE owner; uint count; diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index e872187..48014cc 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -74,7 +74,7 @@ static void report_error(int code, const char *where, const char *what) QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) - : QMutexData(mode), lastSpinCount(0), owner(0), count(0) + : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), owner(0), count(0) { #if defined(Q_OS_MAC) kern_return_t r = semaphore_create(mach_task_self(), &mach_semaphore, SYNC_POLICY_FIFO, 0); diff --git a/src/corelib/thread/qmutex_win.cpp b/src/corelib/thread/qmutex_win.cpp index c278f04..89e8b87 100644 --- a/src/corelib/thread/qmutex_win.cpp +++ b/src/corelib/thread/qmutex_win.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) - : QMutexData(mode), lastSpinCount(0), owner(0), count(0) + : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), owner(0), count(0) { event = CreateEvent(0, FALSE, FALSE, 0); if (!event) -- cgit v0.12 From 6c1180505a0ac55bfd0eac87c2a61103a8fdec14 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 1 Oct 2010 10:21:10 +0200 Subject: Store and track spin times in nanosecond resolution Use the new QElapsedTimer::nsecsElapsed() and store all values in qint64 instead of int. The maximum spin time threshold is now 1000000ns, or 1ms. Spinning for longer than 1ms is just a waste of time, CPU, and battery. Reviewed-by: joao --- src/corelib/thread/qmutex.cpp | 9 +++++---- src/corelib/thread/qmutex_p.h | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 72f87b7..03e623f 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -443,16 +443,17 @@ void QMutex::lockInternal() QElapsedTimer elapsedTimer; elapsedTimer.start(); do { - if (elapsedTimer.hasExpired(d->maximumSpinTime)) { + qint64 spinTime = elapsedTimer.nsecsElapsed(); + if (spinTime > d->maximumSpinTime) { // didn't get the lock, wait for it, since we're not going to gain anything by spinning more - int spinTime = elapsedTimer.restart(); + elapsedTimer.start(); bool isLocked = d->wait(); Q_ASSERT_X(isLocked, "QMutex::lock", "Internal error, infinite wait has timed out."); Q_UNUSED(isLocked); - int maximumSpinTime = d->maximumSpinTime; - int waitTime = elapsedTimer.elapsed(); + qint64 maximumSpinTime = d->maximumSpinTime; + qint64 waitTime = elapsedTimer.nsecsElapsed(); // adjust the spin count when spinning does not benefit contention performance if (spinTime + waitTime > QMutexPrivate::MaximumSpinTimeThreshold) { // long waits, stop spinning diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index 6de42ad..fa6e879 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -72,9 +72,9 @@ public: bool wait(int timeout = -1); void wakeUp(); - // half of a frame (in ms) at 60fps - enum { MaximumSpinTimeThreshold = 8 }; - volatile int maximumSpinTime; + // 1ms = 1000000ns + enum { MaximumSpinTimeThreshold = 1000000 }; + volatile qint64 maximumSpinTime; Qt::HANDLE owner; uint count; -- cgit v0.12 From 44cf2baeb07bf48270a6a41c8f1433517130ba01 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 1 Oct 2010 10:22:10 +0200 Subject: Track average wait times under our maximum spin time threshold Further observation shows that spin times slightly over the average wait time produce the best results. This change keeps a heavily weighted average of the wait times under 1.5ms (1.5 times the max spin threshold), and adjusts the spin time to be 150% of the average wait time. Introduce spin time adjustments when spin locking works, and adjust to between 150% of the average wait time and the maximum threshold. Reviewed-by: joao --- src/corelib/thread/qmutex.cpp | 24 ++++++++++++++++++------ src/corelib/thread/qmutex_p.h | 1 + src/corelib/thread/qmutex_unix.cpp | 2 +- src/corelib/thread/qmutex_win.cpp | 2 +- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 03e623f..1009f7b 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -453,14 +453,20 @@ void QMutex::lockInternal() Q_UNUSED(isLocked); qint64 maximumSpinTime = d->maximumSpinTime; - qint64 waitTime = elapsedTimer.nsecsElapsed(); + qint64 averageWaitTime = d->averageWaitTime; + qint64 actualWaitTime = elapsedTimer.nsecsElapsed(); + if (actualWaitTime < (QMutexPrivate::MaximumSpinTimeThreshold * 3 / 2)) { + // measure the wait times + averageWaitTime = d->averageWaitTime = qMin((averageWaitTime + actualWaitTime) / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold)); + } + // adjust the spin count when spinning does not benefit contention performance - if (spinTime + waitTime > QMutexPrivate::MaximumSpinTimeThreshold) { + if ((spinTime + actualWaitTime) - qint64(QMutexPrivate::MaximumSpinTimeThreshold) >= qint64(QMutexPrivate::MaximumSpinTimeThreshold)) { // long waits, stop spinning d->maximumSpinTime = 0; - } else if (waitTime < maximumSpinTime) { - // never spin more than the minimum wait time (otherwise we may perform worse) - d->maximumSpinTime = waitTime; + } else { + // allow spinning if wait times decrease, but never spin more than the average wait time (otherwise we may perform worse) + d->maximumSpinTime = qBound(qint64(averageWaitTime * 3 / 2), maximumSpinTime / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold)); } return; } @@ -468,7 +474,13 @@ void QMutex::lockInternal() QThread::yieldCurrentThread(); } while (d->contenders != 0 || !d->contenders.testAndSetAcquire(0, 1)); - // spinning is working, do not change the spin time + // spinning is working, do not change the spin time (unless we are using much less time than allowed to spin) + qint64 maximumSpinTime = d->maximumSpinTime; + qint64 spinTime = elapsedTimer.nsecsElapsed(); + if (spinTime < maximumSpinTime / 2) { + // we are using much less time than we need, adjust the limit + d->maximumSpinTime = qBound(qint64(d->averageWaitTime * 3 / 2), maximumSpinTime / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold)); + } } /*! diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index fa6e879..9d40bea 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -75,6 +75,7 @@ public: // 1ms = 1000000ns enum { MaximumSpinTimeThreshold = 1000000 }; volatile qint64 maximumSpinTime; + volatile qint64 averageWaitTime; Qt::HANDLE owner; uint count; diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index 48014cc..0e09ea0 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -74,7 +74,7 @@ static void report_error(int code, const char *where, const char *what) QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) - : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), owner(0), count(0) + : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), averageWaitTime(0), owner(0), count(0) { #if defined(Q_OS_MAC) kern_return_t r = semaphore_create(mach_task_self(), &mach_semaphore, SYNC_POLICY_FIFO, 0); diff --git a/src/corelib/thread/qmutex_win.cpp b/src/corelib/thread/qmutex_win.cpp index 89e8b87..a759caa 100644 --- a/src/corelib/thread/qmutex_win.cpp +++ b/src/corelib/thread/qmutex_win.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) - : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), owner(0), count(0) + : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), averageWaitTime(0), owner(0), count(0) { event = CreateEvent(0, FALSE, FALSE, 0); if (!event) -- cgit v0.12 From 5963b2b92829035d14ab9f5fc5f65dec9460d969 Mon Sep 17 00:00:00 2001 From: Harald Fernengel Date: Tue, 21 Dec 2010 11:14:26 +0100 Subject: Add inter-process binary shader cache for MeeGo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch significantly reduces MeeGo app startup times by caching binary shaders in a shared memory segment. Reviewed-by: Robert Griebl Reviewed-by: Samuel Rødal --- .../gl2paintengineex/qglengineshadermanager.cpp | 294 +++++++------ .../gl2paintengineex/qglshadercache_meego_p.h | 457 +++++++++++++++++++++ src/opengl/gl2paintengineex/qglshadercache_p.h | 98 +++++ src/opengl/opengl.pro | 4 +- src/opengl/util/meego/main.cpp | 48 +++ .../util/meego/shader-cache-introspector.pro | 7 + 6 files changed, 771 insertions(+), 137 deletions(-) create mode 100644 src/opengl/gl2paintengineex/qglshadercache_meego_p.h create mode 100644 src/opengl/gl2paintengineex/qglshadercache_p.h create mode 100644 src/opengl/util/meego/main.cpp create mode 100644 src/opengl/util/meego/shader-cache-introspector.pro diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index 93ff3f4..0723c28 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -42,6 +42,7 @@ #include "qglengineshadermanager_p.h" #include "qglengineshadersource_p.h" #include "qpaintengineex_opengl2_p.h" +#include "qglshadercache_p.h" #if defined(QT_DEBUG) #include @@ -170,64 +171,92 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) QGLShader* fragShader; QGLShader* vertexShader; - QByteArray source; + QByteArray vertexSource; + QByteArray fragSource; // Compile up the simple shader: - source.clear(); - source.append(qShaderSnippets[MainVertexShader]); - source.append(qShaderSnippets[PositionOnlyVertexShader]); - vertexShader = new QGLShader(QGLShader::Vertex, context, 0); - shaders.append(vertexShader); - if (!vertexShader->compileSourceCode(source)) - qWarning("Vertex shader for simpleShaderProg (MainVertexShader & PositionOnlyVertexShader) failed to compile"); - - source.clear(); - source.append(qShaderSnippets[MainFragmentShader]); - source.append(qShaderSnippets[ShockingPinkSrcFragmentShader]); - fragShader = new QGLShader(QGLShader::Fragment, context, 0); - shaders.append(fragShader); - if (!fragShader->compileSourceCode(source)) - qWarning("Fragment shader for simpleShaderProg (MainFragmentShader & ShockingPinkSrcFragmentShader) failed to compile"); + vertexSource.append(qShaderSnippets[MainVertexShader]); + vertexSource.append(qShaderSnippets[PositionOnlyVertexShader]); + + fragSource.append(qShaderSnippets[MainFragmentShader]); + fragSource.append(qShaderSnippets[ShockingPinkSrcFragmentShader]); simpleShaderProg = new QGLShaderProgram(context, 0); - simpleShaderProg->addShader(vertexShader); - simpleShaderProg->addShader(fragShader); - simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); - simpleShaderProg->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR); - simpleShaderProg->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR); - simpleShaderProg->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR); + + CachedShader simpleShaderCache(fragSource, vertexSource); + + bool inCache = simpleShaderCache.load(simpleShaderProg, context); + + if (!inCache) { + vertexShader = new QGLShader(QGLShader::Vertex, context, 0); + shaders.append(vertexShader); + if (!vertexShader->compileSourceCode(vertexSource)) + qWarning("Vertex shader for simpleShaderProg (MainVertexShader & PositionOnlyVertexShader) failed to compile"); + + fragShader = new QGLShader(QGLShader::Fragment, context, 0); + shaders.append(fragShader); + if (!fragShader->compileSourceCode(fragSource)) + qWarning("Fragment shader for simpleShaderProg (MainFragmentShader & ShockingPinkSrcFragmentShader) failed to compile"); + + simpleShaderProg->addShader(vertexShader); + simpleShaderProg->addShader(fragShader); + + simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); + simpleShaderProg->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR); + simpleShaderProg->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR); + simpleShaderProg->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR); + } + simpleShaderProg->link(); - if (!simpleShaderProg->isLinked()) { + + if (simpleShaderProg->isLinked()) { + if (!inCache) + simpleShaderCache.store(simpleShaderProg, context); + } else { qCritical() << "Errors linking simple shader:" << simpleShaderProg->log(); } // Compile the blit shader: - source.clear(); - source.append(qShaderSnippets[MainWithTexCoordsVertexShader]); - source.append(qShaderSnippets[UntransformedPositionVertexShader]); - vertexShader = new QGLShader(QGLShader::Vertex, context, 0); - shaders.append(vertexShader); - if (!vertexShader->compileSourceCode(source)) - qWarning("Vertex shader for blitShaderProg (MainWithTexCoordsVertexShader & UntransformedPositionVertexShader) failed to compile"); - - source.clear(); - source.append(qShaderSnippets[MainFragmentShader]); - source.append(qShaderSnippets[ImageSrcFragmentShader]); - fragShader = new QGLShader(QGLShader::Fragment, context, 0); - shaders.append(fragShader); - if (!fragShader->compileSourceCode(source)) - qWarning("Fragment shader for blitShaderProg (MainFragmentShader & ImageSrcFragmentShader) failed to compile"); + vertexSource.clear(); + vertexSource.append(qShaderSnippets[MainWithTexCoordsVertexShader]); + vertexSource.append(qShaderSnippets[UntransformedPositionVertexShader]); + + fragSource.clear(); + fragSource.append(qShaderSnippets[MainFragmentShader]); + fragSource.append(qShaderSnippets[ImageSrcFragmentShader]); blitShaderProg = new QGLShaderProgram(context, 0); - blitShaderProg->addShader(vertexShader); - blitShaderProg->addShader(fragShader); - blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); - blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); + + CachedShader blitShaderCache(fragSource, vertexSource); + + inCache = blitShaderCache.load(blitShaderProg, context); + + if (!inCache) { + vertexShader = new QGLShader(QGLShader::Vertex, context, 0); + shaders.append(vertexShader); + if (!vertexShader->compileSourceCode(vertexSource)) + qWarning("Vertex shader for blitShaderProg (MainWithTexCoordsVertexShader & UntransformedPositionVertexShader) failed to compile"); + + fragShader = new QGLShader(QGLShader::Fragment, context, 0); + shaders.append(fragShader); + if (!fragShader->compileSourceCode(fragSource)) + qWarning("Fragment shader for blitShaderProg (MainFragmentShader & ImageSrcFragmentShader) failed to compile"); + + blitShaderProg->addShader(vertexShader); + blitShaderProg->addShader(fragShader); + + blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); + blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); + } + blitShaderProg->link(); - if (!blitShaderProg->isLinked()) { + if (blitShaderProg->isLinked()) { + if (!inCache) + blitShaderCache.store(blitShaderProg, context); + } else { qCritical() << "Errors linking blit shader:" - << simpleShaderProg->log(); + << blitShaderProg->log(); } #ifdef QT_GL_SHARED_SHADER_DEBUG @@ -279,101 +308,110 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS } } - QGLShader *vertexShader = 0; - QGLShader *fragShader = 0; - QGLEngineShaderProg *newProg = 0; - bool success = false; + QScopedPointer newProg; do { - QByteArray source; + QByteArray fragSource; // Insert the custom stage before the srcPixel shader to work around an ATI driver bug // where you cannot forward declare a function that takes a sampler as argument. if (prog.srcPixelFragShader == CustomImageSrcFragmentShader) - source.append(prog.customStageSource); - source.append(qShaderSnippets[prog.mainFragShader]); - source.append(qShaderSnippets[prog.srcPixelFragShader]); + fragSource.append(prog.customStageSource); + fragSource.append(qShaderSnippets[prog.mainFragShader]); + fragSource.append(qShaderSnippets[prog.srcPixelFragShader]); if (prog.compositionFragShader) - source.append(qShaderSnippets[prog.compositionFragShader]); + fragSource.append(qShaderSnippets[prog.compositionFragShader]); if (prog.maskFragShader) - source.append(qShaderSnippets[prog.maskFragShader]); - fragShader = new QGLShader(QGLShader::Fragment, ctxGuard.context(), 0); - shaders.append(fragShader); - QByteArray description; + fragSource.append(qShaderSnippets[prog.maskFragShader]); + + QByteArray vertexSource; + vertexSource.append(qShaderSnippets[prog.mainVertexShader]); + vertexSource.append(qShaderSnippets[prog.positionVertexShader]); + + QScopedPointer shaderProgram(new QGLShaderProgram(ctxGuard.context(), 0)); + + CachedShader shaderCache(fragSource, vertexSource); + bool inCache = shaderCache.load(shaderProgram.data(), ctxGuard.context()); + + if (!inCache) { + + QScopedPointer fragShader(new QGLShader(QGLShader::Fragment, ctxGuard.context(), 0)); + QByteArray description; #if defined(QT_DEBUG) - // Name the shader for easier debugging - description.append("Fragment shader: main="); - description.append(snippetNameStr(prog.mainFragShader)); - description.append(", srcPixel="); - description.append(snippetNameStr(prog.srcPixelFragShader)); - if (prog.compositionFragShader) { - description.append(", composition="); - description.append(snippetNameStr(prog.compositionFragShader)); - } - if (prog.maskFragShader) { - description.append(", mask="); - description.append(snippetNameStr(prog.maskFragShader)); - } - fragShader->setObjectName(QString::fromLatin1(description)); + // Name the shader for easier debugging + description.append("Fragment shader: main="); + description.append(snippetNameStr(prog.mainFragShader)); + description.append(", srcPixel="); + description.append(snippetNameStr(prog.srcPixelFragShader)); + if (prog.compositionFragShader) { + description.append(", composition="); + description.append(snippetNameStr(prog.compositionFragShader)); + } + if (prog.maskFragShader) { + description.append(", mask="); + description.append(snippetNameStr(prog.maskFragShader)); + } + fragShader->setObjectName(QString::fromLatin1(description)); #endif - if (!fragShader->compileSourceCode(source)) { - qWarning() << "Warning:" << description << "failed to compile!"; - break; - } + if (!fragShader->compileSourceCode(fragSource)) { + qWarning() << "Warning:" << description << "failed to compile!"; + break; + } - source.clear(); - source.append(qShaderSnippets[prog.mainVertexShader]); - source.append(qShaderSnippets[prog.positionVertexShader]); - vertexShader = new QGLShader(QGLShader::Vertex, ctxGuard.context(), 0); - shaders.append(vertexShader); + QScopedPointer vertexShader(new QGLShader(QGLShader::Vertex, ctxGuard.context(), 0)); #if defined(QT_DEBUG) - // Name the shader for easier debugging - description.clear(); - description.append("Vertex shader: main="); - description.append(snippetNameStr(prog.mainVertexShader)); - description.append(", position="); - description.append(snippetNameStr(prog.positionVertexShader)); - vertexShader->setObjectName(QString::fromLatin1(description)); + // Name the shader for easier debugging + description.clear(); + description.append("Vertex shader: main="); + description.append(snippetNameStr(prog.mainVertexShader)); + description.append(", position="); + description.append(snippetNameStr(prog.positionVertexShader)); + vertexShader->setObjectName(QString::fromLatin1(description)); #endif - if (!vertexShader->compileSourceCode(source)) { - qWarning() << "Warning:" << description << "failed to compile!"; - break; - } + if (!vertexShader->compileSourceCode(vertexSource)) { + qWarning() << "Warning:" << description << "failed to compile!"; + break; + } - newProg = new QGLEngineShaderProg(prog); - - // If the shader program's not found in the cache, create it now. - newProg->program = new QGLShaderProgram(ctxGuard.context(), 0); - newProg->program->addShader(vertexShader); - newProg->program->addShader(fragShader); - - // We have to bind the vertex attribute names before the program is linked: - newProg->program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); - if (newProg->useTextureCoords) - newProg->program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); - if (newProg->useOpacityAttribute) - newProg->program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR); - if (newProg->usePmvMatrixAttribute) { - newProg->program->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR); - newProg->program->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR); - newProg->program->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR); + shaders.append(vertexShader.data()); + shaders.append(fragShader.data()); + shaderProgram->addShader(vertexShader.take()); + shaderProgram->addShader(fragShader.take()); + + // We have to bind the vertex attribute names before the program is linked: + shaderProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); + if (prog.useTextureCoords) + shaderProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); + if (prog.useOpacityAttribute) + shaderProgram->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR); + if (prog.usePmvMatrixAttribute) { + shaderProgram->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR); + shaderProgram->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR); + shaderProgram->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR); + } } + newProg.reset(new QGLEngineShaderProg(prog)); + newProg->program = shaderProgram.take(); + newProg->program->link(); - if (!newProg->program->isLinked()) { + if (newProg->program->isLinked()) { + if (!inCache) + shaderCache.store(newProg->program, ctxGuard.context()); + } else { QLatin1String none("none"); QLatin1String br("\n"); QString error; - error = QLatin1String("Shader program failed to link,") + error = QLatin1String("Shader program failed to link,"); #if defined(QT_DEBUG) - + br - + QLatin1String(" Shaders Used:") + br - + QLatin1String(" ") + vertexShader->objectName() + QLatin1String(": ") + br - + QLatin1String(vertexShader->sourceCode()) + br - + QLatin1String(" ") + fragShader->objectName() + QLatin1String(": ") + br - + QLatin1String(fragShader->sourceCode()) + br + error += QLatin1String("\n Shaders Used:\n"); + for (int i = 0; i < newProg->program->shaders().count(); ++i) { + QGLShader *shader = newProg->program->shaders().at(i); + error += QLatin1String(" ") + shader->objectName() + QLatin1String(": \n") + + QLatin1String(shader->sourceCode()) + br; + } #endif - + QLatin1String(" Error Log:\n") - + QLatin1String(" ") + newProg->program->log(); + error += QLatin1String(" Error Log:\n") + + QLatin1String(" ") + newProg->program->log(); qWarning() << error; break; } @@ -395,26 +433,10 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS } } - cachedPrograms.insert(0, newProg); - - success = true; + cachedPrograms.insert(0, newProg.data()); } while (false); - // Clean up everything if we weren't successful - if (!success) { - if (newProg) { - delete newProg; // Also deletes the QGLShaderProgram which in turn deletes the QGLShaders - newProg = 0; - } - else { - if (vertexShader) - delete vertexShader; - if (fragShader) - delete fragShader; - } - } - - return newProg; + return newProg.take(); } void QGLEngineSharedShaders::cleanupCustomStage(QGLCustomShaderStage* stage) diff --git a/src/opengl/gl2paintengineex/qglshadercache_meego_p.h b/src/opengl/gl2paintengineex/qglshadercache_meego_p.h new file mode 100644 index 0000000..5f51fc2 --- /dev/null +++ b/src/opengl/gl2paintengineex/qglshadercache_meego_p.h @@ -0,0 +1,457 @@ +/**************************************************************************** +** +** 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 QtOpenGL 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$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QGLSHADERCACHE_MEEGO_P_H +#define QGLSHADERCACHE_MEEGO_P_H + +#include + +#if defined(QT_MEEGO_EXPERIMENTAL_SHADERCACHE) && defined(QT_OPENGL_ES_2) + +#include +#include +#include + +#ifndef QT_BOOTSTRAPPED +# include +#endif +#if defined(QT_DEBUG) || defined(QT_MEEGO_EXPERIMENTAL_SHADERCACHE_TRACE) +# include +#endif + +QT_BEGIN_HEADER + +/* + This cache stores internal Qt shader programs in shared memory. + + This header file is ugly on purpose and can only be included once. It is only to be used + for the internal shader cache, not as a generic cache for anyone's shaders. + + The cache stores either ShaderCacheMaxEntries shader programs or ShaderCacheDataSize kilobytes + of shader programs, whatever limit is reached first. + + The layout of the cache is as outlined in the CachedShaders struct. After some + integers, an array of headers is reserved, then comes the space for the actual binaries. + + Shader Programs are identified by the md5sum of their frag and vertex shader source code. + + Shader Programs are never removed. The cache never shrinks or re-shuffles. This is done + on purpose to ensure minimum amount of locking, no alignment problems and very few write + operations. + + Note: Locking the shader cache could be expensive, because the entire system might hang. + That's why the cache is immutable to minimize the time we need to keep it locked. + + Why is it Meego specific? + + First, the size is chosen so that it fits to generic meego usage. Second, on Meego, there's + always at least one Qt application active (the launcher), so the cache will never be destroyed. + Only when the last Qt app exits, the cache dies, which should only be when someone kills the + X11 server. And last but not least it was only tested with Meego's SGX driver. + + There's a small tool in src/opengl/util/meego that dumps the contents of the cache. + */ + +// anonymous namespace, prevent exporting of the private symbols +namespace +{ + +struct CachedShaderHeader +{ + /* the index in the data[] member of CachedShaders */ + int index; + /* the size of the binary shader */ + GLsizei size; + /* the format of the binary shader */ + GLenum format; + /* the md5sum of the frag+vertex shaders */ + char md5Sum[16]; +}; + +enum +{ + /* The maximum amount of shader programs the cache can hold */ + ShaderCacheMaxEntries = 20 +}; + +typedef CachedShaderHeader CachedShaderHeaders[ShaderCacheMaxEntries]; + +enum +{ + // ShaderCacheDataSize is 20k minus the other data members of CachedShaders + ShaderCacheDataSize = 1024 * ShaderCacheMaxEntries - sizeof(CachedShaderHeaders) - 2 * sizeof(int) +}; + +struct CachedShaders +{ + /* How much space is still available in the cache */ + inline int availableSize() const { return ShaderCacheDataSize - dataSize; } + + /* The current amount of cached shaders */ + int shaderCount; + + /* The current amount (in bytes) of cached data */ + int dataSize; + + /* The headers describing the shaders */ + CachedShaderHeaders headers; + + /* The actual binary data of the shader programs */ + char data[ShaderCacheDataSize]; +}; + +//#define QT_DEBUG_SHADER_CACHE +#ifdef QT_DEBUG_SHADER_CACHE +static QDebug shaderCacheDebug() +{ + return QDebug(QtDebugMsg); +} +#else +static inline QNoDebug shaderCacheDebug() { return QNoDebug(); } +#endif + +class ShaderCacheSharedMemory +{ +public: + ShaderCacheSharedMemory() + : shm(QLatin1String("qt_gles2_shadercache_" QT_VERSION_STR)) + { + // we need a system semaphore here, since cache creation and initialization must be atomic + QSystemSemaphore attachSemaphore(QLatin1String("qt_gles2_shadercache_mutex_" QT_VERSION_STR), 1); + + if (!attachSemaphore.acquire()) { + shaderCacheDebug() << "Unable to require shader cache semaphore:" << attachSemaphore.errorString(); + return; + } + + if (shm.attach()) { + // success! + shaderCacheDebug() << "Attached to shader cache"; + } else { + + // no cache exists - create and initialize it + if (shm.create(sizeof(CachedShaders))) { + shaderCacheDebug() << "Created new shader cache"; + initializeCache(); + } else { + shaderCacheDebug() << "Unable to create shader cache:" << shm.errorString(); + } + } + + attachSemaphore.release(); + } + + inline bool isAttached() const { return shm.isAttached(); } + + inline bool lock() { return shm.lock(); } + inline bool unlock() { return shm.unlock(); } + inline void *data() { return shm.data(); } + inline QString errorString() { return shm.errorString(); } + + ~ShaderCacheSharedMemory() + { + if (!shm.detach()) + shaderCacheDebug() << "Unable to detach shader cache" << shm.errorString(); + } + +private: + void initializeCache() + { + // no need to lock the shared memory since we're already protected by the + // attach system semaphore. + + void *data = shm.data(); + Q_ASSERT(data); + + memset(data, 0, sizeof(CachedShaders)); + } + + QSharedMemory shm; +}; + +class ShaderCacheLocker +{ +public: + inline ShaderCacheLocker(ShaderCacheSharedMemory *cache) + : shm(cache->lock() ? cache : (ShaderCacheSharedMemory *)0) + { + if (!shm) + shaderCacheDebug() << "Unable to lock shader cache" << cache->errorString(); + } + + inline bool isLocked() const { return shm; } + + inline ~ShaderCacheLocker() + { + if (!shm) + return; + if (!shm->unlock()) + shaderCacheDebug() << "Unable to unlock shader cache" << shm->errorString(); + } + +private: + ShaderCacheSharedMemory *shm; +}; + +#ifdef QT_BOOTSTRAPPED +} // end namespace +#else + +static void traceCacheOverflow(const char *message) +{ +#if defined(QT_DEBUG) || defined (QT_MEEGO_EXPERIMENTAL_SHADERCACHE_TRACE) + openlog(qPrintable(QCoreApplication::applicationName()), LOG_PID | LOG_ODELAY, LOG_USER); + syslog(LOG_DEBUG, message); + closelog(); +#endif + shaderCacheDebug() << message; +} + +Q_GLOBAL_STATIC(ShaderCacheSharedMemory, shaderCacheSharedMemory) + +/* + Finds the index of the shader program identified by md5Sum in the cache. + Note: Does NOT lock the cache for reading, the cache must already be locked! + + Returns -1 when no shader was found. + */ +static int qt_cache_index_unlocked(const QByteArray &md5Sum, CachedShaders *cache) +{ + for (int i = 0; i < cache->shaderCount; ++i) { + if (qstrncmp(md5Sum.constData(), cache->headers[i].md5Sum, 16) == 0) { + return i; + } + } + return -1; +} + +/* Returns the index of the shader identified by md5Sum */ +static int qt_cache_index(const QByteArray &md5Sum) +{ + ShaderCacheSharedMemory *shm = shaderCacheSharedMemory(); + if (!shm || !shm->isAttached()) + return false; + + Q_ASSERT(md5Sum.length() == 16); + + ShaderCacheLocker locker(shm); + if (!locker.isLocked()) + return false; + + void *data = shm->data(); + Q_ASSERT(data); + + CachedShaders *cache = reinterpret_cast(data); + + return qt_cache_index_unlocked(md5Sum, cache); +} + +/* Loads the cached shader at index \a shaderIndex into \a program + * Note: Since the cache is immutable, this operation doesn't lock the shared memory. + */ +static bool qt_cached_shader(QGLShaderProgram *program, const QGLContext *ctx, int shaderIndex) +{ + Q_ASSERT(shaderIndex >= 0 && shaderIndex <= ShaderCacheMaxEntries); + Q_ASSERT(program); + + ShaderCacheSharedMemory *shm = shaderCacheSharedMemory(); + if (!shm || !shm->isAttached()) + return false; + + void *data = shm->data(); + Q_ASSERT(data); + + CachedShaders *cache = reinterpret_cast(data); + + shaderCacheDebug() << "fetching cached shader at index" << shaderIndex + << "dataIndex" << cache->headers[shaderIndex].index + << "size" << cache->headers[shaderIndex].size + << "format" << cache->headers[shaderIndex].format; + + // call program->programId first, since that resolves the glProgramBinaryOES symbol + GLuint programId = program->programId(); + glProgramBinaryOES(programId, cache->headers[shaderIndex].format, + cache->data + cache->headers[shaderIndex].index, + cache->headers[shaderIndex].size); + + return true; +} + +/* Stores the shader program in the cache. Returns false if there's an error with the cache, or + if the cache is too small to hold the shader. */ +static bool qt_cache_shader(const QGLShaderProgram *shader, const QGLContext *ctx, const QByteArray &md5Sum) +{ + ShaderCacheSharedMemory *shm = shaderCacheSharedMemory(); + if (!shm || !shm->isAttached()) + return false; + + void *data = shm->data(); + Q_ASSERT(data); + + CachedShaders *cache = reinterpret_cast(data); + + ShaderCacheLocker locker(shm); + if (!locker.isLocked()) + return false; + + int cacheIdx = cache->shaderCount; + if (cacheIdx >= ShaderCacheMaxEntries) { + traceCacheOverflow("Qt OpenGL shader cache index overflow!"); + return false; + } + + // now that we have the lock on the shared memory, make sure no one + // inserted the shader already while we were unlocked + if (qt_cache_index_unlocked(md5Sum, cache) != -1) + return true; // already cached + + shaderCacheDebug() << "Caching shader at index" << cacheIdx; + + GLint binaryLength = 0; + glGetProgramiv(shader->programId(), GL_PROGRAM_BINARY_LENGTH_OES, &binaryLength); + + if (!binaryLength) { + shaderCacheDebug() << "Unable to determine binary shader size!"; + return false; + } + + if (binaryLength > cache->availableSize()) { + traceCacheOverflow("Qt OpenGL shader cache data overflow!"); + return false; + } + + GLsizei size = 0; + GLenum format = 0; + glGetProgramBinaryOES(shader->programId(), binaryLength, &size, &format, + cache->data + cache->dataSize); + + if (!size) { + shaderCacheDebug() << "Unable to get binary shader!"; + return false; + } + + cache->headers[cacheIdx].index = cache->dataSize; + cache->dataSize += binaryLength; + ++cache->shaderCount; + cache->headers[cacheIdx].size = binaryLength; + cache->headers[cacheIdx].format = format; + + memcpy(cache->headers[cacheIdx].md5Sum, md5Sum.constData(), 16); + + shaderCacheDebug() << "cached shader size" << size + << "format" << format + << "binarySize" << binaryLength + << "cache index" << cacheIdx + << "data index" << cache->headers[cacheIdx].index; + + return true; +} + +} // namespace + +QT_BEGIN_NAMESPACE + +QT_MODULE(OpenGL) + +class CachedShader +{ +public: + CachedShader(const QByteArray &fragSource, const QByteArray &vertexSource) + : cacheIdx(-1) + { + QCryptographicHash md5Hash(QCryptographicHash::Md5); + + md5Hash.addData(fragSource); + md5Hash.addData(vertexSource); + + md5Sum = md5Hash.result(); + } + + bool isCached() + { + return cacheIndex() != -1; + } + + int cacheIndex() + { + if (cacheIdx != -1) + return cacheIdx; + cacheIdx = qt_cache_index(md5Sum); + return cacheIdx; + } + + bool load(QGLShaderProgram *program, const QGLContext *ctx) + { + if (cacheIndex() == -1) + return false; + return qt_cached_shader(program, ctx, cacheIdx); + } + + bool store(QGLShaderProgram *program, const QGLContext *ctx) + { + return qt_cache_shader(program, ctx, md5Sum); + } + +private: + QByteArray md5Sum; + int cacheIdx; +}; + + +QT_END_NAMESPACE + +#endif + +QT_END_HEADER + +#endif +#endif diff --git a/src/opengl/gl2paintengineex/qglshadercache_p.h b/src/opengl/gl2paintengineex/qglshadercache_p.h new file mode 100644 index 0000000..29616ae --- /dev/null +++ b/src/opengl/gl2paintengineex/qglshadercache_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** 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 QtOpenGL 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$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QGLSHADERCACHE_P_H +#define QGLSHADERCACHE_P_H + +#include + +#if defined(QT_MEEGO_EXPERIMENTAL_SHADERCACHE) && defined(QT_OPENGL_ES_2) +# include "qglshadercache_meego_p.h" +#else + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(OpenGL) + +class QGLShaderProgram; +class QGLContext; + +class CachedShader +{ +public: + inline CachedShader(const QByteArray &, const QByteArray &) + {} + + inline bool isCached() + { + return false; + } + + inline bool load(QGLShaderProgram *, const QGLContext *) + { + return false; + } + + inline bool store(QGLShaderProgram *, const QGLContext *) + { + return false; + } +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif +#endif diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index 682e620..a089d55 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -60,7 +60,9 @@ SOURCES += qgl.cpp \ gl2paintengineex/qglcustomshaderstage_p.h \ gl2paintengineex/qtriangulatingstroker_p.h \ gl2paintengineex/qtriangulator_p.h \ - gl2paintengineex/qtextureglyphcache_gl_p.h + gl2paintengineex/qtextureglyphcache_gl_p.h \ + gl2paintengineex/qglshadercache_p.h \ + gl2paintengineex/qglshadercache_meego_p.h SOURCES += qglshaderprogram.cpp \ qglpixmapfilter.cpp \ diff --git a/src/opengl/util/meego/main.cpp b/src/opengl/util/meego/main.cpp new file mode 100644 index 0000000..0c9a915 --- /dev/null +++ b/src/opengl/util/meego/main.cpp @@ -0,0 +1,48 @@ +#include + +#define QT_DEBUG_SHADER_CACHE +#define QT_MEEGO_EXPERIMENTAL_SHADERCACHE +#define QT_OPENGL_ES_2 +#define QT_BOOTSTRAPPED + +typedef int GLsizei; +typedef unsigned int GLenum; + +#include "../../gl2paintengineex/qglshadercache_meego_p.h" + +#include +#include + +int main() +{ + ShaderCacheSharedMemory shm; + + if (!shm.isAttached()) { + fprintf(stderr, "Unable to attach to shared memory\n"); + return EXIT_FAILURE; + } + + ShaderCacheLocker locker(&shm); + if (!locker.isLocked()) { + fprintf(stderr, "Unable to lock shared memory\n"); + return EXIT_FAILURE; + } + + void *data = shm.data(); + Q_ASSERT(data); + + CachedShaders *cache = reinterpret_cast(data); + + for (int i = 0; i < cache->shaderCount; ++i) { + printf("Shader %d: %d bytes\n", i, cache->headers[i].size); + } + + printf("\nSummary:\n\n" + " Amount of cached shaders: %d\n" + " Bytes used: %d\n" + " Bytes available: %d\n", + cache->shaderCount, cache->dataSize, cache->availableSize()); + + return EXIT_SUCCESS; +} + diff --git a/src/opengl/util/meego/shader-cache-introspector.pro b/src/opengl/util/meego/shader-cache-introspector.pro new file mode 100644 index 0000000..520e9a5 --- /dev/null +++ b/src/opengl/util/meego/shader-cache-introspector.pro @@ -0,0 +1,7 @@ +TEMPLATE = app + +SOURCES += main.cpp + +TARGET = shader-cache-introspector + +QT = core -- cgit v0.12 From e50a0ad18c40322ca0c06a11e7dc7b9a82951f16 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Wed, 22 Dec 2010 16:12:26 +1000 Subject: XmlListModel requests should set 'Accept' header to 'application/xml' Task-number: QTBUG-15836 Reviewed-by: Michael Brasser --- src/declarative/util/qdeclarativexmllistmodel.cpp | 1 + .../tst_qdeclarativexmllistmodel.cpp | 69 ++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/src/declarative/util/qdeclarativexmllistmodel.cpp b/src/declarative/util/qdeclarativexmllistmodel.cpp index 49a12b1..e97cd67 100644 --- a/src/declarative/util/qdeclarativexmllistmodel.cpp +++ b/src/declarative/util/qdeclarativexmllistmodel.cpp @@ -924,6 +924,7 @@ void QDeclarativeXmlListModel::reload() } else { d->notifyQueryStarted(true); QNetworkRequest req(d->src); + req.setRawHeader("Accept", "application/xml"); d->reply = qmlContext(this)->engine()->networkAccessManager()->get(req); QObject::connect(d->reply, SIGNAL(finished()), this, SLOT(requestFinished())); QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), diff --git a/tests/auto/declarative/qdeclarativexmllistmodel/tst_qdeclarativexmllistmodel.cpp b/tests/auto/declarative/qdeclarativexmllistmodel/tst_qdeclarativexmllistmodel.cpp index a14f942..b95b053 100644 --- a/tests/auto/declarative/qdeclarativexmllistmodel/tst_qdeclarativexmllistmodel.cpp +++ b/tests/auto/declarative/qdeclarativexmllistmodel/tst_qdeclarativexmllistmodel.cpp @@ -38,8 +38,13 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include + #include #include +#include +#include +#include #include #include #include @@ -81,6 +86,7 @@ private slots: void roles(); void roleErrors(); void uniqueRoleNames(); + void headers(); void xml(); void xml_data(); void source(); @@ -139,6 +145,44 @@ private: QDeclarativeEngine engine; }; +class CustomNetworkAccessManagerFactory : public QObject, public QDeclarativeNetworkAccessManagerFactory +{ + Q_OBJECT +public: + QVariantMap lastSentHeaders; + +protected: + QNetworkAccessManager *create(QObject *parent); +}; + +class CustomNetworkAccessManager : public QNetworkAccessManager +{ + Q_OBJECT +public: + CustomNetworkAccessManager(CustomNetworkAccessManagerFactory *factory, QObject *parent) + : QNetworkAccessManager(parent), m_factory(factory) {} + +protected: + QNetworkReply *createRequest(Operation op, const QNetworkRequest &req, QIODevice * outgoingData = 0) + { + if (m_factory) { + QVariantMap map; + foreach (const QString &header, req.rawHeaderList()) + map[header] = req.rawHeader(header.toUtf8()); + m_factory->lastSentHeaders = map; + } + return QNetworkAccessManager::createRequest(op, req, outgoingData); + } + + QPointer m_factory; +}; + +QNetworkAccessManager *CustomNetworkAccessManagerFactory::create(QObject *parent) +{ + return new CustomNetworkAccessManager(this, parent); +} + + void tst_qdeclarativexmllistmodel::buildModel() { QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/model.qml")); @@ -312,6 +356,31 @@ void tst_qdeclarativexmllistmodel::xml_data() QTest::newRow("one item") << "HobbesTiger7Large" << 1; } +void tst_qdeclarativexmllistmodel::headers() +{ + // ensure the QNetworkAccessManagers created for this test are immediately deleted + QDeclarativeEngine qmlEng; + + CustomNetworkAccessManagerFactory factory; + qmlEng.setNetworkAccessManagerFactory(&factory); + + QDeclarativeComponent component(&qmlEng, QUrl::fromLocalFile(SRCDIR "/data/model.qml")); + QDeclarativeXmlListModel *model = qobject_cast(component.create()); + QVERIFY(model != 0); + QTRY_COMPARE(model->status(), QDeclarativeXmlListModel::Ready); + + QVariantMap expectedHeaders; + expectedHeaders["Accept"] = "application/xml"; + + QCOMPARE(factory.lastSentHeaders.count(), expectedHeaders.count()); + foreach (const QString &header, expectedHeaders.keys()) { + QVERIFY(factory.lastSentHeaders.contains(header)); + QCOMPARE(factory.lastSentHeaders[header].toString(), expectedHeaders[header].toString()); + } + + delete model; +} + void tst_qdeclarativexmllistmodel::source() { QFETCH(QUrl, source); -- cgit v0.12 From cb31612bf6a48f995fbc05b5e8aa924e13034ae4 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 22 Dec 2010 16:15:28 +1000 Subject: Removing all visible items in ListView resulted in blank view. When delayRemove is true and all visible items are tagged to be removed the visibleIndex became invalid and refill() began filling from 0. Task-number: QTBUG-16183 Reviewed-by: Michael Brasser --- src/declarative/graphicsitems/qdeclarativelistview.cpp | 14 ++++++++++---- .../qdeclarativelistview/tst_qdeclarativelistview.cpp | 3 ++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index 2a7f508..86c8756 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -643,7 +643,8 @@ void QDeclarativeListViewPrivate::refill(qreal from, qreal to, bool doBuffer) int i = visibleItems.count() - 1; while (i > 0 && visibleItems.at(i)->index == -1) --i; - modelIndex = visibleItems.at(i)->index + 1; + if (visibleItems.at(i)->index != -1) + modelIndex = visibleItems.at(i)->index + 1; } bool changed = false; @@ -2804,7 +2805,10 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count) int i = d->visibleItems.count() - 1; while (i > 0 && d->visibleItems.at(i)->index == -1) --i; - if (d->visibleItems.at(i)->index + 1 == modelIndex + if (i == 0 && d->visibleItems.first()->index == -1) { + // there are no visible items except items marked for removal + index = d->visibleItems.count(); + } else if (d->visibleItems.at(i)->index + 1 == modelIndex && d->visibleItems.at(i)->endPosition() < d->buffer+d->position()+d->size()-1) { // Special case of appending an item to the model. index = d->visibleItems.count(); @@ -2836,7 +2840,7 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count) // index can be the next item past the end of the visible items list (i.e. appended) int pos = index < d->visibleItems.count() ? d->visibleItems.at(index)->position() - : d->visibleItems.at(index-1)->endPosition()+d->spacing+1; + : d->visibleItems.last()->endPosition()+d->spacing+1; int initialPos = pos; int diff = 0; QList added; @@ -2988,14 +2992,16 @@ void QDeclarativeListView::itemsRemoved(int modelIndex, int count) } // update visibleIndex + bool haveVisibleIndex = false; for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) { if ((*it)->index != -1) { d->visibleIndex = (*it)->index; + haveVisibleIndex = true; break; } } - if (removedVisible && d->visibleItems.isEmpty()) { + if (removedVisible && !haveVisibleIndex) { d->timeline.clear(); if (d->itemCount == 0) { d->visibleIndex = 0; diff --git a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp index 3df10a9..dba0cc4 100644 --- a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp +++ b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp @@ -667,7 +667,8 @@ void tst_QDeclarativeListView::removed(bool animated) listview->setContentY(80); QTest::qWait(300); - model.removeItems(1, 17); + // remove all visible items + model.removeItems(1, 18); QTest::qWait(300); // Confirm items positioned correctly -- cgit v0.12 From bdc39d20b4958f7adc95dc5990d601e946213fda Mon Sep 17 00:00:00 2001 From: Harald Fernengel Date: Wed, 22 Dec 2010 11:37:56 +0100 Subject: add missing license header --- src/opengl/util/meego/main.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/opengl/util/meego/main.cpp b/src/opengl/util/meego/main.cpp index 0c9a915..5522855 100644 --- a/src/opengl/util/meego/main.cpp +++ b/src/opengl/util/meego/main.cpp @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** 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 QtOpenGL 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$ +** +****************************************************************************/ + #include #define QT_DEBUG_SHADER_CACHE -- cgit v0.12 From 6ecb2f699c203fd937495cba844f7888a1d3305f Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 22 Dec 2010 14:30:59 +0100 Subject: Assistant: Get rid of bogus warning. Task-number: QTBUG-16096 --- tools/assistant/tools/assistant/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/assistant/tools/assistant/main.cpp b/tools/assistant/tools/assistant/main.cpp index e3eef34..5883f7b 100644 --- a/tools/assistant/tools/assistant/main.cpp +++ b/tools/assistant/tools/assistant/main.cpp @@ -292,7 +292,8 @@ void setupTranslation(const QString &fileName, const QString &dir) QTranslator *translator = new QTranslator(QCoreApplication::instance()); if (translator->load(fileName, dir)) { QCoreApplication::installTranslator(translator); - } else if (!fileName.endsWith(QLatin1String("en_US"))) { + } else if (!fileName.endsWith(QLatin1String("en_US")) + && !fileName.endsWith(QLatin1String("_C"))) { qWarning("Could not load translation file %s in directory %s.", qPrintable(fileName), qPrintable(dir)); } -- cgit v0.12 From b461c315547b42293968219583187d83b2b25e0f Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 22 Dec 2010 09:23:48 +1000 Subject: Add additional QDeclarativeProperty autotests. --- .../tst_qdeclarativeproperty.cpp | 62 ++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/auto/declarative/qdeclarativeproperty/tst_qdeclarativeproperty.cpp b/tests/auto/declarative/qdeclarativeproperty/tst_qdeclarativeproperty.cpp index 3cc71bb..41f2b19 100644 --- a/tests/auto/declarative/qdeclarativeproperty/tst_qdeclarativeproperty.cpp +++ b/tests/auto/declarative/qdeclarativeproperty/tst_qdeclarativeproperty.cpp @@ -167,6 +167,7 @@ void tst_qdeclarativeproperty::qmlmetaproperty() QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); + QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), false); QCOMPARE(prop.object(), (QObject *)0); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); @@ -263,6 +264,7 @@ void tst_qdeclarativeproperty::qmlmetaproperty_object() QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); + QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), false); QCOMPARE(prop.object(), (QObject *)0); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); @@ -309,6 +311,7 @@ void tst_qdeclarativeproperty::qmlmetaproperty_object() QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), true); QCOMPARE(prop.isResettable(), false); + QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), true); QCOMPARE(prop.object(), qobject_cast(&dobject)); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::Normal); @@ -362,6 +365,7 @@ void tst_qdeclarativeproperty::qmlmetaproperty_object_string() QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); + QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), false); QCOMPARE(prop.object(), (QObject *)0); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); @@ -408,6 +412,7 @@ void tst_qdeclarativeproperty::qmlmetaproperty_object_string() QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), true); QCOMPARE(prop.isResettable(), false); + QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), true); QCOMPARE(prop.object(), qobject_cast(&dobject)); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::Normal); @@ -456,6 +461,7 @@ void tst_qdeclarativeproperty::qmlmetaproperty_object_string() QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); + QCOMPARE(prop.isSignalProperty(), true); QCOMPARE(prop.isValid(), true); QCOMPARE(prop.object(), qobject_cast(&dobject)); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); @@ -503,6 +509,7 @@ void tst_qdeclarativeproperty::qmlmetaproperty_object_string() QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); + QCOMPARE(prop.isSignalProperty(), true); QCOMPARE(prop.isValid(), true); QCOMPARE(prop.object(), qobject_cast(&dobject)); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); @@ -555,6 +562,7 @@ void tst_qdeclarativeproperty::qmlmetaproperty_object_context() QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); + QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), false); QCOMPARE(prop.object(), (QObject *)0); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); @@ -601,6 +609,7 @@ void tst_qdeclarativeproperty::qmlmetaproperty_object_context() QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), true); QCOMPARE(prop.isResettable(), false); + QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), true); QCOMPARE(prop.object(), qobject_cast(&dobject)); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::Normal); @@ -654,6 +663,7 @@ void tst_qdeclarativeproperty::qmlmetaproperty_object_string_context() QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); + QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), false); QCOMPARE(prop.object(), (QObject *)0); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); @@ -700,6 +710,7 @@ void tst_qdeclarativeproperty::qmlmetaproperty_object_string_context() QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), true); QCOMPARE(prop.isResettable(), false); + QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), true); QCOMPARE(prop.object(), qobject_cast(&dobject)); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::Normal); @@ -748,6 +759,7 @@ void tst_qdeclarativeproperty::qmlmetaproperty_object_string_context() QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); + QCOMPARE(prop.isSignalProperty(), true); QCOMPARE(prop.isValid(), true); QCOMPARE(prop.object(), qobject_cast(&dobject)); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); @@ -795,6 +807,7 @@ void tst_qdeclarativeproperty::qmlmetaproperty_object_string_context() QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); + QCOMPARE(prop.isSignalProperty(), true); QCOMPARE(prop.isValid(), true); QCOMPARE(prop.object(), qobject_cast(&dobject)); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); @@ -922,6 +935,17 @@ void tst_qdeclarativeproperty::read() QCOMPARE(p.read(), QVariant("myName")); } + // Value prop by name (static) + { + QObject o; + + QCOMPARE(QDeclarativeProperty::read(&o, "objectName"), QVariant(QString())); + + o.setObjectName("myName"); + + QCOMPARE(QDeclarativeProperty::read(&o, "objectName"), QVariant("myName")); + } + // Value-type prop { PropertyObject o; @@ -994,6 +1018,16 @@ void tst_qdeclarativeproperty::read() QCOMPARE(qvariant_cast(v)->property("a").toInt(), 10); QCOMPARE(qvariant_cast(v)->property("b").toInt(), 19); } + { // static + QDeclarativeComponent component(&engine, TEST_FILE("readSynthesizedObject.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QVariant v = QDeclarativeProperty::read(object, "test", &engine); + QVERIFY(v.userType() == QMetaType::QObjectStar); + QCOMPARE(qvariant_cast(v)->property("a").toInt(), 10); + QCOMPARE(qvariant_cast(v)->property("b").toInt(), 19); + } // Attached property { @@ -1026,6 +1060,15 @@ void tst_qdeclarativeproperty::read() QCOMPARE(p.read(), QVariant(10)); delete object; } + { // static + QDeclarativeComponent component(&engine); + component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }", QUrl()); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(QDeclarativeProperty::read(object, "Foo.MyContainer.foo", qmlContext(object)), QVariant(10)); + delete object; + } } void tst_qdeclarativeproperty::write() @@ -1066,6 +1109,13 @@ void tst_qdeclarativeproperty::write() QCOMPARE(o.objectName(), QString("myName")); } + // Writable prop by name (static) + { + PropertyObject o; + QCOMPARE(QDeclarativeProperty::write(&o, QString("objectName"), QVariant(QString("myName"))), true); + QCOMPARE(o.objectName(), QString("myName")); + } + // Deleted object { PropertyObject *o = new PropertyObject; @@ -1138,6 +1188,18 @@ void tst_qdeclarativeproperty::write() QCOMPARE(p2.write(QUrl("main.qml")), true); QCOMPARE(o.url(), result); } + { // static + PropertyObject o; + + QCOMPARE(QDeclarativeProperty::write(&o, "url", QUrl("main.qml")), true); + QCOMPARE(o.url(), QUrl("main.qml")); + + QUrl result = engine.baseUrl().resolved(QUrl("main.qml")); + QVERIFY(result != QUrl("main.qml")); + + QCOMPARE(QDeclarativeProperty::write(&o, "url", QUrl("main.qml"), engine.rootContext()), true); + QCOMPARE(o.url(), result); + } // Attached property { -- cgit v0.12 From f360cc9b521e5e3e7d4b896627b3257365c6ad3c Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 22 Dec 2010 10:05:06 +1000 Subject: Improve QDeclarativeComponent test coverage. --- src/declarative/qml/qdeclarativecomponent.cpp | 11 ----------- src/declarative/qml/qdeclarativecomponent_p.h | 1 - .../qdeclarativecomponent/tst_qdeclarativecomponent.cpp | 15 +++++++++++++++ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp index 77fc925..ecb3bc5 100644 --- a/src/declarative/qml/qdeclarativecomponent.cpp +++ b/src/declarative/qml/qdeclarativecomponent.cpp @@ -699,17 +699,6 @@ QObject *QDeclarativeComponent::create(QDeclarativeContext *context) return rv; } -QObject *QDeclarativeComponentPrivate::create(QDeclarativeContextData *context, - const QBitField &bindings) -{ - if (!context) - context = QDeclarativeContextData::get(engine->rootContext()); - - QObject *rv = beginCreate(context, bindings); - completeCreate(); - return rv; -} - /*! This method provides more advanced control over component instance creation. In general, programmers should use QDeclarativeComponent::create() to create a diff --git a/src/declarative/qml/qdeclarativecomponent_p.h b/src/declarative/qml/qdeclarativecomponent_p.h index 7b30bad..daf1dcb 100644 --- a/src/declarative/qml/qdeclarativecomponent_p.h +++ b/src/declarative/qml/qdeclarativecomponent_p.h @@ -81,7 +81,6 @@ class Q_AUTOTEST_EXPORT QDeclarativeComponentPrivate : public QObjectPrivate, pu public: QDeclarativeComponentPrivate() : typeData(0), progress(0.), start(-1), count(-1), cc(0), engine(0), creationContext(0) {} - QObject *create(QDeclarativeContextData *, const QBitField &); QObject *beginCreate(QDeclarativeContextData *, const QBitField &); void completeCreate(); diff --git a/tests/auto/declarative/qdeclarativecomponent/tst_qdeclarativecomponent.cpp b/tests/auto/declarative/qdeclarativecomponent/tst_qdeclarativecomponent.cpp index 8a19b8b..60ce46d 100644 --- a/tests/auto/declarative/qdeclarativecomponent/tst_qdeclarativecomponent.cpp +++ b/tests/auto/declarative/qdeclarativecomponent/tst_qdeclarativecomponent.cpp @@ -57,6 +57,7 @@ public: tst_qdeclarativecomponent() { } private slots: + void null(); void loadEmptyUrl(); void qmlCreateObject(); @@ -64,6 +65,20 @@ private: QDeclarativeEngine engine; }; +void tst_qdeclarativecomponent::null() +{ + { + QDeclarativeComponent c; + QVERIFY(c.isNull()); + } + + { + QDeclarativeComponent c(&engine); + QVERIFY(c.isNull()); + } +} + + void tst_qdeclarativecomponent::loadEmptyUrl() { QDeclarativeComponent c(&engine); -- cgit v0.12 From 01fd44cd76f2da1dd1e39d7e5632b3274ca895a3 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 23 Dec 2010 10:20:23 +1000 Subject: Nested flickables would react alternately to flicks. The grab was not always kept by filtering Flickables, but would remain set next flick, resulting in toggling of flicking. Task-number: QTBUG-16177 Reviewed-by: Michael Brasser --- .../graphicsitems/qdeclarativeflickable.cpp | 6 +- .../data/flickable-nested.0.png | Bin 0 -> 1710 bytes .../data/flickable-nested.1.png | Bin 0 -> 1710 bytes .../data/flickable-nested.2.png | Bin 0 -> 1727 bytes .../data/flickable-nested.3.png | Bin 0 -> 1727 bytes .../data/flickable-nested.4.png | Bin 0 -> 1727 bytes .../data/flickable-nested.5.png | Bin 0 -> 1731 bytes .../data/flickable-nested.qml | 2159 ++++++++++++++++++++ .../qdeclarativeflickable/flickable-nested.qml | 50 + 9 files changed, 2213 insertions(+), 2 deletions(-) create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.0.png create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.1.png create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.2.png create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.3.png create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.4.png create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.5.png create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.qml create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativeflickable/flickable-nested.qml diff --git a/src/declarative/graphicsitems/qdeclarativeflickable.cpp b/src/declarative/graphicsitems/qdeclarativeflickable.cpp index f1d92c5..f5da491 100644 --- a/src/declarative/graphicsitems/qdeclarativeflickable.cpp +++ b/src/declarative/graphicsitems/qdeclarativeflickable.cpp @@ -671,10 +671,12 @@ void QDeclarativeFlickable::setFlickableDirection(FlickableDirection direction) void QDeclarativeFlickablePrivate::handleMousePressEvent(QGraphicsSceneMouseEvent *event) { + Q_Q(QDeclarativeFlickable); if (interactive && timeline.isActive() && (qAbs(hData.velocity) > 10 || qAbs(vData.velocity) > 10)) stealMouse = true; // If we've been flicked then steal the click. else stealMouse = false; + q->setKeepMouseGrab(stealMouse); pressed = true; timeline.clear(); hData.velocity = 0; @@ -769,6 +771,8 @@ void QDeclarativeFlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent } stealMouse = stealX || stealY; + if (stealMouse) + q->setKeepMouseGrab(true); if (!lastPos.isNull()) { qreal elapsed = qreal(QDeclarativeItemPrivate::restart(lastPosTime)) / 1000.; @@ -848,8 +852,6 @@ void QDeclarativeFlickable::mouseMoveEvent(QGraphicsSceneMouseEvent *event) Q_D(QDeclarativeFlickable); if (d->interactive) { d->handleMouseMoveEvent(event); - if (d->stealMouse) - setKeepMouseGrab(true); event->accept(); } else { QDeclarativeItem::mouseMoveEvent(event); diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.0.png b/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.0.png new file mode 100644 index 0000000..464d913 Binary files /dev/null and b/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.0.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.1.png b/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.1.png new file mode 100644 index 0000000..464d913 Binary files /dev/null and b/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.1.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.2.png b/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.2.png new file mode 100644 index 0000000..b16b9f0 Binary files /dev/null and b/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.2.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.3.png b/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.3.png new file mode 100644 index 0000000..c3d2a6f Binary files /dev/null and b/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.3.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.4.png b/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.4.png new file mode 100644 index 0000000..d074e73 Binary files /dev/null and b/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.4.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.5.png b/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.5.png new file mode 100644 index 0000000..0cac34c Binary files /dev/null and b/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.5.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.qml b/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.qml new file mode 100644 index 0000000..c418cc8 --- /dev/null +++ b/tests/auto/declarative/qmlvisual/qdeclarativeflickable/data/flickable-nested.qml @@ -0,0 +1,2159 @@ +import Qt.VisualTest 4.7 + +VisualTest { + Frame { + msec: 0 + } + Frame { + msec: 16 + image: "flickable-nested.0.png" + } + Frame { + msec: 32 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 48 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 64 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 80 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 96 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 112 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 128 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 144 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 160 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 176 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 192 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 208 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 224 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 240 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 256 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 272 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 288 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 304 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 320 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 336 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 352 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 368 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 384 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 400 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 416 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 432 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 448 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 464 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 480 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 496 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 512 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 528 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 544 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 560 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 576 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 592 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 608 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 624 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 640 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 656 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 672 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 688 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 704 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 720 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 736 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 752 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 768 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 784 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 800 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 816 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 832 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 848 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 864 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 880 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 896 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 912 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 928 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Mouse { + type: 2 + button: 1 + buttons: 1 + x: 206; y: 205 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 944 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Frame { + msec: 960 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 206; y: 204 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 976 + image: "flickable-nested.1.png" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 206; y: 203 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 206; y: 202 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 992 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 205; y: 201 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 205; y: 199 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 1008 + hash: "7523750f0fd21aff13e6ab379e87640d" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 204; y: 197 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 202; y: 196 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 1024 + hash: "bddf8ca2638c9a04f7029d6982152d11" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 198; y: 191 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 197; y: 189 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 1040 + hash: "bc15f1b562879d5058d3b1336fb9074e" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 194; y: 185 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 194; y: 184 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 1056 + hash: "3572c62d7d2b9b23a8d9d3e5037591dd" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 194; y: 182 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 3 + button: 1 + buttons: 0 + x: 194; y: 182 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 1072 + hash: "ce9658887cca581a88e7db14b92d46f2" + } + Frame { + msec: 1088 + hash: "e1fe1a2e1669a200e20468b4aa98dd3d" + } + Frame { + msec: 1104 + hash: "b7582829bf01223e6641ce82f62047df" + } + Frame { + msec: 1120 + hash: "80bd41fe22fb84efb011acf50ec38574" + } + Frame { + msec: 1136 + hash: "04c8d6c3922ce9777ee27d8df59d4729" + } + Frame { + msec: 1152 + hash: "f84dba18e525f1c06548c0232a244b6d" + } + Frame { + msec: 1168 + hash: "26c74b95835e8e0da5aadc7c42cac81c" + } + Frame { + msec: 1184 + hash: "1b4fcb1f0bd83a683cfe0ac303be0033" + } + Frame { + msec: 1200 + hash: "1b4fcb1f0bd83a683cfe0ac303be0033" + } + Frame { + msec: 1216 + hash: "4df47f90656fff253883e3e2d33506dc" + } + Frame { + msec: 1232 + hash: "4df47f90656fff253883e3e2d33506dc" + } + Frame { + msec: 1248 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1264 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1280 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1296 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1312 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1328 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1344 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1360 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1376 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1392 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1408 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1424 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1440 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1456 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1472 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1488 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1504 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1520 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1536 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1552 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1568 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1584 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Frame { + msec: 1600 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Mouse { + type: 2 + button: 1 + buttons: 1 + x: 226; y: 218 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 1616 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 225; y: 218 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 1632 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 223; y: 217 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 222; y: 217 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 1648 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 220; y: 216 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 218; y: 214 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 1664 + hash: "7d0d94c4a7a9330f5bd17782ca484848" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 214; y: 212 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 212; y: 211 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 1680 + hash: "54b41609ba43f710b08ba63f0b96df99" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 208; y: 208 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 207; y: 207 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 1696 + hash: "8910b66b9eb1b2be80e36ed2824df1a0" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 205; y: 205 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 3 + button: 1 + buttons: 0 + x: 205; y: 205 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 1712 + hash: "38df31933f34f961a9b7020ad0d469c2" + } + Frame { + msec: 1728 + hash: "7702a7f710991225d9f411e8f410b515" + } + Frame { + msec: 1744 + hash: "c90d402e68208ccfd2c7345a2bf650cd" + } + Frame { + msec: 1760 + hash: "2630ed37aaf37907d1ee48efb0239615" + } + Frame { + msec: 1776 + hash: "527725818699ce3425b5cb95a25610d5" + } + Frame { + msec: 1792 + hash: "7bd6e37853946a835973c3da213beddc" + } + Frame { + msec: 1808 + hash: "e3c5e113d992e5e50b6780185891edd7" + } + Frame { + msec: 1824 + hash: "e3c5e113d992e5e50b6780185891edd7" + } + Frame { + msec: 1840 + hash: "20ced2b9960931c4c0cbe8bcc1f9e52a" + } + Frame { + msec: 1856 + hash: "09710c8964c8b010a90c67f126acdefa" + } + Frame { + msec: 1872 + hash: "09710c8964c8b010a90c67f126acdefa" + } + Frame { + msec: 1888 + hash: "09710c8964c8b010a90c67f126acdefa" + } + Frame { + msec: 1904 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 1920 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 1936 + image: "flickable-nested.2.png" + } + Frame { + msec: 1952 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 1968 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 1984 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2000 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2016 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2032 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2048 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2064 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2080 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2096 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2112 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2128 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2144 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2160 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2176 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2192 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2208 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2224 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2240 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2256 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2272 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2288 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Frame { + msec: 2304 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Mouse { + type: 2 + button: 1 + buttons: 1 + x: 274; y: 218 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2320 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 273; y: 218 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 273; y: 217 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2336 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 272; y: 215 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 272; y: 213 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2352 + hash: "e80b03bd168ec62aba64cdf75dcd1d5f" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 271; y: 210 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 270; y: 208 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2368 + hash: "79a132ab719ccdf48d367cca443cd835" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 269; y: 204 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 269; y: 202 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2384 + hash: "1f19e7d2c7494f5b603dee16e211d65d" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 268; y: 196 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 268; y: 193 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2400 + hash: "64fd22407c77fac28d13035ce78c67b2" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 268; y: 186 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 266; y: 177 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2416 + hash: "f05a0f956b4964d4ebff056b63252297" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 265; y: 173 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 264; y: 167 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2432 + hash: "3de1e9a2b33e37b0fe3b799b68ec22d6" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 263; y: 164 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 3 + button: 1 + buttons: 0 + x: 263; y: 164 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2448 + hash: "71f115c60d4f20422e4ac3f319644c48" + } + Frame { + msec: 2464 + hash: "c3995ac89f0a4b3fb07401479538d338" + } + Frame { + msec: 2480 + hash: "950e83408adf55f4e7fc1c0c127caa89" + } + Frame { + msec: 2496 + hash: "5b335621a76a527d058708384c2e5635" + } + Frame { + msec: 2512 + hash: "a201ae31d5bb778bd44a49dd21951c1b" + } + Frame { + msec: 2528 + hash: "550e6708a8999d56d1f57c121228692f" + } + Frame { + msec: 2544 + hash: "d8eb4dd2b3cf50273cb7dfbb5bd658b9" + } + Frame { + msec: 2560 + hash: "aa1fd0a990e42175acc84de96b384e9d" + } + Frame { + msec: 2576 + hash: "0236fb15db30da5ec794444affee1169" + } + Frame { + msec: 2592 + hash: "a7445a70874a9767462e79e1dff88dbc" + } + Frame { + msec: 2608 + hash: "339ea6bd5b486ff85272e19e07669f0b" + } + Frame { + msec: 2624 + hash: "2b24d9d17c77cd0ac52989328dcf499b" + } + Frame { + msec: 2640 + hash: "2b24d9d17c77cd0ac52989328dcf499b" + } + Frame { + msec: 2656 + hash: "e2fcfe4f3e14e46404eb6955502180a1" + } + Frame { + msec: 2672 + hash: "5d0c9601b871690047f4df91723ccfb1" + } + Frame { + msec: 2688 + hash: "5d0c9601b871690047f4df91723ccfb1" + } + Frame { + msec: 2704 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Frame { + msec: 2720 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Frame { + msec: 2736 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Frame { + msec: 2752 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Frame { + msec: 2768 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Frame { + msec: 2784 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Frame { + msec: 2800 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Frame { + msec: 2816 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Frame { + msec: 2832 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Frame { + msec: 2848 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Frame { + msec: 2864 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Frame { + msec: 2880 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Frame { + msec: 2896 + image: "flickable-nested.3.png" + } + Frame { + msec: 2912 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Frame { + msec: 2928 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Frame { + msec: 2944 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Frame { + msec: 2960 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Mouse { + type: 2 + button: 1 + buttons: 1 + x: 268; y: 102 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2976 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 268; y: 103 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 268; y: 104 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 2992 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 268; y: 105 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 269; y: 108 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 3008 + hash: "5b5d7e880e9f4942f52a3cde738dc7fb" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 270; y: 111 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 270; y: 114 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 3024 + hash: "2b24d9d17c77cd0ac52989328dcf499b" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 271; y: 119 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 272; y: 122 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 3040 + hash: "550e6708a8999d56d1f57c121228692f" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 273; y: 130 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 274; y: 138 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 3056 + hash: "57f3c0a49cef2137e3cfa435396c099e" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 274; y: 142 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 274; y: 149 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 3072 + hash: "0fffc659a270cc614d16ddf3fa2ab51d" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 274; y: 153 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 274; y: 161 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 3088 + hash: "a8d937c8379950299a6e3611ff313415" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 273; y: 165 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 272; y: 172 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 3104 + hash: "46cfebbf821a08aa30055bfa8fffd137" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 271; y: 175 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 270; y: 180 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 3 + button: 1 + buttons: 0 + x: 270; y: 180 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 3120 + hash: "20a32ee8ae2cf88a2cfdb2dd8552255a" + } + Frame { + msec: 3136 + hash: "20a32ee8ae2cf88a2cfdb2dd8552255a" + } + Frame { + msec: 3152 + hash: "20a32ee8ae2cf88a2cfdb2dd8552255a" + } + Frame { + msec: 3168 + hash: "20a32ee8ae2cf88a2cfdb2dd8552255a" + } + Frame { + msec: 3184 + hash: "20a32ee8ae2cf88a2cfdb2dd8552255a" + } + Frame { + msec: 3200 + hash: "20a32ee8ae2cf88a2cfdb2dd8552255a" + } + Frame { + msec: 3216 + hash: "20a32ee8ae2cf88a2cfdb2dd8552255a" + } + Frame { + msec: 3232 + hash: "20a32ee8ae2cf88a2cfdb2dd8552255a" + } + Frame { + msec: 3248 + hash: "20a32ee8ae2cf88a2cfdb2dd8552255a" + } + Frame { + msec: 3264 + hash: "20a32ee8ae2cf88a2cfdb2dd8552255a" + } + Frame { + msec: 3280 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3296 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3312 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3328 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3344 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3360 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3376 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3392 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3408 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3424 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3440 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3456 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3472 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3488 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3504 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3520 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3536 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3552 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3568 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 3584 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Mouse { + type: 2 + button: 1 + buttons: 1 + x: 352; y: 206 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 3600 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 352; y: 205 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 352; y: 204 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 3616 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 352; y: 201 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 352; y: 196 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 3632 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 352; y: 193 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 352; y: 185 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 3648 + hash: "eb718f97648438dae1440e2089434b0a" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 352; y: 176 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 352; y: 172 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 3664 + hash: "e4a2b82752939f351ac46032f2d3333e" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 353; y: 163 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 354; y: 158 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 3680 + hash: "ab1099a146433a5ec77b336673d0527c" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 356; y: 148 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 356; y: 142 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 3696 + hash: "7e4ca5ba45d5de10d72ef5ab1171ead5" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 357; y: 130 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 3 + button: 1 + buttons: 0 + x: 357; y: 130 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 3712 + hash: "417bb78fc4f255194a71193e388b752f" + } + Frame { + msec: 3728 + hash: "be63b1e57006d881a345db3ca66e7097" + } + Frame { + msec: 3744 + hash: "e1b96137c2cc0ef18e224a32f665de9d" + } + Frame { + msec: 3760 + hash: "6157ba3962fc7829e8693e2456fd6e8e" + } + Frame { + msec: 3776 + hash: "951ae231b7b18517f8d6504ce7f01b3d" + } + Frame { + msec: 3792 + hash: "57f60f9da1a204cc7eb930575de45ae4" + } + Frame { + msec: 3808 + hash: "008323603b48a55b589af7cbb2f1c8b0" + } + Frame { + msec: 3824 + hash: "b8447e994280cba5ccddc36e7ad3c927" + } + Frame { + msec: 3840 + hash: "98dfc2d6573e5cb7a56a893b8fecf422" + } + Frame { + msec: 3856 + image: "flickable-nested.4.png" + } + Frame { + msec: 3872 + hash: "09dabc3ef85dc857719e7d20111e6023" + } + Frame { + msec: 3888 + hash: "5864c4197fe3269c3f1ad05caf25832e" + } + Frame { + msec: 3904 + hash: "370a471a614d22d281d9987a5b6a42bf" + } + Frame { + msec: 3920 + hash: "36c74e2e325807c7c06e941581613f48" + } + Frame { + msec: 3936 + hash: "e1e2b69992294dc611e6eef7e259d4cd" + } + Frame { + msec: 3952 + hash: "e1e2b69992294dc611e6eef7e259d4cd" + } + Frame { + msec: 3968 + hash: "e1e2b69992294dc611e6eef7e259d4cd" + } + Frame { + msec: 3984 + hash: "36c74e2e325807c7c06e941581613f48" + } + Frame { + msec: 4000 + hash: "36c74e2e325807c7c06e941581613f48" + } + Frame { + msec: 4016 + hash: "bd8f39423d96fceaf577c7f792b61211" + } + Frame { + msec: 4032 + hash: "370a471a614d22d281d9987a5b6a42bf" + } + Frame { + msec: 4048 + hash: "c8fe4424d96460a2503632e3a54d4f6a" + } + Frame { + msec: 4064 + hash: "09dabc3ef85dc857719e7d20111e6023" + } + Frame { + msec: 4080 + hash: "22bff1406eba529d58320b8b19be76d9" + } + Frame { + msec: 4096 + hash: "478bc04322b93b75b5185d047c2898b7" + } + Frame { + msec: 4112 + hash: "98dfc2d6573e5cb7a56a893b8fecf422" + } + Frame { + msec: 4128 + hash: "03b96d3e148e86f1150b09696012d07c" + } + Frame { + msec: 4144 + hash: "735b24d2811beef969477c8b0f400d32" + } + Frame { + msec: 4160 + hash: "b8399d2a7a6de0b5f81e68e8f8825622" + } + Frame { + msec: 4176 + hash: "766a97e0881b623a0de93babfa841125" + } + Frame { + msec: 4192 + hash: "008323603b48a55b589af7cbb2f1c8b0" + } + Frame { + msec: 4208 + hash: "3da913235e4916b4691e3d089dc7b52f" + } + Frame { + msec: 4224 + hash: "3da913235e4916b4691e3d089dc7b52f" + } + Frame { + msec: 4240 + hash: "8c7f6ff7b3db65d7dd9ac4d18545f0d1" + } + Frame { + msec: 4256 + hash: "8c7f6ff7b3db65d7dd9ac4d18545f0d1" + } + Mouse { + type: 2 + button: 1 + buttons: 1 + x: 346; y: 95 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 4272 + hash: "8c7f6ff7b3db65d7dd9ac4d18545f0d1" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 346; y: 98 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 346; y: 103 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 4288 + hash: "951ae231b7b18517f8d6504ce7f01b3d" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 348; y: 110 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 348; y: 115 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 4304 + hash: "364283bbbcedabc87689ec174ae29818" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 351; y: 124 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 353; y: 129 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 4320 + hash: "6a8a59ba8cf0539704fc035d7d5def41" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 358; y: 141 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 361; y: 145 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 4336 + hash: "d4626b39fbf24cc6a4e23ef33a570add" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 370; y: 163 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 4352 + hash: "255604ac684a18e272dccfa9a81fa1bb" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 376; y: 172 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 4368 + hash: "2696641e48ea2a0ccfc65057b283814f" + } + Mouse { + type: 5 + button: 0 + buttons: 1 + x: 377; y: 175 + modifiers: 0 + sendToViewport: true + } + Mouse { + type: 3 + button: 1 + buttons: 0 + x: 377; y: 175 + modifiers: 0 + sendToViewport: true + } + Frame { + msec: 4384 + hash: "4ae011d8d81c57f9e2495d32a90fb5c0" + } + Frame { + msec: 4400 + hash: "c07f57059244b1164e698430b20aac8e" + } + Frame { + msec: 4416 + hash: "d39c21bc6fc079c76ea78d1a3fb0c974" + } + Frame { + msec: 4432 + hash: "f955985ee02fcb810ab8c5f4790f5c12" + } + Frame { + msec: 4448 + hash: "d06b83769bf0f0331e53c270f5dc294c" + } + Frame { + msec: 4464 + hash: "a49ef3866e3f71c26c57fcd616a6dc4c" + } + Frame { + msec: 4480 + hash: "086f4bb966b2076f51b1f615368afda5" + } + Frame { + msec: 4496 + hash: "898de0b200cb83c9724869dd2b74ed52" + } + Frame { + msec: 4512 + hash: "47833f93c5c55f57de5733950ba53714" + } + Frame { + msec: 4528 + hash: "0ced71db7e8c5b8ce8e195a7b821507d" + } + Frame { + msec: 4544 + hash: "84888b8748e297ed4e0525019865ea2b" + } + Frame { + msec: 4560 + hash: "0f62d1aaa0fec0dd90351258a3745869" + } + Frame { + msec: 4576 + hash: "e34a874942161ea830907f94040fc0a5" + } + Frame { + msec: 4592 + hash: "9031e4ad8ee57a8b826d6a6394f0feb9" + } + Frame { + msec: 4608 + hash: "9031e4ad8ee57a8b826d6a6394f0feb9" + } + Frame { + msec: 4624 + hash: "cc8a2477368001015b68c99db95ebaa1" + } + Frame { + msec: 4640 + hash: "01c0f4d5b155eb16ac364b24d5085bac" + } + Frame { + msec: 4656 + hash: "4c4f318b03e0da461bcecb61f43ef3cd" + } + Frame { + msec: 4672 + hash: "dffd22d719f18c943cd0c30afe272434" + } + Frame { + msec: 4688 + hash: "4f7ab0450512ae1319dad22a6e0400b7" + } + Frame { + msec: 4704 + hash: "ea29e23bdb49a30694640dfb078c796a" + } + Frame { + msec: 4720 + hash: "80739ed287906d0b55297be4b74a54cb" + } + Frame { + msec: 4736 + hash: "8d9117cf841c4b158f30b79ac8f2afb0" + } + Frame { + msec: 4752 + hash: "1850e9117160b2bd1865274092f9ec84" + } + Frame { + msec: 4768 + hash: "07945c8954860895f95f8e352c49e0a5" + } + Frame { + msec: 4784 + hash: "d0fa6087d2859446ff8f317c9d7dafe1" + } + Frame { + msec: 4800 + hash: "8ebba2084793d90a640ec2fb12dc0547" + } + Frame { + msec: 4816 + image: "flickable-nested.5.png" + } + Frame { + msec: 4832 + hash: "77d479675c36ecda0926061449f5a60b" + } + Frame { + msec: 4848 + hash: "77d479675c36ecda0926061449f5a60b" + } + Frame { + msec: 4864 + hash: "b968c1528ce7ecf80008fbd56f0ca9a9" + } + Frame { + msec: 4880 + hash: "b968c1528ce7ecf80008fbd56f0ca9a9" + } + Frame { + msec: 4896 + hash: "b968c1528ce7ecf80008fbd56f0ca9a9" + } + Frame { + msec: 4912 + hash: "b968c1528ce7ecf80008fbd56f0ca9a9" + } + Frame { + msec: 4928 + hash: "b968c1528ce7ecf80008fbd56f0ca9a9" + } + Frame { + msec: 4944 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 4960 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 4976 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 4992 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5008 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5024 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5040 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5056 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5072 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5088 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5104 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5120 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5136 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5152 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5168 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5184 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5200 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5216 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5232 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5248 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5264 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5280 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5296 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5312 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5328 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5344 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5360 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5376 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5392 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5408 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5424 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5440 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5456 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5472 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5488 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5504 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5520 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5536 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5552 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5568 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5584 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5600 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5616 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5632 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5648 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5664 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5680 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } + Frame { + msec: 5696 + hash: "38f29e86bd9bfe4df04c6411374f76ae" + } +} diff --git a/tests/auto/declarative/qmlvisual/qdeclarativeflickable/flickable-nested.qml b/tests/auto/declarative/qmlvisual/qdeclarativeflickable/flickable-nested.qml new file mode 100644 index 0000000..9335b9e --- /dev/null +++ b/tests/auto/declarative/qmlvisual/qdeclarativeflickable/flickable-nested.qml @@ -0,0 +1,50 @@ +import QtQuick 1.0 + +Item { + width: 640 + height: 400 + + Flickable { + objectName: "flick 1" + anchors.fill: parent + contentWidth: width + 100 + contentHeight: height + 100 + + Rectangle { + width: 300 + height: 300 + color: "blue" + + Flickable { + objectName: "flick 2" + width: 300 + height: 300 + clip: true + contentWidth: 400 + contentHeight: 400 + + Rectangle { + width: 100 + height: 100 + anchors.centerIn: parent + color: "yellow" + + Flickable { + objectName: "flick 3" + anchors.fill: parent + clip: true + contentWidth: 150 + contentHeight: 150 + Rectangle { + x: 80 + y: 80 + width: 50 + height: 50 + color: "green" + } + } + } + } + } + } +} -- cgit v0.12 From 1699e8240b8073241f1aaddc12ded6065ef520b9 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 23 Dec 2010 11:02:04 +1000 Subject: Ensure PathView doesn't jump when starting to drag. Task-number: QTBUG-16133 Reviewed-by: Bea Lam --- .../graphicsitems/qdeclarativepathview.cpp | 4 +- .../data/test-pathview-2.0.png | Bin 1114 -> 1114 bytes .../data/test-pathview-2.1.png | Bin 1105 -> 1119 bytes .../data/test-pathview-2.2.png | Bin 1088 -> 1102 bytes .../data/test-pathview-2.3.png | Bin 1096 -> 1092 bytes .../data/test-pathview-2.4.png | Bin 1143 -> 1143 bytes .../data/test-pathview-2.5.png | Bin 1143 -> 1143 bytes .../qdeclarativepathview/data/test-pathview-2.qml | 366 +++++------ .../qdeclarativepathview/data/test-pathview.0.png | Bin 1169 -> 1169 bytes .../qdeclarativepathview/data/test-pathview.1.png | Bin 1182 -> 1172 bytes .../qdeclarativepathview/data/test-pathview.2.png | Bin 1211 -> 1201 bytes .../qdeclarativepathview/data/test-pathview.3.png | Bin 1184 -> 1164 bytes .../qdeclarativepathview/data/test-pathview.4.png | Bin 1152 -> 1226 bytes .../qdeclarativepathview/data/test-pathview.5.png | Bin 1141 -> 1192 bytes .../qdeclarativepathview/data/test-pathview.6.png | Bin 1189 -> 1188 bytes .../qdeclarativepathview/data/test-pathview.qml | 672 ++++++++++----------- .../qdeclarativepathview/test-pathview.qml | 2 + 17 files changed, 524 insertions(+), 520 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativepathview.cpp b/src/declarative/graphicsitems/qdeclarativepathview.cpp index 87ea214..a6f44b3 100644 --- a/src/declarative/graphicsitems/qdeclarativepathview.cpp +++ b/src/declarative/graphicsitems/qdeclarativepathview.cpp @@ -1133,8 +1133,10 @@ void QDeclarativePathViewPrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent QPointF pathPoint = pointNear(event->pos(), &newPc); if (!stealMouse) { QPointF delta = pathPoint - startPoint; - if (qAbs(delta.x()) > QApplication::startDragDistance() || qAbs(delta.y()) > QApplication::startDragDistance()) + if (qAbs(delta.x()) > QApplication::startDragDistance() || qAbs(delta.y()) > QApplication::startDragDistance()) { stealMouse = true; + startPc = newPc; + } } if (stealMouse) { diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.0.png b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.0.png index 699f83e..347e773 100644 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.0.png and b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.0.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.1.png b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.1.png index a742a6a..370ca80 100644 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.1.png and b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.1.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.2.png b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.2.png index 71abae2..97e3906 100644 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.2.png and b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.2.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.3.png b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.3.png index a6e6b3e..5fa3c67 100644 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.3.png and b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.3.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.4.png b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.4.png index 9f125c4..ce11c09 100644 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.4.png and b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.4.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.5.png b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.5.png index 41d0cd5..d155742 100644 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.5.png and b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.5.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.qml b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.qml index b75d140..304d5c7 100644 --- a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.qml +++ b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview-2.qml @@ -222,7 +222,7 @@ VisualTest { } Frame { msec: 752 - hash: "e21cac055208e47e267ac906c7c2ca9c" + hash: "d2dda5bec262721d653e88ec3eaeca57" } Mouse { type: 5 @@ -234,7 +234,7 @@ VisualTest { } Frame { msec: 768 - hash: "131e094a79edbeea9a1b981592e55abf" + hash: "d61d21ab4d83b8578494720d9bfe6fa8" } Mouse { type: 5 @@ -254,7 +254,7 @@ VisualTest { } Frame { msec: 784 - hash: "73faabf52bd2af8d8b9d28ce21e5e77b" + hash: "0a178235529d721529e8dc3b439a64c9" } Mouse { type: 5 @@ -266,7 +266,7 @@ VisualTest { } Frame { msec: 800 - hash: "359554a95362db1734f606cf677001fc" + hash: "c800609ffea814ba7cc2441790157245" } Mouse { type: 5 @@ -286,43 +286,43 @@ VisualTest { } Frame { msec: 816 - hash: "8ef4ecc5c5ba578f0279dc57a6c17ccd" + hash: "afcb452d41c6e895309bb921a1ad1d31" } Frame { msec: 832 - hash: "69c3d9d2700dd395b656b0b09fa63511" + hash: "02d8f91c33f62aaf366bcfd03d232269" } Frame { msec: 848 - hash: "2bbcc36d72c3e9a4b672a46f2aae5076" + hash: "1ba9bc8c2b941fd0ec82f211eb559682" } Frame { msec: 864 - hash: "125a5f0c8efdf97676edbe379660dcce" + hash: "ee8680df3c58a48f3fff4a8fc221e38c" } Frame { msec: 880 - hash: "4347a02227207fbf870b6aed76131619" + hash: "36c04a2bd58124877a332bb6a262a7e5" } Frame { msec: 896 - hash: "e08b494c818669bfc48273598574d22e" + hash: "e6ea836d68c54a8308e10f33d4eb8b98" } Frame { msec: 912 - hash: "186cb5465f45c0df8082ec8cad6ee8b1" + hash: "f2400819feb116ae3b327284bbb292ff" } Frame { msec: 928 - hash: "91d04d4469492c3bb2a1ed415dcd904c" + hash: "5d9a3458cb59ede36e7b51bac869785a" } Frame { msec: 944 - hash: "8cc8ef251d68af926a8f300b8666ecfd" + hash: "b859b690c633a9fec87941e7c89f5d19" } Frame { msec: 960 - hash: "42f64722245f8519386e75ce7e3c0cd9" + hash: "ef0b66e789a8e88389e16bfa36b9f6e2" } Frame { msec: 976 @@ -330,195 +330,195 @@ VisualTest { } Frame { msec: 992 - hash: "058311da9dcf73a4b4928038334b04b5" + hash: "493e3c7b0de4a7b4b46678fe4ce9a763" } Frame { msec: 1008 - hash: "ea662934ee0c3c8d4dbde3ad49448922" + hash: "b7056d635c69b8e5bf98872f4c07ed43" } Frame { msec: 1024 - hash: "01991a871819e7bdbf817580f720ead6" + hash: "68aa8bd6709e1b49cfefc4594c236c46" } Frame { msec: 1040 - hash: "69a7fe47ae589bcc2607cc42fcea7451" + hash: "4b28ebf737b8c4228771122d844b8166" } Frame { msec: 1056 - hash: "8240d087b767311e00b7dd4b8726246c" + hash: "b04155316770a1265e5dc431e1b9a9a1" } Frame { msec: 1072 - hash: "cc70c8e79d68f09e6db0dd43b99906b7" + hash: "d540453541aba394b0958cdc48f91d48" } Frame { msec: 1088 - hash: "2bfabef74bc6e1dbf72111838a0e7557" + hash: "b3e7cbc83c65ec61c768757798b17c58" } Frame { msec: 1104 - hash: "66616f01553364c5bd589b781e22163a" + hash: "b12b31d4959a697fcc8e54f1c846eef9" } Frame { msec: 1120 - hash: "58b9de84ebdaabee3917608f2af3bbdb" + hash: "77c3bbb94471cfbfd23cc3914d796dfc" } Frame { msec: 1136 - hash: "964d96b9b783efb1053501f8a6931248" + hash: "41975592e60f08a0296a8babe1da2df3" } Frame { msec: 1152 - hash: "055b77b921a2bac71b6780ab3179f19f" + hash: "0a5eea8a11b15ee8583f187f336f56c7" } Frame { msec: 1168 - hash: "074904f31b4f7cf0679f0bf7bba30af2" + hash: "bf9c02945fdee4b06353f8f7f4fca2a3" } Frame { msec: 1184 - hash: "f020a490b6800d5b4402ecb9a8bcd436" + hash: "157c92d133a39a2b1d20a551303d2f6f" } Frame { msec: 1200 - hash: "1615bdedf92f91f089e494d893840c4b" + hash: "213716cad9fa2179a17a512e8c03c8f5" } Frame { msec: 1216 - hash: "b6892f6a5db6d211f0d1bb2bbe5045bf" + hash: "0ec517c50e9e36fef4fb14318e298723" } Frame { msec: 1232 - hash: "5f0d903ba682923ac69454026a359ed9" + hash: "bab010fe0f5d3b57fd556a9b709c285e" } Frame { msec: 1248 - hash: "da5bae496a9ad28585151f4c75ee0c9f" + hash: "b6bdf2f21c4137d4b5f25e0fe728bba5" } Frame { msec: 1264 - hash: "68f553248f7ca116671782d1c357b552" + hash: "c091e46064c8096568224ed7e4c8dc4f" } Frame { msec: 1280 - hash: "5503df04dd7f4c88314f9d309a5b36b4" + hash: "c0a6ede96566533ab35384afa535530f" } Frame { msec: 1296 - hash: "cc48c1f58b553adcb27d60f176e2b910" + hash: "f61f5c7617700b9aad71206cfc9e402e" } Frame { msec: 1312 - hash: "661f546199d8753a7b6f6ccea5928c12" + hash: "c70c106d128051c06da3acdf817f5ffb" } Frame { msec: 1328 - hash: "0fd70052c100f77bddbad177d9e5573d" + hash: "624d7c7fb2f39225d51d1a548aa186ed" } Frame { msec: 1344 - hash: "488e0652c0ed82a014de63a64145c34c" + hash: "f052610f17a7484bf6cb2bd07aa91af6" } Frame { msec: 1360 - hash: "8b6bf2519080a6e4a61fe216f72dfa09" + hash: "44cd80041a1965c8c60fdffd9ae19395" } Frame { msec: 1376 - hash: "4dab1827f6ce9561297fce8e067df1bd" + hash: "7597f86b537fbd70260908c973f9db21" } Frame { msec: 1392 - hash: "b3f4c5cd728eaf2b791612a7fea64e7b" + hash: "30cd60db9aa2df2adc7d01091c905cb4" } Frame { msec: 1408 - hash: "3d01abd0b8a5a62d58a4c09546f212d8" + hash: "8da4613759e9bcb926a0c84556213eb5" } Frame { msec: 1424 - hash: "e76796498cf595c60d4b60cc0e320601" + hash: "1085fcc81f0aed8508817839ca748359" } Frame { msec: 1440 - hash: "1b31e96f2823e78a0c4029e7bc45b9f2" + hash: "b87f002bf6fb0684f0b3cf565507e066" } Frame { msec: 1456 - hash: "f75c182dc24f4fabe1034ee494dba2ad" + hash: "b60916a57aec6ebbd8b69be7c8d66e19" } Frame { msec: 1472 - hash: "646c12edadf350405709860381cfced6" + hash: "a28e1538d18ccb7485d0306b9f7b18a6" } Frame { msec: 1488 - hash: "b6719406da9f2484fe55e3c69184f86c" + hash: "832c857f2e05f2f82308cbf91f7bf401" } Frame { msec: 1504 - hash: "5456857d6d48d064df1cb3f35d8447b5" + hash: "ca3e50cd337a07ef07f063be28fa6dc2" } Frame { msec: 1520 - hash: "8d1809b568345e1532fb6d9428fc9729" + hash: "3ecf7faa733653ef20e4a26eb47d63d1" } Frame { msec: 1536 - hash: "5cffa76fe09a771a9f62a9f0392f0431" + hash: "f17a6be2e183f4c87e31004458e5052c" } Frame { msec: 1552 - hash: "8de59915e874ce829c691a19ac930f28" + hash: "bfa62672ee7fcd9c3a75b63198a4c2bf" } Frame { msec: 1568 - hash: "9027bbf8121f70d26530f70423ec05b7" + hash: "cdaafe7f622c18c2409ac539649de1cd" } Frame { msec: 1584 - hash: "d3d1d8b9f7b4eb74a8b7ae5cf19a8e20" + hash: "c957f5c58e0a9b315b51ac1012709493" } Frame { msec: 1600 - hash: "81ffcc0147e3124a3015deb7c0dbfd90" + hash: "925c55a8564f2318f9de4bd406cb5b13" } Frame { msec: 1616 - hash: "ca0c96e908f05c4ee1af1f80d7b432aa" + hash: "466208a8f6ecf45393be01a6dd7f2b0f" } Frame { msec: 1632 - hash: "2bdb6fbf942623856a6963c335794dd2" + hash: "35cff8c0f4b503ba4948966079484feb" } Frame { msec: 1648 - hash: "18ac264d9ea9b592b0738f1cf732f678" + hash: "47472faf5e9bf4b4e514abe55f1e0b72" } Frame { msec: 1664 - hash: "1ee9adbbae7b97dc050c82b8ed7b0aad" + hash: "b699165e354bcadfd0d914d9ecb3d2aa" } Frame { msec: 1680 - hash: "b502390c452883ade550d2761bb09d3d" + hash: "e255c047ce78f5677ccec8bd9737201a" } Frame { msec: 1696 - hash: "31a6f573fbb3f545ee051e2290938004" + hash: "bd4f08095a9c546a42c85e6df6eaf655" } Frame { msec: 1712 - hash: "3be9788228d9e540313e75671319c5b7" + hash: "ca65869f48b169260c3756d846a12f36" } Frame { msec: 1728 - hash: "23cbd718154f939d8270674e8f7607f0" + hash: "1921889beb8e61c8b959d4affa814465" } Frame { msec: 1744 - hash: "5f7f49b894b80ddd7cdc544a49ec24a2" + hash: "a9dda9ebaa97133c671917473721272c" } Mouse { type: 2 @@ -538,11 +538,11 @@ VisualTest { } Frame { msec: 1760 - hash: "2a1ddee3d3a0c2a4fffab3988e35e274" + hash: "cab96d2118b31d43e85dc902df2ed8ed" } Frame { msec: 1776 - hash: "2a1ddee3d3a0c2a4fffab3988e35e274" + hash: "cab96d2118b31d43e85dc902df2ed8ed" } Mouse { type: 5 @@ -562,7 +562,7 @@ VisualTest { } Frame { msec: 1792 - hash: "5594b9139480ba1c814509a049f9b6c5" + hash: "d21c8af68b314800b86922493db6553e" } Mouse { type: 5 @@ -574,7 +574,7 @@ VisualTest { } Frame { msec: 1808 - hash: "d8729deb404f5b821264743943adb288" + hash: "a80c0f6f679ba5f1354f8e16677c1125" } Mouse { type: 5 @@ -586,7 +586,7 @@ VisualTest { } Frame { msec: 1824 - hash: "6de642baf7698ec65d48ccf0a1e8e7db" + hash: "d8729deb404f5b821264743943adb288" } Mouse { type: 5 @@ -606,7 +606,7 @@ VisualTest { } Frame { msec: 1840 - hash: "f6732999861d1f638484a5aaa9cf0550" + hash: "87d41239eb7e170fa7a1ed523a9af942" } Mouse { type: 5 @@ -618,7 +618,7 @@ VisualTest { } Frame { msec: 1856 - hash: "7cd7c1679838f35556bd4ee4565b7a86" + hash: "1c185649e08a54a6949409ed7ee5dc60" } Mouse { type: 5 @@ -638,7 +638,7 @@ VisualTest { } Frame { msec: 1872 - hash: "4276a4d9350503603b0c9c98552697b3" + hash: "d82969ef0f4baf3c51e112e049cb1334" } Mouse { type: 5 @@ -650,7 +650,7 @@ VisualTest { } Frame { msec: 1888 - hash: "954a47627aee0a1128a78191bf32d984" + hash: "e746a3eb8527036b09afb9cdd3d15648" } Mouse { type: 5 @@ -662,7 +662,7 @@ VisualTest { } Frame { msec: 1904 - hash: "360a47795f7f9389f82f2f55fa1fe83f" + hash: "e1d6c01f6cd66a5bcdb08ca810a07282" } Mouse { type: 5 @@ -674,7 +674,7 @@ VisualTest { } Frame { msec: 1920 - hash: "19d4284791d0031342ba995bd17a7833" + hash: "fd0e9cf835131ee6cc5ecf67c6724d73" } Mouse { type: 5 @@ -706,7 +706,7 @@ VisualTest { } Frame { msec: 1952 - hash: "e9cd8fb810ecf39a90af039ead97aaf1" + hash: "69c17a9c18795b1d8ae63d36d76af626" } Mouse { type: 5 @@ -726,7 +726,7 @@ VisualTest { } Frame { msec: 1968 - hash: "42df1a0fbbe7cce5f2359d9e02696299" + hash: "c7ca4762498af158a2f2da6f5ae560ce" } Mouse { type: 5 @@ -738,7 +738,7 @@ VisualTest { } Frame { msec: 1984 - hash: "cc71434d6bd162386b80cb3b7e387116" + hash: "f500232133ec07a3b833b06425379484" } Mouse { type: 5 @@ -758,7 +758,7 @@ VisualTest { } Frame { msec: 2000 - hash: "a130b471b3903f3f1d77f2306da2b92e" + hash: "0a0cd0433e206dfc923ec0d3617e04a1" } Mouse { type: 5 @@ -770,7 +770,7 @@ VisualTest { } Frame { msec: 2016 - hash: "5bdb7472e325651e891c115953afdb39" + hash: "1754875ee6a5712ffb8ce1bbae6d4ed1" } Mouse { type: 5 @@ -782,7 +782,7 @@ VisualTest { } Frame { msec: 2032 - hash: "ab3a64b41c67a0b8a6c0830c0e0cb797" + hash: "1e743264f0a312bc0d0a023fbc6db832" } Mouse { type: 5 @@ -794,7 +794,7 @@ VisualTest { } Frame { msec: 2048 - hash: "8eb1f2c8c02c2acf4262e05000045649" + hash: "ab3a64b41c67a0b8a6c0830c0e0cb797" } Mouse { type: 5 @@ -806,7 +806,7 @@ VisualTest { } Frame { msec: 2064 - hash: "514220d357c4a26e4aaf9ed20d3f4f33" + hash: "d05f721f1d7d23d6e0cc67993bf1fa8f" } Mouse { type: 5 @@ -818,7 +818,7 @@ VisualTest { } Frame { msec: 2080 - hash: "e44526ef273048028d5989fc662eb7e6" + hash: "419c09739f855c53be3427a71aa3faf9" } Mouse { type: 5 @@ -838,7 +838,7 @@ VisualTest { } Frame { msec: 2096 - hash: "29ac091428a89cfcb4c52c08e0e10327" + hash: "f0ae80ed5965d7531d6a653c80eed444" } Mouse { type: 5 @@ -858,7 +858,7 @@ VisualTest { } Frame { msec: 2112 - hash: "82beb845af88fc9432dc104ff805a146" + hash: "1419fe55cc28ce9690846d4c03275fe7" } Mouse { type: 5 @@ -870,7 +870,7 @@ VisualTest { } Frame { msec: 2128 - hash: "371392f267b2c1f4e29963506180e246" + hash: "2e22df53697a599b0e44fb2a3986dcd0" } Mouse { type: 5 @@ -882,11 +882,11 @@ VisualTest { } Frame { msec: 2144 - hash: "1da06d036cc0a2d2de34eee37b6981c0" + hash: "96f763c555b523d9b7ed7a0a159db368" } Frame { msec: 2160 - hash: "1da06d036cc0a2d2de34eee37b6981c0" + hash: "96f763c555b523d9b7ed7a0a159db368" } Mouse { type: 5 @@ -898,31 +898,31 @@ VisualTest { } Frame { msec: 2176 - hash: "4980de22342d1085e205401090777d24" + hash: "20f9cf7787c8cfd4843289f5ab2012e7" } Frame { msec: 2192 - hash: "4980de22342d1085e205401090777d24" + hash: "20f9cf7787c8cfd4843289f5ab2012e7" } Frame { msec: 2208 - hash: "4980de22342d1085e205401090777d24" + hash: "20f9cf7787c8cfd4843289f5ab2012e7" } Frame { msec: 2224 - hash: "4980de22342d1085e205401090777d24" + hash: "20f9cf7787c8cfd4843289f5ab2012e7" } Frame { msec: 2240 - hash: "4980de22342d1085e205401090777d24" + hash: "20f9cf7787c8cfd4843289f5ab2012e7" } Frame { msec: 2256 - hash: "4980de22342d1085e205401090777d24" + hash: "20f9cf7787c8cfd4843289f5ab2012e7" } Frame { msec: 2272 - hash: "4980de22342d1085e205401090777d24" + hash: "20f9cf7787c8cfd4843289f5ab2012e7" } Mouse { type: 5 @@ -934,7 +934,7 @@ VisualTest { } Frame { msec: 2288 - hash: "e0a52543b976dc998615704c63b1f3e9" + hash: "1241895174f4d8e4386c3957e3d2e292" } Mouse { type: 5 @@ -946,7 +946,7 @@ VisualTest { } Frame { msec: 2304 - hash: "82beb845af88fc9432dc104ff805a146" + hash: "1419fe55cc28ce9690846d4c03275fe7" } Mouse { type: 5 @@ -958,7 +958,7 @@ VisualTest { } Frame { msec: 2320 - hash: "e44526ef273048028d5989fc662eb7e6" + hash: "419c09739f855c53be3427a71aa3faf9" } Mouse { type: 5 @@ -978,7 +978,7 @@ VisualTest { } Frame { msec: 2336 - hash: "8eb1f2c8c02c2acf4262e05000045649" + hash: "ab3a64b41c67a0b8a6c0830c0e0cb797" } Mouse { type: 5 @@ -990,7 +990,7 @@ VisualTest { } Frame { msec: 2352 - hash: "442958c3a705745204db96ff9902b7fc" + hash: "a130b471b3903f3f1d77f2306da2b92e" } Mouse { type: 5 @@ -1002,31 +1002,31 @@ VisualTest { } Frame { msec: 2368 - hash: "a130b471b3903f3f1d77f2306da2b92e" + hash: "0a0cd0433e206dfc923ec0d3617e04a1" } Frame { msec: 2384 - hash: "a130b471b3903f3f1d77f2306da2b92e" + hash: "0a0cd0433e206dfc923ec0d3617e04a1" } Frame { msec: 2400 - hash: "a130b471b3903f3f1d77f2306da2b92e" + hash: "0a0cd0433e206dfc923ec0d3617e04a1" } Frame { msec: 2416 - hash: "a130b471b3903f3f1d77f2306da2b92e" + hash: "0a0cd0433e206dfc923ec0d3617e04a1" } Frame { msec: 2432 - hash: "a130b471b3903f3f1d77f2306da2b92e" + hash: "0a0cd0433e206dfc923ec0d3617e04a1" } Frame { msec: 2448 - hash: "a130b471b3903f3f1d77f2306da2b92e" + hash: "0a0cd0433e206dfc923ec0d3617e04a1" } Frame { msec: 2464 - hash: "a130b471b3903f3f1d77f2306da2b92e" + hash: "0a0cd0433e206dfc923ec0d3617e04a1" } Mouse { type: 5 @@ -1046,7 +1046,7 @@ VisualTest { } Frame { msec: 2480 - hash: "374dc7c3ea0c93ac93a857a4620bc031" + hash: "47e86b008567366f37ac043ed8802d53" } Mouse { type: 5 @@ -1058,7 +1058,7 @@ VisualTest { } Frame { msec: 2496 - hash: "0b943f48b39053bfc906a4a47a37d68a" + hash: "92e1d5dbc85e777785cc68171a0a3fbf" } Mouse { type: 5 @@ -1070,7 +1070,7 @@ VisualTest { } Frame { msec: 2512 - hash: "099fbdf1560dd79b700914863406c904" + hash: "360a47795f7f9389f82f2f55fa1fe83f" } Mouse { type: 5 @@ -1090,7 +1090,7 @@ VisualTest { } Frame { msec: 2528 - hash: "3aa1614cc49504d19e979ebf190f2970" + hash: "acefb43050e140d689f1d377f50f5c83" } Mouse { type: 5 @@ -1102,7 +1102,7 @@ VisualTest { } Frame { msec: 2544 - hash: "837420c71a5010f25cccd05e5e9b3eec" + hash: "4bc43ae81aac757c872157ac9b41a2d9" } Mouse { type: 5 @@ -1114,7 +1114,7 @@ VisualTest { } Frame { msec: 2560 - hash: "871349fc09f418717231b8f8e20a7fff" + hash: "41421089f087c54ebcd9fa44e95bd96e" } Mouse { type: 5 @@ -1134,7 +1134,7 @@ VisualTest { } Frame { msec: 2576 - hash: "9b6022024aae22ec1f522fd00ed29e9b" + hash: "db0f09393b5c9284142f9eb3cb5952ce" } Mouse { type: 5 @@ -1154,79 +1154,79 @@ VisualTest { } Frame { msec: 2592 - hash: "8d9410909ae259388fa94b3a60342608" + hash: "9491689e51ec46bec07fb8b280daef80" } Frame { msec: 2608 - hash: "0ceb355351ac99458ba75776c11b3039" + hash: "44a30531642ada65c052afe30874d7ba" } Frame { msec: 2624 - hash: "61ca917ecc8ad4c35b7f2a3b828542bf" + hash: "6bf415b82e7cfa68b8321571ab619c3f" } Frame { msec: 2640 - hash: "fd5db933d1d8684b15eb5239d19d8919" + hash: "645e43948279d528020070125b71c33b" } Frame { msec: 2656 - hash: "13f466a82ee22cabf5cbd2463f55b46a" + hash: "495d14df729eede7e560f2e841bae142" } Frame { msec: 2672 - hash: "3b7f7880f5b568a0e45cd0e268822f3a" + hash: "fa3b12e9869bf4254c8cdf6e5b10bb2d" } Frame { msec: 2688 - hash: "cca22501c3b5a2ed4264ba060eeb1a6e" + hash: "482ce41c4b918a71b803c5f521ea494e" } Frame { msec: 2704 - hash: "efe5258ac5962d1d2bfa4286c1621830" + hash: "79d70563c7e139d9f9785565219133c7" } Frame { msec: 2720 - hash: "141998cff765a4e90836b871f229a1ca" + hash: "0dc70772aa50445c1cb7dbd8ee0092b0" } Frame { msec: 2736 - hash: "9d684675fa883d5488194effcb1d8d0a" + hash: "222d638b8fb896563028f029e6fb3c49" } Frame { msec: 2752 - hash: "fa87f781048f264ddf447441a714ee50" + hash: "20b8fc718d9329c9c8901fdfe14557a2" } Frame { msec: 2768 - hash: "61b4992b9c52222345c9ada3148d50f9" + hash: "e3972b3244e4a98c9ee4df2d4b623c12" } Frame { msec: 2784 - hash: "3e255a634d215746cb95f5d765335ea2" + hash: "e3a4b357c00d3d49e4a7d90f6f57054c" } Frame { msec: 2800 - hash: "d64a755e47a502244e7f14f2091f0ca6" + hash: "44ad81d2ad0d502b003e148412871a41" } Frame { msec: 2816 - hash: "582562992b0652f995b439897182e0f8" + hash: "47d757dab5c72cad08cb8026631d67e6" } Frame { msec: 2832 - hash: "2d69b1a274c262faf5ce9ed3191c7d22" + hash: "8522a3b6202b303a9e65a9e136423e27" } Frame { msec: 2848 - hash: "36c04a2bd58124877a332bb6a262a7e5" + hash: "70e3cd650472d0e95f4d6ca9e34a2ce1" } Frame { msec: 2864 - hash: "798711925da8f5034039dad86cc1fad1" + hash: "19a7825cd8c0eaa6f313ec77fff9ec1b" } Frame { msec: 2880 - hash: "31495157a10c3bb4dd70cfd857fd07e6" + hash: "579688ff6ec910570c0c0c60fdf44cf6" } Frame { msec: 2896 @@ -1234,207 +1234,207 @@ VisualTest { } Frame { msec: 2912 - hash: "b81330eb50dbd39f1abcdb8ff1553d08" + hash: "7ab8cf0d0b650e8f994a9beed8be29fb" } Frame { msec: 2928 - hash: "ececcb86b76e9cd2f57585bd87e16bef" + hash: "92e9be6d36844bb475b861ba9c4bc3ff" } Frame { msec: 2944 - hash: "2c37e2c24cf22a334cfcc6f2691ad9fb" + hash: "08b9cce3b2071b328054af6bcb6755c7" } Frame { msec: 2960 - hash: "ad0572020d273dbca046357aa0f8bf3b" + hash: "b505d2f41a6db06d4ca03f5340800aa6" } Frame { msec: 2976 - hash: "51a469e059a5e1a3675db731f55209d3" + hash: "f0267f59e247e24e4cf9c56f8931112b" } Frame { msec: 2992 - hash: "dca7d50a3faab1f049bece34bd16b8c4" + hash: "ddbc73e2df4da11d5122539a00c126de" } Frame { msec: 3008 - hash: "86dc86bafb01fa086caa3b22f9d393d9" + hash: "8dd67df95fae14079ed5b83c421a5b6e" } Frame { msec: 3024 - hash: "05754bd86070a6f01bf90ca2b964f695" + hash: "7b217f7c51087a07e8922b0286b2c1dc" } Frame { msec: 3040 - hash: "911ec290ba303f0cac258cbb893bbf78" + hash: "e464b5121f3204c64cafe2f5e31cf497" } Frame { msec: 3056 - hash: "f27f29249426f46b8fb508372bcbb32d" + hash: "7fc2018f8db17b65fd01b2ddfa44f66d" } Frame { msec: 3072 - hash: "2f452e2d519f33ee03db67ebd7f69e3b" + hash: "a5d1871511eac7224292b3552da466a8" } Frame { msec: 3088 - hash: "35cf7747a75ea3f727c2fe1dae6136c5" + hash: "2f0a55cf3cd30da77fbb73e749b729a3" } Frame { msec: 3104 - hash: "6773187693f52a8f2c0e358e379b4d21" + hash: "9aab649b6664c179878d0ead438dd751" } Frame { msec: 3120 - hash: "abca1f00f7ec60c8c80ba5345898e54b" + hash: "2ad733363d239d9a3ea1c31427a3b3fe" } Frame { msec: 3136 - hash: "9bee1da64534da97de349e1ee973cc9c" + hash: "e73b4fd7cb6285df9a77d666f25ab245" } Frame { msec: 3152 - hash: "087df06ca720918482f2e29653c7fbac" + hash: "53b05d8be52a74c3a24b88779d4927bf" } Frame { msec: 3168 - hash: "5b08911bf0975bd6615bf29294e4b1f5" + hash: "04fc6aac5f090960cd87eefb4273fb0f" } Frame { msec: 3184 - hash: "dead4bb3768b65418f68bae7dd0bf004" + hash: "294c842a71b5e4927146952ce865c8a2" } Frame { msec: 3200 - hash: "6bfe4c866936d8ae509650419ae12455" + hash: "ac6f7afb4a5e67e2edd8300e7dfdff13" } Frame { msec: 3216 - hash: "7428bdd9609a2594be08fdeac6ff1e17" + hash: "8a7ab6dc549b247f3b897e098d784dd8" } Frame { msec: 3232 - hash: "d02f9f693e0ae8c7034bf727064ec28a" + hash: "0a3144254f66a6b005b95a026496cd32" } Frame { msec: 3248 - hash: "b6284efd849547bbfefc22ec77d61062" + hash: "ca457a1c503a980687926e31ac16995b" } Frame { msec: 3264 - hash: "4b78b647be8e918e85edab0c23b6f882" + hash: "c17922ca04f5ce9916e2907a6c28bf8b" } Frame { msec: 3280 - hash: "c4a02c18ce3574d057e6a54b30efadb3" + hash: "b2a071734226b905f6c6f5652f645517" } Frame { msec: 3296 - hash: "d1d190010239d0b02a697d1c63c748ab" + hash: "1f41a314699151771d7d1ca672aaba8f" } Frame { msec: 3312 - hash: "b198689d11aa59d937297e6fcf675c93" + hash: "de94c2ad2e74036d975e8402dd8b06e9" } Frame { msec: 3328 - hash: "218f3371beea895aefd28aa874012dcc" + hash: "9cfe0627852cefe67fc0b44b31085b4a" } Frame { msec: 3344 - hash: "1135de1b9a4ebf1d2829546d3c3f3903" + hash: "de7ab5230efb63264f76fa1f1b61dcfa" } Frame { msec: 3360 - hash: "773a64cc7bb8e99a25078f348986e28f" + hash: "5ad22cf9e1c9a02cfc570beaac55bee0" } Frame { msec: 3376 - hash: "e8ce58aeb18b3f56ebd3d6f61ac94657" + hash: "9e6210d9e6bfda4fe0695b75d03435e2" } Frame { msec: 3392 - hash: "6de92679c32c7f3e9d9b6ba3a47e65eb" + hash: "d3989a9fb7e99d16032fa1842364f2ed" } Frame { msec: 3408 - hash: "339b37207af10ad986269e21ab37ff6d" + hash: "2f3e7040a4966e56858312f6534e9e77" } Frame { msec: 3424 - hash: "ac01f0708800fdfdacec67ac9e80602f" + hash: "16bb17f511519337be2e60d8b9f95149" } Frame { msec: 3440 - hash: "9de89a748b1e18eb6ed94875af6f26de" + hash: "819250fd9899a9457a9300f942f4d8bf" } Frame { msec: 3456 - hash: "d091e4a93c2beafb0ce4b6dff6d5b05f" + hash: "6639a15d4d23540ccf63c9bea0e1689e" } Frame { msec: 3472 - hash: "9532271085864d2fde3aa6e572599588" + hash: "14b553132a86e57577c416e6f6c53433" } Frame { msec: 3488 - hash: "d00804b42ab1c1f082a9f394ff4d666e" + hash: "f7a95239db44b66698d29f0daae826f1" } Frame { msec: 3504 - hash: "2c745f007353e6f8a7195470ba9492c2" + hash: "b5a6abb5294fb9b069ab8a075003cb61" } Frame { msec: 3520 - hash: "b4e952acb734ab1a608297fcb44fbe46" + hash: "391c1c43ce893aeefc42d164e6e8aaac" } Frame { msec: 3536 - hash: "75ceed3c2ddd557866145393fa50a12f" + hash: "271addef36d51d904bc1d68f65b66de3" } Frame { msec: 3552 - hash: "8b83b80554dd4a1266184092d380554c" + hash: "73a23e56edcd64ac6147aff27b785ebb" } Frame { msec: 3568 - hash: "973bddb1b2f9dbadd40c0de3ca7c3510" + hash: "bd43145ae22086348cb5e68765a42ac1" } Frame { msec: 3584 - hash: "5691b5bf54b50d4ff0a717873e001c00" + hash: "4b2706d1215f2b5b08ac87e40ba8c21b" } Frame { msec: 3600 - hash: "8b26b0aa8b06da031354c59d7fb41bf0" + hash: "6420fd46fd8068010d3caaa68eea457e" } Frame { msec: 3616 - hash: "45786c39a10b8e1cf399df98f3fb7ffb" + hash: "188499a79313d984ed1d710329b0237f" } Frame { msec: 3632 - hash: "c6d0be03e167c16566372cc992604dfb" + hash: "12da197320858ea4f8a1437b7ceac95a" } Frame { msec: 3648 - hash: "8d6e057550632d143faf996a62bbd1cd" + hash: "14bdec5663d1a81fa617d3b81e19f8b4" } Frame { msec: 3664 - hash: "7e3a321b95d5f62f0da2b10324b485b6" + hash: "3430047eca214a217aca0bd71814f4db" } Frame { msec: 3680 - hash: "e842f18dfd36947b2fa086a4d0bb2ec5" + hash: "974c431fe7030990389c7fc719655cfd" } Frame { msec: 3696 - hash: "a9359e143dae4113437a43cc00493479" + hash: "d38f3153b3cf39a278dc6948ff9ef71d" } Frame { msec: 3712 - hash: "2eca61c837cca9beb6d1834eafe8c538" + hash: "0c6eec50abcf4afc20311ffa1326d4e8" } Frame { msec: 3728 diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.0.png b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.0.png index af0e781..da688c7 100644 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.0.png and b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.0.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.1.png b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.1.png index 6f1878f..618d238 100644 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.1.png and b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.1.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.2.png b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.2.png index 97f09f7..0688ed1 100644 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.2.png and b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.2.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.3.png b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.3.png index 878875a..ec6e330 100644 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.3.png and b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.3.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.4.png b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.4.png index cdbe606..1692d17 100644 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.4.png and b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.4.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.5.png b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.5.png index 7b78f7a..d70704d 100644 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.5.png and b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.5.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.6.png b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.6.png index d7b5943..f8f37c6 100644 Binary files a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.6.png and b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.6.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.qml b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.qml index bc900c6..3828e76 100644 --- a/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.qml +++ b/tests/auto/declarative/qmlvisual/qdeclarativepathview/data/test-pathview.qml @@ -182,7 +182,7 @@ VisualTest { } Frame { msec: 592 - hash: "731c8547a72c64ac86aec87c0a9a12cb" + hash: "683d9f54c75f5b1ed082edb0b4559bc8" } Mouse { type: 5 @@ -202,7 +202,7 @@ VisualTest { } Frame { msec: 608 - hash: "d9d7dd7ea05499f028964fdd11af0fe6" + hash: "02e5238c0764f370d0f463cc3f477df7" } Mouse { type: 5 @@ -214,7 +214,7 @@ VisualTest { } Frame { msec: 624 - hash: "361879f350c448a484b71a9e7a42b87f" + hash: "02239cd84ce630a89b94dbcf469d9a70" } Mouse { type: 5 @@ -226,7 +226,7 @@ VisualTest { } Frame { msec: 640 - hash: "998da4b3e36ee3e17deb2b5a097661da" + hash: "6cdaa8ffc906ade671fe259711e76f24" } Mouse { type: 5 @@ -246,7 +246,7 @@ VisualTest { } Frame { msec: 656 - hash: "1b3f9758bd9842cc9545b494499f87c4" + hash: "db00a0d69efd43f69c83dafbf38a06a6" } Mouse { type: 5 @@ -258,7 +258,7 @@ VisualTest { } Frame { msec: 672 - hash: "7e87f7c233dad50549e4bdafe10bb48e" + hash: "76fdf4cb75376ec3a9e084d93765c5cb" } Mouse { type: 5 @@ -286,75 +286,75 @@ VisualTest { } Frame { msec: 688 - hash: "01ceb2fea81f2192ab11d7d6e1df879a" + hash: "b12e86c13e012c5992930b3e559c337c" } Frame { msec: 704 - hash: "9afa862248bd527e07374a5c2f2036a1" + hash: "4056e78a59e8f1e030f3e3a51c436b46" } Frame { msec: 720 - hash: "e06439495148bfbf059cfe2b5df22840" + hash: "c84781b7586943ef889b8911c23e91db" } Frame { msec: 736 - hash: "b206a28d6f3be8cba9595849328b27b8" + hash: "cd952ffa63dbcb772b666ce755c9a2f1" } Frame { msec: 752 - hash: "646e4529bf554dceee0140ec56a02d1c" + hash: "2a31778e3ab7c676ae82278948cef12a" } Frame { msec: 768 - hash: "31bdcf1f178d65e033e23dfbdcb9dc5f" + hash: "ef6319b262fc299b14b40d1521f9c9c3" } Frame { msec: 784 - hash: "b4e897356814ca2dddbc3644b1782f36" + hash: "05ccb24a2025df31188b413c8d837232" } Frame { msec: 800 - hash: "669e5d682aae8727640e0e0f4e855a60" + hash: "df31f9dba1a762397c0364d7e83052ef" } Frame { msec: 816 - hash: "892007b1a379c617412502499df92d01" + hash: "6eec07606ef320072ea23ceedb3f6b29" } Frame { msec: 832 - hash: "f4d66daa2d428aa712a73ded2de7a361" + hash: "e3502cb53c6e17373de3b718a8212f4d" } Frame { msec: 848 - hash: "0c21e69bed6dc2d6b7c23c20714aca67" + hash: "2e01e2e252ca9fb3e7107f04a3ba4031" } Frame { msec: 864 - hash: "189909bdbfeb1f02ad527fbc438d567d" + hash: "547a9f25404c2bf7737526faf67a459d" } Frame { msec: 880 - hash: "b2fcbc0657474e1b6d27e1f2f93be35b" + hash: "aa9c3122e3c2a7ed450a0afffbcf4e6a" } Frame { msec: 896 - hash: "4407d7ad1b6a40b2355145aee136ff15" + hash: "1535dea92038cf87395a616841fd9bf6" } Frame { msec: 912 - hash: "347ada687af0a97f0a862a1f3a1132be" + hash: "1535dea92038cf87395a616841fd9bf6" } Frame { msec: 928 - hash: "db6217ff0194c5a3f9ca9ea7e3b3dfd8" + hash: "1535dea92038cf87395a616841fd9bf6" } Frame { msec: 944 - hash: "8a94ca0ee93daaa1bdcdbfc8a80713c1" + hash: "1535dea92038cf87395a616841fd9bf6" } Frame { msec: 960 - hash: "ab24d0c8545518cbaff876976247be2c" + hash: "1535dea92038cf87395a616841fd9bf6" } Frame { msec: 976 @@ -450,7 +450,7 @@ VisualTest { } Frame { msec: 1216 - hash: "c612bb9906f18786ef7cc6f4e56de218" + hash: "aa9c3122e3c2a7ed450a0afffbcf4e6a" } Mouse { type: 5 @@ -470,7 +470,7 @@ VisualTest { } Frame { msec: 1232 - hash: "ffec210dd863ed32a780506f61b06056" + hash: "b889647c08af7db2e6582d9927cb1cf7" } Mouse { type: 5 @@ -490,7 +490,7 @@ VisualTest { } Frame { msec: 1248 - hash: "9613c658f267d19b84d6e7ef2a676fed" + hash: "ac97616fc3c54711bb067cc72c15d4c5" } Mouse { type: 5 @@ -510,7 +510,7 @@ VisualTest { } Frame { msec: 1264 - hash: "8c5dd8d0f9f434530b20e14a84af9f46" + hash: "b38c46d537e6e622c8a0ecae76dbe506" } Mouse { type: 5 @@ -530,7 +530,7 @@ VisualTest { } Frame { msec: 1280 - hash: "a956e8e9ca8958c387f8f5ce374cdec9" + hash: "6261f2f16bdd89142cfbf1de4ce64a32" } Mouse { type: 5 @@ -550,87 +550,87 @@ VisualTest { } Frame { msec: 1296 - hash: "712e865d894f179cfd9d86b08e60811a" + hash: "d4f8d57bae3d5bc888a4bbe2812b3fdf" } Frame { msec: 1312 - hash: "db5c1f2af2e72ff4edce83cb342b5263" + hash: "4e0a90dda433c1615ea367ec90917409" } Frame { msec: 1328 - hash: "834f0aa26c66234491468c1b27a2d329" + hash: "b20e244f27dae505568fcba25cccb5d8" } Frame { msec: 1344 - hash: "78a2a4b60db730a7367bc77e1dfc1a1b" + hash: "f31d264a002718787ea55a6312c7f9f2" } Frame { msec: 1360 - hash: "a8ff2277b5f7d515bc5a9af1f0e77197" + hash: "0abbf36b5e3f2db9288bde05825dc111" } Frame { msec: 1376 - hash: "e05d730624025000b831860f5b99e8ac" + hash: "64fc0f18174f5e8002cf79a908cc08df" } Frame { msec: 1392 - hash: "54aa124492ea742e4327f1d2b45ab620" + hash: "430d7719ebf3b5835af92683cff10e56" } Frame { msec: 1408 - hash: "bc700bee41ac384a2555723b010e9041" + hash: "411a8fe1ee3a0510574cbf6a69d23456" } Frame { msec: 1424 - hash: "26f66098c505cea4715a89b6a2232759" + hash: "47e431bf01575c44f7c1fa3e20409866" } Frame { msec: 1440 - hash: "00f3255a3ead315410d8c0d338779689" + hash: "d17b62a0b52b4a5220b29b55f764abc6" } Frame { msec: 1456 - hash: "154e7d86d7602ebba38a0d63b211894d" + hash: "9bd0d8dfbee424bd0ccf72703a7c51c2" } Frame { msec: 1472 - hash: "87cf2bff69ebd75af69d0a7c7f668b07" + hash: "8ef880c18ecd8adb66e7e0a2dceb61fc" } Frame { msec: 1488 - hash: "f221b870ecccb1669b6223e5431c31d1" + hash: "fcc1bc7f35342f595448ca2870478b50" } Frame { msec: 1504 - hash: "40a9d4c522d9fd831be2ca698ac10670" + hash: "cf360de1c6649e45beb974ddbe436ea9" } Frame { msec: 1520 - hash: "7ad47479d99fd4d9fde96fef242bdc20" + hash: "b2a6acf1fed92069fd2779b1fa236c95" } Frame { msec: 1536 - hash: "b91912801c790d849399306c693a4d33" + hash: "7128a442b6bb06038477d46ac3da5021" } Frame { msec: 1552 - hash: "e5c8d361abcbc15df0b0b82728cb5b84" + hash: "6a0ab3ccc3749b9a2b9a5b5851b0cf70" } Frame { msec: 1568 - hash: "3f2f82c925e93d4593581cdba16f361f" + hash: "18f6cdad215c55ea8335d06110715aa8" } Frame { msec: 1584 - hash: "7007fd0595c188a9a5b3ff31b0514aa5" + hash: "137420f4b1f51440c3aefd18dbdad71d" } Frame { msec: 1600 - hash: "118661091df765ae35c152c7fe818029" + hash: "faf898388f87948fbacd74589cb18af0" } Frame { msec: 1616 - hash: "0a8edd2a35f7921ced6e3aa7e571bc4b" + hash: "b818181b3fee6f5a35a0da6c0f8e240e" } Mouse { type: 2 @@ -650,7 +650,7 @@ VisualTest { } Frame { msec: 1632 - hash: "ef734ce4d7e1aee19a78b743c9923f90" + hash: "2e74cc22a4e5b20cc231bc08e15e662a" } Mouse { type: 5 @@ -670,7 +670,7 @@ VisualTest { } Frame { msec: 1648 - hash: "09a9925d5ec2fd03cfbf469bc22bf201" + hash: "27be226c985bb0143d1dca3e4be4b10a" } Mouse { type: 5 @@ -690,71 +690,71 @@ VisualTest { } Frame { msec: 1664 - hash: "6babcbf5582d5ed8f0cf52e233867055" + hash: "9384d46806b2a8091b6d16f7636d6ae4" } Frame { msec: 1680 - hash: "94dae9d52f3523e17f3f0e59ca24a069" + hash: "684a17820c3693d893f8199cd7c7076f" } Frame { msec: 1696 - hash: "0d417d25893a0454a729f5c23a2a6c28" + hash: "dc1facc91b6935983bbcd2eada452d4d" } Frame { msec: 1712 - hash: "afd1bbca1dcfea8d1f0a340d86b07fa8" + hash: "6bb08cc431a3ecca1a553ea10669bb0c" } Frame { msec: 1728 - hash: "97e98982742b94dba8b6cb59397bcb66" + hash: "1330640d4ca9ac69dd089cea34b7f61d" } Frame { msec: 1744 - hash: "a0ad8cbbd0daa0afd3831e8a071b9a0e" + hash: "95370207a55b56c41923937b40d5fe6b" } Frame { msec: 1760 - hash: "f71826bcd6ea91d2f64d627a390c379d" + hash: "c36b60f81e7de5c0e5a59655041adff2" } Frame { msec: 1776 - hash: "7699da01cf1ee9a7f404ab053241b530" + hash: "297abbc6b38a1909324fcee6d8b1d908" } Frame { msec: 1792 - hash: "6aba727ecc562d7b5555eae427e6978b" + hash: "0af89e3bab7c517f375897239ea35153" } Frame { msec: 1808 - hash: "ef9c6daa5b04b0be9159594e04524fba" + hash: "05109c3dfac7f65fe00e81d1a145f048" } Frame { msec: 1824 - hash: "6293ede5de83f3b01a3b4d8d87648089" + hash: "57e1e871cbbc627f2fb9bf5583c4f097" } Frame { msec: 1840 - hash: "c3b34d8592f88622cad0f9353d08e739" + hash: "5220aecdd1516d94f0698e79f17fee57" } Frame { msec: 1856 - hash: "880f3cb9d5dbe06cdf17e3a953d4562d" + hash: "f3d8c908e61e5d61bbeeb9c6b5e8a704" } Frame { msec: 1872 - hash: "ed381ce920863a5a6627f383a88ea2fe" + hash: "f27867aeb39ef64ebd50b5d79b69337e" } Frame { msec: 1888 - hash: "b5bc40b8c4abb6458aeb67eda73507b6" + hash: "b807b4e74a0f008df3f4534901debe38" } Frame { msec: 1904 - hash: "482cb61b7fac4b1654483f846b8b6717" + hash: "e19832a0a7fcd57efe46cb0102a8d418" } Frame { msec: 1920 - hash: "e1a4a16d2cf5132a9fbb0869ed6082d9" + hash: "f0dcfd9b22f385fedfde964774480f85" } Frame { msec: 1936 @@ -762,171 +762,171 @@ VisualTest { } Frame { msec: 1952 - hash: "f8874aaab1e65cf9b86d6b5174c3d2c8" + hash: "746c60e03c50dc2e28c62fe52a8dd9d2" } Frame { msec: 1968 - hash: "d8490adeaa793352b812e832f4cb079a" + hash: "27d6da44b605cb38552147fdf451ef45" } Frame { msec: 1984 - hash: "85fdb99926ba34a25fa964df11af9a5a" + hash: "c41d5491c417531ee86ac6ec8571c6a8" } Frame { msec: 2000 - hash: "ad137a75981c181838d97cbe313063ac" + hash: "ac57c578e7e2cbb57e982d6da5fb7268" } Frame { msec: 2016 - hash: "bfa5cecfc0058b56ca66aa816ea098dc" + hash: "db40e242fabf119f0e7187eeb96a34a5" } Frame { msec: 2032 - hash: "53fe3960c2f332eb099fedd8421fcc94" + hash: "0850d4b73a664ee0f1ed6d6e0615ea80" } Frame { msec: 2048 - hash: "61b99ff526560c1589d2fc8737af2af2" + hash: "ae6cb0bfda1cea70b3641251d0dc60c4" } Frame { msec: 2064 - hash: "f9dd63709bed985f5d691d27c0d32484" + hash: "67a28c2188aecfc5dcccedd257789dbc" } Frame { msec: 2080 - hash: "964c20ada9ad9e83edd9b429bf681b83" + hash: "4355f220c8a87ad981088fb23bb15f11" } Frame { msec: 2096 - hash: "997bc44a319c8ce8212387f7564c4005" + hash: "2081c1ffe35f20dd827b3d9f52be90b3" } Frame { msec: 2112 - hash: "892eda6e7446321483ffb1dbf44a0432" + hash: "ba13b0b4790aec7084b5553fe0b0d72b" } Frame { msec: 2128 - hash: "62068dca6da7227882b6c3bc147c6f24" + hash: "7f289e50f1bbd570b6bc2ca1998f8493" } Frame { msec: 2144 - hash: "2cd0c351c53234d4bbf4d2c74d313f59" + hash: "8bb3a37f416032d40cb5f919abb42e30" } Frame { msec: 2160 - hash: "cf812f971bb4f8ab3116cf2b14c325df" + hash: "bcc69f859b3bff759e0c732c7adc23f0" } Frame { msec: 2176 - hash: "be296bd9ab4c38d95e6d7d445d8c7f68" + hash: "d3e8aae08a2518c039d6bda80fc520a4" } Frame { msec: 2192 - hash: "536d0214c8c3f69ce8d4e1585128b2b8" + hash: "955212dc28a6f8fe59c658401284d3a3" } Frame { msec: 2208 - hash: "f71452a0a6ef80758800d67e601a162b" + hash: "8eebcff152288a4ab2a3e64fd7ba6f80" } Frame { msec: 2224 - hash: "e57c099beb70d0a4ca2cbc94a2c3887e" + hash: "85fe363271d480163fb7847a3501472f" } Frame { msec: 2240 - hash: "84cea22f64ff8b8838a7db0b19af1a4e" + hash: "23190380ddcc4e3afce2164a4743d179" } Frame { msec: 2256 - hash: "04aa0d5d089779977f569d0f849b97dd" + hash: "40ca7c3d24883a8d3457de934b247280" } Frame { msec: 2272 - hash: "85b52e125142d52d531132939930dd93" + hash: "299ed19fa4d213e0e9dd127e8799d5fc" } Frame { msec: 2288 - hash: "19bc7b318c21a6ce2be8ebde2e624fc3" + hash: "e39a067860fa7dcb4efba87aee58cc77" } Frame { msec: 2304 - hash: "9cc744249cb031f0400e87893c1642af" + hash: "a709045723c4a9a2e85295fcc360eea9" } Frame { msec: 2320 - hash: "a834706bbf573f37cf9f59c6c6cbbfa5" + hash: "029428301287e4c7cd2f8a1fa6a25381" } Frame { msec: 2336 - hash: "8db3eea9d47a162d8b0ee9cd18e194f3" + hash: "aef25177af3511dc99004a1e37f7f5d3" } Frame { msec: 2352 - hash: "29da9b8da8f572ace93250abb8626a90" + hash: "f9e11fd7023a72366dacaaf19b2eb81c" } Frame { msec: 2368 - hash: "179b74316d885f9ee41066b9c475b57f" + hash: "51f7c896d79c900a2b54a8c756228200" } Frame { msec: 2384 - hash: "35464509ef5a9919af46a30d40c3edc7" + hash: "28c18081813c801c6793873ec23e6c0c" } Frame { msec: 2400 - hash: "aadec42355d38d149421ef6c93783e69" + hash: "39df3050c4100e8a4f6e648b4aa16ba7" } Frame { msec: 2416 - hash: "cb8609791270e8e3c13da4579f85595f" + hash: "752cb6969fa8b76abf4bb229edb2c21f" } Frame { msec: 2432 - hash: "93e81e036a1bc30cc63ce703f8f43a34" + hash: "54d50f6c980cb04a1634622a29a6f0e9" } Frame { msec: 2448 - hash: "d08d18adf9ca92cd6597c2f51ae90383" + hash: "d510db233f025b026f896b760848cc07" } Frame { msec: 2464 - hash: "f54ec103787023647beaa4b992340385" + hash: "e5c8d361abcbc15df0b0b82728cb5b84" } Frame { msec: 2480 - hash: "61c9f72d78fce0b966a278abacc97ce6" + hash: "e5c8d361abcbc15df0b0b82728cb5b84" } Frame { msec: 2496 - hash: "5b0500ed0562b11280c3424412f74188" + hash: "e5c8d361abcbc15df0b0b82728cb5b84" } Frame { msec: 2512 - hash: "b8ee7bc1e94ce35bf946ee71fa03d72c" + hash: "e5c8d361abcbc15df0b0b82728cb5b84" } Frame { msec: 2528 - hash: "60ec6aceeaf82fc730c3df55b5c06f90" + hash: "e5c8d361abcbc15df0b0b82728cb5b84" } Frame { msec: 2544 - hash: "01cc732bad8b28483e79115c117ee26d" + hash: "e5c8d361abcbc15df0b0b82728cb5b84" } Frame { msec: 2560 - hash: "b39c8d373524ba679c8567d16e6c5fe0" + hash: "e5c8d361abcbc15df0b0b82728cb5b84" } Frame { msec: 2576 - hash: "2474476dfd021ff485c3a127bd22367e" + hash: "e5c8d361abcbc15df0b0b82728cb5b84" } Frame { msec: 2592 - hash: "1342a1a0f6bc02159de1be058cf2411b" + hash: "e5c8d361abcbc15df0b0b82728cb5b84" } Frame { msec: 2608 - hash: "a9721b64b9a5526335937245302249ae" + hash: "e5c8d361abcbc15df0b0b82728cb5b84" } Mouse { type: 2 @@ -938,15 +938,15 @@ VisualTest { } Frame { msec: 2624 - hash: "109dc503ee86e731f52d25908daf5d36" + hash: "e5c8d361abcbc15df0b0b82728cb5b84" } Frame { msec: 2640 - hash: "94998dbab6792c518ca1f37f060f1d4b" + hash: "e5c8d361abcbc15df0b0b82728cb5b84" } Frame { msec: 2656 - hash: "3146ba4e63fa74279939b8de935f067c" + hash: "e5c8d361abcbc15df0b0b82728cb5b84" } Mouse { type: 5 @@ -966,7 +966,7 @@ VisualTest { } Frame { msec: 2672 - hash: "1aaea4143076bf8ba8190d94fcc89e64" + hash: "f728208b0fc2f230313c86378cf7f419" } Mouse { type: 5 @@ -986,7 +986,7 @@ VisualTest { } Frame { msec: 2688 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Mouse { type: 5 @@ -1006,7 +1006,7 @@ VisualTest { } Frame { msec: 2704 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Mouse { type: 5 @@ -1026,7 +1026,7 @@ VisualTest { } Frame { msec: 2720 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Mouse { type: 5 @@ -1046,7 +1046,7 @@ VisualTest { } Frame { msec: 2736 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Mouse { type: 5 @@ -1066,39 +1066,39 @@ VisualTest { } Frame { msec: 2752 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 2768 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 2784 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 2800 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 2816 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 2832 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 2848 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 2864 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 2880 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 2896 @@ -1106,51 +1106,51 @@ VisualTest { } Frame { msec: 2912 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 2928 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 2944 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 2960 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 2976 - hash: "a0d8bb20189c3c65e5e72671788d9493" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 2992 - hash: "1236a317e60f7ae3d3fb2fb521bad2a2" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 3008 - hash: "1236a317e60f7ae3d3fb2fb521bad2a2" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 3024 - hash: "1236a317e60f7ae3d3fb2fb521bad2a2" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 3040 - hash: "1236a317e60f7ae3d3fb2fb521bad2a2" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 3056 - hash: "1236a317e60f7ae3d3fb2fb521bad2a2" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 3072 - hash: "1236a317e60f7ae3d3fb2fb521bad2a2" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 3088 - hash: "1236a317e60f7ae3d3fb2fb521bad2a2" + hash: "f728208b0fc2f230313c86378cf7f419" } Mouse { type: 2 @@ -1162,23 +1162,23 @@ VisualTest { } Frame { msec: 3104 - hash: "1236a317e60f7ae3d3fb2fb521bad2a2" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 3120 - hash: "1236a317e60f7ae3d3fb2fb521bad2a2" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 3136 - hash: "1236a317e60f7ae3d3fb2fb521bad2a2" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 3152 - hash: "1236a317e60f7ae3d3fb2fb521bad2a2" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 3168 - hash: "1236a317e60f7ae3d3fb2fb521bad2a2" + hash: "f728208b0fc2f230313c86378cf7f419" } Mouse { type: 5 @@ -1190,11 +1190,11 @@ VisualTest { } Frame { msec: 3184 - hash: "1236a317e60f7ae3d3fb2fb521bad2a2" + hash: "f728208b0fc2f230313c86378cf7f419" } Frame { msec: 3200 - hash: "1236a317e60f7ae3d3fb2fb521bad2a2" + hash: "f728208b0fc2f230313c86378cf7f419" } Mouse { type: 5 @@ -1214,7 +1214,7 @@ VisualTest { } Frame { msec: 3216 - hash: "1236a317e60f7ae3d3fb2fb521bad2a2" + hash: "f728208b0fc2f230313c86378cf7f419" } Mouse { type: 5 @@ -1234,7 +1234,7 @@ VisualTest { } Frame { msec: 3232 - hash: "1b604ea70459a768fb37a6333000174b" + hash: "7d43010a9951054df82571936a04cc50" } Mouse { type: 5 @@ -1254,7 +1254,7 @@ VisualTest { } Frame { msec: 3248 - hash: "25e0aabe364085a61b4572ef015dac2c" + hash: "ab1980970c82238d2c37d61db4fc5153" } Mouse { type: 5 @@ -1274,7 +1274,7 @@ VisualTest { } Frame { msec: 3264 - hash: "ee6fc5c1de08e6f13f23b26829d2cba2" + hash: "849ffa1fdd718a48e9570b88987f9203" } Mouse { type: 5 @@ -1294,7 +1294,7 @@ VisualTest { } Frame { msec: 3280 - hash: "b077c59359d047738d9ba739f591393b" + hash: "d497eff3c8879d30619630e7ffcbf5c9" } Mouse { type: 5 @@ -1314,7 +1314,7 @@ VisualTest { } Frame { msec: 3296 - hash: "2cc0b8d7bd088f2277f5e939c234114c" + hash: "b0679dfe2f631e41f5cc269bd16d742c" } Mouse { type: 5 @@ -1334,7 +1334,7 @@ VisualTest { } Frame { msec: 3312 - hash: "64703db84cd5bda3109546293783804d" + hash: "ab2d88a4cd58d0064c32660272ff1dbd" } Mouse { type: 5 @@ -1354,7 +1354,7 @@ VisualTest { } Frame { msec: 3328 - hash: "137cd88932ad1fdbfdbf1a80cccf7b3f" + hash: "ea3cff28ff3be273332b19a2b8acb95e" } Mouse { type: 5 @@ -1374,7 +1374,7 @@ VisualTest { } Frame { msec: 3344 - hash: "ff9011d861c64bcad214b52cb4245583" + hash: "458decd62af57d333a07459c89e62393" } Mouse { type: 5 @@ -1394,7 +1394,7 @@ VisualTest { } Frame { msec: 3360 - hash: "c3f0132e472d29ddee95c7349243d33e" + hash: "1347a26241ed98d4913e1cb6cda58286" } Mouse { type: 5 @@ -1414,87 +1414,87 @@ VisualTest { } Frame { msec: 3376 - hash: "42ae9c21dce6a7cd59de228dac775dd5" + hash: "2efe07858c0c4de7fd3e339d7a24d5f5" } Frame { msec: 3392 - hash: "3f8631caf6a98d83356b188d6f94e9a6" + hash: "3edbe6755710ce148341faeb6980707a" } Frame { msec: 3408 - hash: "b2788cd1939a6dd42f12d8fd1282a122" + hash: "0f53231de64ac5b0503e92ad10155dea" } Frame { msec: 3424 - hash: "0d1ab6e9f2780be0c392d20f4b3b9619" + hash: "f2be693c23ea0885d6e8180c3062ba76" } Frame { msec: 3440 - hash: "03fdd91b352798b1ff958c23c0bc5f35" + hash: "207003ce6908f9707e9193a6c82a40c0" } Frame { msec: 3456 - hash: "028fee3630fdb3cf862213c0466a56fe" + hash: "ba86efade16e8965f59f6257ae90d131" } Frame { msec: 3472 - hash: "3ab76009ca029723e5cf0bf9bc154102" + hash: "1fdaaa68c4ed484536c207a0eacf6e72" } Frame { msec: 3488 - hash: "866c59b7dd545364b70ddbf21a8ee874" + hash: "d1223c8254f9e7e37c4e09628f38bce2" } Frame { msec: 3504 - hash: "9b4ff972b1055db38900fc0c5007e7b0" + hash: "c822447614f47b5e15ffad967964a061" } Frame { msec: 3520 - hash: "cbe0073c84617e23f0679a08c1a78492" + hash: "5eb2e64f11847cc9360291e14e866611" } Frame { msec: 3536 - hash: "374a5e6070dd628ed031e80d44be1f3f" + hash: "545dcc2645b50d78c84c658880d0500c" } Frame { msec: 3552 - hash: "4d16c81f877585a82549cfc4f68c574d" + hash: "9d984e07b99137b3cb57dd4df16b8237" } Frame { msec: 3568 - hash: "64b2b4c374a730b138b3573095f45d2c" + hash: "da27085e7a3cccde7cc3db2d9c6cc2cd" } Frame { msec: 3584 - hash: "26c59f4131fdb01ac4771231341c75c3" + hash: "8d8c117ca102cb93e752904fe3aee7bc" } Frame { msec: 3600 - hash: "bf6a3fdb7c516ca9cfc09f1059cc8cdf" + hash: "bfb5ed7b65f36d80e3156560a0ec58b7" } Frame { msec: 3616 - hash: "1bfb86796087cd293c68205cce6ac294" + hash: "bbd5f2b95325fde3b8759f2ef713c6bd" } Frame { msec: 3632 - hash: "e0f76f8fc7bd7756a4e004655f97f782" + hash: "1c36be8deb2079ed81f1718c92e44803" } Frame { msec: 3648 - hash: "61d3aa5f827452482d8a4a903fe64acc" + hash: "5a424e7e66d87d278483c43070920d56" } Frame { msec: 3664 - hash: "c8e42d3a5df195eaa091e50fc9dcd51e" + hash: "ae28bc20e20e022e1ac9bc2ddac0e134" } Frame { msec: 3680 - hash: "bb684dccf4c0a74dc091fb78c1be4f2b" + hash: "1551c4aae06a258bdadc9ef356724871" } Frame { msec: 3696 - hash: "54341e5a76fb4657021c41e6e3f3d496" + hash: "526aec43f710e524d247f8a4b08c261c" } Mouse { type: 2 @@ -1514,7 +1514,7 @@ VisualTest { } Frame { msec: 3712 - hash: "435ee710e108df42f659250ad7dbdb5e" + hash: "b50ef7198c1831623ed2210e651ac618" } Mouse { type: 5 @@ -1526,7 +1526,7 @@ VisualTest { } Frame { msec: 3728 - hash: "0c7078ec0d4a1dea84e0fba06323c533" + hash: "913269856c18d4f478eed1aa1d5ae293" } Mouse { type: 5 @@ -1546,7 +1546,7 @@ VisualTest { } Frame { msec: 3744 - hash: "854103790c02ca86fa011ef1b0f2be0a" + hash: "2c6a32e167bef4c3de0ca97e5764f31b" } Mouse { type: 5 @@ -1566,7 +1566,7 @@ VisualTest { } Frame { msec: 3760 - hash: "1a5995196e5bb4d1464ca76191af72d5" + hash: "88386cf4d982c5ca4e3fbd3519d9bd9c" } Mouse { type: 5 @@ -1586,7 +1586,7 @@ VisualTest { } Frame { msec: 3776 - hash: "397bbd080cae99790621642fab6ded91" + hash: "ecf04273061af5f881925f3a33015fbb" } Mouse { type: 5 @@ -1606,7 +1606,7 @@ VisualTest { } Frame { msec: 3792 - hash: "66ecad306911060329dcf7695c358e87" + hash: "b09c45ea79cd818bac6fe35e4167d4bd" } Mouse { type: 5 @@ -1626,7 +1626,7 @@ VisualTest { } Frame { msec: 3808 - hash: "c06da5f40f3f59f576a1d540d0b3244f" + hash: "4a1dbbac65a3caac16b38c45be61003c" } Mouse { type: 5 @@ -1646,7 +1646,7 @@ VisualTest { } Frame { msec: 3824 - hash: "a88d97691539dce19af4c14baf610275" + hash: "f4a805fc5c12cc3b2a22ef01050bf3aa" } Mouse { type: 5 @@ -1666,7 +1666,7 @@ VisualTest { } Frame { msec: 3840 - hash: "a07dca2c0014609ca5241612550992f5" + hash: "aa7805e4d806c4c56ded804145c44464" } Mouse { type: 5 @@ -1706,7 +1706,7 @@ VisualTest { } Frame { msec: 3872 - hash: "e5a4e76dd607ba1bae97aaf184ee009a" + hash: "fd2eab6b3a65713f057da22a412512c7" } Mouse { type: 5 @@ -1726,7 +1726,7 @@ VisualTest { } Frame { msec: 3888 - hash: "bb1d2614e590562479fc8d301bc7402f" + hash: "0dda191a66162db6365c663979b0990d" } Mouse { type: 5 @@ -1746,7 +1746,7 @@ VisualTest { } Frame { msec: 3904 - hash: "5d9fd2238666d3ae04613f1bba0fab05" + hash: "72a57fe4fc34a19040890a9e2a11dae5" } Mouse { type: 5 @@ -1766,7 +1766,7 @@ VisualTest { } Frame { msec: 3920 - hash: "b12a944cb5e593afbb21a10453879b52" + hash: "fd18bd5f8f09c995f122b8b4ecb80279" } Mouse { type: 5 @@ -1786,7 +1786,7 @@ VisualTest { } Frame { msec: 3936 - hash: "2f04c990978627b86fb2ad04579db0db" + hash: "8d33b6fa9d6525902e5611cf8ed2fa1f" } Mouse { type: 5 @@ -1798,7 +1798,7 @@ VisualTest { } Frame { msec: 3952 - hash: "e7ddf142fc36174fcaaa70b9340ef7a8" + hash: "d73a8eba0c43f214946052481f3db98f" } Mouse { type: 5 @@ -1818,7 +1818,7 @@ VisualTest { } Frame { msec: 3968 - hash: "4fce53c6f5347fe03ecf17b07fabe3ac" + hash: "c2f101636963ff5c61be2ad83c6b7ceb" } Mouse { type: 5 @@ -1846,111 +1846,111 @@ VisualTest { } Frame { msec: 3984 - hash: "75a0ec2c0158c55a90147c3f4afaa19c" + hash: "54630f489303c7ec2e94b4c941bd310f" } Frame { msec: 4000 - hash: "e89e98b7c1f36b74c664c77e121dedcb" + hash: "357106c752b13bcca047d55a3c7cd486" } Frame { msec: 4016 - hash: "f4c1e52a7b97a25fba640be2a1430d2d" + hash: "b00b78122721ddcded2c7131cfe40d53" } Frame { msec: 4032 - hash: "be58ca8f63dac8373825231512f483ca" + hash: "7da9e4197cb9be292e561790af1caa27" } Frame { msec: 4048 - hash: "755b16d4be00cb52595d42775d6227ac" + hash: "076fefc33455667af954dcc5a06017d3" } Frame { msec: 4064 - hash: "c62f1ebbb1e4ae4ca22c060078d6240b" + hash: "76edfedd2b9edcc5770dcce87b022427" } Frame { msec: 4080 - hash: "5f1187e9530584f9eb81ce1ce8267da0" + hash: "12e6711077da076b737aef1aaa336d42" } Frame { msec: 4096 - hash: "5dc9921e9ddf15ee0457fcdc834544c5" + hash: "1e19329fb839a00faa3b95d13b7a9015" } Frame { msec: 4112 - hash: "efacedc2782435ef4e269e6956fb3547" + hash: "7469fb57ce0b7ea9a7cc6da14f6a245a" } Frame { msec: 4128 - hash: "5b356dd3082f6b0920bb41d332595ce1" + hash: "17e3aca0838e2ba75cc9b869bb969220" } Frame { msec: 4144 - hash: "5d8afcc1abd890beb2badf85bcf02897" + hash: "32ebb24cee3ba65f9242708538203553" } Frame { msec: 4160 - hash: "03c56ab4fea11cce19fcbb62dccb7683" + hash: "948429b8ded1f688cd7e27e0f056f40c" } Frame { msec: 4176 - hash: "236254ce32a8e06dc42f2fd3c9ac6c7c" + hash: "c6fc2e8519a31bc18eb924ca98cd24be" } Frame { msec: 4192 - hash: "4beb33da77bc2b41eb882a2a5cdeb539" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 4208 - hash: "b345470adead1ffb3af4d1091ffbd95c" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 4224 - hash: "c2677f1653b08952338a5c26a724ebe7" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 4240 - hash: "45b6633acf0ac28c5b5462920cf61282" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 4256 - hash: "26a9a6609ce8eee1f744c2bd43494f22" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 4272 - hash: "9373a8010a05d05cb5b3c2ec75359493" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 4288 - hash: "d0c561761825512a02a9e3640139cadc" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 4304 - hash: "d0c561761825512a02a9e3640139cadc" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 4320 - hash: "d0c561761825512a02a9e3640139cadc" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 4336 - hash: "d0c561761825512a02a9e3640139cadc" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 4352 - hash: "d0c561761825512a02a9e3640139cadc" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 4368 - hash: "d0c561761825512a02a9e3640139cadc" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 4384 - hash: "d0c561761825512a02a9e3640139cadc" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 4400 - hash: "d0c561761825512a02a9e3640139cadc" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Mouse { type: 2 @@ -1962,7 +1962,7 @@ VisualTest { } Frame { msec: 4416 - hash: "d0c561761825512a02a9e3640139cadc" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Mouse { type: 5 @@ -1974,7 +1974,7 @@ VisualTest { } Frame { msec: 4432 - hash: "d0c561761825512a02a9e3640139cadc" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Mouse { type: 5 @@ -1994,7 +1994,7 @@ VisualTest { } Frame { msec: 4448 - hash: "d0c561761825512a02a9e3640139cadc" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Mouse { type: 5 @@ -2014,7 +2014,7 @@ VisualTest { } Frame { msec: 4464 - hash: "0e7554f077e2d6d8c6cf9496b20ab009" + hash: "d8f9d016318e0bd38d4654b4850da952" } Mouse { type: 5 @@ -2034,7 +2034,7 @@ VisualTest { } Frame { msec: 4480 - hash: "d6e78f43c971abcc1d2aadb96e8b80b0" + hash: "13a2382e08ab10ecb40f9c24c682a797" } Mouse { type: 5 @@ -2054,7 +2054,7 @@ VisualTest { } Frame { msec: 4496 - hash: "10d8e0ee5bd432c639963c9cedd25b85" + hash: "cef145c5d105466f3913bb81bb2b58df" } Mouse { type: 5 @@ -2074,7 +2074,7 @@ VisualTest { } Frame { msec: 4512 - hash: "53e142d6b0112644d75df29f7865fbb4" + hash: "9bc0a21266bebbf8fc3509e5f92dd77f" } Mouse { type: 5 @@ -2086,7 +2086,7 @@ VisualTest { } Frame { msec: 4528 - hash: "9609807e6c2a27a8b9f1d5c878c3dadf" + hash: "e419dbe857667b014e4dd9b57b01bbe4" } Mouse { type: 5 @@ -2098,7 +2098,7 @@ VisualTest { } Frame { msec: 4544 - hash: "a0a1e5fd37e9d8033f182f4f2b20fd26" + hash: "411cb7a7f331161059faba4ae6549229" } Mouse { type: 5 @@ -2110,7 +2110,7 @@ VisualTest { } Frame { msec: 4560 - hash: "b40e553dc373e4018488d5421b9a8914" + hash: "b008d6b2b444881c36521595f6b31539" } Mouse { type: 5 @@ -2122,7 +2122,7 @@ VisualTest { } Frame { msec: 4576 - hash: "22e36512a0af86fac12c09f735dcb1f7" + hash: "77fcc3c74c3832ae6b80aec420cb06e0" } Mouse { type: 5 @@ -2142,59 +2142,59 @@ VisualTest { } Frame { msec: 4592 - hash: "70e9ad0f56e4c37f8684e38f614b889d" + hash: "41d1c54bc76caeae057fb1bdb3b93843" } Frame { msec: 4608 - hash: "0754126f5738e3dcec35fc1ef65fdec3" + hash: "03fdd91b352798b1ff958c23c0bc5f35" } Frame { msec: 4624 - hash: "b3d84ceeecc294d21bc09a3197195c20" + hash: "2098ea8b55b54ca8dd648fb285c43ebf" } Frame { msec: 4640 - hash: "ce00501e194b1056edf1ebd43b954a70" + hash: "9929c509654819fd04da4e4b5c8e22b4" } Frame { msec: 4656 - hash: "793f41ac2568530e6d630446216833dc" + hash: "c470d3a57c6b56f9f56b176823b27d53" } Frame { msec: 4672 - hash: "e8573de724b653439bde85c15e9555ab" + hash: "37474b3a23f90dafee6b9e0043a702fa" } Frame { msec: 4688 - hash: "bfb3f3645c7b2425b686ac23bcef82b8" + hash: "0fbb6a9fded011b010fa6f3a2819630c" } Frame { msec: 4704 - hash: "faa78596e208c2cf4593ea25e31fabde" + hash: "6c5a7dad864999548257e4bf0ddc3687" } Frame { msec: 4720 - hash: "f1b0931bffce37abfe5a6d635f1f8454" + hash: "339bc42e559c66d07f37af5e06feacef" } Frame { msec: 4736 - hash: "0975630a55bfd56eb3e39426c1c3f1e5" + hash: "513dc773dc93275e32fa9ac61e6dcb46" } Frame { msec: 4752 - hash: "98f1d79153a8009123abc94141375779" + hash: "b725c84435b1f387dc3f375280e39de6" } Frame { msec: 4768 - hash: "d864817f877a9eeb44c665518ea19687" + hash: "f3d04b513df286aacb9ebdb107d7a0b4" } Frame { msec: 4784 - hash: "79745c267d14e7790e1bb3a7e76f20b4" + hash: "c22839005ed0cb6b2fa9c958d17fd948" } Frame { msec: 4800 - hash: "ec038d4cec64b847711fa221f808bead" + hash: "2fb9a2d5d22a6d0ed567328ffaa512f0" } Frame { msec: 4816 @@ -2202,239 +2202,239 @@ VisualTest { } Frame { msec: 4832 - hash: "ef7b3f93abbf210f8f0d38a58380dc8f" + hash: "ba13b0b4790aec7084b5553fe0b0d72b" } Frame { msec: 4848 - hash: "f0eea63127df25f7f818596fc034fef8" + hash: "2bc983733d4004cc67a56d77e9f48e5d" } Frame { msec: 4864 - hash: "8000dee3ea54522a8193a7f9f2e86023" + hash: "0f729cbe41b155b6eef20a4be207b853" } Frame { msec: 4880 - hash: "111485ebaf93aae4f5e0a83da898bbac" + hash: "c2ca47a7d70ef827029b32c11a052b83" } Frame { msec: 4896 - hash: "4b2dee1fd88dcaeabc8235f6a0e5c090" + hash: "803aefca7f1cbd494d2d2f7e7eea9a3f" } Frame { msec: 4912 - hash: "5e560c777d0294dfa8f249232bfcf3a2" + hash: "2641683e1fa9ed418ac89631be7922f1" } Frame { msec: 4928 - hash: "d8b490092ca5ce3ef9b078f4768c382a" + hash: "3d9370305ca147625828f7ee3b34ca33" } Frame { msec: 4944 - hash: "28b2bbc3fd19786dd9c0ab718141c525" + hash: "5cdfdd22a0dc1ed78035ae4b5e2e26a7" } Frame { msec: 4960 - hash: "d1a61000ebc5a475c0223dde649c8054" + hash: "2af663981b43dbe699849eff4731829a" } Frame { msec: 4976 - hash: "d3e8aae08a2518c039d6bda80fc520a4" + hash: "b159d3a09666327bd2d860bf56920734" } Frame { msec: 4992 - hash: "9f3bd8654adb9af0457dd50ff71fcd43" + hash: "a1ed6f686f4cda9aa59bfd49deb8a075" } Frame { msec: 5008 - hash: "befe00fef613b7616e2dc668a5ed59c7" + hash: "c5f1862e7cbb1dcd6b303e58c525ab5c" } Frame { msec: 5024 - hash: "24e84e6998389aa119d7d9e0ac2206ac" + hash: "3cc5e5d87067978961eee6e7b33ada06" } Frame { msec: 5040 - hash: "2d3d2b66bf016c8e499f527dbf8923db" + hash: "74f3b0eae443bd9f171020fd973ca960" } Frame { msec: 5056 - hash: "52d24673729dbd53d3227675b7001b24" + hash: "432037812ab1a09e0d0b32dfaf0f876e" } Frame { msec: 5072 - hash: "4e5c807682d7b6b7839c047a7fb4ad93" + hash: "0eec7146b8df3b4892e89abd13b8bc9d" } Frame { msec: 5088 - hash: "319affea47c4a0b0e2c3db51b85430bc" + hash: "a01dc5f4b4307aa66068d21159dd64d5" } Frame { msec: 5104 - hash: "344962f0b88c7e8a33df71b4708fd1c0" + hash: "11eefdf5b1be8493a6ed9aaf519c7e17" } Frame { msec: 5120 - hash: "ac099ba8a5639b9c83b6f58f2b5bcf93" + hash: "55ed797b82f5bca2ac2b5954c44c041e" } Frame { msec: 5136 - hash: "2f8e57c93289dcdc758281531300e949" + hash: "498d4ca9faabf8b59e2359b60dc1aff2" } Frame { msec: 5152 - hash: "e4cc3bdf6068064bcfdd0014cc301e65" + hash: "78895368b141ab6d3a16f65f4389b2d5" } Frame { msec: 5168 - hash: "598c8a33e2bbf47b21df8b0636e0f0bc" + hash: "c73b27167bad79f3f3c5ebb64fa579c2" } Frame { msec: 5184 - hash: "6aea67c85370eee8447a22e2b9e8c44c" + hash: "fb05312d65155f0300f456d727698b80" } Frame { msec: 5200 - hash: "39e27a3376f4aba8510f7b0d90ca0e33" + hash: "6e974736a0ecea6a71c1a7052a14fa20" } Frame { msec: 5216 - hash: "0ff93a16a07af43bd5e22a2b00fd2588" + hash: "f5daf5bec03d3e56c877e9b2dc5701b6" } Frame { msec: 5232 - hash: "8b6004368b9b0a766f6b519820fe1ff6" + hash: "29793d2147563feb9ed0ebff18b303cd" } Frame { msec: 5248 - hash: "5d92c0a12ff138d1b2c75bd042be4ea2" + hash: "5b63dfa3cb7ac0847f2e63f9d2a0b2b6" } Frame { msec: 5264 - hash: "4386b0abe49106a0174154c726c301f6" + hash: "cf2f42dd9830d80f50df30e93a0b1ad2" } Frame { msec: 5280 - hash: "832da8d2a86caa3ca96f33d2cd49178e" + hash: "8abb0aa8951612338c3bb87c7a0d2509" } Frame { msec: 5296 - hash: "efee6ab1ba4a1112f2129aad12825667" + hash: "8abb0aa8951612338c3bb87c7a0d2509" } Frame { msec: 5312 - hash: "f20a7e67a4789c559b0b0a7656bd89b1" + hash: "8abb0aa8951612338c3bb87c7a0d2509" } Frame { msec: 5328 - hash: "350cc8c0085a8f79c9ea8880737a0b75" + hash: "8abb0aa8951612338c3bb87c7a0d2509" } Frame { msec: 5344 - hash: "b19715b4029ea489debf7c5a269aca98" + hash: "8abb0aa8951612338c3bb87c7a0d2509" } Frame { msec: 5360 - hash: "f383fcaf603af41650c5622bfaf136b3" + hash: "8abb0aa8951612338c3bb87c7a0d2509" } Frame { msec: 5376 - hash: "0c62a442367fc0bac5117da1327ed39a" + hash: "8abb0aa8951612338c3bb87c7a0d2509" } Frame { msec: 5392 - hash: "323ba45d158d983f359211f1a87b7ebd" + hash: "8abb0aa8951612338c3bb87c7a0d2509" } Frame { msec: 5408 - hash: "aeed1a31b8b77dac2c2858969ff2d86c" + hash: "8abb0aa8951612338c3bb87c7a0d2509" } Frame { msec: 5424 - hash: "27a9357730a97846ffeddd18492df04d" + hash: "8abb0aa8951612338c3bb87c7a0d2509" } Frame { msec: 5440 - hash: "42f78593e64585b33c8854e8ea92710e" + hash: "8abb0aa8951612338c3bb87c7a0d2509" } Frame { msec: 5456 - hash: "064f5cec99b9a351bebe2088019f46d1" + hash: "8abb0aa8951612338c3bb87c7a0d2509" } Frame { msec: 5472 - hash: "d3669826f94aa2afc1069ab967f677a3" + hash: "8abb0aa8951612338c3bb87c7a0d2509" } Frame { msec: 5488 - hash: "a118cf8892d29e6b70b4e65e42380c15" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5504 - hash: "f254260f01ff4697e9e3146cc106140d" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5520 - hash: "ec062b2bb87444115c2e8744b7f80bde" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5536 - hash: "4d45522a4e4253c810cac9cbf24c9b76" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5552 - hash: "532c3d3ead73836948a1036e8e69cadf" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5568 - hash: "4debea14aeac85ff4e64387938d8b010" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5584 - hash: "d8940cf6e39a1bd5e7216a83ce87a676" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5600 - hash: "fba6485f8a60a38ce2f3110137b1f2df" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5616 - hash: "8a8909b114332dd932b784a2640e9ff4" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5632 - hash: "fd901422400333c137240ef5f91928a3" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5648 - hash: "97b84a957515d5823e381fdd86d31fb8" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5664 - hash: "f3547ea694b88dd7d2fb8b04d6bf76a9" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5680 - hash: "9eb0da29d0c323b45e62d31bee97ce8c" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5696 - hash: "9d814096d27e9fbcffdf7e29866e0059" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5712 - hash: "6087185e1e8bf17545a7372be2990ab2" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5728 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5744 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5760 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5776 @@ -2442,126 +2442,126 @@ VisualTest { } Frame { msec: 5792 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5808 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5824 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5840 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5856 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5872 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5888 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5904 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5920 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5936 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5952 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5968 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 5984 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6000 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6016 - hash: "82e534c416dfe884e5abc2f91d902484" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6032 - hash: "6839b467f32eaa79d4c1ce4905145350" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6048 - hash: "6839b467f32eaa79d4c1ce4905145350" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6064 - hash: "6839b467f32eaa79d4c1ce4905145350" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6080 - hash: "6839b467f32eaa79d4c1ce4905145350" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6096 - hash: "6839b467f32eaa79d4c1ce4905145350" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6112 - hash: "6839b467f32eaa79d4c1ce4905145350" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6128 - hash: "6839b467f32eaa79d4c1ce4905145350" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6144 - hash: "6839b467f32eaa79d4c1ce4905145350" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6160 - hash: "6839b467f32eaa79d4c1ce4905145350" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6176 - hash: "6839b467f32eaa79d4c1ce4905145350" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6192 - hash: "6839b467f32eaa79d4c1ce4905145350" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6208 - hash: "6839b467f32eaa79d4c1ce4905145350" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6224 - hash: "6839b467f32eaa79d4c1ce4905145350" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6240 - hash: "6839b467f32eaa79d4c1ce4905145350" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6256 - hash: "6839b467f32eaa79d4c1ce4905145350" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } Frame { msec: 6272 - hash: "6839b467f32eaa79d4c1ce4905145350" + hash: "a29d4b3fa16829823e63bf83e7b62aff" } } diff --git a/tests/auto/declarative/qmlvisual/qdeclarativepathview/test-pathview.qml b/tests/auto/declarative/qmlvisual/qdeclarativepathview/test-pathview.qml index 4374b84..08499e7 100644 --- a/tests/auto/declarative/qmlvisual/qdeclarativepathview/test-pathview.qml +++ b/tests/auto/declarative/qmlvisual/qdeclarativepathview/test-pathview.qml @@ -35,6 +35,8 @@ Rectangle { id: photoPathView; model: rssModel; delegate: photoDelegate anchors.fill: parent; z: 1 anchors.topMargin:40 + highlightMoveDuration: 200 + flickDeceleration: 200 path: Path { startX: -50; startY: 40; -- cgit v0.12 From 34630042ded25177b49f8e54b41269db1be42935 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Thu, 23 Dec 2010 13:17:20 +1000 Subject: Try fixing build error on Windows --- .../declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro b/tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro index 472cffb..efcea12 100644 --- a/tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro +++ b/tests/auto/declarative/qdeclarativexmllistmodel/qdeclarativexmllistmodel.pro @@ -1,5 +1,5 @@ load(qttest_p4) -contains(QT_CONFIG,declarative): QT += declarative script gui +contains(QT_CONFIG,declarative): QT += declarative script gui network contains(QT_CONFIG,xmlpatterns) { QT += xmlpatterns DEFINES += QTEST_XMLPATTERNS -- cgit v0.12 From 16d08f97eaa7dd0469d7c9006546f86f1fd763f6 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 23 Dec 2010 13:13:36 +1000 Subject: Models which load incrementally via fetchMore() don't work. Call canFetchMore()/fetchMore() on setModel(), setRootIndex() and when the last item is created. Task-number: QTBUG-16039 Reviewed-by: Bea Lam --- .../graphicsitems/qdeclarativevisualitemmodel.cpp | 6 ++ .../qdeclarativelistview/incrementalmodel.cpp | 89 ++++++++++++++++++++++ .../qdeclarativelistview/incrementalmodel.h | 68 +++++++++++++++++ .../qdeclarativelistview/qdeclarativelistview.pro | 3 +- .../tst_qdeclarativelistview.cpp | 28 +++++++ 5 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 tests/auto/declarative/qdeclarativelistview/incrementalmodel.cpp create mode 100644 tests/auto/declarative/qdeclarativelistview/incrementalmodel.h diff --git a/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp b/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp index 4f5213a..bf9263b 100644 --- a/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp +++ b/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp @@ -773,6 +773,8 @@ void QDeclarativeVisualDataModel::setModel(const QVariant &model) QObject::connect(d->m_abstractItemModel, SIGNAL(modelReset()), this, SLOT(_q_modelReset())); QObject::connect(d->m_abstractItemModel, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged())); d->m_metaDataCacheable = true; + if (d->m_abstractItemModel->canFetchMore(d->m_root)) + d->m_abstractItemModel->fetchMore(d->m_root); return; } if ((d->m_visualItemModel = qvariant_cast(model))) { @@ -870,6 +872,8 @@ void QDeclarativeVisualDataModel::setRootIndex(const QVariant &root) if (d->m_root != modelIndex) { int oldCount = d->modelCount(); d->m_root = modelIndex; + if (d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(modelIndex)) + d->m_abstractItemModel->fetchMore(modelIndex); int newCount = d->modelCount(); if (d->m_delegate && oldCount) emit itemsRemoved(0, oldCount); @@ -1094,6 +1098,8 @@ QDeclarativeItem *QDeclarativeVisualDataModel::item(int index, const QByteArray d->m_delegateValidated = true; } } + if (d->modelCount()-1 == index && d->m_abstractItemModel && d->m_abstractItemModel->canFetchMore(d->m_root)) + d->m_abstractItemModel->fetchMore(d->m_root); return item; } diff --git a/tests/auto/declarative/qdeclarativelistview/incrementalmodel.cpp b/tests/auto/declarative/qdeclarativelistview/incrementalmodel.cpp new file mode 100644 index 0000000..b2c9df5 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistview/incrementalmodel.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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 test suite 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$ +** +****************************************************************************/ + +#include "incrementalmodel.h" +#include +#include + +IncrementalModel::IncrementalModel(QObject *parent) + : QAbstractListModel(parent), count(0) +{ + for (int i = 0; i < 100; ++i) + list.append("Item " + QString::number(i)); +} + +int IncrementalModel::rowCount(const QModelIndex & /* parent */) const +{ + return count; +} + +QVariant IncrementalModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() >= list.size() || index.row() < 0) + return QVariant(); + + if (role == Qt::DisplayRole) + return list.at(index.row()); + return QVariant(); +} + +bool IncrementalModel::canFetchMore(const QModelIndex & /* index */) const +{ + if (count < list.size()) + return true; + else + return false; +} + +void IncrementalModel::fetchMore(const QModelIndex & /* index */) +{ + int remainder = list.size() - count; + int itemsToFetch = qMin(5, remainder); + + beginInsertRows(QModelIndex(), count, count+itemsToFetch-1); + + count += itemsToFetch; + + endInsertRows(); +} diff --git a/tests/auto/declarative/qdeclarativelistview/incrementalmodel.h b/tests/auto/declarative/qdeclarativelistview/incrementalmodel.h new file mode 100644 index 0000000..b1f7407 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistview/incrementalmodel.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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 test suite 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$ +** +****************************************************************************/ + +#ifndef IncrementalModel_H +#define IncrementalModel_H + +#include +#include +#include + +class IncrementalModel : public QAbstractListModel +{ + Q_OBJECT + +public: + IncrementalModel(QObject *parent = 0); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + +protected: + bool canFetchMore(const QModelIndex &parent) const; + void fetchMore(const QModelIndex &parent); + +private: + QStringList list; + int count; +}; + +#endif diff --git a/tests/auto/declarative/qdeclarativelistview/qdeclarativelistview.pro b/tests/auto/declarative/qdeclarativelistview/qdeclarativelistview.pro index 2c5a859..8c99f08 100644 --- a/tests/auto/declarative/qdeclarativelistview/qdeclarativelistview.pro +++ b/tests/auto/declarative/qdeclarativelistview/qdeclarativelistview.pro @@ -2,7 +2,8 @@ load(qttest_p4) contains(QT_CONFIG,declarative): QT += declarative macx:CONFIG -= app_bundle -SOURCES += tst_qdeclarativelistview.cpp +HEADERS += incrementalmodel.h +SOURCES += tst_qdeclarativelistview.cpp incrementalmodel.cpp symbian: { importFiles.sources = data diff --git a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp index dba0cc4..e76cb15 100644 --- a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp +++ b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp @@ -51,6 +51,7 @@ #include #include #include "../../../shared/util.h" +#include "incrementalmodel.h" #ifdef Q_OS_SYMBIAN // In Symbian OS test data is located in applications private dir @@ -106,6 +107,7 @@ private slots: void resizeDelegate(); void QTBUG_16037(); void indexAt(); + void incrementalModel(); private: template void items(); @@ -1998,6 +2000,32 @@ void tst_QDeclarativeListView::indexAt() delete canvas; } +void tst_QDeclarativeListView::incrementalModel() +{ + QDeclarativeView *canvas = createView(); + + IncrementalModel model; + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/displaylist.qml")); + qApp->processEvents(); + + QDeclarativeListView *listview = findItem(canvas->rootObject(), "list"); + QTRY_VERIFY(listview != 0); + + QDeclarativeItem *contentItem = listview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + QTRY_COMPARE(listview->count(), 20); + + listview->positionViewAtIndex(10, QDeclarativeListView::Beginning); + + QTRY_COMPARE(listview->count(), 25); + + delete canvas; +} + void tst_QDeclarativeListView::qListModelInterface_items() { items(); -- cgit v0.12 From 508d52477fe16f3b425e5d3ec65584e86ed939b3 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 23 Dec 2010 15:01:58 +1000 Subject: Improve docs on attached properties on view delegates. Clarify that the properties are attached to the root of the delegate, and must be accessed as such by child items. Task-number: QTBUG-16193 Reviewed-by: Bea Lam --- doc/src/snippets/declarative/gridview/gridview.qml | 26 ++++++++++++++++++++++ doc/src/snippets/declarative/listview/listview.qml | 14 ++++++++---- .../declarative/pathview/pathattributes.qml | 4 ++-- doc/src/snippets/declarative/pathview/pathview.qml | 14 ++++++++++-- .../graphicsitems/qdeclarativegridview.cpp | 9 ++++++++ .../graphicsitems/qdeclarativelistview.cpp | 7 ++++++ .../graphicsitems/qdeclarativepathview.cpp | 9 ++++++++ 7 files changed, 75 insertions(+), 8 deletions(-) diff --git a/doc/src/snippets/declarative/gridview/gridview.qml b/doc/src/snippets/declarative/gridview/gridview.qml index 73e58ec..87d70de 100644 --- a/doc/src/snippets/declarative/gridview/gridview.qml +++ b/doc/src/snippets/declarative/gridview/gridview.qml @@ -132,6 +132,32 @@ GridView { } //![highlightFollowsCurrentItem] +//![isCurrentItem] +GridView { + width: 300; height: 200 + cellWidth: 80; cellHeight: 80 + + Component { + id: contactsDelegate + Rectangle { + id: wrapper + width: 80 + height: 80 + color: GridView.isCurrentItem ? "black" : "red" + Text { + id: contactInfo + text: name + ": " + number + color: wrapper.GridView.isCurrentItem ? "red" : "black" + } + } + } + + model: ContactModel {} + delegate: contactsDelegate + focus: true +} +//![isCurrentItem] + } } diff --git a/doc/src/snippets/declarative/listview/listview.qml b/doc/src/snippets/declarative/listview/listview.qml index 8ba47a8..370429e 100644 --- a/doc/src/snippets/declarative/listview/listview.qml +++ b/doc/src/snippets/declarative/listview/listview.qml @@ -127,10 +127,16 @@ ListView { Component { id: contactsDelegate - Text { - id: contactInfo - text: name + ": " + number - color: contactInfo.ListView.isCurrentItem ? "red" : "black" + Rectangle { + id: wrapper + width: 180 + height: contactInfo.height + color: ListView.isCurrentItem ? "black" : "red" + Text { + id: contactInfo + text: name + ": " + number + color: wrapper.ListView.isCurrentItem ? "red" : "black" + } } } diff --git a/doc/src/snippets/declarative/pathview/pathattributes.qml b/doc/src/snippets/declarative/pathview/pathattributes.qml index d6dacdb..be933e0 100644 --- a/doc/src/snippets/declarative/pathview/pathattributes.qml +++ b/doc/src/snippets/declarative/pathview/pathattributes.qml @@ -52,8 +52,8 @@ Rectangle { scale: PathView.iconScale opacity: PathView.iconOpacity Column { - Image { anchors.horizontalCenter: name.horizontalCenter; width: 64; height: 64; source: icon } - Text { text: name; font.pointSize: 16} + Image { anchors.horizontalCenter: nameText.horizontalCenter; width: 64; height: 64; source: icon } + Text { id: nameText; text: name; font.pointSize: 16 } } } } diff --git a/doc/src/snippets/declarative/pathview/pathview.qml b/doc/src/snippets/declarative/pathview/pathview.qml index 93298c4..e5e90a4 100644 --- a/doc/src/snippets/declarative/pathview/pathview.qml +++ b/doc/src/snippets/declarative/pathview/pathview.qml @@ -48,8 +48,18 @@ Rectangle { Component { id: delegate Column { - Image { anchors.horizontalCenter: name.horizontalCenter; width: 64; height: 64; source: icon } - Text { text: name; font.pointSize: 16 } + id: wrapper + Image { + anchors.horizontalCenter: nameText.horizontalCenter + width: 64; height: 64 + source: icon + } + Text { + id: nameText + text: name + font.pointSize: 16 + color: wrapper.PathView.isCurrentItem ? "red" : "black" + } } } //! [1] diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp index 4a6a9dc..7ddf6a2 100644 --- a/src/declarative/graphicsitems/qdeclarativegridview.cpp +++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp @@ -1131,6 +1131,13 @@ void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal m Delegates are instantiated as needed and may be destroyed at any time. State should \e never be stored in a delegate. + GridView attaches a number of properties to the root item of the delegate, for example + \c {GridView.isCurrentItem}. In the following example, the root delegate item can access + this attached property directly as \c GridView.isCurrentItem, while the child + \c contactInfo object must refer to this property as \c wrapper.GridView.isCurrentItem. + + \snippet doc/src/snippets/declarative/gridview/gridview.qml isCurrentItem + \note Views do not set the \l{Item::}{clip} property automatically. If the view is not clipped by another item or the screen, it will be necessary to set this property to true in order to clip the items that are partially or @@ -1167,6 +1174,8 @@ QDeclarativeGridView::~QDeclarativeGridView() This attached property holds the view that manages this delegate instance. It is attached to each instance of the delegate. + + \snippet doc/src/snippets/declarative/gridview/gridview.qml isCurrentItem */ /*! diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index 86c8756..702442b 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -1416,6 +1416,13 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m Delegates are instantiated as needed and may be destroyed at any time. State should \e never be stored in a delegate. + ListView attaches a number of properties to the root item of the delegate, for example + \c {ListView.isCurrentItem}. In the following example, the root delegate item can access + this attached property directly as \c ListView.isCurrentItem, while the child + \c contactInfo object must refer to this property as \c wrapper.ListView.isCurrentItem. + + \snippet doc/src/snippets/declarative/listview/listview.qml isCurrentItem + \note Views do not enable \e clip automatically. If the view is not clipped by another item or the screen, it will be necessary to set \e {clip: true} in order to have the out of view items clipped diff --git a/src/declarative/graphicsitems/qdeclarativepathview.cpp b/src/declarative/graphicsitems/qdeclarativepathview.cpp index a6f44b3..e3987d0 100644 --- a/src/declarative/graphicsitems/qdeclarativepathview.cpp +++ b/src/declarative/graphicsitems/qdeclarativepathview.cpp @@ -393,6 +393,13 @@ void QDeclarativePathViewPrivate::regenerate() Delegates are instantiated as needed and may be destroyed at any time. State should \e never be stored in a delegate. + PathView attaches a number of properties to the root item of the delegate, for example + \c {PathView.isCurrentItem}. In the following example, the root delegate item can access + this attached property directly as \c PathView.isCurrentItem, while the child + \c nameText object must refer to this property as \c wrapper.PathView.isCurrentItem. + + \snippet doc/src/snippets/declarative/pathview/pathview.qml 1 + \bold Note that views do not enable \e clip automatically. If the view is not clipped by another item or the screen, it will be necessary to set \e {clip: true} in order to have the out of view items clipped @@ -452,6 +459,8 @@ QDeclarativePathView::~QDeclarativePathView() It is attached to each instance of the delegate. This property may be used to adjust the appearance of the current item. + + \snippet doc/src/snippets/declarative/pathview/pathview.qml 1 */ /*! -- cgit v0.12 From 93edc0680b8ca9cccefa31f8d2df08b0fc8f32f8 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 23 Dec 2010 15:21:32 +1000 Subject: More docs for FolderListModel --- .../qdeclarativefolderlistmodel.cpp | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp b/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp index 9c71004..7b05bc5 100644 --- a/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp +++ b/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp @@ -190,6 +190,12 @@ QVariant QDeclarativeFolderListModel::data(const QModelIndex &index, int role) c return rv; } +/*! + \qmlproperty int FolderListModel::count + + Returns the number of items in the current folder that match the + filter criteria. +*/ int QDeclarativeFolderListModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); @@ -225,6 +231,11 @@ void QDeclarativeFolderListModel::setFolder(const QUrl &folder) } } +/*! + \qmlproperty url FolderListModel::parentFolder + + Returns the URL of the parent of of the current \l folder. +*/ QUrl QDeclarativeFolderListModel::parentFolder() const { QString localFile = d->folder.toLocalFile(); @@ -286,6 +297,21 @@ void QDeclarativeFolderListModel::componentComplete() QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection); } +/*! + \qmlproperty enumeration FolderListModel::sortField + + The \a sortField property contains field to use for sorting. sortField + may be one of: + \list + \o Unsorted - no sorting is applied. The order is system default. + \o Name - sort by filename + \o Time - sort by time modified + \o Size - sort by file size + \o Type - sort by file type (extension) + \endlist + + \sa sortReversed +*/ QDeclarativeFolderListModel::SortField QDeclarativeFolderListModel::sortField() const { return d->sortField; @@ -299,6 +325,13 @@ void QDeclarativeFolderListModel::setSortField(SortField field) } } +/*! + \qmlproperty bool FolderListModel::sortReversed + + If set to true, reverses the sort order. The default is false. + + \sa sortField +*/ bool QDeclarativeFolderListModel::sortReversed() const { return d->sortReversed; -- cgit v0.12 From eb395badcba6eada75ad5e6a72b74f5204170ed9 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 23 Dec 2010 15:41:09 +1000 Subject: WorkerScript could starve image loading of CPU. We use idle priority for image loading and XmlListModel in order to keep the UI responsive, but WorkerScript used LowPriority which would significantly reduce CPU available for image loading. Task-number: QTBUG-16167 --- src/declarative/qml/qdeclarativeworkerscript.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/declarative/qml/qdeclarativeworkerscript.cpp b/src/declarative/qml/qdeclarativeworkerscript.cpp index 4b78020..9dc214f 100644 --- a/src/declarative/qml/qdeclarativeworkerscript.cpp +++ b/src/declarative/qml/qdeclarativeworkerscript.cpp @@ -458,7 +458,7 @@ QDeclarativeWorkerScriptEngine::QDeclarativeWorkerScriptEngine(QDeclarativeEngin { d->m_lock.lock(); connect(d, SIGNAL(stopThread()), this, SLOT(quit()), Qt::DirectConnection); - start(QThread::LowPriority); + start(QThread::IdlePriority); d->m_wait.wait(&d->m_lock); d->moveToThread(this); d->m_lock.unlock(); -- cgit v0.12 From 03f94089a16cf6b6a3b533ba1f90444eb18c29ab Mon Sep 17 00:00:00 2001 From: Charles Yin Date: Thu, 4 Nov 2010 15:38:57 +1000 Subject: Add Postgresql 8.x and 9 supports Change-Id: Ic740686ead768cc3e106703049d878549dfd3c6a Task-number:QTBUG-14206 Reviewed-by: Michael Goddard --- src/sql/drivers/psql/qsql_psql.cpp | 116 ++++++++++++++++++++++---------- src/sql/drivers/psql/qsql_psql.h | 6 +- tests/auto/qsqldatabase/tst_databases.h | 2 + 3 files changed, 88 insertions(+), 36 deletions(-) diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp index 2a4e595..bf9685f 100644 --- a/src/sql/drivers/psql/qsql_psql.cpp +++ b/src/sql/drivers/psql/qsql_psql.cpp @@ -54,7 +54,6 @@ #include #include - #include #include @@ -619,6 +618,50 @@ static void setDatestyle(PGconn* connection) PQclear(result); } +static QPSQLDriver::Protocol qMakePSQLVersion(int vMaj, int vMin) +{ + switch (vMaj) { + case 6: + return QPSQLDriver::Version6; + case 7: + { + switch (vMin) { + case 1: + return QPSQLDriver::Version71; + case 3: + return QPSQLDriver::Version73; + case 4: + return QPSQLDriver::Version74; + default: + return QPSQLDriver::Version7; + } + break; + } + case 8: + { + switch (vMin) { + case 1: + return QPSQLDriver::Version81; + case 2: + return QPSQLDriver::Version82; + case 3: + return QPSQLDriver::Version83; + case 4: + return QPSQLDriver::Version84; + default: + return QPSQLDriver::Version8; + } + break; + } + case 9: + return QPSQLDriver::Version9; + break; + default: + break; + } + return QPSQLDriver::VersionUnknown; +} + static QPSQLDriver::Protocol getPSQLVersion(PGconn* connection) { QPSQLDriver::Protocol serverVersion = QPSQLDriver::Version6; @@ -626,50 +669,44 @@ static QPSQLDriver::Protocol getPSQLVersion(PGconn* connection) int status = PQresultStatus(result); if (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK) { QString val = QString::fromAscii(PQgetvalue(result, 0, 0)); + QRegExp rx(QLatin1String("(\\d+)\\.(\\d+)")); rx.setMinimal(true); // enforce non-greedy RegExp + if (rx.indexIn(val) != -1) { int vMaj = rx.cap(1).toInt(); int vMin = rx.cap(2).toInt(); - - switch (vMaj) { - case 7: - switch (vMin) { - case 0: - serverVersion = QPSQLDriver::Version7; - break; - case 1: - case 2: - serverVersion = QPSQLDriver::Version71; - break; - default: - serverVersion = QPSQLDriver::Version73; - break; - } - break; - case 8: - switch (vMin) { - case 0: - serverVersion = QPSQLDriver::Version8; - break; - case 1: - serverVersion = QPSQLDriver::Version81; - break; - case 2: - default: - serverVersion = QPSQLDriver::Version82; - break; - } - break; - default: - break; + serverVersion = qMakePSQLVersion(vMaj, vMin); +#ifdef PG_MAJORVERSION + if (rx.indexIn(QLatin1String(PG_MAJORVERSION)) != -1) { + vMaj = rx.cap(1).toInt(); + vMin = rx.cap(2).toInt(); + } + QPSQLDriver::Protocol clientVersion = qMakePSQLVersion(vMaj, vMin); + + if (serverVersion >= QPSQLDriver::Version9 && clientVersion < QPSQLDriver::Version9) { + //Client version before QPSQLDriver::Version9 only supports escape mode for bytea type, + //but bytea format is set to hex by default in PSQL 9 and above. So need to force the + //server use the old escape mode when connects to the new server with old client library. + result = PQexec(connection, "SET bytea_output=escape; "); + status = PQresultStatus(result); + } else if (serverVersion == QPSQLDriver::VersionUnknown) { + serverVersion = clientVersion; + if (serverVersion != QPSQLDriver::VersionUnknown) + qWarning("The server version of this PostgreSQL is unknown, falling back to the client version."); } +#endif } } PQclear(result); - if (serverVersion < QPSQLDriver::Version71) + //keep the old behavior unchanged + if (serverVersion == QPSQLDriver::VersionUnknown) + serverVersion = QPSQLDriver::Version6; + + if (serverVersion < QPSQLDriver::Version71) { qWarning("This version of PostgreSQL is not supported and may not work."); + } return serverVersion; } @@ -852,7 +889,10 @@ bool QPSQLDriver::commitTransaction() // This hack can dissapear once there is an API to query this sort of information. if (d->pro == QPSQLDriver::Version8 || d->pro == QPSQLDriver::Version81 || - d->pro == QPSQLDriver::Version82) { + d->pro == QPSQLDriver::Version82 || + d->pro == QPSQLDriver::Version83 || + d->pro == QPSQLDriver::Version84 || + d->pro == QPSQLDriver::Version9) { transaction_failed = qstrcmp(PQcmdStatus(res), "ROLLBACK") == 0; } @@ -963,6 +1003,9 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const case QPSQLDriver::Version8: case QPSQLDriver::Version81: case QPSQLDriver::Version82: + case QPSQLDriver::Version83: + case QPSQLDriver::Version84: + case QPSQLDriver::Version9: stmt = QLatin1String("SELECT pg_attribute.attname, pg_attribute.atttypid::int, " "pg_class.relname " "FROM pg_attribute, pg_class " @@ -1046,6 +1089,9 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const case QPSQLDriver::Version8: case QPSQLDriver::Version81: case QPSQLDriver::Version82: + case QPSQLDriver::Version83: + case QPSQLDriver::Version84: + case QPSQLDriver::Version9: stmt = QLatin1String("select pg_attribute.attname, pg_attribute.atttypid::int, " "pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, " "pg_attrdef.adsrc " diff --git a/src/sql/drivers/psql/qsql_psql.h b/src/sql/drivers/psql/qsql_psql.h index 22871ff..107da87 100644 --- a/src/sql/drivers/psql/qsql_psql.h +++ b/src/sql/drivers/psql/qsql_psql.h @@ -97,6 +97,7 @@ class Q_EXPORT_SQLDRIVER_PSQL QPSQLDriver : public QSqlDriver Q_OBJECT public: enum Protocol { + VersionUnknown = -1, Version6 = 6, Version7 = 7, Version71 = 8, @@ -104,7 +105,10 @@ public: Version74 = 10, Version8 = 11, Version81 = 12, - Version82 = 13 + Version82 = 13, + Version83 = 14, + Version84 = 15, + Version9 = 16, }; explicit QPSQLDriver(QObject *parent=0); diff --git a/tests/auto/qsqldatabase/tst_databases.h b/tests/auto/qsqldatabase/tst_databases.h index 80535df..82ee41a 100644 --- a/tests/auto/qsqldatabase/tst_databases.h +++ b/tests/auto/qsqldatabase/tst_databases.h @@ -235,6 +235,8 @@ public: // addDb( "QPSQL7", "testdb", "testuser", "Ee4Gabf6_", "postgres74-nokia.trolltech.com.au" ); // Version 7.4.19-1.el4_6.1 // addDb( "QPSQL7", "testdb", "testuser", "Ee4Gabf6_", "bq-pgsql81.apac.nokia.com" ); // Version 8.1.11-1.el5_1.1 // addDb( "QPSQL7", "testdb", "testuser", "Ee4Gabf6_", "bq-pgsql84.apac.nokia.com" ); // Version 8.4.1-2.1.i586 +// addDb( "QPSQL7", "testdb", "testuser", "Ee4Gabf6_", "bq-pgsql90.apac.nokia.com" ); // Version 9.0.0 + // addDb( "QDB2", "testdb", "troll", "trond", "silence.nokia.troll.no" ); // DB2 v9.1 on silence -- cgit v0.12 From 4d81f771f513a9911a4812b47c6479c85eff0628 Mon Sep 17 00:00:00 2001 From: Niklas Kurkisuo Date: Thu, 23 Dec 2010 14:48:10 +0100 Subject: Fix resource leak in QCLuceneStopAnalyzer::QCLuceneStopAnalyzer. CID 22164. Merge-request: 2534 Reviewed-by: Harald Fernengel --- tools/assistant/lib/fulltextsearch/qanalyzer.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/assistant/lib/fulltextsearch/qanalyzer.cpp b/tools/assistant/lib/fulltextsearch/qanalyzer.cpp index 835b72e..23a9f14 100644 --- a/tools/assistant/lib/fulltextsearch/qanalyzer.cpp +++ b/tools/assistant/lib/fulltextsearch/qanalyzer.cpp @@ -147,6 +147,12 @@ QCLuceneStopAnalyzer::QCLuceneStopAnalyzer(const QStringList &stopWords) tArray[stopWords.count()] = 0; d->analyzer = new lucene::analysis::StopAnalyzer(tArray); + + // free memory + for(int i = 0; i < stopWords.count(); ++i) { + delete [] tArray[i]; + } + delete [] tArray; } QStringList QCLuceneStopAnalyzer::englishStopWords() const -- cgit v0.12 From e18dfbc2f5cc99aca1ff7abbab5f9b3be2bfed73 Mon Sep 17 00:00:00 2001 From: Niklas Kurkisuo Date: Thu, 23 Dec 2010 14:48:12 +0100 Subject: Fix resource leak in QCLuceneStandardAnalyzer::QCLuceneStandardAnalyzer. CID 22165. Merge-request: 2534 Reviewed-by: Harald Fernengel --- tools/assistant/lib/fulltextsearch/qanalyzer.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/assistant/lib/fulltextsearch/qanalyzer.cpp b/tools/assistant/lib/fulltextsearch/qanalyzer.cpp index 23a9f14..db2f06c 100644 --- a/tools/assistant/lib/fulltextsearch/qanalyzer.cpp +++ b/tools/assistant/lib/fulltextsearch/qanalyzer.cpp @@ -96,6 +96,12 @@ QCLuceneStandardAnalyzer::QCLuceneStandardAnalyzer(const QStringList &stopWords) tArray[stopWords.count()] = 0; d->analyzer = new lucene::analysis::standard::StandardAnalyzer(tArray); + + // free memory + for(int i = 0; i < stopWords.count(); ++i) { + delete [] tArray[i]; + } + delete [] tArray; } -- cgit v0.12 From d2f87812095d658bceea9287543a7f3d52e18944 Mon Sep 17 00:00:00 2001 From: Juuso Pakarinen Date: Thu, 23 Dec 2010 14:48:13 +0100 Subject: Fix for coding conventions. Merge-request: 2534 Reviewed-by: Harald Fernengel --- tools/assistant/lib/fulltextsearch/qanalyzer.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tools/assistant/lib/fulltextsearch/qanalyzer.cpp b/tools/assistant/lib/fulltextsearch/qanalyzer.cpp index db2f06c..c974fa6 100644 --- a/tools/assistant/lib/fulltextsearch/qanalyzer.cpp +++ b/tools/assistant/lib/fulltextsearch/qanalyzer.cpp @@ -97,10 +97,9 @@ QCLuceneStandardAnalyzer::QCLuceneStandardAnalyzer(const QStringList &stopWords) d->analyzer = new lucene::analysis::standard::StandardAnalyzer(tArray); - // free memory - for(int i = 0; i < stopWords.count(); ++i) { + for (int i = 0; i < stopWords.count(); ++i) delete [] tArray[i]; - } + delete [] tArray; } @@ -154,10 +153,9 @@ QCLuceneStopAnalyzer::QCLuceneStopAnalyzer(const QStringList &stopWords) d->analyzer = new lucene::analysis::StopAnalyzer(tArray); - // free memory - for(int i = 0; i < stopWords.count(); ++i) { + for (int i = 0; i < stopWords.count(); ++i) delete [] tArray[i]; - } + delete [] tArray; } -- cgit v0.12 From 1c5a9b8d80b9dfe26b2d669e081d9a461c181222 Mon Sep 17 00:00:00 2001 From: Harald Fernengel Date: Thu, 23 Dec 2010 14:49:52 +0100 Subject: Whitespace change Since I can't touch merge requests, this is a separate commit to fix whitespace errors in code. --- tools/assistant/lib/fulltextsearch/qanalyzer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/assistant/lib/fulltextsearch/qanalyzer.cpp b/tools/assistant/lib/fulltextsearch/qanalyzer.cpp index c974fa6..56eae69 100644 --- a/tools/assistant/lib/fulltextsearch/qanalyzer.cpp +++ b/tools/assistant/lib/fulltextsearch/qanalyzer.cpp @@ -99,7 +99,7 @@ QCLuceneStandardAnalyzer::QCLuceneStandardAnalyzer(const QStringList &stopWords) for (int i = 0; i < stopWords.count(); ++i) delete [] tArray[i]; - + delete [] tArray; } @@ -155,7 +155,7 @@ QCLuceneStopAnalyzer::QCLuceneStopAnalyzer(const QStringList &stopWords) for (int i = 0; i < stopWords.count(); ++i) delete [] tArray[i]; - + delete [] tArray; } -- cgit v0.12 From 15f6124da9c2cf70e74a1e0e6f89c27d17ec9d29 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 23 Dec 2010 15:53:43 +0200 Subject: Fix fullscreen/Maximized dialog misplacement in Symbian Task-number: QTBUG-16277 Reviewed-by: Sami Merila --- src/gui/dialogs/qdialog.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/gui/dialogs/qdialog.cpp b/src/gui/dialogs/qdialog.cpp index 16ea045..bcf952c 100644 --- a/src/gui/dialogs/qdialog.cpp +++ b/src/gui/dialogs/qdialog.cpp @@ -899,9 +899,21 @@ bool QDialog::symbianAdjustedPosition() { #if defined(Q_WS_S60) QPoint p; - const bool doS60Positioning = !(isFullScreen()||isMaximized()); - if (doS60Positioning) { - QPoint oldPos = pos(); + QPoint oldPos = pos(); + if (isFullScreen()) { + p.setX(0); + p.setY(0); + } else if (isMaximized()) { + TRect statusPaneRect = TRect(); + if (S60->screenHeightInPixels > S60->screenWidthInPixels) { + AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStatusPane, statusPaneRect); + } else { + AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStaconTop, statusPaneRect); + } + + p.setX(0); + p.setY(statusPaneRect.Height()); + } else { // naive way to deduce screen orientation if (S60->screenHeightInPixels > S60->screenWidthInPixels) { int cbaHeight; @@ -937,10 +949,10 @@ bool QDialog::symbianAdjustedPosition() p.setX(qMax(0,S60->screenWidthInPixels - width())); } } - if (oldPos != p || p.y() < 0) - move(p); } - return doS60Positioning; + if (oldPos != p || p.y() < 0) + move(p); + return true; #else // TODO - check positioning requirement for Symbian, non-s60 return false; -- cgit v0.12 From c168138195b623afc523ddd647dcfb690106c845 Mon Sep 17 00:00:00 2001 From: axis Date: Thu, 23 Dec 2010 15:07:21 +0100 Subject: Fixed several compile and deployment issues in the mmf phonon plugin. RevBy: Trust me Conflicts: src/plugins/phonon/mmf/mmf.pro src/s60installs/s60installs.pro --- src/plugins/phonon/mmf/mmf.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/phonon/mmf/mmf.pro b/src/plugins/phonon/mmf/mmf.pro index e546d83..9dccc4f 100644 --- a/src/plugins/phonon/mmf/mmf.pro +++ b/src/plugins/phonon/mmf/mmf.pro @@ -128,7 +128,7 @@ symbian { is_using_gnupoc { LIBS += -laudioequalizereffect -lbassboosteffect -ldistanceattenuationeffect -ldopplerbase -leffectbase -lenvironmentalreverbeffect -llistenerdopplereffect -llistenerlocationeffect -llistenerorientationeffect -llocationbase -lloudnesseffect -lorientationbase -lsourcedopplereffect -lsourcelocationeffect -lsourceorientationeffect -lstereowideningeffect } else { - LIBS += -lAudioEqualizerEffect -lBassBoostEffect -lDistanceAttenuationEffect -lDopplerBase -lEffectBase -lEnvironmentalReverbEffect -lListenerDopplerEffect -lListenerLocationEffect -lListenerOrientationEffect -lLocationBase -lLoudnessEffect -lOrientationBase -lSourceDopplerEffect -lSourceLocationEffect -lSourceOrientationEffect -lStereoWideningEffect + LIBS += -lAudioEqualizerEffect -lBassBoostEffect -lDistanceAttenuationEffect -lDopplerbase -lEffectBase -lEnvironmentalReverbEffect -lListenerDopplerEffect -lListenerLocationEffect -lListenerOrientationEffect -lLocationBase -lLoudnessEffect -lOrientationBase -lSourceDopplerEffect -lSourceLocationEffect -lSourceOrientationEffect -lStereoWideningEffect } # This is needed for having the .qtplugin file properly created on Symbian. -- cgit v0.12 From 76c1492a51746730c1b51539b87f8d8c810f44ff Mon Sep 17 00:00:00 2001 From: axis Date: Thu, 23 Dec 2010 15:52:38 +0100 Subject: Fixed a bug in elf2e32_qtwrapper regarding spaces in def files. It would not parse the line correctly if a space was missing between the "@" and the ordinal number. RevBy: Trust me --- bin/elf2e32_qtwrapper.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/elf2e32_qtwrapper.pl b/bin/elf2e32_qtwrapper.pl index d91be14..a90877e 100755 --- a/bin/elf2e32_qtwrapper.pl +++ b/bin/elf2e32_qtwrapper.pl @@ -146,7 +146,7 @@ while (1) { $origDefLine = <$origDefFile>; if (defined($origDefLine)) { $origDefLine =~ s/[\n\r]//; - if ($origDefLine =~ /([a-z0-9_]+) +\@ ([0-9]+) (.*)/i) { + if ($origDefLine =~ /([a-z0-9_]+) +\@ *([0-9]+) (.*)/i) { $origSym = $1; $origOrdinal = $2; $origExtraData = $3; @@ -161,7 +161,7 @@ while (1) { if ($savedNewDefFileLine) { # This happens if the new def file was missing an entry. $newDefLine = $savedNewDefFileLine; - $newDefLine =~ /([a-z0-9_]+) +\@ ([0-9]+) (.*)/i or die("$0: Shouldn't happen"); + $newDefLine =~ /([a-z0-9_]+) +\@ *([0-9]+) (.*)/i or die("$0: Shouldn't happen"); $newSym = $1; $newOrdinal = $2; $newExtraData = $3; @@ -171,7 +171,7 @@ while (1) { $newDefLine = <$newDefFile>; if (defined($newDefLine)) { $newDefLine =~ s/[\n\r]//; - if ($newDefLine =~ /([a-z0-9_]+) +\@ ([0-9]+) (.*)/i) { + if ($newDefLine =~ /([a-z0-9_]+) +\@ *([0-9]+) (.*)/i) { $newSym = $1; $newOrdinal = $2; $newExtraData = $3; -- cgit v0.12