From 34af6fd31e29334e9ffe5d390d5a8b40c5a4a9c6 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Mon, 7 Nov 2011 11:58:04 +0100 Subject: Ensure that the RC_FILE is correctly handled in a single configuration With MSVC 2010 if a single configuration vcxproj file was created then it would not have an entry for the .rc file only the .res file that would be compiled from it. Without the entry for the .rc file then it would not compile the .res file. Task-number: QTBUG-22545 Merge-request: 1452 Reviewed-by: Joerg Bornemann --- qmake/generators/win32/msbuild_objectmodel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/qmake/generators/win32/msbuild_objectmodel.cpp b/qmake/generators/win32/msbuild_objectmodel.cpp index c70d966..130f273 100644 --- a/qmake/generators/win32/msbuild_objectmodel.cpp +++ b/qmake/generators/win32/msbuild_objectmodel.cpp @@ -2896,6 +2896,7 @@ XmlOutput &operator<<(XmlOutput &xml, const VCXProjectSingleConfig &tool) tempProj.outputFilter(xml, xmlFilter, tempProj.ExtraCompilers.at(x)); } + tempProj.outputFilter(xml, xmlFilter, "Root Files"); xml << import("Project", "$(VCTargetsPath)\\Microsoft.Cpp.targets"); xml << tag("ImportGroup") -- cgit v0.12 From 2c072ae53ea4f90a32cfb8260f1bd0251ebab4f9 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Fri, 4 Nov 2011 18:35:41 +0100 Subject: Compile when -no-rtti is specified as a configure option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After discussing with Marko who did the original backport of the ShaderEffect to Qt 4.7 it was agreed that this is the correct thing to do in this case. Merge-request: 2713 Task-number: QTBUG-22419 Reviewed-by: Marko Niemelä --- src/imports/shaders/shadereffect.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/imports/shaders/shadereffect.cpp b/src/imports/shaders/shadereffect.cpp index f40d6b8..a5164e2 100644 --- a/src/imports/shaders/shadereffect.cpp +++ b/src/imports/shaders/shadereffect.cpp @@ -61,6 +61,7 @@ ShaderEffect::~ShaderEffect() void ShaderEffect::prepareBufferedDraw(QPainter *painter) { +#ifndef QT_NO_DYNAMIC_CAST // This workaround needed because QGraphicsEffect seems to always utilize default painters worldtransform // instead of the active painters worldtransform. const ShaderEffectBuffer *effectBuffer = dynamic_cast (painter->device()); @@ -70,6 +71,9 @@ void ShaderEffect::prepareBufferedDraw(QPainter *painter) } else { savedWorldTransform = painter->worldTransform(); } +#else + Q_UNUSED(painter); +#endif } void ShaderEffect::draw (QPainter *painter) -- cgit v0.12 From 3342cd1a4003912dfb419dbe4d3babd1f9c30173 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 17 Oct 2011 15:57:31 +0100 Subject: Symbian - fix compile error when default configured New code assumed building with OpenGL/OpenVG, which is the production configuration, but not the default configuration Reviewed-By: Jani Hautakangas Task-Number: QTBUG-21996 --- src/gui/painting/qgraphicssystemex_symbian.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/painting/qgraphicssystemex_symbian.cpp b/src/gui/painting/qgraphicssystemex_symbian.cpp index 32e040f..5a182ff 100644 --- a/src/gui/painting/qgraphicssystemex_symbian.cpp +++ b/src/gui/painting/qgraphicssystemex_symbian.cpp @@ -46,7 +46,7 @@ #include -#ifdef Q_SYMBIAN_SUPPORTS_SURFACES +#if defined(Q_SYMBIAN_SUPPORTS_SURFACES) && !defined (QT_NO_EGL) #include "private/qegl_p.h" #endif @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE static bool bcm2727Initialized = false; static bool bcm2727 = false; -#ifdef Q_SYMBIAN_SUPPORTS_SURFACES +#if defined(Q_SYMBIAN_SUPPORTS_SURFACES) && !defined (QT_NO_EGL) typedef EGLBoolean (*NOK_resource_profiling)(EGLDisplay, EGLint, EGLint*, EGLint, EGLint*); #define EGL_PROF_TOTAL_MEMORY_NOK 0x3070 #endif @@ -69,7 +69,7 @@ bool QSymbianGraphicsSystemEx::hasBCM2727() if (bcm2727Initialized) return bcm2727; -#ifdef Q_SYMBIAN_SUPPORTS_SURFACES +#if defined(Q_SYMBIAN_SUPPORTS_SURFACES) && !defined (QT_NO_EGL) EGLDisplay display = QEgl::display(); #if 1 // Hacky but fast ~0ms. -- cgit v0.12 From 865ad5053f053c9274973bb07e9f0ca04fd043d3 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 7 Nov 2011 15:42:42 +0000 Subject: symbian - handle path being passed as part of filename in QTranslator Although incorrect API usage, this was a regression from 4.7.3 behaviour Task-number: QTBUG-22489 Reviewed-by: mread --- src/corelib/kernel/qtranslator.cpp | 18 ++++++++++--- tests/auto/qtranslator/i18n/hellotr_en.qm | Bin 0 -> 230 bytes tests/auto/qtranslator/qtranslator.pro | 1 + tests/auto/qtranslator/tst_qtranslator.cpp | 40 +++++++++++++++++++++++++++-- 4 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 tests/auto/qtranslator/i18n/hellotr_en.qm diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp index 8c08760..ca30db1 100644 --- a/src/corelib/kernel/qtranslator.cpp +++ b/src/corelib/kernel/qtranslator.cpp @@ -405,13 +405,26 @@ bool QTranslator::load(const QString & filename, const QString & directory, Q_D(QTranslator); d->clear(); + QString fname = filename; QString prefix; if (QFileInfo(filename).isRelative()) { #ifdef Q_OS_SYMBIAN - if (directory.isEmpty()) + //TFindFile doesn't like path in the filename + QString dir(directory); + int slash = filename.lastIndexOf(QLatin1Char('/')); + slash = qMax(slash, filename.lastIndexOf(QLatin1Char('\\'))); + if (slash >=0) { + //so move the path component into the directory prefix + if (dir.isEmpty()) + dir = filename.left(slash + 1); + else + dir = dir + QLatin1Char('/') + filename.left(slash + 1); + fname = fname.mid(slash + 1); + } + if (dir.isEmpty()) prefix = QCoreApplication::applicationDirPath(); else - prefix = QFileInfo(directory).absoluteFilePath(); //TFindFile doesn't like dirty paths + prefix = QFileInfo(dir).absoluteFilePath(); //TFindFile doesn't like dirty paths if (prefix.length() > 2 && prefix.at(1) == QLatin1Char(':') && prefix.at(0).isLetter()) prefix[0] = QLatin1Char('Y'); #else @@ -425,7 +438,6 @@ bool QTranslator::load(const QString & filename, const QString & directory, QString nativePrefix = QDir::toNativeSeparators(prefix); #endif - QString fname = filename; QString realname; QString delims; delims = search_delimiters.isNull() ? QString::fromLatin1("_.") : search_delimiters; diff --git a/tests/auto/qtranslator/i18n/hellotr_en.qm b/tests/auto/qtranslator/i18n/hellotr_en.qm new file mode 100644 index 0000000..cc42afe Binary files /dev/null and b/tests/auto/qtranslator/i18n/hellotr_en.qm differ diff --git a/tests/auto/qtranslator/qtranslator.pro b/tests/auto/qtranslator/qtranslator.pro index 5b742f7..8ab1fd3 100644 --- a/tests/auto/qtranslator/qtranslator.pro +++ b/tests/auto/qtranslator/qtranslator.pro @@ -4,6 +4,7 @@ RESOURCES += qtranslator.qrc wince*|symbian: { addFiles.sources = hellotr_la.qm msgfmt_from_po.qm + addFiles.sources += i18n addFiles.path = . DEPLOYMENT += addFiles } diff --git a/tests/auto/qtranslator/tst_qtranslator.cpp b/tests/auto/qtranslator/tst_qtranslator.cpp index 8e2ed15..6f65e6a 100644 --- a/tests/auto/qtranslator/tst_qtranslator.cpp +++ b/tests/auto/qtranslator/tst_qtranslator.cpp @@ -66,6 +66,10 @@ protected: private slots: void load(); void load2(); + void loadSubdir(); + void loadSubdir2(); + void loadSubdir3(); + void loadSubdir4(); void threadLoad(); void testLanguageChange(); void plural(); @@ -124,6 +128,38 @@ void tst_QTranslator::load2() QCOMPARE(tor.translate("QPushButton", "Hello world!"), QString::fromLatin1("Hallo Welt!")); } +void tst_QTranslator::loadSubdir() +{ + QTranslator tor( 0 ); + tor.load("hellotr_en_GB", "i18n"); + QVERIFY(!tor.isEmpty()); + QCOMPARE(tor.translate("QPushButton", "Hello world!"), QString::fromLatin1("Hallo Welt!")); +} + +void tst_QTranslator::loadSubdir2() +{ + QTranslator tor( 0 ); + tor.load("i18n/hellotr_en_GB"); + QVERIFY(!tor.isEmpty()); + QCOMPARE(tor.translate("QPushButton", "Hello world!"), QString::fromLatin1("Hallo Welt!")); +} + +void tst_QTranslator::loadSubdir3() +{ + QTranslator tor( 0 ); + tor.load(QString(QLatin1String("i18n%1hellotr_en_GB")).arg(QDir::separator())); + QVERIFY(!tor.isEmpty()); + QCOMPARE(tor.translate("QPushButton", "Hello world!"), QString::fromLatin1("Hallo Welt!")); +} + +void tst_QTranslator::loadSubdir4() +{ + QTranslator tor( 0 ); + tor.load("./hellotr_en_GB", "i18n"); + QVERIFY(!tor.isEmpty()); + QCOMPARE(tor.translate("QPushButton", "Hello world!"), QString::fromLatin1("Hallo Welt!")); +} + class TranslatorThread : public QThread { void run() { @@ -249,10 +285,10 @@ void tst_QTranslator::loadFromResource() void tst_QTranslator::loadDirectory() { - QVERIFY(QFileInfo("../qtranslator").isDir()); + QVERIFY(QFileInfo("i18n").isDir()); QTranslator tor; - tor.load("qtranslator", ".."); + tor.load("qtranslator", "i18n"); QVERIFY(tor.isEmpty()); } -- cgit v0.12 From d278a522dc65046ad7215c333a4a1bf00c12196a Mon Sep 17 00:00:00 2001 From: Sami Rosendahl Date: Fri, 11 Nov 2011 13:17:54 +0100 Subject: Fix crash in QHttpNetworkReplyPrivate::gunzipBodyPartiallyEnd If a HTTP server responds with gzip-encoded empty content without defining Content-Length in the response header QHttpNetworkReplyPrivate::gunzipBodyPartiallyEnd will crash because it calls zlib inflateEnd for an uninitialized stream. - Fixed the crash by adding a check if the stream is initialized to gunzipBodyPartiallyEnd. - Added a regression test tst_QNetworkReply::nb279420gzipNoContentLengthEmptyContentDisconnect PMO 279420 Task-number: QTBUG-22660 Signed-off-by: Sami Rosendahl Merge-request: 1465 Reviewed-by: Peter Hartmann --- src/network/access/qhttpnetworkreply.cpp | 6 ++++-- tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index 129e2c6..b926afe 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -442,8 +442,10 @@ int QHttpNetworkReplyPrivate::gunzipBodyPartially(QByteArray &compressed, QByteA void QHttpNetworkReplyPrivate::gunzipBodyPartiallyEnd() { - inflateEnd(&inflateStrm); - initInflate = false; + if (initInflate) { + inflateEnd(&inflateStrm); + initInflate = false; + } } #endif diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index 7e5b365..28832b2 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -332,6 +332,7 @@ private Q_SLOTS: void qtbug15311doubleContentLength(); void qtbug18232gzipContentLengthZero(); + void nb279420gzipNoContentLengthEmptyContentDisconnect(); void synchronousRequest_data(); void synchronousRequest(); @@ -5307,6 +5308,28 @@ void tst_QNetworkReply::qtbug18232gzipContentLengthZero() QCOMPARE(reply->readAll(), QByteArray()); } +// Reproduced a crash in QHttpNetworkReplyPrivate::gunzipBodyPartiallyEnd +// where zlib inflateEnd was called for uninitialized zlib stream +void tst_QNetworkReply::nb279420gzipNoContentLengthEmptyContentDisconnect() +{ + // Response with no Content-Length in header and empty content + QByteArray response("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\n\r\n"); + MiniHttpServer server(response); + server.doClose = true; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(reply->isFinished()); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->size(), qint64(0)); + QVERIFY(!reply->header(QNetworkRequest::ContentLengthHeader).isValid()); + QCOMPARE(reply->readAll(), QByteArray()); +} + void tst_QNetworkReply::synchronousRequest_data() { QTest::addColumn("url"); -- cgit v0.12 From 26fcd5356a25e092758a75aa4a5e5ef33fb5d926 Mon Sep 17 00:00:00 2001 From: Casper van Donderen Date: Mon, 14 Nov 2011 13:18:07 +0100 Subject: Increase qdoc3 stack size when using MSVC to 4M. When running 'make docs' on Win7 with MSVC2010 64bit debug qdoc will crash from a stack overflow. The stack overflow occurs when sorting the list of nodes in the internal qdoc tree. This patch circumvents the stack overflow crash by increasing the stack size from the standard 1M to 4M. Reviewed-by: Friedemann Kleint --- tools/qdoc3/qdoc3.pro | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/qdoc3/qdoc3.pro b/tools/qdoc3/qdoc3.pro index bb5ff83..254ba92 100644 --- a/tools/qdoc3/qdoc3.pro +++ b/tools/qdoc3/qdoc3.pro @@ -15,6 +15,11 @@ qdoc_bootstrapped { CONFIG -= debug_and_release_target } +# Increase the stack size on MSVC to 4M to avoid a stack overflow +win32-msvc*:{ +    QMAKE_LFLAGS += /STACK:\"4194304\" +} + !isEmpty(QT_BUILD_TREE):DESTDIR = $$QT_BUILD_TREE/bin #CONFIG += debug build_all:!build_pass { -- cgit v0.12 From f41964b2c24f4aa2c6659f2038b87e7c4b33d530 Mon Sep 17 00:00:00 2001 From: Casper van Donderen Date: Mon, 14 Nov 2011 15:00:55 +0100 Subject: Update the supported platforms page. Windows XP, Win7 32-bit and Mac 106 Cocoa were missing from the supported platforms table. --- doc/src/platforms/supported-platforms.qdoc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/src/platforms/supported-platforms.qdoc b/doc/src/platforms/supported-platforms.qdoc index a3fc390..55ba94b 100644 --- a/doc/src/platforms/supported-platforms.qdoc +++ b/doc/src/platforms/supported-platforms.qdoc @@ -416,9 +416,11 @@ \o Compilers \row \o Ubuntu Linux 10.04 (32-bit) \o As provided by Ubuntu + \row \o Microsoft Windows XP SP3 (32-bit) + \o MSVC 2008 \row \o Microsoft Windows 7 (32-bit) \o MSVC 2008 - \row \o Microsoft Windows 7 (64-bit) + \row \o Microsoft Windows 7 (32-bit) \o MSVC 2010 SP1 \row \o Apple Mac OS X 10.6 "Snow Leopard" (64-bit) \o As provided by Apple @@ -440,6 +442,8 @@ \o As provided by Ubuntu \row \o Ubuntu Linux 10.04 (32-bit) \o Intel Compiler [version 12] + \row \o Apple Mac OS X 10.6 "Snow Leopard" Cocoa (32-bit) + \o As provided by Apple \endtable \section1 Tier 3 Platforms (Not Supported by Nokia) -- cgit v0.12 From 261bbb12003dab0e45b5814f85dd74aa64bcfb79 Mon Sep 17 00:00:00 2001 From: Tero Ahola Date: Mon, 14 Nov 2011 15:27:01 +0100 Subject: Fixed memory leak in Windows Vista style widgets The animations are now deleted in destruction of the Vista style. With the previous implementation the animations were not deleted for instance if you move mouse cursor off from a widget with hover animation (like QPushButton). Task-number: QTBUG-21532 Reviewed-by: Friedemann Kleint --- src/gui/styles/qwindowsvistastyle.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/styles/qwindowsvistastyle.cpp b/src/gui/styles/qwindowsvistastyle.cpp index 5525468..8051014 100644 --- a/src/gui/styles/qwindowsvistastyle.cpp +++ b/src/gui/styles/qwindowsvistastyle.cpp @@ -2508,6 +2508,7 @@ QWindowsVistaStylePrivate::QWindowsVistaStylePrivate() : QWindowsVistaStylePrivate::~QWindowsVistaStylePrivate() { + qDeleteAll(animations); delete m_treeViewHelper; } -- cgit v0.12 From 3b2bd144b7873daf2e7119248dbac7c0f0253993 Mon Sep 17 00:00:00 2001 From: Pasi Matilainen Date: Mon, 14 Nov 2011 15:39:25 +0100 Subject: Fix QDockWidget titlebar button positioning on Mac OS X Move the QDockWidget close and float buttons from the right end of the dock widget title bar to the left end to avoid Mac App Store rejection. Task-number: QTBUG-19493 Reviewed-by: Friedemann Kleint --- src/gui/styles/qmacstyle_mac.mm | 101 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/src/gui/styles/qmacstyle_mac.mm b/src/gui/styles/qmacstyle_mac.mm index 8f0e602..4d6252f 100644 --- a/src/gui/styles/qmacstyle_mac.mm +++ b/src/gui/styles/qmacstyle_mac.mm @@ -4552,6 +4552,107 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt, rect.setTop(rect.top() + SIZE(6 /* AHIG */, 3 /* guess */, 2 /* AHIG */)); } break; +#ifndef QT_NO_DOCKWIDGET + case SE_DockWidgetCloseButton: + case SE_DockWidgetFloatButton: + case SE_DockWidgetTitleBarText: + case SE_DockWidgetIcon: { + int iconSize = proxy()->pixelMetric(PM_SmallIconSize, opt, widget); + int buttonMargin = proxy()->pixelMetric(PM_DockWidgetTitleBarButtonMargin, opt, widget); + QRect srect = opt->rect; + + const QStyleOptionDockWidget *dwOpt + = qstyleoption_cast(opt); + bool canClose = dwOpt == 0 ? true : dwOpt->closable; + bool canFloat = dwOpt == 0 ? false : dwOpt->floatable; + const QStyleOptionDockWidgetV2 *v2 + = qstyleoption_cast(opt); + bool verticalTitleBar = v2 == 0 ? false : v2->verticalTitleBar; + + // If this is a vertical titlebar, we transpose and work as if it was + // horizontal, then transpose again. + if (verticalTitleBar) { + QSize size = srect.size(); + size.transpose(); + srect.setSize(size); + } + + do { + int right = srect.right(); + int left = srect.left(); + + QRect closeRect; + if (canClose) { + QSize sz = standardIcon(QStyle::SP_TitleBarCloseButton, + opt, widget).actualSize(QSize(iconSize, iconSize)); + sz += QSize(buttonMargin, buttonMargin); + if (verticalTitleBar) + sz.transpose(); + closeRect = QRect(left, + srect.center().y() - sz.height()/2, + sz.width(), sz.height()); + left = closeRect.right() + 1; + } + if (sr == SE_DockWidgetCloseButton) { + rect = closeRect; + break; + } + + QRect floatRect; + if (canFloat) { + QSize sz = standardIcon(QStyle::SP_TitleBarNormalButton, + opt, widget).actualSize(QSize(iconSize, iconSize)); + sz += QSize(buttonMargin, buttonMargin); + if (verticalTitleBar) + sz.transpose(); + floatRect = QRect(left, + srect.center().y() - sz.height()/2, + sz.width(), sz.height()); + left = floatRect.right() + 1; + } + if (sr == SE_DockWidgetFloatButton) { + rect = floatRect; + break; + } + + QRect iconRect; + if (const QDockWidget *dw = qobject_cast(widget)) { + QIcon icon; + if (dw->isFloating()) + icon = dw->windowIcon(); + if (!icon.isNull() + && icon.cacheKey() != QApplication::windowIcon().cacheKey()) { + QSize sz = icon.actualSize(QSize(rect.height(), rect.height())); + if (verticalTitleBar) + sz.transpose(); + iconRect = QRect(right - sz.width(), srect.center().y() - sz.height()/2, + sz.width(), sz.height()); + right = iconRect.left() - 1; + } + } + if (sr == SE_DockWidgetIcon) { + rect = iconRect; + break; + } + + QRect textRect = QRect(left, srect.top(), + right - left, srect.height()); + if (sr == SE_DockWidgetTitleBarText) { + rect = textRect; + break; + } + } while (false); + + if (verticalTitleBar) { + rect = QRect(srect.left() + rect.top() - srect.top(), + srect.top() + srect.right() - rect.right(), + rect.height(), rect.width()); + } else { + rect = visualRect(opt->direction, srect, rect); + } + break; + } +#endif default: rect = QWindowsStyle::subElementRect(sr, opt, widget); break; -- cgit v0.12 From fba5fce6723a739aec73ef5184ccb6cc425402fe Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 14 Nov 2011 16:26:15 +0100 Subject: Revert "Improved performance of mapFromGlobal/mapToGlobal on X11" The change introduces problems with Unity's global menu bar. Task-number: QTBUG-22420 Reviewed-by: denis This reverts commit cdd776a91e65bf5c30cea1bab9823134a3f797d0. --- src/gui/kernel/qwidget_x11.cpp | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/src/gui/kernel/qwidget_x11.cpp b/src/gui/kernel/qwidget_x11.cpp index f99cc2c..52e3046 100644 --- a/src/gui/kernel/qwidget_x11.cpp +++ b/src/gui/kernel/qwidget_x11.cpp @@ -1336,40 +1336,12 @@ QPoint QWidgetPrivate::mapFromGlobal(const QPoint &pos) const QPoint QWidget::mapToGlobal(const QPoint &pos) const { Q_D(const QWidget); - QPoint offset = data->crect.topLeft(); - const QWidget *w = this; - const QWidget *p = w->parentWidget(); - while (!w->isWindow() && p) { - w = p; - p = p->parentWidget(); - offset += w->data->crect.topLeft(); - } - - const QWidgetPrivate *wd = w->d_func(); - QTLWExtra *tlw = wd->topData(); - if (!tlw->embedded) - return pos + offset; - return d->mapToGlobal(pos); } QPoint QWidget::mapFromGlobal(const QPoint &pos) const { Q_D(const QWidget); - QPoint offset = data->crect.topLeft(); - const QWidget *w = this; - const QWidget *p = w->parentWidget(); - while (!w->isWindow() && p) { - w = p; - p = p->parentWidget(); - offset += w->data->crect.topLeft(); - } - - const QWidgetPrivate *wd = w->d_func(); - QTLWExtra *tlw = wd->topData(); - if (!tlw->embedded) - return pos - offset; - return d->mapFromGlobal(pos); } -- cgit v0.12 From ec6d7694f72498d1b156bb0ae8d305e01931f7b2 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Mon, 14 Nov 2011 16:21:38 +0100 Subject: HTTP: blacklist server for pipelining that server was found out not to support HTTP pipelining. tested manually; for more information see the task. Reviewed-by: Markus Goetz Task-number: QTBUG-21369 --- src/network/access/qhttpnetworkconnectionchannel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 15fda34..b9db7fe 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -788,6 +788,7 @@ void QHttpNetworkConnectionChannel::detectPipeliningSupport() && (!serverHeaderField.contains("Netscape-Enterprise/3.")) // this is adpoted from the knowledge of the Nokia 7.x browser team (DEF143319) && (!serverHeaderField.contains("WebLogic")) + && (!serverHeaderField.startsWith("Rocket")) // a Python Web Server, see Web2py.com ) { pipeliningSupported = QHttpNetworkConnectionChannel::PipeliningProbablySupported; } else { -- cgit v0.12 From a32bfdef6d6b45c916f143dcf8495a2e102c3eec Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Mon, 14 Nov 2011 17:11:00 +0100 Subject: network auto tests: add QNetworkReply test for pipelining Reviewed-by: Markus Goetz Task-number: QTBUG-21369 --- tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 39 ++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index 14ad6a9..371ac57 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -168,6 +168,7 @@ public Q_SLOTS: void gotError(); void authenticationRequired(QNetworkReply*,QAuthenticator*); void proxyAuthenticationRequired(const QNetworkProxy &,QAuthenticator*); + void pipeliningHelperSlot(); #ifndef QT_NO_OPENSSL void sslErrors(QNetworkReply*,const QList &); @@ -380,6 +381,7 @@ private Q_SLOTS: void dontInsertPartialContentIntoTheCache(); void synchronousAuthenticationCache(); + void pipelining(); // NOTE: This test must be last! void parentingRepliesToTheApp(); @@ -6446,6 +6448,43 @@ void tst_QNetworkReply::synchronousAuthenticationCache() } } +void tst_QNetworkReply::pipelining() +{ + QString urlString("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/echo.cgi?"); + QList replies; + for (int a = 0; a < 20; a++) { + QNetworkRequest request(urlString + QString::number(a)); + request.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, QVariant(true)); + replies.append(manager.get(request)); + connect(replies.at(a), SIGNAL(finished()), this, SLOT(pipeliningHelperSlot())); + } + QTestEventLoop::instance().enterLoop(20); + QVERIFY(!QTestEventLoop::instance().timeout()); +} + +void tst_QNetworkReply::pipeliningHelperSlot() { + static int a = 0; + + // check that pipelining was used in at least one of the replies + static bool pipeliningWasUsed = false; + QNetworkReply *reply = qobject_cast(sender()); + bool pipeliningWasUsedInReply = reply->attribute(QNetworkRequest::HttpPipeliningWasUsedAttribute).toBool(); + if (pipeliningWasUsedInReply) + pipeliningWasUsed = true; + + // check that the contents match (the response to echo.cgi?3 should return 3 etc.) + QString urlQueryString = reply->url().queryItems().at(0).first; + QString content = reply->readAll(); + QVERIFY2(urlQueryString == content, "data corruption with pipelining detected"); + + a++; + + if (a == 20) { // all replies have finished + QTestEventLoop::instance().exitLoop(); + QVERIFY2(pipeliningWasUsed, "pipelining was not used in any of the replies when trying to test pipelining"); + } +} + // NOTE: This test must be last testcase in tst_qnetworkreply! void tst_QNetworkReply::parentingRepliesToTheApp() { -- cgit v0.12 From ee60e9c88c43cc33dc94a4cec79c62ffdf02ce58 Mon Sep 17 00:00:00 2001 From: Damian Jansen Date: Tue, 15 Nov 2011 14:01:13 +1000 Subject: Fix focusScopeItemChange setting crash Delay focusScopeItemChange to after reparenting, to prevent an invalid focusScopeItem pointer crash. Task-number: QTBUG-21640 Reviewed-by: Martin Jones --- src/gui/graphicsview/qgraphicsitem.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 466cc47..9e1fd09 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -1157,7 +1157,6 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, const Q if (q_ptr == fsi || q_ptr->isAncestorOf(fsi)) { parentFocusScopeItem = fsi; p->d_ptr->focusScopeItem = 0; - fsi->d_ptr->focusScopeItemChange(false); } break; } @@ -1259,6 +1258,10 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, const Q if (!inDestructor && (transformData || (newParent && newParent->d_ptr->transformData))) transformChanged(); + // Reparenting is finished, now safe to notify the previous focusScopeItem about changes + if (parentFocusScopeItem) + parentFocusScopeItem->d_ptr->focusScopeItemChange(false); + // Restore the sub focus chain. if (subFocusItem) { subFocusItem->d_ptr->setSubFocus(newParent); -- cgit v0.12 From 32e931b40edf4dc53424f3435d22f5c6419182f5 Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Mon, 14 Nov 2011 11:57:21 +1000 Subject: Properly protect access to pixmap reader thread with mutex Previously, access to the data from the reader thread wasn't guarded properly, causing a crash when the reader thread was deleted prior to QDeclarativePixmapData (which then attempted to dereference the thread pointer to cancel the request), or in the case where a QDeclarativePixmapData was deleted after its QDeclarativePixmapReply was removed from the jobs queue but prior to processing. Reviewed-by: Martin Jones Task-number: QTBUG-22125 --- src/declarative/util/qdeclarativepixmapcache.cpp | 57 ++++++++++++++++------ .../qdeclarativeimage/data/qtbug_22125.qml | 44 +++++++++++++++++ .../qdeclarativeimage/tst_qdeclarativeimage.cpp | 41 ++++++++++++++++ 3 files changed, 126 insertions(+), 16 deletions(-) create mode 100644 tests/auto/declarative/qdeclarativeimage/data/qtbug_22125.qml diff --git a/src/declarative/util/qdeclarativepixmapcache.cpp b/src/declarative/util/qdeclarativepixmapcache.cpp index 3557425..b23ac73 100644 --- a/src/declarative/util/qdeclarativepixmapcache.cpp +++ b/src/declarative/util/qdeclarativepixmapcache.cpp @@ -90,8 +90,9 @@ public: ~QDeclarativePixmapReply(); QDeclarativePixmapData *data; - QDeclarativePixmapReader *reader; + QDeclarativeEngine *engineForReader; // always access reader inside readerMutex. QSize requestSize; + QUrl url; bool loading; int redirectCount; @@ -147,6 +148,7 @@ public: void cancel(QDeclarativePixmapReply *rep); static QDeclarativePixmapReader *instance(QDeclarativeEngine *engine); + static QDeclarativePixmapReader *existingInstance(QDeclarativeEngine *engine); protected: void run(); @@ -176,6 +178,7 @@ private: static int downloadProgress; static int threadNetworkRequestDone; static QHash readers; +public: static QMutex readerMutex; }; @@ -326,6 +329,22 @@ QDeclarativePixmapReader::~QDeclarativePixmapReader() readers.remove(engine); readerMutex.unlock(); + mutex.lock(); + // manually cancel all outstanding jobs. + foreach (QDeclarativePixmapReply *reply, jobs) { + delete reply; + } + jobs.clear(); + QList activeJobs = replies.values(); + foreach (QDeclarativePixmapReply *reply, activeJobs) { + if (reply->loading) { + cancelled.append(reply); + reply->data = 0; + } + } + if (threadObject) threadObject->processJobs(); + mutex.unlock(); + eventLoopQuitHack->deleteLater(); wait(); } @@ -433,9 +452,8 @@ void QDeclarativePixmapReader::processJobs() if (!jobs.isEmpty() && replies.count() < IMAGEREQUEST_MAX_REQUEST_COUNT) { QDeclarativePixmapReply *runningJob = jobs.takeLast(); runningJob->loading = true; - - QUrl url = runningJob->data->url; - QSize requestSize = runningJob->data->requestSize; + QUrl url = runningJob->url; + QSize requestSize = runningJob->requestSize; locker.unlock(); processJob(runningJob, url, requestSize); locker.relock(); @@ -459,7 +477,6 @@ void QDeclarativePixmapReader::processJob(QDeclarativePixmapReply *runningJob, c errorCode = QDeclarativePixmapReply::Loading; errorStr = QDeclarativePixmap::tr("Failed to get image from provider: %1").arg(url.toString()); } - mutex.lock(); if (!cancelled.contains(runningJob)) runningJob->postReply(errorCode, errorStr, readSize, image); mutex.unlock(); @@ -487,10 +504,8 @@ void QDeclarativePixmapReader::processJob(QDeclarativePixmapReply *runningJob, c QNetworkRequest req(url); req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true); QNetworkReply *reply = networkAccessManager()->get(req); - QMetaObject::connect(reply, replyDownloadProgress, runningJob, downloadProgress); QMetaObject::connect(reply, replyFinished, threadObject, threadNetworkRequestDone); - replies.insert(reply, runningJob); } } @@ -498,22 +513,27 @@ void QDeclarativePixmapReader::processJob(QDeclarativePixmapReply *runningJob, c QDeclarativePixmapReader *QDeclarativePixmapReader::instance(QDeclarativeEngine *engine) { - readerMutex.lock(); + // XXX NOTE: must be called within readerMutex locking. QDeclarativePixmapReader *reader = readers.value(engine); if (!reader) { reader = new QDeclarativePixmapReader(engine); readers.insert(engine, reader); } - readerMutex.unlock(); return reader; } +QDeclarativePixmapReader *QDeclarativePixmapReader::existingInstance(QDeclarativeEngine *engine) +{ + // XXX NOTE: must be called within readerMutex locking. + return readers.value(engine, 0); +} + QDeclarativePixmapReply *QDeclarativePixmapReader::getImage(QDeclarativePixmapData *data) { mutex.lock(); QDeclarativePixmapReply *reply = new QDeclarativePixmapReply(data); - reply->reader = this; + reply->engineForReader = engine; jobs.append(reply); // XXX if (threadObject) threadObject->processJobs(); @@ -692,7 +712,7 @@ void QDeclarativePixmapStore::flushCache() } QDeclarativePixmapReply::QDeclarativePixmapReply(QDeclarativePixmapData *d) -: data(d), reader(0), requestSize(d->requestSize), loading(false), redirectCount(0) +: data(d), engineForReader(0), requestSize(d->requestSize), url(d->url), loading(false), redirectCount(0) { if (finishedIndex == -1) { finishedIndex = QDeclarativePixmapReply::staticMetaObject.indexOfSignal("finished()"); @@ -750,8 +770,14 @@ void QDeclarativePixmapData::release() if (refCount == 0) { if (reply) { - reply->reader->cancel(reply); + QDeclarativePixmapReply *cancelReply = reply; + reply->data = 0; reply = 0; + QDeclarativePixmapReader::readerMutex.lock(); + QDeclarativePixmapReader *reader = QDeclarativePixmapReader::existingInstance(cancelReply->engineForReader); + if (reader) + reader->cancel(cancelReply); + QDeclarativePixmapReader::readerMutex.unlock(); } if (pixmapStatus == QDeclarativePixmap::Ready) { @@ -1013,13 +1039,12 @@ void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, const if (!engine) return; - QDeclarativePixmapReader *reader = QDeclarativePixmapReader::instance(engine); - d = new QDeclarativePixmapData(url, requestSize); if (options & QDeclarativePixmap::Cache) d->addToCache(); - - d->reply = reader->getImage(d); + QDeclarativePixmapReader::readerMutex.lock(); + d->reply = QDeclarativePixmapReader::instance(engine)->getImage(d); + QDeclarativePixmapReader::readerMutex.unlock(); } else { d = *iter; d->addref(); diff --git a/tests/auto/declarative/qdeclarativeimage/data/qtbug_22125.qml b/tests/auto/declarative/qdeclarativeimage/data/qtbug_22125.qml new file mode 100644 index 0000000..8588028 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeimage/data/qtbug_22125.qml @@ -0,0 +1,44 @@ +import QtQuick 1.1 + +Item { + id: root + width: 800 + height: 800 + + GridView { + anchors.fill: parent + delegate: Image { + source: imagePath; + asynchronous: true + smooth: true + width: 200 + height: 200 + } + model: ListModel { + ListElement { + imagePath: "http://127.0.0.1:14451/big256.png" + } + ListElement { + imagePath: "http://127.0.0.1:14451/big256.png" + } + ListElement { + imagePath: "http://127.0.0.1:14451/big256.png" + } + ListElement { + imagePath: "http://127.0.0.1:14451/colors.png" + } + ListElement { + imagePath: "http://127.0.0.1:14451/colors1.png" + } + ListElement { + imagePath: "http://127.0.0.1:14451/big.jpeg" + } + ListElement { + imagePath: "http://127.0.0.1:14451/heart.png" + } + ListElement { + imagePath: "http://127.0.0.1:14451/green.png" + } + } + } +} diff --git a/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp b/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp index a35d69a..f67c5b5 100644 --- a/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp +++ b/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp @@ -94,6 +94,7 @@ private slots: void resetSourceSize(); void testQtQuick11Attributes(); void testQtQuick11Attributes_data(); + void readerCrash_QTBUG_22125(); private: template @@ -762,6 +763,46 @@ void tst_qdeclarativeimage::testQtQuick11Attributes_data() << ":1 \"Image.cache\" is not available in QtQuick 1.0.\n"; } +void tst_qdeclarativeimage::readerCrash_QTBUG_22125() +{ + { + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + server.serveDirectory(SRCDIR "/data/", TestHTTPServer::Delay); + + { + QDeclarativeView view(QUrl::fromLocalFile(SRCDIR "/data/qtbug_22125.qml")); + view.show(); + qApp->processEvents(); + qApp->processEvents(); + // shouldn't crash when the view drops out of scope due to + // QDeclarativePixmapData attempting to dereference a pointer to + // the destroyed reader. + } + + // shouldn't crash when deleting cancelled QDeclarativePixmapReplys. + QTest::qWait(1000); + qApp->processEvents(QEventLoop::DeferredDeletion); + } + + { + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + server.serveDirectory(SRCDIR "/data/"); + + { + QDeclarativeView view(QUrl::fromLocalFile(SRCDIR "/data/qtbug_22125.qml")); + view.show(); + qApp->processEvents(); + QTest::qWait(1000); + qApp->processEvents(); + // shouldn't crash when the view drops out of scope due to + // the reader thread accessing self-deleted QDeclarativePixmapReplys. + } + qApp->processEvents(); + } +} + /* Find an item with the specified objectName. If index is supplied then the item must also evaluate the {index} expression equal to index -- cgit v0.12 From 9be94925138d11f9a2f191f9676665eb8f3e6d3a Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Thu, 19 May 2011 11:42:31 +1000 Subject: tests: allow unstable tests to be marked with CONFIG+=insignificant_test Marking a test with CONFIG+=insignificant_test will cause the exit code of the test to be discarded during `make check'. This is intended to be used for tests which are valuable to run, but are known to be unstable and are not feasible to immediately fix. Reviewed-by: Jason McDonald Change-Id: I50a712c33c2ebb0af39f1ea0bf2adef7f0936425 (cherry picked from commit b0a5a988900b777cb08012408eb108512a3e873b) --- mkspecs/features/testcase.prf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mkspecs/features/testcase.prf b/mkspecs/features/testcase.prf index 7a7c9e3..eb0aa9f 100644 --- a/mkspecs/features/testcase.prf +++ b/mkspecs/features/testcase.prf @@ -38,6 +38,10 @@ embedded: check.commands += -qws # Allow for custom arguments to tests check.commands += $(TESTARGS) + +# If the test is marked as insignificant, discard the exit code +insignificant_test:check.commands = -$${check.commands} + QMAKE_EXTRA_TARGETS *= check !debug_and_release|build_pass { -- cgit v0.12