From 0ba6c8a2eca9b1611e1ced85dcae1248b24f1e45 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 20 Jul 2011 16:45:29 +0200 Subject: [PATCH 01/75] unmark tst_moc as failing It was fixed in 77ed8787ac9ef0f74c2ab6699af3fec434e433e5 Change-Id: Ic26bfd63c1e9025117fde048b2aa94c73ae7866d Reviewed-on: http://codereview.qt.nokia.com/1897 Reviewed-by: Qt Sanity Bot Reviewed-by: Sergio Ahumada --- tests/auto/moc/moc.pro | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/auto/moc/moc.pro b/tests/auto/moc/moc.pro index 59106aa11d..056c6b0958 100644 --- a/tests/auto/moc/moc.pro +++ b/tests/auto/moc/moc.pro @@ -26,5 +26,3 @@ contains(QT_CONFIG, dbus){ QT += dbus } -CONFIG+=insignificant_test - From 16c17f5965d8913e64698c577c26fcec9402e17a Mon Sep 17 00:00:00 2001 From: Kim Motoyoshi Kalland Date: Tue, 19 Jul 2011 17:53:25 +0200 Subject: [PATCH 02/75] Fixed memory leak in the TIF handler. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Iaa3093b172ddbac6597169ee4217a7f6c7867e60 Reviewed-on: http://codereview.qt.nokia.com/1952 Reviewed-by: Qt Sanity Bot Reviewed-by: Samuel Rødal --- src/gui/image/qtiffhandler.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/gui/image/qtiffhandler.cpp b/src/gui/image/qtiffhandler.cpp index c753b83294..4dc9775d46 100644 --- a/src/gui/image/qtiffhandler.cpp +++ b/src/gui/image/qtiffhandler.cpp @@ -236,14 +236,14 @@ bool QTiffHandler::read(QImage *image) } } else { // create the color table - uint16 *redTable = static_cast(qMalloc(tableSize * sizeof(uint16))); - uint16 *greenTable = static_cast(qMalloc(tableSize * sizeof(uint16))); - uint16 *blueTable = static_cast(qMalloc(tableSize * sizeof(uint16))); - if (!redTable || !greenTable || !blueTable) { + uint16 *redTable = 0; + uint16 *greenTable = 0; + uint16 *blueTable = 0; + if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) { TIFFClose(tiff); return false; } - if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) { + if (!redTable || !greenTable || !blueTable) { TIFFClose(tiff); return false; } @@ -500,6 +500,9 @@ bool QTiffHandler::write(const QImage &image) uint16 *greenTable = static_cast(qMalloc(256 * sizeof(uint16))); uint16 *blueTable = static_cast(qMalloc(256 * sizeof(uint16))); if (!redTable || !greenTable || !blueTable) { + qFree(redTable); + qFree(greenTable); + qFree(blueTable); TIFFClose(tiff); return false; } From cfbdb4cc8a3a1f9e0036ec387cbc00d2058ee6e7 Mon Sep 17 00:00:00 2001 From: Martin Petersson Date: Wed, 20 Jul 2011 12:13:15 +0200 Subject: [PATCH 03/75] tst_QNetworkAddressEntry::prefixAndNetmask use QHostAddress::AnyIPv4 Update the test after the introduction of QHostAddress::AnyIPv4 in 85136496bc8517951dcc3e670d1a46d340819f0d Change-Id: I3b84e85b6dcefa69bf5953205e288a6f0affb341 Reviewed-on: http://codereview.qt.nokia.com/1873 Reviewed-by: Qt Sanity Bot Reviewed-by: Markus Goetz --- tests/auto/qnetworkaddressentry/tst_qnetworkaddressentry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qnetworkaddressentry/tst_qnetworkaddressentry.cpp b/tests/auto/qnetworkaddressentry/tst_qnetworkaddressentry.cpp index cf14aabb41..42b9af8dd3 100644 --- a/tests/auto/qnetworkaddressentry/tst_qnetworkaddressentry.cpp +++ b/tests/auto/qnetworkaddressentry/tst_qnetworkaddressentry.cpp @@ -97,7 +97,7 @@ void tst_QNetworkAddressEntry::prefixAndNetmask_data() // IPv4 set: QHostAddress ipv4(QHostAddress::LocalHost); - QTest::newRow("v4/0") << ipv4 << QHostAddress(QHostAddress::Any) << 0; + QTest::newRow("v4/0") << ipv4 << QHostAddress(QHostAddress::AnyIPv4) << 0; QTest::newRow("v4/32") << ipv4 << QHostAddress("255.255.255.255") << 32; QTest::newRow("v4/24") << ipv4 << QHostAddress("255.255.255.0") << 24; QTest::newRow("v4/23") << ipv4 << QHostAddress("255.255.254.0") << 23; From 74a6fe79d999178de9d16befe7547af2d2f9f698 Mon Sep 17 00:00:00 2001 From: David Faure Date: Thu, 21 Jul 2011 16:56:55 +0200 Subject: [PATCH 04/75] Speed up tst_qcoreapplication It was emitting signals from a thread for 15 seconds. Doing this 10 times should be enough, and way faster. Also a race made it sometimes wait 15 seconds while nothing was happening, and then it would still succeed; the new code prevents this from happening. Change-Id: Ib36785dd8090047c760ddcca44fc805efaef1bd8 Merge-request: 4 Reviewed-by: Olivier Goffart Reviewed-on: http://codereview.qt.nokia.com/1989 Reviewed-by: Qt Sanity Bot --- .../qcoreapplication/tst_qcoreapplication.cpp | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/tests/auto/qcoreapplication/tst_qcoreapplication.cpp b/tests/auto/qcoreapplication/tst_qcoreapplication.cpp index 0b581af77b..99f0941ac2 100644 --- a/tests/auto/qcoreapplication/tst_qcoreapplication.cpp +++ b/tests/auto/qcoreapplication/tst_qcoreapplication.cpp @@ -361,26 +361,25 @@ class DeliverInDefinedOrderObject : public QObject QPointer thread; int count; + int startCount; + int loopLevel; public: DeliverInDefinedOrderObject(QObject *parent) - : QObject(parent), thread(0), count(0) + : QObject(parent), thread(0), count(0), startCount(0), loopLevel(0) { } - ~DeliverInDefinedOrderObject() - { - if (!thread.isNull()) - thread->wait(); - } + +signals: + void done(); public slots: - void start() + void startThread() { QVERIFY(!thread); thread = new DeliverInDefinedOrderThread(); connect(thread, SIGNAL(progress(int)), this, SLOT(threadProgress(int))); connect(thread, SIGNAL(finished()), this, SLOT(threadFinished())); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - connect(thread, SIGNAL(destroyed()), this, SLOT(start())); + connect(thread, SIGNAL(destroyed()), this, SLOT(threadDestroyed())); thread->start(); QCoreApplication::postEvent(this, new QEvent(QEvent::MaxUser), -1); @@ -398,21 +397,34 @@ public slots: { QVERIFY(count == 7); count = 0; + thread->deleteLater(); QCoreApplication::postEvent(this, new QEvent(QEvent::MaxUser), -1); } + void threadDestroyed() + { + if (++startCount < 20) + startThread(); + else + emit done(); + } + public: bool event(QEvent *event) { switch (event->type()) { case QEvent::User: - { - (void) QEventLoop().exec(); - break; + { + ++loopLevel; + if (loopLevel == 2) { + // Ready. Starts a thread that emits (queued) signals, which should be handled in order + startThread(); } - case QEvent::User + 1: + QCoreApplication::postEvent(this, new QEvent(QEvent::MaxUser), -1); + (void) QEventLoop().exec(); break; + } default: break; } @@ -430,11 +442,8 @@ void tst_QCoreApplication::deliverInDefinedOrder() // causes sendPostedEvents() to recurse twice QCoreApplication::postEvent(&obj, new QEvent(QEvent::User)); QCoreApplication::postEvent(&obj, new QEvent(QEvent::User)); - // starts a thread that emits (queued) signals, which should be handled in order - obj.start(); - // run for 15 seconds - QTimer::singleShot(15000, &app, SLOT(quit())); + QObject::connect(&obj, SIGNAL(done()), &app, SLOT(quit())); app.exec(); } #endif // QT_NO_QTHREAD @@ -524,7 +533,7 @@ void tst_QCoreApplication::processEventsAlwaysSendsPostedEvents() QCoreApplication::processEvents(); QCOMPARE(object.counter, i); ++i; - } while (t.elapsed() < 3000); + } while (t.elapsed() < 1000); } void tst_QCoreApplication::reexec() From 001bd63e813cf19d1d6abbbfeb2599e6804807d5 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 21 Jul 2011 16:33:17 +0200 Subject: [PATCH 05/75] Make the N parameter to the QXXXLiterals be the actual string length Before, it was the length + 1, to include the ending NUL or U+0000. This avoids mistakes of -1 in QStringBuilder and will allow us simpler code in the User-Defined Literal (future improvement) Change-Id: I75c47d6c44579124888f925e240817229347dc70 Merge-request: 31 Reviewed-by: Olivier Goffart Reviewed-on: http://codereview.qt.nokia.com/1966 Reviewed-by: Qt Sanity Bot --- src/corelib/tools/qbytearray.h | 12 ++++++------ src/corelib/tools/qstring.h | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h index dbac302d05..4190ffa18a 100644 --- a/src/corelib/tools/qbytearray.h +++ b/src/corelib/tools/qbytearray.h @@ -133,10 +133,10 @@ struct QByteArrayData inline const char *data() const { return d + sizeof(qptrdiff) + offset; } }; -template struct QConstByteArrayData +template struct QConstByteArrayData { const QByteArrayData ba; - const char data[n]; + const char data[N + 1]; }; template struct QConstByteArrayDataPtr @@ -147,9 +147,9 @@ template struct QConstByteArrayDataPtr #if defined(Q_COMPILER_LAMBDA) # define QByteArrayLiteral(str) ([]() { \ - enum { Size = sizeof(str) }; \ + enum { Size = sizeof(str) - 1 }; \ static const QConstByteArrayData qbytearray_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, str }; \ QConstByteArrayDataPtr holder = { &qbytearray_literal }; \ return holder; }()) @@ -160,9 +160,9 @@ template struct QConstByteArrayDataPtr # define QByteArrayLiteral(str) \ __extension__ ({ \ - enum { Size = sizeof(str) }; \ + enum { Size = sizeof(str) - 1 }; \ static const QConstByteArrayData qbytearray_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, str }; \ QConstByteArrayDataPtr holder = { &qbytearray_literal }; \ holder; }) #endif diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index af3e3f3ff9..4471da4b09 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -97,36 +97,36 @@ template struct QConstStringDataPtr }; #if defined(Q_COMPILER_UNICODE_STRINGS) -template struct QConstStringData +template struct QConstStringData { const QStringData str; - const char16_t data[n]; + const char16_t data[N + 1]; }; #define QT_QSTRING_UNICODE_MARKER u"" #elif defined(Q_OS_WIN) || (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) || defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536) // wchar_t is 2 bytes -template struct QConstStringData +template struct QConstStringData { const QStringData str; - const wchar_t data[n]; + const wchar_t data[N + 1]; }; #define QT_QSTRING_UNICODE_MARKER L"" #else -template struct QConstStringData +template struct QConstStringData { const QStringData str; - const ushort data[n]; + const ushort data[N + 1]; }; #endif #if defined(QT_QSTRING_UNICODE_MARKER) # if defined(Q_COMPILER_LAMBDA) # define QStringLiteral(str) ([]() { \ - enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 }; \ + enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 - 1 }; \ static const QConstStringData qstring_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ QConstStringDataPtr holder = { &qstring_literal }; \ return holder; }()) @@ -137,9 +137,9 @@ template struct QConstStringData # define QStringLiteral(str) \ __extension__ ({ \ - enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 }; \ + enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 - 1 }; \ static const QConstStringData qstring_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ QConstStringDataPtr holder = { &qstring_literal }; \ holder; }) # endif From 227cb8c0b91f9e88e53432b3936cd1fc4f90e9f7 Mon Sep 17 00:00:00 2001 From: Sergio Ahumada Date: Wed, 20 Jul 2011 16:50:15 +0200 Subject: [PATCH 06/75] test: fix tst_QFile::rename() autotest This test was incorrectly assuming that a file named "Makefile" exists. Also removing the `insignificant_test' mark for Linux. Change-Id: I318b12f67e0476d6f08d1fc86194ca96f2bdb373 Reviewed-on: http://codereview.qt.nokia.com/1923 Reviewed-by: Qt Sanity Bot Reviewed-by: Rohan McGovern --- tests/auto/qfile/test/test.pro | 2 +- tests/auto/qfile/tst_qfile.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/qfile/test/test.pro b/tests/auto/qfile/test/test.pro index 0f211b9de5..f4ec12f874 100644 --- a/tests/auto/qfile/test/test.pro +++ b/tests/auto/qfile/test/test.pro @@ -41,4 +41,4 @@ symbian { LIBS+=-lefsrv } -CONFIG+=insignificant_test +mac*:CONFIG+=insignificant_test diff --git a/tests/auto/qfile/tst_qfile.cpp b/tests/auto/qfile/tst_qfile.cpp index 4a78876843..aafe79484e 100644 --- a/tests/auto/qfile/tst_qfile.cpp +++ b/tests/auto/qfile/tst_qfile.cpp @@ -2438,7 +2438,7 @@ void tst_QFile::rename_data() QTest::newRow("a -> b") << QString("a") << QString("b") << false; QTest::newRow("a -> .") << QString("a") << QString(".") << false; QTest::newRow("renamefile -> renamefile") << QString("renamefile") << QString("renamefile") << false; - QTest::newRow("renamefile -> Makefile") << QString("renamefile") << QString("Makefile") << false; + QTest::newRow("renamefile -> noreadfile") << QString("renamefile") << QString("noreadfile") << false; #if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) QTest::newRow("renamefile -> /etc/renamefile") << QString("renamefile") << QString("/etc/renamefile") << false; #endif From f74296ef7c9d58d042d7e7e10b65e32b1ff6d60e Mon Sep 17 00:00:00 2001 From: Pierre Rossi Date: Tue, 19 Jul 2011 18:36:05 +0200 Subject: [PATCH 07/75] Add support for rawFonts loaded from data in FaceId The problem was that with an empty filename and index of 0, all raw fonts loaded from data had the same FaceId, and we wouldn't bother to load another one after doing this once. This commit introduces a uuid in FaceId to help distinguish them in that case. Change-Id: I93655ff07a7d8856af1f854024e207c519f8ed1a Reviewed-on: http://codereview.qt.nokia.com/1882 Reviewed-by: Qt Sanity Bot Reviewed-by: Jiang Jiang --- src/gui/text/qfontengine_p.h | 3 ++- src/gui/text/qrawfont_ft.cpp | 2 ++ tests/auto/qrawfont/tst_qrawfont.cpp | 25 ++++++++++++++++++++++++- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index eee2bb6bac..5570768ddb 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -155,6 +155,7 @@ public: struct FaceId { FaceId() : index(0), encoding(0) {} QByteArray filename; + QByteArray uuid; int index; int encoding; }; @@ -303,7 +304,7 @@ inline bool operator ==(const QFontEngine::FaceId &f1, const QFontEngine::FaceId inline uint qHash(const QFontEngine::FaceId &f) { - return qHash((f.index << 16) + f.encoding) + qHash(f.filename); + return qHash((f.index << 16) + f.encoding) + qHash(f.filename + f.uuid); } diff --git a/src/gui/text/qrawfont_ft.cpp b/src/gui/text/qrawfont_ft.cpp index db60459176..d9225ff896 100644 --- a/src/gui/text/qrawfont_ft.cpp +++ b/src/gui/text/qrawfont_ft.cpp @@ -45,6 +45,7 @@ #include "qrawfont_p.h" #include "qfontengine_ft_p.h" +#include "quuid.h" #if defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG) # include "qfontengine_x11_p.h" @@ -87,6 +88,7 @@ public: FaceId faceId; faceId.filename = ""; faceId.index = 0; + faceId.uuid = QUuid::createUuid().toString().toAscii(); return init(faceId, true, Format_None, fontData); } diff --git a/tests/auto/qrawfont/tst_qrawfont.cpp b/tests/auto/qrawfont/tst_qrawfont.cpp index e0680c4257..eb78057b5e 100644 --- a/tests/auto/qrawfont/tst_qrawfont.cpp +++ b/tests/auto/qrawfont/tst_qrawfont.cpp @@ -47,7 +47,6 @@ class tst_QRawFont: public QObject { Q_OBJECT - #if !defined(QT_NO_RAWFONT) private slots: void invalidRawFont(); @@ -94,6 +93,11 @@ private slots: void rawFontSetPixelSize_data(); void rawFontSetPixelSize(); + +#if defined(Q_WS_X11) || defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) + void multipleRawFontsFromData(); +#endif + #endif // QT_NO_RAWFONT }; @@ -843,6 +847,25 @@ void tst_QRawFont::rawFontSetPixelSize() QCOMPARE(rawFont.pixelSize(), 24.0); } +#if defined(Q_WS_X11) || defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) +void tst_QRawFont::multipleRawFontsFromData() +{ + QFile file(QString::fromLatin1(SRCDIR "testfont.ttf")); + QRawFont testFont; + if (file.open(QIODevice::ReadOnly)) { + testFont.loadFromData(file.readAll(), 11, QFont::PreferDefaultHinting); + file.close(); + } + file.setFileName(QLatin1String(SRCDIR "testfont_bold_italic.ttf")); + QRawFont testFontBoldItalic; + if (file.open(QIODevice::ReadOnly)) + testFontBoldItalic.loadFromData(file.readAll(), 11, QFont::PreferDefaultHinting); + + QVERIFY(testFont.familyName() != (testFontBoldItalic.familyName()) + || testFont.styleName() != (testFontBoldItalic.styleName())); +} +#endif + #endif // QT_NO_RAWFONT QTEST_MAIN(tst_QRawFont) From 5e4d13e55c8401b89e8837f81e31b39c87e76e9d Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Mon, 18 Jul 2011 05:50:20 -0500 Subject: [PATCH 08/75] Remove loading "default" as a fall-back for missing "default_pre" "default" was used a very long time ago, and it's time to let it go. Change-Id: I230573ef778789f6e1a5a7df3543e660392da39b Reviewed-on: http://codereview.qt.nokia.com/1746 Reviewed-by: Qt Sanity Bot Reviewed-by: Oswald Buddenhagen --- qmake/project.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qmake/project.cpp b/qmake/project.cpp index cb4117bef4..df4076bd3c 100644 --- a/qmake/project.cpp +++ b/qmake/project.cpp @@ -1385,8 +1385,7 @@ QMakeProject::read(uchar cmd) if(cmd & ReadFeatures) { debug_msg(1, "Processing default_pre: %s", vars["CONFIG"].join("::").toLatin1().constData()); - if(doProjectInclude("default_pre", IncludeFlagFeature, base_vars) == IncludeNoExist) - doProjectInclude("default", IncludeFlagFeature, base_vars); + doProjectInclude("default_pre", IncludeFlagFeature, base_vars); } } From 289d5aed37886c9dcc96d41bf65d23121b0b1bee Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Sat, 16 Jul 2011 12:04:47 +0000 Subject: [PATCH 09/75] Make qmake load default_pre.prf for each project, like default_post.prf If you ran qmake with 'qmake -r', default_pre.prf would only be run once while default_post.prf would run for every sub-project. This makes it more symmetrical and correct. Change-Id: I1d096c38dffb16f1d256c511ed9e2912cfaefe66 Reviewed-on: http://codereview.qt.nokia.com/1716 Reviewed-by: Joerg Bornemann Reviewed-by: Oswald Buddenhagen --- qmake/project.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/qmake/project.cpp b/qmake/project.cpp index df4076bd3c..bbfd9005c6 100644 --- a/qmake/project.cpp +++ b/qmake/project.cpp @@ -1382,15 +1382,15 @@ QMakeProject::read(uchar cmd) read(Option::mkfile::cachefile, base_vars); } } - - if(cmd & ReadFeatures) { - debug_msg(1, "Processing default_pre: %s", vars["CONFIG"].join("::").toLatin1().constData()); - doProjectInclude("default_pre", IncludeFlagFeature, base_vars); - } } vars = base_vars; // start with the base + if(cmd & ReadFeatures) { + debug_msg(1, "Processing default_pre: %s", vars["CONFIG"].join("::").toLatin1().constData()); + doProjectInclude("default_pre", IncludeFlagFeature, vars); + } + //get a default if(pfile != "-" && vars["TARGET"].isEmpty()) vars["TARGET"].append(QFileInfo(pfile).baseName()); From 3fbc9e658df776ceb5cd90e2d145d30a52dd9aa4 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Sat, 16 Jul 2011 07:13:16 -0500 Subject: [PATCH 10/75] Make sure we only run syncqt for the non-buildpass cases In debug_and_release builds, we have three passes, the glue pass, and a pass for each build type. We only need to run syncqt when we are in a glue pass, which is when 'build_pass' is not set. In non-debug_and_release builds, build_pass is never set, so this condition works for all build types, with multiple configurations or not. Change-Id: I191da0df3ad422bb5fb8994391c2b2d2e23efc32 Reviewed-on: http://codereview.qt.nokia.com/1717 Reviewed-by: Qt Sanity Bot Reviewed-by: Joerg Bornemann Reviewed-by: Oswald Buddenhagen --- mkspecs/features/default_pre.prf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkspecs/features/default_pre.prf b/mkspecs/features/default_pre.prf index ebb94e272e..064d24bfa7 100644 --- a/mkspecs/features/default_pre.prf +++ b/mkspecs/features/default_pre.prf @@ -2,7 +2,7 @@ load(exclusive_builds) ### Qt 5: remove "uic" and "resources" - or add "qt" CONFIG = lex yacc warn_on debug uic resources $$CONFIG -exists($$_PRO_FILE_PWD_/sync.profile) { +!build_pass:exists($$_PRO_FILE_PWD_/sync.profile) { PRO_BASENAME = $$basename(_PRO_FILE_) # Try to detect proper QTDIR path. We require QTDIR, as syncqt uses that to create qt_module.pri From f3f5dc634612a3fdbecb2118e6fcd5772d9dfc7d Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Tue, 12 Jul 2011 13:19:01 -0500 Subject: [PATCH 11/75] Fix non-installed library detection Change-Id: I1eb8337bebb524b9f02aef63cd42efcb4a9211bc Reviewed-on: http://codereview.qt.nokia.com/1759 Reviewed-by: Qt Sanity Bot Reviewed-by: Oswald Buddenhagen --- mkspecs/features/qt_functions.prf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index 86d80cb239..13dadeb1e9 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -140,7 +140,7 @@ defineTest(qtAddModule) { } isEmpty(LINKAGE) { # Make sure we can link to uninstalled libraries - !isEqual(MODULE_LIBS, $[QT_INSTALL_LIBS]) { + !isEqual(MODULE_LIBS, $$[QT_INSTALL_LIBS]) { QMAKE_LIBDIR *= $$MODULE_LIBS unix:!mac:QMAKE_LFLAGS *= "-Wl,-rpath-link,$$MODULE_LIBS" } From 7f1d51a45d41a798041bd13200c2fe1ebac9673d Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Tue, 12 Jul 2011 13:01:03 -0500 Subject: [PATCH 12/75] Make sure we qtPrepareTool moc, uic and rcc too Their paths may vary depending on configuration and build/install state going forward. Change-Id: I60c8bcd1dc6c2fb729bf84d211875a3d910d5e4a Reviewed-on: http://codereview.qt.nokia.com/1761 Reviewed-by: Qt Sanity Bot Reviewed-by: Oswald Buddenhagen --- mkspecs/features/qt_module_config.prf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mkspecs/features/qt_module_config.prf b/mkspecs/features/qt_module_config.prf index 8f225fe6ed..7b5b5ad304 100644 --- a/mkspecs/features/qt_module_config.prf +++ b/mkspecs/features/qt_module_config.prf @@ -186,6 +186,9 @@ DEFINES *= QT_USE_QSTRINGBUILDER TARGET = $$qtLibraryTarget($$TARGET$$QT_LIBINFIX) #do this towards the end +qtPrepareTool(QMAKE_MOC, moc) +qtPrepareTool(QMAKE_UIC, uic) +qtPrepareTool(QMAKE_RCC, rcc) qtPrepareTool(QMAKE_LUPDATE, lupdate) qtPrepareTool(QMAKE_LRELEASE, lrelease) From 210211b7793bef626c085a354aa72ab6a397087b Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Mon, 18 Jul 2011 07:08:12 -0500 Subject: [PATCH 13/75] Close filehandle when done Also add a fixme, since the version headers are currently being created in the source directory. Change-Id: If6e9eeba854a1f35561b69518eb8739dc28a58be Reviewed-on: http://codereview.qt.nokia.com/1763 Reviewed-by: Qt Sanity Bot Reviewed-by: Joerg Bornemann --- bin/syncqt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bin/syncqt b/bin/syncqt index 776ee9c257..afa323869a 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -870,6 +870,7 @@ foreach my $lib (@modules_to_sync) { my $modulepri = $modulepris{$lib}; if (-e $modulepri) { my $modulepriname = basename($modulepri); + # FIXME: this creates a file in the source location for shadow-builds my $moduleversionheader = "$modules{$lib}/" . lc($lib) . "version.h"; my $modulehexstring = sprintf("0x%02X%02X%02X", int($module_major_version), int($module_minor_version), int($module_patch_version)); open MODULE_VERSION_HEADER_FILE, ">$moduleversionheader"; @@ -882,6 +883,8 @@ foreach my $lib (@modules_to_sync) { print MODULE_VERSION_HEADER_FILE "#define " .uc($lib) . "_VERSION $modulehexstring\n", ; print MODULE_VERSION_HEADER_FILE "\n"; print MODULE_VERSION_HEADER_FILE "#endif // QT_". uc($lib) . "_VERSION_H\n"; + close MODULE_VERSION_HEADER_FILE; + print "$moduleversionheader created for $lib\n" if(!$quiet); } elsif ($modulepri) { print "WARNING: Module $lib\'s pri file '$modulepri' not found.\nSkipped creating module version header for $lib.\n"; } From e37376dbb47c01e2a3f96ce9126c441d3aae2724 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Thu, 7 Jul 2011 18:05:49 +0000 Subject: [PATCH 14/75] Make syncqt output more compact by default, and add verbosity level By default, syncqt will now compress the console output of what it's doing. Increasing the verbosity level will make syncqt output the same as before Change-Id: I542072504f022f87997b4036eda5747a5da88839 Reviewed-on: http://codereview.qt.nokia.com/1764 Reviewed-by: Qt Sanity Bot Reviewed-by: Oswald Buddenhagen --- bin/syncqt | 66 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/bin/syncqt b/bin/syncqt index afa323869a..405f2757cf 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -38,7 +38,7 @@ our (%modules, %moduleheaders, %classnames, %mastercontent, %modulepris); my $isunix = 0; my $module = 0; my $showonly = 0; -my $quiet = 0; +my $verbose_level = 1; my $remove_stale = 1; my $force_win = 0; my $force_relative = 0; @@ -75,7 +75,9 @@ sub showUsage print " -showonly Show action but not perform (default: " . ($showonly ? "yes" : "no") . ")\n"; print " -outdir Specify output directory for sync (default: $out_basedir)\n"; print " -qtdir Set the path to QtBase (detected: " . (defined $qtbasedir ? $qtbasedir : "-none-") . ")\n"; - print " -quiet Only report problems, not activity (default: " . ($quiet ? "yes" : "no") . ")\n"; + print " -quiet Only report problems, not activity (same as -verbose 0)\n"; + print " -v, -verbose Sets the verbosity level (max. 4) (default: $verbose_level)\n"; + print " The short form increases the level by +1\n"; print " -separate-module ::\n"; print " Create headers for with original headers in\n"; print " relative to \n"; @@ -479,9 +481,9 @@ sub symlinkFile $t =~ s-^$quoted_basedir/--; $p .= "../" while( ($c = index( $t, "/", $c + 1)) != -1 ); $file =~ s-^$quoted_basedir/-$p-; - print " ($file)\n" unless $quiet; + print " ($file)\n" if($verbose_level); } - print "\n" unless $quiet; + print "\n" if($verbose_level); return symlink($file, $ifile); } return copyFile($file, $ifile); @@ -534,8 +536,10 @@ sub findFiles { ###################################################################### sub loadSyncProfile { my ($srcbase, $outbase) = @_; - print("srcbase = $$srcbase \n"); - print("outbase = $$outbase \n"); + if ($verbose_level) { + print(" = $$srcbase \n"); + print(" = $$outbase \n"); + } my $syncprofile = "$$srcbase/sync.profile"; my $result; @@ -627,8 +631,14 @@ while ( @ARGV ) { $var = "showonly"; $val = "yes"; } elsif($arg eq "-quiet") { - $var = "quiet"; + $var = "verbose"; + $val = "0"; + } elsif($arg eq "-v") { + $var = "verbose"; $val = "yes"; + } elsif($arg eq "-verbose") { + $var = "verbose"; + $val = shift @ARGV; } elsif($arg eq "-private") { $var = "create_private_headers"; $val = "yes"; @@ -667,11 +677,13 @@ while ( @ARGV ) { } elsif($showonly) { $showonly--; } - } elsif ($var eq "quiet") { + } elsif ($var eq "verbose") { if($val eq "yes") { - $quiet++; - } elsif($quiet) { - $quiet--; + $verbose_level++; + } elsif($val eq "no" && $verbose_level) { + $verbose_level--; + } else { + $verbose_level = int($val); } } elsif ($var eq "check-includes") { if($val eq "yes") { @@ -698,7 +710,7 @@ while ( @ARGV ) { $force_relative--; } } elsif ($var eq "module") { - print "module :$val:\n" unless $quiet; + print "module :$val:\n" if($verbose_level); die "No such module: $val" unless(defined $modules{$val}); push @modules_to_sync, $val; } elsif ($var eq "separate-module") { @@ -766,9 +778,7 @@ loadSyncProfile(\$basedir, \$out_basedir); $isunix = checkUnix; #cache checkUnix # create path -mkpath "$out_basedir/include", !$quiet; -mkpath "$out_basedir/include/Qt", !$quiet; - +make_path("$out_basedir/include/Qt", "", $verbose_level); foreach my $lib (@modules_to_sync) { #iteration info @@ -884,7 +894,8 @@ foreach my $lib (@modules_to_sync) { print MODULE_VERSION_HEADER_FILE "\n"; print MODULE_VERSION_HEADER_FILE "#endif // QT_". uc($lib) . "_VERSION_H\n"; close MODULE_VERSION_HEADER_FILE; - print "$moduleversionheader created for $lib\n" if(!$quiet); + $moduleversionheader = "" . substr($moduleversionheader, length($basedir)) if ($verbose_level < 2); + print "$moduleversionheader created for $lib\n" if($verbose_level); } elsif ($modulepri) { print "WARNING: Module $lib\'s pri file '$modulepri' not found.\nSkipped creating module version header for $lib.\n"; } @@ -916,6 +927,7 @@ foreach my $lib (@modules_to_sync) { push @headers, "*".$if; } } + my $header_dirname = ""; foreach my $header (@headers) { my $shadow = ($header =~ s/^\*//); $header = 0 if($header =~ /^ui_.*.h/); @@ -1026,9 +1038,29 @@ foreach my $lib (@modules_to_sync) { $pri_install_pfiles.= "$pri_install_iheader ";; } } - print "header created for $iheader ($header_copies)\n" if($header_copies > 0 && !$quiet); + + if ($verbose_level && $header_copies) { + my $new_header_dirname = dirname($iheader); + $new_header_dirname = "" . substr($new_header_dirname, length($basedir)) if ($new_header_dirname && $verbose_level < 2); + my $header_base = basename($iheader); + if ($verbose_level < 3) { + my $line_prefix = ","; + if ($new_header_dirname ne $header_dirname) { + $line_prefix = "created header(s) for $new_header_dirname/ {"; + $line_prefix = " }\n".$line_prefix if ($header_dirname); + $header_dirname = $new_header_dirname; + } else { + $line_prefix = ","; + } + print "$line_prefix $header_base ($header_copies)"; + } else { # $verbose_level >= 3 + $iheader = "" . substr($iheader, length($basedir)) if ($verbose_level == 3); + print "header created for $iheader ($header_copies)\n"; + } + } } } + print " }\n" if ($header_dirname && $verbose_level > 0 && $verbose_level < 3); } } From d83689ca6d80fb20748ca5507bd223a3c296f768 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Thu, 7 Jul 2011 18:48:02 +0000 Subject: [PATCH 15/75] Prefix each output line with the library being processed Makes it easier to track which library output is coming from, when building Qt with -j > 1. Change-Id: I9acda04e84014dc441e409a0b24b2f78762dcc1c Reviewed-on: http://codereview.qt.nokia.com/1765 Reviewed-by: Qt Sanity Bot Reviewed-by: Joerg Bornemann --- bin/syncqt | 69 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/bin/syncqt b/bin/syncqt index 405f2757cf..691f09139c 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -275,6 +275,15 @@ sub classNames { return @ret; } +sub make_path { + my ($dir, $lib, $be_verbose) = @_; + unless(-e $dir) { + mkpath $dir; + $dir = "" . substr($dir, length($out_basedir)) if ($be_verbose < 3); + print "$lib: mkpath $dir\n" if ($be_verbose > 1); + } +} + ###################################################################### # Syntax: syncHeader(header, iheader, copy, timestamp) # Params: header, string, filename to create "symlink" for @@ -286,14 +295,14 @@ sub classNames { # Returns: 1 if successful, else 0. ###################################################################### sub syncHeader { - my ($header, $iheader, $copy, $ts) = @_; + my ($lib, $header, $iheader, $copy, $ts) = @_; $iheader =~ s=\\=/=g; $header =~ s=\\=/=g; - return copyFile($iheader, $header) if($copy); + return copyFile($lib, $iheader, $header) if($copy); unless(-e $header) { my $header_dir = dirname($header); - mkpath $header_dir, !$quiet; + make_path($header_dir, $lib, $verbose_level); #write it my $iheader_out = fixPaths($iheader, $header_dir); @@ -414,7 +423,7 @@ sub fileCompare { ###################################################################### sub copyFile { - my ($file,$ifile, $copy,$knowdiff,$filecontents,$ifilecontents) = @_; + my ($lib, $file,$ifile, $copy,$knowdiff,$filecontents,$ifilecontents) = @_; # Bi-directional synchronization open( I, "< " . $file ) || die "Could not open $file for reading"; local $/; @@ -436,7 +445,7 @@ sub copyFile if ( $knowdiff || ($filecontents ne $ifilecontents) ) { if ( $copy > 0 ) { my $file_dir = dirname($file); - mkpath $file_dir, !$quiet unless(-e $file_dir); + make_path($file_dir, $lib, $verbose_level); open(O, "> " . $file) || die "Could not open $file for writing (no write permission?)"; local $/; binmode O; @@ -446,7 +455,7 @@ sub copyFile return 1; } elsif ( $copy < 0 ) { my $ifile_dir = dirname($ifile); - mkpath $ifile_dir, !$quiet unless(-e $ifile_dir); + make_path($ifile_dir, $lib, $verbose_level); open(O, "> " . $ifile) || die "Could not open $ifile for writing (no write permission?)"; local $/; binmode O; @@ -470,10 +479,10 @@ sub copyFile ###################################################################### sub symlinkFile { - my ($file,$ifile) = @_; + my ($lib, $file, $ifile) = @_; if ($isunix) { - print "symlink created for $file " unless $quiet; + print "$lib: symlink created for $file " if ($verbose_level); if ( $force_relative && ($ifile =~ /^$quoted_basedir/)) { my $t = getcwd(); my $c = -1; @@ -486,7 +495,7 @@ sub symlinkFile print "\n" if($verbose_level); return symlink($file, $ifile); } - return copyFile($file, $ifile); + return copyFile($lib, $file, $ifile); } ###################################################################### @@ -806,7 +815,7 @@ foreach my $lib (@modules_to_sync) { chomp $module_patch_version; } } - print "WARNING: Module $lib\'s pri missing QT..VERSION variable! Private headers not versioned!\n" if (!$module_version); + print "$lib: WARNING: Module\'s pri missing QT..VERSION variable! Private headers not versioned!\n" if (!$module_version); my $pathtoheaders = ""; $pathtoheaders = $moduleheaders{$lib} if ($moduleheaders{$lib}); @@ -895,9 +904,9 @@ foreach my $lib (@modules_to_sync) { print MODULE_VERSION_HEADER_FILE "#endif // QT_". uc($lib) . "_VERSION_H\n"; close MODULE_VERSION_HEADER_FILE; $moduleversionheader = "" . substr($moduleversionheader, length($basedir)) if ($verbose_level < 2); - print "$moduleversionheader created for $lib\n" if($verbose_level); + print "$lib: created version header $moduleversionheader\n" if($verbose_level); } elsif ($modulepri) { - print "WARNING: Module $lib\'s pri file '$modulepri' not found.\nSkipped creating module version header for $lib.\n"; + print "$lib: WARNING: Module\'s pri file '$modulepri' not found.\n$lib: Skipped creating module version header.\n"; } } @@ -994,11 +1003,11 @@ foreach my $lib (@modules_to_sync) { # class =~ s,::,/,g; # } $class_lib_map_contents .= "QT_CLASS_LIB($full_class, $lib, $header_base)\n"; - $header_copies++ if(syncHeader("$out_basedir/include/$lib/$class", "$out_basedir/include/$lib/$header", 0, $ts)); + $header_copies++ if(syncHeader($lib, "$out_basedir/include/$lib/$class", "$out_basedir/include/$lib/$header", 0, $ts)); # KDE-Compat headers for Phonon if ($lib eq "phonon") { - $header_copies++ if (syncHeader("$out_basedir/include/phonon_compat/Phonon/$class", "$out_basedir/include/$lib/$header", 0, $ts)); + $header_copies++ if (syncHeader($lib, "$out_basedir/include/phonon_compat/Phonon/$class", "$out_basedir/include/$lib/$header", 0, $ts)); } } } elsif ($create_private_headers) { @@ -1009,7 +1018,7 @@ foreach my $lib (@modules_to_sync) { } } foreach(@headers) { #sync them - $header_copies++ if(syncHeader($_, $iheader, $copy_headers && !$shadow, $ts)); + $header_copies++ if(syncHeader($lib, $_, $iheader, $copy_headers && !$shadow, $ts)); } if($public_header) { @@ -1046,7 +1055,7 @@ foreach my $lib (@modules_to_sync) { if ($verbose_level < 3) { my $line_prefix = ","; if ($new_header_dirname ne $header_dirname) { - $line_prefix = "created header(s) for $new_header_dirname/ {"; + $line_prefix = "$lib: created fwd-include header(s) for $new_header_dirname/ {"; $line_prefix = " }\n".$line_prefix if ($header_dirname); $header_dirname = $new_header_dirname; } else { @@ -1055,7 +1064,7 @@ foreach my $lib (@modules_to_sync) { print "$line_prefix $header_base ($header_copies)"; } else { # $verbose_level >= 3 $iheader = "" . substr($iheader, length($basedir)) if ($verbose_level == 3); - print "header created for $iheader ($header_copies)\n"; + print "$lib: created $header_copies fwd-include headers for $iheader\n"; } } } @@ -1086,11 +1095,11 @@ foreach my $lib (@modules_to_sync) { } if($master_include && $master_contents) { my $master_dir = dirname($master_include); - mkpath $master_dir, !$quiet; - print "header (master) created for $lib\n" unless $quiet; + make_path($master_dir, $lib, $verbose_level); open MASTERINCLUDE, ">$master_include"; print MASTERINCLUDE $master_contents; close MASTERINCLUDE; + print "$lib: created header (master) file\n" if($verbose_level); } } @@ -1111,11 +1120,11 @@ foreach my $lib (@modules_to_sync) { } if($headers_pri_file && $master_contents) { my $headers_pri_dir = dirname($headers_pri_file); - mkpath $headers_pri_dir, !$quiet; - print "headers.pri file created for $lib\n" unless $quiet; + make_path($headers_pri_dir, $lib, $verbose_level); open HEADERS_PRI_FILE, ">$headers_pri_file"; print HEADERS_PRI_FILE $headers_pri_contents; close HEADERS_PRI_FILE; + print "$lib: created headers.pri file\n" if($verbose_level); } # create forwarding module pri in qtbase/mkspecs/modules @@ -1123,7 +1132,7 @@ foreach my $lib (@modules_to_sync) { my $modulepri = $modulepris{$lib}; if (-e $modulepri) { my $modulepriname = basename($modulepri); - mkpath($module_fwd); + make_path($module_fwd, $lib, $verbose_level); my $moduleprifwd = "$module_fwd/$modulepriname"; my $mod_base = $developer_build ? $basedir : $out_basedir; my $mod_component_base = $developer_build ? $qtbasedir : $out_basedir; @@ -1149,7 +1158,7 @@ foreach my $lib (@modules_to_sync) { } } } elsif ($modulepri) { - print "WARNING: Module $lib\'s pri file '$modulepri' not found.\nSkipped creating forwarding pri for $lib.\n"; + print "$lib: WARNING: Module\'s pri file '$modulepri' not found.\n$lib: Skipped creating forwarding pri.\n"; } } } @@ -1167,7 +1176,7 @@ unless($showonly || !$create_uic_class_map) { } if($class_lib_map) { my $class_lib_map_dir = dirname($class_lib_map); - mkpath $class_lib_map_dir, !$quiet; + make_path($class_lib_map_dir, "", $verbose_level); open CLASS_LIB_MAP, ">$class_lib_map"; print CLASS_LIB_MAP $class_lib_map_contents; close CLASS_LIB_MAP; @@ -1251,7 +1260,7 @@ if($check_includes) { if($include) { for my $trylib (keys(%modules)) { if(-e "$out_basedir/include/$trylib/$include") { - print "WARNING: $iheader includes $include when it should include $trylib/$include\n"; + print "$lib: WARNING: $iheader includes $include when it should include $trylib/$include\n"; } } } @@ -1269,27 +1278,27 @@ if($check_includes) { } if ($header_skip_qt_begin_header_test == 0) { if ($qt_begin_header_found == 0) { - print "WARNING: $iheader does not include QT_BEGIN_HEADER\n"; + print "$lib: WARNING: $iheader does not include QT_BEGIN_HEADER\n"; } if ($qt_begin_header_found && $qt_end_header_found == 0) { - print "WARNING: $iheader has QT_BEGIN_HEADER but no QT_END_HEADER\n"; + print "$lib: WARNING: $iheader has QT_BEGIN_HEADER but no QT_END_HEADER\n"; } } if ($header_skip_qt_begin_namespace_test == 0) { if ($qt_begin_namespace_found == 0) { - print "WARNING: $iheader does not include QT_BEGIN_NAMESPACE\n"; + print "$lib: WARNING: $iheader does not include QT_BEGIN_NAMESPACE\n"; } if ($qt_begin_namespace_found && $qt_end_namespace_found == 0) { - print "WARNING: $iheader has QT_BEGIN_NAMESPACE but no QT_END_NAMESPACE\n"; + print "$lib: WARNING: $iheader has QT_BEGIN_NAMESPACE but no QT_END_NAMESPACE\n"; } } if ($header_skip_qt_module_test == 0) { if ($qt_module_found == 0) { - print "WARNING: $iheader does not include QT_MODULE\n"; + print "$lib: WARNING: $iheader does not include QT_MODULE\n"; } } close(F); From 2a4ab8590587a8a39d3b2133df3d989f1d844404 Mon Sep 17 00:00:00 2001 From: Sergio Ahumada Date: Thu, 21 Jul 2011 21:04:32 +0200 Subject: [PATCH 16/75] test: unmark tst_QNetworkAddressEntry::prefixAndNetmask as "insignificant" It was fixed by cfbdb4cc8a3a1f9e0036ec387cbc00d2058ee6e7 Change-Id: I2cd1216235c77c6f2521a6d899e81e7e442758cd Reviewed-on: http://codereview.qt.nokia.com/1997 Reviewed-by: Qt Sanity Bot Reviewed-by: Sergio Ahumada --- tests/auto/qnetworkaddressentry/qnetworkaddressentry.pro | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/auto/qnetworkaddressentry/qnetworkaddressentry.pro b/tests/auto/qnetworkaddressentry/qnetworkaddressentry.pro index 7b968723cd..885dbf796c 100644 --- a/tests/auto/qnetworkaddressentry/qnetworkaddressentry.pro +++ b/tests/auto/qnetworkaddressentry/qnetworkaddressentry.pro @@ -4,5 +4,3 @@ SOURCES += tst_qnetworkaddressentry.cpp QT = core network symbian: TARGET.CAPABILITY = NetworkServices - -CONFIG+=insignificant_test From 038d7c6c3b9815068e1f5b6df12625181f0313e1 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 21 Jul 2011 17:10:30 +0200 Subject: [PATCH 17/75] Fix the timeout calculation again. The commit 412ef92162f8874a1585221125c31ef5f8ccc9cb introduced a fix, but the fix was incomplete. Fix it for good. Change-Id: I3e7fbdb294f8e960fbbf2e830790750240ed813a Merge-request: 30 Reviewed-by: Olivier Goffart Reviewed-on: http://codereview.qt.nokia.com/1991 Reviewed-by: Qt Sanity Bot --- src/corelib/thread/qmutex_unix.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index e692e19525..2a9d23c361 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -161,8 +161,8 @@ bool QMutexPrivate::wait(int timeout) return false; } - ts.tv_sec = timeout / Q_INT64_C(1000) / 1000 / 1000; - ts.tv_nsec = timeout % (Q_INT64_C(1000) * 1000 * 1000); + ts.tv_sec = xtimeout / Q_INT64_C(1000) / 1000 / 1000; + ts.tv_nsec = xtimeout % (Q_INT64_C(1000) * 1000 * 1000); } } return true; From 26a996b2ebc2ff80a087bd21c558601101a7a015 Mon Sep 17 00:00:00 2001 From: David Faure Date: Thu, 21 Jul 2011 16:56:56 +0200 Subject: [PATCH 18/75] Silence expected warnings from QObject::connect()/disconnect() Merge-request: 4 Reviewed-by: Olivier Goffart Change-Id: Ibee937140d0d81377c6adf74fce7856c4655b924 Reviewed-on: http://codereview.qt.nokia.com/1990 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- tests/auto/qglobal/tst_qglobal.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/qglobal/tst_qglobal.cpp b/tests/auto/qglobal/tst_qglobal.cpp index 841151efc4..19a13f6ad0 100644 --- a/tests/auto/qglobal/tst_qglobal.cpp +++ b/tests/auto/qglobal/tst_qglobal.cpp @@ -130,10 +130,12 @@ void tst_QGlobal::qInternalCallbacks() QInternal::unregisterCallback(QInternal::DisconnectCallback, disconnect_callback); connect_info.reset(); + QTest::ignoreMessage(QtWarningMsg, "Object::connect: No such signal QObject::mysignal(x)"); ok = QObject::connect(&a, signal.toLatin1(), &b, slot.toLatin1(), Qt::AutoConnection); QVERIFY(!ok); QCOMPARE(connect_info.sender, (QObject *) 0); + QTest::ignoreMessage(QtWarningMsg, "Object::disconnect: No such signal QObject::mysignal(x)"); ok = QObject::disconnect(&a, signal.toLatin1(), &b, slot.toLatin1()); QVERIFY(!ok); QCOMPARE(connect_info.sender, (QObject *) 0); From a6d87b51141e362f39e323bf329491d27565b137 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 21 Jul 2011 16:33:40 +0200 Subject: [PATCH 19/75] Add unit tests to QStringLiteral and QByteArrayLiteral with operator % This requires a fix for QByteArrayLiteral to work too. Change-Id: I3c2a50ad431d5b0c014a341e675fa54e7b206e70 Merge-request: 27 Reviewed-by: Olivier Goffart Reviewed-on: http://codereview.qt.nokia.com/1967 Reviewed-by: Qt Sanity Bot --- src/corelib/tools/qstringbuilder.h | 21 +++++++++ tests/auto/qstringbuilder1/stringbuilder.cpp | 47 ++++++++++++++++---- 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h index 6d998b62aa..63c487ef56 100644 --- a/src/corelib/tools/qstringbuilder.h +++ b/src/corelib/tools/qstringbuilder.h @@ -364,6 +364,27 @@ template <> struct QConcatenable : private QAbstractConcatenable } }; +template struct QConcatenable > : private QAbstractConcatenable +{ + typedef QConstByteArrayDataPtr type; + typedef QByteArray ConvertTo; + enum { ExactSize = false }; + static int size(const type &) { return N; } +#ifndef QT_NO_CAST_FROM_ASCII + static inline QT_ASCII_CAST_WARN void appendTo(const type &a, QChar *&out) + { + // adding 1 because convertFromAscii expects the size including the null-termination + QAbstractConcatenable::convertFromAscii(a.ptr->data, N + 1, out); + } +#endif + static inline void appendTo(const type &ba, char *&out) + { + const char *a = ba.ptr->data; + while (*a) + *out++ = *a++; + } +}; + namespace QtStringBuilder { template struct ConvertToTypeHelper { typedef A ConvertTo; }; diff --git a/tests/auto/qstringbuilder1/stringbuilder.cpp b/tests/auto/qstringbuilder1/stringbuilder.cpp index de7ad656e4..4d453b0585 100644 --- a/tests/auto/qstringbuilder1/stringbuilder.cpp +++ b/tests/auto/qstringbuilder1/stringbuilder.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#include + #define LITERAL "some literal" #define LITERAL_LEN (sizeof(LITERAL)-1) #define LITERAL_EXTRA "some literal" "EXTRA" @@ -48,6 +50,12 @@ #define UTF8_LITERAL_LEN (sizeof(UTF8_LITERAL)-1) #define UTF8_LITERAL_EXTRA "s\xc3\xb6m\xc3\xab l\xc3\xaft\xc3\xabr\xc3\xa4l" "EXTRA" +#ifdef Q_COMPILER_UNICODE_STRINGS +// "some literal", but replacing all vocals by their umlauted UTF-8 string :) +#define UNICODE_LITERAL u"s\u00f6m\u00eb l\u00eft\u00ebr\u00e4l" +#define UNICODE_LITERAL_LEN ((sizeof(UNICODE_LITERAL) - 1) / 2) +#define UNICODE_LITERAL_EXTRA u"s\u00f6m\u00eb l\u00eft\u00ebr\u00e4l" "EXTRA" +#endif //fix for gcc4.0: if the operator+ does not exist without QT_USE_FAST_OPERATOR_PLUS #ifndef QT_USE_FAST_CONCATENATION @@ -68,6 +76,7 @@ void runScenario() QStringRef stringref(&string, 2, 10); QLatin1Char achar('c'); QString r2(QLatin1String(LITERAL LITERAL)); + QString r3 = QString::fromUtf8(UTF8_LITERAL UTF8_LITERAL); QString r; r = l1literal Q l1literal; @@ -80,10 +89,23 @@ void runScenario() QCOMPARE(r, r2); r = string P l1string; QCOMPARE(r, r2); + r = string Q QStringLiteral(LITERAL); + QCOMPARE(r, r2); + r = QStringLiteral(LITERAL) Q string; + QCOMPARE(r, r2); + r = l1string Q QStringLiteral(LITERAL); + QCOMPARE(r, r2); r = string + achar; QCOMPARE(r, QString(string P achar)); r = achar + string; QCOMPARE(r, QString(achar P string)); + +#ifdef Q_COMPILER_UNICODE_STRINGS + r = QStringLiteral(UNICODE_LITERAL); + r = r Q QStringLiteral(UNICODE_LITERAL); + QCOMPARE(r, r3); +#endif + #ifndef QT_NO_CAST_FROM_ASCII r = string P LITERAL; QCOMPARE(r, r2); @@ -96,6 +118,11 @@ void runScenario() r = string P ba; QCOMPARE(r, r2); + r = string P QByteArrayLiteral(LITERAL); + QCOMPARE(r, r2); + r = QByteArrayLiteral(LITERAL) P string; + QCOMPARE(r, r2); + static const char badata[] = LITERAL_EXTRA; ba = QByteArray::fromRawData(badata, LITERAL_LEN); r = ba P string; @@ -109,24 +136,23 @@ void runScenario() QCOMPARE(QTextCodec::codecForCStrings()->name(), QByteArray("UTF-8")); string = QString::fromUtf8(UTF8_LITERAL); - r2 = QString::fromUtf8(UTF8_LITERAL UTF8_LITERAL); ba = UTF8_LITERAL; r = string P UTF8_LITERAL; - QCOMPARE(r.size(), r2.size()); - QCOMPARE(r, r2); + QCOMPARE(r.size(), r3.size()); + QCOMPARE(r, r3); r = UTF8_LITERAL P string; - QCOMPARE(r, r2); + QCOMPARE(r, r3); r = ba P string; - QCOMPARE(r, r2); + QCOMPARE(r, r3); r = string P ba; - QCOMPARE(r, r2); + QCOMPARE(r, r3); ba = QByteArray::fromRawData(UTF8_LITERAL_EXTRA, UTF8_LITERAL_LEN); r = ba P string; - QCOMPARE(r, r2); + QCOMPARE(r, r3); r = string P ba; - QCOMPARE(r, r2); + QCOMPARE(r, r3); ba = QByteArray(); // empty r = ba P string; @@ -152,6 +178,11 @@ void runScenario() QByteArray superba = ba P ba P LITERAL; QCOMPARE(superba, QByteArray(LITERAL LITERAL LITERAL)); + ba = QByteArrayLiteral(LITERAL); + QCOMPARE(ba, QByteArray(LITERAL)); + superba = ba P QByteArrayLiteral(LITERAL) P LITERAL; + QCOMPARE(superba, QByteArray(LITERAL LITERAL LITERAL)); + QByteArray testWith0 = ba P "test\0with\0zero" P ba; QCOMPARE(testWith0, QByteArray(LITERAL "test" LITERAL)); From 345a8a67f0a8a1ddb9ed26ec2a12b20728c741da Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Fri, 22 Jul 2011 11:02:19 +1000 Subject: [PATCH 20/75] Optimize QMetaObject::property(). Avoid using QByteArray. Change-Id: I7216bc88efdd6e4e57d84b8c45e7c38119dc7092 Reviewed-on: http://codereview.qt.nokia.com/2000 Reviewed-by: Qt Sanity Bot Reviewed-by: Michael Goddard --- src/corelib/kernel/qmetaobject.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index c8ac15c1fa..b6de002cf4 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -859,20 +859,31 @@ QMetaProperty QMetaObject::property(int index) const if (flags & EnumOrFlag) { result.menum = enumerator(indexOfEnumerator(type)); if (!result.menum.isValid()) { - QByteArray enum_name = type; - QByteArray scope_name = d.stringdata; - int s = enum_name.lastIndexOf("::"); - if (s > 0) { - scope_name = enum_name.left(s); - enum_name = enum_name.mid(s + 2); + const char *enum_name = type; + const char *scope_name = d.stringdata; + char *scope_buffer = 0; + + const char *colon = strrchr(enum_name, ':'); + // ':' will always appear in pairs + Q_ASSERT(colon <= enum_name || *(colon-1) == ':'); + if (colon > enum_name) { + int len = colon-enum_name-1; + scope_buffer = (char *)qMalloc(len+1); + qMemCopy(scope_buffer, enum_name, len); + scope_buffer[len] = '\0'; + scope_name = scope_buffer; + enum_name = colon+1; } + const QMetaObject *scope = 0; - if (scope_name == "Qt") + if (qstrcmp(scope_name, "Qt") == 0) scope = &QObject::staticQtMetaObject; else scope = QMetaObject_findMetaObject(this, scope_name); if (scope) result.menum = scope->enumerator(scope->indexOfEnumerator(enum_name)); + if (scope_buffer) + qFree(scope_buffer); } } } From 769f5223425e24d4305c94482580970dea1e63c8 Mon Sep 17 00:00:00 2001 From: Ritt Konstantin Date: Thu, 21 Jul 2011 10:20:06 +0200 Subject: [PATCH 21/75] remove Qt3 leftovers Merge-request: 22 Reviewed-by: Olivier Goffart Change-Id: I5d25fb05894d9baa645f97946e1f9aaa1622c876 Reviewed-on: http://codereview.qt.nokia.com/1925 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/tools/qchar.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp index 00261daa95..736bc63b11 100644 --- a/src/corelib/tools/qchar.cpp +++ b/src/corelib/tools/qchar.cpp @@ -317,8 +317,6 @@ QT_BEGIN_NAMESPACE \value Vertical \value Wide - \omitvalue Single - \sa decomposition() */ @@ -382,12 +380,6 @@ QT_BEGIN_NAMESPACE \value ByteOrderSwapped \value ParagraphSeparator \value LineSeparator - - \omitvalue null - \omitvalue replacement - \omitvalue byteOrderMark - \omitvalue byteOrderSwapped - \omitvalue nbsp */ /*! @@ -957,7 +949,7 @@ QString QChar::decomposition(uint ucs4) /*! Returns the tag defining the composition of the character. Returns - QChar::Single if no decomposition exists. + QChar::NoDecomposition if no decomposition exists. */ QChar::Decomposition QChar::decompositionTag() const { @@ -967,7 +959,7 @@ QChar::Decomposition QChar::decompositionTag() const /*! \overload Returns the tag defining the composition of the UCS-4-encoded character - specified by \a ucs4. Returns QChar::Single if no decomposition exists. + specified by \a ucs4. Returns QChar::NoDecomposition if no decomposition exists. */ QChar::Decomposition QChar::decompositionTag(uint ucs4) { @@ -1232,7 +1224,6 @@ ushort QChar::toCaseFolded(ushort ucs2) return ucs2 + qGetProp(ucs2)->caseFoldDiff; } - /*! \fn char QChar::toLatin1() const From 7fc3203062f27f582de84420fa0b519c58b5d1ff Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 21 Jul 2011 16:39:55 +0200 Subject: [PATCH 22/75] QAbstractConcatenable::convertFromAscii: make len the actual length Before, it was the length + 1, to include the ending \0 (for historical reasons) Having it the actual length is more intuitive and less error prone Also added QT_ASCII_CAST_WARN to QConcatenable::appendTo to show the warnig that convertion from ascii to qstring occurs. Change-Id: Ie7c8552b6b4e7ccb393cb09f5f0ca9b00336c714 Reviewed-by: thiago Reviewed-on: http://codereview.qt.nokia.com/1988 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/tools/qstringbuilder.cpp | 5 ++--- src/corelib/tools/qstringbuilder.h | 12 +++++------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/corelib/tools/qstringbuilder.cpp b/src/corelib/tools/qstringbuilder.cpp index 4c6848498b..7c1bde4ac7 100644 --- a/src/corelib/tools/qstringbuilder.cpp +++ b/src/corelib/tools/qstringbuilder.cpp @@ -108,13 +108,12 @@ QT_BEGIN_NAMESPACE */ /*! \internal - Note: The len contains the ending \0 */ void QAbstractConcatenable::convertFromAscii(const char *a, int len, QChar *&out) { #ifndef QT_NO_TEXTCODEC if (QString::codecForCStrings && len) { - QString tmp = QString::fromAscii(a, len > 0 ? len - 1 : -1); + QString tmp = QString::fromAscii(a, len > 0 ? len : -1); memcpy(out, reinterpret_cast(tmp.constData()), sizeof(QChar) * tmp.size()); out += tmp.length(); return; @@ -126,7 +125,7 @@ void QAbstractConcatenable::convertFromAscii(const char *a, int len, QChar *&out while (*a) *out++ = QLatin1Char(*a++); } else { - for (int i = 0; i < len - 1; ++i) + for (int i = 0; i < len; ++i) *out++ = QLatin1Char(a[i]); } } diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h index 63c487ef56..30b81c42f4 100644 --- a/src/corelib/tools/qstringbuilder.h +++ b/src/corelib/tools/qstringbuilder.h @@ -294,7 +294,7 @@ template struct QConcatenable : private QAbstractConcatenable #ifndef QT_NO_CAST_FROM_ASCII static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out) { - QAbstractConcatenable::convertFromAscii(a, N, out); + QAbstractConcatenable::convertFromAscii(a, N - 1, out); } #endif static inline void appendTo(const char a[N], char *&out) @@ -313,7 +313,7 @@ template struct QConcatenable : private QAbstractConcaten #ifndef QT_NO_CAST_FROM_ASCII static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out) { - QAbstractConcatenable::convertFromAscii(a, N, out); + QAbstractConcatenable::convertFromAscii(a, N - 1, out); } #endif static inline void appendTo(const char a[N], char *&out) @@ -349,10 +349,9 @@ template <> struct QConcatenable : private QAbstractConcatenable enum { ExactSize = false }; static int size(const QByteArray &ba) { return ba.size(); } #ifndef QT_NO_CAST_FROM_ASCII - static inline void appendTo(const QByteArray &ba, QChar *&out) + static inline QT_ASCII_CAST_WARN void appendTo(const QByteArray &ba, QChar *&out) { - // adding 1 because convertFromAscii expects the size including the null-termination - QAbstractConcatenable::convertFromAscii(ba.constData(), ba.size() + 1, out); + QAbstractConcatenable::convertFromAscii(ba.constData(), ba.size(), out); } #endif static inline void appendTo(const QByteArray &ba, char *&out) @@ -373,8 +372,7 @@ template struct QConcatenable > : private QAbs #ifndef QT_NO_CAST_FROM_ASCII static inline QT_ASCII_CAST_WARN void appendTo(const type &a, QChar *&out) { - // adding 1 because convertFromAscii expects the size including the null-termination - QAbstractConcatenable::convertFromAscii(a.ptr->data, N + 1, out); + QAbstractConcatenable::convertFromAscii(a.ptr->data, N, out); } #endif static inline void appendTo(const type &ba, char *&out) From 997b2a96c1aec1c7f35cd2228eba907f29a28f25 Mon Sep 17 00:00:00 2001 From: Michael Goddard Date: Thu, 30 Jun 2011 14:51:16 +1000 Subject: [PATCH 23/75] Add rudimentary config.test support when configuring modules. An extra script is added (qtmodule-configtests) which is currently invoked from syncqt (with some derived parameters passed to it). The module can optionally have an entry in the module's sync.profile file in the form of a perl map of "test name" => parameters. Tests can print an advisory message if they fail (e.g. "Install this SDK/dev package"), or abort the syncqt process (e.g. mandatory prereq missing). Also, if the test has a "requires(foo)" line that results in it being skipped, this is also supported. Change-Id: Ic3c820a488a0992c944994d4d7dc283da36742d6 Reviewed-on: http://codereview.qt.nokia.com/928 Reviewed-by: Qt Sanity Bot Reviewed-by: Sarah Jane Smith Reviewed-by: Marius Storm-Olsen --- bin/qtmodule-configtests | 337 +++++++++++++++++++++++++++++++ bin/syncqt | 17 ++ mkspecs/features/default_pre.prf | 2 +- 3 files changed, 355 insertions(+), 1 deletion(-) create mode 100755 bin/qtmodule-configtests diff --git a/bin/qtmodule-configtests b/bin/qtmodule-configtests new file mode 100755 index 0000000000..a5c5899cc5 --- /dev/null +++ b/bin/qtmodule-configtests @@ -0,0 +1,337 @@ +#!/usr/bin/perl +###################################################################### +# +# Runs any module configuration tests +# +# Called (currently) from syncqt, and expects a few arguments +# +# configtests $basedir $out_basedir $qtbasedir $quietmode +# +# Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +# Contact: Nokia Corporation (qt-info@nokia.com) +# +###################################################################### + +use strict; +use warnings; + +# use packages ------------------------------------------------------- +use File::Basename; +use File::Path 'mkpath'; +use File::Spec::Functions; +use Cwd; +use Cwd 'abs_path'; +use Config; + +# Which file to look for the %configtests variable in +my $configTestSource = "sync.profile"; + +if ($#ARGV < 3) { + warn "Usage:\n"; + warn " $0 \n"; + exit 1; +} + +# These might be needed in sync.profile +our $basedir = $ARGV[0]; +our $out_basedir = $ARGV[1]; +our $qtbasedir = $ARGV[2]; +my $generator = $ARGV[3]; + +our %configtests; + +my $qmakeCachePath = catfile($out_basedir, ".qmake.cache"); + +my $QMAKE = catfile($qtbasedir, "bin", ($^O =~ /win32/i) ? 'qmake.exe' : 'qmake'); +if (!-x $QMAKE) { + # try the qmake from the path (e.g. this is a shadow build) + $QMAKE = 'qmake'; +} + +# Need to use the right make +# SYMBIAN_UNIX/MINGW should fall back to the non SYMBIAN ones +my $MAKE = 'make'; # default, only works on unix +if ($generator =~ /UNIX|XCODE/i) { # XCODE = make? + $MAKE = 'make'; +} elsif ($generator =~ /MINGW/i) { + $MAKE = 'mingw32-make'; +} elsif ($generator =~ /MSVC.NET|MSBUILD/i) { + $MAKE = 'nmake'; +} else { + # Unhandled (at least): BMAKE, GBUILD, SYMBIAN_ABLD, SYMBIAN_SBSV2 + warn "Unrecognized generator spec ($generator) - assuming '$MAKE'\n"; +} + +###################################################################### +# Syntax: fileContents(filename) +# Params: filename, string, filename of file to return contents +# +# Purpose: Get the contents of a file. +# Returns: String with contents of the file, or empty string if file +# doens't exist. +# Warning: Dies if it does exist but script cannot get read access. +###################################################################### +sub fileContents { + my ($filename) = @_; + my $filecontents = ""; + if (-e $filename) { + open(I, "< $filename") || die "Could not open $filename for reading, read block?"; + local $/; + binmode I; + $filecontents = ; + close I; + } + return $filecontents; +} + +###################################################################### +# Syntax: loadConfigTests() +# +# Purpose: Loads the config tests from the source basedir into %configtests. +# Returns: Nothing +###################################################################### +sub loadConfigTests { + my $configprofile = catfile($basedir, $configTestSource); + my $result; + unless ($result = do $configprofile) { + die "configtests couldn't parse $configprofile: $@\n" if $@; + # We don't check for non null output, since that is valid + } +} + +###################################################################### +# Syntax: hashesAreDifferent +# +# Purpose: Compares two hashes. (must have same key=value for everything) +# Returns: 0 if they are the same, 1 otherwise +###################################################################### +sub hashesAreDifferent { + my %a = %{$_[0]}; + my %b = %{$_[1]}; + + if (keys %a != keys %b) { + return 1; + } + + my %cmp = map { $_ => 1 } keys %a; + for my $key (keys %b) { + last unless exists $cmp{$key}; + last unless $a{$key} eq $b{$key}; + delete $cmp{$key}; + } + if (%cmp) { + return 1; + } else { + return 0; + } +} + +###################################################################### +# Syntax: executeSomething +# Params: A list of things. +# +# Purpose: Executes the first arg, passing the list. +# stderr is redirected to stdout, and the output is captured. +# Returns: The output. +###################################################################### +sub executeSomething { + my @args = @_; + my $program = $args[0]; + + my $pid = open(KID_TO_READ, "-|"); + + my $output; + + if ($pid) { # parent + while () { + $output = $output . $_; + } + close(KID_TO_READ) || $! == 0 || warn "\nFailed to execute $program: exited $?"; + } else { + # redirect STDERR to STDOUT + open STDERR, ">&STDOUT"; + + # Exec something + exec ($program, @args) || die "\nCan't exec $program: $!\n"; + # NOTREACHED + } + + return $output; +} + +###################################################################### +# Syntax: executeTest() +# Params: testName +# +# The testName variable controls the actual config test run - the +# source is assumed to be in $basedir/config.tests/$testName, and +# when 'qmake; make clean; make' is run, is expected to produce a file +# $out_basedir/config.tests/$testName/$testName. If this test passes, +# then 'config_test_$testName = yes' will be written to $out_basedir/.qmake.cache +# +# Purpose: Runs a configuration time test. +# Returns: 0 if the test fails, 1 if it passes, 2 if the test is skipped +# (e.g. .pro file has requires(x) and x is not satisfied) +###################################################################### +sub executeTest { + my ($testName) = @_; + + my $oldWorkingDir = getcwd(); + my $ret = 0; + + my @QMAKEARGS = ('CONFIG-=debug_and_release'); + + my $testOutDir = catdir($out_basedir, 'config.tests', $testName); + + if (abs_path($basedir) eq abs_path($out_basedir)) { + chdir $testOutDir or die "\nUnable to change to config test directory ($testOutDir): $!\n"; + } else { # shadow build + if (! -e $testOutDir) { + mkpath $testOutDir or die "\nUnable to create shadow build config test directory ($testOutDir): $!\n"; + } + chdir $testOutDir or die "\nUnable to change to config test directory ($testOutDir): $!\n"; + + push (@QMAKEARGS, catdir($basedir, 'config.tests', $testName)); + } + + # Throw it all away + executeSomething($QMAKE, @QMAKEARGS); + executeSomething($MAKE, 'clean'); + my $makeOutput = executeSomething(($MAKE)); + + # If make prints "blah blah blah\nSkipped." we consider this a skipped test + if ($makeOutput !~ qr(^Skipped\.$)ms) { + + # Check the test exists (can't reliably execute, especially for cross compilation) + if ($^O =~ /win32/i) { + # On windows look for $testName.exe + if (-e catfile($testOutDir, "$testName.exe")) { + $ret = 1; + } + } else { + if (-e catfile($testOutDir, $testName)) { + $ret = 1; + } + } + } else { + $ret = 2; + } + + chdir $oldWorkingDir or die "\nUnable to restore working directory: $!\n"; + return $ret; +} + +# Now run configuration tests +# %configtests is a map from config test name to a map of parameters +# e.g: +# +# %configtests = ( +# "simple" => {fatal => 1, message => "Missing required 'simple' component\n"}, +# "failed" => {message => "You need to install the FAILED sdk for this to work\n"} +# ); +# +# Parameters and their defaults: +# - fatal [false] - whether failing this test should abort everything +# - message [""] - A special message to display if this test fails +# +loadConfigTests(); + +# Only do this step for modules that have config tests +# (qtbase doesn't). We try to preserve existing contents (and furthermore +# only write to .qmake.cache if the tests change) +if (abs_path($out_basedir) ne abs_path($qtbasedir)) { + # Read any existing content + my $existingContents = fileContents($qmakeCachePath); + my %oldTestResults; + my %newTestResults; + my @fatalTestsEncountered; + + # Parse the existing results so we can check if we change them + while ($existingContents =~ /^config_test_(.*) = (yes|no)$/gm) { + $oldTestResults{$1} = $2; + } + + # Get the longest length test name so we can pretty print + use List::Util qw(max); + my $maxNameLength = max map { length $_ } keys %configtests; + + # Turn off buffering + $| = 1; + + # Now run the configuration tests + print "Configuration tests:\n"; + + while ((my $testName, my $testParameters) = each %configtests) { + printf " % *s: ", $maxNameLength, $testName; # right aligned, yes/no lines up + + my $fatalTest = $testParameters->{"fatal"} // 0; + my $message = $testParameters->{"message"}; + + my $testResult = executeTest($testName); + my @testResultStrings = ("no\n","yes\n","skipped\n"); + + $newTestResults{$testName} = (($testResult == 1) ? "yes" : "no"); # skipped = no + + if ($testResult == 0) { + # Failed test + if ($fatalTest) { + print "no (fatal)\n"; + # Report the fatality at the end, too + push (@fatalTestsEncountered, $testName); + } else { + print "no\n"; + } + if (defined($message)) { + print $message; + print "\n" unless chop $message eq "\n"; + } + } else { + # yes or skipped + print $testResultStrings[$testResult]; + } + } + + # Check if the test results are different + if (hashesAreDifferent(\%oldTestResults, \%newTestResults)) { + # Generate the new contents + my $newContents = $existingContents; + + # Strip out any existing config test results + $newContents =~ s/^config_test_.*$//gms; + $newContents =~ s/^# Compile time test results.*$//gms; + + # Add any remaining content and make sure we start on a new line + if ($newContents and chop $newContents ne '\n') { + $newContents = $newContents . "\n"; + } + + # Results and header + if (%newTestResults) { + $newContents = $newContents . '# Compile time test results ('.(localtime).")\n"; + + # Results + while ((my $testName, my $testResult) = each %newTestResults) { + $newContents = $newContents . "config_test_$testName = $testResult\n"; + } + } + + # and open the file + open my $cacheFileHandle, ">$qmakeCachePath" or die "Unable to open $qmakeCachePath for writing: $!\n"; + + print $cacheFileHandle $newContents; + + close $cacheFileHandle or die "Unable to close $qmakeCachePath: $!\n"; + } + + # Now see if we have to die + if (@fatalTestsEncountered) { + if ($#fatalTestsEncountered == 0) { + warn "Mandatory configuration test (".$fatalTestsEncountered[0].") failed.\n\n"; + } else { + warn "Mandatory configuration tests (". join (", ", @fatalTestsEncountered) . ") failed.\n\n"; + } + exit -1; + } +} + +exit 0; diff --git a/bin/syncqt b/bin/syncqt index 691f09139c..0c22cf8a6f 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -15,6 +15,7 @@ use Cwd; use Cwd 'abs_path'; use Config; use strict; +use English qw(-no_match_vars ); # set output basedir to be where ever syncqt is run from our $out_basedir = getcwd(); @@ -50,6 +51,7 @@ my $module_fwd = ""; my $cache_module_fwd = 0; my $developer_build = 0; my $no_module_version_header = 0; +my $makefile_generator = ""; my @modules_to_sync ; $force_relative = 1 if ( -d "/System/Library/Frameworks" ); @@ -90,6 +92,7 @@ sub showUsage print " easy development\n"; print " -no-module-version-header\n"; print " Don't create module version header file\n"; + print " -generator Specify the makefile generator setting (e.g. 'UNIX')\n"; print " -help This help\n"; exit 0; } @@ -658,6 +661,9 @@ while ( @ARGV ) { # skip, it's been dealt with at the top of the file shift @ARGV; next; + } elsif($arg eq "-generator") { + $var = "makefile_generator"; + $val = shift @ARGV; } elsif($arg =~/^-/) { print "Unknown option: $arg\n\n" if(!$var); showUsage(); @@ -741,6 +747,8 @@ while ( @ARGV ) { $cache_module_fwd = 1; } elsif ($var eq "developer_build") { $developer_build = 1; + } elsif ($var eq "makefile_generator") { + $makefile_generator = $val; } elsif ($var eq "no_module_version_header") { $no_module_version_header = 1; } elsif ($var eq "output") { @@ -1310,4 +1318,13 @@ if($check_includes) { } } +# Do configure tests now (pass some things along) +# fatal tests have a non zero return +unless ($showonly) { + my $configtests = dirname($0)."/qtmodule-configtests"; + if (system($EXECUTABLE_NAME, $configtests, $basedir, $out_basedir, $qtbasedir, $makefile_generator)) { + die "$configtests exited with status $?"; + } +} + exit 0; diff --git a/mkspecs/features/default_pre.prf b/mkspecs/features/default_pre.prf index 064d24bfa7..35a4d3f4a4 100644 --- a/mkspecs/features/default_pre.prf +++ b/mkspecs/features/default_pre.prf @@ -31,7 +31,7 @@ CONFIG = lex yacc warn_on debug uic resources $$CONFIG qtPrepareTool(QMAKE_SYNCQT, syncqt) - MSG = $$quote($$QMAKE_SYNCQT $$QTFWD -outdir $$OUT_PWD $$_PRO_FILE_PWD_) + MSG = $$quote($$QMAKE_SYNCQT $$QTFWD -generator $$MAKEFILE_GENERATOR -outdir $$OUT_PWD $$_PRO_FILE_PWD_) !silent:message($$MSG) system($$MSG) { # success! Nothing to do From be76c09981eab137abda0e855aa0aa4e5d11a2e7 Mon Sep 17 00:00:00 2001 From: liangqi Date: Fri, 22 Jul 2011 14:19:44 +0200 Subject: [PATCH 24/75] Use QUuid::toByteArray() instead of QUuid::toString().toAscii() This is a cheaper way. Change-Id: Ibfc67e0ac46a77e95b2ef32cd6f28c7409c42d63 Reviewed-on: http://codereview.qt.nokia.com/2037 Reviewed-by: Qt Sanity Bot Reviewed-by: Liang Qi --- src/gui/text/qrawfont_ft.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/text/qrawfont_ft.cpp b/src/gui/text/qrawfont_ft.cpp index d9225ff896..984efdbcef 100644 --- a/src/gui/text/qrawfont_ft.cpp +++ b/src/gui/text/qrawfont_ft.cpp @@ -88,7 +88,7 @@ public: FaceId faceId; faceId.filename = ""; faceId.index = 0; - faceId.uuid = QUuid::createUuid().toString().toAscii(); + faceId.uuid = QUuid::createUuid().toByteArray(); return init(faceId, true, Format_None, fontData); } From a150880ae6ea698a2e979c93498db4f3bb66c1b0 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 25 Jul 2011 13:25:15 +1000 Subject: [PATCH 25/75] Delay masking the last character in Password echo mode. If QT_GUI_PASSWORD_ECHO_DELAY is defined in qplatformdefs.h with an integer value in milliseconds, QLineEdit and TextInput will display the last character entered unmasked for that delay period and then mask the character as normal. If QT_GUI_PASSWORD_ECHO_DELAY is not defined then the behaviour is unchanged. Task-number: QTBUG-17003 Reviewed-by: Martin Jones (cherry picked from commit f9e7aee2019d321edd655bfde7de43f20a106971) Conflicts: src/declarative/graphicsitems/qdeclarativetextinput.cpp tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp Change-Id: I3683223189b7176e4ef5081ee315c95a0efb9cfe Reviewed-on: http://codereview.qt.nokia.com/2060 Reviewed-by: Qt Sanity Bot Reviewed-by: Andrew den Exter --- src/gui/widgets/qlinecontrol.cpp | 54 +++++++++++++++++++++++++- src/gui/widgets/qlinecontrol_p.h | 26 ++++++++++++- tests/auto/qlineedit/tst_qlineedit.cpp | 51 ++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 3 deletions(-) diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index bf36033c08..84674a51d3 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -59,6 +59,22 @@ QT_BEGIN_NAMESPACE +#ifdef QT_GUI_PASSWORD_ECHO_DELAY +static int qt_passwordEchoDelay = QT_GUI_PASSWORD_ECHO_DELAY; +#endif + +/*! + \macro QT_GUI_PASSWORD_ECHO_DELAY + + \internal + + Defines the amount of time in milliseconds the last entered character + should be displayed unmasked in the Password echo mode. + + If not defined in qplatformdefs.h there will be no delay in masking + password characters. +*/ + /*! \internal @@ -74,9 +90,25 @@ void QLineControl::updateDisplayText(bool forceUpdate) else str = m_text; - if (m_echoMode == QLineEdit::Password || (m_echoMode == QLineEdit::PasswordEchoOnEdit - && !m_passwordEchoEditing)) + if (m_echoMode == QLineEdit::Password) { str.fill(m_passwordCharacter); +#ifdef QT_GUI_PASSWORD_ECHO_DELAY + if (m_passwordEchoTimer != 0 && !str.isEmpty()) { + int cursor = m_text.length() - 1; + QChar uc = m_text.at(cursor); + str[cursor] = uc; + if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) { + // second half of a surrogate, check if we have the first half as well, + // if yes restore both at once + uc = m_text.at(cursor - 1); + if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) + str[cursor - 1] = uc; + } + } +#endif + } else if (m_echoMode == QLineEdit::PasswordEchoOnEdit && !m_passwordEchoEditing) { + str.fill(m_passwordCharacter); + } // replace certain non-printable characters with spaces (to avoid // drawing boxes when using fonts that don't have glyphs for such @@ -311,6 +343,7 @@ void QLineControl::init(const QString &txt) */ void QLineControl::updatePasswordEchoEditing(bool editing) { + cancelPasswordEchoTimer(); m_passwordEchoEditing = editing; updateDisplayText(); } @@ -640,6 +673,7 @@ bool QLineControl::finishChange(int validateFromState, bool update, bool edited) */ void QLineControl::internalSetText(const QString &txt, int pos, bool edited) { + cancelPasswordEchoTimer(); internalDeselect(); emit resetInputContext(); QString oldText = m_text; @@ -692,6 +726,13 @@ void QLineControl::addCommand(const Command &cmd) */ void QLineControl::internalInsert(const QString &s) { +#ifdef QT_GUI_PASSWORD_ECHO_DELAY + if (m_echoMode == QLineEdit::Password) { + if (m_passwordEchoTimer != 0) + killTimer(m_passwordEchoTimer); + m_passwordEchoTimer = startTimer(qt_passwordEchoDelay); + } +#endif if (hasSelectedText()) addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend)); if (m_maskData) { @@ -729,6 +770,7 @@ void QLineControl::internalInsert(const QString &s) void QLineControl::internalDelete(bool wasBackspace) { if (m_cursor < (int) m_text.length()) { + cancelPasswordEchoTimer(); if (hasSelectedText()) addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend)); addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)), @@ -755,6 +797,7 @@ void QLineControl::internalDelete(bool wasBackspace) void QLineControl::removeSelectedText() { if (m_selstart < m_selend && m_selend <= (int) m_text.length()) { + cancelPasswordEchoTimer(); separate(); int i ; addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend)); @@ -1153,6 +1196,7 @@ void QLineControl::internalUndo(int until) { if (!isUndoAvailable()) return; + cancelPasswordEchoTimer(); internalDeselect(); while (m_undoState && m_undoState > until) { Command& cmd = m_history[--m_undoState]; @@ -1357,6 +1401,12 @@ void QLineControl::timerEvent(QTimerEvent *event) } else if (event->timerId() == m_tripleClickTimer) { killTimer(m_tripleClickTimer); m_tripleClickTimer = 0; +#ifdef QT_GUI_PASSWORD_ECHO_DELAY + } else if (event->timerId() == m_passwordEchoTimer) { + killTimer(m_passwordEchoTimer); + m_passwordEchoTimer = 0; + updateDisplayText(); +#endif } } diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h index c6105f8472..44bd7214be 100644 --- a/src/gui/widgets/qlinecontrol_p.h +++ b/src/gui/widgets/qlinecontrol_p.h @@ -66,6 +66,8 @@ #include "QtGui/qcompleter.h" #include "QtGui/qaccessible.h" +#include "qplatformdefs.h" + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -85,6 +87,9 @@ public: m_ascent(0), m_maxLength(32767), m_lastCursorPos(-1), m_tripleClickTimer(0), m_maskData(0), m_modifiedState(0), m_undoState(0), m_selstart(0), m_selend(0), m_passwordEchoEditing(false) +#ifdef QT_GUI_PASSWORD_ECHO_DELAY + , m_passwordEchoTimer(0) +#endif { init(txt); } @@ -222,6 +227,7 @@ public: uint echoMode() const { return m_echoMode; } void setEchoMode(uint mode) { + cancelPasswordEchoTimer(); m_echoMode = mode; m_passwordEchoEditing = false; updateDisplayText(); @@ -271,7 +277,13 @@ public: QString preeditAreaText() const { return m_textLayout.preeditAreaText(); } void updatePasswordEchoEditing(bool editing); - bool passwordEchoEditing() const { return m_passwordEchoEditing; } + bool passwordEchoEditing() const { +#ifdef QT_GUI_PASSWORD_ECHO_DELAY + if (m_passwordEchoTimer != 0) + return true; +#endif + return m_passwordEchoEditing ; + } QChar passwordCharacter() const { return m_passwordCharacter; } void setPasswordCharacter(const QChar &character) { m_passwordCharacter = character; updateDisplayText(); } @@ -426,6 +438,18 @@ private: bool m_passwordEchoEditing; QChar m_passwordCharacter; +#ifdef QT_GUI_PASSWORD_ECHO_DELAY + int m_passwordEchoTimer; +#endif + void cancelPasswordEchoTimer() + { +#ifdef QT_GUI_PASSWORD_ECHO_DELAY + if (m_passwordEchoTimer != 0) { + killTimer(m_passwordEchoTimer); + m_passwordEchoTimer = 0; + } +#endif + } Q_SIGNALS: void cursorPositionChanged(int, int); diff --git a/tests/auto/qlineedit/tst_qlineedit.cpp b/tests/auto/qlineedit/tst_qlineedit.cpp index 92574ea01b..d178e26476 100644 --- a/tests/auto/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/qlineedit/tst_qlineedit.cpp @@ -72,6 +72,8 @@ #include "qcommonstyle.h" #include "qstyleoption.h" +#include "qplatformdefs.h" + QT_BEGIN_NAMESPACE class QPainter; QT_END_NAMESPACE @@ -180,6 +182,10 @@ private slots: void echoMode(); void passwordEchoOnEdit(); +#ifdef QT_GUI_PASSWORD_ECHO_DELAY + void passwordEchoDelay(); +#endif + void maxLength_mask_data(); void maxLength_mask(); @@ -1679,6 +1685,51 @@ void tst_QLineEdit::passwordEchoOnEdit() testWidget->setEchoMode(QLineEdit::Normal); } +#ifdef QT_GUI_PASSWORD_ECHO_DELAY +void tst_QLineEdit::passwordEchoDelay() +{ + QStyleOptionFrameV2 opt; + QChar fillChar = testWidget->style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter, &opt, testWidget); + + testWidget->setEchoMode(QLineEdit::Password); + testWidget->setFocus(); + testWidget->raise(); + QTRY_VERIFY(testWidget->hasFocus()); + + QTest::keyPress(testWidget, '0'); + QTest::keyPress(testWidget, '1'); + QTest::keyPress(testWidget, '2'); + QCOMPARE(testWidget->displayText(), QString(2, fillChar) + QLatin1Char('2')); + QTest::keyPress(testWidget, '3'); + QTest::keyPress(testWidget, '4'); + QCOMPARE(testWidget->displayText(), QString(4, fillChar) + QLatin1Char('4')); + QTest::keyPress(testWidget, Qt::Key_Backspace); + QCOMPARE(testWidget->displayText(), QString(4, fillChar)); + QTest::keyPress(testWidget, '4'); + QCOMPARE(testWidget->displayText(), QString(4, fillChar) + QLatin1Char('4')); + QTest::qWait(QT_GUI_PASSWORD_ECHO_DELAY); + QTRY_COMPARE(testWidget->displayText(), QString(5, fillChar)); + QTest::keyPress(testWidget, '5'); + QCOMPARE(testWidget->displayText(), QString(5, fillChar) + QLatin1Char('5')); + testWidget->clearFocus(); + QVERIFY(!testWidget->hasFocus()); + QCOMPARE(testWidget->displayText(), QString(6, fillChar)); + testWidget->setFocus(); + QTRY_VERIFY(testWidget->hasFocus()); + QCOMPARE(testWidget->displayText(), QString(6, fillChar)); + QTest::keyPress(testWidget, '6'); + QCOMPARE(testWidget->displayText(), QString(6, fillChar) + QLatin1Char('6')); + + QInputMethodEvent ev; + ev.setCommitString(QLatin1String("7")); + QApplication::sendEvent(testWidget, &ev); + QCOMPARE(testWidget->displayText(), QString(7, fillChar) + QLatin1Char('7')); + + // restore clean state + testWidget->setEchoMode(QLineEdit::Normal); +} +#endif + void tst_QLineEdit::maxLength_mask_data() { QTest::addColumn("mask"); From 8d762c9caea4f8b9ff589b6c23564f4e37242745 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Mon, 25 Jul 2011 10:52:48 +0200 Subject: [PATCH 26/75] Making cached glyphs drawing check clearer Putting the logic inside supportsTransformation() is a bit confusing and that name is misleading. Also move the same check in GL2 paint engine to the same place. Change-Id: I182500a0ff375122e6be966b7ce2495c84d113d0 Reviewed-on: http://codereview.qt.nokia.com/2096 Reviewed-by: Qt Sanity Bot Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/painting/qpaintengine_raster.cpp | 7 ++----- src/gui/painting/qpaintengineex.cpp | 10 ++++++++++ src/gui/painting/qpaintengineex_p.h | 1 + src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 10 ++-------- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index e1802e6552..299f248d2b 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -3011,7 +3011,7 @@ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) ensureState(); QFontEngine *fontEngine = textItem->fontEngine(); - if (!supportsTransformations(fontEngine)) { + if (shouldDrawCachedGlyphs(fontEngine->fontDef.pixelSize, state()->matrix)) { drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions, fontEngine); } else { @@ -3385,10 +3385,7 @@ bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransfo #endif return true; - if (pixelSize * pixelSize * qAbs(m.determinant()) >= 64 * 64) - return true; - - return false; + return !shouldDrawCachedGlyphs(pixelSize, m); } /*! diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 9427dd5105..5ef6900cc8 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -53,6 +53,10 @@ QT_BEGIN_NAMESPACE +#if !defined(QT_MAX_CACHED_GLYPH_SIZE) +# define QT_MAX_CACHED_GLYPH_SIZE 64 +#endif + /******************************************************************************* * * class QVectorPath @@ -1096,4 +1100,10 @@ bool QPaintEngineEx::supportsTransformations(qreal pixelSize, const QTransform & return false; } +bool QPaintEngineEx::shouldDrawCachedGlyphs(qreal pixelSize, const QTransform &m) const +{ + return (pixelSize * pixelSize * qAbs(m.determinant())) < + QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE; +} + QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h index c6056855f0..e90d40be4d 100644 --- a/src/gui/painting/qpaintengineex_p.h +++ b/src/gui/painting/qpaintengineex_p.h @@ -228,6 +228,7 @@ public: }; virtual uint flags() const {return 0;} virtual bool supportsTransformations(qreal pixelSize, const QTransform &m) const; + virtual bool shouldDrawCachedGlyphs(qreal pixelSize, const QTransform &m) const; protected: QPaintEngineEx(QPaintEngineExPrivate &data); diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index cf5fddbf84..d2c63ddc10 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -98,10 +98,6 @@ extern Q_GUI_EXPORT bool qt_cleartype_enabled; extern bool qt_applefontsmoothing_enabled; #endif -#if !defined(QT_MAX_CACHED_GLYPH_SIZE) -# define QT_MAX_CACHED_GLYPH_SIZE 64 -#endif - Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert); ////////////////////////////////// Private Methods ////////////////////////////////////////// @@ -1442,8 +1438,7 @@ void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) // don't try to cache huge fonts or vastly transformed fonts QFontEngine *fontEngine = textItem->fontEngine(); const qreal pixelSize = fontEngine->fontDef.pixelSize; - if (pixelSize * pixelSize * qAbs(det) < QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE || - det < 0.25f || det > 4.f) { + if (shouldDrawCachedGlyphs(pixelSize, s->matrix) || det < 0.25f || det > 4.f) { QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(textItem->fontEngine()->glyphFormat) : d->glyphCacheType; @@ -1501,8 +1496,7 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem // don't try to cache huge fonts or vastly transformed fonts const qreal pixelSize = ti.fontEngine->fontDef.pixelSize; - if (pixelSize * pixelSize * qAbs(det) >= QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE || - det < 0.25f || det > 4.f) + if (shouldDrawCachedGlyphs(pixelSize, s->matrix) || det < 0.25f || det > 4.f) drawCached = false; QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 From b949b17c3cb7b6752bc8daf2834415163792a76c Mon Sep 17 00:00:00 2001 From: Kim Motoyoshi Kalland Date: Thu, 21 Jul 2011 18:47:26 +0200 Subject: [PATCH 27/75] Changed QLibrary::resolve() to return a function pointer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the C++ standard, there is no guarantee that you can cast between function pointers and void pointers without data loss (section 5.2.10-6). Change-Id: I27f4d835e4c8ca8ecca0d76cfea9ce34491956bd Reviewed-on: http://codereview.qt.nokia.com/1995 Reviewed-by: Qt Sanity Bot Reviewed-by: João Abecasis --- dist/changes-5.0.0 | 3 +++ src/3rdparty/harfbuzz/src/harfbuzz-external.h | 2 +- .../harfbuzz/tests/linebreaking/harfbuzz-qt.cpp | 2 +- src/corelib/global/qglobal.cpp | 7 +++++++ src/corelib/global/qglobal.h | 2 ++ src/corelib/plugin/qlibrary.cpp | 10 +++++----- src/corelib/plugin/qlibrary.h | 8 ++++---- src/corelib/plugin/qlibrary_p.h | 4 ++-- src/corelib/plugin/qlibrary_unix.cpp | 14 +++++++------- src/corelib/plugin/qlibrary_win.cpp | 8 ++++---- src/corelib/plugin/qsystemlibrary_p.h | 8 ++++---- src/corelib/tools/qharfbuzz.cpp | 2 +- src/dbus/qdbus_symbols.cpp | 9 ++++----- src/dbus/qdbus_symbols_p.h | 4 ++-- src/gui/kernel/qapplication_x11.cpp | 6 +++--- src/gui/text/qrawfont_win.cpp | 6 ++++-- src/opengl/qgl_x11.cpp | 8 ++++---- src/opengl/qglpixelbuffer_x11.cpp | 2 +- src/plugins/platforms/xlib/qxlibstatic.cpp | 6 +++--- tests/auto/qlibrary/tst_qlibrary.cpp | 2 +- 20 files changed, 63 insertions(+), 50 deletions(-) diff --git a/dist/changes-5.0.0 b/dist/changes-5.0.0 index 344edb6517..523d649573 100644 --- a/dist/changes-5.0.0 +++ b/dist/changes-5.0.0 @@ -17,6 +17,9 @@ information about a particular change. - Unite clipping support has been removed from QPainter. The alternative is to unite QRegion's and using the result on QPainter. +- QLibrary::resolve() now returns a function pointer instead of a void + pointer. + **************************************************************************** * General * **************************************************************************** diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-external.h b/src/3rdparty/harfbuzz/src/harfbuzz-external.h index 5fff35fe50..1f7ae1c902 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-external.h +++ b/src/3rdparty/harfbuzz/src/harfbuzz-external.h @@ -144,7 +144,7 @@ HB_CharCategory HB_GetUnicodeCharCategory(HB_UChar32 ch); int HB_GetUnicodeCharCombiningClass(HB_UChar32 ch); HB_UChar16 HB_GetMirroredChar(HB_UChar16 ch); -void *HB_Library_Resolve(const char *library, int version, const char *symbol); +void (*HB_Library_Resolve(const char *library, int version, const char *symbol))(); HB_END_HEADER diff --git a/src/3rdparty/harfbuzz/tests/linebreaking/harfbuzz-qt.cpp b/src/3rdparty/harfbuzz/tests/linebreaking/harfbuzz-qt.cpp index f0048b75ef..2c261639ad 100644 --- a/src/3rdparty/harfbuzz/tests/linebreaking/harfbuzz-qt.cpp +++ b/src/3rdparty/harfbuzz/tests/linebreaking/harfbuzz-qt.cpp @@ -79,7 +79,7 @@ void HB_GetGraphemeAndLineBreakClass(HB_UChar32 ch, HB_GraphemeClass *grapheme, *lineBreak = (HB_LineBreakClass) prop->line_break_class; } -void *HB_Library_Resolve(const char *library, int version, const char *symbol) +void (*HB_Library_Resolve(const char *library, int version, const char *symbol))() { return QLibrary::resolve(library, version, symbol); } diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index a59cbf9382..452679c7d7 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -718,6 +718,13 @@ QT_BEGIN_NAMESPACE \sa QtMsgHandler, qInstallMsgHandler() */ +/*! \typedef QFunctionPointer + \relates + + This is a typedef for \c{void (*)()}, a pointer to a function that takes + no arguments and returns void. +*/ + /*! \macro qint64 Q_INT64_C(literal) \relates diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 63333b6233..6dfe805a92 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -1807,6 +1807,8 @@ Q_CORE_EXPORT void qt_message_output(QtMsgType, const char *buf); typedef void (*QtMsgHandler)(QtMsgType, const char *); Q_CORE_EXPORT QtMsgHandler qInstallMsgHandler(QtMsgHandler); +typedef void (*QFunctionPointer)(); + #if !defined(Q_UNIMPLEMENTED) # define Q_UNIMPLEMENTED() qWarning("%s:%d: %s: Unimplemented code.", __FILE__, __LINE__, Q_FUNC_INFO) #endif diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index 314ccd7861..45515f32e1 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -447,7 +447,7 @@ QLibraryPrivate::~QLibraryPrivate() } } -void *QLibraryPrivate::resolve(const char *symbol) +QFunctionPointer QLibraryPrivate::resolve(const char *symbol) { if (!pHnd) return 0; @@ -1129,7 +1129,7 @@ void QLibrary::setFileNameAndVersion(const QString &fileName, const QString &ver Note: In Symbian resolving with symbol names works only if the loaded library was built as STDDLL. Otherwise, the ordinals must be used. */ -void *QLibrary::resolve(const char *symbol) +QFunctionPointer QLibrary::resolve(const char *symbol) { if (!isLoaded() && !load()) return 0; @@ -1152,7 +1152,7 @@ void *QLibrary::resolve(const char *symbol) \sa resolve() */ -void *QLibrary::resolve(const QString &fileName, const char *symbol) +QFunctionPointer QLibrary::resolve(const QString &fileName, const char *symbol) { QLibrary library(fileName); return library.resolve(symbol); @@ -1175,7 +1175,7 @@ void *QLibrary::resolve(const QString &fileName, const char *symbol) \sa resolve() */ -void *QLibrary::resolve(const QString &fileName, int verNum, const char *symbol) +QFunctionPointer QLibrary::resolve(const QString &fileName, int verNum, const char *symbol) { QLibrary library(fileName, verNum); return library.resolve(symbol); @@ -1199,7 +1199,7 @@ void *QLibrary::resolve(const QString &fileName, int verNum, const char *symbol) \sa resolve() */ -void *QLibrary::resolve(const QString &fileName, const QString &version, const char *symbol) +QFunctionPointer QLibrary::resolve(const QString &fileName, const QString &version, const char *symbol) { QLibrary library(fileName, version); return library.resolve(symbol); diff --git a/src/corelib/plugin/qlibrary.h b/src/corelib/plugin/qlibrary.h index 0154e949b3..e3f557dd7d 100644 --- a/src/corelib/plugin/qlibrary.h +++ b/src/corelib/plugin/qlibrary.h @@ -79,10 +79,10 @@ public: explicit QLibrary(const QString& fileName, const QString &version, QObject *parent = 0); ~QLibrary(); - void *resolve(const char *symbol); - static void *resolve(const QString &fileName, const char *symbol); - static void *resolve(const QString &fileName, int verNum, const char *symbol); - static void *resolve(const QString &fileName, const QString &version, const char *symbol); + QFunctionPointer resolve(const char *symbol); + static QFunctionPointer resolve(const QString &fileName, const char *symbol); + static QFunctionPointer resolve(const QString &fileName, int verNum, const char *symbol); + static QFunctionPointer resolve(const QString &fileName, const QString &version, const char *symbol); bool load(); bool unload(); diff --git a/src/corelib/plugin/qlibrary_p.h b/src/corelib/plugin/qlibrary_p.h index 44860f4b23..12d625050f 100644 --- a/src/corelib/plugin/qlibrary_p.h +++ b/src/corelib/plugin/qlibrary_p.h @@ -87,7 +87,7 @@ public: bool loadPlugin(); // loads and resolves instance bool unload(); void release(); - void *resolve(const char *); + QFunctionPointer resolve(const char *); static QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version = QString()); @@ -108,7 +108,7 @@ private: bool load_sys(); bool unload_sys(); - void *resolve_sys(const char *); + QFunctionPointer resolve_sys(const char *); QAtomicInt libraryRefCount; QAtomicInt libraryUnloadCount; diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp index 0a7e841519..d3b08e1acf 100644 --- a/src/corelib/plugin/qlibrary_unix.cpp +++ b/src/corelib/plugin/qlibrary_unix.cpp @@ -267,29 +267,29 @@ bool QLibraryPrivate::unload_sys() } #ifdef Q_OS_MAC -Q_CORE_EXPORT void *qt_mac_resolve_sys(void *handle, const char *symbol) +Q_CORE_EXPORT QFunctionPointer qt_mac_resolve_sys(void *handle, const char *symbol) { - return dlsym(handle, symbol); + return QFunctionPointer(dlsym(handle, symbol)); } #endif -void* QLibraryPrivate::resolve_sys(const char* symbol) +QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol) { #if defined(QT_AOUT_UNDERSCORE) // older a.out systems add an underscore in front of symbols char* undrscr_symbol = new char[strlen(symbol)+2]; undrscr_symbol[0] = '_'; strcpy(undrscr_symbol+1, symbol); - void* address = dlsym(pHnd, undrscr_symbol); + QFunctionPointer address = QFunctionPointer(dlsym(pHnd, undrscr_symbol)); delete [] undrscr_symbol; #elif defined(QT_HPUX_LD) - void* address = 0; + QFunctionPointer address = 0; if (shl_findsym((shl_t*)&pHnd, symbol, TYPE_UNDEFINED, &address) < 0) address = 0; #elif defined (QT_NO_DYNAMIC_LIBRARY) - void *address = 0; + QFunctionPointer address = 0; #else - void* address = dlsym(pHnd, symbol); + QFunctionPointer address = QFunctionPointer(dlsym(pHnd, symbol)); #endif if (!address) { errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg( diff --git a/src/corelib/plugin/qlibrary_win.cpp b/src/corelib/plugin/qlibrary_win.cpp index 667d9cca45..4eeb2fc441 100644 --- a/src/corelib/plugin/qlibrary_win.cpp +++ b/src/corelib/plugin/qlibrary_win.cpp @@ -113,12 +113,12 @@ bool QLibraryPrivate::unload_sys() return true; } -void* QLibraryPrivate::resolve_sys(const char* symbol) +QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol) { #ifdef Q_OS_WINCE - void* address = (void*)GetProcAddress(pHnd, (const wchar_t*)QString::fromLatin1(symbol).utf16()); + FARPROC address = GetProcAddress(pHnd, (const wchar_t*)QString::fromLatin1(symbol).utf16()); #else - void* address = (void*)GetProcAddress(pHnd, symbol); + FARPROC address = GetProcAddress(pHnd, symbol); #endif if (!address) { errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg( @@ -126,6 +126,6 @@ void* QLibraryPrivate::resolve_sys(const char* symbol) } else { errorString.clear(); } - return address; + return QFunctionPointer(address); } QT_END_NAMESPACE diff --git a/src/corelib/plugin/qsystemlibrary_p.h b/src/corelib/plugin/qsystemlibrary_p.h index f20d0b6b9d..3298f05b8f 100644 --- a/src/corelib/plugin/qsystemlibrary_p.h +++ b/src/corelib/plugin/qsystemlibrary_p.h @@ -78,20 +78,20 @@ public: return (m_handle != 0); } - void *resolve(const char *symbol) + QFunctionPointer resolve(const char *symbol) { if (!m_didLoad) load(); if (!m_handle) return 0; #ifdef Q_OS_WINCE - return (void*)GetProcAddress(m_handle, (const wchar_t*)QString::fromLatin1(symbol).utf16()); + return QFunctionPointer(GetProcAddress(m_handle, (const wchar_t*)QString::fromLatin1(symbol).utf16())); #else - return (void*)GetProcAddress(m_handle, symbol); + return QFunctionPointer(GetProcAddress(m_handle, symbol)); #endif } - static void *resolve(const QString &libraryName, const char *symbol) + static QFunctionPointer resolve(const QString &libraryName, const char *symbol) { return QSystemLibrary(libraryName).resolve(symbol); } diff --git a/src/corelib/tools/qharfbuzz.cpp b/src/corelib/tools/qharfbuzz.cpp index 68f780d9fd..324cd481ed 100644 --- a/src/corelib/tools/qharfbuzz.cpp +++ b/src/corelib/tools/qharfbuzz.cpp @@ -102,7 +102,7 @@ HB_UChar16 HB_GetMirroredChar(HB_UChar16 ch) return QChar::mirroredChar(ch); } -void *HB_Library_Resolve(const char *library, int version, const char *symbol) +void (*HB_Library_Resolve(const char *library, int version, const char *symbol))() { #ifdef QT_NO_LIBRARY return 0; diff --git a/src/dbus/qdbus_symbols.cpp b/src/dbus/qdbus_symbols.cpp index fed18350bb..8e74b8b922 100644 --- a/src/dbus/qdbus_symbols.cpp +++ b/src/dbus/qdbus_symbols.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE -void *qdbus_resolve_me(const char *name); +void (*qdbus_resolve_me(const char *name))(); #if !defined QT_LINKED_LIBDBUS @@ -95,20 +95,19 @@ bool qdbus_loadLibDBus() return false; } -void *qdbus_resolve_conditionally(const char *name) +void (*qdbus_resolve_conditionally(const char *name))() { if (qdbus_loadLibDBus()) return qdbus_libdbus->resolve(name); return 0; } -void *qdbus_resolve_me(const char *name) +void (*qdbus_resolve_me(const char *name))() { - void *ptr = 0; if (!qdbus_loadLibDBus()) qFatal("Cannot find libdbus-1 in your system to resolve symbol '%s'.", name); - ptr = qdbus_libdbus->resolve(name); + QFunctionPointer ptr = qdbus_libdbus->resolve(name); if (!ptr) qFatal("Cannot resolve '%s' in your libdbus-1.", name); diff --git a/src/dbus/qdbus_symbols_p.h b/src/dbus/qdbus_symbols_p.h index a59c08a8ab..8178e2ecf3 100644 --- a/src/dbus/qdbus_symbols_p.h +++ b/src/dbus/qdbus_symbols_p.h @@ -63,8 +63,8 @@ QT_BEGIN_NAMESPACE #if !defined QT_LINKED_LIBDBUS -void *qdbus_resolve_conditionally(const char *name); // doesn't print a warning -void *qdbus_resolve_me(const char *name); // prints a warning +void (*qdbus_resolve_conditionally(const char *name))(); // doesn't print a warning +void (*qdbus_resolve_me(const char *name))(); // prints a warning bool qdbus_loadLibDBus(); # define DEFINEFUNC(ret, func, args, argcall, funcret) \ diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 8bf1c70cce..8d5a0b8a50 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -467,8 +467,8 @@ extern bool qt_is_gui_used; \c XFIXES_MAJOR - it is a part of soname and may differ from the Xfixes version. */ -static void* qt_load_library_runtime(const char *library, int vernum, - int highestVernum, const char *symbol) +static QFunctionPointer qt_load_library_runtime(const char *library, int vernum, + int highestVernum, const char *symbol) { QList versions; // we try to load in the following order: @@ -483,7 +483,7 @@ static void* qt_load_library_runtime(const char *library, int vernum, Q_FOREACH(int version, versions) { QLatin1String libName(library); QLibrary xfixesLib(libName, version); - void *ptr = xfixesLib.resolve(symbol); + QFunctionPointer ptr = xfixesLib.resolve(symbol); if (ptr) return ptr; } diff --git a/src/gui/text/qrawfont_win.cpp b/src/gui/text/qrawfont_win.cpp index 6c62673b54..111439c024 100644 --- a/src/gui/text/qrawfont_win.cpp +++ b/src/gui/text/qrawfont_win.cpp @@ -529,7 +529,8 @@ void QRawFontPrivate::platformCleanUp() { if (fontHandle != NULL) { if (ptrRemoveFontMemResourceEx == NULL) { - void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); + QFunctionPointer func = + QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); ptrRemoveFontMemResourceEx = reinterpret_cast(func); } @@ -572,7 +573,8 @@ void QRawFontPrivate::platformLoadFromData(const QByteArray &_fontData, } if (ptrAddFontMemResourceEx == NULL || ptrRemoveFontMemResourceEx == NULL) { - void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); + QFunctionPointer func = + QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); ptrRemoveFontMemResourceEx = reinterpret_cast(func); diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp index 18b6eaaf91..22a222eb1b 100644 --- a/src/opengl/qgl_x11.cpp +++ b/src/opengl/qgl_x11.cpp @@ -347,13 +347,13 @@ static void find_trans_colors() QGLFormat UNIX/GLX-specific code *****************************************************************************/ -void* qglx_getProcAddress(const char* procName) +void (*qglx_getProcAddress(const char* procName))() { // On systems where the GL driver is pluggable (like Mesa), we have to use // the glXGetProcAddressARB extension to resolve other function pointers as // the symbols wont be in the GL library, but rather in a plugin loaded by // the GL library. - typedef void* (*qt_glXGetProcAddressARB)(const char *); + typedef void (*(*qt_glXGetProcAddressARB)(const char *))(); static qt_glXGetProcAddressARB glXGetProcAddressARB = 0; static bool triedResolvingGlxGetProcAddress = false; if (!triedResolvingGlxGetProcAddress) { @@ -378,7 +378,7 @@ void* qglx_getProcAddress(const char* procName) } } - void *procAddress = 0; + void (*procAddress)() = 0; if (glXGetProcAddressARB) procAddress = glXGetProcAddressARB(procName); @@ -387,7 +387,7 @@ void* qglx_getProcAddress(const char* procName) if (!procAddress) { void *handle = dlopen(NULL, RTLD_LAZY); if (handle) { - procAddress = dlsym(handle, procName); + procAddress = (void (*)())dlsym(handle, procName); dlclose(handle); } } diff --git a/src/opengl/qglpixelbuffer_x11.cpp b/src/opengl/qglpixelbuffer_x11.cpp index 9e8beba311..fcd7b521bb 100644 --- a/src/opengl/qglpixelbuffer_x11.cpp +++ b/src/opengl/qglpixelbuffer_x11.cpp @@ -93,7 +93,7 @@ static _glXMakeContextCurrent qt_glXMakeContextCurrent = 0; #define glXGetFBConfigAttrib qt_glXGetFBConfigAttrib #define glXMakeContextCurrent qt_glXMakeContextCurrent -extern void* qglx_getProcAddress(const char* procName); // in qgl_x11.cpp +extern void (*qglx_getProcAddress(const char* procName))(); // in qgl_x11.cpp static bool qt_resolve_pbuffer_extensions() { diff --git a/src/plugins/platforms/xlib/qxlibstatic.cpp b/src/plugins/platforms/xlib/qxlibstatic.cpp index ee4c463b94..3ba0eb4c32 100644 --- a/src/plugins/platforms/xlib/qxlibstatic.cpp +++ b/src/plugins/platforms/xlib/qxlibstatic.cpp @@ -218,8 +218,8 @@ static const char * x11_atomnames = { \c XFIXES_MAJOR - it is a part of soname and may differ from the Xfixes version. */ -static void* qt_load_library_runtime(const char *library, int vernum, - int highestVernum, const char *symbol) +static QFunctionPointer qt_load_library_runtime(const char *library, int vernum, + int highestVernum, const char *symbol) { QList versions; // we try to load in the following order: @@ -234,7 +234,7 @@ static void* qt_load_library_runtime(const char *library, int vernum, Q_FOREACH(int version, versions) { QLatin1String libName(library); QLibrary xfixesLib(libName, version); - void *ptr = xfixesLib.resolve(symbol); + QFunctionPointer ptr = xfixesLib.resolve(symbol); if (ptr) return ptr; } diff --git a/tests/auto/qlibrary/tst_qlibrary.cpp b/tests/auto/qlibrary/tst_qlibrary.cpp index 0c31fddfdb..675d0e6ab6 100644 --- a/tests/auto/qlibrary/tst_qlibrary.cpp +++ b/tests/auto/qlibrary/tst_qlibrary.cpp @@ -297,7 +297,7 @@ void tst_QLibrary::unload_after_implicit_load() #endif QLibrary library( "./mylib" ); - void *p = library.resolve("mylibversion"); + QFunctionPointer p = library.resolve("mylibversion"); QVERIFY(p); // Check if it was loaded QVERIFY(library.isLoaded()); QVERIFY(library.unload()); From 3ef653f68166818ddd1f9df6f17c1ea94e16ff8f Mon Sep 17 00:00:00 2001 From: Ilya Konkov Date: Fri, 22 Jul 2011 13:25:46 +0200 Subject: [PATCH 28/75] Add initial support for bitmap version 4/5 headers. The headers are just skipped, information stored in them is ignored. Merge-request: 824 Change-Id: I48f37757114ed83cd5c92cb3d5a43eeaca4b91b3 Reviewed-on: http://codereview.qt.nokia.com/2108 Reviewed-by: Kim M. Kalland --- src/gui/image/qbmphandler.cpp | 64 +++++++++++++++--- tests/auto/qimagereader/images/test32bfv4.bmp | Bin 0 -> 232874 bytes tests/auto/qimagereader/images/test32v5.bmp | Bin 0 -> 174858 bytes tests/auto/qimagereader/qimagereader.qrc | 2 + tests/auto/qimagereader/tst_qimagereader.cpp | 22 ++++++ 5 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 tests/auto/qimagereader/images/test32bfv4.bmp create mode 100644 tests/auto/qimagereader/images/test32v5.bmp diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index 07de4d349f..8840a83ff0 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -97,8 +97,10 @@ static QDataStream &operator<<(QDataStream &s, const BMP_FILEHDR &bf) const int BMP_OLD = 12; // old Windows/OS2 BMP size -const int BMP_WIN = 40; // new Windows BMP size +const int BMP_WIN = 40; // Windows BMP v3 size const int BMP_OS2 = 64; // new OS/2 BMP size +const int BMP_WIN4 = 108; // Windows BMP v4 size +const int BMP_WIN5 = 124; // Windows BMP v5 size const int BMP_RGB = 0; // no compression const int BMP_RLE8 = 1; // run-length encoded, 8 bits @@ -109,7 +111,7 @@ const int BMP_BITFIELDS = 3; // RGB values encoded in dat static QDataStream &operator>>(QDataStream &s, BMP_INFOHDR &bi) { s >> bi.biSize; - if (bi.biSize == BMP_WIN || bi.biSize == BMP_OS2) { + if (bi.biSize == BMP_WIN || bi.biSize == BMP_OS2 || bi.biSize == BMP_WIN4 || bi.biSize == BMP_WIN5) { s >> bi.biWidth >> bi.biHeight >> bi.biPlanes >> bi.biBitCount; s >> bi.biCompression >> bi.biSizeImage; s >> bi.biXPelsPerMeter >> bi.biYPelsPerMeter; @@ -255,7 +257,57 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int image.setDotsPerMeterY(bi.biYPelsPerMeter); if (!d->isSequential()) - d->seek(startpos + BMP_FILEHDR_SIZE + bi.biSize); // goto start of colormap + d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap + + if (bi.biSize >= BMP_WIN4 || (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32))) { + Q_ASSERT(ncols == 0); + + if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask)) + return false; + if (d->read((char *)&green_mask, sizeof(green_mask)) != sizeof(green_mask)) + return false; + if (d->read((char *)&blue_mask, sizeof(blue_mask)) != sizeof(blue_mask)) + return false; + + // Read BMP v4+ header + if (bi.biSize >= BMP_WIN4) { + int alpha_mask = 0; + int CSType = 0; + int gamma_red = 0; + int gamma_green = 0; + int gamma_blue = 0; + int endpoints[9]; + + if (d->read((char *)&alpha_mask, sizeof(alpha_mask)) != sizeof(alpha_mask)) + return false; + if (d->read((char *)&CSType, sizeof(CSType)) != sizeof(CSType)) + return false; + if (d->read((char *)&endpoints, sizeof(endpoints)) != sizeof(endpoints)) + return false; + if (d->read((char *)&gamma_red, sizeof(gamma_red)) != sizeof(gamma_red)) + return false; + if (d->read((char *)&gamma_green, sizeof(gamma_green)) != sizeof(gamma_green)) + return false; + if (d->read((char *)&gamma_blue, sizeof(gamma_blue)) != sizeof(gamma_blue)) + return false; + + if (bi.biSize == BMP_WIN5) { + qint32 intent = 0; + qint32 profileData = 0; + qint32 profileSize = 0; + qint32 reserved = 0; + + if (d->read((char *)&intent, sizeof(intent)) != sizeof(intent)) + return false; + if (d->read((char *)&profileData, sizeof(profileData)) != sizeof(profileData)) + return false; + if (d->read((char *)&profileSize, sizeof(profileSize)) != sizeof(profileSize)) + return false; + if (d->read((char *)&reserved, sizeof(reserved)) != sizeof(reserved) || reserved != 0) + return false; + } + } + } if (ncols > 0) { // read color table uchar rgb[4]; @@ -268,12 +320,6 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int return false; } } else if (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32)) { - if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask)) - return false; - if (d->read((char *)&green_mask, sizeof(green_mask)) != sizeof(green_mask)) - return false; - if (d->read((char *)&blue_mask, sizeof(blue_mask)) != sizeof(blue_mask)) - return false; red_shift = calc_shift(red_mask); red_scale = 256 / ((red_mask >> red_shift) + 1); green_shift = calc_shift(green_mask); diff --git a/tests/auto/qimagereader/images/test32bfv4.bmp b/tests/auto/qimagereader/images/test32bfv4.bmp new file mode 100644 index 0000000000000000000000000000000000000000..37060373ede2b8908ef5a2cfad9c06a7c2727c8a GIT binary patch literal 232874 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
Y91F!!CIK4GWXB-lsqLNbco%xBkQDjvAeTh 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

|nQNV?1D6KmQ;4vXe|0VDDt=`DFgV18(-NoO?1J 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 M2Ob^xEOp@j0eus$0{{R3 literal 0 HcmV?d00001 diff --git a/tests/auto/qimagereader/images/test32v5.bmp b/tests/auto/qimagereader/images/test32v5.bmp new file mode 100644 index 0000000000000000000000000000000000000000..8ad3cfa60d13f53371ebbdbff4567398a9073956 GIT binary patch literal 174858 zcmeF)eXO77Ss(C|ICHZyu)V>QxSm8LHVO=~N@Ei$h!=s>KPY4E7DhH2s}@w#fjIQg z1$K(e*0aXVPMIrtQ3M&(lq7ha8LY}kL#qL)58B2eY7paPnx|_1X98`KHCfuwvd{PW z{(etR)1-CYy8RJ!_vU)8`+C2x>w50zd49+FmN&ol!#8f^|L*s{cl+PFZrIp($p61# z;}-MA#*h8;8#jL73pVC|gP7^*jg5|6J&k4gzw3cReDlIl;N5Tfi?5DXBk*bjUX8#j z5rK_YLg=e9UyZ=45qLEMBJgT|dG+}A`G~;Afh&LE_NTw|d;Y`y|Lm9k!Re1}+7t2jw`0Ip! z`Ct2uANi3>_uTvIbeUl!I=BVDAL!Du+9fmmez=S!TciOx;Hg7jU62JJzy3S_n9DGn zGHMk}fqU+}h|(p?&0sWThXKO?kXhv#44}?}0VM;tEL{9+4u1;L5U2>eGx4lnE*Ez` z55WHy{e{ne?z`SEnug>^>KM|<7(n&_x&-cJ$v*9JNxMV43w?6Y<+4=aE<3uk5Depr z<Oe(Vn$&^lEa$Y+uY;l3q4lsj&^x<-u!3 zhOFb5mk+~Yi*YUZ3S3{dZV6cdO9CJ`d_G9LO@ocS*L}$!HHBi{pRcL zOkS>&8;#8NIweraJPFvD2wi~w=TnnJ1PyJB{>;J}sYWn?L9SVa|6g3gr# zE?HF|hN(RzD?1Ee``-Uig3@3igbfQNpqC3?xHJ^_1w&L}fMF{gZJyN;Uf#=Bw!i2p z%*|b5-8ky){-88!W+7W(Kw;r1yeu^Zml<9h32cro`-&h-N3U91!N;DFN$mcmMN7pl zmcV0Q4A>9AFI>gLbigkX%II*$+I6Jf<&h0wgN^jDkjOiws+q2gF zD}AtV$*`A&sOf8TQK1vXjP+>cwlN%@U__)q^rvefJCzZC5CDA977tGVE9GUoS5Jn%;4uC z)KbqcJrl8+8TAW+8-Gjn*2^fJOUW0q%yWV*5V3PcsOnrE+6|**1s}N>d=CzD1ONvk#mC_6 zVsD{KVH~{H!&ElaU47X1J5o2{joPpP@oVTAkfm`az#L5C@0`LGd*WA5J*v?OZcJi% zdB5rF&#nXt!jX${YHbg=yfD%|@DOmP*-rvX!czGTkE&&!IEqJ5!_ZeRyqz@%KcTCN z%o}?l>+!0=oUJ62*;ovlXdo*P3DZYb?PJ|dg6vtTU1pg9?o~7AB&ExMyY=P0^>Rc( zRx;wl=PNwNx7j`kNr=)FLnZ}}xbYkePrI!s5hOm-l>o(G#|#ceX$2MlqZuzEA3R@?U_!jHXO0Yd|2WiDlmtBOclfOZE< z%A4xiSpZGQZh2=fm)-#bƓ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 literal 0 HcmV?d00001 diff --git a/tests/auto/qimagereader/qimagereader.qrc b/tests/auto/qimagereader/qimagereader.qrc index 632b73abb0..2c70652389 100644 --- a/tests/auto/qimagereader/qimagereader.qrc +++ b/tests/auto/qimagereader/qimagereader.qrc @@ -42,6 +42,8 @@ images/teapot.ppm images/test.ppm images/test.xpm + images/test32bfv4.bmp + images/test32v5.bmp images/tst7.bmp images/tst7.png images/transparent.xpm diff --git a/tests/auto/qimagereader/tst_qimagereader.cpp b/tests/auto/qimagereader/tst_qimagereader.cpp index 5c65cb3044..5d958d76dd 100644 --- a/tests/auto/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/qimagereader/tst_qimagereader.cpp @@ -234,6 +234,8 @@ void tst_QImageReader::readImage_data() QTest::newRow("empty") << QString() << false << QByteArray(); QTest::newRow("BMP: colorful") << QString("colorful.bmp") << true << QByteArray("bmp"); + QTest::newRow("BMP: test32bfv4") << QString("test32bfv4.bmp") << true << QByteArray("bmp"); + QTest::newRow("BMP: test32v5") << QString("test32v5.bmp") << true << QByteArray("bmp"); QTest::newRow("BMP: font") << QString("font.bmp") << true << QByteArray("bmp"); QTest::newRow("BMP: signed char") << QString("crash-signed-char.bmp") << true << QByteArray("bmp"); QTest::newRow("BMP: 4bpp RLE") << QString("4bpp-rle.bmp") << true << QByteArray("bmp"); @@ -432,6 +434,8 @@ void tst_QImageReader::setClipRect_data() QTest::addColumn("newRect"); QTest::addColumn("format"); QTest::newRow("BMP: colorful") << "colorful" << QRect(0, 0, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: test32bfv4") << "test32bfv4" << QRect(0, 0, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: test32v5") << "test32v5" << QRect(0, 0, 50, 50) << QByteArray("bmp"); QTest::newRow("BMP: font") << "font" << QRect(0, 0, 50, 50) << QByteArray("bmp"); QTest::newRow("BMP: 4bpp uncompressed") << "tst7.bmp" << QRect(0, 0, 31, 31) << QByteArray("bmp"); QTest::newRow("XPM: marble") << "marble" << QRect(0, 0, 50, 50) << QByteArray("xpm"); @@ -484,6 +488,8 @@ void tst_QImageReader::setScaledClipRect_data() QTest::addColumn("format"); QTest::newRow("BMP: colorful") << "colorful" << QRect(0, 0, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: test32bfv4") << "test32bfv4" << QRect(0, 0, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: test32v5") << "test32v5" << QRect(0, 0, 50, 50) << QByteArray("bmp"); QTest::newRow("BMP: font") << "font" << QRect(0, 0, 50, 50) << QByteArray("bmp"); QTest::newRow("XPM: marble") << "marble" << QRect(0, 0, 50, 50) << QByteArray("xpm"); QTest::newRow("PNG: kollada") << "kollada" << QRect(0, 0, 50, 50) << QByteArray("png"); @@ -555,6 +561,8 @@ void tst_QImageReader::imageFormat_data() QTest::newRow("xpm") << QString("marble.xpm") << QByteArray("xpm") << QImage::Format_Indexed8; QTest::newRow("bmp-1") << QString("colorful.bmp") << QByteArray("bmp") << QImage::Format_Indexed8; QTest::newRow("bmp-2") << QString("font.bmp") << QByteArray("bmp") << QImage::Format_Indexed8; + QTest::newRow("bmp-3") << QString("test32bfv4.bmp") << QByteArray("bmp") << QImage::Format_RGB32; + QTest::newRow("bmp-4") << QString("test32v5.bmp") << QByteArray("bmp") << QImage::Format_RGB32; QTest::newRow("png") << QString("kollada.png") << QByteArray("png") << QImage::Format_ARGB32; QTest::newRow("png-2") << QString("YCbCr_cmyk.png") << QByteArray("png") << QImage::Format_RGB32; QTest::newRow("mng-1") << QString("ball.mng") << QByteArray("mng") << QImage::Format_Invalid; @@ -684,6 +692,8 @@ void tst_QImageReader::supportsAnimation_data() QTest::newRow("BMP: colorful") << QString("colorful.bmp") << false; QTest::newRow("BMP: font") << QString("font.bmp") << false; QTest::newRow("BMP: signed char") << QString("crash-signed-char.bmp") << false; + QTest::newRow("BMP: test32bfv4") << QString("test32bfv4.bmp") << false;; + QTest::newRow("BMP: test32v5") << QString("test32v5.bmp") << false; QTest::newRow("XPM: marble") << QString("marble.xpm") << false; QTest::newRow("PNG: kollada") << QString("kollada.png") << false; QTest::newRow("PPM: teapot") << QString("teapot.ppm") << false; @@ -1064,6 +1074,8 @@ void tst_QImageReader::readFromDevice_data() QTest::newRow("xpm") << QString("marble.xpm") << QByteArray("xpm"); QTest::newRow("bmp-1") << QString("colorful.bmp") << QByteArray("bmp"); QTest::newRow("bmp-2") << QString("font.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-3") << QString("test32bfv4.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-4") << QString("test32v5.bmp") << QByteArray("bmp"); QTest::newRow("png") << QString("kollada.png") << QByteArray("png"); #ifdef QTEST_HAVE_MNG QTest::newRow("mng-1") << QString("ball.mng") << QByteArray("mng"); @@ -1155,6 +1167,8 @@ void tst_QImageReader::readFromFileAfterJunk_data() QTest::newRow("xpm") << QString("marble.xpm") << QByteArray("xpm"); QTest::newRow("bmp-1") << QString("colorful.bmp") << QByteArray("bmp"); QTest::newRow("bmp-2") << QString("font.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-3") << QString("test32bfv4.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-4") << QString("test32v5.bmp") << QByteArray("bmp"); QTest::newRow("png") << QString("kollada.png") << QByteArray("png"); // QTest::newRow("mng-1") << QString("images/ball.mng") << QByteArray("mng"); // QTest::newRow("mng-2") << QString("images/fire.mng") << QByteArray("mng"); @@ -1233,6 +1247,8 @@ void tst_QImageReader::devicePosition_data() QTest::newRow("xpm") << QString("marble.xpm") << QByteArray("xpm"); QTest::newRow("bmp-1") << QString("colorful.bmp") << QByteArray("bmp"); QTest::newRow("bmp-2") << QString("font.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-3") << QString("test32bfv4.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-4") << QString("test32v5.bmp") << QByteArray("bmp"); QTest::newRow("png") << QString("kollada.png") << QByteArray("png"); // QTest::newRow("mng-1") << QString("images/ball.mng") << QByteArray("mng"); // QTest::newRow("mng-2") << QString("images/fire.mng") << QByteArray("mng"); @@ -1305,6 +1321,12 @@ void tst_QImageReader::readFromResources_data() QTest::newRow("4bpp-rle.bmp") << QString("4bpp-rle.bmp") << QByteArray("bmp") << QSize(640, 480) << QString(""); + QTest::newRow("test32bfv4.bmp") << QString("test32bfv4.bmp") + << QByteArray("bmp") << QSize(373, 156) + << QString(""); + QTest::newRow("test32v5.bmp") << QString("test32v5.bmp") + << QByteArray("bmp") << QSize(373, 156) + << QString(""); #ifdef QTEST_HAVE_GIF QTest::newRow("corrupt.gif") << QString("corrupt.gif") << QByteArray("gif") << QSize(0, 0) From ffa8882ad6debb486cf7c8e3474827ae32a09823 Mon Sep 17 00:00:00 2001 From: Sergio Ahumada Date: Sun, 24 Jul 2011 16:10:33 +0200 Subject: [PATCH 29/75] testlib: fix include of `qttestversion.h' in testlib.pro The actual file defined in `sync.profile' and generated by 'syncqt' is `qttestversion.h' instead of `qttestlibversion.h' Change-Id: I90ed2d5b7cd9f98855a878c97afceced01e7e8b0 Reviewed-on: http://codereview.qt.nokia.com/2050 Reviewed-by: Qt Sanity Bot Reviewed-by: Jason McDonald --- src/testlib/testlib.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testlib/testlib.pro b/src/testlib/testlib.pro index aa416699f0..c3df1b4ec7 100644 --- a/src/testlib/testlib.pro +++ b/src/testlib/testlib.pro @@ -88,7 +88,7 @@ qpa:mac: { load(qt_module_config) -HEADERS += $$QT_SOURCE_TREE/src/testlib/qttestlibversion.h +HEADERS += $$QT_SOURCE_TREE/src/testlib/qttestversion.h QMAKE_TARGET_PRODUCT = QTestLib QMAKE_TARGET_DESCRIPTION = Qt \ From cec00a2dda6f843cde8754141ff4ab7e209c6b99 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Mon, 25 Jul 2011 13:12:00 +0200 Subject: [PATCH 30/75] Add the missing function in bootstrap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (required for the metatype changes) Change-Id: I0e3c73e7828493b4f03ec6439ec80b1c8c2bf377 Reviewed-on: http://codereview.qt.nokia.com/2105 Reviewed-by: Qt Sanity Bot Reviewed-by: Jędrzej Nowacki --- src/corelib/arch/qatomic_bootstrap.h | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/corelib/arch/qatomic_bootstrap.h b/src/corelib/arch/qatomic_bootstrap.h index ecce758e71..74dc6cfbb2 100644 --- a/src/corelib/arch/qatomic_bootstrap.h +++ b/src/corelib/arch/qatomic_bootstrap.h @@ -75,13 +75,34 @@ inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) return testAndSetOrdered(expectedValue, newValue); } -inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) { int returnValue = _q_value; _q_value += valueToAdd; return returnValue; } +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + + template Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) { From f7acedb0887fe0980a325303cd86f54d70eabead Mon Sep 17 00:00:00 2001 From: Sergio Ahumada Date: Mon, 25 Jul 2011 20:32:45 +0200 Subject: [PATCH 31/75] test: unmark tst_QWidget::getSetCheck() as "insignificant" for Linux Change-Id: I86570148f1fcbf2932c6314b0a6c666c02a3554f Reviewed-on: http://codereview.qt.nokia.com/2127 Reviewed-by: Sergio Ahumada --- tests/auto/qwidget/qwidget.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qwidget/qwidget.pro b/tests/auto/qwidget/qwidget.pro index 0cd4a70e99..a8cfecf4c3 100644 --- a/tests/auto/qwidget/qwidget.pro +++ b/tests/auto/qwidget/qwidget.pro @@ -25,4 +25,4 @@ symbian { !wince*:!symbian:win32: LIBS += -luser32 -lgdi32 -CONFIG+=insignificant_test +mac:CONFIG+=insignificant_test From ef2384ad57c7e7ea40937cced6e6210fd371a978 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 25 Jul 2011 16:28:07 +1000 Subject: [PATCH 32/75] Update cursor position when selection is reversed. A reversed selection will have the same resolved start and end positions but a different cursor position so testing the end points alone doesn't guarantee the selection is the same. Task-number: QTBUG-19456 Reviewed-by: Martin Jones Change-Id: I516e5a501ec878d673f21e54d688fd2d21b624ef Reviewed-on: http://codereview.qt.nokia.com/2080 Reviewed-by: Qt Sanity Bot Reviewed-by: Andrew den Exter --- src/gui/widgets/qlinecontrol.cpp | 14 +++++++------- tests/auto/qlineedit/tst_qlineedit.cpp | 12 ++++++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index 84674a51d3..550b5cf947 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -281,27 +281,27 @@ void QLineControl::setSelection(int start, int length) } if (length > 0) { - if (start == m_selstart && start + length == m_selend) - return; + m_selDirty |= (start != m_selstart || start + length != m_selend); m_selstart = start; m_selend = qMin(start + length, (int)m_text.length()); m_cursor = m_selend; } else if (length < 0){ - if (start == m_selend && start + length == m_selstart) - return; + m_selDirty |= (start != m_selend || start + length != m_selstart); m_selstart = qMax(start + length, 0); m_selend = start; m_cursor = m_selstart; } else if (m_selstart != m_selend) { + m_selDirty = true; m_selstart = 0; m_selend = 0; m_cursor = start; } else { m_cursor = start; - emitCursorPositionChanged(); - return; } - emit selectionChanged(); + if (m_selDirty) { + m_selDirty = false; + emit selectionChanged(); + } emitCursorPositionChanged(); } diff --git a/tests/auto/qlineedit/tst_qlineedit.cpp b/tests/auto/qlineedit/tst_qlineedit.cpp index d178e26476..72b402f69d 100644 --- a/tests/auto/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/qlineedit/tst_qlineedit.cpp @@ -289,6 +289,8 @@ private slots: void bidiLogicalMovement_data(); void bidiLogicalMovement(); + void selectAndCursorPosition(); + protected slots: void editingFinished(); @@ -3871,5 +3873,15 @@ void tst_QLineEdit::bidiLogicalMovement() } while (moved && i >= 0); } +void tst_QLineEdit::selectAndCursorPosition() +{ + testWidget->setText("This is a long piece of text"); + + testWidget->setSelection(0, 5); + QCOMPARE(testWidget->cursorPosition(), 5); + testWidget->setSelection(5, -5); + QCOMPARE(testWidget->cursorPosition(), 0); +} + QTEST_MAIN(tst_QLineEdit) #include "tst_qlineedit.moc" From ac22379a75b2e252ae0fe6fe2585e3beb2096be9 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 25 Jul 2011 15:48:01 +1000 Subject: [PATCH 33/75] Emit selectionChanged signals when input method alters the selection. Check if the input method removes the selection and force emit selectionChanged if it sets a new selection. Task-number: QTBUG-19727 Reviewed-by: Martin Jones Change-Id: Ic8ea1044d0917aac4e52368f431ac9e5c7db7c56 Reviewed-on: http://codereview.qt.nokia.com/2076 Reviewed-by: Qt Sanity Bot Reviewed-by: Andrew den Exter --- src/gui/text/qtextcontrol.cpp | 3 +++ tests/auto/qtextedit/tst_qtextedit.cpp | 27 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index aacac0445c..424d1979b2 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -1918,6 +1918,7 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) bool isGettingInput = !e->commitString().isEmpty() || e->preeditString() != cursor.block().layout()->preeditAreaText() || e->replacementLength() > 0; + bool forceSelectionChanged = false; cursor.beginEditBlock(); if (isGettingInput) { @@ -1941,6 +1942,7 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) cursor.setPosition(blockStart + a.length, QTextCursor::KeepAnchor); q->ensureCursorVisible(); repaintOldAndNewSelection(oldCursor); + forceSelectionChanged = true; } } @@ -1974,6 +1976,7 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) cursor.d->setX(); if (oldPreeditCursor != preeditCursor) emit q->microFocusChanged(); + selectionChanged(forceSelectionChanged); } QVariant QTextControl::inputMethodQuery(Qt::InputMethodQuery property) const diff --git a/tests/auto/qtextedit/tst_qtextedit.cpp b/tests/auto/qtextedit/tst_qtextedit.cpp index 65158d3d7a..7208861394 100644 --- a/tests/auto/qtextedit/tst_qtextedit.cpp +++ b/tests/auto/qtextedit/tst_qtextedit.cpp @@ -207,6 +207,8 @@ private slots: void bidiLogicalMovement_data(); void bidiLogicalMovement(); + void inputMethodSelection(); + private: void createSelection(); int blockCount() const; @@ -2365,5 +2367,30 @@ void tst_QTextEdit::bidiLogicalMovement() } while (moved && i >= 0); } +void tst_QTextEdit::inputMethodSelection() +{ + ed->setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + + QSignalSpy selectionSpy(ed, SIGNAL(selectionChanged())); + QTextCursor cursor = ed->textCursor(); + cursor.setPosition(0); + cursor.setPosition(5, QTextCursor::KeepAnchor); + ed->setTextCursor(cursor); + + QCOMPARE(selectionSpy.count(), 1); + QCOMPARE(ed->textCursor().selectionStart(), 0); + QCOMPARE(ed->textCursor().selectionEnd(), 5); + + QList attributes; + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 12, 5, QVariant()); + QInputMethodEvent event("", attributes); + QApplication::sendEvent(ed, &event); + + QCOMPARE(selectionSpy.count(), 2); + QCOMPARE(ed->textCursor().selectionStart(), 12); + QCOMPARE(ed->textCursor().selectionEnd(), 17); +} + + QTEST_MAIN(tst_QTextEdit) #include "tst_qtextedit.moc" From 750147f5c9ab892f1892fe33718fc4c402f2f73c Mon Sep 17 00:00:00 2001 From: Sarah Smith Date: Mon, 25 Jul 2011 14:38:08 +1000 Subject: [PATCH 34/75] Improve doc to avoid row vs col major confusion. There has been a few reports of user confusion from the fact that the constData and data functions return results in column-major format. There is nothing in the doc anywhere that states this, and nothing states that the class is especially for OpenGL which would give a clue at least. Change-Id: I3a9afde0fbeb8b9d2bcba6a387620b60a56774b9 Reviewed-on: http://codereview.qt.nokia.com/2066 Reviewed-by: Qt Sanity Bot Reviewed-by: Julian de Bhal --- src/gui/math3d/qmatrix4x4.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp index 837bd519b8..cef92af66b 100644 --- a/src/gui/math3d/qmatrix4x4.cpp +++ b/src/gui/math3d/qmatrix4x4.cpp @@ -55,6 +55,20 @@ QT_BEGIN_NAMESPACE \since 4.6 \ingroup painting-3D + The QMatrix4x4 class in general is treated as a row-major matrix, in that the + constructors and operator() functions take data in row-major format, as is + familiar in C-style usage. + + Internally the data is stored as column-major format, so as to be optimal for + passing to OpenGL functions, which expect column-major data. + + When using these functions be aware that they return data in \bold{column-major} + format: + \list + \o data() + \o constData() + \endlist + \sa QVector3D, QGenericMatrix */ @@ -1725,6 +1739,7 @@ QRectF QMatrix4x4::mapRect(const QRectF& rect) const \fn const qreal *QMatrix4x4::data() const Returns a constant pointer to the raw data of this matrix. + This raw data is stored in column-major format. \sa constData() */ @@ -1733,6 +1748,7 @@ QRectF QMatrix4x4::mapRect(const QRectF& rect) const \fn const qreal *QMatrix4x4::constData() const Returns a constant pointer to the raw data of this matrix. + This raw data is stored in column-major format. \sa data() */ From c0589cde3d2d37191490d4421e8503568005682b Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Tue, 26 Jul 2011 10:06:45 +1000 Subject: [PATCH 35/75] Windows: fixed qtmain.lib not going to `lib' directory `load(qt_module_config)' clobbers DESTDIR. Rearrange the order so that our setting of DESTDIR works as intended. Change-Id: Id6f02e9fb55069fae9b2a75c9d0f51578b84f4d1 Reviewed-on: http://codereview.qt.nokia.com/2130 Reviewed-by: Qt Sanity Bot Reviewed-by: Michael Goddard --- src/winmain/winmain.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/winmain/winmain.pro b/src/winmain/winmain.pro index b353e8e382..6630d86326 100644 --- a/src/winmain/winmain.pro +++ b/src/winmain/winmain.pro @@ -1,7 +1,6 @@ # Additional Qt project file for qtmain lib on Windows TEMPLATE = lib TARGET = qtmain -DESTDIR = $$QMAKE_LIBDIR_QT QT = CONFIG += staticlib warn_on @@ -17,5 +16,6 @@ win32 { !win32:error("$$_FILE_ is intended only for Windows!") load(qt_module_config) +DESTDIR = $$QMAKE_LIBDIR_QT wince*:QMAKE_POST_LINK = From b7064513e2b0fc51f5f68d2057047ed30bae6eba Mon Sep 17 00:00:00 2001 From: David Faure Date: Tue, 26 Jul 2011 11:40:18 +0200 Subject: [PATCH 36/75] Make QTabWidget::tabBar() public. This is very much useful to be able to write things like myTabWidget->tabBar()->setSelectionBehaviorOnRemove( QTabBar::SelectPreviousTab ); without subclassing QTabWidget. Change-Id: Ic7c42709ea1086631d37f90f184b058c4b6e9601 Merge-request: 3 Reviewed-by: Olivier Goffart Reviewed-on: http://codereview.qt.nokia.com/2172 Reviewed-by: Qt Sanity Bot --- src/gui/widgets/qtabwidget.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/qtabwidget.h b/src/gui/widgets/qtabwidget.h index 6a026c0023..524767ecbb 100644 --- a/src/gui/widgets/qtabwidget.h +++ b/src/gui/widgets/qtabwidget.h @@ -148,6 +148,8 @@ public: void clear(); + QTabBar* tabBar() const; + public Q_SLOTS: void setCurrentIndex(int index); void setCurrentWidget(QWidget *widget); @@ -165,7 +167,6 @@ protected: void keyPressEvent(QKeyEvent *); void paintEvent(QPaintEvent *); void setTabBar(QTabBar *); - QTabBar* tabBar() const; void changeEvent(QEvent *); bool event(QEvent *); void initStyleOption(QStyleOptionTabWidgetFrame *option) const; From 6b82798ee73dc8aac6f6a6c4c12ff291d6d7e9e1 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 19 Jul 2011 15:53:32 +0200 Subject: [PATCH 37/75] Add QFreeList as an internal class This is a generic implementation of the lock-free free list found in qabstracteventdispatcher.cpp. Use next() to get the next free entry in the list, and release(id) when done with the id. This version is templated and allows having a payload which can be accessed using the id returned by next(). The payload is allocated and deallocated automatically by the free list, but *NOT* when calling next()/release(). Initialization should be done by code needing it after next() returns. Likewise, cleanup should happen before calling release(). It is possible to have use 'void' as the payload type, in which case the free list only contains indexes to the next free entry. Autotest included. Change-Id: Ifd12a961d47f3d76593c45061f72e55c9b80a43b Reviewed-on: http://codereview.qt.nokia.com/2160 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/tools/qfreelist.cpp | 62 ++++++ src/corelib/tools/qfreelist_p.h | 294 +++++++++++++++++++++++++ src/corelib/tools/tools.pri | 2 + tests/auto/corelib.pro | 1 + tests/auto/qfreelist/qfreelist.pro | 6 + tests/auto/qfreelist/tst_qfreelist.cpp | 179 +++++++++++++++ 6 files changed, 544 insertions(+) create mode 100644 src/corelib/tools/qfreelist.cpp create mode 100644 src/corelib/tools/qfreelist_p.h create mode 100644 tests/auto/qfreelist/qfreelist.pro create mode 100644 tests/auto/qfreelist/tst_qfreelist.cpp diff --git a/src/corelib/tools/qfreelist.cpp b/src/corelib/tools/qfreelist.cpp new file mode 100644 index 0000000000..63e37ec249 --- /dev/null +++ b/src/corelib/tools/qfreelist.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfreelist_p.h" + +// default sizes and offsets (no need to define these when customizing) +enum { + Offset0 = 0x00000000, + Offset1 = 0x00008000, + Offset2 = 0x00080000, + Offset3 = 0x00800000, + + Size0 = Offset1 - Offset0, + Size1 = Offset2 - Offset1, + Size2 = Offset3 - Offset2, + Size3 = QFreeListDefaultConstants::MaxIndex - Offset3 +}; + +const int QFreeListDefaultConstants::Sizes[QFreeListDefaultConstants::BlockCount] = { + Size0, + Size1, + Size2, + Size3 +}; diff --git a/src/corelib/tools/qfreelist_p.h b/src/corelib/tools/qfreelist_p.h new file mode 100644 index 0000000000..74ba3b587e --- /dev/null +++ b/src/corelib/tools/qfreelist_p.h @@ -0,0 +1,294 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFREELIST_P_H +#define QFREELIST_P_H + +// +// 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. +// + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +/*! \internal + + Element in a QFreeList. ConstReferenceType and ReferenceType are used as + the return values for QFreeList::at() and QFreeList::operator[](). Contains + the real data storage (_t) and the id of the next free element (next). + + Note: the t() functions should be used to access the data, not _t. +*/ +template +struct QFreeListElement +{ + typedef const T &ConstReferenceType; + typedef T &ReferenceType; + + T _t; + int next; + + inline ConstReferenceType t() const { return _t; } + inline ReferenceType t() { return _t; } +}; + +/*! \internal + + Element in a QFreeList without a paylout. ConstReferenceType and + ReferenceType are void, the t() functions return void and are empty. +*/ +template <> +struct QFreeListElement +{ + typedef void ConstReferenceType; + typedef void ReferenceType; + + int next; + + inline void t() const { } + inline void t() { } +}; + +/*! \internal + + Defines default constants used by QFreeList: + + - The initial value returned by QFreeList::next() is zero. + + - QFreeList allows for up to 16777216 elements in QFreeList and uses the top + 8 bits to store a serial counter for ABA protection. + + - QFreeList will make a maximum of 4 allocations (blocks), with each + successive block larger than the previous. + + - Sizes static int[] array to define the size of each block. + + It is possible to define your own constants struct/class and give this to + QFreeList to customize/tune the behavior. +*/ +struct Q_AUTOTEST_EXPORT QFreeListDefaultConstants +{ + // used by QFreeList, make sure to define all of when customizing + enum { + InitialNextValue = 0, + IndexMask = 0x00ffffff, + SerialMask = ~IndexMask & ~0x80000000, + SerialCounter = IndexMask + 1, + MaxIndex = IndexMask, + BlockCount = 4, + }; + + static const int Sizes[BlockCount]; +}; + +/*! \internal + + This is a generic implementation of a lock-free free list. Use next() to + get the next free entry in the list, and release(id) when done with the id. + + This version is templated and allows having a payload of type T which can + be accessed using the id returned by next(). The payload is allocated and + deallocated automatically by the free list, but *NOT* when calling + next()/release(). Initialization should be done by code needing it after + next() returns. Likewise, cleanup() should happen before calling release(). + It is possible to have use 'void' as the payload type, in which case the + free list only contains indexes to the next free entry. + + The ConstantsType type defaults to QFreeListDefaultConstants above. You can + define your custom ConstantsType, see above for details on what needs to be + available. +*/ +template +class QFreeList +{ + typedef T ValueType; + typedef QFreeListElement ElementType; + typedef typename ElementType::ConstReferenceType ConstReferenceType; + typedef typename ElementType::ReferenceType ReferenceType; + + // return which block the index \a x falls in, and modify \a x to be the index into that block + static inline int blockfor(int &x) + { + for (int i = 0; i < ConstantsType::BlockCount; ++i) { + int size = ConstantsType::Sizes[i]; + if (x < size) + return i; + x -= size; + } + Q_ASSERT(false); + return -1; + } + + // allocate a block of the given \a size, initialized starting with the given \a offset + static inline ElementType *allocate(int offset, int size) + { + // qDebug("QFreeList: allocating %d elements (%ld bytes) with offset %d", size, size * sizeof(ElementType), offset); + ElementType *v = new ElementType[size]; + for (int i = 0; i < size; ++i) + v[i].next = offset + i + 1; + return v; + } + + // take the current serial number from \a o, increment it, and store it in \a n + static inline int incrementserial(int o, int n) + { + return (n & ConstantsType::IndexMask) | ((o + ConstantsType::SerialCounter) & ConstantsType::SerialMask); + } + + // the blocks + QAtomicPointer _v[ConstantsType::BlockCount]; + // the next free id + QAtomicInt _next; + + // QFreeList is not copyable + Q_DISABLE_COPY(QFreeList) + +public: + inline QFreeList(); + inline ~QFreeList(); + + // returns the payload for the given index \a x + inline ConstReferenceType at(int x) const; + inline ReferenceType operator[](int x); + + /* + Return the next free id. Use this id to access the payload (see above). + Call release(id) when done using the id. + */ + inline int next(); + inline void release(int id); +}; + +template +inline QFreeList::QFreeList() + : _next(ConstantsType::InitialNextValue) +{ } + +template +inline QFreeList::~QFreeList() +{ + for (int i = 0; i < ConstantsType::BlockCount; ++i) + delete [] static_cast(_v[i]); +} + +template +inline typename QFreeList::ConstReferenceType QFreeList::at(int x) const +{ + const int block = blockfor(x); + return _v[block][x].t(); +} + +template +inline typename QFreeList::ReferenceType QFreeList::operator[](int x) +{ + const int block = blockfor(x); + return _v[block][x].t(); +} + +template +inline int QFreeList::next() +{ + int id, newid, at; + ElementType *v; + do { + id = _next; // .loadAqcuire(); + + at = id & ConstantsType::IndexMask; + const int block = blockfor(at); + v = _v[block]; + + if (!v) { + v = allocate((id & ConstantsType::IndexMask) - at, ConstantsType::Sizes[block]); + if (!_v[block].testAndSetRelease(0, v)) { + // race with another thread lost + delete [] v; + v = _v[block]; + Q_ASSERT(v != 0); + } + } + + newid = v[at].next | (id & ~ConstantsType::IndexMask); + } while (!_next.testAndSetRelease(id, newid)); + // qDebug("QFreeList::next(): returning %d (_next now %d, serial %d)", + // id & ConstantsType::IndexMask, + // newid & ConstantsType::IndexMask, + // (newid & ~ConstantsType::IndexMask) >> 24); + return id & ConstantsType::IndexMask; +} + +template +inline void QFreeList::release(int id) +{ + int at = id & ConstantsType::IndexMask; + const int block = blockfor(at); + ElementType *v = _v[block]; + + int x, newid; + do { + x = _next; // .loadAcquire(); + v[at].next = x & ConstantsType::IndexMask; + + newid = incrementserial(x, id); + } while (!_next.testAndSetRelease(x, newid)); + // qDebug("QFreeList::release(%d): _next now %d (was %d), serial %d", + // id & ConstantsType::IndexMask, + // newid & ConstantsType::IndexMask, + // x & ConstantsType::IndexMask, + // (newid & ~ConstantsType::IndexMask) >> 24); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QFREELIST_P_H diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index f5b38eb1c0..13b597d513 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -13,6 +13,7 @@ HEADERS += \ tools/qdatetime.h \ tools/qdatetime_p.h \ tools/qeasingcurve.h \ + tools/qfreelist_p.h \ tools/qhash.h \ tools/qline.h \ tools/qlinkedlist.h \ @@ -61,6 +62,7 @@ SOURCES += \ tools/qdatetime.cpp \ tools/qeasingcurve.cpp \ tools/qelapsedtimer.cpp \ + tools/qfreelist.cpp \ tools/qhash.cpp \ tools/qline.cpp \ tools/qlinkedlist.cpp \ diff --git a/tests/auto/corelib.pro b/tests/auto/corelib.pro index 95a16f67d9..7a655d6208 100644 --- a/tests/auto/corelib.pro +++ b/tests/auto/corelib.pro @@ -30,6 +30,7 @@ SUBDIRS=\ qfileinfo \ qfilesystemwatcher \ qflags \ + qfreelist \ qfuture \ qfuturewatcher \ qgetputenv \ diff --git a/tests/auto/qfreelist/qfreelist.pro b/tests/auto/qfreelist/qfreelist.pro new file mode 100644 index 0000000000..b7f2b3d38f --- /dev/null +++ b/tests/auto/qfreelist/qfreelist.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +SOURCES += tst_qfreelist.cpp +QT += core-private +QT -= gui + +!private_tests:SOURCES += $$QT_SOURCE_TREE/src/corelib/tools/qfreelist.cpp diff --git a/tests/auto/qfreelist/tst_qfreelist.cpp b/tests/auto/qfreelist/tst_qfreelist.cpp new file mode 100644 index 0000000000..139d76e64a --- /dev/null +++ b/tests/auto/qfreelist/tst_qfreelist.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include +#include +#include +#include +#include +#include + +//TESTED_CLASS=QFreeList +//TESTED_FILES=corelib/tools/qfreelist_p.h + +class tst_QFreeList : public QObject +{ + Q_OBJECT + +private slots: + void basicTest(); + void customized(); + void threadedTest(); +}; + +void tst_QFreeList::basicTest() +{ + { + QFreeList voidFreeList; + int zero = voidFreeList.next(); + int one = voidFreeList.next(); + int two = voidFreeList.next(); + QCOMPARE(zero, 0); + QCOMPARE(one, 1); + QCOMPARE(two, 2); + voidFreeList[zero]; + voidFreeList[one]; + voidFreeList[two]; + voidFreeList.at(zero); + voidFreeList.at(one); + voidFreeList.at(two); + voidFreeList.release(one); + int next = voidFreeList.next(); + QCOMPARE(next, 1); + voidFreeList[next]; + voidFreeList.at(next); + } + + { + QFreeList intFreeList; + int zero = intFreeList.next(); + int one = intFreeList.next(); + int two = intFreeList.next(); + QCOMPARE(zero, 0); + QCOMPARE(one, 1); + QCOMPARE(two, 2); + intFreeList[zero] = zero; + intFreeList[one] = one; + intFreeList[two] = two; + QCOMPARE(intFreeList.at(zero), zero); + QCOMPARE(intFreeList.at(one), one); + QCOMPARE(intFreeList.at(two), two); + intFreeList.release(one); + int next = intFreeList.next(); + QCOMPARE(next, 1); + QCOMPARE(intFreeList.at(next), one); + intFreeList[next] = -one; + QCOMPARE(intFreeList.at(next), -one); + } +} + +struct CustomFreeListConstants : public QFreeListDefaultConstants +{ + enum { + InitialNextValue = 50, + BlockCount = 10 + }; + + static const int Sizes[10]; +}; + +const int CustomFreeListConstants::Sizes[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 16777216 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 }; + +void tst_QFreeList::customized() +{ + QFreeList customFreeList; + int next = customFreeList.next(); + QCOMPARE(next, int(CustomFreeListConstants::InitialNextValue)); + customFreeList[next]; + customFreeList.at(next); + customFreeList.release(next); +} + +enum { TimeLimit = 3000 }; + +class FreeListThread : public QThread +{ + static QFreeList freelist; + +public: + inline FreeListThread() : QThread() { } + inline void run() + { + QElapsedTimer t; + t.start(); + QList needToRelease; + do { + int i = freelist.next(); + int j = freelist.next(); + int k = freelist.next(); + int l = freelist.next(); + freelist.release(k); + int n = freelist.next(); + int m = freelist.next(); + freelist.release(l); + freelist.release(m); + freelist.release(n); + freelist.release(j); + // freelist.release(i); + needToRelease << i; + } while (t.elapsed() < TimeLimit); + + foreach (int x, needToRelease) + freelist.release(x); + } +}; + +QFreeList FreeListThread::freelist; + +void tst_QFreeList::threadedTest() +{ + const int ThreadCount = QThread::idealThreadCount(); + FreeListThread *threads = new FreeListThread[ThreadCount]; + for (int i = 0; i < ThreadCount; ++i) + threads[i].start(); + for (int i = 0; i < ThreadCount; ++i) + threads[i].wait(); + delete [] threads; +} + +QTEST_MAIN(tst_QFreeList) +#include "tst_qfreelist.moc" From 33a55c5661299085c5e381f9aaf99b74ccc7b6b1 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 19 Jul 2011 16:27:42 +0200 Subject: [PATCH 38/75] Use QFreeList for timer id allocation The timer id allocator doesn't need a paylod (hence T=void), but we want to tune the allocation 'strategy.' We allocate a maximum of 6 blocks (like before), but the first block is twice as large as before and is not static writable anymore. The initial value is 1 (0 is not a valid timer id), but otherwise the constants are the same as the defaults. Change-Id: Ied49ff4d7a6a8d69bc8c7bfa5475e4111446659f Reviewed-on: http://codereview.qt.nokia.com/2161 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- .../kernel/qabstracteventdispatcher.cpp | 210 ++++-------------- 1 file changed, 43 insertions(+), 167 deletions(-) diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp index 1b0707605c..10de2caf62 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.cpp +++ b/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -45,109 +45,10 @@ #include "qthread.h" #include #include +#include QT_BEGIN_NAMESPACE -// we allow for 2^24 = 8^8 = 16777216 simultaneously running timers -static const int TimerIdMask = 0x00ffffff; -static const int TimerSerialMask = ~TimerIdMask & ~0x80000000; -static const int TimerSerialCounter = TimerIdMask + 1; -static const int MaxTimerId = TimerIdMask; - -static int FirstBucket[] = { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 -}; - -enum { - FirstBucketOffset = 0, - SecondBucketOffset = sizeof(FirstBucket) / sizeof(FirstBucket[0]), - ThirdBucketOffset = 0x100, - FourthBucketOffset = 0x1000, - FifthBucketOffset = 0x10000, - SixthBucketOffset = 0x100000 -}; - -enum { - FirstBucketSize = SecondBucketOffset, - SecondBucketSize = ThirdBucketOffset - SecondBucketOffset, - ThirdBucketSize = FourthBucketOffset - ThirdBucketOffset, - FourthBucketSize = FifthBucketOffset - FourthBucketOffset, - FifthBucketSize = SixthBucketOffset - FifthBucketOffset, - SixthBucketSize = MaxTimerId - SixthBucketOffset -}; - -static const int BucketSize[] = { - FirstBucketSize, SecondBucketSize, ThirdBucketSize, - FourthBucketSize, FifthBucketSize, SixthBucketSize -}; -enum { NumberOfBuckets = sizeof(BucketSize) / sizeof(BucketSize[0]) }; - -static const int BucketOffset[] = { - FirstBucketOffset, SecondBucketOffset, ThirdBucketOffset, - FourthBucketOffset, FifthBucketOffset, SixthBucketOffset -}; - -static QBasicAtomicPointer timerIds[] = - { Q_BASIC_ATOMIC_INITIALIZER(FirstBucket), - Q_BASIC_ATOMIC_INITIALIZER(0), - Q_BASIC_ATOMIC_INITIALIZER(0), - Q_BASIC_ATOMIC_INITIALIZER(0), - Q_BASIC_ATOMIC_INITIALIZER(0), - Q_BASIC_ATOMIC_INITIALIZER(0) }; - -static void timerIdsDestructorFunction() -{ - // start at one, the first bucket is pre-allocated - for (int i = 1; i < NumberOfBuckets; ++i) - delete [] static_cast(timerIds[i]); -} -Q_DESTRUCTOR_FUNCTION(timerIdsDestructorFunction) - -static QBasicAtomicInt nextFreeTimerId = Q_BASIC_ATOMIC_INITIALIZER(1); - -// avoid the ABA-problem by using 7 of the top 8 bits of the timerId as a serial number -static inline int prepareNewValueWithSerialNumber(int oldId, int newId) -{ - return (newId & TimerIdMask) | ((oldId + TimerSerialCounter) & TimerSerialMask); -} - -namespace { - template struct QStaticAssertType; - template<> struct QStaticAssertType { enum { Value = 1 }; }; -} -#define q_static_assert(expr) (void)QStaticAssertType::Value - -static inline int bucketOffset(int timerId) -{ - q_static_assert(sizeof BucketSize == sizeof BucketOffset); - q_static_assert(sizeof(timerIds) / sizeof(timerIds[0]) == NumberOfBuckets); - - for (int i = 0; i < NumberOfBuckets; ++i) { - if (timerId < BucketSize[i]) - return i; - timerId -= BucketSize[i]; - } - qFatal("QAbstractEventDispatcher: INTERNAL ERROR, timer ID %d is too large", timerId); - return -1; -} - -static inline int bucketIndex(int bucket, int timerId) -{ - return timerId - BucketOffset[bucket]; -} - -static inline int *allocateBucket(int bucket) -{ - // allocate a new bucket - const int size = BucketSize[bucket]; - const int offset = BucketOffset[bucket]; - int *b = new int[size]; - for (int i = 0; i != size; ++i) - b[i] = offset + i + 1; - return b; -} - void QAbstractEventDispatcherPrivate::init() { Q_Q(QAbstractEventDispatcher); @@ -158,79 +59,54 @@ void QAbstractEventDispatcherPrivate::init() } } -// Timer IDs are implemented using a free-list; -// there's a vector initialized with: -// X[i] = i + 1 -// and nextFreeTimerId starts with 1. -// -// Allocating a timer ID involves taking the ID from -// X[nextFreeTimerId] -// updating nextFreeTimerId to this value and returning the old value -// -// When the timer ID is allocated, its cell in the vector is unused (it's a -// free list). As an added protection, we use the cell to store an invalid -// (negative) value that we can later check for integrity. -// -// (continues below). +// we allow for 2^24 = 8^8 = 16777216 simultaneously running timers +struct QtTimerIdFreeListConstants : public QFreeListDefaultConstants +{ + enum + { + InitialNextValue = 1, + BlockCount = 6, + }; + + static const int Sizes[BlockCount]; +}; + +enum { + Offset0 = 0x00000000, + Offset1 = 0x00000040, + Offset2 = 0x00000100, + Offset3 = 0x00001000, + Offset4 = 0x00010000, + Offset5 = 0x00100000, + + Size0 = Offset1 - Offset0, + Size1 = Offset2 - Offset1, + Size2 = Offset3 - Offset2, + Size3 = Offset4 - Offset3, + Size4 = Offset5 - Offset4, + Size5 = QtTimerIdFreeListConstants::MaxIndex - Offset5 +}; + +const int QtTimerIdFreeListConstants::Sizes[QtTimerIdFreeListConstants::BlockCount] = { + Size0, + Size1, + Size2, + Size3, + Size4, + Size5 +}; + +typedef QFreeList QtTimerIdFreeList; +Q_GLOBAL_STATIC(QtTimerIdFreeList, timerIdFreeList) + int QAbstractEventDispatcherPrivate::allocateTimerId() { - int timerId, newTimerId; - int at, *b; - do { - timerId = nextFreeTimerId; //.loadAcquire(); // ### FIXME Proper memory ordering semantics - - // which bucket are we looking in? - int which = timerId & TimerIdMask; - int bucket = bucketOffset(which); - at = bucketIndex(bucket, which); - b = timerIds[bucket]; - - if (!b) { - // allocate a new bucket - b = allocateBucket(bucket); - if (!timerIds[bucket].testAndSetRelease(0, b)) { - // another thread won the race to allocate the bucket - delete [] b; - b = timerIds[bucket]; - } - } - - newTimerId = prepareNewValueWithSerialNumber(timerId, b[at]); - } while (!nextFreeTimerId.testAndSetRelaxed(timerId, newTimerId)); - - b[at] = -timerId; - - return timerId; + return timerIdFreeList()->next(); } -// Releasing a timer ID requires putting the current ID back in the vector; -// we do it by setting: -// X[timerId] = nextFreeTimerId; -// then we update nextFreeTimerId to the timer we've just released -// -// The extra code in allocateTimerId and releaseTimerId are ABA prevention -// and bucket memory. The buckets are simply to make sure we allocate only -// the necessary number of timers. See above. -// -// ABA prevention simply adds a value to 7 of the top 8 bits when resetting -// nextFreeTimerId. void QAbstractEventDispatcherPrivate::releaseTimerId(int timerId) { - int which = timerId & TimerIdMask; - int bucket = bucketOffset(which); - int at = bucketIndex(bucket, which); - int *b = timerIds[bucket]; - - Q_ASSERT_X(timerId == -b[at], "QAbstractEventDispatcher::releaseTimerId", - "Internal error: timer ID not found"); - - int freeId, newTimerId; - do { - freeId = nextFreeTimerId;//.loadAcquire(); // ### FIXME Proper memory ordering semantics - b[at] = freeId & TimerIdMask; - - newTimerId = prepareNewValueWithSerialNumber(freeId, timerId); - } while (!nextFreeTimerId.testAndSetRelease(freeId, newTimerId)); + timerIdFreeList()->release(timerId); } /*! From d55aa1ad2aa2391eb6b32fa696867fd8b20e570b Mon Sep 17 00:00:00 2001 From: Michael Goddard Date: Mon, 25 Jul 2011 10:10:54 +1000 Subject: [PATCH 39/75] Tighten up the config test success checking. Try a lot harder to remove the old $TARGET output, since make clean isn't sufficient. Also fix a bug in program invocation that was hidden because of the stale files. Change-Id: I0a365409d81efb74c5836eaf9f129fd9b2cca77e Reviewed-on: http://codereview.qt.nokia.com/2052 Reviewed-by: Qt Sanity Bot Reviewed-by: Rohan McGovern --- bin/qtmodule-configtests | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/bin/qtmodule-configtests b/bin/qtmodule-configtests index a5c5899cc5..f6cc2052da 100755 --- a/bin/qtmodule-configtests +++ b/bin/qtmodule-configtests @@ -135,8 +135,7 @@ sub hashesAreDifferent { # Returns: The output. ###################################################################### sub executeSomething { - my @args = @_; - my $program = $args[0]; + my ($program, @args) = @_; my $pid = open(KID_TO_READ, "-|"); @@ -183,6 +182,10 @@ sub executeTest { my $testOutDir = catdir($out_basedir, 'config.tests', $testName); + # Since we might be cross compiling, look for barename (Linux) and .exe (Win32/Symbian) + my $testOutFile1 = catfile($testOutDir, "$testName.exe"); + my $testOutFile2 = catfile($testOutDir, $testName); + if (abs_path($basedir) eq abs_path($out_basedir)) { chdir $testOutDir or die "\nUnable to change to config test directory ($testOutDir): $!\n"; } else { # shadow build @@ -194,24 +197,24 @@ sub executeTest { push (@QMAKEARGS, catdir($basedir, 'config.tests', $testName)); } - # Throw it all away + # First remove existing stuff (XXX this probably needs generator specific code, but hopefully + # the target removal below will suffice) + if (-e "Makefile") { + executeSomething($MAKE, 'distclean'); + } + + # and any targets that we might find that weren't distcleaned + unlink $testOutFile1, $testOutFile2; + + # Run qmake && make executeSomething($QMAKE, @QMAKEARGS); - executeSomething($MAKE, 'clean'); my $makeOutput = executeSomething(($MAKE)); # If make prints "blah blah blah\nSkipped." we consider this a skipped test if ($makeOutput !~ qr(^Skipped\.$)ms) { - # Check the test exists (can't reliably execute, especially for cross compilation) - if ($^O =~ /win32/i) { - # On windows look for $testName.exe - if (-e catfile($testOutDir, "$testName.exe")) { - $ret = 1; - } - } else { - if (-e catfile($testOutDir, $testName)) { - $ret = 1; - } + if (-e $testOutFile1 or -e $testOutFile2) { + $ret = 1; } } else { $ret = 2; From 2dc77d9264f3a5b713c1742515d627c92a1b61b6 Mon Sep 17 00:00:00 2001 From: Michael Goddard Date: Mon, 25 Jul 2011 22:07:54 +1000 Subject: [PATCH 40/75] Try to make sure the config test script is installed. And try to fail a bit more gracefully if it isn't. Change-Id: I62e01c0536aa0a032940d6a9a5ccf5edcfeef221 Reviewed-on: http://codereview.qt.nokia.com/2109 Reviewed-by: Qt Sanity Bot Reviewed-by: Rohan McGovern Reviewed-by: Michael Goddard --- bin/syncqt | 14 +++++++++++--- configure | 2 +- qtbase.pro | 5 +++++ tools/configure/configureapp.cpp | 6 ++++++ 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/bin/syncqt b/bin/syncqt index 0c22cf8a6f..0dcbc4d58e 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -1320,10 +1320,18 @@ if($check_includes) { # Do configure tests now (pass some things along) # fatal tests have a non zero return -unless ($showonly) { +# If the generator is not set (e.g. someone invoking syncqt as part of configure etc, then don't run tests either) +unless ($showonly || $makefile_generator eq '') { my $configtests = dirname($0)."/qtmodule-configtests"; - if (system($EXECUTABLE_NAME, $configtests, $basedir, $out_basedir, $qtbasedir, $makefile_generator)) { - die "$configtests exited with status $?"; + if (! -f $configtests) { + $configtests = $qtbasedir."/bin/qtmodule-configtests"; + } + if (! -f $configtests) { + warn "Unable to locate qtmodule-configtests script - config tests disabled.\n"; + } else { + if (system($EXECUTABLE_NAME, $configtests, $basedir, $out_basedir, $qtbasedir, $makefile_generator)) { + die "$configtests exited with status $?"; + } } } diff --git a/configure b/configure index 35aea298ff..2bd5c06351 100755 --- a/configure +++ b/configure @@ -2577,7 +2577,7 @@ if [ "$OPT_SHADOW" = "yes" ]; then chmod 755 "$outpath/bin/syncqt" fi - for i in elf2e32_qtwrapper createpackage patch_capabilities; do + for i in elf2e32_qtwrapper createpackage patch_capabilities qtmodule-configtests; do rm -f "$outpath/bin/$i" if [ -x "$relpath/bin/$i" ]; then mkdir -p "$outpath/bin" diff --git a/qtbase.pro b/qtbase.pro index ecbb183471..c28bc9382b 100644 --- a/qtbase.pro +++ b/qtbase.pro @@ -135,6 +135,11 @@ syncqt.files=$$QT_BUILD_TREE/bin/syncqt win32:syncqt.files=$$QT_BUILD_TREE/bin/syncqt.bat INSTALLS += syncqt +#qtmodule-configtests +configtests.path=$$[QT_INSTALL_BINS] +configtests.files=$$QT_BUILD_TREE/bin/qtmodule-configtests +INSTALLS += configtests + #mkspecs mkspecs.path=$$[QT_INSTALL_DATA]/mkspecs mkspecs.files=$$QT_BUILD_TREE/mkspecs/qconfig.pri $$files($$QT_SOURCE_TREE/mkspecs/*) diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index 698b6a381e..f76b9930a7 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -221,6 +221,12 @@ Configure::Configure(int& argc, char** argv) createpackage_bat.close(); } + QFile configtests(buildPath + "/bin/qtmodule-configtests"); + if (configtests.open(QFile::WriteOnly)) { + QTextStream stream(&configtests); + stream << "#!/usr/bin/perl -w" << endl + << "require \"" << sourcePath + "/bin/qtmodule-configtests\";" << endl; + } // For Windows CE and shadow builds we need to copy these to the // build directory. QFile::copy(sourcePath + "/bin/setcepaths.bat" , buildPath + "/bin/setcepaths.bat"); From 4ed3ac722e17a10a17f75d7050b837edb09441fd Mon Sep 17 00:00:00 2001 From: Michael Goddard Date: Tue, 26 Jul 2011 12:10:01 +0200 Subject: [PATCH 41/75] Revert "test: unmark tst_QWidget::getSetCheck() as "insignificant" for Linux" This reverts commit 33cb4ff4d45ddf389a7c676b36ddaf45f20b2f37 Test still seems unstable :( Change-Id: I20d9c393e1553abba2a335532bee4e3ba716d8ce Reviewed-on: http://codereview.qt.nokia.com/2179 Reviewed-by: Qt Sanity Bot Reviewed-by: Michael Goddard --- tests/auto/qwidget/qwidget.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qwidget/qwidget.pro b/tests/auto/qwidget/qwidget.pro index a8cfecf4c3..0cd4a70e99 100644 --- a/tests/auto/qwidget/qwidget.pro +++ b/tests/auto/qwidget/qwidget.pro @@ -25,4 +25,4 @@ symbian { !wince*:!symbian:win32: LIBS += -luser32 -lgdi32 -mac:CONFIG+=insignificant_test +CONFIG+=insignificant_test From 1cd497a14ed1823a574f088ad11fcd9548095bed Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Thu, 28 Jul 2011 08:41:50 +1000 Subject: [PATCH 42/75] Mark tst_qsslcertificate::verify with QEXPECT_FAIL Test started to fail, complains about outdated SSL certificate. Task-number: QTBUG-20582 Change-Id: I2622375d9bc7b446dbbc18f72403896c60a8dee1 Reviewed-on: http://codereview.qt.nokia.com/2307 Reviewed-by: Qt Sanity Bot Reviewed-by: Jonas Rabbe --- tests/auto/qsslcertificate/tst_qsslcertificate.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/auto/qsslcertificate/tst_qsslcertificate.cpp b/tests/auto/qsslcertificate/tst_qsslcertificate.cpp index 451465df0c..1b3d039ded 100644 --- a/tests/auto/qsslcertificate/tst_qsslcertificate.cpp +++ b/tests/auto/qsslcertificate/tst_qsslcertificate.cpp @@ -920,6 +920,7 @@ void tst_QSslCertificate::verify() toVerify = QSslCertificate::fromPath(SRCDIR "verify-certs/test-ocsp-good-cert.pem"); errors = QSslCertificate::verify(toVerify); + QEXPECT_FAIL("", "QTBUG-20582 fails since ~5am, 27th July 2011", Continue); QVERIFY(errors.count() == 0); errors.clear(); @@ -955,10 +956,12 @@ void tst_QSslCertificate::verify() toVerify << QSslCertificate::fromPath(SRCDIR "verify-certs/test-intermediate-is-ca-cert.pem").first(); toVerify << QSslCertificate::fromPath(SRCDIR "verify-certs/test-intermediate-ca-cert.pem").first(); errors = QSslCertificate::verify(toVerify); + QEXPECT_FAIL("", "QTBUG-20582 fails since ~5am, 27th July 2011", Continue); QVERIFY(errors.length() == 0); // Recheck the above with hostname validation errors = QSslCertificate::verify(toVerify, QLatin1String("example.com")); + QEXPECT_FAIL("", "QTBUG-20582 fails since ~5am, 27th July 2011", Continue); QVERIFY(errors.length() == 0); // Recheck the above with a bad hostname From 3ca3ea4742f937185a1d64f93f9a687147c97212 Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Thu, 28 Jul 2011 11:48:28 +1000 Subject: [PATCH 43/75] configure: fixed setting of CFG_MAC_ARCHS for mac qpa builds Previously, the mac arch was only put into qconfig.pri for carbon and cocoa builds. Make sure it is also available for qpa builds. This is needed for projects which need to select architecture-specific sources in their .pro file. Change-Id: I5f72e3b699b11dafc4dae052620913f2b9b81d0a Reviewed-on: http://codereview.qt.nokia.com/2313 Reviewed-by: Qt Sanity Bot Reviewed-by: Marius Storm-Olsen --- configure | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 2bd5c06351..74162cab6a 100755 --- a/configure +++ b/configure @@ -6877,7 +6877,7 @@ fi # For "-carbon" builds: 32 bit x86/ppc. # For builds on snow leopard : compiler default (64-bit). # For builds on leopard : compiler default (32-bit). -if [ "$PLATFORM_MAC" = "yes" ] && [ "$CFG_MAC_ARCHS" = "" ]; then +if [ "$CFG_ARCH" = "macosx" ] && [ "$CFG_MAC_ARCHS" = "" ]; then source "$mactests/defaultarch.test" "$TEST_COMPILER" "$OPT_VERBOSE" "$mactests" if [ "$CFG_MAC_CARBON" = "yes" ]; then @@ -7129,7 +7129,7 @@ fi [ "$CFG_AVX" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG avx" [ "$CFG_IWMMXT" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG iwmmxt" [ "$CFG_NEON" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG neon" -[ "$PLATFORM_MAC" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG $CFG_MAC_ARCHS" +[ "$CFG_ARCH" = "macosx" ] && QMAKE_CONFIG="$QMAKE_CONFIG $CFG_MAC_ARCHS" if [ "$CFG_CLOCK_GETTIME" = "yes" ]; then QT_CONFIG="$QT_CONFIG clock-gettime" fi @@ -8598,7 +8598,7 @@ else echo "Building for: $XPLATFORM" fi -if [ "$PLATFORM_MAC" = "yes" ]; then +if [ ! -z "$CFG_MAC_ARCHS" ]; then echo "Architecture: $CFG_ARCH ($CFG_MAC_ARCHS )" else echo "Architecture: $CFG_ARCH" From d692b8663c062e3b7f146529d29194ca8724f214 Mon Sep 17 00:00:00 2001 From: Jason McDonald Date: Tue, 26 Jul 2011 16:11:03 +1000 Subject: [PATCH 44/75] Fix obsolete contact email Replace the old Trolltech contact email address with the current Qt contact email address. Task-number: QTBUG-20370 Change-Id: If5b9c3a044e1ee46264548eea456c704ced8e363 Reviewed-on: http://codereview.qt.nokia.com/2153 Reviewed-by: Qt Sanity Bot Reviewed-by: Rohan McGovern --- configure | 2 +- examples/tutorials/addressbook-fr/README | 2 +- examples/tutorials/addressbook/README | 2 +- src/corelib/global/qglobal.h | 4 ++-- src/corelib/io/qfilesystemwatcher_inotify.cpp | 2 +- src/gui/kernel/qkeymapper_x11.cpp | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/configure b/configure index 74162cab6a..877b13eb96 100755 --- a/configure +++ b/configure @@ -2970,7 +2970,7 @@ if [ '!' -f "${XQMAKESPEC}/qplatformdefs.h" ]; then echo echo " $XQMAKESPEC/qplatformdefs.h" echo - echo " Please contact qt-bugs@trolltech.com." + echo " Please contact qt-info@nokia.com." echo exit 2 fi diff --git a/examples/tutorials/addressbook-fr/README b/examples/tutorials/addressbook-fr/README index 359859390e..5f82d3ce38 100644 --- a/examples/tutorials/addressbook-fr/README +++ b/examples/tutorials/addressbook-fr/README @@ -39,4 +39,4 @@ qmake -spec macx-xcode Then open the generated Xcode project in Xcode and build it. -Feel free to send comments about the tutorial to qt-bugs@trolltech.com. +Feel free to send comments about the tutorial to qt-info@nokia.com. diff --git a/examples/tutorials/addressbook/README b/examples/tutorials/addressbook/README index 20ae7f3ada..5f364d909c 100644 --- a/examples/tutorials/addressbook/README +++ b/examples/tutorials/addressbook/README @@ -39,4 +39,4 @@ qmake -spec macx-xcode Then open the generated Xcode project in Xcode and build it. -Feel free to send comments about the tutorial to qt-bugs@trolltech.com. +Feel free to send comments about the tutorial to qt-info@nokia.com. diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 6dfe805a92..56022a7e6e 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -281,7 +281,7 @@ namespace QT_NAMESPACE {} # define Q_OS_VXWORKS #elif defined(__MAKEDEPEND__) #else -# error "Qt has not been ported to this OS - talk to qt-bugs@trolltech.com" +# error "Qt has not been ported to this OS - talk to qt-info@nokia.com" #endif #if defined(Q_OS_WIN32) || defined(Q_OS_WIN64) || defined(Q_OS_WINCE) @@ -803,7 +803,7 @@ namespace QT_NAMESPACE {} # define Q_CC_NOKIAX86 #else -# error "Qt has not been tested with this compiler - talk to qt-bugs@trolltech.com" +# error "Qt has not been tested with this compiler - talk to qt-info@nokia.com" #endif diff --git a/src/corelib/io/qfilesystemwatcher_inotify.cpp b/src/corelib/io/qfilesystemwatcher_inotify.cpp index 5c5223eb1c..ef302243da 100644 --- a/src/corelib/io/qfilesystemwatcher_inotify.cpp +++ b/src/corelib/io/qfilesystemwatcher_inotify.cpp @@ -131,7 +131,7 @@ # define __NR_inotify_rm_watch 286 # define __NR_inotify_init1 328 #else -# error "This architecture is not supported. Please talk to qt-bugs@trolltech.com" +# error "This architecture is not supported. Please talk to qt-info@nokia.com" #endif #if !defined(IN_CLOEXEC) && defined(O_CLOEXEC) && defined(__NR_inotify_init1) diff --git a/src/gui/kernel/qkeymapper_x11.cpp b/src/gui/kernel/qkeymapper_x11.cpp index e243716f6a..455840f8b2 100644 --- a/src/gui/kernel/qkeymapper_x11.cpp +++ b/src/gui/kernel/qkeymapper_x11.cpp @@ -513,7 +513,7 @@ void QKeyMapperPrivate::clearMappings() // ### ??? // if (keyboardLayoutName.isEmpty()) - // qWarning("Qt: unable to determine keyboard layout, please talk to qt-bugs@trolltech.com"); ? + // qWarning("Qt: unable to determine keyboard layout, please talk to qt-info@nokia.com"); ? keyboardInputLocale = q_getKeyboardLocale(layoutName, variantName); keyboardInputDirection = keyboardInputLocale.textDirection(); From a7860d8bf18d1330718fd0dfdc694c92ec69f069 Mon Sep 17 00:00:00 2001 From: Jason McDonald Date: Tue, 26 Jul 2011 15:22:37 +1000 Subject: [PATCH 45/75] Fix typo in padnavigator example docs Change-Id: Ifde02273107441add4eb77d8fc092eac2cc2c798 Reviewed-on: http://codereview.qt.nokia.com/2150 Reviewed-by: Qt Sanity Bot Reviewed-by: Rohan McGovern --- doc/src/examples/padnavigator.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/examples/padnavigator.qdoc b/doc/src/examples/padnavigator.qdoc index 0942c82215..591d3d0e63 100644 --- a/doc/src/examples/padnavigator.qdoc +++ b/doc/src/examples/padnavigator.qdoc @@ -316,7 +316,7 @@ Now we construct the \c FlippablePad item, passing its column-row count to its constructor. - The pad is constrolled by three transformations, and we create one + The pad is controlled by three transformations, and we create one QGraphicsRotation object for each of these. \list From 4f59b5b5308011fdc4bb08bc179d5298077fd9ad Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 25 Jul 2011 16:58:46 +1000 Subject: [PATCH 46/75] Emit selectionChanged signals when input method alters selection. Mark the selection as dirty if an input method event contains a selection and emit selectionChanged() if it's not emitted by finishChange(). Task-number: QTBUG-19731 Change-Id: Ief6f06f40071f64dae4db0ba365676c059a39c7e Reviewed-on: http://codereview.qt.nokia.com/2081 Reviewed-by: Qt Sanity Bot Reviewed-by: Andrew den Exter --- src/gui/widgets/qlinecontrol.cpp | 17 ++++++++++++----- tests/auto/qlineedit/tst_qlineedit.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index 550b5cf947..59374466d6 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -494,6 +494,7 @@ void QLineControl::processInputMethodEvent(QInputMethodEvent *event) if (m_selend < m_selstart) { qSwap(m_selstart, m_selend); } + m_selDirty = true; } else { m_selstart = m_selend = 0; } @@ -525,12 +526,18 @@ void QLineControl::processInputMethodEvent(QInputMethodEvent *event) } m_textLayout.setAdditionalFormats(formats); updateDisplayText(/*force*/ true); - if (cursorPositionChanged) - emitCursorPositionChanged(); - else if (m_preeditCursor != oldPreeditCursor) - emit updateMicroFocus(); - if (isGettingInput) + if (isGettingInput) { finishChange(priorState); + } else { + if (cursorPositionChanged) + emitCursorPositionChanged(); + else if (m_preeditCursor != oldPreeditCursor) + emit updateMicroFocus(); + if (m_selDirty) { + m_selDirty = false; + emit selectionChanged(); + } + } } /*! diff --git a/tests/auto/qlineedit/tst_qlineedit.cpp b/tests/auto/qlineedit/tst_qlineedit.cpp index 72b402f69d..68e88a87ed 100644 --- a/tests/auto/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/qlineedit/tst_qlineedit.cpp @@ -290,6 +290,7 @@ private slots: void bidiLogicalMovement(); void selectAndCursorPosition(); + void inputMethodSelection(); protected slots: void editingFinished(); @@ -3883,5 +3884,28 @@ void tst_QLineEdit::selectAndCursorPosition() QCOMPARE(testWidget->cursorPosition(), 0); } +void tst_QLineEdit::inputMethodSelection() +{ + testWidget->setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + testWidget->setSelection(0,0); + QSignalSpy selectionSpy(testWidget, SIGNAL(selectionChanged())); + + QCOMPARE(selectionSpy.count(), 0); + QCOMPARE(testWidget->selectionStart(), -1); + + testWidget->setSelection(0,5); + + QCOMPARE(selectionSpy.count(), 1); + QCOMPARE(testWidget->selectionStart(), 0); + + QList attributes; + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 12, 5, QVariant()); + QInputMethodEvent event("", attributes); + QApplication::sendEvent(testWidget, &event); + + QCOMPARE(selectionSpy.count(), 2); + QCOMPARE(testWidget->selectionStart(), 12); +} + QTEST_MAIN(tst_QLineEdit) #include "tst_qlineedit.moc" From 404126d578ee351ec42856e351412d20ff5faf0b Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 27 Jul 2011 19:01:15 +0200 Subject: [PATCH 47/75] Get rid of compiler warnings with MSVC Change-Id: Ibd027c502a5b8bcbfc6dae71c4f244f1080d4064 Reviewed-on: http://codereview.qt.nokia.com/2303 Reviewed-by: Qt Sanity Bot Reviewed-by: Oswald Buddenhagen --- src/corelib/tools/qbytearray.cpp | 21 +++++++++++---------- src/corelib/tools/qbytearray.h | 4 ++-- src/corelib/tools/qstring.cpp | 18 +++++++++--------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 9f21b72bfd..11ebd8a103 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -904,7 +904,7 @@ QByteArray &QByteArray::operator=(const char *str) x = const_cast(&shared_empty.ba); } else { int len = qstrlen(str); - if (d->ref != 1 || len > d->alloc || (len < d->size && len < d->alloc >> 1)) + if (d->ref != 1 || len > int(d->alloc) || (len < d->size && len < int(d->alloc) >> 1)) realloc(len); x = d; memcpy(x->data(), str, len + 1); // include null terminator @@ -1432,9 +1432,10 @@ void QByteArray::resize(int size) x->data()[size] = '\0'; d = x; } else { - if (d->ref != 1 || size > d->alloc || (!d->capacityReserved && size < d->size && size < d->alloc >> 1)) + if (d->ref != 1 || size > int(d->alloc) + || (!d->capacityReserved && size < d->size && size < int(d->alloc) >> 1)) realloc(qAllocMore(size, sizeof(Data))); - if (d->alloc >= size) { + if (int(d->alloc) >= size) { d->size = size; d->data()[size] = '\0'; } @@ -1563,7 +1564,7 @@ QByteArray &QByteArray::prepend(const char *str) QByteArray &QByteArray::prepend(const char *str, int len) { if (str) { - if (d->ref != 1 || d->size + len > d->alloc) + if (d->ref != 1 || d->size + len > int(d->alloc)) realloc(qAllocMore(d->size + len, sizeof(Data))); memmove(d->data()+len, d->data(), d->size); memcpy(d->data(), str, len); @@ -1581,7 +1582,7 @@ QByteArray &QByteArray::prepend(const char *str, int len) QByteArray &QByteArray::prepend(char ch) { - if (d->ref != 1 || d->size + 1 > d->alloc) + if (d->ref != 1 || d->size + 1 > int(d->alloc)) realloc(qAllocMore(d->size + 1, sizeof(Data))); memmove(d->data()+1, d->data(), d->size); d->data()[0] = ch; @@ -1619,7 +1620,7 @@ QByteArray &QByteArray::append(const QByteArray &ba) if ((d == &shared_null.ba || d == &shared_empty.ba) && !IS_RAW_DATA(ba.d)) { *this = ba; } else if (ba.d != &shared_null.ba) { - if (d->ref != 1 || d->size + ba.d->size > d->alloc) + if (d->ref != 1 || d->size + ba.d->size > int(d->alloc)) realloc(qAllocMore(d->size + ba.d->size, sizeof(Data))); memcpy(d->data() + d->size, ba.d->data(), ba.d->size); d->size += ba.d->size; @@ -1653,7 +1654,7 @@ QByteArray& QByteArray::append(const char *str) { if (str) { int len = qstrlen(str); - if (d->ref != 1 || d->size + len > d->alloc) + if (d->ref != 1 || d->size + len > int(d->alloc)) realloc(qAllocMore(d->size + len, sizeof(Data))); memcpy(d->data() + d->size, str, len + 1); // include null terminator d->size += len; @@ -1678,7 +1679,7 @@ QByteArray &QByteArray::append(const char *str, int len) if (len < 0) len = qstrlen(str); if (str && len) { - if (d->ref != 1 || d->size + len > d->alloc) + if (d->ref != 1 || d->size + len > int(d->alloc)) realloc(qAllocMore(d->size + len, sizeof(Data))); memcpy(d->data() + d->size, str, len); // include null terminator d->size += len; @@ -1695,7 +1696,7 @@ QByteArray &QByteArray::append(const char *str, int len) QByteArray& QByteArray::append(char ch) { - if (d->ref != 1 || d->size + 1 > d->alloc) + if (d->ref != 1 || d->size + 1 > int(d->alloc)) realloc(qAllocMore(d->size + 1, sizeof(Data))); d->data()[d->size++] = ch; d->data()[d->size] = '\0'; @@ -2204,7 +2205,7 @@ QByteArray QByteArray::repeated(int times) const QByteArray result; result.reserve(resultSize); - if (result.d->alloc != resultSize) + if (int(result.d->alloc) != resultSize) return QByteArray(); // not enough memory memcpy(result.d->data(), d->data(), d->size); diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h index 4190ffa18a..5cf4c15179 100644 --- a/src/corelib/tools/qbytearray.h +++ b/src/corelib/tools/qbytearray.h @@ -439,10 +439,10 @@ inline int QByteArray::capacity() const { return d->alloc; } inline void QByteArray::reserve(int asize) -{ if (d->ref != 1 || asize > d->alloc) realloc(asize); d->capacityReserved = true; } +{ if (d->ref != 1 || asize > int(d->alloc)) realloc(asize); d->capacityReserved = true; } inline void QByteArray::squeeze() -{ if (d->size < d->alloc) realloc(d->size); d->capacityReserved = false; } +{ if (d->size < int(d->alloc)) realloc(d->size); d->capacityReserved = false; } class Q_CORE_EXPORT QByteRef { QByteArray &a; diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 9e238193a3..9ce5eead8c 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -1267,10 +1267,10 @@ void QString::resize(int size) QString::free(d); d = x; } else { - if (d->ref != 1 || size > d->alloc || - (!d->capacityReserved && size < d->size && size < d->alloc >> 1)) + if (d->ref != 1 || size > int(d->alloc) || + (!d->capacityReserved && size < d->size && size < int(d->alloc) >> 1)) realloc(grow(size)); - if (d->alloc >= size) { + if (int(d->alloc) >= size) { d->size = size; d->data()[size] = '\0'; } @@ -1560,7 +1560,7 @@ QString &QString::append(const QString &str) if (d == &shared_null.str) { operator=(str); } else { - if (d->ref != 1 || d->size + str.d->size > d->alloc) + if (d->ref != 1 || d->size + str.d->size > int(d->alloc)) realloc(grow(d->size + str.d->size)); memcpy(d->data() + d->size, str.d->data(), str.d->size * sizeof(QChar)); d->size += str.d->size; @@ -1580,7 +1580,7 @@ QString &QString::append(const QLatin1String &str) const uchar *s = (const uchar *)str.latin1(); if (s) { int len = qstrlen((char *)s); - if (d->ref != 1 || d->size + len > d->alloc) + if (d->ref != 1 || d->size + len > int(d->alloc)) realloc(grow(d->size + len)); ushort *i = d->data() + d->size; while ((*i++ = *s++)) @@ -1623,7 +1623,7 @@ QString &QString::append(const QLatin1String &str) */ QString &QString::append(QChar ch) { - if (d->ref != 1 || d->size + 1 > d->alloc) + if (d->ref != 1 || d->size + 1 > int(d->alloc)) realloc(grow(d->size + 1)); d->data()[d->size++] = ch.unicode(); d->data()[d->size] = '\0'; @@ -3550,8 +3550,8 @@ static QByteArray toLatin1_helper(const QChar *data, int length) const __m128i questionMark = _mm_set1_epi16('?'); // SSE has no compare instruction for unsigned comparison. // The variables must be shiffted + 0x8000 to be compared - const __m128i signedBitOffset = _mm_set1_epi16(0x8000); - const __m128i thresholdMask = _mm_set1_epi16(0xff + 0x8000); + const __m128i signedBitOffset = _mm_set1_epi16(short(0x8000)); + const __m128i thresholdMask = _mm_set1_epi16(short(0xff + 0x8000)); for (int i = 0; i < chunkCount; ++i) { __m128i chunk1 = _mm_loadu_si128((__m128i*)src); // load src += 8; @@ -6152,7 +6152,7 @@ QString QString::repeated(int times) const QString result; result.reserve(resultSize); - if (result.d->alloc != resultSize) + if (int(result.d->alloc) != resultSize) return QString(); // not enough memory memcpy(result.d->data(), d->data(), d->size * sizeof(ushort)); From 85f05924f48c95192787555f0bc025338286d3f5 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Mon, 25 Jul 2011 14:38:24 +0200 Subject: [PATCH 48/75] Added meta type info for Q[Explicitly]SharedDataPointer Change-Id: I1269630ae5154f7318e1c7ae9fa2014a15234bf4 Reviewed-on: http://codereview.qt.nokia.com/2110 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/tools/qshareddata.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/corelib/tools/qshareddata.h b/src/corelib/tools/qshareddata.h index 9b404bdf0c..811b186e8b 100644 --- a/src/corelib/tools/qshareddata.h +++ b/src/corelib/tools/qshareddata.h @@ -279,6 +279,9 @@ namespace std { QT_BEGIN_NAMESPACE #endif +template Q_DECLARE_TYPEINFO_BODY(QSharedDataPointer, Q_MOVABLE_TYPE); +template Q_DECLARE_TYPEINFO_BODY(QExplicitlySharedDataPointer, Q_MOVABLE_TYPE); + QT_END_NAMESPACE QT_END_HEADER From ade2ef0a3e2fcf92a153f5e44f726ee603df12aa Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Fri, 3 Jun 2011 08:17:40 +0200 Subject: [PATCH 49/75] Make it possible to update a related table after an external update When a table that is related to in a QSqlRelationalTableModel gets updated in some way (e.g. a new row, or the data is changed) then the related model could not be updated without recreating the QSqlRelationalTableModel. Now, to get around this, select() can be called on the related model to get it to be updated. Task-number: QTBUG-7885 Reviewed-by: Charles Yin Reviewed-by: Michael Goddard Change-Id: Ic589e840234f3a809bcb112a807a87afe0bc25ca (cherry picked from commit 2c60a4f67f9fb02f3b711fe749b2f293a07b4e02) Reviewed-on: http://codereview.qt.nokia.com/2224 Reviewed-by: Charles Yin --- src/sql/models/qsqlrelationaltablemodel.cpp | 36 +++++++++++++++++-- .../tst_qsqlrelationaltablemodel.cpp | 23 ++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/sql/models/qsqlrelationaltablemodel.cpp b/src/sql/models/qsqlrelationaltablemodel.cpp index f6c401842f..5b0406f4b0 100644 --- a/src/sql/models/qsqlrelationaltablemodel.cpp +++ b/src/sql/models/qsqlrelationaltablemodel.cpp @@ -119,6 +119,8 @@ QT_BEGIN_NAMESPACE returns false. */ +class QRelatedTableModel; + struct QRelation { public: @@ -135,7 +137,7 @@ struct QRelation bool isValid(); QSqlRelation rel; - QSqlTableModel *model; + QRelatedTableModel *model; QHash dictionary;//maps keys to display values private: @@ -143,6 +145,15 @@ struct QRelation bool m_dictInitialized; }; +class QRelatedTableModel : public QSqlTableModel +{ +public: + QRelatedTableModel(QRelation *rel, QObject *parent = 0, QSqlDatabase db = QSqlDatabase()); + bool select(); +private: + bool firstSelect; + QRelation *relation; +}; /* A QRelation must be initialized before it is considered valid. Note: population of the model and dictionary are kept separate @@ -162,7 +173,7 @@ void QRelation::populateModel() Q_ASSERT(m_parent != NULL); if (!model) { - model = new QSqlTableModel(m_parent, m_parent->database()); + model = new QRelatedTableModel(this, m_parent, m_parent->database()); model->setTable(rel.tableName()); model->select(); } @@ -219,6 +230,27 @@ bool QRelation::isValid() return (rel.isValid() && m_parent != NULL); } + + +QRelatedTableModel::QRelatedTableModel(QRelation *rel, QObject *parent, QSqlDatabase db) : + QSqlTableModel(parent, db), firstSelect(true), relation(rel) +{ +} + +bool QRelatedTableModel::select() +{ + if (firstSelect) { + firstSelect = false; + return QSqlTableModel::select(); + } + relation->clearDictionary(); + bool res = QSqlTableModel::select(); + if (res) + relation->populateDictionary(); + return res; +} + + class QSqlRelationalTableModelPrivate: public QSqlTableModelPrivate { Q_DECLARE_PUBLIC(QSqlRelationalTableModel) diff --git a/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp b/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp index cc4ab67d53..5f1a6211aa 100644 --- a/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp +++ b/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp @@ -92,6 +92,7 @@ private slots: void escapedTableName(); void whiteSpaceInIdentifiers(); void psqlSchemaTest(); + void selectAfterUpdate(); private: void dropTestTables( QSqlDatabase db ); @@ -1467,5 +1468,27 @@ void tst_QSqlRelationalTableModel::psqlSchemaTest() QVERIFY_SQL(model, select()); } +void tst_QSqlRelationalTableModel::selectAfterUpdate() +{ + QFETCH_GLOBAL(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + + QSqlRelationalTableModel model(0, db); + model.setTable(reltest1); + model.setRelation(2, QSqlRelation(reltest2, "tid", "title")); + QVERIFY_SQL(model, select()); + QVERIFY(model.relationModel(2)->rowCount() == 2); + { + QSqlQuery q(db); + QVERIFY_SQL(q, exec("insert into " + reltest2 + " values(3, 'mrs')")); + model.relationModel(2)->select(); + } + QVERIFY(model.relationModel(2)->rowCount() == 3); + QVERIFY(model.setData(model.index(0,2), 3)); + QVERIFY(model.submitAll()); + QCOMPARE(model.data(model.index(0,2)), QVariant("mrs")); +} + QTEST_MAIN(tst_QSqlRelationalTableModel) #include "tst_qsqlrelationaltablemodel.moc" From a2c0390468b91a3f8a97a3bbabc2f9c98e0d105a Mon Sep 17 00:00:00 2001 From: Charles Yin Date: Tue, 26 Jul 2011 13:46:54 +1000 Subject: [PATCH 50/75] Add notify signals for QIntvalidator, QDoubleValidator, QRegExpValidator Task-number:QTBUG-19956 Change-Id: I5ab5e4494189ece5b0eb1f63e73e49cb2c4e9656 Reviewed-by:Michael Brasser Reviewed-on: http://codereview.qt.nokia.com/2147 Reviewed-by: Qt Sanity Bot Reviewed-by: Michael Brasser --- src/gui/widgets/qvalidator.cpp | 101 ++++++++++++++++-- src/gui/widgets/qvalidator.h | 27 +++-- .../qdoublevalidator/tst_qdoublevalidator.cpp | 57 ++++++++++ .../auto/qintvalidator/tst_qintvalidator.cpp | 33 +++++- .../qregexpvalidator/tst_qregexpvalidator.cpp | 3 + 5 files changed, 204 insertions(+), 17 deletions(-) diff --git a/src/gui/widgets/qvalidator.cpp b/src/gui/widgets/qvalidator.cpp index b32bea8b7a..43251a8829 100644 --- a/src/gui/widgets/qvalidator.cpp +++ b/src/gui/widgets/qvalidator.cpp @@ -131,6 +131,69 @@ QT_BEGIN_NAMESPACE \omitvalue Valid */ + +/*! + \fn void QIntValidator::topChanged(int top) + + This signal is emitted after the top property changed. + + \sa QIntValidator::top(), QIntValidator::setTop(), QIntValidator::bottom(), QIntValidator::setBottom() + \internal +*/ + +/*! + \fn void QIntValidator::bottomChanged(int bottom) + + This signal is emitted after the bottom property changed. + + \sa QIntValidator::top(), QIntValidator::setTop(), QIntValidator::bottom(), QIntValidator::setBottom() + \internal +*/ + +/*! + \fn void QDoubleValidator::topChanged(int top) + + This signal is emitted after the top property changed. + + \sa QDoubleValidator::top(), QDoubleValidator::setTop(), QDoubleValidator::bottom(), QDoubleValidator::setBottom() + \internal +*/ + +/*! + \fn void QDoubleValidator::bottomChanged(int bottom) + + This signal is emitted after the bottom property changed. + + \sa QDoubleValidator::top(), QDoubleValidator::setTop(), QDoubleValidator::bottom(), QDoubleValidator::setBottom() + \internal +*/ + +/*! + \fn void QDoubleValidator::decimalsChanged(int decimals) + + This signal is emitted after the decimals property changed. + + \internal +*/ + +/*! + \fn void QDoubleValidator::notationChanged(QDoubleValidator::Notation notation) + + This signal is emitted after the notation property changed. + + QDoubleValidator::Notation is not a registered metatype, so for queued connections, + you will have to register it with Q_DECLARE_METATYPE() and qRegisterMetaType(). + + \internal +*/ + +/*! + \fn void QRegExpValidator::regExpChanged(const QRegExp ®Exp) + + This signal is emitted after the regExp property changed. + \internal +*/ + class QValidatorPrivate : public QObjectPrivate{ Q_DECLARE_PUBLIC(QValidator) public: @@ -436,8 +499,15 @@ void QIntValidator::fixup(QString &input) const void QIntValidator::setRange(int bottom, int top) { - b = bottom; - t = top; + if (b != bottom) { + b = bottom; + emit bottomChanged(b); + } + + if (t != top) { + t = top; + emit topChanged(t); + } } @@ -710,9 +780,20 @@ QValidator::State QDoubleValidatorPrivate::validateWithLocale(QString &input, QL void QDoubleValidator::setRange(double minimum, double maximum, int decimals) { - b = minimum; - t = maximum; - dec = decimals; + if (b != minimum) { + b = minimum; + emit bottomChanged(b); + } + + if (t != maximum) { + t = maximum; + emit topChanged(t); + } + + if (dec != decimals) { + dec = decimals; + emit decimalsChanged(dec); + } } /*! @@ -771,7 +852,10 @@ void QDoubleValidator::setDecimals(int decimals) void QDoubleValidator::setNotation(Notation newNotation) { Q_D(QDoubleValidator); - d->notation = newNotation; + if (d->notation != newNotation) { + d->notation = newNotation; + emit notationChanged(d->notation); + } } QDoubleValidator::Notation QDoubleValidator::notation() const @@ -915,7 +999,10 @@ QValidator::State QRegExpValidator::validate(QString &input, int& pos) const void QRegExpValidator::setRegExp(const QRegExp& rx) { - r = rx; + if (r != rx) { + r = rx; + emit regExpChanged(r); + } } #endif diff --git a/src/gui/widgets/qvalidator.h b/src/gui/widgets/qvalidator.h index 70f656e6a8..cb0436cc3e 100644 --- a/src/gui/widgets/qvalidator.h +++ b/src/gui/widgets/qvalidator.h @@ -96,8 +96,8 @@ private: class Q_GUI_EXPORT QIntValidator : public QValidator { Q_OBJECT - Q_PROPERTY(int bottom READ bottom WRITE setBottom) - Q_PROPERTY(int top READ top WRITE setTop) + Q_PROPERTY(int bottom READ bottom WRITE setBottom NOTIFY bottomChanged) + Q_PROPERTY(int top READ top WRITE setTop NOTIFY topChanged) public: explicit QIntValidator(QObject * parent = 0); @@ -113,7 +113,9 @@ public: int bottom() const { return b; } int top() const { return t; } - +Q_SIGNALS: + void bottomChanged(int bottom); + void topChanged(int top); #ifdef QT3_SUPPORT public: QT3_SUPPORT_CONSTRUCTOR QIntValidator(QObject * parent, const char *name); @@ -134,11 +136,11 @@ class QDoubleValidatorPrivate; class Q_GUI_EXPORT QDoubleValidator : public QValidator { Q_OBJECT - Q_PROPERTY(double bottom READ bottom WRITE setBottom) - Q_PROPERTY(double top READ top WRITE setTop) - Q_PROPERTY(int decimals READ decimals WRITE setDecimals) + Q_PROPERTY(double bottom READ bottom WRITE setBottom NOTIFY bottomChanged) + Q_PROPERTY(double top READ top WRITE setTop NOTIFY topChanged) + Q_PROPERTY(int decimals READ decimals WRITE setDecimals NOTIFY decimalsChanged) Q_ENUMS(Notation) - Q_PROPERTY(Notation notation READ notation WRITE setNotation) + Q_PROPERTY(Notation notation READ notation WRITE setNotation NOTIFY notationChanged) public: explicit QDoubleValidator(QObject * parent = 0); @@ -149,7 +151,6 @@ public: StandardNotation, ScientificNotation }; - QValidator::State validate(QString &, int &) const; virtual void setRange(double bottom, double top, int decimals = 0); @@ -163,6 +164,12 @@ public: int decimals() const { return dec; } Notation notation() const; +Q_SIGNALS: + void bottomChanged(double bottom); + void topChanged(double top); + void decimalsChanged(int decimals); + void notationChanged(QDoubleValidator::Notation notation); + #ifdef QT3_SUPPORT public: QT3_SUPPORT_CONSTRUCTOR QDoubleValidator(QObject * parent, const char *name); @@ -182,7 +189,7 @@ private: class Q_GUI_EXPORT QRegExpValidator : public QValidator { Q_OBJECT - Q_PROPERTY(QRegExp regExp READ regExp WRITE setRegExp) + Q_PROPERTY(QRegExp regExp READ regExp WRITE setRegExp NOTIFY regExpChanged) public: explicit QRegExpValidator(QObject *parent = 0); @@ -194,6 +201,8 @@ public: void setRegExp(const QRegExp& rx); const QRegExp& regExp() const { return r; } // ### make inline for 5.0 +Q_SIGNALS: + void regExpChanged(const QRegExp& regExp); #ifdef QT3_SUPPORT public: QT3_SUPPORT_CONSTRUCTOR QRegExpValidator(QObject *parent, const char *name); diff --git a/tests/auto/qdoublevalidator/tst_qdoublevalidator.cpp b/tests/auto/qdoublevalidator/tst_qdoublevalidator.cpp index 76d4494a39..6014ce5165 100644 --- a/tests/auto/qdoublevalidator/tst_qdoublevalidator.cpp +++ b/tests/auto/qdoublevalidator/tst_qdoublevalidator.cpp @@ -55,6 +55,7 @@ private slots: void validateThouSep(); void validateIntEquiv_data(); void validateIntEquiv(); + void notifySignals(); }; Q_DECLARE_METATYPE(QValidator::State); @@ -244,6 +245,62 @@ void tst_QDoubleValidator::validate() dv.setNotation(QDoubleValidator::StandardNotation); QCOMPARE((int)dv.validate(value, dummy), (int)standard_state); } +void tst_QDoubleValidator::notifySignals() +{ + QDoubleValidator dv(0.1, 0.9, 10, 0); + QSignalSpy topSpy(&dv, SIGNAL(topChanged(double))); + QSignalSpy bottomSpy(&dv, SIGNAL(bottomChanged(double))); + QSignalSpy decSpy(&dv, SIGNAL(decimalsChanged(int))); + + qRegisterMetaType("QDoubleValidator::Notation"); + QSignalSpy notSpy(&dv, SIGNAL(notationChanged(QDoubleValidator::Notation))); + + dv.setTop(0.8); + QCOMPARE(topSpy.count(), 1); + QVERIFY(dv.top() == 0.8); + dv.setBottom(0.2); + QCOMPARE(bottomSpy.count(), 1); + QVERIFY(dv.bottom() == 0.2); + + dv.setRange(0.2, 0.7); + QCOMPARE(topSpy.count(), 2); + QCOMPARE(bottomSpy.count(), 1); + QCOMPARE(decSpy.count(), 1); + QVERIFY(dv.bottom() == 0.2); + QVERIFY(dv.top() == 0.7); + QVERIFY(dv.decimals() == 0.); + + dv.setRange(0.3, 0.7); + QCOMPARE(topSpy.count(), 2); + QCOMPARE(bottomSpy.count(), 2); + QVERIFY(dv.bottom() == 0.3); + QVERIFY(dv.top() == 0.7); + QVERIFY(dv.decimals() == 0.); + + dv.setRange(0.4, 0.6); + QCOMPARE(topSpy.count(), 3); + QCOMPARE(bottomSpy.count(), 3); + QVERIFY(dv.bottom() == 0.4); + QVERIFY(dv.top() == 0.6); + QVERIFY(dv.decimals() == 0.); + + dv.setDecimals(10); + QCOMPARE(decSpy.count(), 2); + QVERIFY(dv.decimals() == 10.); + + + dv.setRange(0.4, 0.6, 100); + QCOMPARE(topSpy.count(), 3); + QCOMPARE(bottomSpy.count(), 3); + QCOMPARE(decSpy.count(), 3); + QVERIFY(dv.bottom() == 0.4); + QVERIFY(dv.top() == 0.6); + QVERIFY(dv.decimals() == 100.); + + dv.setNotation(QDoubleValidator::StandardNotation); + QCOMPARE(notSpy.count(), 1); + QVERIFY(dv.notation() == QDoubleValidator::StandardNotation); +} void tst_QDoubleValidator::validateIntEquiv_data() { diff --git a/tests/auto/qintvalidator/tst_qintvalidator.cpp b/tests/auto/qintvalidator/tst_qintvalidator.cpp index d53763566d..369e3254e8 100644 --- a/tests/auto/qintvalidator/tst_qintvalidator.cpp +++ b/tests/auto/qintvalidator/tst_qintvalidator.cpp @@ -51,6 +51,7 @@ private slots: void validate(); void validateArabic(); void validateFrench(); + void notifySignals(); }; Q_DECLARE_METATYPE(QValidator::State); @@ -189,7 +190,6 @@ void tst_QIntValidator::validateFrench() QIntValidator validator(-2000, 2000, 0); validator.setLocale(QLocale::French); int i; - QString s = QLatin1String("1 "); QCOMPARE(validator.validate(s, i), QValidator::Acceptable); validator.fixup(s); @@ -220,5 +220,36 @@ void tst_QIntValidator::validate() QCOMPARE((int)iv.validate(value, dummy), (int)state); } +void tst_QIntValidator::notifySignals() +{ + QIntValidator iv(0, 10, 0); + QSignalSpy topSpy(&iv, SIGNAL(topChanged(int))); + QSignalSpy bottomSpy(&iv, SIGNAL(bottomChanged(int))); + iv.setTop(9); + QCOMPARE(topSpy.count(), 1); + QVERIFY(iv.top() == 9); + iv.setBottom(1); + QCOMPARE(bottomSpy.count(), 1); + QVERIFY(iv.bottom() == 1); + + iv.setRange(1, 8); + QCOMPARE(topSpy.count(), 2); + QCOMPARE(bottomSpy.count(), 1); + QVERIFY(iv.top() == 8); + QVERIFY(iv.bottom() == 1); + + iv.setRange(2, 8); + QCOMPARE(topSpy.count(), 2); + QCOMPARE(bottomSpy.count(), 2); + QVERIFY(iv.top() == 8); + QVERIFY(iv.bottom() == 2); + + iv.setRange(3, 7); + QCOMPARE(topSpy.count(), 3); + QCOMPARE(bottomSpy.count(), 3); + QVERIFY(iv.top() == 7); + QVERIFY(iv.bottom() == 3); +} + QTEST_MAIN(tst_QIntValidator) #include "tst_qintvalidator.moc" diff --git a/tests/auto/qregexpvalidator/tst_qregexpvalidator.cpp b/tests/auto/qregexpvalidator/tst_qregexpvalidator.cpp index d8ef92a439..23cd5b1ef1 100644 --- a/tests/auto/qregexpvalidator/tst_qregexpvalidator.cpp +++ b/tests/auto/qregexpvalidator/tst_qregexpvalidator.cpp @@ -115,9 +115,12 @@ void tst_QRegExpValidator::validate() QFETCH( int, state ); QRegExpValidator rv( 0 ); + QSignalSpy spy(&rv, SIGNAL(regExpChanged(const QRegExp&))); + rv.setRegExp( QRegExp( rx ) ); int dummy; QCOMPARE( (int)rv.validate( value, dummy ), state ); + QCOMPARE(spy.count(), 1); } QTEST_MAIN(tst_QRegExpValidator) From 78cf553469bbfc0a5b4952d54ffe96566cae266c Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 29 Jul 2011 13:03:52 +1000 Subject: [PATCH 51/75] Flag meta objects generated by QtDBus QtDBus requires a QVariant argument to be passed to property reads and writes. For performance reasons QtDeclarative does not do this. By flagging the meta object as requiring this, QtDeclarative can do so only required. Task-number: QTBUG-15052 Change-Id: I032c946f079523f5f10217ed56642fb315265d9f Reviewed-on: http://codereview.qt.nokia.com/2365 Reviewed-by: Qt Sanity Bot Reviewed-by: Martin Jones --- src/corelib/kernel/qmetaobject_p.h | 3 ++- src/dbus/qdbusmetaobject.cpp | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h index 63605ecadb..5da936aab0 100644 --- a/src/corelib/kernel/qmetaobject_p.h +++ b/src/corelib/kernel/qmetaobject_p.h @@ -101,7 +101,8 @@ enum MethodFlags { }; enum MetaObjectFlags { - DynamicMetaObject = 0x01 + DynamicMetaObject = 0x01, + RequiresVariantMetaObject = 0x02 }; class QMutex; diff --git a/src/dbus/qdbusmetaobject.cpp b/src/dbus/qdbusmetaobject.cpp index d12642d632..8daf2300b7 100644 --- a/src/dbus/qdbusmetaobject.cpp +++ b/src/dbus/qdbusmetaobject.cpp @@ -125,6 +125,11 @@ private: MethodScriptable = 0x40 }; + enum MetaObjectFlags { + DynamicMetaObject = 0x01, + RequiresVariantMetaObject = 0x02 + }; + QMap methods; QMap properties; @@ -152,6 +157,8 @@ struct QDBusMetaObjectPrivate int methodCount, methodData; int propertyCount, propertyData; int enumeratorCount, enumeratorData; + int constructorCount, constructorData; // since revision 2 + int flags; // since revision 3 // this is specific for QDBusMetaObject: int propertyDBusData; @@ -416,7 +423,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj) idata.resize(sizeof(QDBusMetaObjectPrivate) / sizeof(int)); QDBusMetaObjectPrivate *header = reinterpret_cast(idata.data()); - header->revision = 1; + header->revision = 3; header->className = 0; header->classInfoCount = 0; header->classInfoData = 0; @@ -426,6 +433,9 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj) header->propertyData = header->methodData + header->methodCount * 5; header->enumeratorCount = 0; header->enumeratorData = 0; + header->constructorCount = 0; + header->constructorData = 0; + header->flags = RequiresVariantMetaObject; header->propertyDBusData = header->propertyData + header->propertyCount * 3; header->methodDBusData = header->propertyDBusData + header->propertyCount * intsPerProperty; From 487583459ea7958f24cd579888a662bcce26caf3 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Thu, 28 Jul 2011 14:51:54 +0200 Subject: [PATCH 52/75] Fix off-by-one error in binary search This one-line change makes the binary search in QTextEngine::findItem behave consistently with the linear search that it replaced in commit acf678e57ed088f3e56a551cac6c7c3322005750. The new behavior seems to cause crashes in kword (and perhaps other applications) by triggering a logClusters assert, although I have been unable to create a unit test that reproduces this. Task-number: QTBUG-17209 Done-by: Dr. Robert Marmorstein Change-Id: I68b79f024e9836e1cc8b0f3514889120541eb2ea Reviewed-on: http://codereview.qt.nokia.com/2343 Reviewed-by: Qt Sanity Bot Reviewed-by: Jiang Jiang --- src/gui/text/qtextengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 41ea56a23a..cca30e6e20 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1632,7 +1632,7 @@ bool QTextEngine::isRightToLeft() const int QTextEngine::findItem(int strPos) const { itemize(); - int left = 0; + int left = 1; int right = layoutData->items.size()-1; while(left <= right) { int middle = ((right-left)/2)+left; From 86a237929e2b67ce333b635b760e78c628effb60 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Sat, 2 Jul 2011 15:13:12 +0200 Subject: [PATCH 53/75] QMutex is now just a pointer And added a POD QBasicMutex. (QBasicMutex* can safely be static_cast'ed to QMutex*) The d pointer is not anymore always a QMutexPrivate. If d == 0x0: the mutex is unlocked If d == 0x1: the mutex is locked, uncontended On linux: if d == 0x3: the mutex is locked contended, waiting on a futex If d is a pointer, it is a recursive mutex. On non-linux platforms: When a thread tries to lock a mutex for which d == 0x1, it will try to assing it a QMutexPrivated (allocated from a freelist) in order to wait for it. Change-Id: Ie1431cd9402a576fdd9a693cfd747166eebf5622 Reviewed-by: Bradley T. Hughes Reviewed-on: http://codereview.qt.nokia.com/2116 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/kernel/qobject.cpp | 8 +- src/corelib/thread/qmutex.cpp | 441 ++++++++++-------- src/corelib/thread/qmutex.h | 121 ++--- src/corelib/thread/qmutex_linux.cpp | 138 ++++++ src/corelib/thread/qmutex_mac.cpp | 96 ++++ src/corelib/thread/qmutex_p.h | 70 ++- src/corelib/thread/qmutex_unix.cpp | 116 +---- src/corelib/thread/qmutex_win.cpp | 10 +- src/corelib/thread/qorderedmutexlocker_p.h | 12 +- src/corelib/thread/qwaitcondition_unix.cpp | 2 +- src/corelib/thread/qwaitcondition_win.cpp | 2 +- src/corelib/thread/thread.pri | 9 +- tests/auto/qmutex/tst_qmutex.cpp | 111 ++++- .../corelib/thread/qmutex/tst_qmutex.cpp | 11 - 14 files changed, 685 insertions(+), 462 deletions(-) create mode 100644 src/corelib/thread/qmutex_linux.cpp create mode 100644 src/corelib/thread/qmutex_mac.cpp diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 27edbdacac..ab9314ce53 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -878,7 +878,7 @@ QObject::~QObject() if (c->next) c->next->prev = c->prev; } if (needToUnlock) - m->unlockInline(); + m->unlock(); connectionList.first = c->nextConnectionList; delete c; @@ -902,7 +902,7 @@ QObject::~QObject() bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m); //the node has maybe been removed while the mutex was unlocked in relock? if (!node || node->sender != sender) { - m->unlockInline(); + m->unlock(); continue; } node->receiver = 0; @@ -912,7 +912,7 @@ QObject::~QObject() node = node->next; if (needToUnlock) - m->unlockInline(); + m->unlock(); } } @@ -3076,7 +3076,7 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, } if (needToUnlock) - receiverMutex->unlockInline(); + receiverMutex->unlock(); c->receiver = 0; diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 3e3bf8ff13..c90b44be6c 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -49,8 +49,25 @@ #include "qthread.h" #include "qmutex_p.h" +#ifndef Q_OS_LINUX +#include "private/qfreelist_p.h" +#endif + QT_BEGIN_NAMESPACE +/*! + \class QBasicMutex + \brief QMutex POD + \internal + + \ingroup thread + + - Can be used as global static object. + - Always non-recursive + - Do not use tryLock with timeout > 0, else you can have a leak (see the ~QMutex destructor) +*/ + + /*! \class QMutex \brief The QMutex class provides access serialization between threads. @@ -122,8 +139,12 @@ QT_BEGIN_NAMESPACE \sa lock(), unlock() */ QMutex::QMutex(RecursionMode mode) - : d(new QMutexPrivate(mode)) -{ } +{ + if (mode == Recursive) + d = new QRecursiveMutexPrivate; + else + d = 0; +} /*! Destroys the mutex. @@ -131,9 +152,18 @@ QMutex::QMutex(RecursionMode mode) \warning Destroying a locked mutex may result in undefined behavior. */ QMutex::~QMutex() -{ delete static_cast(d); } +{ + if (isRecursive()) + delete static_cast(d._q_value); + else if (d) { +#ifndef Q_OS_LINUX + if (d->possiblyUnlocked && tryLock()) { unlock(); return; } +#endif + qWarning("QMutex: destroying locked mutex"); + } +} -/*! +/*! \fn void QMutex::lock() Locks the mutex. If another thread has locked the mutex then this call will block until that thread has unlocked it. @@ -145,40 +175,8 @@ QMutex::~QMutex() \sa unlock() */ -void QMutex::lock() -{ - QMutexPrivate *d = static_cast(this->d); - Qt::HANDLE self; - if (d->recursive) { - self = QThread::currentThreadId(); - if (d->owner == self) { - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::lock", "Overflow in recursion counter"); - return; - } - - 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."); - } - - d->owner = self; - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::lock", "Overflow in recursion counter"); - return; - } - - bool isLocked = d->contenders.testAndSetAcquire(0, 1); - if (!isLocked) { - lockInternal(); - } -} - -/*! +/*!\fn bool QMutex::trylock() Attempts to lock the mutex. If the lock was obtained, this function returns true. If another thread has locked the mutex, this function returns false immediately. @@ -195,36 +193,9 @@ void QMutex::lock() \sa lock(), unlock() */ -bool QMutex::tryLock() -{ - QMutexPrivate *d = static_cast(this->d); - Qt::HANDLE self; - if (d->recursive) { - self = QThread::currentThreadId(); - if (d->owner == self) { - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter"); - return true; - } - - 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 - return isLocked; - } - - d->owner = self; - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter"); - return isLocked; - } - - return d->contenders.testAndSetAcquire(0, 1); -} - -/*! \overload +/*! \fn bool QMutex::tryLock(int timeout) + \overload Attempts to lock the mutex. This function returns true if the lock was obtained; otherwise it returns false. If another thread has @@ -247,81 +218,30 @@ bool QMutex::tryLock() \sa lock(), unlock() */ -bool QMutex::tryLock(int timeout) -{ - QMutexPrivate *d = static_cast(this->d); - Qt::HANDLE self; - - if (d->recursive) { - self = QThread::currentThreadId(); - if (d->owner == self) { - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter"); - return true; - } - - bool isLocked = d->contenders.testAndSetAcquire(0, 1); - if (!isLocked) { - // didn't get the lock, wait for it - isLocked = d->wait(timeout); - if (!isLocked) - return false; - } - - d->owner = self; - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter"); - return true; - } - - return (d->contenders.testAndSetAcquire(0, 1) - // didn't get the lock, wait for it - || d->wait(timeout)); -} -/*! +/*! \fn void QMutex::unlock() Unlocks the mutex. Attempting to unlock a mutex in a different thread to the one that locked it results in an error. Unlocking a mutex that is not locked results in undefined behavior. \sa lock() */ -void QMutex::unlock() -{ - QMutexPrivate *d = static_cast(this->d); - if (d->recursive) { - if (!--d->count) { - d->owner = 0; - if (!d->contenders.testAndSetRelease(1, 0)) - d->wakeUp(); - } - } else { - if (!d->contenders.testAndSetRelease(1, 0)) - d->wakeUp(); - } -} /*! - \fn bool QMutex::locked() + \fn void QMutex::isRecursive() + \since 5.0 - Returns true if the mutex is locked by another thread; otherwise - returns false. + Returns true if the mutex is recursive - It is generally a bad idea to use this function, because code - that uses it has a race condition. Use tryLock() and unlock() - instead. - - \oldcode - bool isLocked = mutex.locked(); - \newcode - bool isLocked = true; - if (mutex.tryLock()) { - mutex.unlock(); - isLocked = false; - } - \endcode */ +bool QBasicMutex::isRecursive() { + QMutexPrivate *d = this->d; + if (quintptr(d) <= 0x3) + return false; + return d->recursive; +} + /*! \class QMutexLocker @@ -418,96 +338,217 @@ void QMutex::unlock() \sa unlock() */ +#ifndef Q_OS_LINUX //linux implementation is in qmutex_linux.cpp /*! - \fn QMutex::QMutex(bool recursive) - - Use the constructor that takes a RecursionMode parameter instead. -*/ - -/*! - \internal helper for lockInline() + \internal helper for lock() */ -void QMutex::lockInternal() +bool QBasicMutex::lockInternal(int timeout) { - QMutexPrivate *d = static_cast(this->d); + while (!fastTryLock()) { + QMutexPrivate *d = this->d; + if (!d) // if d is 0, the mutex is unlocked + continue; - 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; - } - - QElapsedTimer elapsedTimer; - elapsedTimer.start(); - do { - 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 - elapsedTimer.start(); - bool isLocked = d->wait(); - Q_ASSERT_X(isLocked, "QMutex::lock", - "Internal error, infinite wait has timed out."); - Q_UNUSED(isLocked); - - qint64 maximumSpinTime = d->maximumSpinTime; - 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)); + if (d == dummyLocked()) { + if (timeout == 0) + return false; + QMutexPrivate *newD = QMutexPrivate::allocate(); + if (!this->d.testAndSetOrdered(d, newD)) { + //Either the mutex is already unlocked, or another thread already set it. + newD->deref(); + continue; } - - // adjust the spin count when spinning does not benefit contention performance - if ((spinTime + actualWaitTime) - qint64(QMutexPrivate::MaximumSpinTimeThreshold) >= qint64(QMutexPrivate::MaximumSpinTimeThreshold)) { - // long waits, stop spinning - d->maximumSpinTime = 0; - } 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; + d = newD; + //the d->refCount is already 1 the deref will occurs when we unlock + } else if (d->recursive) { + return static_cast(d)->lock(timeout); } - // 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)); - // 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)); + if (timeout == 0 && !d->possiblyUnlocked) + return false; + + if (!d->ref()) + continue; //that QMutexPrivate was already released + + if (d != this->d) { + //Either the mutex is already unlocked, or relocked with another mutex + d->deref(); + continue; + } + + int old_waiters; + do { + old_waiters = d->waiters; + if (old_waiters == -QMutexPrivate::BigNumber) { + // we are unlocking, and the thread that unlocks is about to change d to 0 + // we try to aquire the mutex by changing to dummyLocked() + if (this->d.testAndSetAcquire(d, dummyLocked())) { + // Mutex aquired + Q_ASSERT(d->waiters == -QMutexPrivate::BigNumber || d->waiters == 0); + d->waiters = 0; + d->deref(); + return true; + } else { + Q_ASSERT(d != this->d); //else testAndSetAcquire should have succeeded + // Mutex is likely to bo 0, we should continue the outer-loop, + // set old_waiters to the magic value of BigNumber + old_waiters = QMutexPrivate::BigNumber; + break; + } + } + } while (!d->waiters.testAndSetRelaxed(old_waiters, old_waiters + 1)); + + if (d != this->d) { + // Mutex was unlocked. + if (old_waiters != QMutexPrivate::BigNumber) { + //we did not break the previous loop + Q_ASSERT(d->waiters >= 1); + d->waiters.deref(); + } + d->deref(); + continue; + } + + if (d->wait(timeout)) { + if (d->possiblyUnlocked && d->possiblyUnlocked.testAndSetRelaxed(true, false)) + d->deref(); + d->derefWaiters(1); + //we got the lock. (do not deref) + Q_ASSERT(d == this->d); + return true; + } else { + Q_ASSERT(timeout >= 0); + //timeout + d->derefWaiters(1); + //There may be a race in which the mutex is unlocked right after we timed out, + // and before we deref the waiters, so maybe the mutex is actually unlocked. + if (!d->possiblyUnlocked.testAndSetRelaxed(false, true)) + d->deref(); + return false; + } } + Q_ASSERT(this->d); + return true; } /*! \internal */ -void QMutex::unlockInternal() +void QBasicMutex::unlockInternal() { - static_cast(d)->wakeUp(); + QMutexPrivate *d = this->d; + Q_ASSERT(d); //we must be locked + Q_ASSERT(d != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed + + if (d->recursive) { + static_cast(d)->unlock(); + return; + } + + if (d->waiters.fetchAndAddRelease(-QMutexPrivate::BigNumber) == 0) { + //there is no one waiting on this mutex anymore, set the mutex as unlocked (d = 0) + if (this->d.testAndSetRelease(d, 0)) { + if (d->possiblyUnlocked && d->possiblyUnlocked.testAndSetRelaxed(true, false)) + d->deref(); + } + d->derefWaiters(0); + } else { + d->derefWaiters(0); + //there are thread waiting, transfer the lock. + d->wakeUp(); + } + d->deref(); +} + +//The freelist managment +namespace { +struct FreeListConstants : QFreeListDefaultConstants { + enum { BlockCount = 4, MaxIndex=0xffff }; + static const int Sizes[BlockCount]; +}; +const int FreeListConstants::Sizes[FreeListConstants::BlockCount] = { + 16, + 128, + 1024, + FreeListConstants::MaxIndex - (16-128-1024) +}; + +typedef QFreeList FreeList; +Q_GLOBAL_STATIC(FreeList, freelist); +} + +QMutexPrivate *QMutexPrivate::allocate() +{ + int i = freelist()->next(); + QMutexPrivate *d = &(*freelist())[i]; + d->id = i; + Q_ASSERT(d->refCount == 0); + Q_ASSERT(!d->recursive); + Q_ASSERT(!d->possiblyUnlocked); + Q_ASSERT(d->waiters == 0); + d->refCount = 1; + return d; +} + +void QMutexPrivate::release() +{ + Q_ASSERT(!recursive); + Q_ASSERT(refCount == 0); + Q_ASSERT(!possiblyUnlocked); + Q_ASSERT(waiters == 0); + freelist()->release(id); +} + +// atomically substract "value" to the waiters, and remove the QMutexPrivate::BigNumber flag +void QMutexPrivate::derefWaiters(int value) +{ + int old_waiters; + int new_waiters; + do { + old_waiters = waiters; + new_waiters = old_waiters; + if (new_waiters < 0) { + new_waiters += QMutexPrivate::BigNumber; + } + new_waiters -= value; + } while (!waiters.testAndSetRelaxed(old_waiters, new_waiters)); +} +#endif + +/*! + \internal + */ +bool QRecursiveMutexPrivate::lock(int timeout) { + Qt::HANDLE self = QThread::currentThreadId(); + if (owner == self) { + ++count; + Q_ASSERT_X(count != 0, "QMutex::lock", "Overflow in recursion counter"); + return true; + } + bool success = true; + if (timeout == -1) { + mutex.lock(); + } else { + success = mutex.tryLock(timeout); + } + + if (success) + owner = self; + return success; } /*! - \fn QMutex::lockInline() \internal - inline version of QMutex::lock() -*/ - -/*! - \fn QMutex::unlockInline() - \internal - inline version of QMutex::unlock() -*/ - -/*! - \fn QMutex::tryLockInline() - \internal - inline version of QMutex::tryLock() -*/ + */ +void QRecursiveMutexPrivate::unlock() +{ + if (count > 0) { + count--; + } else { + owner = 0; + mutex.unlock(); + } +} QT_END_NAMESPACE diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h index cc667560db..a49b981d01 100644 --- a/src/corelib/thread/qmutex.h +++ b/src/corelib/thread/qmutex.h @@ -52,47 +52,64 @@ QT_BEGIN_NAMESPACE QT_MODULE(Core) -#ifndef QT_NO_THREAD +#if !defined(QT_NO_THREAD) && !defined(qdoc) -class QAtomicInt; -class QMutexData; +class QMutexPrivate; -class Q_CORE_EXPORT QMutex +class Q_CORE_EXPORT QBasicMutex { - friend class QWaitCondition; - friend class QWaitConditionPrivate; - public: - enum RecursionMode { NonRecursive, Recursive }; + inline void lock() { + if (!fastTryLock()) + lockInternal(); + } - explicit QMutex(RecursionMode mode = NonRecursive); - ~QMutex(); + inline void unlock() { + Q_ASSERT(d); //mutex must be locked + if (!d.testAndSetRelease(dummyLocked(), 0)) + unlockInternal(); + } - void lock(); //### Qt5: make inline; - inline void lockInline(); - bool tryLock(); //### Qt5: make inline; - bool tryLock(int timeout); - inline bool tryLockInline(); - void unlock(); //### Qt5: make inline; - inline void unlockInline(); + bool tryLock(int timeout = 0) { + return fastTryLock() || lockInternal(timeout); + } + + bool isRecursive(); private: - void lockInternal(); + inline bool fastTryLock() { + return d.testAndSetAcquire(0, dummyLocked()); + } + bool lockInternal(int timeout = -1); void unlockInternal(); - Q_DISABLE_COPY(QMutex) - QMutexData *d; + QBasicAtomicPointer d; + static inline QMutexPrivate *dummyLocked() { + return reinterpret_cast(quintptr(1)); + } + + friend class QMutex; + friend class QMutexPrivate; +}; + +class Q_CORE_EXPORT QMutex : public QBasicMutex { +public: + enum RecursionMode { NonRecursive, Recursive }; + explicit QMutex(RecursionMode mode = NonRecursive); + ~QMutex(); +private: + Q_DISABLE_COPY(QMutex) }; class Q_CORE_EXPORT QMutexLocker { public: - inline explicit QMutexLocker(QMutex *m) + inline explicit QMutexLocker(QBasicMutex *m) { Q_ASSERT_X((reinterpret_cast(m) & quintptr(1u)) == quintptr(0), "QMutexLocker", "QMutex pointer is misaligned"); if (m) { - m->lockInline(); + m->lock(); val = reinterpret_cast(m) | quintptr(1u); } else { val = 0; @@ -104,7 +121,7 @@ public: { if ((val & quintptr(1u)) == quintptr(1u)) { val &= ~quintptr(1u); - mutex()->unlockInline(); + mutex()->unlock(); } } @@ -112,7 +129,7 @@ public: { if (val) { if ((val & quintptr(1u)) == quintptr(0u)) { - mutex()->lockInline(); + mutex()->lock(); val |= quintptr(1u); } } @@ -138,54 +155,9 @@ private: quintptr val; }; -class QMutexData -{ - public: - QAtomicInt contenders; - const uint recursive : 1; - uint reserved : 31; - protected: - QMutexData(QMutex::RecursionMode mode); - ~QMutexData(); -}; - -#ifdef QT_NO_DEBUG -inline void QMutex::unlockInline() -{ - if (d->recursive) { - unlock(); - } else if (!d->contenders.testAndSetRelease(1, 0)) { - unlockInternal(); - } -} - -inline bool QMutex::tryLockInline() -{ - if (d->recursive) { - return tryLock(); - } else { - return d->contenders.testAndSetAcquire(0, 1); - } -} - -inline void QMutex::lockInline() -{ - if (d->recursive) { - lock(); - } else if(!tryLockInline()) { - lockInternal(); - } -} -#else // QT_NO_DEBUG -//in debug we do not use inline calls in order to allow debugging tools -// to hook the mutex locking functions. -inline void QMutex::unlockInline() { unlock(); } -inline bool QMutex::tryLockInline() { return tryLock(); } -inline void QMutex::lockInline() { lock(); } -#endif // QT_NO_DEBUG -#else // QT_NO_THREAD +#else // QT_NO_THREAD or qdoc class Q_CORE_EXPORT QMutex @@ -194,14 +166,11 @@ public: enum RecursionMode { NonRecursive, Recursive }; inline explicit QMutex(RecursionMode mode = NonRecursive) { Q_UNUSED(mode); } - inline ~QMutex() {} static inline void lock() {} - static inline void lockInline() {} static inline bool tryLock(int timeout = 0) { Q_UNUSED(timeout); return true; } - static inline bool tryLockInline() { return true; } static inline void unlock() {} - static inline void unlockInline() {} + static inline bool isRecursive() { return true; } private: Q_DISABLE_COPY(QMutex) @@ -221,7 +190,9 @@ private: Q_DISABLE_COPY(QMutexLocker) }; -#endif // QT_NO_THREAD +typedef QMutex QBasicMutex; + +#endif // QT_NO_THREAD or qdoc QT_END_NAMESPACE diff --git a/src/corelib/thread/qmutex_linux.cpp b/src/corelib/thread/qmutex_linux.cpp new file mode 100644 index 0000000000..17015b8f84 --- /dev/null +++ b/src/corelib/thread/qmutex_linux.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" +#include "qmutex.h" + +#ifndef QT_NO_THREAD +#include "qatomic.h" +#include "qmutex_p.h" +# include "qelapsedtimer.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static inline int _q_futex(QMutexPrivate *volatile *addr, int op, int val, const struct timespec *timeout) +{ + volatile int *int_addr = reinterpret_cast(addr); +#if Q_BYTE_ORDER == Q_BIG_ENDIAN && QT_POINTER_SIZE == 8 + int_addr++; //We want a pointer to the 32 least significant bit of QMutex::d +#endif + int *addr2 = 0; + int val2 = 0; + return syscall(SYS_futex, int_addr, op, val, timeout, addr2, val2); +} + +static inline QMutexPrivate *dummyFutexValue() +{ + return reinterpret_cast(quintptr(3)); +} + + +QMutexPrivate::~QMutexPrivate() {} +QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) + : recursive(mode == QMutex::Recursive) {} + +bool QBasicMutex::lockInternal(int timeout) +{ + QElapsedTimer elapsedTimer; + if (timeout >= 1) + elapsedTimer.start(); + + while (!fastTryLock()) { + QMutexPrivate *d = this->d; + if (!d) // if d is 0, the mutex is unlocked + continue; + + if (quintptr(d) <= 0x3) { //d == dummyLocked() || d == dummyFutexValue() + if (timeout == 0) + return false; + while (this->d.fetchAndStoreAcquire(dummyFutexValue()) != 0) { + struct timespec ts, *pts = 0; + if (timeout >= 1) { + // recalculate the timeout + qint64 xtimeout = timeout * 1000 * 1000; + xtimeout -= elapsedTimer.nsecsElapsed(); + if (xtimeout <= 0) { + // timer expired after we returned + return false; + } + ts.tv_sec = xtimeout / Q_INT64_C(1000) / 1000 / 1000; + ts.tv_nsec = xtimeout % (Q_INT64_C(1000) * 1000 * 1000); + pts = &ts; + } + int r = _q_futex(&this->d._q_value, FUTEX_WAIT, quintptr(dummyFutexValue()), pts); + if (r != 0 && errno == ETIMEDOUT) + return false; + } + return true; + } + Q_ASSERT(d->recursive); + return static_cast(d)->lock(timeout); + } + Q_ASSERT(this->d); + return true; +} + +void QBasicMutex::unlockInternal() +{ + QMutexPrivate *d = this->d; + Q_ASSERT(d); //we must be locked + Q_ASSERT(d != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed + + if (d == dummyFutexValue()) { + this->d.fetchAndStoreRelease(0); + _q_futex(&this->d._q_value, FUTEX_WAKE, 1, 0); + return; + } + + Q_ASSERT(d->recursive); + static_cast(d)->unlock(); +} + + +QT_END_NAMESPACE + +#endif // QT_NO_THREAD diff --git a/src/corelib/thread/qmutex_mac.cpp b/src/corelib/thread/qmutex_mac.cpp new file mode 100644 index 0000000000..f63feebca4 --- /dev/null +++ b/src/corelib/thread/qmutex_mac.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" +#include "qmutex.h" + +#if !defined(QT_NO_THREAD) + +#include "qmutex_p.h" + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) + : recursive(mode == QMutex::Recursive) +{ + 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); +} + +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); +} + +bool QMutexPrivate::wait(int timeout) +{ + kern_return_t r; + if (timeout < 0) { + do { + r = semaphore_wait(mach_semaphore); + } while (r == KERN_ABORTED); + Q_ASSERT(r == KERN_SUCCESS); + } else { + mach_timespec_t ts; + ts.tv_nsec = ((timeout % 1000) * 1000) * 1000; + ts.tv_sec = (timeout / 1000); + r = semaphore_timedwait(mach_semaphore, ts); + } + return (r == KERN_SUCCESS); +} + +void QMutexPrivate::wakeUp() +{ + semaphore_signal(mach_semaphore); +} + + +QT_END_NAMESPACE + +#endif //QT_NO_THREAD diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index a9923c47a4..00f071ebef 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -57,50 +57,80 @@ #include #include #include +#include #if defined(Q_OS_MAC) # include #endif -#if defined(Q_OS_SYMBIAN) -# include -#endif - QT_BEGIN_NAMESPACE -class QMutexPrivate : public QMutexData { +class QMutexPrivate { public: - QMutexPrivate(QMutex::RecursionMode mode); ~QMutexPrivate(); + QMutexPrivate(QMutex::RecursionMode mode = QMutex::NonRecursive); bool wait(int timeout = -1); void wakeUp(); - // 1ms = 1000000ns - enum { MaximumSpinTimeThreshold = 1000000 }; - volatile qint64 maximumSpinTime; - volatile qint64 averageWaitTime; - Qt::HANDLE owner; - uint count; +#if !defined(Q_OS_LINUX) + // Conrol the lifetime of the privates + QAtomicInt refCount; + int id; + bool ref() { + Q_ASSERT(refCount >= 0); + int c; + do { + c = refCount; + if (c == 0) + return false; + } while (!refCount.testAndSetRelaxed(c, c + 1)); + Q_ASSERT(refCount >= 0); + return true; + } + void deref() { + Q_ASSERT(refCount >=0); + if (!refCount.deref()) + release(); + Q_ASSERT(refCount >=0); + } + void release(); + static QMutexPrivate *allocate(); + + QAtomicInt waiters; //number of thread waiting + QAtomicInt possiblyUnlocked; //bool saying that a timed wait timed out + enum { BigNumber = 0x100000 }; //Must be bigger than the possible number of waiters (number of threads) + void derefWaiters(int value); +#endif + + // handle recursive mutex + bool recursive; + + //platform specific stuff #if defined(Q_OS_MAC) semaphore_t mach_semaphore; -#elif defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) && !defined(Q_OS_SYMBIAN) - volatile bool wakeup; +#elif defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) + bool wakeup; pthread_mutex_t mutex; pthread_cond_t cond; #elif defined(Q_OS_WIN32) || defined(Q_OS_WINCE) HANDLE event; -#elif defined(Q_OS_SYMBIAN) - RSemaphore lock; #endif }; -inline QMutexData::QMutexData(QMutex::RecursionMode mode) - : recursive(mode == QMutex::Recursive) -{} +class QRecursiveMutexPrivate : public QMutexPrivate +{ +public: + QRecursiveMutexPrivate() + : QMutexPrivate(QMutex::Recursive), owner(0), count(0) {} + Qt::HANDLE owner; + uint count; + QMutex mutex; -inline QMutexData::~QMutexData() {} + bool lock(int timeout); + void unlock(); +}; QT_END_NAMESPACE diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index 2a9d23c361..0bccad589d 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -46,142 +46,35 @@ #ifndef QT_NO_THREAD #include "qatomic.h" #include "qmutex_p.h" - #include #if defined(Q_OS_VXWORKS) && defined(wakeup) #undef wakeup #endif -#if defined(Q_OS_MAC) -# include -# include -#elif defined(Q_OS_LINUX) -# include -# include -# include -# include -#endif - QT_BEGIN_NAMESPACE -#if !defined(Q_OS_MAC) && !defined(Q_OS_LINUX) 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), maximumSpinTime(MaximumSpinTimeThreshold), averageWaitTime(0), owner(0), count(0) + : recursive(mode == QMutex::Recursive), wakeup(false) { -#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); -#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"); -#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); -#elif !defined(Q_OS_LINUX) 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; - } - kern_return_t r; - if (timeout < 0) { - do { - r = semaphore_wait(mach_semaphore); - } while (r == KERN_ABORTED); - if (r != KERN_SUCCESS) - qWarning("QMutex: infinite wait failed, error %d", r); - } else { - mach_timespec_t ts; - ts.tv_nsec = ((timeout % 1000) * 1000) * 1000; - ts.tv_sec = (timeout / 1000); - r = semaphore_timedwait(mach_semaphore, ts); - } - contenders.deref(); - return r == KERN_SUCCESS; -} - -void QMutexPrivate::wakeUp() -{ - semaphore_signal(mach_semaphore); -} - -#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) { - struct timespec ts, *pts = 0; - QElapsedTimer timer; - if (timeout >= 0) { - ts.tv_nsec = ((timeout % 1000) * 1000) * 1000; - ts.tv_sec = (timeout / 1000); - pts = &ts; - timer.start(); - } - while (contenders.fetchAndStoreAcquire(2) > 0) { - int r = _q_futex(&contenders._q_value, FUTEX_WAIT, 2, pts, 0, 0); - if (r != 0 && errno == ETIMEDOUT) - return false; - - if (pts) { - // recalculate the timeout - qint64 xtimeout = timeout * 1000 * 1000; - xtimeout -= timer.nsecsElapsed(); - if (xtimeout < 0) { - // timer expired after we returned - return false; - } - - ts.tv_sec = xtimeout / Q_INT64_C(1000) / 1000 / 1000; - ts.tv_nsec = xtimeout % (Q_INT64_C(1000) * 1000 * 1000); - } - } - 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) -{ - 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) { @@ -190,12 +83,10 @@ bool QMutexPrivate::wait(int timeout) } else { struct timeval tv; gettimeofday(&tv, 0); - timespec ti; ti.tv_nsec = (tv.tv_usec + (timeout % 1000) * 1000) * 1000; ti.tv_sec = tv.tv_sec + (timeout / 1000) + (ti.tv_nsec / 1000000000); ti.tv_nsec %= 1000000000; - errorCode = pthread_cond_timedwait(&cond, &mutex, &ti); } if (errorCode) { @@ -207,10 +98,10 @@ bool QMutexPrivate::wait(int timeout) report_error(errorCode, "QMutex::lock()", "cv wait"); } } + bool ret = wakeup; wakeup = false; report_error(pthread_mutex_unlock(&mutex), "QMutex::lock", "mutex unlock"); - contenders.deref(); - return errorCode == 0; + return ret; } void QMutexPrivate::wakeUp() @@ -221,7 +112,6 @@ void QMutexPrivate::wakeUp() report_error(pthread_mutex_unlock(&mutex), "QMutex::unlock", "mutex unlock"); } -#endif // !Q_OS_MAC && !Q_OS_LINUX QT_END_NAMESPACE diff --git a/src/corelib/thread/qmutex_win.cpp b/src/corelib/thread/qmutex_win.cpp index 53ad8cfe89..f6670f6d1e 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), averageWaitTime(0), owner(0), count(0) + : recursive(mode) { event = CreateEvent(0, FALSE, FALSE, 0); if (!event) @@ -60,13 +60,7 @@ QMutexPrivate::~QMutexPrivate() bool QMutexPrivate::wait(int timeout) { - 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; + return (WaitForSingleObject(event, timeout < 0 ? INFINITE : timeout) == WAIT_OBJECT_0); } void QMutexPrivate::wakeUp() diff --git a/src/corelib/thread/qorderedmutexlocker_p.h b/src/corelib/thread/qorderedmutexlocker_p.h index 8f01c1c056..e65a601369 100644 --- a/src/corelib/thread/qorderedmutexlocker_p.h +++ b/src/corelib/thread/qorderedmutexlocker_p.h @@ -79,8 +79,8 @@ public: void relock() { if (!locked) { - if (mtx1) mtx1->lockInline(); - if (mtx2) mtx2->lockInline(); + if (mtx1) mtx1->lock(); + if (mtx2) mtx2->lock(); locked = true; } } @@ -88,8 +88,8 @@ public: void unlock() { if (locked) { - if (mtx1) mtx1->unlockInline(); - if (mtx2) mtx2->unlockInline(); + if (mtx1) mtx1->unlock(); + if (mtx2) mtx2->unlock(); locked = false; } } @@ -100,10 +100,10 @@ public: if (mtx1 == mtx2) return false; if (mtx1 < mtx2) { - mtx2->lockInline(); + mtx2->lock(); return true; } - if (!mtx2->tryLockInline()) { + if (!mtx2->tryLock()) { mtx1->unlock(); mtx2->lock(); mtx1->lock(); diff --git a/src/corelib/thread/qwaitcondition_unix.cpp b/src/corelib/thread/qwaitcondition_unix.cpp index b946a9de24..dd85bf4023 100644 --- a/src/corelib/thread/qwaitcondition_unix.cpp +++ b/src/corelib/thread/qwaitcondition_unix.cpp @@ -146,7 +146,7 @@ bool QWaitCondition::wait(QMutex *mutex, unsigned long time) { if (! mutex) return false; - if (mutex->d->recursive) { + if (mutex->isRecursive()) { qWarning("QWaitCondition: cannot wait on recursive mutexes"); return false; } diff --git a/src/corelib/thread/qwaitcondition_win.cpp b/src/corelib/thread/qwaitcondition_win.cpp index 8a8db97342..bf1ec5e5ba 100644 --- a/src/corelib/thread/qwaitcondition_win.cpp +++ b/src/corelib/thread/qwaitcondition_win.cpp @@ -164,7 +164,7 @@ bool QWaitCondition::wait(QMutex *mutex, unsigned long time) { if (!mutex) return false; - if (mutex->d->recursive) { + if (mutex->isRecursive()) { qWarning("QWaitCondition::wait: Cannot wait on recursive mutexes"); return false; } diff --git a/src/corelib/thread/thread.pri b/src/corelib/thread/thread.pri index 592ab1644b..309bf30d25 100644 --- a/src/corelib/thread/thread.pri +++ b/src/corelib/thread/thread.pri @@ -24,8 +24,7 @@ SOURCES += thread/qatomic.cpp \ thread/qthread.cpp \ thread/qthreadstorage.cpp -unix:!symbian:SOURCES += thread/qmutex_unix.cpp \ - thread/qthread_unix.cpp \ +unix:!symbian:SOURCES += thread/qthread_unix.cpp \ thread/qwaitcondition_unix.cpp symbian:SOURCES += thread/qmutex_symbian.cpp \ @@ -39,3 +38,9 @@ win32:SOURCES += thread/qmutex_win.cpp \ integrity:SOURCES += thread/qmutex_unix.cpp \ thread/qthread_unix.cpp \ thread/qwaitcondition_unix.cpp + +unix: { + macx-* { SOURCES += thread/qmutex_mac.cpp } + else:linux-* { SOURCES += thread/qmutex_linux.cpp } + else { SOURCES += thread/qmutex_unix.cpp } +} diff --git a/tests/auto/qmutex/tst_qmutex.cpp b/tests/auto/qmutex/tst_qmutex.cpp index 5fed6bb44e..7ad6a98a4d 100644 --- a/tests/auto/qmutex/tst_qmutex.cpp +++ b/tests/auto/qmutex/tst_qmutex.cpp @@ -65,6 +65,7 @@ private slots: void stressTest(); void tryLockRace(); void qtbug16115_trylock(); + void moreStress(); }; static const int iterations = 100; @@ -83,6 +84,8 @@ QMutex normalMutex, recursiveMutex(QMutex::Recursive); QSemaphore testsTurn; QSemaphore threadsTurn; +enum { waitTime = 100 }; + void tst_QMutex::tryLock() { // test non-recursive mutex @@ -109,18 +112,18 @@ void tst_QMutex::tryLock() threadsTurn.acquire(); QTime timer; timer.start(); - QVERIFY(!normalMutex.tryLock(1000)); - QVERIFY(timer.elapsed() >= 1000); + QVERIFY(!normalMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() >= waitTime); testsTurn.release(); threadsTurn.acquire(); timer.start(); - QVERIFY(normalMutex.tryLock(1000)); - QVERIFY(timer.elapsed() <= 1000); + QVERIFY(normalMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() <= waitTime); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); timer.start(); - QVERIFY(!normalMutex.tryLock(1000)); - QVERIFY(timer.elapsed() >= 1000); + QVERIFY(!normalMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() >= waitTime); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); normalMutex.unlock(); testsTurn.release(); @@ -132,7 +135,7 @@ void tst_QMutex::tryLock() threadsTurn.acquire(); timer.start(); QVERIFY(normalMutex.tryLock(0)); - QVERIFY(timer.elapsed() < 1000); + QVERIFY(timer.elapsed() < waitTime); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); QVERIFY(!normalMutex.tryLock(0)); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); @@ -158,13 +161,13 @@ void tst_QMutex::tryLock() normalMutex.unlock(); threadsTurn.release(); - // thread can't acquire lock, timeout = 1000 + // thread can't acquire lock, timeout = waitTime testsTurn.acquire(); normalMutex.lock(); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); threadsTurn.release(); - // thread can acquire lock, timeout = 1000 + // thread can acquire lock, timeout = waitTime testsTurn.acquire(); QVERIFY(lockCount.testAndSetRelaxed(1, 0)); normalMutex.unlock(); @@ -215,17 +218,17 @@ void tst_QMutex::tryLock() threadsTurn.acquire(); QTime timer; timer.start(); - QVERIFY(!recursiveMutex.tryLock(1000)); - QVERIFY(timer.elapsed() >= 1000); + QVERIFY(!recursiveMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() >= waitTime); QVERIFY(!recursiveMutex.tryLock(0)); testsTurn.release(); threadsTurn.acquire(); timer.start(); - QVERIFY(recursiveMutex.tryLock(1000)); - QVERIFY(timer.elapsed() <= 1000); + QVERIFY(recursiveMutex.tryLock(waitTime)); + QVERIFY(timer.elapsed() <= waitTime); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); - QVERIFY(recursiveMutex.tryLock(1000)); + QVERIFY(recursiveMutex.tryLock(waitTime)); QVERIFY(lockCount.testAndSetRelaxed(1, 2)); QVERIFY(lockCount.testAndSetRelaxed(2, 1)); recursiveMutex.unlock(); @@ -241,7 +244,7 @@ void tst_QMutex::tryLock() threadsTurn.acquire(); timer.start(); QVERIFY(recursiveMutex.tryLock(0)); - QVERIFY(timer.elapsed() < 1000); + QVERIFY(timer.elapsed() < waitTime); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); QVERIFY(recursiveMutex.tryLock(0)); QVERIFY(lockCount.testAndSetRelaxed(1, 2)); @@ -274,7 +277,7 @@ void tst_QMutex::tryLock() recursiveMutex.unlock(); threadsTurn.release(); - // thread can't acquire lock, timeout = 1000 + // thread can't acquire lock, timeout = waitTime testsTurn.acquire(); recursiveMutex.lock(); QVERIFY(lockCount.testAndSetRelaxed(0, 1)); @@ -282,7 +285,7 @@ void tst_QMutex::tryLock() QVERIFY(lockCount.testAndSetRelaxed(1, 2)); threadsTurn.release(); - // thread can acquire lock, timeout = 1000 + // thread can acquire lock, timeout = waitTime testsTurn.acquire(); QVERIFY(lockCount.testAndSetRelaxed(2, 1)); recursiveMutex.unlock(); @@ -436,7 +439,8 @@ void tst_QMutex::lock_unlock_locked_tryLock() } } -enum { one_minute = 60 * 1000, threadCount = 10 }; +enum { one_minute = 6 * 1000, //not really one minute, but else it is too long. + threadCount = 10 }; class StressTestThread : public QThread { @@ -497,7 +501,7 @@ public: do { if (mutex.tryLock()) mutex.unlock(); - } while (t.elapsed() < 20000); + } while (t.elapsed() < one_minute/2); } }; QMutex TryLockRaceThread::mutex; @@ -534,7 +538,7 @@ void tst_QMutex::qtbug16115_trylock() TrylockThread(QMutex &mut) : mut(mut) {} QMutex &mut; void run() { - for (int i = 0; i < 1000000; ++i) { + for (int i = 0; i < 100000; ++i) { if (mut.tryLock(0)) { if ((++qtbug16115_trylock_counter) != 1) ++qtbug16115_failure_count; @@ -553,7 +557,7 @@ void tst_QMutex::qtbug16115_trylock() t2.start(); t3.start(); - for (int i = 0; i < 1000000; ++i) { + for (int i = 0; i < 100000; ++i) { mut.lock(); if ((++qtbug16115_trylock_counter) != 1) ++qtbug16115_failure_count; @@ -567,5 +571,70 @@ void tst_QMutex::qtbug16115_trylock() QCOMPARE(qtbug16115_failure_count, 0); } + +class MoreStressTestThread : public QThread +{ + QTime t; +public: + static QAtomicInt lockCount; + static QAtomicInt sentinel[threadCount]; + static QMutex mutex[threadCount]; + static QAtomicInt errorCount; + void start() + { + t.start(); + QThread::start(); + } + void run() + { + quint64 i = 0; + while (t.elapsed() < one_minute) { + i++; + uint nb = (i * 9 + lockCount * 13) % threadCount; + QMutexLocker locker(&mutex[nb]); + if (sentinel[nb]) errorCount.ref(); + if (sentinel[nb].fetchAndAddRelaxed(5)) errorCount.ref(); + if (!sentinel[nb].testAndSetRelaxed(5, 0)) errorCount.ref(); + if (sentinel[nb]) errorCount.ref(); + lockCount.ref(); + nb = (nb * 17 + i * 5 + lockCount * 3) % threadCount; + if (mutex[nb].tryLock()) { + if (sentinel[nb]) errorCount.ref(); + if (sentinel[nb].fetchAndAddRelaxed(16)) errorCount.ref(); + if (!sentinel[nb].testAndSetRelaxed(16, 0)) errorCount.ref(); + if (sentinel[nb]) errorCount.ref(); + lockCount.ref(); + mutex[nb].unlock(); + } + nb = (nb * 15 + i * 47 + lockCount * 31) % threadCount; + if (mutex[nb].tryLock(2)) { + if (sentinel[nb]) errorCount.ref(); + if (sentinel[nb].fetchAndAddRelaxed(53)) errorCount.ref(); + if (!sentinel[nb].testAndSetRelaxed(53, 0)) errorCount.ref(); + if (sentinel[nb]) errorCount.ref(); + lockCount.ref(); + mutex[nb].unlock(); + } + } + } +}; +QMutex MoreStressTestThread::mutex[threadCount]; +QAtomicInt MoreStressTestThread::lockCount; +QAtomicInt MoreStressTestThread::sentinel[threadCount]; +QAtomicInt MoreStressTestThread::errorCount = 0; + +void tst_QMutex::moreStress() +{ + MoreStressTestThread threads[threadCount]; + for (int i = 0; i < threadCount; ++i) + threads[i].start(); + QVERIFY(threads[0].wait(one_minute + 10000)); + for (int i = 1; i < threadCount; ++i) + QVERIFY(threads[i].wait(10000)); + qDebug("locked %d times", int(MoreStressTestThread::lockCount)); + QCOMPARE(int(MoreStressTestThread::errorCount), 0); +} + + QTEST_MAIN(tst_QMutex) #include "tst_qmutex.moc" diff --git a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp index 05a15750c1..05e184d0c2 100644 --- a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp +++ b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp @@ -151,7 +151,6 @@ void tst_QMutex::noThread_data() QTest::addColumn("t"); QTest::newRow("noLock") << 1; - QTest::newRow("QMutexInline") << 2; QTest::newRow("QMutex") << 3; QTest::newRow("QMutexLocker") << 4; } @@ -172,16 +171,6 @@ void tst_QMutex::noThread() } } break; - case 2: - QBENCHMARK { - count = 0; - for (int i = 0; i < N; i++) { - mtx.lockInline(); - count++; - mtx.unlockInline(); - } - } - break; case 3: QBENCHMARK { count = 0; From ddf444d31a7cb961b79190131cb679fd7a6351fd Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 26 Jul 2011 10:44:55 +0200 Subject: [PATCH 54/75] Simplify the mutexpool used in QObject. Since we now have QBasicMutex as a POD, we can simplify the mutexpool. This remove the call the the Q_GLOBAL_STATIC and some others tests that are taking CPU cycles when activating a signal. The QMutexPool class itself can't be simplified because its mutex are recursive mutexes, and the size is dynamic. also it is harder to get all the mutexes initialized to 0. Change-Id: Ie781655635907d2ad620eb189099cba14638414f Reviewed-by: Bradley T. Hughes Reviewed-on: http://codereview.qt.nokia.com/2171 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/kernel/qobject.cpp | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index ab9314ce53..076744ee00 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -60,7 +60,6 @@ #include #include -#include #include @@ -95,35 +94,22 @@ static int *queuedConnectionTypes(const QList &typeNames) return types; } -static QBasicAtomicPointer signalSlotMutexes = Q_BASIC_ATOMIC_INITIALIZER(0); -static QBasicAtomicInt objectCount = Q_BASIC_ATOMIC_INITIALIZER(0); +static QBasicMutex _q_ObjectMutexPool[131]; /** \internal * mutex to be locked when accessing the connectionlists or the senders list */ static inline QMutex *signalSlotLock(const QObject *o) { - if (!signalSlotMutexes) { - QMutexPool *mp = new QMutexPool; - if (!signalSlotMutexes.testAndSetOrdered(0, mp)) { - delete mp; - } - } - return signalSlotMutexes->get(o); + return static_cast(&_q_ObjectMutexPool[ + uint(quintptr(o)) % sizeof(_q_ObjectMutexPool)/sizeof(QBasicMutex)]); } extern "C" Q_CORE_EXPORT void qt_addObject(QObject *) -{ - objectCount.ref(); -} +{} extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *) -{ - if(!objectCount.deref()) { - QMutexPool *old = signalSlotMutexes.fetchAndStoreAcquire(0); - delete old; - } -} +{} struct QConnectionSenderSwitcher { QObject *receiver; From 23bf50432b27c544690922652d13d3a537c47d2f Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Thu, 21 Jul 2011 15:09:24 +0200 Subject: [PATCH 55/75] Switch to use floating point pixelSize in QRawFont completely Reviewed-by: Eskil (cherry picked from commit 500f8a4368be85a0ae8b7c46012deb0ab0c844ad) Change-Id: I6cfebcbb68697c9bf7a5634e98a09a26928467d7 Reviewed-on: http://codereview.qt.nokia.com/2386 Reviewed-by: Qt Sanity Bot Reviewed-by: Jiang Jiang --- src/gui/text/qrawfont.cpp | 8 ++++---- src/gui/text/qrawfont.h | 8 ++++---- src/gui/text/qrawfont_ft.cpp | 2 +- src/gui/text/qrawfont_mac.cpp | 2 +- src/gui/text/qrawfont_p.h | 2 +- src/gui/text/qrawfont_qpa.cpp | 2 +- src/gui/text/qrawfont_win.cpp | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp index 4c65ad5de0..26b6a8aad7 100644 --- a/src/gui/text/qrawfont.cpp +++ b/src/gui/text/qrawfont.cpp @@ -139,7 +139,7 @@ QRawFont::QRawFont() \note The referenced file must contain a TrueType or OpenType font. */ QRawFont::QRawFont(const QString &fileName, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) : d(new QRawFontPrivate) { @@ -154,7 +154,7 @@ QRawFont::QRawFont(const QString &fileName, \note The data must contain a TrueType or OpenType font. */ QRawFont::QRawFont(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) : d(new QRawFontPrivate) { @@ -204,7 +204,7 @@ bool QRawFont::isValid() const \sa loadFromData() */ void QRawFont::loadFromFile(const QString &fileName, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) { QFile file(fileName); @@ -222,7 +222,7 @@ void QRawFont::loadFromFile(const QString &fileName, \sa loadFromFile() */ void QRawFont::loadFromData(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) { detach(); diff --git a/src/gui/text/qrawfont.h b/src/gui/text/qrawfont.h index e94bd99b8c..f7d7494f0b 100644 --- a/src/gui/text/qrawfont.h +++ b/src/gui/text/qrawfont.h @@ -70,10 +70,10 @@ public: QRawFont(); QRawFont(const QString &fileName, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference = QFont::PreferDefaultHinting); QRawFont(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference = QFont::PreferDefaultHinting); QRawFont(const QRawFont &other); ~QRawFont(); @@ -117,11 +117,11 @@ public: qreal unitsPerEm() const; void loadFromFile(const QString &fileName, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference); void loadFromData(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference); bool supportsCharacter(quint32 ucs4) const; diff --git a/src/gui/text/qrawfont_ft.cpp b/src/gui/text/qrawfont_ft.cpp index 984efdbcef..1666df3fdf 100644 --- a/src/gui/text/qrawfont_ft.cpp +++ b/src/gui/text/qrawfont_ft.cpp @@ -100,7 +100,7 @@ void QRawFontPrivate::platformCleanUp() // Font engine handles all resources } -void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, int pixelSize, +void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) { Q_ASSERT(fontEngine == 0); diff --git a/src/gui/text/qrawfont_mac.cpp b/src/gui/text/qrawfont_mac.cpp index df68eb7e7a..40c719a1af 100644 --- a/src/gui/text/qrawfont_mac.cpp +++ b/src/gui/text/qrawfont_mac.cpp @@ -55,7 +55,7 @@ void QRawFontPrivate::platformCleanUp() extern int qt_defaultDpi(); void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) { // Mac OS X ignores it diff --git a/src/gui/text/qrawfont_p.h b/src/gui/text/qrawfont_p.h index 56ea6a031d..4a4ed56223 100644 --- a/src/gui/text/qrawfont_p.h +++ b/src/gui/text/qrawfont_p.h @@ -99,7 +99,7 @@ public: void cleanUp(); void platformCleanUp(); void platformLoadFromData(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference); static QRawFontPrivate *get(const QRawFont &font) { return font.d.data(); } diff --git a/src/gui/text/qrawfont_qpa.cpp b/src/gui/text/qrawfont_qpa.cpp index 3492946c1c..6a69804fac 100644 --- a/src/gui/text/qrawfont_qpa.cpp +++ b/src/gui/text/qrawfont_qpa.cpp @@ -53,7 +53,7 @@ void QRawFontPrivate::platformCleanUp() { } -void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, int pixelSize, +void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) { Q_ASSERT(fontEngine == 0); diff --git a/src/gui/text/qrawfont_win.cpp b/src/gui/text/qrawfont_win.cpp index 111439c024..d8aa557975 100644 --- a/src/gui/text/qrawfont_win.cpp +++ b/src/gui/text/qrawfont_win.cpp @@ -546,7 +546,7 @@ void QRawFontPrivate::platformCleanUp() } void QRawFontPrivate::platformLoadFromData(const QByteArray &_fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) { QByteArray fontData(_fontData); From 2c3382d30574a56b640c46aab7c407d63435d3bb Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 29 Jul 2011 12:26:43 +0200 Subject: [PATCH 56/75] Fix compilation with namespaced builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add QT_BEGIN_NAMESPACE and QT_END_NAMESPACE to src/corelib/tools/qfreelist.cpp Change-Id: Ie01e74a3c2d9cd4de1f52a546d13398e1409c86b Reviewed-on: http://codereview.qt.nokia.com/2390 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart Reviewed-by: João Abecasis --- src/corelib/tools/qfreelist.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/corelib/tools/qfreelist.cpp b/src/corelib/tools/qfreelist.cpp index 63e37ec249..bbbdb25e49 100644 --- a/src/corelib/tools/qfreelist.cpp +++ b/src/corelib/tools/qfreelist.cpp @@ -41,6 +41,8 @@ #include "qfreelist_p.h" +QT_BEGIN_NAMESPACE + // default sizes and offsets (no need to define these when customizing) enum { Offset0 = 0x00000000, @@ -60,3 +62,6 @@ const int QFreeListDefaultConstants::Sizes[QFreeListDefaultConstants::BlockCount Size2, Size3 }; + +QT_END_NAMESPACE + From 9d16ae8d2ce5478f7387ec70c70be46e76c85796 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Fri, 29 Jul 2011 10:44:30 +0200 Subject: [PATCH 57/75] Fix tst_qgraphicsview::task255529_transformationAnchorMouseAndViewportMargins If we do not process the event, q->underMouse may return false in QGraphicsViewPrivate::centerView (as the QEvent::Enter has not been received yet.) It was working before if by luck, the window appears under the cursor. Change-Id: I9b4497683eae20915680297013a9c21fd6275f4b Reviewed-on: http://codereview.qt.nokia.com/2385 Reviewed-by: Qt Sanity Bot Reviewed-by: Sergio Ahumada --- tests/auto/qgraphicsview/tst_qgraphicsview.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp index e9ddf481af..cdb87b57d7 100644 --- a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp @@ -104,6 +104,7 @@ static void sendMouseMove(QWidget *widget, const QPoint &point, Qt::MouseButton QTest::mouseMove(widget, point); QMouseEvent event(QEvent::MouseMove, point, button, buttons, 0); QApplication::sendEvent(widget, &event); + QApplication::processEvents(); } static void sendMouseRelease(QWidget *widget, const QPoint &point, Qt::MouseButton button = Qt::LeftButton) From 30eff894d9b31e0c800901e7334fed2401be0f1c Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Mon, 1 Aug 2011 10:17:51 +1000 Subject: [PATCH 58/75] Fixed tst_qprocess, tst_qtcpserver when crashing is slow These tests assumed that a crashing program will always exit within five seconds. This is not true in some situations. On our test macs, enabling crash dumps can easily cause a process to take longer than five seconds to crash. Increased the timeout to 30 seconds. Change-Id: Ifca240ac8d3da1346f33110653ac47de6ba2ab81 Reviewed-on: http://codereview.qt.nokia.com/2407 Reviewed-by: Kalle Lehtonen --- tests/auto/qprocess/tst_qprocess.cpp | 6 +++--- tests/auto/qtcpserver/tst_qtcpserver.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/auto/qprocess/tst_qprocess.cpp b/tests/auto/qprocess/tst_qprocess.cpp index f54dfa3f68..9873c3e357 100644 --- a/tests/auto/qprocess/tst_qprocess.cpp +++ b/tests/auto/qprocess/tst_qprocess.cpp @@ -335,7 +335,7 @@ void tst_QProcess::crashTest() QSignalSpy spy(process, SIGNAL(error(QProcess::ProcessError))); QSignalSpy spy2(process, SIGNAL(finished(int, QProcess::ExitStatus))); - QVERIFY(process->waitForFinished(5000)); + QVERIFY(process->waitForFinished(30000)); QCOMPARE(spy.count(), 1); QCOMPARE(*static_cast(spy.at(0).at(0).constData()), QProcess::Crashed); @@ -372,7 +372,7 @@ void tst_QProcess::crashTest2() QObject::connect(process, SIGNAL(finished(int)), this, SLOT(exitLoopSlot())); - QTestEventLoop::instance().enterLoop(5); + QTestEventLoop::instance().enterLoop(30); if (QTestEventLoop::instance().timeout()) QFAIL("Failed to detect crash : operation timed out"); @@ -673,7 +673,7 @@ void tst_QProcess::exitStatus() for (int i = 0; i < processList.count(); ++i) { process->start(processList.at(i)); QVERIFY(process->waitForStarted(5000)); - QVERIFY(process->waitForFinished(5000)); + QVERIFY(process->waitForFinished(30000)); QCOMPARE(process->exitStatus(), exitStatus.at(i)); } diff --git a/tests/auto/qtcpserver/tst_qtcpserver.cpp b/tests/auto/qtcpserver/tst_qtcpserver.cpp index b566e5cebd..b72e61f374 100644 --- a/tests/auto/qtcpserver/tst_qtcpserver.cpp +++ b/tests/auto/qtcpserver/tst_qtcpserver.cpp @@ -575,7 +575,7 @@ void tst_QTcpServer::addressReusable() socket.connectToHost(QHostAddress::LocalHost, 49199); QVERIFY(socket.waitForConnected(5000)); - QVERIFY(process.waitForFinished(5000)); + QVERIFY(process.waitForFinished(30000)); // Give the system some time. QTest::qSleep(10); From 4e84be2876543c1bfcab3b854c92a7edade4144b Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Mon, 1 Aug 2011 14:21:56 +1000 Subject: [PATCH 59/75] test: fixed tst_qfilesystemmodel and removed insignificant_test tst_qfilesystemmodel::sort uses some internal API to affect the sorting behavior. This means that part of the test must be disabled when private symbols aren't available. Change-Id: I2e7b9d7a33cb3e7032bc5380c03fa29ecc84e12c Reviewed-on: http://codereview.qt.nokia.com/2413 Reviewed-by: Sergio Ahumada Reviewed-by: Qt Sanity Bot --- tests/auto/qfilesystemmodel/qfilesystemmodel.pro | 2 -- tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/auto/qfilesystemmodel/qfilesystemmodel.pro b/tests/auto/qfilesystemmodel/qfilesystemmodel.pro index 88ff56cebf..ab121306e3 100644 --- a/tests/auto/qfilesystemmodel/qfilesystemmodel.pro +++ b/tests/auto/qfilesystemmodel/qfilesystemmodel.pro @@ -14,5 +14,3 @@ symbian: { DEPLOYMENT += dummyDeploy LIBS += -lefsrv } - -CONFIG+=insignificant_test diff --git a/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp b/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp index 5f610945ab..5afcf40800 100644 --- a/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp +++ b/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp @@ -909,12 +909,16 @@ void tst_QFileSystemModel::sort() expectedOrder << tempFile2.fileName() << tempFile.fileName() << dirPath + QChar('/') + "." << dirPath + QChar('/') + ".."; //File dialog Mode means sub trees are not sorted, only the current root if (fileDialogMode) { + // FIXME: we were only able to disableRecursiveSort in developer builds, so we can only + // stably perform this test for developer builds +#ifdef QT_BUILD_INTERNAL QList actualRows; for(int i = 0; i < myModel->rowCount(parent); ++i) { actualRows << dirPath + QChar('/') + myModel->index(i, 1, parent).data(QFileSystemModel::FileNameRole).toString(); } QVERIFY(actualRows != expectedOrder); +#endif } else { for(int i = 0; i < myModel->rowCount(parent); ++i) { From fb8d316e83c333acd20b912abf874fd240a8bedc Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Tue, 2 Aug 2011 14:46:15 +1000 Subject: [PATCH 60/75] test: replace CONFIG+=insignificant_test with QEXPECT_FAIL for tst_qftp This autotest failure is entirely stable, so QEXPECT_FAIL should be used instead of insignificant_test. Task-number: QTBUG-20687 Change-Id: I0444e725b436fe93d30cbe54edc673594ca9b9fe Reviewed-on: http://codereview.qt.nokia.com/2486 Reviewed-by: Qt Sanity Bot Reviewed-by: Kalle Lehtonen --- tests/auto/qftp/qftp.pro | 2 -- tests/auto/qftp/tst_qftp.cpp | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/qftp/qftp.pro b/tests/auto/qftp/qftp.pro index 42c700e72e..69f89572ba 100644 --- a/tests/auto/qftp/qftp.pro +++ b/tests/auto/qftp/qftp.pro @@ -18,5 +18,3 @@ wince*: { } else { DEFINES += SRCDIR=\\\"$$PWD/\\\" } - -CONFIG+=insignificant_test diff --git a/tests/auto/qftp/tst_qftp.cpp b/tests/auto/qftp/tst_qftp.cpp index 62b454099b..e31b5acda3 100644 --- a/tests/auto/qftp/tst_qftp.cpp +++ b/tests/auto/qftp/tst_qftp.cpp @@ -378,6 +378,8 @@ void tst_QFtp::connectToUnresponsiveHost() a lot of other stuff in QFtp, so we just expect this test to fail on Windows. */ QEXPECT_FAIL("", "timeout not working due to strange Windows socket behaviour (see source file of this test for explanation)", Abort); +#else + QEXPECT_FAIL("", "QTBUG-20687", Abort); #endif QVERIFY2(! QTestEventLoop::instance().timeout(), "Network timeout longer than expected (should have been 60 seconds)"); From b1ea3efb52b97a3de6f728d1c24cb5051e90972a Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Tue, 2 Aug 2011 11:12:47 +1000 Subject: [PATCH 61/75] test: fixed spelling errors in tst_qtextscriptengine couln't -> couldn't Change-Id: I37e86ecea74db1114fcfac93423388fae81df63d Reviewed-on: http://codereview.qt.nokia.com/2465 Reviewed-by: Jason McDonald --- .../tst_qtextscriptengine.cpp | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/auto/qtextscriptengine/tst_qtextscriptengine.cpp b/tests/auto/qtextscriptengine/tst_qtextscriptengine.cpp index 6cbff362bc..11a9c60c48 100644 --- a/tests/auto/qtextscriptengine/tst_qtextscriptengine.cpp +++ b/tests/auto/qtextscriptengine/tst_qtextscriptengine.cpp @@ -233,7 +233,7 @@ void tst_QTextScriptEngine::devanagari() ++s; } } else { - QSKIP("couln't find Raghindi", SkipAll); + QSKIP("couldn't find Raghindi", SkipAll); } } @@ -403,7 +403,7 @@ void tst_QTextScriptEngine::bengali() ++s; } } else { - QSKIP("couln't find Akaash", SkipAll); + QSKIP("couldn't find Akaash", SkipAll); } } { @@ -508,7 +508,7 @@ void tst_QTextScriptEngine::bengali() ++s; } } else { - QSKIP("couln't find Mukti", SkipAll); + QSKIP("couldn't find Mukti", SkipAll); } } { @@ -536,7 +536,7 @@ void tst_QTextScriptEngine::bengali() ++s; } } else { - QSKIP("couln't find Likhan", SkipAll); + QSKIP("couldn't find Likhan", SkipAll); } } #else @@ -563,7 +563,7 @@ void tst_QTextScriptEngine::gurmukhi() ++s; } } else { - QSKIP("couln't find Lohit Punjabi", SkipAll); + QSKIP("couldn't find Lohit Punjabi", SkipAll); } } #endif @@ -600,7 +600,7 @@ void tst_QTextScriptEngine::oriya() ++s; } } else { - QSKIP("couln't find utkal", SkipAll); + QSKIP("couldn't find utkal", SkipAll); } } #else @@ -677,7 +677,7 @@ void tst_QTextScriptEngine::tamil() ++s; } } else { - QSKIP("couln't find AkrutiTml1", SkipAll); + QSKIP("couldn't find AkrutiTml1", SkipAll); } } #else @@ -725,7 +725,7 @@ void tst_QTextScriptEngine::telugu() ++s; } } else { - QSKIP("couln't find Pothana2000", SkipAll); + QSKIP("couldn't find Pothana2000", SkipAll); } } #else @@ -772,7 +772,7 @@ void tst_QTextScriptEngine::kannada() ++s; } } else { - QSKIP("couln't find Sampige", SkipAll); + QSKIP("couldn't find Sampige", SkipAll); } } { @@ -803,7 +803,7 @@ void tst_QTextScriptEngine::kannada() ++s; } } else { - QSKIP("couln't find Tunga", SkipAll); + QSKIP("couldn't find Tunga", SkipAll); } } #else @@ -864,7 +864,7 @@ void tst_QTextScriptEngine::malayalam() ++s; } } else { - QSKIP("couln't find AkrutiMal2", SkipAll); + QSKIP("couldn't find AkrutiMal2", SkipAll); } } { @@ -892,7 +892,7 @@ void tst_QTextScriptEngine::malayalam() ++s; } } else { - QSKIP("couln't find Rachana", SkipAll); + QSKIP("couldn't find Rachana", SkipAll); } } @@ -930,7 +930,7 @@ void tst_QTextScriptEngine::sinhala() ++s; } } else { - QSKIP("couln't find Malithi Web", SkipAll); + QSKIP("couldn't find Malithi Web", SkipAll); } } #else @@ -974,7 +974,7 @@ void tst_QTextScriptEngine::khmer() ++s; } } else { - QSKIP("couln't find Khmer OS", SkipAll); + QSKIP("couldn't find Khmer OS", SkipAll); } } #else @@ -1001,7 +1001,7 @@ void tst_QTextScriptEngine::linearB() ++s; } } else { - QSKIP("couln't find Penuturesu", SkipAll); + QSKIP("couldn't find Penuturesu", SkipAll); } } #else @@ -1075,7 +1075,7 @@ void tst_QTextScriptEngine::greek() QVERIFY( decomposedShaping(f, QChar(uc)) ); } } else { - QSKIP("couln't find DejaVu Sans", SkipAll); + QSKIP("couldn't find DejaVu Sans", SkipAll); } } @@ -1111,7 +1111,7 @@ void tst_QTextScriptEngine::greek() ++s; } } else { - QSKIP("couln't find SBL_grk", SkipAll); + QSKIP("couldn't find SBL_grk", SkipAll); } } #else From 7e57389a5bd1281751051a17bd28f5ebb3c07bb8 Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Tue, 2 Aug 2011 14:52:25 +1000 Subject: [PATCH 62/75] test: fixed tst_qmessagebox and removed CONFIG+=insignificant_test Removed some binary compatibility tests written specifically to test a change introduced between Qt 4.1 and 4.2. Qt 4 and 5 are not binary compatible, the test no longer makes sense. Change-Id: I3e8f9b6011105e504c20bedad51af8193b102552 Reviewed-on: http://codereview.qt.nokia.com/2464 Reviewed-by: Qt Sanity Bot Reviewed-by: Kalle Lehtonen --- tests/auto/qmessagebox/qmessagebox.pro | 2 - tests/auto/qmessagebox/tst_qmessagebox.cpp | 83 ---------------------- 2 files changed, 85 deletions(-) diff --git a/tests/auto/qmessagebox/qmessagebox.pro b/tests/auto/qmessagebox/qmessagebox.pro index f79b0707df..1893c42a64 100644 --- a/tests/auto/qmessagebox/qmessagebox.pro +++ b/tests/auto/qmessagebox/qmessagebox.pro @@ -6,5 +6,3 @@ INCLUDEPATH += . # Input SOURCES += tst_qmessagebox.cpp - -CONFIG+=insignificant_test diff --git a/tests/auto/qmessagebox/tst_qmessagebox.cpp b/tests/auto/qmessagebox/tst_qmessagebox.cpp index 0913454263..6b737681b1 100644 --- a/tests/auto/qmessagebox/tst_qmessagebox.cpp +++ b/tests/auto/qmessagebox/tst_qmessagebox.cpp @@ -127,9 +127,7 @@ private slots: void shortcut(); void staticSourceCompat(); - void staticBinaryCompat(); void instanceSourceCompat(); - void instanceBinaryCompat(); void testSymbols(); void incorrectDefaultButton(); @@ -407,19 +405,6 @@ void tst_QMessageBox::about() #endif } -// Old message box enums -const int Old_Ok = 1; -const int Old_Cancel = 2; -const int Old_Yes = 3; -const int Old_No = 4; -const int Old_Abort = 5; -const int Old_Retry = 6; -const int Old_Ignore = 7; -const int Old_YesAll = 8; -const int Old_NoAll = 9; -const int Old_Default = 0x100; -const int Old_Escape = 0x200; - void tst_QMessageBox::staticSourceCompat() { int ret; @@ -508,74 +493,6 @@ void tst_QMessageBox::instanceSourceCompat() QCOMPARE(exec(&mb, Qt::ALT + Qt::Key_Z), 1); } -void tst_QMessageBox::staticBinaryCompat() -{ - int ret; - - // binary compat tests for < 4.2 - keyToSend = Qt::Key_Enter; - sendKeySoon(); - ret = QMessageBox::information(0, "title", "text", Old_Yes, Old_No, 0); - int expectedButton = int(Old_Yes); -#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC) - if (qobject_cast(qApp->style())) - expectedButton = int(Old_No); -#elif !defined(QT_NO_STYLE_CLEANLOOKS) - if (qobject_cast(qApp->style())) - expectedButton = int(Old_No); -#endif - QCOMPARE(ret, expectedButton); - QCOMPARE(keyToSend, -1); - - keyToSend = Qt::Key_Escape; - sendKeySoon(); - ret = QMessageBox::information(0, "title", "text", Old_Yes | Old_Escape, Old_No, 0); - QCOMPARE(ret, int(Old_Yes)); - QCOMPARE(keyToSend, -1); - - keyToSend = Qt::Key_Enter; - sendKeySoon(); - ret = QMessageBox::information(0, "title", "text", Old_Yes | Old_Default, Old_No, 0); - QCOMPARE(ret, int(Old_Yes)); - QCOMPARE(keyToSend, -1); - -#if 0 - keyToSend = Qt::Key_Escape; - sendKeySoon(); - ret = QMessageBox::information(0, "title", "text", Old_Yes, Old_No | Old_Default, 0); - QCOMPARE(ret, -1); - QCOMPARE(keyToSend, -1); -#endif - - keyToSend = Qt::Key_Escape; - sendKeySoon(); - ret = QMessageBox::information(0, "title", "text", Old_Yes | Old_Escape, Old_No | Old_Default, 0); - QCOMPARE(ret, Old_Yes); - QCOMPARE(keyToSend, -1); - - keyToSend = Qt::Key_Escape; - sendKeySoon(); - ret = QMessageBox::information(0, "title", "text", Old_Yes | Old_Default, Old_No | Old_Escape, 0); - QCOMPARE(ret, Old_No); - QCOMPARE(keyToSend, -1); - -} - -void tst_QMessageBox::instanceBinaryCompat() -{ - QMessageBox mb("Application name here", - "Saving the file will overwrite the original file on the disk.\n" - "Do you really want to save?", - QMessageBox::Information, - Old_Yes | Old_Default, - Old_No, - Old_Cancel | Old_Escape); - mb.setButtonText(Old_Yes, "Save"); - mb.setButtonText(Old_No, "Discard"); - QCOMPARE(exec(&mb, Qt::Key_Enter), int(Old_Yes)); - QCOMPARE(exec(&mb, Qt::Key_Escape), int(Old_Cancel)); -} - void tst_QMessageBox::testSymbols() { return; From 6e745ecda73c360195de8760473eca88b31f87cf Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Tue, 2 Aug 2011 10:22:08 +1000 Subject: [PATCH 63/75] test: improved stability of tst_qwaitcondition Increased thread wait timeout from 3 to 10 milliseconds, for slower or heavily loaded machines. (There was a previous attempt to improve stability of this test some time ago by increasing the timeout from 1 to 3 milliseconds.) Note that this increases the runtime of the wakeOne test from ~5 to ~14 seconds. Change-Id: Ib556d4c949a6989fe71c11f5dc10feb2ec45c512 Reviewed-on: http://codereview.qt.nokia.com/2458 Reviewed-by: Qt Sanity Bot Reviewed-by: Kalle Lehtonen --- tests/auto/qwaitcondition/tst_qwaitcondition.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/auto/qwaitcondition/tst_qwaitcondition.cpp b/tests/auto/qwaitcondition/tst_qwaitcondition.cpp index c677d17fbe..6545df9189 100644 --- a/tests/auto/qwaitcondition/tst_qwaitcondition.cpp +++ b/tests/auto/qwaitcondition/tst_qwaitcondition.cpp @@ -491,7 +491,7 @@ void tst_QWaitCondition::wakeOne() for (int y = 0; y < ThreadCount; ++y) { if (thread_exited[y]) continue; - if (thread[y].wait(exited > 0 ? 3 : 1000)) { + if (thread[y].wait(exited > 0 ? 10 : 1000)) { thread_exited[y] = TRUE; ++exited; } @@ -535,7 +535,7 @@ void tst_QWaitCondition::wakeOne() for (int y = 0; y < ThreadCount; ++y) { if (thread_exited[y]) continue; - if (rwthread[y].wait(exited > 0 ? 3 : 1000)) { + if (rwthread[y].wait(exited > 0 ? 10 : 1000)) { thread_exited[y] = TRUE; ++exited; } @@ -587,7 +587,7 @@ void tst_QWaitCondition::wakeOne() for (int y = 0; y < ThreadCount; ++y) { if (thread_exited[y]) continue; - if (thread[y].wait(exited > 0 ? 3 : 1000)) { + if (thread[y].wait(exited > 0 ? 10 : 1000)) { thread_exited[y] = TRUE; ++exited; } @@ -633,7 +633,7 @@ void tst_QWaitCondition::wakeOne() for (int y = 0; y < ThreadCount; ++y) { if (thread_exited[y]) continue; - if (rwthread[y].wait(exited > 0 ? 3 : 1000)) { + if (rwthread[y].wait(exited > 0 ? 10 : 1000)) { thread_exited[y] = TRUE; ++exited; } From b117c3175e324446709ac77d6385d1c0f4c3315e Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Tue, 2 Aug 2011 09:44:09 +1000 Subject: [PATCH 64/75] test: fixed tst_qimagereader and removed CONFIG+=insignificant_test This test assumed that Qt's available image formats could be determined at compile time. This was never correct since the image formats are loaded from plugins at runtime; in Qt5 it became a real problem since one image format (svg) was moved out of qtbase into a separate module, turning this into a circular dependency: this test in qtbase depends on qtsvg, which depends on qtbase. Always check the image formats at runtime instead. Change-Id: I5e770c5b11276c39910e34f232a2fea0a7abaa8c Reviewed-on: http://codereview.qt.nokia.com/2457 Reviewed-by: Qt Sanity Bot Reviewed-by: Kalle Lehtonen --- tests/auto/qimagereader/qimagereader.pro | 8 - tests/auto/qimagereader/tst_qimagereader.cpp | 289 ++++++++----------- 2 files changed, 117 insertions(+), 180 deletions(-) diff --git a/tests/auto/qimagereader/qimagereader.pro b/tests/auto/qimagereader/qimagereader.pro index c2bf3259ec..5c939b3a3c 100644 --- a/tests/auto/qimagereader/qimagereader.pro +++ b/tests/auto/qimagereader/qimagereader.pro @@ -5,12 +5,6 @@ QT += core-private gui-private network RESOURCES += qimagereader.qrc !symbian:DEFINES += SRCDIR=\\\"$$PWD\\\" -!contains(QT_CONFIG, no-gif):DEFINES += QTEST_HAVE_GIF -!contains(QT_CONFIG, no-jpeg):DEFINES += QTEST_HAVE_JPEG -!contains(QT_CONFIG, no-mng):DEFINES += QTEST_HAVE_MNG -!contains(QT_CONFIG, no-tiff):DEFINES += QTEST_HAVE_TIFF -!contains(QT_CONFIG, no-svg):DEFINES += QTEST_HAVE_SVG - win32-msvc:QMAKE_CXXFLAGS -= -Zm200 win32-msvc:QMAKE_CXXFLAGS += -Zm800 win32-msvc.net:QMAKE_CXXFLAGS -= -Zm300 @@ -40,5 +34,3 @@ symbian: { DEPLOYMENT += imagePlugins } } - -CONFIG+=insignificant_test diff --git a/tests/auto/qimagereader/tst_qimagereader.cpp b/tests/auto/qimagereader/tst_qimagereader.cpp index 5d958d76dd..6359468597 100644 --- a/tests/auto/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/qimagereader/tst_qimagereader.cpp @@ -143,12 +143,10 @@ private slots: void imageFormatBeforeRead_data(); void imageFormatBeforeRead(); -#if defined QTEST_HAVE_GIF void gifHandlerBugs(); void animatedGif(); void gifImageCount(); void gifLoopCount(); -#endif void readCorruptImage_data(); void readCorruptImage(); @@ -157,7 +155,6 @@ private slots: void supportsOption_data(); void supportsOption(); -#if defined QTEST_HAVE_TIFF void tiffCompression_data(); void tiffCompression(); void tiffEndianness(); @@ -166,7 +163,6 @@ private slots: void tiffOrientation(); void tiffGrayscale(); -#endif void autoDetectImageFormat(); void fileNameProbing(); @@ -192,6 +188,12 @@ private slots: static const QLatin1String prefix(SRCDIR "/images/"); +// helper to skip an autotest when the given image format is not supported +#define SKIP_IF_UNSUPPORTED(format) do { \ + if (!QByteArray(format).isEmpty() && !QImageReader::supportedImageFormats().contains(format)) \ + QSKIP("\"" + QByteArray(format) + "\" images are not supported", SkipSingle); \ +} while (0) + // Testing get/set functions void tst_QImageReader::getSetCheck() { @@ -249,22 +251,17 @@ void tst_QImageReader::readImage_data() QTest::newRow("PPM: test") << QString("test.ppm") << true << QByteArray("ppm"); QTest::newRow("XBM: gnus") << QString("gnus.xbm") << true << QByteArray("xbm"); -#if defined QTEST_HAVE_JPEG QTest::newRow("JPEG: beavis") << QString("beavis.jpg") << true << QByteArray("jpeg"); QTest::newRow("JPEG: qtbug13653") << QString("qtbug13653-no_eoi.jpg") << true << QByteArray("jpeg"); -#endif -#if defined QTEST_HAVE_GIF + QTest::newRow("GIF: earth") << QString("earth.gif") << true << QByteArray("gif"); QTest::newRow("GIF: trolltech") << QString("trolltech.gif") << true << QByteArray("gif"); -#endif -#if defined QTEST_HAVE_MNG + QTest::newRow("MNG: ball") << QString("ball.mng") << true << QByteArray("mng"); QTest::newRow("MNG: fire") << QString("fire.mng") << true << QByteArray("mng"); -#endif -#if defined QTEST_HAVE_SVG + QTest::newRow("SVG: rect") << QString("rect.svg") << true << QByteArray("svg"); QTest::newRow("SVGZ: rect") << QString("rect.svgz") << true << QByteArray("svgz"); -#endif } void tst_QImageReader::readImage() @@ -273,6 +270,8 @@ void tst_QImageReader::readImage() QFETCH(bool, success); QFETCH(QByteArray, format); + SKIP_IF_UNSUPPORTED(format); + for (int i = 0; i < 2; ++i) { QImageReader io(prefix + fileName, i ? QByteArray() : format); if (success) { @@ -363,7 +362,7 @@ void tst_QImageReader::setScaledSize_data() QTest::newRow("PPM: runners") << "runners.ppm" << QSize(400, 400) << QByteArray("ppm"); QTest::newRow("PPM: test") << "test.ppm" << QSize(10, 10) << QByteArray("ppm"); QTest::newRow("XBM: gnus") << "gnus" << QSize(200, 200) << QByteArray("xbm"); -#ifdef QTEST_HAVE_JPEG + QTest::newRow("JPEG: beavis A") << "beavis" << QSize(200, 200) << QByteArray("jpeg"); QTest::newRow("JPEG: beavis B") << "beavis" << QSize(175, 175) << QByteArray("jpeg"); QTest::newRow("JPEG: beavis C") << "beavis" << QSize(100, 100) << QByteArray("jpeg"); @@ -373,19 +372,15 @@ void tst_QImageReader::setScaledSize_data() QTest::newRow("JPEG: beavis G") << "beavis" << QSize(50, 45) << QByteArray("jpeg"); QTest::newRow("JPEG: beavis H") << "beavis" << QSize(43, 43) << QByteArray("jpeg"); QTest::newRow("JPEG: beavis I") << "beavis" << QSize(25, 25) << QByteArray("jpeg"); -#endif // QTEST_HAVE_JPEG -#ifdef QTEST_HAVE_GIF + QTest::newRow("GIF: earth") << "earth" << QSize(200, 200) << QByteArray("gif"); QTest::newRow("GIF: trolltech") << "trolltech" << QSize(200, 200) << QByteArray("gif"); -#endif // QTEST_HAVE_GIF -#ifdef QTEST_HAVE_MNG + QTest::newRow("MNG: ball") << "ball" << QSize(200, 200) << QByteArray("mng"); QTest::newRow("MNG: fire") << "fire" << QSize(200, 200) << QByteArray("mng"); -#endif // QTEST_HAVE_MNG -#if defined QTEST_HAVE_SVG + QTest::newRow("SVG: rect") << "rect" << QSize(200, 200) << QByteArray("svg"); QTest::newRow("SVGZ: rect") << "rect" << QSize(200, 200) << QByteArray("svgz"); -#endif } void tst_QImageReader::setScaledSize() @@ -394,8 +389,7 @@ void tst_QImageReader::setScaledSize() QFETCH(QSize, newSize); QFETCH(QByteArray, format); - if (!format.isEmpty() && !QImageReader::supportedImageFormats().contains(format)) - QSKIP("Qt does not support reading the \"" + format + "\" format", SkipSingle); + SKIP_IF_UNSUPPORTED(format); QImageReader reader(prefix + fileName); reader.setScaledSize(newSize); @@ -415,8 +409,7 @@ void tst_QImageReader::task255627_setNullScaledSize() QFETCH(QString, fileName); QFETCH(QByteArray, format); - if (!format.isEmpty() && !QImageReader::supportedImageFormats().contains(format)) - QSKIP("Qt does not support reading the \"" + format + "\" format", SkipSingle); + SKIP_IF_UNSUPPORTED(format); QImageReader reader(prefix + fileName); @@ -444,21 +437,17 @@ void tst_QImageReader::setClipRect_data() QTest::newRow("PPM: runners") << "runners.ppm" << QRect(0, 0, 50, 50) << QByteArray("ppm"); QTest::newRow("PPM: test") << "test.ppm" << QRect(0, 0, 50, 50) << QByteArray("ppm"); QTest::newRow("XBM: gnus") << "gnus" << QRect(0, 0, 50, 50) << QByteArray("xbm"); -#ifdef QTEST_HAVE_JPEG + QTest::newRow("JPEG: beavis") << "beavis" << QRect(0, 0, 50, 50) << QByteArray("jpeg"); -#endif // QTEST_HAVE_JPEG -#ifdef QTEST_HAVE_GIF + QTest::newRow("GIF: earth") << "earth" << QRect(0, 0, 50, 50) << QByteArray("gif"); QTest::newRow("GIF: trolltech") << "trolltech" << QRect(0, 0, 50, 50) << QByteArray("gif"); -#endif // QTEST_HAVE_GIF -#ifdef QTEST_HAVE_MNG + QTest::newRow("MNG: ball") << "ball" << QRect(0, 0, 50, 50) << QByteArray("mng"); QTest::newRow("MNG: fire") << "fire" << QRect(0, 0, 50, 50) << QByteArray("mng"); -#endif // QTEST_HAVE_MNG -#if defined QTEST_HAVE_SVG + QTest::newRow("SVG: rect") << "rect" << QRect(0, 0, 50, 50) << QByteArray("svg"); QTest::newRow("SVGZ: rect") << "rect" << QRect(0, 0, 50, 50) << QByteArray("svgz"); -#endif } void tst_QImageReader::setClipRect() @@ -467,8 +456,7 @@ void tst_QImageReader::setClipRect() QFETCH(QRect, newRect); QFETCH(QByteArray, format); - if (!format.isEmpty() && !QImageReader::supportedImageFormats().contains(format)) - QSKIP("Qt does not support reading the \"" + format + "\" format", SkipSingle); + SKIP_IF_UNSUPPORTED(format); QImageReader reader(prefix + fileName); reader.setClipRect(newRect); @@ -497,21 +485,17 @@ void tst_QImageReader::setScaledClipRect_data() QTest::newRow("PPM: runners") << "runners.ppm" << QRect(0, 0, 50, 50) << QByteArray("ppm"); QTest::newRow("PPM: test") << "test.ppm" << QRect(0, 0, 50, 50) << QByteArray("ppm"); QTest::newRow("XBM: gnus") << "gnus" << QRect(0, 0, 50, 50) << QByteArray("xbm"); -#ifdef QTEST_HAVE_JPEG + QTest::newRow("JPEG: beavis") << "beavis" << QRect(0, 0, 50, 50) << QByteArray("jpeg"); -#endif // QTEST_HAVE_JPEG -#ifdef QTEST_HAVE_GIF + QTest::newRow("GIF: earth") << "earth" << QRect(0, 0, 50, 50) << QByteArray("gif"); QTest::newRow("GIF: trolltech") << "trolltech" << QRect(0, 0, 50, 50) << QByteArray("gif"); -#endif // QTEST_HAVE_GIF -#ifdef QTEST_HAVE_MNG + QTest::newRow("MNG: ball") << "ball" << QRect(0, 0, 50, 50) << QByteArray("mng"); QTest::newRow("MNG: fire") << "fire" << QRect(0, 0, 50, 50) << QByteArray("mng"); -#endif // QTEST_HAVE_MNG -#if defined QTEST_HAVE_SVG + QTest::newRow("SVG: rect") << "rect" << QRect(0, 0, 50, 50) << QByteArray("svg"); QTest::newRow("SVGZ: rect") << "rect" << QRect(0, 0, 50, 50) << QByteArray("svgz"); -#endif } void tst_QImageReader::setScaledClipRect() @@ -520,8 +504,7 @@ void tst_QImageReader::setScaledClipRect() QFETCH(QRect, newRect); QFETCH(QByteArray, format); - if (!format.isEmpty() && !QImageReader::supportedImageFormats().contains(format)) - QSKIP("Qt does not support reading the \"" + format + "\" format", SkipSingle); + SKIP_IF_UNSUPPORTED(format); QImageReader reader(prefix + fileName); reader.setScaledSize(QSize(300, 300)); @@ -548,15 +531,14 @@ void tst_QImageReader::imageFormat_data() QTest::newRow("ppm-2") << QString("teapot.ppm") << QByteArray("ppm") << QImage::Format_RGB32; QTest::newRow("ppm-3") << QString("runners.ppm") << QByteArray("ppm") << QImage::Format_RGB32; QTest::newRow("ppm-4") << QString("test.ppm") << QByteArray("ppm") << QImage::Format_RGB32; -#ifdef QTEST_HAVE_JPEG + QTest::newRow("jpeg-1") << QString("beavis.jpg") << QByteArray("jpeg") << QImage::Format_Indexed8; QTest::newRow("jpeg-2") << QString("YCbCr_cmyk.jpg") << QByteArray("jpeg") << QImage::Format_RGB32; QTest::newRow("jpeg-3") << QString("YCbCr_rgb.jpg") << QByteArray("jpeg") << QImage::Format_RGB32; -#endif -#if defined QTEST_HAVE_GIF + QTest::newRow("gif-1") << QString("earth.gif") << QByteArray("gif") << QImage::Format_Invalid; QTest::newRow("gif-2") << QString("trolltech.gif") << QByteArray("gif") << QImage::Format_Invalid; -#endif + QTest::newRow("xbm") << QString("gnus.xbm") << QByteArray("xbm") << QImage::Format_MonoLSB; QTest::newRow("xpm") << QString("marble.xpm") << QByteArray("xpm") << QImage::Format_Indexed8; QTest::newRow("bmp-1") << QString("colorful.bmp") << QByteArray("bmp") << QImage::Format_Indexed8; @@ -577,27 +559,9 @@ void tst_QImageReader::imageFormat() QFETCH(QByteArray, format); QFETCH(QImage::Format, imageFormat); - if (QImageReader::imageFormat(prefix + fileName).isEmpty()) { - if (QByteArray("jpeg") == format) -#ifndef QTEST_HAVE_JPEG - return; -#endif // !QTEST_HAVE_JPEG - if (QByteArray("gif") == format) -#ifndef QTEST_HAVE_GIF - return; -#endif // !QTEST_HAVE_GIF - if (QByteArray("mng") == format) -#ifndef QTEST_HAVE_MNG - return; -#endif // !QTEST_HAVE_MNG - if (QByteArray("svg") == format || QByteArray("svgz") == format) -#ifndef QTEST_HAVE_SVG - return; -#endif // !QTEST_HAVE_SVG - QSKIP(("Qt does not support the " + format + " format.").constData(), SkipSingle); - } else { - QCOMPARE(QImageReader::imageFormat(prefix + fileName), format); - } + SKIP_IF_UNSUPPORTED(format); + + QCOMPARE(QImageReader::imageFormat(prefix + fileName), format); QImageReader reader(prefix + fileName); QCOMPARE(reader.imageFormat(), imageFormat); } @@ -657,21 +621,17 @@ void tst_QImageReader::setBackgroundColor_data() QTest::newRow("PPM: runners") << QString("runners.ppm") << QColor(Qt::red); QTest::newRow("PPM: test") << QString("test.ppm") << QColor(Qt::white); QTest::newRow("XBM: gnus") << QString("gnus.xbm") << QColor(Qt::blue); -#if defined QTEST_HAVE_JPEG + QTest::newRow("JPEG: beavis") << QString("beavis.jpg") << QColor(Qt::darkBlue); -#endif -#if defined QTEST_HAVE_GIF + QTest::newRow("GIF: earth") << QString("earth.gif") << QColor(Qt::cyan); QTest::newRow("GIF: trolltech") << QString("trolltech.gif") << QColor(Qt::magenta); -#endif -#if defined QTEST_HAVE_MNG + QTest::newRow("MNG: ball") << QString("ball.mng") << QColor(Qt::yellow); QTest::newRow("MNG: fire") << QString("fire.mng") << QColor(Qt::gray); -#endif -#if defined QTEST_HAVE_SVG + QTest::newRow("SVG: rect") << QString("rect.svg") << QColor(Qt::darkGreen); QTest::newRow("SVGZ: rect") << QString("rect.svgz") << QColor(Qt::darkGreen); -#endif } void tst_QImageReader::setBackgroundColor() @@ -700,21 +660,17 @@ void tst_QImageReader::supportsAnimation_data() QTest::newRow("PPM: teapot") << QString("teapot.ppm") << false; QTest::newRow("PPM: runners") << QString("runners.ppm") << false; QTest::newRow("XBM: gnus") << QString("gnus.xbm") << false; -#if defined QTEST_HAVE_JPEG + QTest::newRow("JPEG: beavis") << QString("beavis.jpg") << false; -#endif -#if defined QTEST_HAVE_GIF + QTest::newRow("GIF: earth") << QString("earth.gif") << true; QTest::newRow("GIF: trolltech") << QString("trolltech.gif") << true; -#endif -#if defined QTEST_HAVE_MNG + QTest::newRow("MNG: ball") << QString("ball.mng") << true; QTest::newRow("MNG: fire") << QString("fire.mng") << true; -#endif -#if defined QTEST_HAVE_SVG + QTest::newRow("SVG: rect") << QString("rect.svg") << false; QTest::newRow("SVGZ: rect") << QString("rect.svgz") << false; -#endif } void tst_QImageReader::supportsAnimation() @@ -734,6 +690,9 @@ void tst_QImageReader::sizeBeforeRead() { QFETCH(QString, fileName); QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); + QImageReader reader(prefix + fileName); QVERIFY(reader.canRead()); if (format == "mng") { @@ -781,7 +740,11 @@ void tst_QImageReader::imageFormatBeforeRead_data() void tst_QImageReader::imageFormatBeforeRead() { QFETCH(QString, fileName); + QFETCH(QByteArray, format); QFETCH(QImage::Format, imageFormat); + + SKIP_IF_UNSUPPORTED(format); + QImageReader reader(fileName); if (reader.supportsOption(QImageIOHandler::ImageFormat)) { QImage::Format fileFormat = reader.imageFormat(); @@ -793,9 +756,10 @@ void tst_QImageReader::imageFormatBeforeRead() } } -#if defined QTEST_HAVE_GIF void tst_QImageReader::gifHandlerBugs() { + SKIP_IF_UNSUPPORTED("gif"); + { QImageReader io(prefix + "trolltech.gif"); QVERIFY(io.loopCount() != 1); @@ -837,6 +801,8 @@ void tst_QImageReader::gifHandlerBugs() void tst_QImageReader::animatedGif() { + SKIP_IF_UNSUPPORTED("gif"); + QImageReader io(":images/qt.gif"); QImage image = io.read(); QVERIFY(!image.isNull()); @@ -852,6 +818,8 @@ void tst_QImageReader::animatedGif() // Check the count of images in various call orders... void tst_QImageReader::gifImageCount() { + SKIP_IF_UNSUPPORTED("gif"); + // just read every frame... and see how much we got.. { QImageReader io(":images/four-frames.gif"); @@ -987,6 +955,8 @@ void tst_QImageReader::gifImageCount() void tst_QImageReader::gifLoopCount() { + SKIP_IF_UNSUPPORTED("gif"); + { QImageReader io(":images/qt-gif-anim.gif"); QCOMPARE(io.loopCount(), -1); // infinite loop @@ -997,8 +967,6 @@ void tst_QImageReader::gifLoopCount() } } -#endif - class Server : public QObject { Q_OBJECT @@ -1060,16 +1028,15 @@ void tst_QImageReader::readFromDevice_data() QTest::newRow("ppm-2") << QString("teapot.ppm") << QByteArray("ppm"); QTest::newRow("ppm-3") << QString("teapot.ppm") << QByteArray("ppm"); QTest::newRow("ppm-4") << QString("runners.ppm") << QByteArray("ppm"); -#ifdef QTEST_HAVE_JPEG + QTest::newRow("jpeg-1") << QString("beavis.jpg") << QByteArray("jpeg"); QTest::newRow("jpeg-2") << QString("YCbCr_cmyk.jpg") << QByteArray("jpeg"); QTest::newRow("jpeg-3") << QString("YCbCr_rgb.jpg") << QByteArray("jpeg"); QTest::newRow("jpeg-4") << QString("qtbug13653-no_eoi.jpg") << QByteArray("jpeg"); -#endif // QTEST_HAVE_JPEG -#ifdef QTEST_HAVE_GIF + QTest::newRow("gif-1") << QString("earth.gif") << QByteArray("gif"); QTest::newRow("gif-2") << QString("trolltech.gif") << QByteArray("gif"); -#endif // QTEST_HAVE_GIF + QTest::newRow("xbm") << QString("gnus.xbm") << QByteArray("xbm"); QTest::newRow("xpm") << QString("marble.xpm") << QByteArray("xpm"); QTest::newRow("bmp-1") << QString("colorful.bmp") << QByteArray("bmp"); @@ -1077,14 +1044,12 @@ void tst_QImageReader::readFromDevice_data() QTest::newRow("bmp-3") << QString("test32bfv4.bmp") << QByteArray("bmp"); QTest::newRow("bmp-4") << QString("test32v5.bmp") << QByteArray("bmp"); QTest::newRow("png") << QString("kollada.png") << QByteArray("png"); -#ifdef QTEST_HAVE_MNG + QTest::newRow("mng-1") << QString("ball.mng") << QByteArray("mng"); QTest::newRow("mng-2") << QString("fire.mng") << QByteArray("mng"); -#endif // QTEST_HAVE_MNG -#if defined QTEST_HAVE_SVG + QTest::newRow("svg") << QString("rect.svg") << QByteArray("svg"); QTest::newRow("svgz") << QString("rect.svgz") << QByteArray("svgz"); -#endif } void tst_QImageReader::readFromDevice() @@ -1092,6 +1057,8 @@ void tst_QImageReader::readFromDevice() QFETCH(QString, fileName); QFETCH(QByteArray, format); + SKIP_IF_UNSUPPORTED(format); + QImage expectedImage(prefix + fileName, format); QFile file(prefix + fileName); @@ -1154,15 +1121,11 @@ void tst_QImageReader::readFromFileAfterJunk_data() QTest::newRow("ppm-2") << QString("teapot.ppm") << QByteArray("ppm"); QTest::newRow("ppm-3") << QString("teapot.ppm") << QByteArray("ppm"); QTest::newRow("ppm-4") << QString("runners.ppm") << QByteArray("ppm"); -#ifdef QTEST_HAVE_JPEG + QTest::newRow("jpeg-1") << QString("beavis.jpg") << QByteArray("jpeg"); QTest::newRow("jpeg-2") << QString("YCbCr_cmyk.jpg") << QByteArray("jpeg"); QTest::newRow("jpeg-3") << QString("YCbCr_rgb.jpg") << QByteArray("jpeg"); -#endif -#if defined QTEST_HAVE_GIF -// QTest::newRow("gif-1") << QString("images/earth.gif") << QByteArray("gif"); -// QTest::newRow("gif-2") << QString("images/trolltech.gif") << QByteArray("gif"); -#endif + QTest::newRow("xbm") << QString("gnus.xbm") << QByteArray("xbm"); QTest::newRow("xpm") << QString("marble.xpm") << QByteArray("xpm"); QTest::newRow("bmp-1") << QString("colorful.bmp") << QByteArray("bmp"); @@ -1170,12 +1133,8 @@ void tst_QImageReader::readFromFileAfterJunk_data() QTest::newRow("bmp-3") << QString("test32bfv4.bmp") << QByteArray("bmp"); QTest::newRow("bmp-4") << QString("test32v5.bmp") << QByteArray("bmp"); QTest::newRow("png") << QString("kollada.png") << QByteArray("png"); -// QTest::newRow("mng-1") << QString("images/ball.mng") << QByteArray("mng"); -// QTest::newRow("mng-2") << QString("images/fire.mng") << QByteArray("mng"); -#if defined QTEST_HAVE_SVG QTest::newRow("svg") << QString("rect.svg") << QByteArray("svg"); QTest::newRow("svgz") << QString("rect.svgz") << QByteArray("svgz"); -#endif } void tst_QImageReader::readFromFileAfterJunk() @@ -1183,10 +1142,7 @@ void tst_QImageReader::readFromFileAfterJunk() QFETCH(QString, fileName); QFETCH(QByteArray, format); - if (!QImageReader::supportedImageFormats().contains(format)) { - QString cause = QString("Skipping %1; no %2 support").arg(fileName).arg(QString(format)); - QSKIP(qPrintable(cause), SkipSingle); - } + SKIP_IF_UNSUPPORTED(format); QFile::remove("junk"); QFile junkFile("junk"); @@ -1235,14 +1191,13 @@ void tst_QImageReader::devicePosition_data() QTest::newRow("pbm") << QString("image.pbm") << QByteArray("pbm"); QTest::newRow("pgm") << QString("image.pgm") << QByteArray("pgm"); QTest::newRow("ppm-1") << QString("image.ppm") << QByteArray("ppm"); -#ifdef QTEST_HAVE_JPEG + QTest::newRow("jpeg-1") << QString("beavis.jpg") << QByteArray("jpeg"); QTest::newRow("jpeg-2") << QString("YCbCr_cmyk.jpg") << QByteArray("jpeg"); QTest::newRow("jpeg-3") << QString("YCbCr_rgb.jpg") << QByteArray("jpeg"); -#endif -#if defined QTEST_HAVE_GIF + QTest::newRow("gif-1") << QString("earth.gif") << QByteArray("gif"); -#endif + QTest::newRow("xbm") << QString("gnus.xbm") << QByteArray("xbm"); QTest::newRow("xpm") << QString("marble.xpm") << QByteArray("xpm"); QTest::newRow("bmp-1") << QString("colorful.bmp") << QByteArray("bmp"); @@ -1250,12 +1205,8 @@ void tst_QImageReader::devicePosition_data() QTest::newRow("bmp-3") << QString("test32bfv4.bmp") << QByteArray("bmp"); QTest::newRow("bmp-4") << QString("test32v5.bmp") << QByteArray("bmp"); QTest::newRow("png") << QString("kollada.png") << QByteArray("png"); -// QTest::newRow("mng-1") << QString("images/ball.mng") << QByteArray("mng"); -// QTest::newRow("mng-2") << QString("images/fire.mng") << QByteArray("mng"); -#if defined QTEST_HAVE_SVG QTest::newRow("svg") << QString("rect.svg") << QByteArray("svg"); QTest::newRow("svgz") << QString("rect.svgz") << QByteArray("svgz"); -#endif } void tst_QImageReader::devicePosition() @@ -1263,6 +1214,8 @@ void tst_QImageReader::devicePosition() QFETCH(QString, fileName); QFETCH(QByteArray, format); + SKIP_IF_UNSUPPORTED(format); + QImage expected(prefix + fileName); QVERIFY(!expected.isNull()); @@ -1327,7 +1280,6 @@ void tst_QImageReader::readFromResources_data() QTest::newRow("test32v5.bmp") << QString("test32v5.bmp") << QByteArray("bmp") << QSize(373, 156) << QString(""); -#ifdef QTEST_HAVE_GIF QTest::newRow("corrupt.gif") << QString("corrupt.gif") << QByteArray("gif") << QSize(0, 0) << QString(""); @@ -1346,8 +1298,6 @@ void tst_QImageReader::readFromResources_data() QTest::newRow("bat2.gif") << QString("bat2.gif") << QByteArray("gif") << QSize(32, 32) << QString(""); -#endif -#ifdef QTEST_HAVE_JPEG QTest::newRow("corrupt.jpg") << QString("corrupt.jpg") << QByteArray("jpg") << QSize(0, 0) << QString("JPEG datastream contains no image"); @@ -1363,8 +1313,6 @@ void tst_QImageReader::readFromResources_data() QTest::newRow("qtbug13653-no_eoi.jpg") << QString("qtbug13653-no_eoi.jpg") << QByteArray("jpg") << QSize(240, 180) << QString(""); -#endif -#ifdef QTEST_HAVE_MNG QTest::newRow("corrupt.mng") << QString("corrupt.mng") << QByteArray("mng") << QSize(0, 0) << QString("MNG error 901: Application signalled I/O error; chunk IHDR; subcode 0:0"); @@ -1374,8 +1322,6 @@ void tst_QImageReader::readFromResources_data() QTest::newRow("ball.mng") << QString("ball.mng") << QByteArray("mng") << QSize(32, 32) << QString(""); -#endif -#ifdef QTEST_HAVE_SVG QTest::newRow("rect.svg") << QString("rect.svg") << QByteArray("svg") << QSize(105, 137) << QString(""); @@ -1388,7 +1334,6 @@ void tst_QImageReader::readFromResources_data() QTest::newRow("corrupt.svgz") << QString("corrupt.svgz") << QByteArray("svgz") << QSize(0, 0) << QString(""); -#endif QTest::newRow("image.pbm") << QString("image.pbm") << QByteArray("pbm") << QSize(16, 6) << QString(""); @@ -1425,7 +1370,6 @@ void tst_QImageReader::readFromResources_data() QTest::newRow("test.ppm") << QString("test.ppm") << QByteArray("ppm") << QSize(10, 10) << QString(""); -// QTest::newRow("corrupt.xbm") << QString("corrupt.xbm") << QByteArray("xbm") << QSize(0, 0); QTest::newRow("gnus.xbm") << QString("gnus.xbm") << QByteArray("xbm") << QSize(271, 273) << QString(""); @@ -1464,6 +1408,9 @@ void tst_QImageReader::readFromResources() QFETCH(QByteArray, format); QFETCH(QSize, size); QFETCH(QString, message); + + SKIP_IF_UNSUPPORTED(format); + for (int i = 0; i < 2; ++i) { QString file = i ? (":/images/" + fileName) : (prefix + fileName); { @@ -1537,31 +1484,26 @@ void tst_QImageReader::readCorruptImage_data() QTest::addColumn("fileName"); QTest::addColumn("shouldFail"); QTest::addColumn("message"); -#if defined QTEST_HAVE_JPEG + QTest::addColumn("format"); QTest::newRow("corrupt jpeg") << QString("corrupt.jpg") << true - << QString("JPEG datastream contains no image"); -#endif -#if defined QTEST_HAVE_GIF - QTest::newRow("corrupt gif") << QString("corrupt.gif") << true << QString(""); -#endif -#ifdef QTEST_HAVE_MNG + << QString("JPEG datastream contains no image") + << QByteArray("jpeg"); + QTest::newRow("corrupt gif") << QString("corrupt.gif") << true << QString("") << QByteArray("gif"); QTest::newRow("corrupt mng") << QString("corrupt.mng") << true - << QString("MNG error 901: Application signalled I/O error; chunk IHDR; subcode 0:0"); -#endif - QTest::newRow("corrupt png") << QString("corrupt.png") << true << QString(""); - QTest::newRow("corrupt bmp") << QString("corrupt.bmp") << true << QString(""); + << QString("MNG error 901: Application signalled I/O error; chunk IHDR; subcode 0:0") + << QByteArray("mng"); + QTest::newRow("corrupt png") << QString("corrupt.png") << true << QString("") << QByteArray("png"); + QTest::newRow("corrupt bmp") << QString("corrupt.bmp") << true << QString("") << QByteArray("bmp"); QTest::newRow("corrupt xpm (colors)") << QString("corrupt-colors.xpm") << true - << QString("QImage: XPM color specification is missing: bla9an.n#x"); + << QString("QImage: XPM color specification is missing: bla9an.n#x") + << QByteArray("xpm"); QTest::newRow("corrupt xpm (pixels)") << QString("corrupt-pixels.xpm") << true - << QString("QImage: XPM pixels missing on image line 3"); - QTest::newRow("corrupt xbm") << QString("corrupt.xbm") << false << QString(""); -#if defined QTEST_HAVE_TIFF - QTest::newRow("corrupt tiff") << QString("corrupt-data.tif") << true << QString(""); -#endif -#if defined QTEST_HAVE_SVG - QTest::newRow("corrupt svg") << QString("corrupt.svg") << true << QString(""); - QTest::newRow("corrupt svgz") << QString("corrupt.svgz") << true << QString(""); -#endif + << QString("QImage: XPM pixels missing on image line 3") + << QByteArray("xpm"); + QTest::newRow("corrupt xbm") << QString("corrupt.xbm") << false << QString("") << QByteArray("xbm"); + QTest::newRow("corrupt tiff") << QString("corrupt-data.tif") << true << QString("") << QByteArray("tiff"); + QTest::newRow("corrupt svg") << QString("corrupt.svg") << true << QString("") << QByteArray("svg"); + QTest::newRow("corrupt svgz") << QString("corrupt.svgz") << true << QString("") << QByteArray("svgz"); } void tst_QImageReader::readCorruptImage() @@ -1569,6 +1511,9 @@ void tst_QImageReader::readCorruptImage() QFETCH(QString, fileName); QFETCH(bool, shouldFail); QFETCH(QString, message); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); if (!message.isEmpty()) QTest::ignoreMessage(QtWarningMsg, message.toLatin1()); @@ -1625,7 +1570,6 @@ void tst_QImageReader::supportsOption() QVERIFY(!reader.supportsOption(option)); } -#if defined QTEST_HAVE_TIFF void tst_QImageReader::tiffCompression_data() { QTest::addColumn("uncompressedFile"); @@ -1646,6 +1590,8 @@ void tst_QImageReader::tiffCompression() QFETCH(QString, uncompressedFile); QFETCH(QString, compressedFile); + SKIP_IF_UNSUPPORTED("tiff"); + QImage uncompressedImage(prefix + uncompressedFile); QImage compressedImage(prefix + compressedFile); @@ -1654,6 +1600,8 @@ void tst_QImageReader::tiffCompression() void tst_QImageReader::tiffEndianness() { + SKIP_IF_UNSUPPORTED("tiff"); + QImage littleEndian(prefix + "rgba_nocompression_littleendian.tif"); QImage bigEndian(prefix + "rgba_nocompression_bigendian.tif"); @@ -1697,6 +1645,8 @@ void tst_QImageReader::tiffOrientation() QFETCH(QString, expected); QFETCH(QString, oriented); + SKIP_IF_UNSUPPORTED("tiff"); + QImage expectedImage(prefix + expected); QImage orientedImage(prefix + oriented); QCOMPARE(expectedImage, orientedImage); @@ -1704,22 +1654,22 @@ void tst_QImageReader::tiffOrientation() void tst_QImageReader::tiffGrayscale() { + SKIP_IF_UNSUPPORTED("tiff"); + QImage actualImage(prefix + "grayscale.tif"); QImage expectedImage(prefix + "grayscale-ref.tif"); QCOMPARE(expectedImage, actualImage.convertToFormat(expectedImage.format())); } -#endif void tst_QImageReader::dotsPerMeter_data() { QTest::addColumn("fileName"); QTest::addColumn("expectedDotsPerMeterX"); QTest::addColumn("expectedDotsPerMeterY"); -#if defined QTEST_HAVE_TIFF - QTest::newRow("TIFF: 72 dpi") << ("rgba_nocompression_littleendian.tif") << qRound(72 * (100 / 2.54)) << qRound(72 * (100 / 2.54)); - QTest::newRow("TIFF: 100 dpi") << ("image_100dpi.tif") << qRound(100 * (100 / 2.54)) << qRound(100 * (100 / 2.54)); -#endif + QTest::addColumn("format"); + QTest::newRow("TIFF: 72 dpi") << ("rgba_nocompression_littleendian.tif") << qRound(72 * (100 / 2.54)) << qRound(72 * (100 / 2.54)) << QByteArray("tiff"); + QTest::newRow("TIFF: 100 dpi") << ("image_100dpi.tif") << qRound(100 * (100 / 2.54)) << qRound(100 * (100 / 2.54)) << QByteArray("tiff"); } void tst_QImageReader::dotsPerMeter() @@ -1727,6 +1677,9 @@ void tst_QImageReader::dotsPerMeter() QFETCH(QString, fileName); QFETCH(int, expectedDotsPerMeterX); QFETCH(int, expectedDotsPerMeterY); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); QImage image(prefix + fileName); @@ -1739,10 +1692,9 @@ void tst_QImageReader::physicalDpi_data() QTest::addColumn("fileName"); QTest::addColumn("expectedPhysicalDpiX"); QTest::addColumn("expectedPhysicalDpiY"); -#if defined QTEST_HAVE_TIFF - QTest::newRow("TIFF: 72 dpi") << "rgba_nocompression_littleendian.tif" << 72 << 72; - QTest::newRow("TIFF: 100 dpi") << "image_100dpi.tif" << 100 << 100; -#endif + QTest::addColumn("format"); + QTest::newRow("TIFF: 72 dpi") << "rgba_nocompression_littleendian.tif" << 72 << 72 << QByteArray("tiff"); + QTest::newRow("TIFF: 100 dpi") << "image_100dpi.tif" << 100 << 100 << QByteArray("tiff"); } void tst_QImageReader::physicalDpi() @@ -1750,6 +1702,9 @@ void tst_QImageReader::physicalDpi() QFETCH(QString, fileName); QFETCH(int, expectedPhysicalDpiX); QFETCH(int, expectedPhysicalDpiY); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); QImage image(prefix + fileName); @@ -1791,21 +1746,19 @@ void tst_QImageReader::autoDetectImageFormat() QVERIFY(!reader.read().isNull()); } -#ifdef QTEST_HAVE_JPEG - { + if (QImageReader::supportedImageFormats().contains("jpeg")) { QImageReader io(prefix + "YCbCr_rgb.jpg"); io.setAutoDetectImageFormat(false); // This should fail since no format string is given QImage image; QVERIFY(!io.read(&image)); } - { + if (QImageReader::supportedImageFormats().contains("jpeg")) { QImageReader io(prefix + "YCbCr_rgb.jpg", "jpg"); io.setAutoDetectImageFormat(false); QImage image; QVERIFY(io.read(&image)); } -#endif { QImageReader io(prefix + "tst7.png"); io.setAutoDetectImageFormat(false); @@ -1895,26 +1848,16 @@ void tst_QImageReader::testIgnoresFormatAndExtension_data() QTest::newRow("image.pbm") << "image" << "pbm" << "pbm"; QTest::newRow("image.pgm") << "image" << "pgm" << "pgm"; -#if defined QTEST_HAVE_GIF QTest::newRow("bat1.gif") << "bat1" << "gif" << "gif"; -#endif -#if defined QTEST_HAVE_JPEG QTest::newRow("beavis.jpg") << "beavis" << "jpg" << "jpeg"; -#endif -#if defined QTEST_HAVE_MNG QTest::newRow("fire.mng") << "fire" << "mng" << "mng"; -#endif -#if defined QTEST_HAVE_TIFF QTest::newRow("image_100dpi.tif") << "image_100dpi" << "tif" << "tiff"; -#endif -#if defined QTEST_HAVE_SVG QTest::newRow("rect.svg") << "rect" << "svg" << "svg"; QTest::newRow("rect.svgz") << "rect" << "svgz" << "svgz"; -#endif } @@ -1924,6 +1867,8 @@ void tst_QImageReader::testIgnoresFormatAndExtension() QFETCH(QString, extension); QFETCH(QString, expected); + SKIP_IF_UNSUPPORTED(expected.toLatin1()); + QList formats = QImageReader::supportedImageFormats(); QString fileNameBase = prefix + name + "."; From 493634a71190679666082687626c05047b5cd463 Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Tue, 2 Aug 2011 09:24:25 +1000 Subject: [PATCH 65/75] test: improved stability of tst_qiodevice on slow machines Increased network timeout from 5 to 30 seconds. Change-Id: I4751dbfbb82c2091f1cec26150f06f913ffbe4c0 Reviewed-on: http://codereview.qt.nokia.com/2456 Reviewed-by: Qt Sanity Bot Reviewed-by: Kalle Lehtonen --- tests/auto/qiodevice/tst_qiodevice.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/auto/qiodevice/tst_qiodevice.cpp b/tests/auto/qiodevice/tst_qiodevice.cpp index 70debfa1f3..a0f57f9d8d 100644 --- a/tests/auto/qiodevice/tst_qiodevice.cpp +++ b/tests/auto/qiodevice/tst_qiodevice.cpp @@ -129,11 +129,11 @@ void tst_QIODevice::constructing_QTcpSocket() QVERIFY(!device->isOpen()); socket.connectToHost(QtNetworkSettings::serverName(), 143); - QVERIFY(socket.waitForConnected(5000)); + QVERIFY(socket.waitForConnected(30000)); QVERIFY(device->isOpen()); while (!device->canReadLine()) - QVERIFY(device->waitForReadyRead(5000)); + QVERIFY(device->waitForReadyRead(30000)); char buf[1024]; memset(buf, 0, sizeof(buf)); @@ -143,11 +143,11 @@ void tst_QIODevice::constructing_QTcpSocket() socket.close(); socket.connectToHost(QtNetworkSettings::serverName(), 143); - QVERIFY(socket.waitForConnected(5000)); + QVERIFY(socket.waitForConnected(30000)); QVERIFY(device->isOpen()); while (!device->canReadLine()) - QVERIFY(device->waitForReadyRead(5000)); + QVERIFY(device->waitForReadyRead(30000)); char buf2[1024]; memset(buf2, 0, sizeof(buf2)); From 569cd194d20e61d35768b210b4351f4eeb5c1ef8 Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Tue, 2 Aug 2011 09:13:38 +1000 Subject: [PATCH 66/75] test: fixed crash of tst_qdialog and removed CONFIG+=insignificant_test This test assumed that C++ exceptions could always be caught by the event loop. This is not the case when the Glib event loop is used. Skip the relevant portion of the test in that case. Change-Id: I6a6325c3590c810a5aba28ec98279581dcfaf55c Reviewed-on: http://codereview.qt.nokia.com/2455 Reviewed-by: Qt Sanity Bot Reviewed-by: Kalle Lehtonen --- tests/auto/qdialog/qdialog.pro | 3 --- tests/auto/qdialog/tst_qdialog.cpp | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/tests/auto/qdialog/qdialog.pro b/tests/auto/qdialog/qdialog.pro index ab7bfd9022..161a6b47f1 100644 --- a/tests/auto/qdialog/qdialog.pro +++ b/tests/auto/qdialog/qdialog.pro @@ -1,5 +1,2 @@ load(qttest_p4) SOURCES += tst_qdialog.cpp - - -CONFIG+=insignificant_test diff --git a/tests/auto/qdialog/tst_qdialog.cpp b/tests/auto/qdialog/tst_qdialog.cpp index 6d9f7988cd..86dde21ba0 100644 --- a/tests/auto/qdialog/tst_qdialog.cpp +++ b/tests/auto/qdialog/tst_qdialog.cpp @@ -467,6 +467,22 @@ void tst_QDialog::throwInExec() #if defined(Q_WS_MAC) || (defined(Q_WS_WINCE) && defined(_ARM_)) QSKIP("Throwing exceptions in exec() is not supported on this platform.", SkipAll); #endif + +#if defined(Q_OS_LINUX) + // C++ exceptions can't be passed through glib callbacks. Skip the test if + // we're using the glib event loop. + QByteArray dispatcher = QAbstractEventDispatcher::instance()->metaObject()->className(); + if (dispatcher.contains("Glib")) { + QSKIP( + qPrintable(QString( + "Throwing exceptions in exec() won't work if %1 event dispatcher is used.\n" + "Try running with QT_NO_GLIB=1 in environment." + ).arg(QString::fromLatin1(dispatcher))), + SkipAll + ); + } +#endif + int caughtExceptions = 0; try { ExceptionDialog dialog; From c07e1130d9fbfec2aeda2248341858b12a99fb93 Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Mon, 1 Aug 2011 16:44:09 +1000 Subject: [PATCH 67/75] test: fixed failure of tst_qicon This test unconditionally assumed that SVG support was available. This is an invalid circular dependency: the test is in qtbase and depends on qtsvg, which depends on qtbase. Change the test so that it uses SVG support only if available. Change-Id: Ia63ce74abdecd4bcf7a4e0714b8cb7c488e17495 Reviewed-on: http://codereview.qt.nokia.com/2426 Reviewed-by: Qt Sanity Bot Reviewed-by: Sergio Ahumada --- tests/auto/qicon/qicon.pro | 2 -- tests/auto/qicon/tst_qicon.cpp | 20 +++++++++++++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/tests/auto/qicon/qicon.pro b/tests/auto/qicon/qicon.pro index 21d967b978..77a9b91032 100644 --- a/tests/auto/qicon/qicon.pro +++ b/tests/auto/qicon/qicon.pro @@ -27,5 +27,3 @@ wince* { } else { DEFINES += SRCDIR=\\\"$$PWD\\\" } - -CONFIG+=insignificant_test diff --git a/tests/auto/qicon/tst_qicon.cpp b/tests/auto/qicon/tst_qicon.cpp index cd3f84f4b0..4c430f9435 100644 --- a/tests/auto/qicon/tst_qicon.cpp +++ b/tests/auto/qicon/tst_qicon.cpp @@ -41,7 +41,7 @@ #include - +#include #include #if defined(Q_OS_SYMBIAN) @@ -87,6 +87,8 @@ private slots: void task239461_custom_iconengine_crash(); private: + bool haveImageFormat(QByteArray const&); + QString oldCurrentDir; const static QIcon staticIcon; @@ -112,6 +114,11 @@ void tst_QIcon::cleanup() } } +bool tst_QIcon::haveImageFormat(QByteArray const& desiredFormat) +{ + return QImageReader::supportedImageFormats().contains(desiredFormat); +} + tst_QIcon::tst_QIcon() { } @@ -205,6 +212,10 @@ void tst_QIcon::actualSize2() void tst_QIcon::svgActualSize() { + if (!haveImageFormat("svg")) { + QSKIP("SVG support is not available", SkipAll); + } + const QString prefix = QLatin1String(SRCDIR) + QLatin1String("/"); QIcon icon(prefix + "rect.svg"); QCOMPARE(icon.actualSize(QSize(16, 16)), QSize(16, 2)); @@ -415,6 +426,9 @@ void tst_QIcon::detach() void tst_QIcon::svg() { + if (!haveImageFormat("svg")) { + QSKIP("SVG support is not available", SkipAll); + } QIcon icon1("heart.svg"); QVERIFY(!icon1.pixmap(32).isNull()); @@ -521,14 +535,14 @@ void tst_QIcon::availableSizes() QCOMPARE(availableSizes.at(0), QSize(16,16)); } - { + if (haveImageFormat("svg")) { // checks that there are no availableSizes for scalable images. QIcon icon("heart.svg"); QList availableSizes = icon.availableSizes(); QVERIFY(availableSizes.isEmpty()); } - { + if (haveImageFormat("svg")) { // even if an a scalable image contain added pixmaps, // availableSizes still should be empty. QIcon icon("heart.svg"); From 95d9a0c25c207c7dfc5fa228e90a2eb873b2ecbc Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Mon, 1 Aug 2011 14:38:36 +1000 Subject: [PATCH 68/75] test: remove CONFIG+=insignificant_test for tst_qgraphicstransform This autotest failure is stable, so it should be marked with QEXPECT_FAIL, not CONFIG+=insignificant_test. Note that the test row naming had to be changed, as the test previously created many rows of testdata with the same name, making it impossible to skip only the broken rows. Task-number: QTBUG-20661 Change-Id: Ie38f5dddafe7686e30eaa8ff3445310935d2cd9a Reviewed-on: http://codereview.qt.nokia.com/2419 Reviewed-by: Sergio Ahumada Reviewed-by: Qt Sanity Bot --- .../qgraphicstransform/qgraphicstransform.pro | 2 - .../tst_qgraphicstransform.cpp | 58 +++++++++++++++++-- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/tests/auto/qgraphicstransform/qgraphicstransform.pro b/tests/auto/qgraphicstransform/qgraphicstransform.pro index b5e8f34c74..67c939ed8b 100644 --- a/tests/auto/qgraphicstransform/qgraphicstransform.pro +++ b/tests/auto/qgraphicstransform/qgraphicstransform.pro @@ -1,5 +1,3 @@ load(qttest_p4) SOURCES += tst_qgraphicstransform.cpp CONFIG += parallel_test - -CONFIG+=insignificant_test diff --git a/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp b/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp index f229ee7d5f..7b928909ff 100644 --- a/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp +++ b/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp @@ -61,6 +61,9 @@ private slots: void rotation3d(); void rotation3dArbitraryAxis_data(); void rotation3dArbitraryAxis(); + +private: + QString toString(QTransform const&); }; @@ -305,6 +308,15 @@ void tst_QGraphicsTransform::rotation3d() QVERIFY(transform2D(rotation).isIdentity()); } +QByteArray labelForTest(QVector3D const& axis, int angle) { + return QString("rotation of %1 on (%2, %3, %4)") + .arg(angle) + .arg(axis.x()) + .arg(axis.y()) + .arg(axis.z()) + .toLatin1(); +} + void tst_QGraphicsTransform::rotation3dArbitraryAxis_data() { QTest::addColumn("axis"); @@ -317,11 +329,11 @@ void tst_QGraphicsTransform::rotation3dArbitraryAxis_data() QVector3D axis5 = QVector3D(0.01f, 0.01f, 0.01f); for (int angle = 0; angle <= 360; angle++) { - QTest::newRow("test rotation on (1, 1, 1)") << axis1 << qreal(angle); - QTest::newRow("test rotation on (2, -3, .5)") << axis2 << qreal(angle); - QTest::newRow("test rotation on (-2, 0, -.5)") << axis3 << qreal(angle); - QTest::newRow("test rotation on (.0001, .0001, .0001)") << axis4 << qreal(angle); - QTest::newRow("test rotation on (.01, .01, .01)") << axis5 << qreal(angle); + QTest::newRow(labelForTest(axis1, angle).constData()) << axis1 << qreal(angle); + QTest::newRow(labelForTest(axis2, angle).constData()) << axis2 << qreal(angle); + QTest::newRow(labelForTest(axis3, angle).constData()) << axis3 << qreal(angle); + QTest::newRow(labelForTest(axis4, angle).constData()) << axis4 << qreal(angle); + QTest::newRow(labelForTest(axis5, angle).constData()) << axis5 << qreal(angle); } } @@ -347,7 +359,26 @@ void tst_QGraphicsTransform::rotation3dArbitraryAxis() exp.rotate(angle, axis); QTransform expected = exp.toTransform(1024.0f); - QVERIFY(fuzzyCompare(transform2D(rotation), expected)); +#ifdef Q_OS_LINUX + // These failures possibly relate to the float vs qreal issue mentioned + // in the comment above fuzzyCompare(). + if (sizeof(qreal) == sizeof(double)) { + QEXPECT_FAIL("rotation of 120 on (1, 1, 1)", "QTBUG-20661", Abort); + QEXPECT_FAIL("rotation of 240 on (1, 1, 1)", "QTBUG-20661", Abort); + QEXPECT_FAIL("rotation of 120 on (0.01, 0.01, 0.01)", "QTBUG-20661", Abort); + QEXPECT_FAIL("rotation of 240 on (0.01, 0.01, 0.01)", "QTBUG-20661", Abort); + QEXPECT_FAIL("rotation of 120 on (0.0001, 0.0001, 0.0001)", "QTBUG-20661", Abort); + QEXPECT_FAIL("rotation of 240 on (0.0001, 0.0001, 0.0001)", "QTBUG-20661", Abort); + } +#endif + + QTransform actual = transform2D(rotation); + QVERIFY2(fuzzyCompare(actual, expected), qPrintable( + QString("\nactual: %1\n" + "expected: %2") + .arg(toString(actual)) + .arg(toString(expected)) + )); // Check that "rotation" produces the 4x4 form of the 3x3 matrix. // i.e. third row and column are 0 0 1 0. @@ -357,6 +388,21 @@ void tst_QGraphicsTransform::rotation3dArbitraryAxis() QVERIFY(qFuzzyCompare(t, r)); } +QString tst_QGraphicsTransform::toString(QTransform const& t) +{ + return QString("[ [ %1 %2 %3 ]; [ %4 %5 %6 ]; [ %7 %8 %9 ] ]") + .arg(t.m11()) + .arg(t.m12()) + .arg(t.m13()) + .arg(t.m21()) + .arg(t.m22()) + .arg(t.m23()) + .arg(t.m31()) + .arg(t.m32()) + .arg(t.m33()) + ; +} + QTEST_MAIN(tst_QGraphicsTransform) #include "tst_qgraphicstransform.moc" From c8ee59952a050506dfebe939c04af2e67aaee849 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Mon, 18 Apr 2011 17:20:49 +0200 Subject: [PATCH 69/75] Introduced a CONFIG option that enables declarative debug services This replaces the need for applications to explicitly make a call to enable the debug services, and rather does it in declarative.h when the 'declarative_debug' CONFIG option is used. Done-with: Kai Koehne Reviewed-by: Martin Jones Reviewed-by: Michael Brasser (cherry-picked from commit 5517cc588c39814530b8bfd957821f55be42acf2) Change-Id: If180d2b826879d6d02c7be4d3075917815ccf349 Reviewed-on: http://codereview.qt.nokia.com/2435 Reviewed-by: Qt Sanity Bot Reviewed-by: Martin Jones --- mkspecs/features/declarative_debug.prf | 1 + 1 file changed, 1 insertion(+) create mode 100644 mkspecs/features/declarative_debug.prf diff --git a/mkspecs/features/declarative_debug.prf b/mkspecs/features/declarative_debug.prf new file mode 100644 index 0000000000..b0248f0ac3 --- /dev/null +++ b/mkspecs/features/declarative_debug.prf @@ -0,0 +1 @@ +contains(QT, declarative):DEFINES += QT_DECLARATIVE_DEBUG From af6c1a32982564035f3f9d1c0887c9d3fc0e5bbb Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Tue, 2 Aug 2011 11:35:01 +1000 Subject: [PATCH 70/75] test: skip some tst_qtextscriptengine tests when fonts are missing This autotest may fail depending on the version of fonts which are installed on the system. It has no way to verify if the correct fonts are installed, and it's unclear from where the correct version of the fonts may be obtained. Therefore, disable the test by default unless the user has indicated that they have a correct setup by setting QT_HAVE_TEST_FONTS=1. Task-number: QTBUG-20682 Change-Id: I24174520f54af6a9b2c13c9c1347f46555bce3d4 Reviewed-on: http://codereview.qt.nokia.com/2469 Reviewed-by: Qt Sanity Bot Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../qtextscriptengine/qtextscriptengine.pro | 2 - .../tst_qtextscriptengine.cpp | 67 ++++++++++++++++++- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/tests/auto/qtextscriptengine/qtextscriptengine.pro b/tests/auto/qtextscriptengine/qtextscriptengine.pro index 1bd80d35b6..0f5076e2ed 100644 --- a/tests/auto/qtextscriptengine/qtextscriptengine.pro +++ b/tests/auto/qtextscriptengine/qtextscriptengine.pro @@ -5,5 +5,3 @@ QT += core-private gui-private HEADERS += SOURCES += tst_qtextscriptengine.cpp INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/harfbuzz/src - -CONFIG+=insignificant_test diff --git a/tests/auto/qtextscriptengine/tst_qtextscriptengine.cpp b/tests/auto/qtextscriptengine/tst_qtextscriptengine.cpp index 11a9c60c48..cbed675cb7 100644 --- a/tests/auto/qtextscriptengine/tst_qtextscriptengine.cpp +++ b/tests/auto/qtextscriptengine/tst_qtextscriptengine.cpp @@ -76,9 +76,6 @@ //TESTED_CLASS= //TESTED_FILES= gui/text/qscriptengine.cpp -// This test depends on the fonts in the following package being installed: -// http://people.freedesktop.org/~hausmann/harfbuzz-test-fonts-0.1.tar.bz2 - class tst_QTextScriptEngine : public QObject { Q_OBJECT @@ -89,6 +86,7 @@ public: public slots: + void initTestCase(); void init(); void cleanup(); private slots: @@ -111,9 +109,13 @@ private slots: void mirroredChars_data(); void mirroredChars(); + +private: + bool haveTestFonts; }; tst_QTextScriptEngine::tst_QTextScriptEngine() + : haveTestFonts(qgetenv("QT_HAVE_TEST_FONTS") == QByteArray("1")) { } @@ -121,6 +123,21 @@ tst_QTextScriptEngine::~tst_QTextScriptEngine() { } +void tst_QTextScriptEngine::initTestCase() +{ +#if defined(Q_WS_X11) + if (!haveTestFonts) { + qWarning( + "Some of these tests depend on the internals of some test fonts which are not freely " + "distributable.\n" + "These tests will be skipped.\n" + "If you have the fonts available, set QT_HAVE_TEST_FONTS=1 in your environment and " + "run the test again." + ); + } +#endif +} + void tst_QTextScriptEngine::init() { } @@ -184,6 +201,10 @@ static bool shaping( const QFont &f, const ShapeTable *s) void tst_QTextScriptEngine::devanagari() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Devanagari).contains("Raghindi")) { QFont f("Raghindi"); @@ -296,6 +317,10 @@ void tst_QTextScriptEngine::devanagari() void tst_QTextScriptEngine::bengali() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Bengali).contains("Akaash")) { QFont f("Akaash"); @@ -547,6 +572,10 @@ void tst_QTextScriptEngine::bengali() void tst_QTextScriptEngine::gurmukhi() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Gurmukhi).contains("Lohit Punjabi")) { QFont f("Lohit Punjabi"); @@ -572,6 +601,10 @@ void tst_QTextScriptEngine::gurmukhi() void tst_QTextScriptEngine::oriya() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Oriya).contains("utkal")) { QFont f("utkal"); @@ -612,6 +645,10 @@ void tst_QTextScriptEngine::oriya() void tst_QTextScriptEngine::tamil() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Tamil).contains("AkrutiTml1")) { QFont f("AkrutiTml1"); @@ -689,6 +726,10 @@ void tst_QTextScriptEngine::tamil() void tst_QTextScriptEngine::telugu() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Telugu).contains("Pothana2000")) { QFont f("Pothana2000"); @@ -816,6 +857,10 @@ void tst_QTextScriptEngine::kannada() void tst_QTextScriptEngine::malayalam() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Malayalam).contains("AkrutiMal2")) { QFont f("AkrutiMal2"); @@ -904,6 +949,10 @@ void tst_QTextScriptEngine::malayalam() void tst_QTextScriptEngine::sinhala() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Sinhala).contains("Malithi Web")) { QFont f("Malithi Web"); @@ -942,6 +991,10 @@ void tst_QTextScriptEngine::sinhala() void tst_QTextScriptEngine::khmer() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Khmer).contains("Khmer OS")) { QFont f("Khmer OS"); @@ -985,6 +1038,10 @@ void tst_QTextScriptEngine::khmer() void tst_QTextScriptEngine::linearB() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Any).contains("Penuturesu")) { QFont f("Penuturesu"); @@ -1060,6 +1117,10 @@ static bool decomposedShaping( const QFont &f, const QChar &ch) void tst_QTextScriptEngine::greek() { #if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + { if (QFontDatabase().families(QFontDatabase::Any).contains("DejaVu Sans")) { QFont f("DejaVu Sans"); From c8a31a31004f7d8953c86656ee04c40af40efd82 Mon Sep 17 00:00:00 2001 From: Jason McDonald Date: Tue, 2 Aug 2011 14:20:34 +1000 Subject: [PATCH 71/75] Eliminate reference to Trolltech. Task-number: QTBUG-19653 Change-Id: If3c822dd59ccbdd03037068acfe902ed9688a874 Reviewed-on: http://codereview.qt.nokia.com/2482 Reviewed-by: Qt Sanity Bot Reviewed-by: Rohan McGovern --- examples/tools/settingseditor/locationdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tools/settingseditor/locationdialog.cpp b/examples/tools/settingseditor/locationdialog.cpp index 911392630b..6ebf56682c 100644 --- a/examples/tools/settingseditor/locationdialog.cpp +++ b/examples/tools/settingseditor/locationdialog.cpp @@ -54,7 +54,7 @@ LocationDialog::LocationDialog(QWidget *parent) scopeComboBox->addItem(tr("System")); organizationComboBox = new QComboBox; - organizationComboBox->addItem(tr("Trolltech")); + organizationComboBox->addItem(tr("Qt")); organizationComboBox->setEditable(true); applicationComboBox = new QComboBox; From c6b6278ab298da0ae312a61b524b84ac39998c05 Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Tue, 2 Aug 2011 17:06:34 +1000 Subject: [PATCH 72/75] Make failure messages from tst_QSslCertificate::verify much more useful Changes the failure message from the previously brief: '(errors.count() == 0)' returned FALSE. To the vastly more useful: '(errors.count() == 0)' returned FALSE. (errors: [ "The certificate has expired" ]) Change-Id: I587cd8ddfd3c17e273220bc95691b3dc92390547 Reviewed-on: http://codereview.qt.nokia.com/2241 Reviewed-by: Qt Sanity Bot Reviewed-by: Peter Hartmann --- .../qsslcertificate/tst_qsslcertificate.cpp | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/tests/auto/qsslcertificate/tst_qsslcertificate.cpp b/tests/auto/qsslcertificate/tst_qsslcertificate.cpp index 1b3d039ded..e0bc029c71 100644 --- a/tests/auto/qsslcertificate/tst_qsslcertificate.cpp +++ b/tests/auto/qsslcertificate/tst_qsslcertificate.cpp @@ -118,6 +118,9 @@ private slots: void subjectAndIssuerAttributes(); void verify(); + // helper for verbose test failure messages + QString toString(const QList&); + // ### add tests for certificate bundles (multiple certificates concatenated into a single // structure); both PEM and DER formatted #endif @@ -907,10 +910,16 @@ void tst_QSslCertificate::verify() QList errors; QList toVerify; + // Like QVERIFY, but be verbose about the content of `errors' when failing +#define VERIFY_VERBOSE(A) \ + QVERIFY2((A), \ + qPrintable(QString("errors: %1").arg(toString(errors))) \ + ) + // Empty chain is unspecified error errors = QSslCertificate::verify(toVerify); - QVERIFY(errors.count() == 1); - QVERIFY(errors[0] == QSslError(QSslError::UnspecifiedError)); + VERIFY_VERBOSE(errors.count() == 1); + VERIFY_VERBOSE(errors[0] == QSslError(QSslError::UnspecifiedError)); errors.clear(); // Verify a valid cert signed by a CA @@ -921,7 +930,7 @@ void tst_QSslCertificate::verify() errors = QSslCertificate::verify(toVerify); QEXPECT_FAIL("", "QTBUG-20582 fails since ~5am, 27th July 2011", Continue); - QVERIFY(errors.count() == 0); + VERIFY_VERBOSE(errors.count() == 0); errors.clear(); // Test a blacklisted certificate @@ -940,8 +949,8 @@ void tst_QSslCertificate::verify() // This one is expired and untrusted toVerify = QSslCertificate::fromPath(SRCDIR "more-certificates/cert-large-serial-number.pem"); errors = QSslCertificate::verify(toVerify); - QVERIFY(errors.contains(QSslError(QSslError::SelfSignedCertificate, toVerify[0]))); - QVERIFY(errors.contains(QSslError(QSslError::CertificateExpired, toVerify[0]))); + VERIFY_VERBOSE(errors.contains(QSslError(QSslError::SelfSignedCertificate, toVerify[0]))); + VERIFY_VERBOSE(errors.contains(QSslError(QSslError::CertificateExpired, toVerify[0]))); errors.clear(); toVerify.clear(); @@ -949,7 +958,7 @@ void tst_QSslCertificate::verify() toVerify << QSslCertificate::fromPath(SRCDIR "verify-certs/test-intermediate-not-ca-cert.pem").first(); toVerify << QSslCertificate::fromPath(SRCDIR "verify-certs/test-ocsp-good-cert.pem").first(); errors = QSslCertificate::verify(toVerify); - QVERIFY(errors.contains(QSslError(QSslError::InvalidCaCertificate, toVerify[1]))); + VERIFY_VERBOSE(errors.contains(QSslError(QSslError::InvalidCaCertificate, toVerify[1]))); toVerify.clear(); // This one is signed by a valid cert, and the signer is a valid CA @@ -957,17 +966,30 @@ void tst_QSslCertificate::verify() toVerify << QSslCertificate::fromPath(SRCDIR "verify-certs/test-intermediate-ca-cert.pem").first(); errors = QSslCertificate::verify(toVerify); QEXPECT_FAIL("", "QTBUG-20582 fails since ~5am, 27th July 2011", Continue); - QVERIFY(errors.length() == 0); + VERIFY_VERBOSE(errors.count() == 0); // Recheck the above with hostname validation errors = QSslCertificate::verify(toVerify, QLatin1String("example.com")); QEXPECT_FAIL("", "QTBUG-20582 fails since ~5am, 27th July 2011", Continue); - QVERIFY(errors.length() == 0); + VERIFY_VERBOSE(errors.count() == 0); // Recheck the above with a bad hostname errors = QSslCertificate::verify(toVerify, QLatin1String("fail.example.com")); - QVERIFY(errors.contains(QSslError(QSslError::HostNameMismatch, toVerify[0]))); + VERIFY_VERBOSE(errors.contains(QSslError(QSslError::HostNameMismatch, toVerify[0]))); toVerify.clear(); + +#undef VERIFY_VERBOSE +} + +QString tst_QSslCertificate::toString(const QList& errors) +{ + QStringList errorStrings; + + foreach (const QSslError& error, errors) { + errorStrings.append(QLatin1String("\"") + error.errorString() + QLatin1String("\"")); + } + + return QLatin1String("[ ") + errorStrings.join(QLatin1String(", ")) + QLatin1String(" ]"); } #endif // QT_NO_OPENSSL From dd032aacc0b2ebe960176296426b4ad23a73de37 Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Tue, 2 Aug 2011 13:47:31 +1000 Subject: [PATCH 73/75] test: mark tst_qabstractnetworkcache as insignificant This test crashes pseudorandomly, which makes the result insignificant for the purpose of detecting regressions. Task-number: QTBUG-20686 Change-Id: I3079d935d46a4bcd2b119c2b9b452f0b69dccf21 Reviewed-on: http://codereview.qt.nokia.com/2479 Reviewed-by: Qt Sanity Bot Reviewed-by: Kalle Lehtonen --- tests/auto/qabstractnetworkcache/qabstractnetworkcache.pro | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/qabstractnetworkcache/qabstractnetworkcache.pro b/tests/auto/qabstractnetworkcache/qabstractnetworkcache.pro index 6f5044f6bb..4dea3c9c8c 100644 --- a/tests/auto/qabstractnetworkcache/qabstractnetworkcache.pro +++ b/tests/auto/qabstractnetworkcache/qabstractnetworkcache.pro @@ -10,3 +10,5 @@ wince*|symbian: { } symbian: TARGET.CAPABILITY = NetworkServices + +CONFIG += insignificant_test # QTBUG-20686; note, assumed unstable on all platforms From b29fae1736ed306f10629bbd8b3363a23afbfb0f Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Tue, 2 Aug 2011 16:41:47 +1000 Subject: [PATCH 74/75] test: mark tst_qtconcurrentfilter as insignificant on Linux This test fails pseudorandomly, which makes the result insignificant for the purpose of detecting regressions. Task-number: QTBUG-20688 Change-Id: I3274953841a553e35b4eb844702868f2f9ec0525 Reviewed-on: http://codereview.qt.nokia.com/2491 Reviewed-by: Qt Sanity Bot Reviewed-by: Sergio Ahumada --- tests/auto/qtconcurrentfilter/qtconcurrentfilter.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qtconcurrentfilter/qtconcurrentfilter.pro b/tests/auto/qtconcurrentfilter/qtconcurrentfilter.pro index ee2b77d63c..62d4908e69 100644 --- a/tests/auto/qtconcurrentfilter/qtconcurrentfilter.pro +++ b/tests/auto/qtconcurrentfilter/qtconcurrentfilter.pro @@ -3,4 +3,4 @@ DEFINES += QT_STRICT_ITERATORS SOURCES += tst_qtconcurrentfilter.cpp QT = core CONFIG += parallel_test -CONFIG += parallel_test +linux*:CONFIG += insignificant_test From 6f4212e5936b96a8be0eacddbfc4dd7ca5abd776 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 2 Aug 2011 15:58:48 +0200 Subject: [PATCH 75/75] Fix QString/QByteArray literals for MSVC2010 (compilation of tests). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Specify return type of QByteArrayLiteral/QStringLiteral lambdas. - Define QT_UNICODE_LITERAL instead of QT_UNICODE_MARKER. Change-Id: I8a53506887d2736b093798220b088f645f05e415 Reviewed-on: http://codereview.qt.nokia.com/2514 Reviewed-by: Qt Sanity Bot Reviewed-by: João Abecasis --- src/corelib/tools/qbytearray.h | 2 +- src/corelib/tools/qstring.h | 23 +++++++++++++++-------- tests/auto/qstring/tst_qstring.cpp | 2 +- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h index 5cf4c15179..b70dba4d55 100644 --- a/src/corelib/tools/qbytearray.h +++ b/src/corelib/tools/qbytearray.h @@ -146,7 +146,7 @@ template struct QConstByteArrayDataPtr #if defined(Q_COMPILER_LAMBDA) -# define QByteArrayLiteral(str) ([]() { \ +# define QByteArrayLiteral(str) ([]() -> QConstByteArrayDataPtr { \ enum { Size = sizeof(str) - 1 }; \ static const QConstByteArrayData qbytearray_literal = \ { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, str }; \ diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 4471da4b09..209994de16 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -102,7 +102,8 @@ template struct QConstStringData const QStringData str; const char16_t data[N + 1]; }; -#define QT_QSTRING_UNICODE_MARKER u"" + +#define QT_UNICODE_LITERAL_II(str) u"" str #elif defined(Q_OS_WIN) || (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) || defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536) // wchar_t is 2 bytes @@ -111,7 +112,12 @@ template struct QConstStringData const QStringData str; const wchar_t data[N + 1]; }; -#define QT_QSTRING_UNICODE_MARKER L"" + +#if defined(Q_CC_MSVC) +# define QT_UNICODE_LITERAL_II(str) L##str +#else +# define QT_UNICODE_LITERAL_II(str) L"" str +#endif #else template struct QConstStringData @@ -121,12 +127,13 @@ template struct QConstStringData }; #endif -#if defined(QT_QSTRING_UNICODE_MARKER) +#if defined(QT_UNICODE_LITERAL_II) +# define QT_UNICODE_LITERAL(str) QT_UNICODE_LITERAL_II(str) # if defined(Q_COMPILER_LAMBDA) -# define QStringLiteral(str) ([]() { \ - enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 - 1 }; \ +# define QStringLiteral(str) ([]() -> QConstStringDataPtr { \ + enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \ static const QConstStringData qstring_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_UNICODE_LITERAL(str) }; \ QConstStringDataPtr holder = { &qstring_literal }; \ return holder; }()) @@ -137,9 +144,9 @@ template struct QConstStringData # define QStringLiteral(str) \ __extension__ ({ \ - enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 - 1 }; \ + enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \ static const QConstStringData qstring_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_UNICODE_LITERAL(str) }; \ QConstStringDataPtr holder = { &qstring_literal }; \ holder; }) # endif diff --git a/tests/auto/qstring/tst_qstring.cpp b/tests/auto/qstring/tst_qstring.cpp index 8c725fa109..f7a725c164 100644 --- a/tests/auto/qstring/tst_qstring.cpp +++ b/tests/auto/qstring/tst_qstring.cpp @@ -5110,7 +5110,7 @@ void tst_QString::toUpperLower_icu() void tst_QString::literals() { -#if defined(QT_QSTRING_UNICODE_MARKER) && (defined(Q_COMPILER_LAMBDA) || defined(Q_CC_GNU)) +#if defined(QT_UNICODE_LITERAL) && (defined(Q_COMPILER_LAMBDA) || defined(Q_CC_GNU)) QString str(QStringLiteral("abcd")); QVERIFY(str.length() == 4);