From af9f8ffb479e35d131f2ff9bedc7cf46842f93ff Mon Sep 17 00:00:00 2001 From: John Brooks Date: Wed, 26 Oct 2016 13:20:21 -0600 Subject: [PATCH 01/33] Fix crash when trying to allocate in a filled atlas texture Atlas::create returns null when allocating space in the atlas texture fails, including when the texture is full. Manager::create assumed that this function would never fail. Change-Id: I2ed8a1b94640d6a3cc65011e83b88f8bd42ca074 Reviewed-by: Gunnar Sletta --- src/quick/scenegraph/util/qsgatlastexture.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index 1a1f0d37f7..e163191c6e 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -110,8 +110,9 @@ QSGTexture *Manager::create(const QImage &image, bool hasAlphaChannel) if (image.width() < m_atlas_size_limit && image.height() < m_atlas_size_limit) { if (!m_atlas) m_atlas = new Atlas(m_atlas_size); + // t may be null for atlas allocation failure t = m_atlas->create(image); - if (!hasAlphaChannel && t->hasAlphaChannel()) + if (t && !hasAlphaChannel && t->hasAlphaChannel()) t->setHasAlphaChannel(false); } return t; From 1372abd309303b0de61fbb269f6e7f9ad32e1fbd Mon Sep 17 00:00:00 2001 From: Venugopal Shivashankar Date: Fri, 21 Oct 2016 11:21:21 +0200 Subject: [PATCH 02/33] Example: Enable auto scaling on HighDPI screens Task-number: QTBUG-56425 Change-Id: I2246245216fb8cd0d4dc4b15a0687edfc64ccad1 Reviewed-by: J-P Nurmi --- examples/quick/shared/shared.h | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/quick/shared/shared.h b/examples/quick/shared/shared.h index d8fb80b97e..0eed618d9d 100644 --- a/examples/quick/shared/shared.h +++ b/examples/quick/shared/shared.h @@ -44,6 +44,7 @@ #include //Not using QQmlApplicationEngine because many examples don't have a Window{} #define DECLARATIVE_EXAMPLE_MAIN(NAME) int main(int argc, char* argv[]) \ {\ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);\ QGuiApplication app(argc,argv);\ app.setOrganizationName("QtProject");\ app.setOrganizationDomain("qt-project.org");\ From 5861ea797da3ff3ce86e81a35af007648b732efd Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 31 Oct 2016 12:12:41 +0100 Subject: [PATCH 03/33] Doc: replace "textEdit" with "TextEdit" in lineCount documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I24a186af0538027719beb464c2b489825ddd9420 Reviewed-by: Topi Reiniö --- src/quick/items/qquicktextedit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 3ab7f358ff..8cee37782b 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -838,7 +838,7 @@ void QQuickTextEdit::setWrapMode(WrapMode mode) /*! \qmlproperty int QtQuick::TextEdit::lineCount - Returns the total number of lines in the textEdit item. + Returns the total number of lines in the TextEdit item. */ int QQuickTextEdit::lineCount() const { From 64714ea431f2fd355ed27edc69dba4e992511e75 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Fri, 4 Nov 2016 00:11:59 +0100 Subject: [PATCH 04/33] QV4String: properly detect overflow when trying to convert to an array index A wrong overflow detection caused strings like "240000000000" to pass the conversion, even though they would not fit into a uint when converted into base-10. This mis-conversion to uint then caused all sorts of side effects (broken comparisons, wrong listing of properties, and so on). So, properly fix the overflow detection by using our numeric private functions. Change-Id: Icbf67ac68cf5785d6c77b433c7a45aed5285a8c2 Task-number: QTBUG-56830 Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4string.cpp | 12 ++++++++--- src/qmldevtools/qmldevtools.pro | 2 +- tests/auto/qml/qjsvalue/tst_qjsvalue.cpp | 27 ++++++++++++++++++++++++ tests/auto/qml/qjsvalue/tst_qjsvalue.h | 2 ++ 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index 24a13ddd10..da3c783808 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -40,6 +40,7 @@ #include "qv4stringobject_p.h" #endif #include +#include using namespace QV4; @@ -57,10 +58,15 @@ static uint toArrayIndex(const QChar *ch, const QChar *end) uint x = ch->unicode() - '0'; if (x > 9) return UINT_MAX; - uint n = i*10 + x; - if (n < i) - // overflow + + uint n; + // n = i * 10 + x, with overflow checking + if (mul_overflow(i, 10u, &n)) return UINT_MAX; + + if (add_overflow(n, x, &n)) + return UINT_MAX; + i = n; ++ch; } diff --git a/src/qmldevtools/qmldevtools.pro b/src/qmldevtools/qmldevtools.pro index 3f199e5971..42fe53ed60 100644 --- a/src/qmldevtools/qmldevtools.pro +++ b/src/qmldevtools/qmldevtools.pro @@ -1,6 +1,6 @@ option(host_build) TARGET = QtQmlDevTools -QT = core +QT = core core-private CONFIG += static internal_module qmldevtools_build # Don't use pch because the auto-generated header refers to QtBootstrap, diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp index bf9bd18807..b9a9fec6d9 100644 --- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp +++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp @@ -1371,6 +1371,33 @@ void tst_QJSValue::hasProperty_changePrototype() QVERIFY(obj.hasOwnProperty("foo")); } +void tst_QJSValue::hasProperty_QTBUG56830_data() +{ + QTest::addColumn("key"); + QTest::addColumn("lookup"); + + QTest::newRow("bugreport-1") << QStringLiteral("240000000000") << QStringLiteral("3776798720"); + QTest::newRow("bugreport-2") << QStringLiteral("240000000001") << QStringLiteral("3776798721"); + QTest::newRow("biggest-ok-before-bug") << QStringLiteral("238609294221") << QStringLiteral("2386092941"); + QTest::newRow("smallest-bugged") << QStringLiteral("238609294222") << QStringLiteral("2386092942"); + QTest::newRow("biggest-bugged") << QStringLiteral("249108103166") << QStringLiteral("12884901886"); + QTest::newRow("smallest-ok-after-bug") << QStringLiteral("249108103167") << QStringLiteral("12884901887"); +} + +void tst_QJSValue::hasProperty_QTBUG56830() +{ + QFETCH(QString, key); + QFETCH(QString, lookup); + + QJSEngine eng; + const QJSValue value(42); + + QJSValue obj = eng.newObject(); + obj.setProperty(key, value); + QVERIFY(obj.hasProperty(key)); + QVERIFY(!obj.hasProperty(lookup)); +} + void tst_QJSValue::deleteProperty_basic() { QJSEngine eng; diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.h b/tests/auto/qml/qjsvalue/tst_qjsvalue.h index 16667ff344..485577bf97 100644 --- a/tests/auto/qml/qjsvalue/tst_qjsvalue.h +++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.h @@ -97,6 +97,8 @@ private slots: void hasProperty_basic(); void hasProperty_globalObject(); void hasProperty_changePrototype(); + void hasProperty_QTBUG56830_data(); + void hasProperty_QTBUG56830(); void deleteProperty_basic(); void deleteProperty_globalObject(); From 9bfe3324f7fa94e1f272c35bcb943daa2669edba Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 3 Nov 2016 18:14:37 +0100 Subject: [PATCH 05/33] remove dependencies from sync.profile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the CI obtains them from the qt5 super repo nowadays. Change-Id: I1be0b8a494a5f7db02fa82ec46de2ec3573dd485 Reviewed-by: Jędrzej Nowacki --- sync.profile | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/sync.profile b/sync.profile index 28d0698da9..6ca6dde13d 100644 --- a/sync.profile +++ b/sync.profile @@ -11,14 +11,3 @@ ); %deprecatedheaders = ( ); -# Module dependencies. -# Every module that is required to build this module should have one entry. -# Each of the module version specifiers can take one of the following values: -# - A specific Git revision. -# - any git symbolic ref resolvable from the module's repository (e.g. "refs/heads/master" to track master branch) -# - an empty string to use the same branch under test (dependencies will become "refs/heads/master" if we are in the master branch) -# -%dependencies = ( - "qtbase" => "", - "qtxmlpatterns" => "", -); From fe98037e76d95e7634cce3c96878956edd2f61fa Mon Sep 17 00:00:00 2001 From: Jesus Fernandez Date: Fri, 28 Oct 2016 12:12:05 +0200 Subject: [PATCH 06/33] Fix crash when using custom OpenGL functions The code was using the ::glGetString function and this could fail if we are using a custom platform plugin. Change-Id: Idb9ccd178ea52255b9d6f0f6d3fd529094c15292 Reviewed-by: Laszlo Agocs --- src/particles/qquickimageparticle.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp index d78a350306..f3feb91ffa 100644 --- a/src/particles/qquickimageparticle.cpp +++ b/src/particles/qquickimageparticle.cpp @@ -1276,14 +1276,16 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) // OS X 10.8.3 introduced a bug in the AMD drivers, for at least the 2011 macbook pros, // causing point sprites who read gl_PointCoord in the frag shader to come out as // green-red blobs. - if (perfLevel < Deformable && strstr((char *) glGetString(GL_VENDOR), "ATI")) { + const GLubyte *glVendor = QOpenGLContext::currentContext()->functions()->glGetString(GL_VENDOR); + if (perfLevel < Deformable && glVendor && strstr((char *) glVendor, "ATI")) { perfLevel = Deformable; } #endif #ifdef Q_OS_LINUX // Nouveau drivers can potentially freeze a machine entirely when taking the point-sprite path. - if (perfLevel < Deformable && strstr((const char *) glGetString(GL_VENDOR), "nouveau")) + const GLubyte *glVendor = QOpenGLContext::currentContext()->functions()->glGetString(GL_VENDOR); + if (perfLevel < Deformable && glVendor && strstr((const char *) glVendor, "nouveau")) perfLevel = Deformable; #endif From 43d56d164f1fd2a148fd9feb00c4672f7d6489d4 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 2 Nov 2016 13:04:07 +0100 Subject: [PATCH 07/33] Quick: Move counters out of a bitfield in QQuickitem Storing the anchor-loop-detection counters in a bitfield has the disadvantage that the full field has to be read and masked in order to use (increment) them. The same for the subsequent store. By putting them in their own byte, this can be done a lot faster. Those bytes were available, because they were needed for padding. By making them signed, there is also no need for the compiler to insert overflow handling. Change-Id: I3c250983c74de2ecfd33fe72ea8df04e24b8cd0c Reviewed-by: Lars Knoll --- src/quick/items/qquickanchors.cpp | 131 ++++++++++++++-------------- src/quick/items/qquickanchors_p_p.h | 19 ++-- 2 files changed, 77 insertions(+), 73 deletions(-) diff --git a/src/quick/items/qquickanchors.cpp b/src/quick/items/qquickanchors.cpp index b6978e534e..a069f1ece3 100644 --- a/src/quick/items/qquickanchors.cpp +++ b/src/quick/items/qquickanchors.cpp @@ -617,74 +617,75 @@ void QQuickAnchorsPrivate::updateVerticalAnchors() if (fill || centerIn || !isItemComplete()) return; - if (updatingVerticalAnchor < 2) { - ++updatingVerticalAnchor; - if (usedAnchors & QQuickAnchors::TopAnchor) { - //Handle stretching - bool invalid = true; - qreal height = 0.0; - if (usedAnchors & QQuickAnchors::BottomAnchor) { - invalid = calcStretch(topAnchorItem, topAnchorLine, - bottomAnchorItem, bottomAnchorLine, - topMargin, -bottomMargin, QQuickAnchors::TopAnchor, height); - } else if (usedAnchors & QQuickAnchors::VCenterAnchor) { - invalid = calcStretch(topAnchorItem, topAnchorLine, - vCenterAnchorItem, vCenterAnchorLine, - topMargin, vCenterOffset, QQuickAnchors::TopAnchor, height); - height *= 2; - } - if (!invalid) - setItemHeight(height); - - //Handle top - if (topAnchorItem == readParentItem(item)) { - setItemY(adjustedPosition(topAnchorItem, topAnchorLine) + topMargin); - } else if (readParentItem(topAnchorItem) == readParentItem(item)) { - setItemY(position(topAnchorItem, topAnchorLine) + topMargin); - } - } else if (usedAnchors & QQuickAnchors::BottomAnchor) { - //Handle stretching (top + bottom case is handled above) - if (usedAnchors & QQuickAnchors::VCenterAnchor) { - qreal height = 0.0; - bool invalid = calcStretch(vCenterAnchorItem, vCenterAnchorLine, - bottomAnchorItem, bottomAnchorLine, - vCenterOffset, -bottomMargin, QQuickAnchors::TopAnchor, - height); - if (!invalid) - setItemHeight(height*2); - } - - //Handle bottom - if (bottomAnchorItem == readParentItem(item)) { - setItemY(adjustedPosition(bottomAnchorItem, bottomAnchorLine) - readHeight(item) - bottomMargin); - } else if (readParentItem(bottomAnchorItem) == readParentItem(item)) { - setItemY(position(bottomAnchorItem, bottomAnchorLine) - readHeight(item) - bottomMargin); - } - } else if (usedAnchors & QQuickAnchors::VCenterAnchor) { - //(stetching handled above) - - //Handle vCenter - if (vCenterAnchorItem == readParentItem(item)) { - setItemY(adjustedPosition(vCenterAnchorItem, vCenterAnchorLine) - - vcenter(item) + vCenterOffset); - } else if (readParentItem(vCenterAnchorItem) == readParentItem(item)) { - setItemY(position(vCenterAnchorItem, vCenterAnchorLine) - vcenter(item) + vCenterOffset); - } - } else if (usedAnchors & QQuickAnchors::BaselineAnchor) { - //Handle baseline - if (baselineAnchorItem == readParentItem(item)) { - setItemY(adjustedPosition(baselineAnchorItem, baselineAnchorLine) - - readBaselineOffset(item) + baselineOffset); - } else if (readParentItem(baselineAnchorItem) == readParentItem(item)) { - setItemY(position(baselineAnchorItem, baselineAnchorLine) - - readBaselineOffset(item) + baselineOffset); - } - } - --updatingVerticalAnchor; - } else { + if (Q_UNLIKELY(updatingVerticalAnchor > 1)) { // ### Make this certain :) qmlInfo(item) << QQuickAnchors::tr("Possible anchor loop detected on vertical anchor."); + return; } + + ++updatingVerticalAnchor; + if (usedAnchors & QQuickAnchors::TopAnchor) { + //Handle stretching + bool invalid = true; + qreal height = 0.0; + if (usedAnchors & QQuickAnchors::BottomAnchor) { + invalid = calcStretch(topAnchorItem, topAnchorLine, + bottomAnchorItem, bottomAnchorLine, + topMargin, -bottomMargin, QQuickAnchors::TopAnchor, height); + } else if (usedAnchors & QQuickAnchors::VCenterAnchor) { + invalid = calcStretch(topAnchorItem, topAnchorLine, + vCenterAnchorItem, vCenterAnchorLine, + topMargin, vCenterOffset, QQuickAnchors::TopAnchor, height); + height *= 2; + } + if (!invalid) + setItemHeight(height); + + //Handle top + if (topAnchorItem == readParentItem(item)) { + setItemY(adjustedPosition(topAnchorItem, topAnchorLine) + topMargin); + } else if (readParentItem(topAnchorItem) == readParentItem(item)) { + setItemY(position(topAnchorItem, topAnchorLine) + topMargin); + } + } else if (usedAnchors & QQuickAnchors::BottomAnchor) { + //Handle stretching (top + bottom case is handled above) + if (usedAnchors & QQuickAnchors::VCenterAnchor) { + qreal height = 0.0; + bool invalid = calcStretch(vCenterAnchorItem, vCenterAnchorLine, + bottomAnchorItem, bottomAnchorLine, + vCenterOffset, -bottomMargin, QQuickAnchors::TopAnchor, + height); + if (!invalid) + setItemHeight(height*2); + } + + //Handle bottom + if (bottomAnchorItem == readParentItem(item)) { + setItemY(adjustedPosition(bottomAnchorItem, bottomAnchorLine) - readHeight(item) - bottomMargin); + } else if (readParentItem(bottomAnchorItem) == readParentItem(item)) { + setItemY(position(bottomAnchorItem, bottomAnchorLine) - readHeight(item) - bottomMargin); + } + } else if (usedAnchors & QQuickAnchors::VCenterAnchor) { + //(stetching handled above) + + //Handle vCenter + if (vCenterAnchorItem == readParentItem(item)) { + setItemY(adjustedPosition(vCenterAnchorItem, vCenterAnchorLine) + - vcenter(item) + vCenterOffset); + } else if (readParentItem(vCenterAnchorItem) == readParentItem(item)) { + setItemY(position(vCenterAnchorItem, vCenterAnchorLine) - vcenter(item) + vCenterOffset); + } + } else if (usedAnchors & QQuickAnchors::BaselineAnchor) { + //Handle baseline + if (baselineAnchorItem == readParentItem(item)) { + setItemY(adjustedPosition(baselineAnchorItem, baselineAnchorLine) + - readBaselineOffset(item) + baselineOffset); + } else if (readParentItem(baselineAnchorItem) == readParentItem(item)) { + setItemY(position(baselineAnchorItem, baselineAnchorLine) + - readBaselineOffset(item) + baselineOffset); + } + } + --updatingVerticalAnchor; } static inline QQuickAnchors::Anchor reverseAnchorLine(QQuickAnchors::Anchor anchorLine) diff --git a/src/quick/items/qquickanchors_p_p.h b/src/quick/items/qquickanchors_p_p.h index 3357e134bf..0373b1f824 100644 --- a/src/quick/items/qquickanchors_p_p.h +++ b/src/quick/items/qquickanchors_p_p.h @@ -113,12 +113,12 @@ public: , inDestructor(false) , baselineAnchorLine(QQuickAnchors::InvalidAnchor) , centerAligned(true) + , usedAnchors(QQuickAnchors::InvalidAnchor) + , componentComplete(true) , updatingFill(0) , updatingCenterIn(0) , updatingHorizontalAnchor(0) , updatingVerticalAnchor(0) - , componentComplete(true) - , usedAnchors(QQuickAnchors::InvalidAnchor) { } @@ -198,13 +198,16 @@ public: uint inDestructor : 1; QQuickAnchors::Anchor baselineAnchorLine : 7; uint centerAligned : 1; - uint updatingFill : 2; - uint updatingCenterIn : 2; - uint updatingHorizontalAnchor : 2; - uint updatingVerticalAnchor : 2; - - uint componentComplete : 1; uint usedAnchors : 7; // QQuickAnchors::Anchors + uint componentComplete : 1; + + // Instead of using a mostly empty bit field, we can stretch the following fields up to be full + // bytes. The advantage is that incrementing/decrementing does not need any combining ands/ors. + qint8 updatingFill; + qint8 updatingCenterIn; + qint8 updatingHorizontalAnchor; + qint8 updatingVerticalAnchor; + static inline QQuickAnchorsPrivate *get(QQuickAnchors *o) { return static_cast(QObjectPrivate::get(o)); From 0dd7b69d11d4b445017fbd6fefde806bbff4f6d3 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 3 Nov 2016 14:13:45 +0100 Subject: [PATCH 08/33] Quick: Only take a copy of changeListeners when there are some In the case where there are no change listeners, there is no need to do an ref() operation (which involves atomic loads) only to find out that it's an empty vector (!isSharable). Better still: the whole loop start-up can be skipped. Change-Id: I94fd22029a321a5dbef571145007071a54f5b04b Reviewed-by: Simon Hausmann --- src/quick/items/qquickitem.cpp | 152 +++++++++++++++++++-------------- 1 file changed, 88 insertions(+), 64 deletions(-) diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index efb7d46efa..9e86247162 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2308,29 +2308,31 @@ QQuickItem::~QQuickItem() while (!d->childItems.isEmpty()) d->childItems.constFirst()->setParentItem(0); - const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732) - for (const QQuickItemPrivate::ChangeListener &change : listeners) { - QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate(); - if (anchor) - anchor->clearItem(this); - } + if (!d->changeListeners.isEmpty()) { + const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732) + for (const QQuickItemPrivate::ChangeListener &change : listeners) { + QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate(); + if (anchor) + anchor->clearItem(this); + } - /* + /* update item anchors that depended on us unless they are our child (and will also be destroyed), or our sibling, and our parent is also being destroyed. */ - for (const QQuickItemPrivate::ChangeListener &change : listeners) { - QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate(); - if (anchor && anchor->item && anchor->item->parentItem() && anchor->item->parentItem() != this) - anchor->update(); - } + for (const QQuickItemPrivate::ChangeListener &change : listeners) { + QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate(); + if (anchor && anchor->item && anchor->item->parentItem() && anchor->item->parentItem() != this) + anchor->update(); + } - for (const QQuickItemPrivate::ChangeListener &change : listeners) { - if (change.types & QQuickItemPrivate::Destroyed) - change.listener->itemDestroyed(this); - } + for (const QQuickItemPrivate::ChangeListener &change : listeners) { + if (change.types & QQuickItemPrivate::Destroyed) + change.listener->itemDestroyed(this); + } - d->changeListeners.clear(); + d->changeListeners.clear(); + } /* Remove any references our transforms have to us, in case they try to @@ -3549,10 +3551,12 @@ QQuickAnchors *QQuickItemPrivate::anchors() const void QQuickItemPrivate::siblingOrderChanged() { Q_Q(QQuickItem); - const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) - for (const QQuickItemPrivate::ChangeListener &change : listeners) { - if (change.types & QQuickItemPrivate::SiblingOrder) { - change.listener->itemSiblingOrderChanged(q); + if (!changeListeners.isEmpty()) { + const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) + for (const QQuickItemPrivate::ChangeListener &change : listeners) { + if (change.types & QQuickItemPrivate::SiblingOrder) { + change.listener->itemSiblingOrderChanged(q); + } } } } @@ -3663,11 +3667,13 @@ void QQuickItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo change.setWidthChange(diff.width() != 0); change.setHeightChange(diff.height() != 0); - const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732) - for (const QQuickItemPrivate::ChangeListener &listener : listeners) { - if (listener.types & QQuickItemPrivate::Geometry) { - if (change.matches(listener.gTypes)) - listener.listener->itemGeometryChanged(this, change, diff); + if (!d->changeListeners.isEmpty()) { + const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732) + for (const QQuickItemPrivate::ChangeListener &listener : listeners) { + if (listener.types & QQuickItemPrivate::Geometry) { + if (change.matches(listener.gTypes)) + listener.listener->itemGeometryChanged(this, change, diff); + } } } @@ -4224,12 +4230,14 @@ void QQuickItem::setBaselineOffset(qreal offset) d->baselineOffset = offset; - const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732) - for (const QQuickItemPrivate::ChangeListener &change : listeners) { - if (change.types & QQuickItemPrivate::Geometry) { - QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate(); - if (anchor) - anchor->updateVerticalAnchors(); + if (!d->changeListeners.isEmpty()) { + const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732) + for (const QQuickItemPrivate::ChangeListener &change : listeners) { + if (change.types & QQuickItemPrivate::Geometry) { + QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate(); + if (anchor) + anchor->updateVerticalAnchors(); + } } } @@ -5977,20 +5985,24 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt switch (change) { case QQuickItem::ItemChildAddedChange: { q->itemChange(change, data); - const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) - for (const QQuickItemPrivate::ChangeListener &change : listeners) { - if (change.types & QQuickItemPrivate::Children) { - change.listener->itemChildAdded(q, data.item); + if (!changeListeners.isEmpty()) { + const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) + for (const QQuickItemPrivate::ChangeListener &change : listeners) { + if (change.types & QQuickItemPrivate::Children) { + change.listener->itemChildAdded(q, data.item); + } } } break; } case QQuickItem::ItemChildRemovedChange: { q->itemChange(change, data); - const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) - for (const QQuickItemPrivate::ChangeListener &change : listeners) { - if (change.types & QQuickItemPrivate::Children) { - change.listener->itemChildRemoved(q, data.item); + if (!changeListeners.isEmpty()) { + const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) + for (const QQuickItemPrivate::ChangeListener &change : listeners) { + if (change.types & QQuickItemPrivate::Children) { + change.listener->itemChildRemoved(q, data.item); + } } } break; @@ -6000,30 +6012,36 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt break; case QQuickItem::ItemVisibleHasChanged: { q->itemChange(change, data); - const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) - for (const QQuickItemPrivate::ChangeListener &change : listeners) { - if (change.types & QQuickItemPrivate::Visibility) { - change.listener->itemVisibilityChanged(q); + if (!changeListeners.isEmpty()) { + const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) + for (const QQuickItemPrivate::ChangeListener &change : listeners) { + if (change.types & QQuickItemPrivate::Visibility) { + change.listener->itemVisibilityChanged(q); + } } } break; } case QQuickItem::ItemParentHasChanged: { q->itemChange(change, data); - const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) - for (const QQuickItemPrivate::ChangeListener &change : listeners) { - if (change.types & QQuickItemPrivate::Parent) { - change.listener->itemParentChanged(q, data.item); + if (!changeListeners.isEmpty()) { + const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) + for (const QQuickItemPrivate::ChangeListener &change : listeners) { + if (change.types & QQuickItemPrivate::Parent) { + change.listener->itemParentChanged(q, data.item); + } } } break; } case QQuickItem::ItemOpacityHasChanged: { q->itemChange(change, data); - const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) - for (const QQuickItemPrivate::ChangeListener &change : listeners) { - if (change.types & QQuickItemPrivate::Opacity) { - change.listener->itemOpacityChanged(q); + if (!changeListeners.isEmpty()) { + const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) + for (const QQuickItemPrivate::ChangeListener &change : listeners) { + if (change.types & QQuickItemPrivate::Opacity) { + change.listener->itemOpacityChanged(q); + } } } break; @@ -6033,10 +6051,12 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt break; case QQuickItem::ItemRotationHasChanged: { q->itemChange(change, data); - const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) - for (const QQuickItemPrivate::ChangeListener &change : listeners) { - if (change.types & QQuickItemPrivate::Rotation) { - change.listener->itemRotationChanged(q); + if (!changeListeners.isEmpty()) { + const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) + for (const QQuickItemPrivate::ChangeListener &change : listeners) { + if (change.types & QQuickItemPrivate::Rotation) { + change.listener->itemRotationChanged(q); + } } } break; @@ -6395,10 +6415,12 @@ void QQuickItem::resetWidth() void QQuickItemPrivate::implicitWidthChanged() { Q_Q(QQuickItem); - const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) - for (const QQuickItemPrivate::ChangeListener &change : listeners) { - if (change.types & QQuickItemPrivate::ImplicitWidth) { - change.listener->itemImplicitWidthChanged(q); + if (!changeListeners.isEmpty()) { + const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) + for (const QQuickItemPrivate::ChangeListener &change : listeners) { + if (change.types & QQuickItemPrivate::ImplicitWidth) { + change.listener->itemImplicitWidthChanged(q); + } } } emit q->implicitWidthChanged(); @@ -6559,10 +6581,12 @@ void QQuickItem::resetHeight() void QQuickItemPrivate::implicitHeightChanged() { Q_Q(QQuickItem); - const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) - for (const QQuickItemPrivate::ChangeListener &change : listeners) { - if (change.types & QQuickItemPrivate::ImplicitHeight) { - change.listener->itemImplicitHeightChanged(q); + if (!changeListeners.isEmpty()) { + const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732) + for (const QQuickItemPrivate::ChangeListener &change : listeners) { + if (change.types & QQuickItemPrivate::ImplicitHeight) { + change.listener->itemImplicitHeightChanged(q); + } } } emit q->implicitHeightChanged(); From 9f4bb9a687277932125a065a53e3f3d8afdebc8b Mon Sep 17 00:00:00 2001 From: Inhye Seo Date: Fri, 21 Oct 2016 17:31:18 +0900 Subject: [PATCH 09/33] Add checking "before" as child node qquickitem_before_paintNode returns the transform node for the rectangle as child node. But the node has no parent. It leads to following assertion case at QSGNode::insertChildNodeAfter(). But, I tested it in release mode, so no assertion happened. So, Some node not be able to add group node from this cause. Task-number: QTBUG-56657 Change-Id: Ie032dc6c56984bcb58cfcd348ff532f56e39e5b8 Reviewed-by: Inhye Seo Reviewed-by: Gunnar Sletta --- src/quick/items/qquickwindow.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 7875005e2d..e19570ea03 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -3067,10 +3067,12 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item) if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) { QSGNode *before = qquickitem_before_paintNode(itemPriv); - if (before) + if (before && before->parent()) { + Q_ASSERT(before->parent() == itemPriv->childContainerNode()); itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, before); - else + } else { itemPriv->childContainerNode()->prependChildNode(itemPriv->paintNode); + } } } else if (itemPriv->paintNode) { delete itemPriv->paintNode; From 2afee1c3f13a8dde2ad6d12e62c291e44fff262b Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 9 Nov 2016 08:26:53 +0100 Subject: [PATCH 10/33] qv4object_p.h: Replace QtPrivate::is_same by std::is_same Task-number: QTBUG-57007 Change-Id: I05cabe53e7993cd63498334e95917fe6c3077ab6 Reviewed-by: Kai Koehne --- src/qml/jsruntime/qv4object_p.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index d5195adaf0..00a004ef5f 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -58,8 +58,6 @@ #include "qv4value_p.h" #include "qv4internalclass_p.h" -#include - QT_BEGIN_NAMESPACE @@ -147,7 +145,7 @@ struct ObjectVTable #define DEFINE_OBJECT_VTABLE_BASE(classname) \ const QV4::ObjectVTable classname::static_vtbl = \ { \ - DEFINE_MANAGED_VTABLE_INT(classname, (QT_PREPEND_NAMESPACE(QtPrivate)::is_same::value) ? Q_NULLPTR : &classname::SuperClass::static_vtbl.vTable), \ + DEFINE_MANAGED_VTABLE_INT(classname, (std::is_same::value) ? nullptr : &classname::SuperClass::static_vtbl.vTable), \ call, \ construct, \ get, \ From ece0682712ec23b2a7fed68893db71a2cc0370a7 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 3 Nov 2016 14:31:19 +0100 Subject: [PATCH 11/33] Quick: Hint that a reparent action will most probably work fine When assigning an item a new parent item, a check is done if it is already part of the children tree below that parent. This is an unlikely case, so hint the compiler that it can optimize the loop that way. Change-Id: Ic9f1810aa4b83d84be88f0049e61d21c4add7767 Reviewed-by: Simon Hausmann --- src/quick/items/qquickitem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 9e86247162..1e60ef8c02 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2603,7 +2603,7 @@ void QQuickItem::setParentItem(QQuickItem *parentItem) if (parentItem) { QQuickItem *itemAncestor = parentItem; while (itemAncestor != 0) { - if (itemAncestor == this) { + if (Q_UNLIKELY(itemAncestor == this)) { qWarning() << "QQuickItem::setParentItem: Parent" << parentItem << "is already part of the subtree of" << this; return; } From 05e3cdd8ab57686407d472722ab2e724c01de6b7 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 8 Nov 2016 13:09:54 +0100 Subject: [PATCH 12/33] Set Qt version on tools Change-Id: I21d77b2eba7107528fc00db0cf5d87f8347b63be Reviewed-by: Erik Verbruggen --- tools/qml/main.cpp | 1 + tools/qmleasing/main.cpp | 1 + tools/qmlimportscanner/main.cpp | 1 + tools/qmljs/qmljs.cpp | 1 + tools/qmlmin/main.cpp | 1 + tools/qmlplugindump/main.cpp | 1 + tools/qmlscene/main.cpp | 1 + tools/qmltime/qmltime.cpp | 1 + 8 files changed, 8 insertions(+) diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp index be62500858..071908e78e 100644 --- a/tools/qml/main.cpp +++ b/tools/qml/main.cpp @@ -453,6 +453,7 @@ int main(int argc, char *argv[]) app->setApplicationName("Qml Runtime"); app->setOrganizationName("QtProject"); app->setOrganizationDomain("qt-project.org"); + QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR)); qmlRegisterType("QmlRuntime.Config", 1, 0, "Configuration"); qmlRegisterType("QmlRuntime.Config", 1, 0, "PartialScene"); diff --git a/tools/qmleasing/main.cpp b/tools/qmleasing/main.cpp index ab137d5eb4..389503507e 100644 --- a/tools/qmleasing/main.cpp +++ b/tools/qmleasing/main.cpp @@ -33,6 +33,7 @@ int main(int argc, char ** argv) { QApplication app(argc, argv); + QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR)); MainWindow mainWindow; mainWindow.show(); diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp index f7f5a5e4e4..f069c1883f 100644 --- a/tools/qmlimportscanner/main.cpp +++ b/tools/qmlimportscanner/main.cpp @@ -483,6 +483,7 @@ QVariantList findQmlImportsRecursively(const QStringList &qmlDirs, const QString int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); + QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR)); QStringList args = app.arguments(); const QString appName = QFileInfo(app.applicationFilePath()).baseName(); if (args.size() < 2) { diff --git a/tools/qmljs/qmljs.cpp b/tools/qmljs/qmljs.cpp index 4b63357363..b0079dcf49 100644 --- a/tools/qmljs/qmljs.cpp +++ b/tools/qmljs/qmljs.cpp @@ -135,6 +135,7 @@ static void showException(QV4::ExecutionContext *ctx, const QV4::Value &exceptio int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); + QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR)); QStringList args = app.arguments(); args.removeFirst(); diff --git a/tools/qmlmin/main.cpp b/tools/qmlmin/main.cpp index d2bad9d0d5..6877ca7442 100644 --- a/tools/qmlmin/main.cpp +++ b/tools/qmlmin/main.cpp @@ -533,6 +533,7 @@ static void usage(bool showHelp = false) int runQmlmin(int argc, char *argv[]) { QCoreApplication app(argc, argv); + QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR)); const QStringList args = app.arguments(); diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp index ea54fee885..cfd14aff6d 100644 --- a/tools/qmlplugindump/main.cpp +++ b/tools/qmlplugindump/main.cpp @@ -983,6 +983,7 @@ int main(int argc, char *argv[]) QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true); QGuiApplication app(argc, argv); + QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR)); const QStringList args = app.arguments(); const QString appName = QFileInfo(app.applicationFilePath()).baseName(); if (args.size() < 2) { diff --git a/tools/qmlscene/main.cpp b/tools/qmlscene/main.cpp index 9e1002166d..db0af1d071 100644 --- a/tools/qmlscene/main.cpp +++ b/tools/qmlscene/main.cpp @@ -467,6 +467,7 @@ int main(int argc, char ** argv) app.setApplicationName("QtQmlViewer"); app.setOrganizationName("QtProject"); app.setOrganizationDomain("qt-project.org"); + QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR)); const QStringList arguments = QCoreApplication::arguments(); for (int i = 1, size = arguments.size(); i < size; ++i) { diff --git a/tools/qmltime/qmltime.cpp b/tools/qmltime/qmltime.cpp index 8afaebc413..4c282dd8f4 100644 --- a/tools/qmltime/qmltime.cpp +++ b/tools/qmltime/qmltime.cpp @@ -205,6 +205,7 @@ void usage(const char *name) int main(int argc, char ** argv) { QGuiApplication app(argc, argv); + QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR)); qmlRegisterType("QmlTime", 1, 0, "Timer"); From 94acdbfbdf8eef9e22d50d307be32cc3e21b9081 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 9 Nov 2016 10:49:24 +0100 Subject: [PATCH 13/33] V4: Replace memset by a for loop GCC would often generate a call to a special "safe" version of memset, which would in turn prevent inlining in many cases. A simple for loop does not prevent inlining, and compilers can still decide to replace it with a memset. It also makes it easier for the compiler to do dead store elimination. Change-Id: I60fa3e321c2edb9225699bf57e8a31a3f8356ddc Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4engine_p.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 843a6f4d94..a46066bde4 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -131,7 +131,8 @@ public: Value *jsAlloca(int nValues) { Value *ptr = jsStackTop; jsStackTop = ptr + nValues; - memset(ptr, 0, nValues*sizeof(Value)); + for (int i = 0; i < nValues; ++i) + ptr[i] = Primitive::undefinedValue(); return ptr; } From cc86bf1a231ad5ec67495af701b5b6b58fc61815 Mon Sep 17 00:00:00 2001 From: Marco Benelli Date: Fri, 4 Nov 2016 11:04:54 +0100 Subject: [PATCH 14/33] Update Window plugins.qmltypes Some signals (ie onClosing) as marked as error by QtCreator because they are registered with version 1 or 2, while QQuick is exported only as version 0. Exporting version 1 or 2 of QQuickWindow seems to cause some conflicts with QQuickWindowImpl. So the plugins.qmltypes has been manually updated. Task-number: QTBUG-47917 Change-Id: I2ddacfbf0564d8ecfbaadc0323011dbd18439c36 Reviewed-by: Erik Verbruggen --- src/imports/window/plugins.qmltypes | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/imports/window/plugins.qmltypes b/src/imports/window/plugins.qmltypes index 6a8dbfa024..a79bd8c332 100644 --- a/src/imports/window/plugins.qmltypes +++ b/src/imports/window/plugins.qmltypes @@ -55,8 +55,12 @@ Module { name: "QQuickWindow" defaultProperty: "data" prototype: "QWindow" - exports: ["QtQuick.Window/Window 2.0"] - exportMetaObjectRevisions: [0] + exports: [ + "QtQuick.Window/Window 2.0", + "QtQuick.Window/Window 2.1", + "QtQuick.Window/Window 2.2" + ] + exportMetaObjectRevisions: [0, 1, 2] Enum { name: "SceneGraphError" values: { From f4ac007f4a19bc095ff15d415a6629986de78e49 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 9 Nov 2016 16:06:56 +0100 Subject: [PATCH 15/33] Fix more cases where DSE would optimize out too many stores GCC5/6 do aggressive dead store elimination on memory passed to placement-new. This resulted in the Heap::Object::prototype being a nullptr. qml.pro already contained the -fno-lifetime-dse flag, but there are other places where we ask the memory manager to allocate data. This is temporary band-aid, and is already fixed in 5.8. Change-Id: Ia61a69f65fab351068a588cfc36b5b3d762ffc9f Task-number: QTBUG-56932 Reviewed-by: Simon Hausmann Reviewed-by: Lars Knoll --- src/imports/particles/particles.pro | 5 +++++ src/quick/quick.pro | 5 +++++ tests/auto/qml/qqmlecmascript/qqmlecmascript.pro | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/src/imports/particles/particles.pro b/src/imports/particles/particles.pro index 4460d03a04..fb9626c40e 100644 --- a/src/imports/particles/particles.pro +++ b/src/imports/particles/particles.pro @@ -3,6 +3,11 @@ TARGET = particlesplugin TARGETPATH = QtQuick/Particles.2 IMPORT_VERSION = 2.0 +greaterThan(QT_GCC_MAJOR_VERSION, 5) { + # Our code is bad. Temporary workaround. Fixed in 5.8 + QMAKE_CXXFLAGS += -fno-delete-null-pointer-checks -fno-lifetime-dse +} + SOURCES += \ plugin.cpp diff --git a/src/quick/quick.pro b/src/quick/quick.pro index 1c14ff8d57..f56fb2e081 100644 --- a/src/quick/quick.pro +++ b/src/quick/quick.pro @@ -13,6 +13,11 @@ exists("qqml_enable_gcov") { LIBS_PRIVATE += -lgcov } +greaterThan(QT_GCC_MAJOR_VERSION, 5) { + # Our code is bad. Temporary workaround. Fixed in 5.8 + QMAKE_CXXFLAGS += -fno-delete-null-pointer-checks -fno-lifetime-dse +} + QMAKE_DOCS = $$PWD/doc/qtquick.qdocconf ANDROID_LIB_DEPENDENCIES = \ diff --git a/tests/auto/qml/qqmlecmascript/qqmlecmascript.pro b/tests/auto/qml/qqmlecmascript/qqmlecmascript.pro index 6f3f765aba..21e745f58e 100644 --- a/tests/auto/qml/qqmlecmascript/qqmlecmascript.pro +++ b/tests/auto/qml/qqmlecmascript/qqmlecmascript.pro @@ -13,6 +13,11 @@ RESOURCES += qqmlecmascript.qrc include (../../shared/util.pri) +greaterThan(QT_GCC_MAJOR_VERSION, 5) { + # Our code is bad. Temporary workaround. Fixed in 5.8 + QMAKE_CXXFLAGS += -fno-delete-null-pointer-checks -fno-lifetime-dse +} + # QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage # LIBS += -lgcov From a23bcdf91971510b79c541fdff4a9467ead08751 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Tue, 1 Nov 2016 15:19:59 +0100 Subject: [PATCH 16/33] qmlimportscanner: When passed an invalid file/directory it should cause an error Task-number: QTBUG-56617 Change-Id: I82eb9c07fd6350b2a63f80e62af4c0adf52656c7 Reviewed-by: J-P Nurmi Reviewed-by: Anton Kudryavtsev Reviewed-by: Mitch Curtis --- tools/qmlimportscanner/main.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp index f069c1883f..0f8eca34e1 100644 --- a/tools/qmlimportscanner/main.cpp +++ b/tools/qmlimportscanner/main.cpp @@ -528,7 +528,12 @@ int main(int argc, char *argv[]) if (arg.startsWith(QLatin1Char('-')) && arg != QLatin1String("-")) break; ++i; - *argReceiver += arg; + if (!QFile::exists(arg)) { + std::cerr << "No such file or directory: \"" << qPrintable(arg) << "\"\n"; + return 1; + } else { + *argReceiver += arg; + } } } From a7c24b49fd7ac1a1c2ce7a5671cfae6c9f3351fa Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 9 Nov 2016 17:06:25 +0100 Subject: [PATCH 17/33] Doc: replace "the empty string" with "an empty string" in TestCase docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Idcc23782f2ed382914a74740ad9f2984d7a98f78 Reviewed-by: Topi Reiniö --- src/imports/testlib/TestCase.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml index ca3e3b0a30..8328f5c027 100644 --- a/src/imports/testlib/TestCase.qml +++ b/src/imports/testlib/TestCase.qml @@ -221,7 +221,7 @@ Item { \qmlproperty string TestCase::name This property defines the name of the test case for result reporting. - The default is the empty string. + The default value is an empty string. \code TestCase { @@ -763,7 +763,7 @@ Item { \c{QEXPECT_FAIL(tag, message, Abort)} in C++. If the test is not data-driven, then \a tag must be set to - the empty string. + an empty string. \sa expectFailContinue() */ @@ -789,7 +789,7 @@ Item { \c{QEXPECT_FAIL(tag, message, Continue)} in C++. If the test is not data-driven, then \a tag must be set to - the empty string. + an empty string. \sa expectFail() */ From 08a9fc04989aa05d4cc8c44430977d23cc729656 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Tue, 8 Nov 2016 12:47:25 +0100 Subject: [PATCH 18/33] Change implementation of shadow nodes to use a double-linked list Since eea8fa64ab27854b71f46ef143e35b6c9acbba14, we're seeing increased times in QSGNode::removeChildNode(). The reason for this seems to be that iteration through the linked list is significantly slower than iteration through a QList<> due to that each node needs to be loaded in memory to iterate to the next, compared a more plain sequential pointer compare with QList<>. This implementation changes the nodes to use a circular double-linked list so we can drop the iteration when removing nodes. This brings us slightly better performance than the original QList based implementation while still using the same amount of memory as the single-linked list one. Change-Id: I0b693730f5b82ad7767e507accafd90551e03fbc Reviewed-by: Erik Verbruggen --- .../scenegraph/coreapi/qsgbatchrenderer.cpp | 57 ++++----------- .../scenegraph/coreapi/qsgbatchrenderer_p.h | 70 +++++++++++++++++-- 2 files changed, 81 insertions(+), 46 deletions(-) diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 49bbbf0ba8..81aa641e03 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -90,7 +90,7 @@ DECLARE_DEBUG_VAR(noclip) static QElapsedTimer qsg_renderer_timer; #define QSGNODE_TRAVERSE(NODE) for (QSGNode *child = NODE->firstChild(); child; child = child->nextSibling()) -#define SHADOWNODE_TRAVERSE(NODE) for (Node *child = NODE->firstChild; child; child = child->nextSibling) +#define SHADOWNODE_TRAVERSE(NODE) for (Node *child = NODE->firstChild(); child; child = child->sibling()) static inline int size_of_type(GLenum type) { @@ -510,7 +510,7 @@ void Updater::updateRootTransforms(Node *node, Node *root, const QMatrix4x4 &com while (n != root) { if (n->type() == QSGNode::TransformNodeType) m = static_cast(n->sgNode)->matrix() * m; - n = n->parent; + n = n->parent(); } m = combined * m; @@ -1013,16 +1013,8 @@ void Renderer::nodeWasAdded(QSGNode *node, Node *shadowParent) Node *snode = m_nodeAllocator.allocate(); snode->sgNode = node; m_nodes.insert(node, snode); - if (shadowParent) { - snode->parent = shadowParent; - if (shadowParent->lastChild) { - shadowParent->lastChild->nextSibling = snode; - shadowParent->lastChild = snode; - } else { - shadowParent->firstChild = snode; - shadowParent->lastChild = snode; - } - } + if (shadowParent) + shadowParent->append(snode); if (node->type() == QSGNode::GeometryNodeType) { snode->data = m_elementAllocator.allocate(); @@ -1054,17 +1046,12 @@ void Renderer::nodeWasRemoved(Node *node) // here, because we delete 'child' (when recursed, down below), so we'd // have a use-after-free. { - Node *child = node->firstChild; - Node *nextChild = 0; - + Node *child = node->firstChild(); while (child) { - // Get the next child now before we proceed - nextChild = child->nextSibling; - // Remove (and delete) child + node->remove(child); nodeWasRemoved(child); - - child = nextChild; + child = node->firstChild(); } } @@ -1110,6 +1097,7 @@ void Renderer::nodeWasRemoved(Node *node) } Q_ASSERT(m_nodes.contains(node->sgNode)); + m_nodeAllocator.release(m_nodes.take(node->sgNode)); } @@ -1120,13 +1108,13 @@ void Renderer::turnNodeIntoBatchRoot(Node *node) node->isBatchRoot = true; node->becameBatchRoot = true; - Node *p = node->parent; + Node *p = node->parent(); while (p) { if (p->type() == QSGNode::ClipNodeType || p->isBatchRoot) { registerBatchRoot(node, p); break; } - p = p->parent; + p = p->parent(); } SHADOWNODE_TRAVERSE(node) @@ -1255,33 +1243,18 @@ void Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state) | QSGNode::DirtyForceUpdate); if (dirtyChain != 0) { dirtyChain = QSGNode::DirtyState(dirtyChain << 16); - Node *sn = shadowNode->parent; + Node *sn = shadowNode->parent(); while (sn) { sn->dirtyState |= dirtyChain; - sn = sn->parent; + sn = sn->parent(); } } // Delete happens at the very end because it deletes the shadownode. if (state & QSGNode::DirtyNodeRemoved) { - Node *parent = shadowNode->parent; - if (parent) { - Q_ASSERT(parent->firstChild); - Q_ASSERT(parent->lastChild); - shadowNode->parent = 0; - Node *child = parent->firstChild; - if (child == shadowNode) { - parent->firstChild = shadowNode->nextSibling; - if (parent->lastChild == shadowNode) - parent->lastChild = 0; - } else { - while (child->nextSibling != shadowNode) - child = child->nextSibling; - child->nextSibling = shadowNode->nextSibling; - if (shadowNode == parent->lastChild) - parent->lastChild = child; - } - } + Node *parent = shadowNode->parent(); + if (parent) + parent->remove(shadowNode); nodeWasRemoved(shadowNode); Q_ASSERT(m_nodes.value(node) == 0); } diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index 01e517e65b..eb5bfca1ee 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -451,11 +451,73 @@ struct Batch struct Node { QSGNode *sgNode; - Node *parent; void *data; - Node *firstChild; - Node *nextSibling; - Node *lastChild; + + Node *m_parent; + Node *m_child; + Node *m_next; + Node *m_prev; + + Node *parent() const { return m_parent; } + + void append(Node *child) { + Q_ASSERT(child); + Q_ASSERT(!hasChild(child)); + Q_ASSERT(child->m_parent == 0); + Q_ASSERT(child->m_next == 0); + Q_ASSERT(child->m_prev == 0); + + if (!m_child) { + child->m_next = child; + child->m_prev = child; + m_child = child; + } else { + m_child->m_prev->m_next = child; + child->m_prev = m_child->m_prev; + m_child->m_prev = child; + child->m_next = m_child; + } + child->setParent(this); + } + + void remove(Node *child) { + Q_ASSERT(child); + Q_ASSERT(hasChild(child)); + + // only child.. + if (child->m_next == child) { + m_child = 0; + } else { + if (m_child == child) + m_child = child->m_next; + child->m_next->m_prev = child->m_prev; + child->m_prev->m_next = child->m_next; + } + child->m_next = 0; + child->m_prev = 0; + child->setParent(0); + } + + Node *firstChild() const { return m_child; } + + Node *sibling() const { + Q_ASSERT(m_parent); + return m_next == m_parent->m_child ? 0 : m_next; + } + + void setParent(Node *p) { + Q_ASSERT(m_parent == 0 || p == 0); + m_parent = p; + } + + bool hasChild(Node *child) const { + Node *n = m_child; + while (n && n != child) + n = n->sibling(); + return n; + } + + QSGNode::DirtyState dirtyState; From 8161a92b5fe1c0e4818a0fb19ed2177d7a12f731 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 3 Nov 2016 14:34:43 +0100 Subject: [PATCH 19/33] Quick: Do not calculate the difference in a geometryChange This difference is only used by the ListView, so calculating it and storing it (on the stack) introduces a penalty for all items. As the new geometry is already applied, the old geometry is passed along. This has the added advantage that the ListView does not have to re-calculate that either. This fixes a performance regression. Change-Id: Id5e67bb663a5b11a55ec15ff24ca5b213d1fcef5 Reviewed-by: Gunnar Sletta --- src/quick/items/qquickitem.cpp | 14 +++++-------- src/quick/items/qquickitemchangelistener_p.h | 4 +++- src/quick/items/qquickitemview.cpp | 4 ++-- src/quick/items/qquicklistview.cpp | 20 +++++++++---------- src/quick/items/qquickloader.cpp | 6 +++--- src/quick/items/qquickloader_p_p.h | 2 +- src/quick/items/qquickview.cpp | 4 ++-- src/quickwidgets/qquickwidget.cpp | 4 ++-- src/quickwidgets/qquickwidget_p.h | 2 +- .../auto/quick/qquickitem2/tst_qquickitem.cpp | 12 +++++------ 10 files changed, 34 insertions(+), 38 deletions(-) diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 1e60ef8c02..13b75c0482 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -3658,21 +3658,17 @@ void QQuickItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo QQuickAnchorsPrivate::get(d->_anchors)->updateMe(); QQuickGeometryChange change; - QRectF diff(newGeometry.x() - oldGeometry.x(), - newGeometry.y() - oldGeometry.y(), - newGeometry.width() - oldGeometry.width(), - newGeometry.height() - oldGeometry.height()); - change.setXChange(diff.x() != 0); - change.setYChange(diff.y() != 0); - change.setWidthChange(diff.width() != 0); - change.setHeightChange(diff.height() != 0); + change.setXChange(newGeometry.x() != oldGeometry.x()); + change.setYChange(newGeometry.y() != oldGeometry.y()); + change.setWidthChange(newGeometry.width() != oldGeometry.width()); + change.setHeightChange(newGeometry.height() != oldGeometry.height()); if (!d->changeListeners.isEmpty()) { const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732) for (const QQuickItemPrivate::ChangeListener &listener : listeners) { if (listener.types & QQuickItemPrivate::Geometry) { if (change.matches(listener.gTypes)) - listener.listener->itemGeometryChanged(this, change, diff); + listener.listener->itemGeometryChanged(this, change, oldGeometry); } } } diff --git a/src/quick/items/qquickitemchangelistener_p.h b/src/quick/items/qquickitemchangelistener_p.h index 19ff73056b..83c69a9330 100644 --- a/src/quick/items/qquickitemchangelistener_p.h +++ b/src/quick/items/qquickitemchangelistener_p.h @@ -115,12 +115,14 @@ private: int kind; }; +#define QT_QUICK_NEW_GEOMETRY_CHANGED_HANDLING + class QQuickItemChangeListener { public: virtual ~QQuickItemChangeListener() {} - virtual void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF & /* diff */) {} + virtual void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF & /* oldGeometry */) {} virtual void itemSiblingOrderChanged(QQuickItem *) {} virtual void itemVisibilityChanged(QQuickItem *) {} virtual void itemOpacityChanged(QQuickItem *) {} diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index e017d6564a..7f8b26f20b 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -1206,10 +1206,10 @@ void QQuickItemViewPrivate::showVisibleItems() const } void QQuickItemViewPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, - const QRectF &diff) + const QRectF &oldGeometry) { Q_Q(QQuickItemView); - QQuickFlickablePrivate::itemGeometryChanged(item, change, diff); + QQuickFlickablePrivate::itemGeometryChanged(item, change, oldGeometry); if (!q->isComponentComplete()) return; diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index 30625c7ea8..f89a995e76 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -131,7 +131,7 @@ public: void updateAverage(); - void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) Q_DECL_OVERRIDE; + void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &oldGeometry) Q_DECL_OVERRIDE; void fixupPosition() Q_DECL_OVERRIDE; void fixup(AxisData &data, qreal minExtent, qreal maxExtent) Q_DECL_OVERRIDE; bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, @@ -1401,11 +1401,11 @@ bool QQuickListViewPrivate::hasStickyFooter() const } void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, - const QRectF &diff) + const QRectF &oldGeometry) { Q_Q(QQuickListView); - QQuickItemViewPrivate::itemGeometryChanged(item, change, diff); + QQuickItemViewPrivate::itemGeometryChanged(item, change, oldGeometry); if (!q->isComponentComplete()) return; @@ -1426,24 +1426,22 @@ void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometry // position all subsequent items if (visibleItems.count() && item == visibleItems.constFirst()->item) { FxListItemSG *listItem = static_cast(visibleItems.constFirst()); - const QRectF oldGeometry(item->x() - diff.x(), - item->y() - diff.y(), - item->width() - diff.width(), - item->height() - diff.height()); if (listItem->transitionScheduledOrRunning()) return; if (orient == QQuickListView::Vertical) { const qreal oldItemEndPosition = verticalLayoutDirection == QQuickItemView::BottomToTop ? -oldGeometry.y() : oldGeometry.y() + oldGeometry.height(); + const qreal heightDiff = item->height() - oldGeometry.height(); if (verticalLayoutDirection == QQuickListView::TopToBottom && oldItemEndPosition < q->contentY()) - listItem->setPosition(listItem->position() - diff.height(), true); + listItem->setPosition(listItem->position() - heightDiff, true); else if (verticalLayoutDirection == QQuickListView::BottomToTop && oldItemEndPosition > q->contentY()) - listItem->setPosition(listItem->position() + diff.height(), true); + listItem->setPosition(listItem->position() + heightDiff, true); } else { const qreal oldItemEndPosition = q->effectiveLayoutDirection() == Qt::RightToLeft ? -oldGeometry.x() : oldGeometry.x() + oldGeometry.width(); + const qreal widthDiff = item->width() - oldGeometry.width(); if (q->effectiveLayoutDirection() == Qt::LeftToRight && oldItemEndPosition < q->contentX()) - listItem->setPosition(listItem->position() - diff.width(), true); + listItem->setPosition(listItem->position() - widthDiff, true); else if (q->effectiveLayoutDirection() == Qt::RightToLeft && oldItemEndPosition > q->contentX()) - listItem->setPosition(listItem->position() + diff.width(), true); + listItem->setPosition(listItem->position() + widthDiff, true); } } forceLayoutPolish(); diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index 9aea9c50df..eeec562e3c 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -65,12 +65,12 @@ QQuickLoaderPrivate::~QQuickLoaderPrivate() disposeInitialPropertyValues(); } -void QQuickLoaderPrivate::itemGeometryChanged(QQuickItem *resizeItem, QQuickGeometryChange change - , const QRectF &diff) +void QQuickLoaderPrivate::itemGeometryChanged(QQuickItem *resizeItem, QQuickGeometryChange change, + const QRectF &oldGeometry) { if (resizeItem == item) _q_updateSize(false); - QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, diff); + QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, oldGeometry); } void QQuickLoaderPrivate::itemImplicitWidthChanged(QQuickItem *) diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h index fcccbfe4f5..a1e97b97d8 100644 --- a/src/quick/items/qquickloader_p_p.h +++ b/src/quick/items/qquickloader_p_p.h @@ -84,7 +84,7 @@ public: QQuickLoaderPrivate(); ~QQuickLoaderPrivate(); - void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) Q_DECL_OVERRIDE; + void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &oldGeometry) Q_DECL_OVERRIDE; void itemImplicitWidthChanged(QQuickItem *) Q_DECL_OVERRIDE; void itemImplicitHeightChanged(QQuickItem *) Q_DECL_OVERRIDE; void clear(); diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp index a167f01484..573440ff7f 100644 --- a/src/quick/items/qquickview.cpp +++ b/src/quick/items/qquickview.cpp @@ -111,14 +111,14 @@ void QQuickViewPrivate::execute() } void QQuickViewPrivate::itemGeometryChanged(QQuickItem *resizeItem, QQuickGeometryChange change, - const QRectF &diff) + const QRectF &oldGeometry) { Q_Q(QQuickView); if (resizeItem == root && resizeMode == QQuickView::SizeViewToRootObject) { // wait for both width and height to be changed resizetimer.start(0,q); } - QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, diff); + QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, oldGeometry); } /*! diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index de3692afb0..1d617f5098 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -245,14 +245,14 @@ void QQuickWidgetPrivate::execute() } void QQuickWidgetPrivate::itemGeometryChanged(QQuickItem *resizeItem, QQuickGeometryChange change, - const QRectF &diff) + const QRectF &oldGeometry) { Q_Q(QQuickWidget); if (resizeItem == root && resizeMode == QQuickWidget::SizeViewToRootObject) { // wait for both width and height to be changed resizetimer.start(0,q); } - QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, diff); + QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, oldGeometry); } void QQuickWidgetPrivate::render(bool needsSync) diff --git a/src/quickwidgets/qquickwidget_p.h b/src/quickwidgets/qquickwidget_p.h index 3d64981797..0ba86172e6 100644 --- a/src/quickwidgets/qquickwidget_p.h +++ b/src/quickwidgets/qquickwidget_p.h @@ -87,7 +87,7 @@ public: ~QQuickWidgetPrivate(); void execute(); - void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) Q_DECL_OVERRIDE; + void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &oldGeometry) Q_DECL_OVERRIDE; void initResize(); void updateSize(); void updatePosition(); diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp index 6554d749dd..78322b44a1 100644 --- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp @@ -2726,9 +2726,9 @@ struct TestListener : public QQuickItemChangeListener { TestListener(bool remove = false) : remove(remove) { } - void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange, const QRectF &diff) override + void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange, const QRectF &oldGeometry) override { - record(item, QQuickItemPrivate::Geometry, diff); + record(item, QQuickItemPrivate::Geometry, oldGeometry); } void itemSiblingOrderChanged(QQuickItem *item) override { @@ -2810,20 +2810,20 @@ void tst_QQuickItem::changeListener() item->setImplicitWidth(10); QCOMPARE(itemListener.count(QQuickItemPrivate::ImplicitWidth), 1); QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 1); - QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,10,0))); + QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,0,0))); item->setImplicitHeight(20); QCOMPARE(itemListener.count(QQuickItemPrivate::ImplicitHeight), 1); QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 2); - QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,0,20))); + QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,10,0))); item->setWidth(item->width() + 30); QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 3); - QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,30,0))); + QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,10,20))); item->setHeight(item->height() + 40); QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 4); - QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,0,40))); + QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,40,20))); item->setOpacity(0.5); QCOMPARE(itemListener.count(QQuickItemPrivate::Opacity), 1); From cf63d8fc8f2006df2211c33ad077c2dcd95349e9 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 8 Nov 2016 15:52:00 +0100 Subject: [PATCH 20/33] Work around -Wtautological-compare warnings on clang 3.6 Same workaround as for gcc 6.0 Change-Id: I6137b226c05ddc287bea7230d1f546c5fcf8371f Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4managed_p.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 1fff5a45da..28b255bd9a 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -107,11 +107,18 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} (classname::func == QV4::Managed::func ? 0 : classname::func) // Q_VTABLE_FUNCTION triggers a bogus tautological-compare warning in GCC6+ -#if defined(Q_CC_GNU) && Q_CC_GNU >= 600 +#if (defined(Q_CC_GNU) && Q_CC_GNU >= 600) #define QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_ON \ QT_WARNING_PUSH; \ QT_WARNING_DISABLE_GCC("-Wtautological-compare") +#define QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_OFF \ + ;QT_WARNING_POP +#elif defined(Q_CC_CLANG) && Q_CC_CLANG >= 306 +#define QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_ON \ + QT_WARNING_PUSH; \ + QT_WARNING_DISABLE_CLANG("-Wtautological-compare") + #define QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_OFF \ ;QT_WARNING_POP #else From 291223876bb190ca4b5a07cf8f605c7bf88d7ab6 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Thu, 10 Nov 2016 10:58:21 +0100 Subject: [PATCH 21/33] Fix QtQuickTest::mouseMove not having timestamps af002b8df9b084fd7f26e9eead9844aab36bdc4d added timestamps to press and release events. It did not add the timestamp to move events though. When using the quick test functionality to send events to flickable, this leads to great confusion since the move events will be from a completely different time than the release, in which case flickable responds with "you waited a long time before releasing, I think you didn't want to flick". Adding the timestamp also to move events is consistent and makes tests in qtlocation happy. Change-Id: I33653c435eff5b62eeaf5a03653d917b7acc4fed Reviewed-by: Peter Varga Reviewed-by: Paolo Angelelli --- src/qmltest/quicktestevent.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qmltest/quicktestevent.cpp b/src/qmltest/quicktestevent.cpp index b26d463445..230bc4eca9 100644 --- a/src/qmltest/quicktestevent.cpp +++ b/src/qmltest/quicktestevent.cpp @@ -177,6 +177,7 @@ namespace QtQuickTest case MouseMove: // with move event the button is NoButton, but 'buttons' holds the currently pressed buttons me = QMouseEvent(QEvent::MouseMove, pos, window->mapToGlobal(pos), Qt::NoButton, button, stateKey); + me.setTimestamp(++lastMouseTimestamp); break; default: QTEST_ASSERT(false); From 769002ffe4a93995447a71393371579b1df41e12 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 14 Sep 2016 10:48:36 +0200 Subject: [PATCH 22/33] TextEdit: set cursor delegate's height to match the selected font RichText can have blocks of text with varying font sizes, so we must ensure that the cursor delegate's height is also set when it's moved to a different position in the text. Change-Id: I00691a94a2360c7d3272571fc4ba0da28b01006a Task-number: QTBUG-54934 Reviewed-by: J-P Nurmi --- src/quick/items/qquicktextedit.cpp | 1 + .../qquicktextedit/data/cursorHeight.qml | 20 ++++++++++ .../qquicktextedit/tst_qquicktextedit.cpp | 38 +++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 tests/auto/quick/qquicktextedit/data/cursorHeight.qml diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 9b23abc877..d9179d4cf1 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -2290,6 +2290,7 @@ void QQuickTextEdit::moveCursorDelegate() QRectF cursorRect = cursorRectangle(); d->cursorItem->setX(cursorRect.x()); d->cursorItem->setY(cursorRect.y()); + d->cursorItem->setHeight(cursorRect.height()); } void QQuickTextEdit::updateSelection() diff --git a/tests/auto/quick/qquicktextedit/data/cursorHeight.qml b/tests/auto/quick/qquicktextedit/data/cursorHeight.qml new file mode 100644 index 0000000000..b831a9eb6f --- /dev/null +++ b/tests/auto/quick/qquicktextedit/data/cursorHeight.qml @@ -0,0 +1,20 @@ +import QtQuick 2.0 + +Rectangle { + width: 300 + height: 300 + color: "white" + + TextEdit { + objectName: "textEditObject" + width: 300 + height: 300 + text: "Blah
blah" + textFormat: TextEdit.RichText + cursorDelegate: Rectangle { + objectName: "cursorInstance" + color: "red" + width: 2 + } + } +} diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp index cb2a7bfd83..fa5a0a254d 100644 --- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp @@ -139,6 +139,7 @@ private slots: void cursorVisible(); void delegateLoading_data(); void delegateLoading(); + void cursorDelegateHeight(); void navigation(); void readOnly(); #ifndef QT_NO_CLIPBOARD @@ -2779,6 +2780,43 @@ void tst_qquicktextedit::delegateLoading() //QVERIFY(!delegate); } +void tst_qquicktextedit::cursorDelegateHeight() +{ + QQuickView view(testFileUrl("cursorHeight.qml")); + view.show(); + view.requestActivate(); + QTest::qWaitForWindowActive(&view); + QQuickTextEdit *textEditObject = view.rootObject()->findChild("textEditObject"); + QVERIFY(textEditObject); + // Delegate creation is deferred until focus in or cursor visibility is forced. + QVERIFY(!textEditObject->findChild("cursorInstance")); + QVERIFY(!textEditObject->isCursorVisible()); + + // Test that the delegate gets created. + textEditObject->setFocus(true); + QVERIFY(textEditObject->isCursorVisible()); + QQuickItem* delegateObject = textEditObject->findChild("cursorInstance"); + QVERIFY(delegateObject); + + const int largerHeight = textEditObject->cursorRectangle().height(); + + textEditObject->setCursorPosition(0); + QCOMPARE(delegateObject->x(), textEditObject->cursorRectangle().x()); + QCOMPARE(delegateObject->y(), textEditObject->cursorRectangle().y()); + QCOMPARE(delegateObject->height(), textEditObject->cursorRectangle().height()); + + // Move the cursor to the next line, which has a smaller font. + textEditObject->setCursorPosition(5); + QCOMPARE(delegateObject->x(), textEditObject->cursorRectangle().x()); + QCOMPARE(delegateObject->y(), textEditObject->cursorRectangle().y()); + QVERIFY(textEditObject->cursorRectangle().height() < largerHeight); + QCOMPARE(delegateObject->height(), textEditObject->cursorRectangle().height()); + + // Test that the delegate gets deleted + textEditObject->setCursorDelegate(0); + QVERIFY(!textEditObject->findChild("cursorInstance")); +} + /* TextEdit element should only handle left/right keys until the cursor reaches the extent of the text, then they should ignore the keys. From cf9c2c3db39e4b4d2f0dd3daaa7d6050f19c6b62 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 11 Nov 2016 15:55:16 +0100 Subject: [PATCH 23/33] Fix performance regression in rich text with images In a3da23d5a92ab0f9b8280b9ed591986f8ac6a2d6 we added linear filtering to the image node in rich text when smooth was set to true (which it is by default). But we also enabled mipmapping, which caused a bad performance regression when updating the text item. If we want to support mipmapping, we would have to add a separate property for this like in the image node, but since the original bug report only called for supporting smooth scaling like in Image, we can simply revert part of the change. [ChangeLog][QtQuick][Text] Fixed a performance regression when rendering a rich text item with scaled images. Task-number: QTBUG-54723 Change-Id: Ib930112b76f0fe0b2e658f86520a9290354b8f6f Reviewed-by: Laszlo Agocs --- src/quick/items/qquicktextnode.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/quick/items/qquicktextnode.cpp b/src/quick/items/qquicktextnode.cpp index b0bb60f566..26a84ed42a 100644 --- a/src/quick/items/qquicktextnode.cpp +++ b/src/quick/items/qquicktextnode.cpp @@ -160,18 +160,14 @@ void QQuickTextNode::addImage(const QRectF &rect, const QImage &image) QSGRenderContext *sg = QQuickItemPrivate::get(m_ownerElement)->sceneGraphRenderContext(); QSGImageNode *node = sg->sceneGraphContext()->createImageNode(); QSGTexture *texture = sg->createTexture(image); - if (m_ownerElement->smooth()) { + if (m_ownerElement->smooth()) texture->setFiltering(QSGTexture::Linear); - texture->setMipmapFiltering(QSGTexture::Linear); - } m_textures.append(texture); node->setTargetRect(rect); node->setInnerTargetRect(rect); node->setTexture(texture); - if (m_ownerElement->smooth()) { + if (m_ownerElement->smooth()) node->setFiltering(QSGTexture::Linear); - node->setMipmapFiltering(QSGTexture::Linear); - } appendChildNode(node); node->update(); } From daa866a196962beb6171f847bd6f691f3ae38300 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Fri, 11 Nov 2016 09:47:57 +0100 Subject: [PATCH 24/33] StocQt example: Prefetch values for stock list model Instead of doing a network request for each item in the stock list, prefetch values for all entries when creating the model. This improves performance when scrolling the list. Task-number: QTBUG-56114 Change-Id: I12f0012ec0a97f2bf03b53a5b51076171cd7fc7a Reviewed-by: Venugopal Shivashankar --- .../demos/stocqt/content/StockListModel.qml | 66 +++++++++++++++++++ .../demos/stocqt/content/StockListView.qml | 60 ----------------- 2 files changed, 66 insertions(+), 60 deletions(-) diff --git a/examples/quick/demos/stocqt/content/StockListModel.qml b/examples/quick/demos/stocqt/content/StockListModel.qml index be00e7bb1c..9b48124bda 100644 --- a/examples/quick/demos/stocqt/content/StockListModel.qml +++ b/examples/quick/demos/stocqt/content/StockListModel.qml @@ -42,6 +42,72 @@ import QtQuick 2.0 ListModel { id: stocks + + // pre-fetch data for all entries + Component.onCompleted: { + for (var idx = 0; idx < count; ++idx) { + getCloseValue(idx) + } + } + + function requestUrl(stockId) { + var endDate = new Date(""); // today + var startDate = new Date() + startDate.setDate(startDate.getDate() - 5); + + var request = "http://ichart.finance.yahoo.com/table.csv?"; + request += "s=" + stockId; + request += "&g=d"; + request += "&a=" + startDate.getMonth(); + request += "&b=" + startDate.getDate(); + request += "&c=" + startDate.getFullYear(); + request += "&d=" + endDate.getMonth(); + request += "&e=" + endDate.getDate(); + request += "&f=" + endDate.getFullYear(); + request += "&g=d"; + request += "&ignore=.csv"; + return request; + } + + function getCloseValue(index) { + var req = requestUrl(get(index).stockId); + + if (!req) + return; + + var xhr = new XMLHttpRequest; + + xhr.open("GET", req, true); + + xhr.onreadystatechange = function() { + if (xhr.readyState === XMLHttpRequest.LOADING || xhr.readyState === XMLHttpRequest.DONE) { + var records = xhr.responseText.split('\n'); + if (records.length > 0 && xhr.status == 200) { + var r = records[1].split(','); + var today = parseFloat(r[4]); + setProperty(index, "value", today.toFixed(2)); + + r = records[2].split(','); + var yesterday = parseFloat(r[4]); + var change = today - yesterday; + if (change >= 0.0) + setProperty(index, "change", "+" + change.toFixed(2)); + else + setProperty(index, "change", change.toFixed(2)); + + var changePercentage = (change / yesterday) * 100.0; + if (changePercentage >= 0.0) + setProperty(index, "changePercentage", "+" + changePercentage.toFixed(2) + "%"); + else + setProperty(index, "changePercentage", changePercentage.toFixed(2) + "%"); + } else { + var unknown = "n/a"; + set(index, {"value": unknown, "change": unknown, "changePercentage": unknown}); + } + } + } + xhr.send() + } // Uncomment to test invalid entries // ListElement {name: "The Qt Company"; stockId: "TQTC"; value: "999.0"; change: "0.0"; changePercentage: "0.0"} diff --git a/examples/quick/demos/stocqt/content/StockListView.qml b/examples/quick/demos/stocqt/content/StockListView.qml index 59f36b42cc..d2bd52a69d 100644 --- a/examples/quick/demos/stocqt/content/StockListView.qml +++ b/examples/quick/demos/stocqt/content/StockListView.qml @@ -64,65 +64,6 @@ Rectangle { model: StockListModel{} currentIndex: -1 // Don't pre-select any item - function requestUrl(stockId) { - var endDate = new Date(""); //today - var startDate = new Date() - startDate.setDate(startDate.getDate() - 5); - - var request = "http://ichart.finance.yahoo.com/table.csv?"; - request += "s=" + stockId; - request += "&g=d"; - request += "&a=" + startDate.getMonth(); - request += "&b=" + startDate.getDate(); - request += "&c=" + startDate.getFullYear(); - request += "&d=" + endDate.getMonth(); - request += "&e=" + endDate.getDate(); - request += "&f=" + endDate.getFullYear(); - request += "&g=d"; - request += "&ignore=.csv"; - return request; - } - - function getCloseValue(index) { - var req = requestUrl(model.get(index).stockId); - - if (!req) - return; - - var xhr = new XMLHttpRequest; - - xhr.open("GET", req, true); - - xhr.onreadystatechange = function() { - if (xhr.readyState === XMLHttpRequest.LOADING || xhr.readyState === XMLHttpRequest.DONE) { - var records = xhr.responseText.split('\n'); - if (records.length > 0 && xhr.status == 200) { - var r = records[1].split(','); - var today = parseFloat(r[4]); - model.setProperty(index, "value", today.toFixed(2)); - - r = records[2].split(','); - var yesterday = parseFloat(r[4]); - var change = today - yesterday; - if (change >= 0.0) - model.setProperty(index, "change", "+" + change.toFixed(2)); - else - model.setProperty(index, "change", change.toFixed(2)); - - var changePercentage = (change / yesterday) * 100.0; - if (changePercentage >= 0.0) - model.setProperty(index, "changePercentage", "+" + changePercentage.toFixed(2) + "%"); - else - model.setProperty(index, "changePercentage", changePercentage.toFixed(2) + "%"); - } else { - var unknown = "n/a"; - model.set(index, {"value": unknown, "change": unknown, "changePercentage": unknown}); - } - } - } - xhr.send() - } - onCurrentIndexChanged: { if (currentItem) { root.currentStockId = model.get(currentIndex).stockId; @@ -175,7 +116,6 @@ Rectangle { horizontalAlignment: Text.AlignRight verticalAlignment: Text.AlignVCenter text: value - Component.onCompleted: view.getCloseValue(index); } Text { From 47847bebcacef2bbf3b5627ca18966d7d34d6762 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 11 Nov 2016 10:22:33 +0100 Subject: [PATCH 25/33] Fix flow text objects in beginning of RTL block If the block is right-to-left and starts with a text object, it should be aligned to the right edge of the QTextLine instead of the left one. [ChangeLog][QtQuick][Text] Fixed placement of flowing text objects in the start of a right-to-left block. Task-number: QTBUG-43133 Change-Id: Id790e88f3464280f124c38b4260386b84cac8826 Reviewed-by: Lars Knoll --- src/quick/items/qquicktextnodeengine.cpp | 7 ++++++- src/quick/items/qquicktextnodeengine_p.h | 12 +++++++++++- .../data/text/text_flow_image_start_ltr.qml | 14 ++++++++++++++ .../data/text/text_flow_image_start_rtl.qml | 14 ++++++++++++++ 4 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 tests/manual/scenegraph_lancelot/data/text/text_flow_image_start_ltr.qml create mode 100644 tests/manual/scenegraph_lancelot/data/text/text_flow_image_start_rtl.qml diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp index 4631b2e724..538356e679 100644 --- a/src/quick/items/qquicktextnodeengine.cpp +++ b/src/quick/items/qquicktextnodeengine.cpp @@ -423,7 +423,10 @@ void QQuickTextNodeEngine::addImage(const QRectF &rect, const QImage &image, qre QRectF searchRect = rect; if (layoutPosition == QTextFrameFormat::InFlow) { if (m_currentLineTree.isEmpty()) { - searchRect.moveTopLeft(m_position + m_currentLine.position() + QPointF(0,1)); + if (m_currentTextDirection == Qt::RightToLeft) + searchRect.moveTopRight(m_position + m_currentLine.rect().topRight() + QPointF(0, 1)); + else + searchRect.moveTopLeft(m_position + m_currentLine.position() + QPointF(0,1)); } else { const BinaryTreeNode *lastNode = m_currentLineTree.data() + m_currentLineTree.size() - 1; if (lastNode->glyphRun.isRightToLeft()) { @@ -952,6 +955,8 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText int preeditPosition = block.isValid() ? block.layout()->preeditAreaPosition() : -1; #endif + setCurrentTextDirection(block.textDirection()); + QVarLengthArray colorChanges; mergeFormats(block.layout(), &colorChanges); diff --git a/src/quick/items/qquicktextnodeengine_p.h b/src/quick/items/qquicktextnodeengine_p.h index 91ed6f4430..18c624513a 100644 --- a/src/quick/items/qquicktextnodeengine_p.h +++ b/src/quick/items/qquicktextnodeengine_p.h @@ -144,7 +144,11 @@ public: int selectionState; }; - QQuickTextNodeEngine() : m_hasSelection(false), m_hasContents(false) {} + QQuickTextNodeEngine() + : m_currentTextDirection(Qt::LeftToRight) + , m_hasSelection(false) + , m_hasContents(false) + {} bool hasContents() const { return m_hasContents; } void addTextBlock(QTextDocument *, const QTextBlock &, const QPointF &position, const QColor &textColor, const QColor& anchorColor, int selectionStart, int selectionEnd); @@ -158,6 +162,11 @@ public: m_currentLine = currentLine; } + void setCurrentTextDirection(Qt::LayoutDirection textDirection) + { + m_currentTextDirection = textDirection; + } + void addBorder(const QRectF &rect, qreal border, QTextFrameFormat::BorderStyle borderStyle, const QBrush &borderBrush); void addFrameDecorations(QTextDocument *document, QTextFrame *frame); @@ -247,6 +256,7 @@ private: QPointF m_position; QTextLine m_currentLine; + Qt::LayoutDirection m_currentTextDirection; QList > m_backgrounds; QList m_selectionRects; diff --git a/tests/manual/scenegraph_lancelot/data/text/text_flow_image_start_ltr.qml b/tests/manual/scenegraph_lancelot/data/text/text_flow_image_start_ltr.qml new file mode 100644 index 0000000000..b8f0458818 --- /dev/null +++ b/tests/manual/scenegraph_lancelot/data/text/text_flow_image_start_ltr.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +Item { + width: 320 + height: 480 + + Text { + anchors.centerIn: parent + font.family: "Arial" + font.pixelSize: 16 + textFormat: Text.RichText + text: "This image is in the start of the text" + } +} diff --git a/tests/manual/scenegraph_lancelot/data/text/text_flow_image_start_rtl.qml b/tests/manual/scenegraph_lancelot/data/text/text_flow_image_start_rtl.qml new file mode 100644 index 0000000000..e5bea08e62 --- /dev/null +++ b/tests/manual/scenegraph_lancelot/data/text/text_flow_image_start_rtl.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +Item { + width: 320 + height: 480 + + Text { + anchors.centerIn: parent + font.family: "Arial" + font.pixelSize: 16 + textFormat: Text.RichText + text: "هو أمّا حكومة" + } +} From 8ff69297eeddc3f5650c4cc5517c7e2eafaf6c59 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Fri, 14 Oct 2016 07:52:24 -0500 Subject: [PATCH 26/33] Setting Connection's target to null should disconnect implicit target Change-Id: Id7c8c7080e6db8bb6d09c1df13cddaef047cf611 Task-number: QTBUG-56499 Reviewed-by: J-P Nurmi --- src/qml/types/qqmlconnections.cpp | 4 +-- .../data/test-connection-implicit.qml | 9 +++++++ .../qqmlconnections/tst_qqmlconnections.cpp | 27 +++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 tests/auto/qml/qqmlconnections/data/test-connection-implicit.qml diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index 6a93410ecb..8e14589100 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -159,9 +159,9 @@ private: void QQmlConnections::setTarget(QObject *obj) { Q_D(QQmlConnections); - d->targetSet = true; // even if setting to 0, it is *set* - if (d->target == obj) + if (d->targetSet && d->target == obj) return; + d->targetSet = true; // even if setting to 0, it is *set* foreach (QQmlBoundSignal *s, d->boundsignals) { // It is possible that target is being changed due to one of our signal // handlers -> use deleteLater(). diff --git a/tests/auto/qml/qqmlconnections/data/test-connection-implicit.qml b/tests/auto/qml/qqmlconnections/data/test-connection-implicit.qml new file mode 100644 index 0000000000..d5aa0f102a --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/test-connection-implicit.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +Item { + width: 50 + + property bool tested: false + + Connections { onWidthChanged: tested = true } +} diff --git a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp index e529c74acc..eaf08a2a26 100644 --- a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp +++ b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp @@ -56,6 +56,7 @@ private slots: void errors(); void rewriteErrors(); void singletonTypeTarget(); + void clearImplicitTarget(); private: QQmlEngine engine; @@ -329,6 +330,32 @@ void tst_qqmlconnections::singletonTypeTarget() delete object; } +//QTBUG-56499 +void tst_qqmlconnections::clearImplicitTarget() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("test-connection-implicit.qml")); + QQuickItem *item = qobject_cast(c.create()); + + QVERIFY(item != 0); + + // normal case: fire Connections + item->setWidth(100.); + QCOMPARE(item->property("tested").toBool(), true); + + item->setProperty("tested", false); + // clear the implicit target + QQmlConnections *connections = item->findChild(); + QVERIFY(connections); + connections->setTarget(0); + + // target cleared: no longer fire Connections + item->setWidth(150.); + QCOMPARE(item->property("tested").toBool(), false); + + delete item; +} + QTEST_MAIN(tst_qqmlconnections) #include "tst_qqmlconnections.moc" From 441e6bbdb01733c0f9860ce881b61f5907d2d2f8 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 26 Oct 2016 12:17:55 +0200 Subject: [PATCH 27/33] Adjust positioners example for tooling * Fully qualify all property bindings * Not using flow as id, because it collides with the property flow These changes are required so the example works nicely in the designer. Change-Id: I05972a5a7ebe7277ae7f4230bb68a8b8b011b2f3 Reviewed-by: Tim Jenssen --- .../positioners-attachedproperties.qml | 18 ++-- .../positioners/positioners-transitions.qml | 94 +++++++++---------- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/examples/quick/positioners/positioners-attachedproperties.qml b/examples/quick/positioners/positioners-attachedproperties.qml index ac2c76db47..e7fa59bb9a 100644 --- a/examples/quick/positioners/positioners-attachedproperties.qml +++ b/examples/quick/positioners/positioners-attachedproperties.qml @@ -66,14 +66,14 @@ Rectangle { anchors.left: parent.left anchors.leftMargin: page.width / 32 anchors.topMargin: page.height / 48 - spacing: elementSpacing + spacing: page.elementSpacing //! [0] Rectangle { id: green color: "#80c342" - width: 100 * ratio - height: 100 * ratio + width: 100 * page.ratio + height: 100 * page.ratio Text { anchors.left: parent.right @@ -95,8 +95,8 @@ Rectangle { Rectangle { id: blue color: "#14aaff" - width: 100 * ratio - height: 100 * ratio + width: 100 * page.ratio + height: 100 * page.ratio Text { anchors.left: parent.right @@ -117,8 +117,8 @@ Rectangle { Rectangle { id: purple color: "#6400aa" - width: 100 * ratio - height: 100 * ratio + width: 100 * page.ratio + height: 100 * page.ratio Text { anchors.left: parent.right @@ -140,8 +140,8 @@ Rectangle { Rectangle { id: hidingRect color: "#006325" - width: 100 * ratio - height: 100 * ratio + width: 100 * page.ratio + height: 100 * page.ratio visible: false Text { diff --git a/examples/quick/positioners/positioners-transitions.qml b/examples/quick/positioners/positioners-transitions.qml index 0d283f7301..17fe41a7e2 100644 --- a/examples/quick/positioners/positioners-transitions.qml +++ b/examples/quick/positioners/positioners-transitions.qml @@ -55,7 +55,7 @@ Item { interval: 2000 running: true repeat: true - onTriggered: effectiveOpacity = (effectiveOpacity == 1.0 ? 0.0 : 1.0); + onTriggered: page.effectiveOpacity = (page.effectiveOpacity == 1.0 ? 0.0 : 1.0); } Column { @@ -65,7 +65,7 @@ Item { top: parent.top topMargin: page.height / 48 } - spacing: elementSpacing + spacing: page.elementSpacing populate: Transition { NumberAnimation { properties: "x,y"; from: 200; duration: 100; easing.type: Easing.OutBounce } @@ -77,32 +77,32 @@ Item { NumberAnimation { properties: "y"; easing.type: Easing.OutBounce } } - Rectangle { color: "#80c342"; width: bigSize; height: smallSize } + Rectangle { color: "#80c342"; width: page.bigSize; height: page.smallSize } Rectangle { id: greenV1 visible: opacity != 0 - width: bigSize; height: smallSize + width: page.bigSize; height: page.smallSize color: "#006325" border.color: "transparent" Behavior on opacity { NumberAnimation {} } - opacity: effectiveOpacity + opacity: page.effectiveOpacity } - Rectangle { color: "#14aaff"; width: bigSize; height: smallSize } + Rectangle { color: "#14aaff"; width: page.bigSize; height: page.smallSize } Rectangle { id: greenV2 visible: opacity != 0 - width: bigSize; height: smallSize + width: page.bigSize; height: page.smallSize color: "#006325" border.color: "transparent" Behavior on opacity { NumberAnimation {} } - opacity: effectiveOpacity + opacity: page.effectiveOpacity } - Rectangle { color: "#6400aa"; width: bigSize; height: smallSize } - Rectangle { color: "#80c342"; width: bigSize; height: smallSize } + Rectangle { color: "#6400aa"; width: page.bigSize; height: page.smallSize } + Rectangle { color: "#80c342"; width: page.bigSize; height: page.smallSize } } Row { @@ -112,7 +112,7 @@ Item { bottom: page.bottom bottomMargin: page.height / 48 } - spacing: elementSpacing + spacing: page.elementSpacing populate: Transition { NumberAnimation { properties: "x,y"; from: 200; duration: 100; easing.type: Easing.OutBounce } @@ -124,40 +124,40 @@ Item { NumberAnimation { properties: "x"; easing.type: Easing.OutBounce } } - Rectangle { color: "#80c342"; width: smallSize; height: bigSize } + Rectangle { color: "#80c342"; width: page.smallSize; height: page.bigSize } Rectangle { id: blueH1 visible: opacity != 0 - width: smallSize; height: bigSize + width: page.smallSize; height: page.bigSize color: "#006325" border.color: "transparent" Behavior on opacity { NumberAnimation {} } - opacity: effectiveOpacity + opacity: page.effectiveOpacity } - Rectangle { color: "#14aaff"; width: smallSize; height: bigSize } + Rectangle { color: "#14aaff"; width: page.smallSize; height: page.bigSize } Rectangle { id: greenH2 visible: opacity != 0 - width: smallSize; height: bigSize + width: page.smallSize; height: page.bigSize color: "#006325" border.color: "transparent" Behavior on opacity { NumberAnimation {} } - opacity: effectiveOpacity + opacity: page.effectiveOpacity } - Rectangle { color: "#6400aa"; width: smallSize; height: bigSize } - Rectangle { color: "#80c342"; width: smallSize; height: bigSize } + Rectangle { color: "#6400aa"; width: page.smallSize; height: page.bigSize } + Rectangle { color: "#80c342"; width: page.smallSize; height: page.bigSize } } Grid { anchors.top: parent.top anchors.topMargin: page.height / 48 - anchors.left: flow.left + anchors.left: flowItem.left columns: 3 - spacing: elementSpacing + spacing: page.elementSpacing populate: Transition { NumberAnimation { properties: "x,y"; from: 200; duration: 100; easing.type: Easing.OutBounce } @@ -169,55 +169,55 @@ Item { NumberAnimation { properties: "x,y"; easing.type: Easing.OutBounce } } - Rectangle { color: "#80c342"; width: smallSize; height: smallSize } + Rectangle { color: "#80c342"; width: page.smallSize; height: page.smallSize } Rectangle { id: greenG1 visible: opacity != 0 - width: smallSize; height: smallSize + width: page.smallSize; height: page.smallSize color: "#006325" border.color: "transparent" Behavior on opacity { NumberAnimation {} } - opacity: effectiveOpacity + opacity: page.effectiveOpacity } - Rectangle { color: "#14aaff"; width: smallSize; height: smallSize } + Rectangle { color: "#14aaff"; width: page.smallSize; height: page.smallSize } Rectangle { id: greenG2 visible: opacity != 0 - width: smallSize; height: smallSize + width: page.smallSize; height:page. smallSize color: "#006325" border.color: "transparent" Behavior on opacity { NumberAnimation {} } - opacity: effectiveOpacity + opacity: page.effectiveOpacity } - Rectangle { color: "#6400aa"; width: smallSize; height: smallSize } + Rectangle { color: "#6400aa"; width: page.smallSize; height: page.smallSize } Rectangle { id: greenG3 visible: opacity != 0 - width: smallSize; height: smallSize + width: page.smallSize; height: page.smallSize color: "#006325" border.color: "transparent" Behavior on opacity { NumberAnimation {} } - opacity: effectiveOpacity + opacity: page.effectiveOpacity } - Rectangle { color: "#80c342"; width: smallSize; height: smallSize } - Rectangle { color: "#14aaff"; width: smallSize; height: smallSize } - Rectangle { color: "#6400aa"; width: smallSize; height: smallSize } + Rectangle { color: "#80c342"; width:page. smallSize; height: page.smallSize } + Rectangle { color: "#14aaff"; width: smallSize; height: page.smallSize } + Rectangle { color: "#6400aa"; width: page.page.smallSize; height: page.smallSize } } Flow { - id: flow + id: flowItem anchors.right: page.right anchors.rightMargin: page.width / 32 - y: 2 * bigSize - width: 1.8 * bigSize - spacing: elementSpacing + y: 2 * page.bigSize + width: 1.8 * page.bigSize + spacing: page.elementSpacing //! [move] move: Transition { @@ -237,42 +237,42 @@ Item { } //! [populate] - Rectangle { color: "#80c342"; width: smallSize; height: smallSize } + Rectangle { color: "#80c342"; width: page.smallSize; height: page.smallSize } Rectangle { id: greenF1 visible: opacity != 0 - width: 0.6 * bigSize; height: smallSize + width: 0.6 * page.bigSize; height: page.smallSize color: "#006325" border.color: "transparent" Behavior on opacity { NumberAnimation {} } - opacity: effectiveOpacity + opacity: page.effectiveOpacity } - Rectangle { color: "#14aaff"; width: 0.3 * bigSize; height: smallSize } + Rectangle { color: "#14aaff"; width: 0.3 * page.bigSize; height: page.smallSize } Rectangle { id: greenF2 visible: opacity != 0 - width: 0.6 * bigSize; height: smallSize + width: 0.6 * page.bigSize; height: page.smallSize color: "#006325" border.color: "transparent" Behavior on opacity { NumberAnimation {} } - opacity: effectiveOpacity + opacity: page.effectiveOpacity } - Rectangle { color: "#6400aa"; width: smallSize; height: smallSize } + Rectangle { color: "#6400aa"; width: page.smallSize; height: page.smallSize } Rectangle { id: greenF3 visible: opacity != 0 - width: 0.4 * bigSize; height: smallSize + width: 0.4 * page.bigSize; height: page.smallSize color: "#006325" border.color: "transparent" Behavior on opacity { NumberAnimation {} } - opacity: effectiveOpacity + opacity: page.effectiveOpacity } - Rectangle { color: "#80c342"; width: 0.8 * bigSize; height: smallSize } + Rectangle { color: "#80c342"; width: 0.8 * page.bigSize; height: page.smallSize } } } From fccbc89125852f9d8679f7ae8d201a67619f6066 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 16 Nov 2016 14:29:32 +0100 Subject: [PATCH 28/33] QML: Add another specialization for QQmlPropertyCache::property QQmlListReference passes a QLatin1String in, which can behandled by the stringCache just fine. So if there is a cache entry, then this will skip toQString conversion. Change-Id: I13afe4f6e63d486b313ac58cbd86fb7f9e1a80f6 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlpropertycache.cpp | 7 +++++++ src/qml/qml/qqmlpropertycache_p.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 2610a807b5..a110dccee2 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -1096,6 +1096,13 @@ QQmlPropertyCache::property(QJSEngine *engine, QObject *obj, return qQmlPropertyCacheProperty(engine, obj, name, context, local); } +QQmlPropertyData * +QQmlPropertyCache::property(QJSEngine *engine, QObject *obj, const QLatin1String &name, + QQmlContextData *context, QQmlPropertyData &local) +{ + return qQmlPropertyCacheProperty(engine, obj, name, context, local); +} + // these two functions are copied from qmetaobject.cpp static inline const QMetaObjectPrivate *priv(const uint* data) { return reinterpret_cast(data); } diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 6281b9c05e..60414188a5 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -408,6 +408,8 @@ public: static QQmlPropertyData *property(QJSEngine *, QObject *, const QString &, QQmlContextData *, QQmlPropertyData &); + static QQmlPropertyData *property(QJSEngine *, QObject *, const QLatin1String &, + QQmlContextData *, QQmlPropertyData &); static QQmlPropertyData *property(QJSEngine *, QObject *, const QV4::String *, QQmlContextData *, QQmlPropertyData &); From 584c90df98891d5ab7d62ef09f63986ab91dfc6b Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 18 Nov 2016 14:02:59 +0100 Subject: [PATCH 29/33] QSGRendererInterface: Add Resource suffix for consistency Change-Id: I60e674760725d4c4dd13f53b31c3abb6b09c1790 Reviewed-by: Simon Hausmann --- examples/quick/scenegraph/rendernode/d3d12renderer.cpp | 5 +++-- examples/quick/scenegraph/rendernode/softwarerenderer.cpp | 2 +- src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp | 6 +++--- .../adaptations/software/qsgsoftwarecontext.cpp | 2 +- src/quick/scenegraph/coreapi/qsgrendererinterface.cpp | 8 ++++---- src/quick/scenegraph/coreapi/qsgrendererinterface.h | 8 ++++---- 6 files changed, 16 insertions(+), 15 deletions(-) diff --git a/examples/quick/scenegraph/rendernode/d3d12renderer.cpp b/examples/quick/scenegraph/rendernode/d3d12renderer.cpp index 3b377f1cb1..72ebfe869e 100644 --- a/examples/quick/scenegraph/rendernode/d3d12renderer.cpp +++ b/examples/quick/scenegraph/rendernode/d3d12renderer.cpp @@ -78,7 +78,7 @@ void D3D12RenderNode::releaseResources() void D3D12RenderNode::init() { QSGRendererInterface *rif = m_item->window()->rendererInterface(); - m_device = static_cast(rif->getResource(m_item->window(), QSGRendererInterface::Device)); + m_device = static_cast(rif->getResource(m_item->window(), QSGRendererInterface::DeviceResource)); Q_ASSERT(m_device); D3D12_ROOT_PARAMETER rootParameter; @@ -235,7 +235,8 @@ void D3D12RenderNode::render(const RenderState *state) init(); QSGRendererInterface *rif = m_item->window()->rendererInterface(); - ID3D12GraphicsCommandList *commandList = static_cast(rif->getResource(m_item->window(), QSGRendererInterface::CommandList)); + ID3D12GraphicsCommandList *commandList = static_cast( + rif->getResource(m_item->window(), QSGRendererInterface::CommandListResource)); Q_ASSERT(commandList); const int msize = 16 * sizeof(float); diff --git a/examples/quick/scenegraph/rendernode/softwarerenderer.cpp b/examples/quick/scenegraph/rendernode/softwarerenderer.cpp index 06e406874a..d303b9ef13 100644 --- a/examples/quick/scenegraph/rendernode/softwarerenderer.cpp +++ b/examples/quick/scenegraph/rendernode/softwarerenderer.cpp @@ -61,7 +61,7 @@ void SoftwareRenderNode::releaseResources() void SoftwareRenderNode::render(const RenderState *renderState) { QSGRendererInterface *rif = m_item->window()->rendererInterface(); - QPainter *p = static_cast(rif->getResource(m_item->window(), QSGRendererInterface::Painter)); + QPainter *p = static_cast(rif->getResource(m_item->window(), QSGRendererInterface::PainterResource)); Q_ASSERT(p); p->setTransform(matrix()->toTransform()); diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp index a318ce23f7..44f79ebea7 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp @@ -3236,11 +3236,11 @@ void QSGD3D12EnginePrivate::DeviceLossTester::killDevice() void *QSGD3D12EnginePrivate::getResource(QSGRendererInterface::Resource resource) const { switch (resource) { - case QSGRendererInterface::Device: + case QSGRendererInterface::DeviceResource: return device; - case QSGRendererInterface::CommandQueue: + case QSGRendererInterface::CommandQueueResource: return commandQueue.Get(); - case QSGRendererInterface::CommandList: + case QSGRendererInterface::CommandListResource: return commandList; default: break; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp index 05d5daa686..d71b0c3e2a 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp @@ -215,7 +215,7 @@ QSGRendererInterface::ShaderSourceTypes QSGSoftwareContext::shaderSourceType() c void *QSGSoftwareContext::getResource(QQuickWindow *window, Resource resource) const { - if (resource == Painter && window && window->isSceneGraphInitialized()) + if (resource == PainterResource && window && window->isSceneGraphInitialized()) return static_cast(QQuickWindowPrivate::get(window)->context)->m_activePainter; return nullptr; diff --git a/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp index fa543aecad..d309044e8f 100644 --- a/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp +++ b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp @@ -81,10 +81,10 @@ QT_BEGIN_NAMESPACE /*! \enum QSGRendererInterface::Resource - \value Device The graphics device, when applicable. - \value CommandQueue The graphics command queue used by the scenegraph, when applicable. - \value CommandList The command list or buffer used by the scenegraph, when applicable. - \value Painter The active QPainter used by the scenegraph, when running with the software backend. + \value DeviceResource The graphics device, when applicable. + \value CommandQueueResource The graphics command queue used by the scenegraph, when applicable. + \value CommandListResource The command list or buffer used by the scenegraph, when applicable. + \value PainterResource The active QPainter used by the scenegraph, when running with the software backend. */ /*! diff --git a/src/quick/scenegraph/coreapi/qsgrendererinterface.h b/src/quick/scenegraph/coreapi/qsgrendererinterface.h index a50b362aeb..cf8fcf9015 100644 --- a/src/quick/scenegraph/coreapi/qsgrendererinterface.h +++ b/src/quick/scenegraph/coreapi/qsgrendererinterface.h @@ -57,10 +57,10 @@ public: }; enum Resource { - Device, - CommandQueue, - CommandList, - Painter + DeviceResource, + CommandQueueResource, + CommandListResource, + PainterResource }; enum ShaderType { From 5b2c71877a34597b82d2ce81494b9e91c7e31cb8 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Tue, 15 Nov 2016 18:18:26 +0100 Subject: [PATCH 30/33] QSGDistanceFieldUtil: Make use of the newly added QRawFont qHash function Relies on qtbase/094b64fb605b39d1ae88d91d2b9a0672b9ff4780. This was previously responsible for around 1.1% of CPU samples when profiling text creation & rendering under qmlbench. Change-Id: I287067b994231a39881ba8208ad3b802233c7486 Reviewed-by: Gunnar Sletta --- .../scenegraph/util/qsgdistancefieldutil.cpp | 24 ++----------------- .../scenegraph/util/qsgdistancefieldutil_p.h | 4 +--- 2 files changed, 3 insertions(+), 25 deletions(-) diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp b/src/quick/scenegraph/util/qsgdistancefieldutil.cpp index 65a6bcd52c..79e43e3820 100644 --- a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp +++ b/src/quick/scenegraph/util/qsgdistancefieldutil.cpp @@ -84,32 +84,12 @@ QSGDistanceFieldGlyphCacheManager::~QSGDistanceFieldGlyphCacheManager() QSGDistanceFieldGlyphCache *QSGDistanceFieldGlyphCacheManager::cache(const QRawFont &font) { - return m_caches.value(fontKey(font), 0); + return m_caches.value(font, 0); } void QSGDistanceFieldGlyphCacheManager::insertCache(const QRawFont &font, QSGDistanceFieldGlyphCache *cache) { - m_caches.insert(fontKey(font), cache); -} - -QString QSGDistanceFieldGlyphCacheManager::fontKey(const QRawFont &font) -{ - QFontEngine *fe = QRawFontPrivate::get(font)->fontEngine; - if (!fe->faceId().filename.isEmpty()) { - QByteArray keyName = fe->faceId().filename; - if (font.style() != QFont::StyleNormal) - keyName += QByteArray(" I"); - if (font.weight() != QFont::Normal) - keyName += ' ' + QByteArray::number(font.weight()); - keyName += QByteArray(" DF"); - return QString::fromUtf8(keyName); - } else { - return QString::fromLatin1("%1_%2_%3_%4") - .arg(font.familyName()) - .arg(font.styleName()) - .arg(font.weight()) - .arg(font.style()); - } + m_caches.insert(font, cache); } QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil_p.h b/src/quick/scenegraph/util/qsgdistancefieldutil_p.h index 354a48a81e..ad366cb4d4 100644 --- a/src/quick/scenegraph/util/qsgdistancefieldutil_p.h +++ b/src/quick/scenegraph/util/qsgdistancefieldutil_p.h @@ -80,9 +80,7 @@ public: void setAntialiasingSpreadFunc(AntialiasingSpreadFunc func) { m_antialiasingSpread_func = func; } private: - static QString fontKey(const QRawFont &font); - - QHash m_caches; + QHash m_caches; ThresholdFunc m_threshold_func; AntialiasingSpreadFunc m_antialiasingSpread_func; From ffcfc9099be1425009eda3afe9e5057b73070b66 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 21 Nov 2016 13:44:10 +0100 Subject: [PATCH 31/33] rendernode example: do not rely on build-time shader compilation There is no public intrastructure for this. Relying on the internal qmake rule in qtdeclarative is wrong as it is not meant for public consumption and is not available in out of tree examples in the installed Qt anyway. Instead, ship the bytecode for now. Task-number: QTBUG-56327 Change-Id: I19327aa880ad573560d1e9376f36c67aa509b51a Reviewed-by: Andy Nichols --- .../scenegraph/rendernode/d3d12renderer.cpp | 25 +++++++++++++----- .../scenegraph/rendernode/rendernode.pro | 16 +---------- .../scenegraph/rendernode/rendernode.qrc | 2 ++ .../scenegraph/rendernode/shader_frag.cso | Bin 0 -> 908 bytes .../scenegraph/rendernode/shader_vert.cso | Bin 0 -> 1720 bytes 5 files changed, 21 insertions(+), 22 deletions(-) create mode 100644 examples/quick/scenegraph/rendernode/shader_frag.cso create mode 100644 examples/quick/scenegraph/rendernode/shader_vert.cso diff --git a/examples/quick/scenegraph/rendernode/d3d12renderer.cpp b/examples/quick/scenegraph/rendernode/d3d12renderer.cpp index 72ebfe869e..9916769241 100644 --- a/examples/quick/scenegraph/rendernode/d3d12renderer.cpp +++ b/examples/quick/scenegraph/rendernode/d3d12renderer.cpp @@ -42,12 +42,10 @@ #include #include #include +#include #if QT_CONFIG(d3d12) -#include "vs_shader.hlslh" -#include "ps_shader.hlslh" - D3D12RenderNode::D3D12RenderNode(QQuickItem *item) : m_item(item) { @@ -111,12 +109,25 @@ void D3D12RenderNode::init() { "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 8, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; + QFile f(QStringLiteral(":/scenegraph/rendernode/shader_vert.cso")); + if (!f.open(QIODevice::ReadOnly)) { + qWarning("Failed to open file with vertex shader bytecode"); + return; + } + QByteArray vshader_cso = f.readAll(); + f.close(); + f.setFileName(QStringLiteral(":/scenegraph/rendernode/shader_frag.cso")); + if (!f.open(QIODevice::ReadOnly)) { + qWarning("Failed to open file with fragment shader bytecode"); + return; + } + QByteArray fshader_cso = f.readAll(); D3D12_SHADER_BYTECODE vshader; - vshader.pShaderBytecode = g_VS_Simple; - vshader.BytecodeLength = sizeof(g_VS_Simple); + vshader.pShaderBytecode = vshader_cso.constData(); + vshader.BytecodeLength = vshader_cso.size(); D3D12_SHADER_BYTECODE pshader; - pshader.pShaderBytecode = g_PS_Simple; - pshader.BytecodeLength = sizeof(g_PS_Simple); + pshader.pShaderBytecode = fshader_cso.constData(); + pshader.BytecodeLength = fshader_cso.size(); D3D12_RASTERIZER_DESC rastDesc = {}; rastDesc.FillMode = D3D12_FILL_MODE_SOLID; diff --git a/examples/quick/scenegraph/rendernode/rendernode.pro b/examples/quick/scenegraph/rendernode/rendernode.pro index 968902a5be..76e498042b 100644 --- a/examples/quick/scenegraph/rendernode/rendernode.pro +++ b/examples/quick/scenegraph/rendernode/rendernode.pro @@ -15,24 +15,10 @@ target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/rendernode INSTALLS += target OTHER_FILES += \ - main.qml \ - shader.hlsl + main.qml qtConfig(d3d12) { HEADERS += d3d12renderer.h SOURCES += d3d12renderer.cpp LIBS += -ld3d12 - - VSPS = shader.hlsl - vshader.input = VSPS - vshader.header = vs_shader.hlslh - vshader.entry = VS_Simple - vshader.type = vs_5_0 - pshader.input = VSPS - pshader.header = ps_shader.hlslh - pshader.entry = PS_Simple - pshader.type = ps_5_0 - - HLSL_SHADERS = vshader pshader - load(hlsl_bytecode_header) } diff --git a/examples/quick/scenegraph/rendernode/rendernode.qrc b/examples/quick/scenegraph/rendernode/rendernode.qrc index 3674baccd8..049adcf8a6 100644 --- a/examples/quick/scenegraph/rendernode/rendernode.qrc +++ b/examples/quick/scenegraph/rendernode/rendernode.qrc @@ -1,5 +1,7 @@ main.qml + shader_vert.cso + shader_frag.cso diff --git a/examples/quick/scenegraph/rendernode/shader_frag.cso b/examples/quick/scenegraph/rendernode/shader_frag.cso new file mode 100644 index 0000000000000000000000000000000000000000..686c6af3fcdb185f027e74d8ea9b425f1ec944bc GIT binary patch literal 908 zcmb`F%}T>S5XYxhZ3WTb$%BVQL=;6V6!9S1+AoXMlq86PptYtnQoAL_uUioh3L+vN z1s@bfR7;_MX3KtS}3S^@ejYu?(EEDW|QRlVq)lNaANfGc{%*@@bS2OD*{Ax z6(s6{je=J=COe3>!5h$$sq{U399IEs=Kysz8oY6UmW)K$HwXk610$dpur_`3?a8&6 zgsdJog{rf7SSpz|xg3v{=p5XDmOh({Sko$;3^ky38-+gx2gCX;ZUJ$1oOc3@O8H;v z?aN)Wa%7puRI12=6FrHN8$^elUM3QMP&aDTY`JF^9ZOb8)(S<-IrR&W>$*H)z?=Su zWVkZOU$Kg|JdhPXzPm2?(7S_qjHerM;|_cNzFeEdchp+*zJ1O6zr^|fp)bV!aaI5T literal 0 HcmV?d00001 diff --git a/examples/quick/scenegraph/rendernode/shader_vert.cso b/examples/quick/scenegraph/rendernode/shader_vert.cso new file mode 100644 index 0000000000000000000000000000000000000000..fa13be516062d61ef0ecb978163d4bbe594ae23b GIT binary patch literal 1720 zcmb7EO-~b16ulK_AsT6n8e>d+3m0`ETGAL61c83gn#zz)Z7?w*O_|D&(rJcKG%<#S zZd|Af7bd!9;l!N_e}G%}{sMnM7p#nU?t6V@7@!|7Iq%(f=e*N<-koV?buqp3Fng=~ z?fa{*pQmom-T(D7LPS5JL}OS}z;7fHXNX<`*N`t|vbitFF|PseIt$R)zXRTQKq-?< za_$NsfCO*@I0x`}td?UlYcbMJbK9#ny~U^Xy5*A3{1ME8;2eck%XK!b znrAyra$41z?Y&R}q&OfkguCwjbJ&`Eg6#1fA6y`>C-Eu|R*=pGh z1j##7Nh+92%Xu7Suj9bXp^Uso-cC*uErjxHHx`3$!z`2w#xkXiqERB>fL;;L!g|c- zzVLt?Wn`o#&PzQMU{=<`lD?VGu6_b(1*|{dZjMvr5w1S>PDlZ+dkymKcwFu|b`i7Y z6Y$zX<#})MGweCuK$%=8JWsSqaVl>FGO8Y}&+qp%(OJ#WdG395S77e&&nu0SxcD4s z@2y~}{Ow#1F0PgK-wUQ5;iAr1w}#I7$|d!i+5`L29{9YjHRypkIv?~P`OxL(+Cz{V z^w5tR^bq29@0#y`^`o7>={q^e3-?LaJct*`AJ9ubZqQ4Jd(6w;Rn?DPUif_<#*5?+ z=%pVw=q1FR(BFyf%l`GFUhd+bTYo#b3#xZ>cty?fLir;+T?Y7mc<_65QATRwJ`Xd7 I<)5bgA8c8+umAu6 literal 0 HcmV?d00001 From 39bed6135cd08b346866bb35ac95eaaf6f69b95c Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 22 Nov 2016 15:47:22 +0100 Subject: [PATCH 32/33] Add a missing break statement Converting a constant to null or undefined shouldn't happen in practice, but it still shouldn't run into the Q_UNIMPLEMENTED. Change-Id: I994a55defd7f4e29628732a8a9071bc785a80ee2 Reviewed-by: Erik Verbruggen --- src/qml/compiler/qv4ssa.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 4111cc77db..3bcc231696 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -2692,6 +2692,7 @@ void convertConst(Const *c, Type targetType) case UndefinedType: c->value = qt_qnan(); c->type = targetType; + break; default: Q_UNIMPLEMENTED(); Q_ASSERT(!"Unimplemented!"); From 07cde200e55ee03bf9e2f9af89c20f91072deccc Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 22 Nov 2016 13:29:55 +0100 Subject: [PATCH 33/33] Move rebuildGeometry() functions of nodes Move QSGDefaultImageNode::rebuildGeometry(), QSGDefaultNinePatchNode::rebuildGeometry() to QSGImageNode::rebuildGeometry(), QSGNinePatchNode::rebuildGeometry() respectively. This makes it possible to use then from the D3D12 plugin when built without OpenGL support. Task-number: QTBUG-57185 Change-Id: Ib88c5622f7048618151a63d7536d76296a25842e Reviewed-by: Laszlo Agocs --- .../scenegraph/d3d12/qsgd3d12publicnodes.cpp | 14 ++--- .../scenegraph/util/qsgdefaultimagenode.cpp | 29 ----------- .../scenegraph/util/qsgdefaultimagenode_p.h | 6 --- .../util/qsgdefaultninepatchnode.cpp | 52 ------------------- .../util/qsgdefaultninepatchnode_p.h | 3 -- src/quick/scenegraph/util/qsgimagenode.cpp | 29 +++++++++++ src/quick/scenegraph/util/qsgimagenode.h | 6 +++ .../scenegraph/util/qsgninepatchnode.cpp | 52 +++++++++++++++++++ src/quick/scenegraph/util/qsgninepatchnode.h | 4 ++ 9 files changed, 96 insertions(+), 99 deletions(-) diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12publicnodes.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12publicnodes.cpp index 783caa280f..1f01c440e5 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12publicnodes.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12publicnodes.cpp @@ -39,10 +39,6 @@ #include "qsgd3d12publicnodes_p.h" -// for rebuildGeometry -#include -#include - QT_BEGIN_NAMESPACE QSGD3D12RectangleNode::QSGD3D12RectangleNode() @@ -138,7 +134,7 @@ void QSGD3D12ImageNode::setRect(const QRectF &r) return; m_rect = r; - QSGDefaultImageNode::rebuildGeometry(&m_geometry, texture(), m_rect, m_sourceRect, m_texCoordMode); + QSGImageNode::rebuildGeometry(&m_geometry, texture(), m_rect, m_sourceRect, m_texCoordMode); markDirty(DirtyGeometry); } @@ -153,7 +149,7 @@ void QSGD3D12ImageNode::setSourceRect(const QRectF &r) return; m_sourceRect = r; - QSGDefaultImageNode::rebuildGeometry(&m_geometry, texture(), m_rect, m_sourceRect, m_texCoordMode); + QSGImageNode::rebuildGeometry(&m_geometry, texture(), m_rect, m_sourceRect, m_texCoordMode); markDirty(DirtyGeometry); } @@ -170,7 +166,7 @@ void QSGD3D12ImageNode::setTexture(QSGTexture *texture) delete m_material.texture(); m_material.setTexture(texture); - QSGDefaultImageNode::rebuildGeometry(&m_geometry, texture, m_rect, m_sourceRect, m_texCoordMode); + QSGImageNode::rebuildGeometry(&m_geometry, texture, m_rect, m_sourceRect, m_texCoordMode); DirtyState dirty = DirtyMaterial; const bool wasAtlas = m_isAtlasTexture; @@ -192,7 +188,7 @@ void QSGD3D12ImageNode::setTextureCoordinatesTransform(TextureCoordinatesTransfo return; m_texCoordMode = mode; - QSGDefaultImageNode::rebuildGeometry(&m_geometry, texture(), m_rect, m_sourceRect, m_texCoordMode); + QSGImageNode::rebuildGeometry(&m_geometry, texture(), m_rect, m_sourceRect, m_texCoordMode); markDirty(DirtyMaterial); } @@ -247,7 +243,7 @@ void QSGD3D12NinePatchNode::setPadding(qreal left, qreal top, qreal right, qreal void QSGD3D12NinePatchNode::update() { - QSGDefaultNinePatchNode::rebuildGeometry(m_material.texture(), &m_geometry, m_padding, m_bounds, m_devicePixelRatio); + QSGNinePatchNode::rebuildGeometry(m_material.texture(), &m_geometry, m_padding, m_bounds, m_devicePixelRatio); markDirty(QSGNode::DirtyGeometry | QSGNode::DirtyMaterial); } diff --git a/src/quick/scenegraph/util/qsgdefaultimagenode.cpp b/src/quick/scenegraph/util/qsgdefaultimagenode.cpp index 6afe591dca..63773887a0 100644 --- a/src/quick/scenegraph/util/qsgdefaultimagenode.cpp +++ b/src/quick/scenegraph/util/qsgdefaultimagenode.cpp @@ -173,33 +173,4 @@ bool QSGDefaultImageNode::ownsTexture() const return m_ownsTexture; } -void QSGDefaultImageNode::rebuildGeometry(QSGGeometry *g, - QSGTexture *texture, - const QRectF &rect, - QRectF sourceRect, - TextureCoordinatesTransformMode texCoordMode) -{ - if (!texture) - return; - - if (!sourceRect.width() || !sourceRect.height()) { - QSize ts = texture->textureSize(); - sourceRect = QRectF(0, 0, ts.width(), ts.height()); - } - - // Maybe transform the texture coordinates - if (texCoordMode.testFlag(QSGImageNode::MirrorHorizontally)) { - float tmp = sourceRect.left(); - sourceRect.setLeft(sourceRect.right()); - sourceRect.setRight(tmp); - } - if (texCoordMode.testFlag(QSGImageNode::MirrorVertically)) { - float tmp = sourceRect.top(); - sourceRect.setTop(sourceRect.bottom()); - sourceRect.setBottom(tmp); - } - - QSGGeometry::updateTexturedRectGeometry(g, rect, texture->convertToNormalizedSourceRect(sourceRect)); -} - QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgdefaultimagenode_p.h b/src/quick/scenegraph/util/qsgdefaultimagenode_p.h index eb6c487c18..bb9ebec885 100644 --- a/src/quick/scenegraph/util/qsgdefaultimagenode_p.h +++ b/src/quick/scenegraph/util/qsgdefaultimagenode_p.h @@ -85,12 +85,6 @@ public: void setOwnsTexture(bool owns) override; bool ownsTexture() const override; - static void rebuildGeometry(QSGGeometry *g, - QSGTexture *texture, - const QRectF &rect, - QRectF sourceRect, - TextureCoordinatesTransformMode texCoordMode); - private: QSGGeometry m_geometry; QSGOpaqueTextureMaterial m_opaque_material; diff --git a/src/quick/scenegraph/util/qsgdefaultninepatchnode.cpp b/src/quick/scenegraph/util/qsgdefaultninepatchnode.cpp index e5a53a3617..6023a9af93 100644 --- a/src/quick/scenegraph/util/qsgdefaultninepatchnode.cpp +++ b/src/quick/scenegraph/util/qsgdefaultninepatchnode.cpp @@ -81,56 +81,4 @@ void QSGDefaultNinePatchNode::update() markDirty(QSGNode::DirtyGeometry | QSGNode::DirtyMaterial); } -void QSGDefaultNinePatchNode::rebuildGeometry(QSGTexture *texture, QSGGeometry *geometry, const QVector4D &padding, - const QRectF &bounds, qreal dpr) -{ - if (padding.x() <= 0 && padding.y() <= 0 && padding.z() <= 0 && padding.w() <= 0) { - geometry->allocate(4, 0); - QSGGeometry::updateTexturedRectGeometry(geometry, bounds, texture->normalizedTextureSubRect()); - return; - } - - QRectF tc = texture->normalizedTextureSubRect(); - QSize ts = texture->textureSize(); - ts.setHeight(ts.height() / dpr); - ts.setWidth(ts.width() / dpr); - - qreal invtw = tc.width() / ts.width(); - qreal invth = tc.height() / ts.height(); - - struct Coord { qreal p; qreal t; }; - Coord cx[4] = { { bounds.left(), tc.left() }, - { bounds.left() + padding.x(), tc.left() + padding.x() * invtw }, - { bounds.right() - padding.z(), tc.right() - padding.z() * invtw }, - { bounds.right(), tc.right() } - }; - Coord cy[4] = { { bounds.top(), tc.top() }, - { bounds.top() + padding.y(), tc.top() + padding.y() * invth }, - { bounds.bottom() - padding.w(), tc.bottom() - padding.w() * invth }, - { bounds.bottom(), tc.bottom() } - }; - - geometry->allocate(16, 28); - QSGGeometry::TexturedPoint2D *v = geometry->vertexDataAsTexturedPoint2D(); - for (int y = 0; y < 4; ++y) { - for (int x = 0; x < 4; ++x) { - v->set(cx[x].p, cy[y].p, cx[x].t, cy[y].t); - ++v; - } - } - - quint16 *i = geometry->indexDataAsUShort(); - for (int r = 0; r < 3; ++r) { - if (r > 0) - *i++ = 4 * r; - for (int c = 0; c < 4; ++c) { - i[0] = 4 * r + c; - i[1] = 4 * r + c + 4; - i += 2; - } - if (r < 2) - *i++ = 4 * r + 3 + 4; - } -} - QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgdefaultninepatchnode_p.h b/src/quick/scenegraph/util/qsgdefaultninepatchnode_p.h index 675cf48f47..3752a75ac6 100644 --- a/src/quick/scenegraph/util/qsgdefaultninepatchnode_p.h +++ b/src/quick/scenegraph/util/qsgdefaultninepatchnode_p.h @@ -70,9 +70,6 @@ public: void setPadding(qreal left, qreal top, qreal right, qreal bottom) override; void update() override; - static void rebuildGeometry(QSGTexture *texture, QSGGeometry *geometry, const QVector4D &padding, - const QRectF &bounds, qreal dpr); - private: QRectF m_bounds; qreal m_devicePixelRatio; diff --git a/src/quick/scenegraph/util/qsgimagenode.cpp b/src/quick/scenegraph/util/qsgimagenode.cpp index a78bfc1c66..c03c91d1cb 100644 --- a/src/quick/scenegraph/util/qsgimagenode.cpp +++ b/src/quick/scenegraph/util/qsgimagenode.cpp @@ -187,4 +187,33 @@ QT_BEGIN_NAMESPACE \return \c true if the node takes ownership of the texture; otherwise \c false. */ +void QSGImageNode::rebuildGeometry(QSGGeometry *g, + QSGTexture *texture, + const QRectF &rect, + QRectF sourceRect, + TextureCoordinatesTransformMode texCoordMode) +{ + if (!texture) + return; + + if (!sourceRect.width() || !sourceRect.height()) { + QSize ts = texture->textureSize(); + sourceRect = QRectF(0, 0, ts.width(), ts.height()); + } + + // Maybe transform the texture coordinates + if (texCoordMode.testFlag(QSGImageNode::MirrorHorizontally)) { + float tmp = sourceRect.left(); + sourceRect.setLeft(sourceRect.right()); + sourceRect.setRight(tmp); + } + if (texCoordMode.testFlag(QSGImageNode::MirrorVertically)) { + float tmp = sourceRect.top(); + sourceRect.setTop(sourceRect.bottom()); + sourceRect.setBottom(tmp); + } + + QSGGeometry::updateTexturedRectGeometry(g, rect, texture->convertToNormalizedSourceRect(sourceRect)); +} + QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgimagenode.h b/src/quick/scenegraph/util/qsgimagenode.h index 7eab42c4e6..d25e732e4b 100644 --- a/src/quick/scenegraph/util/qsgimagenode.h +++ b/src/quick/scenegraph/util/qsgimagenode.h @@ -79,6 +79,12 @@ public: virtual void setOwnsTexture(bool owns) = 0; virtual bool ownsTexture() const = 0; + + static void rebuildGeometry(QSGGeometry *g, + QSGTexture *texture, + const QRectF &rect, + QRectF sourceRect, + TextureCoordinatesTransformMode texCoordMode); }; Q_DECLARE_OPERATORS_FOR_FLAGS(QSGImageNode::TextureCoordinatesTransformMode) diff --git a/src/quick/scenegraph/util/qsgninepatchnode.cpp b/src/quick/scenegraph/util/qsgninepatchnode.cpp index 9c167ca76f..33568b5488 100644 --- a/src/quick/scenegraph/util/qsgninepatchnode.cpp +++ b/src/quick/scenegraph/util/qsgninepatchnode.cpp @@ -74,4 +74,56 @@ QT_BEGIN_NAMESPACE \internal */ +void QSGNinePatchNode::rebuildGeometry(QSGTexture *texture, QSGGeometry *geometry, const QVector4D &padding, + const QRectF &bounds, qreal dpr) +{ + if (padding.x() <= 0 && padding.y() <= 0 && padding.z() <= 0 && padding.w() <= 0) { + geometry->allocate(4, 0); + QSGGeometry::updateTexturedRectGeometry(geometry, bounds, texture->normalizedTextureSubRect()); + return; + } + + QRectF tc = texture->normalizedTextureSubRect(); + QSize ts = texture->textureSize(); + ts.setHeight(ts.height() / dpr); + ts.setWidth(ts.width() / dpr); + + qreal invtw = tc.width() / ts.width(); + qreal invth = tc.height() / ts.height(); + + struct Coord { qreal p; qreal t; }; + Coord cx[4] = { { bounds.left(), tc.left() }, + { bounds.left() + padding.x(), tc.left() + padding.x() * invtw }, + { bounds.right() - padding.z(), tc.right() - padding.z() * invtw }, + { bounds.right(), tc.right() } + }; + Coord cy[4] = { { bounds.top(), tc.top() }, + { bounds.top() + padding.y(), tc.top() + padding.y() * invth }, + { bounds.bottom() - padding.w(), tc.bottom() - padding.w() * invth }, + { bounds.bottom(), tc.bottom() } + }; + + geometry->allocate(16, 28); + QSGGeometry::TexturedPoint2D *v = geometry->vertexDataAsTexturedPoint2D(); + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + v->set(cx[x].p, cy[y].p, cx[x].t, cy[y].t); + ++v; + } + } + + quint16 *i = geometry->indexDataAsUShort(); + for (int r = 0; r < 3; ++r) { + if (r > 0) + *i++ = 4 * r; + for (int c = 0; c < 4; ++c) { + i[0] = 4 * r + c; + i[1] = 4 * r + c + 4; + i += 2; + } + if (r < 2) + *i++ = 4 * r + 3 + 4; + } +} + QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgninepatchnode.h b/src/quick/scenegraph/util/qsgninepatchnode.h index 8677a432ba..8509cbd326 100644 --- a/src/quick/scenegraph/util/qsgninepatchnode.h +++ b/src/quick/scenegraph/util/qsgninepatchnode.h @@ -55,6 +55,10 @@ public: virtual void setDevicePixelRatio(qreal ratio) = 0; virtual void setPadding(qreal left, qreal top, qreal right, qreal bottom) = 0; virtual void update() = 0; + + static void rebuildGeometry(QSGTexture *texture, QSGGeometry *geometry, + const QVector4D &padding, + const QRectF &bounds, qreal dpr); }; QT_END_NAMESPACE