From 240c2ef60e854575dced056d916f8a8922905e8f Mon Sep 17 00:00:00 2001 From: Andrea Bernabei Date: Tue, 31 May 2016 14:21:44 +0100 Subject: Flickable: fix minXExtent/minYExtent when content is smaller than view At the moment, defining leftMargin (or topMargin) and contentWidth (or contentHeight) so that "leftMargin+contentWidth < flickable.width" (or topMargin+contentHeight < flickable.height) leads to widthRatio (or heightRatio) having value != 1. The value should, however, be 1, as the content is completely visible inside the view, margins included. As a sideeffect, under the assumptions described above, it will now not be possible to scroll the leftMargin (or topMargin) out of screen, something which was possible (and it shouldn't have) before this fix. Task-number: QTBUG-53726 Change-Id: I22426c8038e90a2cfc7445914206eae0e781a3fb Reviewed-by: Robin Burchell Reviewed-by: Albert Astals Cid Reviewed-by: Shawn Rutledge --- src/quick/items/qquickflickable.cpp | 4 ++-- .../qquickflickable/data/ratios_smallContent.qml | 19 +++++++++++++++ .../quick/qquickflickable/tst_qquickflickable.cpp | 28 ++++++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 tests/auto/quick/qquickflickable/data/ratios_smallContent.qml diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 32d445dbc5..b0980cd2c1 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -1580,13 +1580,13 @@ qreal QQuickFlickable::minXExtent() const qreal QQuickFlickable::maxXExtent() const { Q_D(const QQuickFlickable); - return qMin(0, width() - vWidth() - d->hData.endMargin); + return qMin(minXExtent(), width() - vWidth() - d->hData.endMargin); } /* returns -ve */ qreal QQuickFlickable::maxYExtent() const { Q_D(const QQuickFlickable); - return qMin(0, height() - vHeight() - d->vData.endMargin); + return qMin(minYExtent(), height() - vHeight() - d->vData.endMargin); } void QQuickFlickable::componentComplete() diff --git a/tests/auto/quick/qquickflickable/data/ratios_smallContent.qml b/tests/auto/quick/qquickflickable/data/ratios_smallContent.qml new file mode 100644 index 0000000000..07bad683ee --- /dev/null +++ b/tests/auto/quick/qquickflickable/data/ratios_smallContent.qml @@ -0,0 +1,19 @@ +import QtQuick 2.0 + +Flickable { + property double heightRatioIs: visibleArea.heightRatio + property double widthRatioIs: visibleArea.widthRatio + + width: 200 + height: 200 + contentWidth: item.width + contentHeight: item.height + topMargin: 20 + leftMargin: 40 + + Item { + id: item + width: 100 + height: 100 + } +} diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index dc7171746c..2e134ff5ad 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -95,6 +95,7 @@ private slots: void movementFromProgrammaticFlick(); void cleanup(); void contentSize(); + void ratios_smallContent(); private: void flickWithTouch(QQuickWindow *window, QTouchDevice *touchDevice, const QPoint &from, const QPoint &to); @@ -1817,6 +1818,33 @@ void tst_qquickflickable::contentSize() QCOMPARE(chspy.count(), 1); } +// QTBUG-53726 +void tst_qquickflickable::ratios_smallContent() +{ + QScopedPointer window(new QQuickView); + window->setSource(testFileUrl("ratios_smallContent.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + window->setTitle(QTest::currentTestFunction()); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QQuickItem *root = window->rootObject(); + QVERIFY(root); + QQuickFlickable *obj = qobject_cast(root); + QVERIFY(obj != 0); + + //doublecheck the item, as specified by contentWidth/Height, fits in the view + //use tryCompare to allow a bit of stabilization in component's properties + QTRY_COMPARE(obj->leftMargin() + obj->contentWidth() + obj->rightMargin() <= obj->width(), true); + QTRY_COMPARE(obj->topMargin() + obj->contentHeight() + obj->bottomMargin() <= obj->height(), true); + + //the whole item fits in the flickable, heightRatio should be 1 + QCOMPARE(obj->property("heightRatioIs").toDouble(), 1.); + QCOMPARE(obj->property("widthRatioIs").toDouble(), 1.); +} + + QTEST_MAIN(tst_qquickflickable) #include "tst_qquickflickable.moc" -- cgit v1.2.3 From 506ae2dba8270341cbe3ee6435baf472b0d1abed Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 30 Jun 2016 16:54:13 +0200 Subject: Fix crash in QQuickShaderEffect::updatePaintNode When having a ShaderEffect and an Image sharing the texture via supportsAtlasTextures This used to work fine in 5.4 but 38cab579a0c5398b7621221fd8609bc43cf1f3c5 removed the check for the provider not being null Change-Id: I18cb969dbf8011ea01543cc079214e8ecbb66623 Reviewed-by: Frederik Gladhorn --- src/quick/items/qquickshadereffect.cpp | 2 +- .../auto/quick/qquickshadereffect/data/MyIcon.qml | 76 ++++++++++++++++++++++ .../data/twoImagesOneShaderEffect.qml | 61 +++++++++++++++++ .../qquickshadereffect/tst_qquickshadereffect.cpp | 14 ++++ 4 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 tests/auto/quick/qquickshadereffect/data/MyIcon.qml create mode 100644 tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp index 94fa7e92e3..690433af4b 100644 --- a/src/quick/items/qquickshadereffect.cpp +++ b/src/quick/items/qquickshadereffect.cpp @@ -1054,7 +1054,7 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa bool geometryUsesTextureSubRect = false; if (m_supportsAtlasTextures && material->textureProviders.size() == 1) { QSGTextureProvider *provider = material->textureProviders.at(0); - if (provider->texture()) { + if (provider && provider->texture()) { srcRect = provider->texture()->normalizedTextureSubRect(); geometryUsesTextureSubRect = true; } diff --git a/tests/auto/quick/qquickshadereffect/data/MyIcon.qml b/tests/auto/quick/qquickshadereffect/data/MyIcon.qml new file mode 100644 index 0000000000..b83da321f2 --- /dev/null +++ b/tests/auto/quick/qquickshadereffect/data/MyIcon.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 + +Item { + id: root + + property alias source: image.source + property bool shaderActive: false + + implicitWidth: image.width + + Image { + id: image + objectName: "image" + anchors { top: parent.top; bottom: parent.bottom } + sourceSize.height: height + + visible: !shaderActive + } + + ShaderEffect { + id: colorizedImage + + anchors.fill: parent + visible: shaderActive && image.status == Image.Ready + supportsAtlasTextures: true + + property Image source: visible ? image : null + + fragmentShader: " + varying highp vec2 qt_TexCoord0; + uniform sampler2D source; + void main() { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + }" + } +} diff --git a/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml b/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml new file mode 100644 index 0000000000..d1292f74b8 --- /dev/null +++ b/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 + +Item { + width: 400 + height: 700 + + MyIcon { + id: icon + + height: 24 + source: "star.png" + shaderActive: true + } + + MyIcon { + anchors.top: icon.bottom + + height: 24 + source: "star.png" + } +} diff --git a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp index c95fef9ef5..2f1d7679c8 100644 --- a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp +++ b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp @@ -81,6 +81,7 @@ private slots: void deleteSourceItem(); void deleteShaderEffectSource(); + void twoImagesOneShaderEffect(); private: enum PresenceFlags { @@ -307,6 +308,19 @@ void tst_qquickshadereffect::deleteShaderEffectSource() delete view; } +void tst_qquickshadereffect::twoImagesOneShaderEffect() +{ + // purely to ensure that deleting the sourceItem of a shader doesn't cause a crash + QQuickView *view = new QQuickView(0); + view->setSource(QUrl::fromLocalFile(testFile("twoImagesOneShaderEffect.qml"))); + view->show(); + QVERIFY(QTest::qWaitForWindowExposed(view)); + QVERIFY(view); + QObject *obj = view->rootObject(); + QVERIFY(obj); + delete view; +} + QTEST_MAIN(tst_qquickshadereffect) #include "tst_qquickshadereffect.moc" -- cgit v1.2.3 From dffe4ab249ced63255e83942be447df4183bf2f2 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Tue, 5 Jul 2016 17:16:44 +0200 Subject: demos: Fix installation of photoviewer example and add to build deployment.pri seems suspicious (and qmake errors about it actually), so just use the example install path and trust that it will be okay. Change-Id: Id3b6abd80f84485e006473130873ab89ee11c0d4 Reviewed-by: Oswald Buddenhagen --- examples/quick/demos/demos.pro | 3 +-- examples/quick/demos/photoviewer/deployment.pri | 23 ----------------------- examples/quick/demos/photoviewer/photoviewer.pro | 7 ++----- 3 files changed, 3 insertions(+), 30 deletions(-) delete mode 100644 examples/quick/demos/photoviewer/deployment.pri diff --git a/examples/quick/demos/demos.pro b/examples/quick/demos/demos.pro index 9aac7bf6f7..e6937683ab 100644 --- a/examples/quick/demos/demos.pro +++ b/examples/quick/demos/demos.pro @@ -5,9 +5,8 @@ SUBDIRS = samegame \ tweetsearch \ maroon \ photosurface \ + photoviewer \ stocqt qtHaveModule(xmlpatterns): SUBDIRS += rssnews -EXAMPLE_FILES = \ - photoviewer diff --git a/examples/quick/demos/photoviewer/deployment.pri b/examples/quick/demos/photoviewer/deployment.pri deleted file mode 100644 index 839b3b5cac..0000000000 --- a/examples/quick/demos/photoviewer/deployment.pri +++ /dev/null @@ -1,23 +0,0 @@ -android-no-sdk { - target.path = /data/user/qt - export(target.path) - INSTALLS += target -} else:android { - x86 { - target.path = /libs/x86 - } else: armeabi-v7a { - target.path = /libs/armeabi-v7a - } else { - target.path = /libs/armeabi - } - export(target.path) - INSTALLS += target -} else:unix { - isEmpty(target.path) { - target.path = /opt/$${TARGET}/bin - export(target.path) - } - INSTALLS += target -} - -export(INSTALLS) diff --git a/examples/quick/demos/photoviewer/photoviewer.pro b/examples/quick/demos/photoviewer/photoviewer.pro index 704e2ce003..4bfdb86f31 100644 --- a/examples/quick/demos/photoviewer/photoviewer.pro +++ b/examples/quick/demos/photoviewer/photoviewer.pro @@ -15,8 +15,5 @@ TRANSLATIONS += i18n/qml_fr.ts \ RESOURCES += qml.qrc -# Additional import path used to resolve QML modules in Qt Creator's code model -QML_IMPORT_PATH = - -# Default rules for deployment. -include(deployment.pri) +target.path = $$[QT_INSTALL_EXAMPLES]/quick/demos/photoviewer +INSTALLS += target -- cgit v1.2.3 From a858ce0039cb63a6a0afdfabab80ad4adc98ce17 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 1 Jul 2016 14:48:06 +0200 Subject: localstorage: disable warning about tautological comparison When building with gcc 6.1.1, there is a warning like this: plugin.cpp:152:126: error: self-comparison always evaluates to true [-Werror=tautological-compare] DEFINE_OBJECT_VTABLE(QV4::QQmlSqlDatabaseWrapper); In the definition of DEFINE_OBJECT_VTABLE, the comparison &classname::SuperClass::static_vtbl == &Object::static_vtbl ? 0 : &classname::SuperClass::static_vtbl.vTable will be done at runtime. Maybe the macro could somehow do that at compile time (or maybe the compiler will optimize it away after detecting that the result is constant); but for now, this warning breaks the build. Task-number: QTBUG-53373 Change-Id: I5f8e429a3f1446d3ef931ff8b0c41fcf652f7a02 Reviewed-by: Thiago Macieira --- src/imports/localstorage/plugin.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index a043af6b46..fbcb6ddea5 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -149,7 +149,12 @@ public: using namespace QV4; +QT_WARNING_PUSH +#if (Q_CC_GNU >= 600) +QT_WARNING_DISABLE_GCC("-Wtautological-compare") +#endif DEFINE_OBJECT_VTABLE(QV4::QQmlSqlDatabaseWrapper); +QT_WARNING_POP -- cgit v1.2.3 From f640a9b7bbefd069f9ee3bf9435e48ccc1f19d1a Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Tue, 5 Jul 2016 09:31:18 +0200 Subject: tst_qquicklistview: Style fixes Change-Id: I18983b06d28bf8f31043070db5aa6c1540062197 Reviewed-by: Shawn Rutledge --- tests/auto/quick/qquicklistview/tst_qquicklistview.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index 48230891ba..08c0887fcf 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -657,11 +657,9 @@ void tst_QQuickListView::inserted_more(QQuickItemView::VerticalLayoutDirection v #endif QList visibleItems = QQuickItemViewPrivate::get(listview)->visibleItems; - for (QList::const_iterator itemIt = visibleItems.begin(); itemIt != visibleItems.end(); ++itemIt) - { + for (QList::const_iterator itemIt = visibleItems.begin(); itemIt != visibleItems.end(); ++itemIt) { FxViewItem *item = *itemIt; - if (item->item->position().y() >= 0 && item->item->position().y() < listview->height()) - { + if (item->item->position().y() >= 0 && item->item->position().y() < listview->height()) { QVERIFY(!QQuickItemPrivate::get(item->item)->culled); } } -- cgit v1.2.3 From d7ebaa1611758a9677809d77e0b11f501c103f8d Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Wed, 6 Jul 2016 12:19:18 +0200 Subject: Doc: Added definition of enum value ItemAntialiasingHasChanged Error message: Undocumented enum item 'ItemAntialiasingHasChanged' in QQuickItem::ItemChange Change-Id: I0ea7bf4ba9cdf7fb69a9794694113c6501066d75 Reviewed-by: Martin Smith --- src/quick/items/qquickitem.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 5676bdb13a..aaa7ce04b9 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2102,6 +2102,9 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus) \value ItemDevicePixelRatioHasChanged The device pixel ratio of the screen the item is on has changed. ItemChangedData::realValue contains the new device pixel ratio. + + \value ItemAntialiasingHasChanged The antialiasing has changed. The current + (boolean) value can be found in QQuickItem::antialiasing. */ /*! -- cgit v1.2.3 From 1e18a4f985f6ec4a0191a2e0cc087b13d29b1719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Tue, 28 Jun 2016 11:34:59 +0100 Subject: macOS: Use sRGB when doing native font rendering into FBO Otherwise text appears too dark. A similar bug was fixed in the past for QQuickWidget (which also uses FBO). Now this fixes it for ShaderEffectSource and QQuickItem::grabImage() too. Change-Id: Ia0e176372b9ba8282972f8d60f87f02747291ffe Task-Id: QTBUG-52906 Reviewed-by: Sean Harmer --- src/quick/scenegraph/qsgdefaultlayer.cpp | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/quick/scenegraph/qsgdefaultlayer.cpp b/src/quick/scenegraph/qsgdefaultlayer.cpp index fa69f911dd..99735564ef 100644 --- a/src/quick/scenegraph/qsgdefaultlayer.cpp +++ b/src/quick/scenegraph/qsgdefaultlayer.cpp @@ -42,6 +42,29 @@ DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY) #endif DEFINE_BOOL_CONFIG_OPTION(qmlFboFlushBeforeDetach, QML_FBO_FLUSH_BEFORE_DETACH) + + +static QOpenGLFramebufferObject *createFramebuffer(const QSize &size, + QOpenGLFramebufferObjectFormat format) +{ +#ifdef Q_OS_MACOS + QOpenGLContext *context = QOpenGLContext::currentContext(); + if (context->hasExtension("GL_ARB_framebuffer_sRGB") + && context->hasExtension("GL_EXT_texture_sRGB") + && context->hasExtension("GL_EXT_texture_sRGB_decode")) + format.setInternalTextureFormat(GL_SRGB8_ALPHA8_EXT); +#endif + QOpenGLFramebufferObject *fbo = new QOpenGLFramebufferObject(size, format); +#ifdef Q_OS_MACOS + if (format.internalTextureFormat() == GL_SRGB8_ALPHA8_EXT) { + QOpenGLFunctions *funcs = context->functions(); + funcs->glBindTexture(GL_TEXTURE_2D, fbo->texture()); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); + } +#endif + return fbo; +} + namespace { class BindableFbo : public QSGBindable @@ -324,7 +347,7 @@ void QSGDefaultLayer::grab() format.setInternalTextureFormat(m_format); format.setSamples(m_context->openglContext()->format().samples()); - m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); + m_secondaryFbo = createFramebuffer(m_size, format); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { QOpenGLFramebufferObjectFormat format; @@ -333,14 +356,14 @@ void QSGDefaultLayer::grab() if (m_recursive) { deleteFboLater = true; delete m_secondaryFbo; - m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); + m_secondaryFbo = createFramebuffer(m_size, format); funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { delete m_fbo; delete m_secondaryFbo; - m_fbo = new QOpenGLFramebufferObject(m_size, format); + m_fbo = createFramebuffer(m_size, format); m_secondaryFbo = 0; funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); updateBindOptions(true); @@ -354,7 +377,7 @@ void QSGDefaultLayer::grab() Q_ASSERT(m_fbo); Q_ASSERT(!m_multisampling); - m_secondaryFbo = new QOpenGLFramebufferObject(m_size, m_fbo->format()); + m_secondaryFbo = createFramebuffer(m_size, m_fbo->format()); funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); } -- cgit v1.2.3 From e4f7ab42c6c4f19eed76d9d0de5accda5835a3a8 Mon Sep 17 00:00:00 2001 From: Daniel d'Andrada Date: Wed, 6 Jul 2016 17:01:35 -0300 Subject: QQuickWindow: Fill out timestamps in QHoverEvents sent to QQuickItems Task-number: QTBUG-54600 Change-Id: Ie24c44e2f68aae55ff1146c13c3dfc25349b7a29 Reviewed-by: Frederik Gladhorn Reviewed-by: Robin Burchell Reviewed-by: Shawn Rutledge --- src/quick/items/qquickwindow.cpp | 28 +++---- src/quick/items/qquickwindow_p.h | 6 +- tests/auto/quick/qquickwindow/tst_qquickwindow.cpp | 85 ++++++++++++++++++++++ 3 files changed, 103 insertions(+), 16 deletions(-) diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 14e7915dba..de1b5f236e 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -661,10 +661,10 @@ bool QQuickWindowPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *e lastMousePosition = me->windowPos(); bool accepted = me->isAccepted(); - bool delivered = deliverHoverEvent(contentItem, me->windowPos(), last, me->modifiers(), accepted); + bool delivered = deliverHoverEvent(contentItem, me->windowPos(), last, me->modifiers(), me->timestamp(), accepted); if (!delivered) { //take care of any exits - accepted = clearHover(); + accepted = clearHover(me->timestamp()); } me->setAccepted(accepted); break; @@ -1397,7 +1397,7 @@ QQuickItem *QQuickWindow::mouseGrabberItem() const } -bool QQuickWindowPrivate::clearHover() +bool QQuickWindowPrivate::clearHover(ulong timestamp) { Q_Q(QQuickWindow); if (hoverItems.isEmpty()) @@ -1407,7 +1407,7 @@ bool QQuickWindowPrivate::clearHover() bool accepted = false; foreach (QQuickItem* item, hoverItems) - accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), true) || accepted; + accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), timestamp, true) || accepted; hoverItems.clear(); return accepted; } @@ -1657,13 +1657,15 @@ void QQuickWindow::mouseDoubleClickEvent(QMouseEvent *event) bool QQuickWindowPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos, - Qt::KeyboardModifiers modifiers, bool accepted) + Qt::KeyboardModifiers modifiers, ulong timestamp, + bool accepted) { Q_Q(QQuickWindow); const QTransform transform = QQuickItemPrivate::get(item)->windowToItemTransform(); //create copy of event QHoverEvent hoverEvent(type, transform.map(scenePos), transform.map(lastScenePos), modifiers); + hoverEvent.setTimestamp(timestamp); hoverEvent.setAccepted(accepted); QSet hasFiltered; @@ -1699,10 +1701,10 @@ void QQuickWindow::mouseMoveEvent(QMouseEvent *event) d->lastMousePosition = event->windowPos(); bool accepted = event->isAccepted(); - bool delivered = d->deliverHoverEvent(d->contentItem, event->windowPos(), last, event->modifiers(), accepted); + bool delivered = d->deliverHoverEvent(d->contentItem, event->windowPos(), last, event->modifiers(), event->timestamp(), accepted); if (!delivered) { //take care of any exits - accepted = d->clearHover(); + accepted = d->clearHover(event->timestamp()); } event->setAccepted(accepted); return; @@ -1712,7 +1714,7 @@ void QQuickWindow::mouseMoveEvent(QMouseEvent *event) } bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos, - Qt::KeyboardModifiers modifiers, bool &accepted) + Qt::KeyboardModifiers modifiers, ulong timestamp, bool &accepted) { Q_Q(QQuickWindow); QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); @@ -1728,7 +1730,7 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce QQuickItem *child = children.at(ii); if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled) continue; - if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted)) + if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, timestamp, accepted)) return true; } @@ -1737,7 +1739,7 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce if (item->contains(p)) { if (!hoverItems.isEmpty() && hoverItems[0] == item) { //move - accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted); + accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, timestamp, accepted); } else { QList itemsToHover; QQuickItem* parent = item; @@ -1748,12 +1750,12 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce // Leaving from previous hovered items until we reach the item or one of its ancestors. while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) { QQuickItem *hoverLeaveItem = hoverItems.takeFirst(); - sendHoverEvent(QEvent::HoverLeave, hoverLeaveItem, scenePos, lastScenePos, modifiers, accepted); + sendHoverEvent(QEvent::HoverLeave, hoverLeaveItem, scenePos, lastScenePos, modifiers, timestamp, accepted); } if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item // ### Shouldn't we send moves for the parent items as well? - accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted); + accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, timestamp, accepted); } else { // Enter items that are not entered yet. int startIdx = -1; @@ -1772,7 +1774,7 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce // itemToHoverPrivate->window here prevents that case. if (itemToHoverPrivate->window == q && itemToHoverPrivate->hoverEnabled) { hoverItems.prepend(itemToHover); - sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted); + sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, timestamp, accepted); } } } diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 33aa021d98..be7252d335 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -155,14 +155,14 @@ public: bool deliverTouchCancelEvent(QTouchEvent *); void deliverDelayedTouchEvent(); void flushDelayedTouchEvent(); - bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool &accepted); + bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, ulong timestamp, bool &accepted); bool deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet *acceptedNewPoints, const QSet &matchingNewPoints, const QList &matchingPoints, QSet *filtered); QTouchEvent *touchEventForItemBounds(QQuickItem *target, const QTouchEvent &originalEvent); QTouchEvent *touchEventWithPoints(const QTouchEvent &event, const QList &newPoints); bool sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event, QSet *filtered); bool sendHoverEvent(QEvent::Type, QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, - Qt::KeyboardModifiers modifiers, bool accepted); - bool clearHover(); + Qt::KeyboardModifiers modifiers, ulong timestamp, bool accepted); + bool clearHover(ulong timestamp = 0); #ifndef QT_NO_DRAGANDDROP void deliverDragEvent(QQuickDragGrabber *, QEvent *); bool deliverDragEvent(QQuickDragGrabber *, QQuickItem *, QDragMoveEvent *); diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index c597cf03dd..b03cb856c1 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -371,6 +371,7 @@ private slots: void testRenderJob(); void testHoverChildMouseEventFilter(); + void testHoverTimestamp(); private: QTouchDevice *touchDevice; QTouchDevice *touchDeviceWithVelocity; @@ -2282,6 +2283,90 @@ void tst_qquickwindow::testHoverChildMouseEventFilter() QCOMPARE(middleItem->eventCount(QEvent::HoverEnter), 0); } +class HoverTimestampConsumer : public QQuickItem +{ + Q_OBJECT +public: + HoverTimestampConsumer(QQuickItem *parent = 0) + : QQuickItem(parent) + { + setAcceptHoverEvents(true); + } + + void hoverEnterEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); } + void hoverLeaveEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); } + void hoverMoveEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); } + + QList hoverTimestamps; +}; + +// Checks that a QHoverEvent carries the timestamp of the QMouseEvent that caused it. +// QTBUG-54600 +void tst_qquickwindow::testHoverTimestamp() +{ + QQuickWindow window; + + window.resize(200, 200); + window.setPosition(100, 100); + window.setTitle(QTest::currentTestFunction()); + window.show(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + + HoverTimestampConsumer *hoverConsumer = new HoverTimestampConsumer(window.contentItem()); + hoverConsumer->setWidth(100); + hoverConsumer->setHeight(100); + hoverConsumer->setX(50); + hoverConsumer->setY(50); + + // First position, outside + { + QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(40, 40), QPointF(40, 40), QPointF(140, 140), + Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized); + mouseEvent.setTimestamp(10); + QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent)); + } + + // Enter + { + QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(50, 50), QPointF(50, 50), QPointF(150, 150), + Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized); + mouseEvent.setTimestamp(20); + QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent)); + } + QCOMPARE(hoverConsumer->hoverTimestamps.size(), 1); + QCOMPARE(hoverConsumer->hoverTimestamps.last(), 20UL); + + // Move + { + QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(60, 60), QPointF(60, 60), QPointF(160, 160), + Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized); + mouseEvent.setTimestamp(30); + QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent)); + } + QCOMPARE(hoverConsumer->hoverTimestamps.size(), 2); + QCOMPARE(hoverConsumer->hoverTimestamps.last(), 30UL); + + // Move + { + QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(100, 100), QPointF(100, 100), QPointF(200, 200), + Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized); + mouseEvent.setTimestamp(40); + QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent)); + } + QCOMPARE(hoverConsumer->hoverTimestamps.size(), 3); + QCOMPARE(hoverConsumer->hoverTimestamps.last(), 40UL); + + // Leave + { + QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(160, 160), QPointF(160, 160), QPointF(260, 260), + Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized); + mouseEvent.setTimestamp(5); + QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent)); + } + QCOMPARE(hoverConsumer->hoverTimestamps.size(), 4); + QCOMPARE(hoverConsumer->hoverTimestamps.last(), 5UL); +} + QTEST_MAIN(tst_qquickwindow) #include "tst_qquickwindow.moc" -- cgit v1.2.3 From 91ed06b767aa4993d28c8b2db4900c319098b035 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 14 Jul 2016 11:58:14 +0200 Subject: Fix logic bug when deleting properties of JS objects The code used the size of the internal class in an inconsistent way. It should simply compute and work with the old internal class size, as that reflects the old object layout. [ChangeLog][QtQml] Fix assertion when deleting properties of JS objects Task-number: QTBUG-54589 Change-Id: Ie3db70437e780215d08a1a96491db75f8b859754 Reviewed-by: Robin Burchell Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4internalclass.cpp | 8 ++++---- tests/auto/qml/qqmlecmascript/data/qtbug_54589.qml | 16 ++++++++++++++++ tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 11 +++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 tests/auto/qml/qqmlecmascript/data/qtbug_54589.qml diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 8f0b1776d7..0bc4b9a7fc 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -155,8 +155,8 @@ static void insertHoleIntoPropertyData(Object *object, int idx) static void removeFromPropertyData(Object *object, int idx, bool accessor = false) { int inlineSize = object->d()->inlineMemberSize; - int icSize = object->internalClass()->size; int delta = (accessor ? 2 : 1); + int oldSize = object->internalClass()->size + delta; int to = idx; int from = to + delta; if (from < inlineSize) { @@ -164,15 +164,15 @@ static void removeFromPropertyData(Object *object, int idx, bool accessor = fals to = inlineSize - delta; from = inlineSize; } - if (to < inlineSize && from < icSize) { + if (to < inlineSize && from < oldSize) { Q_ASSERT(from >= inlineSize); memcpy(object->propertyData(to), object->d()->propertyData(from), (inlineSize - to)*sizeof(Value)); to = inlineSize; from = inlineSize + delta; } - if (from < icSize + delta) { + if (from < oldSize) { Q_ASSERT(to >= inlineSize && from > to); - memmove(object->propertyData(to), object->d()->propertyData(from), (icSize + delta - to)*sizeof(Value)); + memmove(object->propertyData(to), object->d()->propertyData(from), (oldSize - to)*sizeof(Value)); } } diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_54589.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_54589.qml new file mode 100644 index 0000000000..8f7d5f2a70 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/qtbug_54589.qml @@ -0,0 +1,16 @@ +import QtQuick 2.0 + +QtObject { + function checkPropertyDeletion() { + var o = { + x: 1, + y: 2 + }; + o.z = 3 + delete o.y; + + return (o.x === 1 && o.y === undefined && o.z === 3) + } + + property bool result: checkPropertyDeletion() +} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 08ebfbbbcf..2ec296ae66 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -328,6 +328,7 @@ private slots: void switchExpression(); void qtbug_46022(); void qtbug_52340(); + void qtbug_54589(); private: // static void propertyVarWeakRefCallback(v8::Persistent object, void* parameter); @@ -7922,6 +7923,16 @@ void tst_qqmlecmascript::qtbug_52340() QVERIFY(returnValue.toBool()); } +void tst_qqmlecmascript::qtbug_54589() +{ + QQmlComponent component(&engine, testFileUrl("qtbug_54589.qml")); + + QScopedPointer obj(component.create()); + QVERIFY(obj != 0); + QCOMPARE(obj->property("result").toBool(), true); +} + + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" -- cgit v1.2.3 From a1f6409d1c34238405bbd73d067a39091bf844f7 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Thu, 7 Jul 2016 13:21:05 +0200 Subject: Fix missing closing parenthesis in TextEdit docs Change-Id: Ib1872e6353a49bc12a6a714a79873e8c0a7032f7 Reviewed-by: Robin Burchell --- src/quick/items/qquicktextedit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 8282c09770..3ab7f358ff 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -1435,8 +1435,8 @@ void QQuickTextEdit::setSelectByKeyboard(bool on) If true, the user can use the mouse to select text in some platform-specific way. Note that for some platforms this may - not be an appropriate interaction (eg. may conflict with how - the text needs to behave inside a Flickable. + not be an appropriate interaction; it may conflict with how + the text needs to behave inside a Flickable, for example. */ bool QQuickTextEdit::selectByMouse() const { -- cgit v1.2.3 From 50cc3c20047b88e763dc21ec3c5d8b28c7ecb2d4 Mon Sep 17 00:00:00 2001 From: Joni Poikelin Date: Thu, 14 Jul 2016 08:55:08 +0300 Subject: Avoid crashing when failing to query GL_EXTENSIONS Change-Id: Ice542d53c4eb9f34745e2d06dd03c32de7a9817e Reviewed-by: Laszlo Agocs --- src/quick/scenegraph/util/qsgatlastexture.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index 832510148c..1a1f0d37f7 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -151,13 +151,13 @@ Atlas::Atlas(const QSize &size) wrongfullyReportsBgra8888Support = false; const char *ext = (const char *) QOpenGLContext::currentContext()->functions()->glGetString(GL_EXTENSIONS); - if (!wrongfullyReportsBgra8888Support + if (ext && !wrongfullyReportsBgra8888Support && (strstr(ext, "GL_EXT_bgra") || strstr(ext, "GL_EXT_texture_format_BGRA8888") || strstr(ext, "GL_IMG_texture_format_BGRA8888"))) { m_internalFormat = m_externalFormat = GL_BGRA; #ifdef Q_OS_IOS - } else if (strstr(ext, "GL_APPLE_texture_format_BGRA8888")) { + } else if (ext && strstr(ext, "GL_APPLE_texture_format_BGRA8888")) { m_internalFormat = GL_RGBA; m_externalFormat = GL_BGRA; #endif // IOS -- cgit v1.2.3 From c8c1d4964ba4af8700d01cefdd80359090479bc0 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Mon, 30 May 2016 10:19:20 +0200 Subject: PieChart examples: initialize members Coverity (CID 161680, 161678) pointed out that constructors don't initialize some members; getters would have returned drivel if called before setters. Unimportant but we should set a good example in our example code. Change-Id: Ia0483cfbe2cae379a0e84f10db1d8edc9cb5c52b Reviewed-by: Simon Hausmann --- .../tutorials/extending-qml/chapter4-customPropertyTypes/piechart.cpp | 2 +- .../qml/tutorials/extending-qml/chapter5-listproperties/pieslice.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.cpp b/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.cpp index 965e5152c1..d963b6d1b4 100644 --- a/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.cpp +++ b/examples/qml/tutorials/extending-qml/chapter4-customPropertyTypes/piechart.cpp @@ -41,7 +41,7 @@ #include "pieslice.h" PieChart::PieChart(QQuickItem *parent) - : QQuickItem(parent) + : QQuickItem(parent), m_pieSlice(0) { } diff --git a/examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.cpp b/examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.cpp index ceb0041ec8..50c018e33e 100644 --- a/examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.cpp +++ b/examples/qml/tutorials/extending-qml/chapter5-listproperties/pieslice.cpp @@ -42,7 +42,7 @@ #include PieSlice::PieSlice(QQuickItem *parent) - : QQuickPaintedItem(parent) + : QQuickPaintedItem(parent), m_fromAngle(0), m_angleSpan(0) { } -- cgit v1.2.3 From 20b96e21090fd008cc4a0d39300402fa3865d705 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 15 Jul 2016 10:45:22 +0200 Subject: Relax QQmlProfilerService test for scene graph events The scene graph might decide to do an initial rendering, before the first SceneGraphContextFrame. Change-Id: Ie6d96574b5585cfda4dcd258b6031303f9a37715 Reviewed-by: Laszlo Agocs --- .../qqmlprofilerservice/tst_qqmlprofilerservice.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp index 670d58e4fd..61006ad1f1 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp +++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp @@ -648,11 +648,11 @@ void tst_QQmlProfilerService::scenegraphData() checkTraceReceived(); checkJsHeap(); - // check that at least one frame was rendered - // there should be a SGPolishAndSync + SGRendererFrame + SGRenderLoopFrame sequence - // (though we can't be sure to get the SGRenderLoopFrame in the threaded renderer) + // Check that at least one frame was rendered. + // There should be a SGContextFrame + SGRendererFrame + SGRenderLoopFrame sequence, + // but we can't be sure to get the SGRenderLoopFrame in the threaded renderer. // - // since the rendering happens in a different thread, there could be other unrelated events + // Since the rendering happens in a different thread, there could be other unrelated events // interleaved. Also, events could carry the same time stamps and be sorted in an unexpected way // if the clocks are acting up. qint64 contextFrameTime = -1; @@ -681,8 +681,13 @@ void tst_QQmlProfilerService::scenegraphData() foreach (const QQmlProfilerData &msg, m_client->asynchronousMessages) { if (msg.detailType == QQmlProfilerClient::SceneGraphRenderLoopFrame) { - QVERIFY(msg.time >= renderFrameTime); - break; + if (msg.time >= contextFrameTime) { + // Make sure SceneGraphRenderLoopFrame is not between SceneGraphContextFrame and + // SceneGraphRendererFrame. A SceneGraphRenderLoopFrame before everything else is + // OK as the scene graph might decide to do an initial rendering. + QVERIFY(msg.time >= renderFrameTime); + break; + } } } } -- cgit v1.2.3 From b08a4c2f421494b515dc7ef6f50d33e37e18eb91 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Tue, 12 Jul 2016 19:29:39 +0200 Subject: Remove vsync sleep before rendering first frame The QSGRenderThread slept for up to one vsync interval before the first frame was rendered. This happened when the QSGRenderContext was not yet initialized and thus a sync could not result in changes. With LTTNG and custom trace points this latency was easily visible before the first frame swap. With perf it can also be checked, when one does: QSG_RENDER_LOOP=threaded perf trace record -m 10M \ -e syscalls:sys_enter_nanosleep,syscalls:sys_enter_ioctl \ --call-graph dwarf qml main.qml ... [ perf record: Captured and wrote 116.731 MB perf.data (14309 samples) ] Then afterwards have a look at the output of perf script --comms QSGRenderThread And you will notice the sleep directly at the start, followed by the bulk of ioctl required to setup the OpenGL contexts: QSGRenderThread 10875 [001] 13940.801449: syscalls:sys_enter_nanosleep: rqtp: 0x7f1ab954cd60, rmtp: 0x7f1ab954cd60 7f1ada3997fd __nanosleep+0x2d (/usr/lib/libpthread-2.23.so) 7f1ada9683ed qt_nanosleep+0x2d (/home/milian/projects/compiled/qt5-5.7-opt/lib/libQt5Core.so.5.7.0) 7f1ada8c73b8 QThread::msleep+0x38 (/home/milian/projects/compiled/qt5-5.7-opt/lib/libQt5Core.so.5.7.0) 7f1abb594320 QSGRenderThread::syncAndRender+0x320 (/home/milian/projects/compiled/qt5-5.7-opt/lib/libQt5Quick.so.5.7.0) 7f1abb598b0c QSGRenderThread::run+0x19c (/home/milian/projects/compiled/qt5-5.7-opt/lib/libQt5Quick.so.5.7.0) 7f1ada8c7f89 QThreadPrivate::start+0x149 (/home/milian/projects/compiled/qt5-5.7-opt/lib/libQt5Core.so.5.7.0) 7f1ada390484 start_thread+0xc4 (/usr/lib/libpthread-2.23.so) 7f1ad982e6dd __clone+0x6d (/usr/lib/libc-2.23.so) ... ioctl follow This change here checks the validity of the render context before sleeping, thereby removing the vsync latency before rendering the first frame. Note that simply skipping the calls to `syncAndRender` from `run` is not an option, as those also trigger the expose event that is required for the initialization to happen eventually. [ChangeLog][QtQuick] The threaded scene graph renderer does not sleep up to one vsync interval before the first frame anymore. Change-Id: If7474d5420e0d4a1d05ccb664c7c6932fa989127 Reviewed-by: Gunnar Sletta Reviewed-by: Ulf Hermann --- src/quick/scenegraph/qsgthreadedrenderloop.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 8d6bea9e67..ceb3caa53f 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -593,7 +593,7 @@ void QSGRenderThread::syncAndRender() #endif Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame); - if (!syncResultedInChanges && !repaintRequested) { + if (!syncResultedInChanges && !repaintRequested && sgrc->isValid()) { qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- no changes, render aborted"; int waitTime = vsyncDelta - (int) waitTimer.elapsed(); if (waitTime > 0) -- cgit v1.2.3 From 9d4b55640788bf96ea100ad0616fd4236370d140 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Thu, 31 Mar 2016 19:43:27 +0200 Subject: Add benchmark for pathological O(N^2) behavior in QQmlChangeSet. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch is just here for documentation of this behavior and does not come with a fix yet. This hotspot was found while profiling the example code attached to QTBUG-34391. It is triggered by the repeated calls to _q_itemsMoved in QQmlDelegateModel::_q_layoutChanged. Change-Id: I758744b3650c3c47dc86b914b823c3e9f96ce81e Reviewed-by: Albert Astals Cid Reviewed-by: Daniel Vrátil Reviewed-by: Christopher Adams --- tests/benchmarks/qml/qml.pro | 1 + .../benchmarks/qml/qqmlchangeset/qqmlchangeset.pro | 10 ++++ .../qml/qqmlchangeset/tst_qqmlchangeset.cpp | 60 ++++++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 tests/benchmarks/qml/qqmlchangeset/qqmlchangeset.pro create mode 100644 tests/benchmarks/qml/qqmlchangeset/tst_qqmlchangeset.cpp diff --git a/tests/benchmarks/qml/qml.pro b/tests/benchmarks/qml/qml.pro index d3ce69c713..5d48ec0067 100644 --- a/tests/benchmarks/qml/qml.pro +++ b/tests/benchmarks/qml/qml.pro @@ -5,6 +5,7 @@ SUBDIRS += \ compilation \ javascript \ holistic \ + qqmlchangeset \ qqmlcomponent \ qqmlimage \ qqmlmetaproperty \ diff --git a/tests/benchmarks/qml/qqmlchangeset/qqmlchangeset.pro b/tests/benchmarks/qml/qqmlchangeset/qqmlchangeset.pro new file mode 100644 index 0000000000..fc0ccdf8ed --- /dev/null +++ b/tests/benchmarks/qml/qqmlchangeset/qqmlchangeset.pro @@ -0,0 +1,10 @@ +CONFIG += benchmark +TEMPLATE = app +TARGET = tst_qqmlchangeset +QT += qml quick-private testlib +osx:CONFIG -= app_bundle + +SOURCES += tst_qqmlchangeset.cpp + +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 + diff --git a/tests/benchmarks/qml/qqmlchangeset/tst_qqmlchangeset.cpp b/tests/benchmarks/qml/qqmlchangeset/tst_qqmlchangeset.cpp new file mode 100644 index 0000000000..bbfb52343c --- /dev/null +++ b/tests/benchmarks/qml/qqmlchangeset/tst_qqmlchangeset.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include + +#include + +class tst_qqmlchangeset : public QObject +{ + Q_OBJECT + +private slots: + void move(); +}; + +void tst_qqmlchangeset::move() +{ + QBENCHMARK { + QQmlChangeSet set; + const int MAX_ROWS = 30000; + for (int i = 0; i < MAX_ROWS; ++i) { + set.move(i, MAX_ROWS - 1 - i, 1, i); + } + } +} + +QTEST_MAIN(tst_qqmlchangeset) +#include "tst_qqmlchangeset.moc" -- cgit v1.2.3 From 0839d89cc0ada7b304939bc527433c2498d995b0 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Mon, 18 Jul 2016 12:20:16 +0200 Subject: Doc: minor spelling issue Change-Id: I18316de7c0eaee98a7eb0aa274c06864af471116 Reviewed-by: Martin Smith --- examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc b/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc index 278f154781..d6eb711929 100644 --- a/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc +++ b/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc @@ -102,8 +102,8 @@ state and we use it to update the shader program with the current color. The previous state is passed in as a second parameter so that the user can update only that which has changed. In our - usecase, where all the colors are different, the updateState will - be called once for every node. + use case, where all the colors are different, the updateState() + function will be called once for every node. \snippet scenegraph/simplematerial/simplematerial.cpp 7 -- cgit v1.2.3 From 06ed1ad17abe1ef597d4ecf86962da5ac21365e5 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 19 Jul 2016 11:28:14 +0200 Subject: JS: Check for errors before using sub-expression results Specifically: don't de-reference a result and assume that it's not-null. Task-number: QTBUG-54687 Change-Id: If07d3250a95a7815ab7a3262b88e0227965ef8e7 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4codegen.cpp | 116 +++++++++++++++++---- .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 7 ++ 2 files changed, 102 insertions(+), 21 deletions(-) diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index c14163a2f7..6bf931c882 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1052,6 +1052,8 @@ bool Codegen::visit(ArrayLiteral *ast) current->expr = _block->CONST(IR::MissingType, 0); } Result expr = expression(it->expression); + if (hasError) + return false; IR::ExprList *arg = _function->New(); if (!current) { @@ -1094,6 +1096,8 @@ bool Codegen::visit(ArrayMemberExpression *ast) Result base = expression(ast->base); Result index = expression(ast->expression); + if (hasError) + return false; _expr.code = subscript(*base, *index); return false; } @@ -1133,10 +1137,16 @@ bool Codegen::visit(BinaryExpression *ast) const unsigned r = _block->newTemp(); - move(_block->TEMP(r), *expression(ast->left)); + Result lhs = expression(ast->left); + if (hasError) + return false; + move(_block->TEMP(r), *lhs); setLocation(cjump(_block->TEMP(r), iftrue, endif), ast->operatorToken); _block = iftrue; - move(_block->TEMP(r), *expression(ast->right)); + Result rhs = expression(ast->right); + if (hasError) + return false; + move(_block->TEMP(r), *rhs); _block->JUMP(endif); _expr.code = _block->TEMP(r); @@ -1154,10 +1164,16 @@ bool Codegen::visit(BinaryExpression *ast) IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler()); const unsigned r = _block->newTemp(); - move(_block->TEMP(r), *expression(ast->left)); + Result lhs = expression(ast->left); + if (hasError) + return false; + move(_block->TEMP(r), *lhs); setLocation(cjump(_block->TEMP(r), endif, iffalse), ast->operatorToken); _block = iffalse; - move(_block->TEMP(r), *expression(ast->right)); + Result rhs = expression(ast->right); + if (hasError) + return false; + move(_block->TEMP(r), *rhs); _block->JUMP(endif); _block = endif; @@ -1167,6 +1183,8 @@ bool Codegen::visit(BinaryExpression *ast) } IR::Expr* left = *expression(ast->left); + if (hasError) + return false; switch (ast->op) { case QSOperator::Or: @@ -1176,17 +1194,19 @@ bool Codegen::visit(BinaryExpression *ast) case QSOperator::Assign: { if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation())) return false; - IR::Expr* right = *expression(ast->right); + Result right = expression(ast->right); + if (hasError) + return false; if (!left->isLValue()) { throwReferenceError(ast->operatorToken, QStringLiteral("left-hand side of assignment operator is not an lvalue")); return false; } if (_expr.accept(nx)) { - move(left, right); + move(left, *right); } else { const unsigned t = _block->newTemp(); - move(_block->TEMP(t), right); + move(_block->TEMP(t), *right); move(left, _block->TEMP(t)); _expr.code = _block->TEMP(t); } @@ -1206,17 +1226,19 @@ bool Codegen::visit(BinaryExpression *ast) case QSOperator::InplaceXor: { if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation())) return false; - IR::Expr* right = *expression(ast->right); + Result right = expression(ast->right); + if (hasError) + return false; if (!left->isLValue()) { throwSyntaxError(ast->operatorToken, QStringLiteral("left-hand side of inplace operator is not an lvalue")); return false; } if (_expr.accept(nx)) { - move(left, right, baseOp(ast->op)); + move(left, *right, baseOp(ast->op)); } else { const unsigned t = _block->newTemp(); - move(_block->TEMP(t), right); + move(_block->TEMP(t), *right); move(left, _block->TEMP(t), baseOp(ast->op)); _expr.code = left; } @@ -1239,12 +1261,14 @@ bool Codegen::visit(BinaryExpression *ast) left = _block->TEMP(t); } - IR::Expr* right = *expression(ast->right); + Result right = expression(ast->right); + if (hasError) + return false; if (_expr.accept(cx)) { - setLocation(cjump(binop(IR::binaryOperator(ast->op), left, right, ast->operatorToken), _expr.iftrue, _expr.iffalse), ast->operatorToken); + setLocation(cjump(binop(IR::binaryOperator(ast->op), left, *right, ast->operatorToken), _expr.iftrue, _expr.iffalse), ast->operatorToken); } else { - IR::Expr *e = binop(IR::binaryOperator(ast->op), left, right, ast->operatorToken); + IR::Expr *e = binop(IR::binaryOperator(ast->op), left, *right, ast->operatorToken); if (e->asConst() || e->asString()) _expr.code = e; else { @@ -1273,9 +1297,11 @@ bool Codegen::visit(BinaryExpression *ast) left = _block->TEMP(t); } - IR::Expr* right = *expression(ast->right); + Result right = expression(ast->right); + if (hasError) + return false; - IR::Expr *e = binop(IR::binaryOperator(ast->op), left, right, ast->operatorToken); + IR::Expr *e = binop(IR::binaryOperator(ast->op), left, *right, ast->operatorToken); if (e->asConst() || e->asString()) _expr.code = e; else { @@ -1300,11 +1326,15 @@ bool Codegen::visit(CallExpression *ast) IR::ExprList *args = 0, **args_it = &args; for (ArgumentList *it = ast->arguments; it; it = it->next) { Result arg = expression(it->expression); + if (hasError) + return false; IR::Expr *actual = argument(*arg); *args_it = _function->New(); (*args_it)->init(actual); args_it = &(*args_it)->next; } + if (hasError) + return false; _expr.code = call(*base, args); return false; } @@ -1323,11 +1353,17 @@ bool Codegen::visit(ConditionalExpression *ast) condition(ast->expression, iftrue, iffalse); _block = iftrue; - move(_block->TEMP(t), *expression(ast->ok)); + Result ok = expression(ast->ok); + if (hasError) + return false; + move(_block->TEMP(t), *ok); _block->JUMP(endif); _block = iffalse; - move(_block->TEMP(t), *expression(ast->ko)); + Result ko = expression(ast->ko); + if (hasError) + return false; + move(_block->TEMP(t), *ko); _block->JUMP(endif); _block = endif; @@ -1343,6 +1379,8 @@ bool Codegen::visit(DeleteExpression *ast) return false; IR::Expr* expr = *expression(ast->expression); + if (hasError) + return false; // Temporaries cannot be deleted IR::ArgLocal *al = expr->asArgLocal(); if (al && al->index < static_cast(_env->members.size())) { @@ -1404,7 +1442,8 @@ bool Codegen::visit(FieldMemberExpression *ast) return false; Result base = expression(ast->base); - _expr.code = member(*base, _function->newString(ast->name.toString())); + if (!hasError) + _expr.code = member(*base, _function->newString(ast->name.toString())); return false; } @@ -1495,6 +1534,8 @@ bool Codegen::visit(NewExpression *ast) return false; Result base = expression(ast->expression); + if (hasError) + return false; IR::Expr *expr = *base; if (expr && !expr->asTemp() && !expr->asArgLocal() && !expr->asName() && !expr->asMember()) { const unsigned t = _block->newTemp(); @@ -1511,6 +1552,8 @@ bool Codegen::visit(NewMemberExpression *ast) return false; Result base = expression(ast->base); + if (hasError) + return false; IR::Expr *expr = *base; if (expr && !expr->asTemp() && !expr->asArgLocal() && !expr->asName() && !expr->asMember()) { const unsigned t = _block->newTemp(); @@ -1521,6 +1564,8 @@ bool Codegen::visit(NewMemberExpression *ast) IR::ExprList *args = 0, **args_it = &args; for (ArgumentList *it = ast->arguments; it; it = it->next) { Result arg = expression(it->expression); + if (hasError) + return false; IR::Expr *actual = argument(*arg); *args_it = _function->New(); (*args_it)->init(actual); @@ -1538,6 +1583,8 @@ bool Codegen::visit(NotExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; const unsigned r = _block->newTemp(); setLocation(move(_block->TEMP(r), unop(IR::OpNot, *expr, ast->notToken)), ast->notToken); _expr.code = _block->TEMP(r); @@ -1595,6 +1642,8 @@ bool Codegen::visit(ObjectLiteral *ast) QString name = it->assignment->name->asString(); if (PropertyNameAndValue *nv = AST::cast(it->assignment)) { Result value = expression(nv->value); + if (hasError) + return false; ObjectPropertyValue &v = valueMap[name]; if (v.hasGetter() || v.hasSetter() || (_function->isStrict && v.value)) { throwSyntaxError(nv->lastSourceLocation(), @@ -1725,6 +1774,8 @@ bool Codegen::visit(PostDecrementExpression *ast) return false; Result expr = expression(ast->base); + if (hasError) + return false; if (!expr->isLValue()) { throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation")); return false; @@ -1751,6 +1802,8 @@ bool Codegen::visit(PostIncrementExpression *ast) return false; Result expr = expression(ast->base); + if (hasError) + return false; if (!expr->isLValue()) { throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation")); return false; @@ -1777,6 +1830,8 @@ bool Codegen::visit(PreDecrementExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; if (!expr->isLValue()) { throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference.")); return false; @@ -1802,6 +1857,8 @@ bool Codegen::visit(PreIncrementExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; if (!expr->isLValue()) { throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference.")); return false; @@ -1854,6 +1911,8 @@ bool Codegen::visit(TildeExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; const unsigned t = _block->newTemp(); setLocation(move(_block->TEMP(t), unop(IR::OpCompl, *expr, ast->tildeToken)), ast->tildeToken); _expr.code = _block->TEMP(t); @@ -1879,6 +1938,8 @@ bool Codegen::visit(TypeOfExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; IR::ExprList *args = _function->New(); args->init(reference(*expr)); _expr.code = call(_block->NAME(IR::Name::builtin_typeof, ast->typeofToken.startLine, ast->typeofToken.startColumn), args); @@ -1891,6 +1952,8 @@ bool Codegen::visit(UnaryMinusExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; const unsigned t = _block->newTemp(); setLocation(move(_block->TEMP(t), unop(IR::OpUMinus, *expr, ast->minusToken)), ast->minusToken); _expr.code = _block->TEMP(t); @@ -1903,6 +1966,8 @@ bool Codegen::visit(UnaryPlusExpression *ast) return false; Result expr = expression(ast->expression); + if (hasError) + return false; const unsigned t = _block->newTemp(); setLocation(move(_block->TEMP(t), unop(IR::OpUPlus, *expr, ast->plusToken)), ast->plusToken); _expr.code = _block->TEMP(t); @@ -2217,7 +2282,10 @@ bool Codegen::visit(ForEachStatement *ast) IR::BasicBlock *foreachend = _function->newBasicBlock(exceptionHandler()); int objectToIterateOn = _block->newTemp(); - move(_block->TEMP(objectToIterateOn), *expression(ast->expression)); + Result expr = expression(ast->expression); + if (hasError) + return false; + move(_block->TEMP(objectToIterateOn), *expr); IR::ExprList *args = _function->New(); args->init(_block->TEMP(objectToIterateOn)); @@ -2229,7 +2297,10 @@ bool Codegen::visit(ForEachStatement *ast) _block = foreachbody; int temp = _block->newTemp(); - move(*expression(ast->initialiser), _block->TEMP(temp)); + Result init = expression(ast->initialiser); + if (hasError) + return false; + move(*init, _block->TEMP(temp)); statement(ast->statement); _block->JUMP(foreachin); @@ -2719,7 +2790,10 @@ bool Codegen::visit(WithStatement *ast) _function->hasWith = true; const int withObject = _block->newTemp(); - _block->MOVE(_block->TEMP(withObject), *expression(ast->expression)); + Result src = expression(ast->expression); + if (hasError) + return false; + _block->MOVE(_block->TEMP(withObject), *src); // need an exception handler for with to cleanup the with scope IR::BasicBlock *withExceptionHandler = _function->newBasicBlock(exceptionHandler()); diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 2ec296ae66..aaa72d48cd 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -329,6 +329,7 @@ private slots: void qtbug_46022(); void qtbug_52340(); void qtbug_54589(); + void qtbug_54687(); private: // static void propertyVarWeakRefCallback(v8::Persistent object, void* parameter); @@ -7932,6 +7933,12 @@ void tst_qqmlecmascript::qtbug_54589() QCOMPARE(obj->property("result").toBool(), true); } +void tst_qqmlecmascript::qtbug_54687() +{ + QJSEngine e; + // it's simple: this shouldn't crash. + engine.evaluate("12\n----12"); +} QTEST_MAIN(tst_qqmlecmascript) -- cgit v1.2.3 From d48b397cc79265e80c8437888f9ded0b0364e418 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Wed, 20 Jul 2016 11:30:39 +0200 Subject: Doc: syntax error qml example onRelased --> onReleased Change-Id: I0078229b66bc8db4c70789d0536de70166ee0852 Reviewed-by: Martin Smith Reviewed-by: Mitch Curtis --- src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc index 04d0d0ed2e..de0515e5d0 100644 --- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc +++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc @@ -729,7 +729,7 @@ Rectangle { MouseArea { anchors.fill: parent onPressed: root.activated(mouse.x, mouse.y) - onRelased: root.deactivated() + onReleased: root.deactivated() } } \endqml -- cgit v1.2.3 From d6ac86f59250e05eb5e7db5bb8a45a85db1f0f25 Mon Sep 17 00:00:00 2001 From: Maximiliano Curia Date: Tue, 19 Jul 2016 15:49:48 +0200 Subject: Fix QQmlEngine crash on big endian 64 bit architectures (s390x) This change disables the BIG_ENDIAN 32 bits words mangling in 64 bits machines (where the words are 64 bits long); this would otherwise result in a segfault. Task-number: QTBUG-54717 Change-Id: I6b5ab6f213880b030795185c05e609d290168901 Reviewed-by: Simon Hausmann Reviewed-by: Timo Jyrinki Reviewed-by: Erik Verbruggen --- src/qml/jsruntime/qv4value_p.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 7c2bb31a00..5abf5ad9e8 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -96,13 +96,13 @@ public: Q_ALWAYS_INLINE quint64 rawValue() const { return _val; } Q_ALWAYS_INLINE void setRawValue(quint64 raw) { _val = raw; } -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN || defined(QV4_USE_64_BIT_VALUE_ENCODING) static inline int valueOffset() { return 0; } static inline int tagOffset() { return 4; } Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; } Q_ALWAYS_INLINE quint32 value() const { return _val & quint64(~quint32(0)); } Q_ALWAYS_INLINE quint32 tag() const { return _val >> 32; } -#else // !Q_LITTLE_ENDIAN +#else // !Q_LITTLE_ENDIAN && !defined(QV4_USE_64_BIT_VALUE_ENCODING) static inline int valueOffset() { return 4; } static inline int tagOffset() { return 0; } Q_ALWAYS_INLINE void setTagValue(quint32 tag, quint32 value) { _val = quint64(value) << 32 | tag; } -- cgit v1.2.3 From c016634478a4c9f480f7d9d5c85dded307a80d13 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 20 Jul 2016 09:25:46 +0200 Subject: Fix string property assignments to 2d vectors and quaternions Just like it's possible to assign "1,2,3" to a QVector3D, the same should be possible for a QVector2D and a QQuaternion. Task-number: QTBUG-54858 Change-Id: I8f394279dcdf5c057876efaa316b4bad51a4c126 Reviewed-by: Robin Burchell --- src/qml/compiler/qqmltypecompiler.cpp | 24 ++++++++++++++++++++ src/qml/qml/qqmlobjectcreator.cpp | 26 ++++++++++++++++++++++ .../qml/qqmllanguage/data/assignBasicTypes.qml | 2 ++ tests/auto/qml/qqmllanguage/testtypes.h | 24 ++++++++++++++++++++ tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 2 ++ 5 files changed, 78 insertions(+) diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index fcc0ca8d14..7e4ee344ff 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -2244,6 +2244,17 @@ bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCa } } break; + case QVariant::Vector2D: { + struct { + float xp; + float yp; + } vec; + if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) { + recordError(binding->valueLocation, tr("Invalid property assignment: 2D vector expected")); + return false; + } + } + break; case QVariant::Vector3D: { struct { float xp; @@ -2269,6 +2280,19 @@ bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCa } } break; + case QVariant::Quaternion: { + struct { + float wp; + float xp; + float yp; + float zp; + } vec; + if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) { + recordError(binding->valueLocation, tr("Invalid property assignment: quaternion expected")); + return false; + } + } + break; case QVariant::RegExp: recordError(binding->valueLocation, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax")); return false; diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 15c38c1d5b..0c13a7a017 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -507,6 +507,18 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } break; + case QVariant::Vector2D: { + struct { + float xp; + float yp; + } vec; + bool ok = QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(qmlUnit), &vec, sizeof(vec)); + Q_ASSERT(ok); + Q_UNUSED(ok); + argv[0] = reinterpret_cast(&vec); + QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + } + break; case QVariant::Vector3D: { struct { float xp; @@ -534,6 +546,20 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); } break; + case QVariant::Quaternion: { + struct { + float wp; + float xp; + float yp; + float zp; + } vec; + bool ok = QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(qmlUnit), &vec, sizeof(vec)); + Q_ASSERT(ok); + Q_UNUSED(ok); + argv[0] = reinterpret_cast(&vec); + QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + } + break; case QVariant::RegExp: Q_ASSERT(!"not possible"); break; diff --git a/tests/auto/qml/qqmllanguage/data/assignBasicTypes.qml b/tests/auto/qml/qqmllanguage/data/assignBasicTypes.qml index c91cf581b3..52027232db 100644 --- a/tests/auto/qml/qqmllanguage/data/assignBasicTypes.qml +++ b/tests/auto/qml/qqmllanguage/data/assignBasicTypes.qml @@ -26,7 +26,9 @@ MyTypeObject { boolProperty: true variantProperty: "Hello World!" vectorProperty: "10,1,2.2" + vector2Property: "2, 3" vector4Property: "10,1,2.2,2.3" + quaternionProperty: "4,5,6,7" urlProperty: "main.qml?with%3cencoded%3edata" objectProperty: MyTypeObject { intProperty: 8 } diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index c6c956cf36..be1129f4ab 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -38,8 +38,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -247,8 +249,10 @@ class MyTypeObject : public QObject Q_PROPERTY(QRectF rectFProperty READ rectFProperty WRITE setRectFProperty NOTIFY rectFPropertyChanged) Q_PROPERTY(bool boolProperty READ boolProperty WRITE setBoolProperty NOTIFY boolPropertyChanged) Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty NOTIFY variantPropertyChanged) + Q_PROPERTY(QVector2D vector2Property READ vector2Property WRITE setVector2Property NOTIFY vector2PropertyChanged) Q_PROPERTY(QVector3D vectorProperty READ vectorProperty WRITE setVectorProperty NOTIFY vectorPropertyChanged) Q_PROPERTY(QVector4D vector4Property READ vector4Property WRITE setVector4Property NOTIFY vector4PropertyChanged) + Q_PROPERTY(QQuaternion quaternionProperty READ quaternionProperty WRITE setQuaternionProperty NOTIFY quaternionPropertyChanged) Q_PROPERTY(QUrl urlProperty READ urlProperty WRITE setUrlProperty NOTIFY urlPropertyChanged) Q_PROPERTY(QQmlScriptString scriptProperty READ scriptProperty WRITE setScriptProperty) @@ -529,6 +533,15 @@ public: emit vectorPropertyChanged(); } + QVector2D vector2PropertyValue; + QVector2D vector2Property() const { + return vector2PropertyValue; + } + void setVector2Property(const QVector2D &v) { + vector2PropertyValue = v; + emit vector2PropertyChanged(); + } + QVector4D vector4PropertyValue; QVector4D vector4Property() const { return vector4PropertyValue; @@ -538,6 +551,15 @@ public: emit vector4PropertyChanged(); } + QQuaternion quaternionPropertyValue; + QQuaternion quaternionProperty() const { + return quaternionPropertyValue; + } + void setQuaternionProperty(const QQuaternion &v) { + quaternionPropertyValue = v; + emit quaternionPropertyChanged(); + } + QUrl urlPropertyValue; QUrl urlProperty() const { return urlPropertyValue; @@ -591,7 +613,9 @@ signals: void boolPropertyChanged(); void variantPropertyChanged(); void vectorPropertyChanged(); + void vector2PropertyChanged(); void vector4PropertyChanged(); + void quaternionPropertyChanged(); void urlPropertyChanged(); }; diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index f66caa31f1..2a519d55f0 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -682,7 +682,9 @@ void tst_qqmllanguage::assignBasicTypes() QCOMPARE(object->boolProperty(), true); QCOMPARE(object->variantProperty(), QVariant("Hello World!")); QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2f)); + QCOMPARE(object->vector2Property(), QVector2D(2, 3)); QCOMPARE(object->vector4Property(), QVector4D(10, 1, 2.2f, 2.3f)); + QCOMPARE(object->quaternionProperty(), QQuaternion(4, 5, 6, 7)); QUrl encoded; encoded.setEncodedUrl("main.qml?with%3cencoded%3edata", QUrl::TolerantMode); QCOMPARE(object->urlProperty(), component.url().resolved(encoded)); -- cgit v1.2.3 From 0a87552e8122cdda58160da2dd549da411d9093c Mon Sep 17 00:00:00 2001 From: Dan Cape Date: Wed, 7 Oct 2015 15:46:14 -0400 Subject: Fix QQuickItem's setAcceptedMouseButtons function When using setAcceptedMouseButtons to only allow the LeftButton, the user can click the LeftButton and while still holding it press the RightButton. There would be a press event sent for both. To resolve this, a check needed to be added to ensure the acceptedMouseButtons are checked when a second press comes in. [ChangeLog][QtQuick][QQuickItem] Fixed issue with mouse button events being sent even when they were disabled by setAcceptedMouseButtons. Change-Id: I064f3ff56ede12b1572e172be326eb337e280750 Task-number: QTBUG-31861 Reviewed-by: Frederik Gladhorn Reviewed-by: Robin Burchell Reviewed-by: Shawn Rutledge --- src/quick/items/qquickwindow.cpp | 6 ++++++ tests/auto/quick/qquickitem/tst_qquickitem.cpp | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index de1b5f236e..8a2471b34f 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1584,6 +1584,12 @@ bool QQuickWindowPrivate::deliverMouseEvent(QMouseEvent *event) } if (mouseGrabberItem) { + if (event->button() != Qt::NoButton + && mouseGrabberItem->acceptedMouseButtons() + && !(mouseGrabberItem->acceptedMouseButtons() & event->button())) { + event->ignore(); + return false; + } QPointF localPos = mouseGrabberItem->mapFromScene(event->windowPos()); QScopedPointer me(cloneMouseEvent(event, &localPos)); me->accept(); diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp index 73e691b08c..6a49c4dd7e 100644 --- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp @@ -172,6 +172,8 @@ private slots: void contains_data(); void contains(); + void ignoreButtonPressNotInAcceptedMouseButtons(); + private: enum PaintOrderOp { @@ -1971,6 +1973,27 @@ void tst_qquickitem::contains() QCOMPARE(result.toBool(), contains); } +void tst_qquickitem::ignoreButtonPressNotInAcceptedMouseButtons() +{ + // Verify the fix for QTBUG-31861 + TestItem item; + QCOMPARE(item.acceptedMouseButtons(), Qt::MouseButtons(Qt::NoButton)); + + QQuickWindow window; + item.setSize(QSizeF(200,100)); + item.setParentItem(window.contentItem()); + + item.setAcceptedMouseButtons(Qt::LeftButton); + QCOMPARE(item.acceptedMouseButtons(), Qt::MouseButtons(Qt::LeftButton)); + + QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(50, 50)); + QTest::mousePress(&window, Qt::RightButton, 0, QPoint(50, 50)); // ignored because it's not LeftButton + QTest::mouseRelease(&window, Qt::RightButton, 0, QPoint(50, 50)); // ignored because it didn't grab the RightButton press + QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(50, 50)); + + QCOMPARE(item.pressCount, 1); + QCOMPARE(item.releaseCount, 1); +} QTEST_MAIN(tst_qquickitem) -- cgit v1.2.3 From 1943ef3b06d3f95a4e6c4d24f771cee8db02d342 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 22 Jul 2016 19:38:10 -0700 Subject: Work around ICC bug about C++11 noexcept inheritance qquickitemanimation.cpp(213): error #809: exception specification for virtual function "QQuickParentAnimationData::~QQuickParentAnimationData" is incompatible with that of overridden function "QAbstractAnimationAction::~QAbstractAnimationAction" Change-Id: I149e0540c00745fe8119fffd1463cb59e590b6b8 Reviewed-by: Simon Hausmann --- src/quick/items/qquickitemanimation.cpp | 42 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/quick/items/qquickitemanimation.cpp b/src/quick/items/qquickitemanimation.cpp index 9d140b3156..6b48ca5bf9 100644 --- a/src/quick/items/qquickitemanimation.cpp +++ b/src/quick/items/qquickitemanimation.cpp @@ -194,6 +194,27 @@ QPointF QQuickParentAnimationPrivate::computeTransformOrigin(QQuickItem::Transfo } } +struct QQuickParentAnimationData : public QAbstractAnimationAction +{ + QQuickParentAnimationData() : reverse(false) {} + ~QQuickParentAnimationData() { qDeleteAll(pc); } + + QQuickStateActions actions; + //### reverse should probably apply on a per-action basis + bool reverse; + QList pc; + void doAction() Q_DECL_OVERRIDE + { + for (int ii = 0; ii < actions.count(); ++ii) { + const QQuickStateAction &action = actions.at(ii); + if (reverse) + action.event->reverse(); + else + action.event->execute(); + } + } +}; + QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &actions, QQmlProperties &modified, TransitionDirection direction, @@ -201,27 +222,6 @@ QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &act { Q_D(QQuickParentAnimation); - struct QQuickParentAnimationData : public QAbstractAnimationAction - { - QQuickParentAnimationData() : reverse(false) {} - ~QQuickParentAnimationData() { qDeleteAll(pc); } - - QQuickStateActions actions; - //### reverse should probably apply on a per-action basis - bool reverse; - QList pc; - void doAction() Q_DECL_OVERRIDE - { - for (int ii = 0; ii < actions.count(); ++ii) { - const QQuickStateAction &action = actions.at(ii); - if (reverse) - action.event->reverse(); - else - action.event->execute(); - } - } - }; - QQuickParentAnimationData *data = new QQuickParentAnimationData; QQuickParentAnimationData *viaData = new QQuickParentAnimationData; -- cgit v1.2.3 From f32d0f724ff2010bfb69f8b1772a62b5a2141823 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 22 Jul 2016 21:06:32 -0700 Subject: Fix build on macOS with ICC: -sectcreate is a linker option Apparently Clang understands it and passes to the linker. ICC doesn't, so we have to use the -Wl option. Change-Id: Ibad13c8c3c8d7596aca965c4f6e96c1e82b3cef5 Reviewed-by: Jake Petroules --- tools/qmlplugindump/qmlplugindump.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qmlplugindump/qmlplugindump.pro b/tools/qmlplugindump/qmlplugindump.pro index e45a7fad83..b38eea2554 100644 --- a/tools/qmlplugindump/qmlplugindump.pro +++ b/tools/qmlplugindump/qmlplugindump.pro @@ -17,7 +17,7 @@ macx { # Prevent qmlplugindump from popping up in the dock when launched. # We embed the Info.plist file, so the application doesn't need to # be a bundle. - QMAKE_LFLAGS += -sectcreate __TEXT __info_plist $$shell_quote($$PWD/Info.plist) + QMAKE_LFLAGS += -Wl,-sectcreate,__TEXT,__info_plist,$$shell_quote($$PWD/Info.plist) CONFIG -= app_bundle } -- cgit v1.2.3 From 16b680b734101db0cb4fa3f313ac563a509ddff4 Mon Sep 17 00:00:00 2001 From: Thomas McGuire Date: Mon, 25 Jul 2016 13:23:34 +0200 Subject: QQmlPropertyMap: Don't spuriously emit valueChanged() signal The valueChanged() signal was emitted when the property was written with the same value. This increased the potential for binding loops in user code. Change-Id: Ifeb8f6f23e2022aa35cb6cac7cf1a3dbc0e8ca2f Task-number: QTBUG-48136 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlopenmetaobject.cpp | 2 +- .../qml/qqmlpropertymap/tst_qqmlpropertymap.cpp | 35 ++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp index 9188ba6174..0e60cae92f 100644 --- a/src/qml/qml/qqmlopenmetaobject.cpp +++ b/src/qml/qml/qqmlopenmetaobject.cpp @@ -272,7 +272,7 @@ int QQmlOpenMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void * propertyRead(propId); *reinterpret_cast(a[0]) = d->getData(propId); } else if (c == QMetaObject::WriteProperty) { - if (propId <= d->data.count() || d->data[propId].first != *reinterpret_cast(a[0])) { + if (propId >= d->data.count() || d->data[propId].first != *reinterpret_cast(a[0])) { propertyWrite(propId); QPair &prop = d->getDataRef(propId); prop.first = propertyWriteValue(propId, *reinterpret_cast(a[0])); diff --git a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp index 2f3754e42d..1649cde4ce 100644 --- a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp +++ b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp @@ -65,6 +65,7 @@ private slots: void QTBUG_35233(); void disallowExtending(); void QTBUG_35906(); + void QTBUG_48136(); }; class LazyPropertyMap : public QQmlPropertyMap, public QQmlParserStatus @@ -467,6 +468,40 @@ void tst_QQmlPropertyMap::QTBUG_35906() QCOMPARE(value.toInt(), 42); } +void tst_QQmlPropertyMap::QTBUG_48136() +{ + static const char key[] = "mykey"; + QQmlPropertyMap map; + + // + // Test that the notify signal is emitted correctly + // + + const int propIndex = map.metaObject()->indexOfProperty(key); + const QMetaProperty prop = map.metaObject()->property(propIndex); + QSignalSpy notifySpy(&map, QByteArray::number(QSIGNAL_CODE) + prop.notifySignal().methodSignature()); + + map.insert(key, 42); + QCOMPARE(notifySpy.count(), 1); + map.insert(key, 43); + QCOMPARE(notifySpy.count(), 2); + map.insert(key, 43); + QCOMPARE(notifySpy.count(), 2); + map.insert(key, 44); + QCOMPARE(notifySpy.count(), 3); + + // + // Test that the valueChanged signal is emitted correctly + // + QSignalSpy valueChangedSpy(&map, &QQmlPropertyMap::valueChanged); + map.setProperty(key, 44); + QCOMPARE(valueChangedSpy.count(), 0); + map.setProperty(key, 45); + QCOMPARE(valueChangedSpy.count(), 1); + map.setProperty(key, 45); + QCOMPARE(valueChangedSpy.count(), 1); +} + QTEST_MAIN(tst_QQmlPropertyMap) #include "tst_qqmlpropertymap.moc" -- cgit v1.2.3 From 1c5737d3cb0502f551f7108feda517b153572954 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 26 Jul 2016 09:43:49 +0200 Subject: Mention Q_FLAG in C++ <=> QML type conversion documentation For a user visiting doc.qt.io/qt-5/qtqml-cppintegration-data.html, it's very difficult to know how to use an enum as flags in QML, because it's not mentioned anywhere on this page. Change-Id: I35065bff825b8aebab1477ec883d17cbab92b3ba Reviewed-by: Frederik Gladhorn --- src/qml/doc/src/cppintegration/data.qdoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc index e153ca3d8b..ff30bffa83 100644 --- a/src/qml/doc/src/cppintegration/data.qdoc +++ b/src/qml/doc/src/cppintegration/data.qdoc @@ -375,6 +375,8 @@ Message { } \endqml +To use an enum as a \l {QFlags}{flags} type in QML, see \l Q_FLAG(). + \note The names of enum values must begin with a capital letter in order to be accessible from QML. -- cgit v1.2.3 From a05f59388e004160899d5d311884cfabe10c3b8c Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Fri, 1 Jul 2016 16:32:20 +0200 Subject: Fix documentation of Component.createObject The parent argument should really be any QObject, not just Items. Change-Id: I4d105722b9d76585dd353eddf464a1ec39fea75e Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlcomponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 24abf52e38..9d56ea50de 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1145,7 +1145,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent) } /*! - \qmlmethod object Component::createObject(Item parent, object properties) + \qmlmethod object Component::createObject(QtObject parent, object properties) Creates and returns an object instance of this component that will have the given \a parent and \a properties. The \a properties argument is optional. -- cgit v1.2.3 From d4a1b34e335d124ac044a37c43e68565eebf7efc Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 27 Jul 2016 14:39:43 -0700 Subject: tst_qmlproperty: Fix access of dangling pointer const char *name = propertyName.toLatin1().constData(); big no-no... valgrind was quite angry: ==49215== Invalid read of size 1 ==49215== at 0x4C304F2: strlen (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==49215== by 0x5E991C5: QMetaObject::indexOfProperty(char const*) const (qmetaobject.cpp:1007) ==49215== by 0x5ED1273: QObject::property(char const*) const (qobject.cpp:3912) ==49215== by 0x42AAA5: tst_qqmlproperty::floatToStringPrecision() (tst_qqmlproperty.cpp:2082) ==49215== by 0x42BB37: tst_qqmlproperty::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) (tst_qqmlproperty.moc:533) ==49215== by 0x5E9B32D: QMetaMethod::invoke(QObject*, Qt::ConnectionType, QGenericReturnArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument) const (qmetaobject.cpp:2237) ==49215== by 0x40434FB: QMetaMethod::invoke(QObject*, Qt::ConnectionType, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument) const (qmetaobject.h:123) ==49215== by 0x403C39C: QTest::TestMethods::invokeTestOnData(int) const (qtestcase.cpp:838) ==49215== by 0x403CE98: QTest::TestMethods::invokeTest(int, char const*, QTest::WatchDog*) const (qtestcase.cpp:1019) ==49215== by 0x403DF45: QTest::TestMethods::invokeTests(QObject*) const (qtestcase.cpp:1321) ==49215== by 0x403EA9F: QTest::qExec(QObject*, int, char**) (qtestcase.cpp:1733) ==49215== by 0x42B219: main (tst_qqmlproperty.cpp:2104) ==49215== Address 0x155bb3d0 is 16 bytes inside a block of size 18 free'd ==49215== at 0x4C2E38B: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==49215== by 0x5C3F9FC: QArrayData::deallocate(QArrayData*, unsigned long, unsigned long) (qarraydata.cpp:215) ==49215== by 0x42F2CB: QTypedArrayData::deallocate(QArrayData*) (qarraydata.h:459) ==49215== by 0x42CC7A: QByteArray::~QByteArray() (in /home/tjmaciei/obj/qt/qt5/qtdeclarative/tests/auto/qml/qqmlproperty/tst_qqmlproperty) ==49215== by 0x42AA8B: tst_qqmlproperty::floatToStringPrecision() (tst_qqmlproperty.cpp:2081) ==49215== by 0x42BB37: tst_qqmlproperty::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) (tst_qqmlproperty.moc:533) ==49215== by 0x5E9B32D: QMetaMethod::invoke(QObject*, Qt::ConnectionType, QGenericReturnArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument) const (qmetaobject.cpp:2237) ==49215== by 0x40434FB: QMetaMethod::invoke(QObject*, Qt::ConnectionType, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument) const (qmetaobject.h:123) ==49215== by 0x403C39C: QTest::TestMethods::invokeTestOnData(int) const (qtestcase.cpp:838) ==49215== by 0x403CE98: QTest::TestMethods::invokeTest(int, char const*, QTest::WatchDog*) const (qtestcase.cpp:1019) ==49215== by 0x403DF45: QTest::TestMethods::invokeTests(QObject*) const (qtestcase.cpp:1321) ==49215== by 0x403EA9F: QTest::qExec(QObject*, int, char**) (qtestcase.cpp:1733) ==49215== Block was alloc'd at ==49215== at 0x4C2D12F: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==49215== by 0x5C3F4DE: allocateData(unsigned long, unsigned int) (qarraydata.cpp:107) ==49215== by 0x5C3F6DE: QArrayData::allocate(QArrayData**, unsigned long, unsigned long, unsigned long, QFlags) (qarraydata.cpp:155) ==49215== by 0x5C47BED: QTypedArrayData::allocate(unsigned long, QFlags) (qarraydata.h:436) ==49215== by 0x5C42123: QByteArray::QByteArray(int, Qt::Initialization) (qbytearray.cpp:1627) ==49215== by 0x5D15F95: QString::toLatin1_helper(QChar const*, int) (qstring.cpp:4635) ==49215== by 0x5D15F5F: QString::toLatin1_helper(QString const&) (qstring.cpp:4630) ==49215== by 0x42D076: QString::toLatin1() const & (qstring.h:521) ==49215== by 0x42AA69: tst_qqmlproperty::floatToStringPrecision() (tst_qqmlproperty.cpp:2081) ==49215== by 0x42BB37: tst_qqmlproperty::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) (tst_qqmlproperty.moc:533) ==49215== by 0x5E9B32D: QMetaMethod::invoke(QObject*, Qt::ConnectionType, QGenericReturnArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument) const (qmetaobject.cpp:2237) ==49215== by 0x40434FB: QMetaMethod::invoke(QObject*, Qt::ConnectionType, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument) const (qmetaobject.h:123) Change-Id: I0031aa609e714ae983c3fffd146543f79048468f Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 5a8f2747a9..e140747881 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -2078,15 +2078,15 @@ void tst_qqmlproperty::floatToStringPrecision() QFETCH(QString, qtString); QFETCH(QString, jsString); - const char *name = propertyName.toLatin1().constData(); + QByteArray name = propertyName.toLatin1(); QCOMPARE(obj->property(name).toDouble(), number); QCOMPARE(obj->property(name).toString(), qtString); - const char *name1 = (propertyName + QLatin1Char('1')).toLatin1().constData(); + QByteArray name1 = (propertyName + QLatin1Char('1')).toLatin1(); QCOMPARE(obj->property(name1).toDouble(), number); QCOMPARE(obj->property(name1).toString(), qtString); - const char *name2 = (propertyName + QLatin1Char('2')).toLatin1().constData(); + QByteArray name2 = (propertyName + QLatin1Char('2')).toLatin1(); QCOMPARE(obj->property(name2).toDouble(), number); QCOMPARE(obj->property(name2).toString(), jsString); -- cgit v1.2.3 From cc5ead1b3c8ce79c240b70bdfcfb687fe60e50f5 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 28 Jul 2016 13:50:41 +0200 Subject: Bump version Change-Id: I9857609a360664d1f88b4e6594a9adcd8a995e06 --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index 40e57878b5..45d16f2971 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,4 +1,4 @@ load(qt_build_config) CONFIG += warning_clean -MODULE_VERSION = 5.7.0 +MODULE_VERSION = 5.7.1 -- cgit v1.2.3 From 3c9a70eec93ad3155708686b4aa8493599341a6b Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 28 Jul 2016 12:50:38 +0200 Subject: MSVC: Make Lancelot's scenegrabber compile The extern declaration needs Q_CORE_EXPORT (which resolves to an import declaration on MSVC). Also, the type of the qt_qhash_seed variable is a QBasicAtomicInt, not int, so with proper signature mangling it would not resolve (since memory layout is the same for an int and a QBasicAtomicInt, it would just work for linkers that did not detect it.) Change-Id: I92375afcfc13e045e78a4d6cfdd539bd01b66136 Reviewed-by: Eirik Aavitsland --- tests/manual/scenegraph_lancelot/scenegrabber/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp b/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp index d8eedd5afb..8231c7ffef 100644 --- a/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp +++ b/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp @@ -139,7 +139,7 @@ private: }; -extern uint qt_qhash_seed; +Q_CORE_EXPORT extern QBasicAtomicInt qt_qhash_seed; int main(int argc, char *argv[]) { -- cgit v1.2.3 From 75d6392d6c5efa6fdd1f63cac6a2438fedb2f2a9 Mon Sep 17 00:00:00 2001 From: Venugopal Shivashankar Date: Tue, 1 Mar 2016 15:31:52 +0100 Subject: Doc: Describe how to implement custom SQL models for QML Change-Id: I31781f32c2f9699f386a326f18cb5cc705582a89 Reviewed-by: Leena Miettinen Reviewed-by: Mitch Curtis --- .../doc/src/concepts/modelviewsdata/cppmodels.qdoc | 105 +++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc index cb281a2d4a..a764402c2f 100644 --- a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc +++ b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc @@ -156,6 +156,111 @@ with list models of QAbstractItemModel type: \li \l DelegateModel::parentModelIndex() returns a QModelIndex which can be assigned to DelegateModel::rootIndex \endlist +\section2 SQL Models + +Qt provides C++ classes that support SQL data models. These classes work +transparently on the underlying SQL data, reducing the need to run SQL +queries for basic SQL operations such as create, insert, or update. +For more details about these classes, see \l{Using the SQL Model Classes}. + +Although the C++ classes provide complete feature sets to operate on SQL +data, they do not provide data access to QML. So you must implement a +C++ custom data model as a subclass of one of these classes, and expose it +to QML either as a type or context property. + +\section3 Read-only Data Model + +The custom model must reimplement the following methods to enable read-only +access to the data from QML: + +\list +\li \l{QAbstractItemModel::}{roleNames}() to expose the role names to the + QML frontend. For example, the following version returns the selected + table's field names as role names: + \code + QHash SqlQueryModel::roleNames() const + { + QHash roles; + // record() returns an empty QSqlRecord + for (int i = 0; i < this->record().count(); i ++) { + roles.insert(Qt::UserRole + i + 1, record().fieldName(i).toUtf8()); + } + return roles; + } + \endcode +\li \l{QSqlQueryModel::}{data}() to expose SQL data to the QML frontend. + For example, the following implementation returns data for the given + model index: + \code + QVariant SqlQueryModel::data(const QModelIndex &index, int role) const + { + QVariant value; + + if (index.isValid()) { + if (role < Qt::UserRole) { + value = QSqlQueryModel::data(index, role); + } else { + int columnIdx = role - Qt::UserRole - 1; + QModelIndex modelIndex = this->index(index.row(), columnIdx); + value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole); + } + } + return value; + } + \endcode +\endlist + +The QSqlQueryModel class is good enough to implement a custom read-only +model that represents data in an SQL database. The +\l{Qt Quick Controls 2 - Chat Tutorial}{chat tutorial} example +demonstrates this very well by implementing a custom model to fetch the +contact details from an SQLite database. + +\section3 Editable Data Model + +Besides the \c roleNames() and \c data(), the editable models must reimplement +the \l{QSqlTableModel::}{setData} method to save changes to existing SQL data. +The following version of the method checks if the given model index is valid +and the \c role is equal to \l Qt::EditRole, before calling the parent class +version: + +\code +bool SqlEditableModel::setData(const QModelIndex &item, const QVariant &value, int role) +{ + if (item.isValid() && role == Qt::EditRole) { + QSqlTableModel::setData(item, value,role); + emit dataChanged(item, item); + return true; + } + return false; + +} +\endcode + +\note It is important to emit the \l{QAbstractItemModel::}{dataChanged}() +signal after saving the changes. + +Unlike the C++ item views such as QListView or QTableView, the \c setData() +method must be explicitly invoked from QML whenever appropriate. For example, +on the \l[QML]{TextField::}{editingFinished}() or \l[QML]{TextField::}{accepted}() +signal of \l[QtQuickControls]{TextField}. Depending on the +\l{QSqlTableModel::}{EditStrategy} used by the model, the changes are either +queued for submission later or submitted immediately. + +You can also insert new data into the model by calling +\l {QSqlTableModel::insertRecord}(). In the following example snippet, +a QSqlRecord is populated with book details and appended to the +model: + +\code + ... + QSqlRecord newRecord = record(); + newRecord.setValue("author", "John Grisham"); + newRecord.setValue("booktitle", "The Litigators"); + insertRecord(rowCount(), newRecord); + ... +\endcode + \section2 Exposing C++ Data Models to QML The above examples use QQmlContext::setContextProperty() to set -- cgit v1.2.3 From fe92db0a0eeed502ef851930b3404b38c4a03f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Fri, 29 Jul 2016 13:32:22 +0100 Subject: Revert "macOS: Use sRGB when doing native font rendering into FBO" This reverts commit 1e18a4f985f6ec4a0191a2e0cc087b13d29b1719. It breaks a QtCanvas3D unit-test and I can't look at it now. Will have another take at this soon. Change-Id: I22acd55443783934596d25cc4c8774bd34609f6b Reviewed-by: Liang Qi --- src/quick/scenegraph/qsgdefaultlayer.cpp | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/src/quick/scenegraph/qsgdefaultlayer.cpp b/src/quick/scenegraph/qsgdefaultlayer.cpp index 99735564ef..fa69f911dd 100644 --- a/src/quick/scenegraph/qsgdefaultlayer.cpp +++ b/src/quick/scenegraph/qsgdefaultlayer.cpp @@ -42,29 +42,6 @@ DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY) #endif DEFINE_BOOL_CONFIG_OPTION(qmlFboFlushBeforeDetach, QML_FBO_FLUSH_BEFORE_DETACH) - - -static QOpenGLFramebufferObject *createFramebuffer(const QSize &size, - QOpenGLFramebufferObjectFormat format) -{ -#ifdef Q_OS_MACOS - QOpenGLContext *context = QOpenGLContext::currentContext(); - if (context->hasExtension("GL_ARB_framebuffer_sRGB") - && context->hasExtension("GL_EXT_texture_sRGB") - && context->hasExtension("GL_EXT_texture_sRGB_decode")) - format.setInternalTextureFormat(GL_SRGB8_ALPHA8_EXT); -#endif - QOpenGLFramebufferObject *fbo = new QOpenGLFramebufferObject(size, format); -#ifdef Q_OS_MACOS - if (format.internalTextureFormat() == GL_SRGB8_ALPHA8_EXT) { - QOpenGLFunctions *funcs = context->functions(); - funcs->glBindTexture(GL_TEXTURE_2D, fbo->texture()); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); - } -#endif - return fbo; -} - namespace { class BindableFbo : public QSGBindable @@ -347,7 +324,7 @@ void QSGDefaultLayer::grab() format.setInternalTextureFormat(m_format); format.setSamples(m_context->openglContext()->format().samples()); - m_secondaryFbo = createFramebuffer(m_size, format); + m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { QOpenGLFramebufferObjectFormat format; @@ -356,14 +333,14 @@ void QSGDefaultLayer::grab() if (m_recursive) { deleteFboLater = true; delete m_secondaryFbo; - m_secondaryFbo = createFramebuffer(m_size, format); + m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { delete m_fbo; delete m_secondaryFbo; - m_fbo = createFramebuffer(m_size, format); + m_fbo = new QOpenGLFramebufferObject(m_size, format); m_secondaryFbo = 0; funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); updateBindOptions(true); @@ -377,7 +354,7 @@ void QSGDefaultLayer::grab() Q_ASSERT(m_fbo); Q_ASSERT(!m_multisampling); - m_secondaryFbo = createFramebuffer(m_size, m_fbo->format()); + m_secondaryFbo = new QOpenGLFramebufferObject(m_size, m_fbo->format()); funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); } -- cgit v1.2.3