From 388f9b151245ae194a0a9175da7cc70ce534e6e6 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Sat, 13 Jan 2018 19:32:22 +0100 Subject: QQuickItem::stackBefore/After: print more useful warnings Before this patch, you'd get the following warning: QQuickItem::stackAfter: Cannot stack after 0x7f9e668368c0, which must be a sibling After this patch, you get this warning: QQuickItem::stackAfter: Cannot stack QQuickItem_QML_131(0x7ff548f44d70, name="hoverPathDelegate", parent=0x7ff54a871c90, geometry=0,0 0x0) after QQuickItem_QML_131(0x7ff548f3c8f0, name = "hoverPathDelegate"), which must be a sibling This tells you which type caused the warning, and, if you've set it, its objectName. Change-Id: I7b20f1ac089f42d73f02bcca0382022905d0cb57 Reviewed-by: Shawn Rutledge --- src/quick/items/qquickitem.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index af60ab879b..8499c37010 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2805,7 +2805,8 @@ void QQuickItem::stackBefore(const QQuickItem *sibling) { Q_D(QQuickItem); if (!sibling || sibling == this || !d->parentItem || d->parentItem != QQuickItemPrivate::get(sibling)->parentItem) { - qWarning("QQuickItem::stackBefore: Cannot stack before %p, which must be a sibling", sibling); + qWarning().nospace() << "QQuickItem::stackBefore: Cannot stack " + << this << " before " << sibling << ", which must be a sibling"; return; } @@ -2849,7 +2850,8 @@ void QQuickItem::stackAfter(const QQuickItem *sibling) { Q_D(QQuickItem); if (!sibling || sibling == this || !d->parentItem || d->parentItem != QQuickItemPrivate::get(sibling)->parentItem) { - qWarning("QQuickItem::stackAfter: Cannot stack after %p, which must be a sibling", sibling); + qWarning().nospace() << "QQuickItem::stackAfter: Cannot stack " + << this << " after " << sibling << ", which must be a sibling"; return; } -- cgit v1.2.3 From eec58534ab9c3fae74a1b4cb0861d4b40253cd2d Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 10 Jan 2018 13:51:23 +0100 Subject: Fix segfault when alias target refers to lowercase-named type Create an error via QQmlCompileError and return it instead of asserting. Task-number: QTBUG-43567 Change-Id: I0c0741943d30516379eff5f44ed8618a0f0116a4 Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmlpropertycachecreator_p.h | 27 ++++++++++++++++++--------- src/qml/compiler/qqmltypecompiler.cpp | 6 +++++- 2 files changed, 23 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qqmlpropertycachecreator_p.h b/src/qml/compiler/qqmlpropertycachecreator_p.h index 22e83de9ae..8743a57d7a 100644 --- a/src/qml/compiler/qqmlpropertycachecreator_p.h +++ b/src/qml/compiler/qqmlpropertycachecreator_p.h @@ -536,11 +536,11 @@ public: void appendAliasPropertiesToMetaObjects(); - void appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex); + QQmlCompileError appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex); private: void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex); - void propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, QQmlPropertyRawData::Flags *propertyFlags); + QQmlCompileError propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, QQmlPropertyRawData::Flags *propertyFlags); void collectObjectsWithAliasesRecursively(int objectIndex, QVector *objectsWithAliases) const; @@ -651,7 +651,7 @@ inline void QQmlPropertyCacheAliasCreator::collectObjectsWithAl } template -inline void QQmlPropertyCacheAliasCreator::propertyDataForAlias( +inline QQmlCompileError QQmlPropertyCacheAliasCreator::propertyDataForAlias( const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, QQmlPropertyData::Flags *propertyFlags) { @@ -670,12 +670,16 @@ inline void QQmlPropertyCacheAliasCreator::propertyDataForAlias auto targetAlias = targetObject.aliasesBegin(); for (uint i = 0; i < alias.localAliasIndex; ++i) ++targetAlias; - propertyDataForAlias(component, *targetAlias, type, propertyFlags); - return; + return propertyDataForAlias(component, *targetAlias, type, propertyFlags); } else if (alias.encodedMetaPropertyIndex == -1) { Q_ASSERT(alias.flags & QV4::CompiledData::Alias::AliasPointsToPointerObject); auto *typeRef = objectContainer->resolvedTypes.value(targetObject.inheritedTypeNameIndex); - Q_ASSERT(typeRef); + if (!typeRef) { + // Can be caused by the alias target not being a valid id or property. E.g.: + // property alias dataValue: dataVal + // invalidAliasComponent { id: dataVal } + return QQmlCompileError(targetObject.location, QQmlPropertyCacheCreatorBase::tr("Invalid alias target")); + } if (typeRef->type.isValid()) *type = typeRef->type.typeId(); @@ -718,15 +722,16 @@ inline void QQmlPropertyCacheAliasCreator::propertyDataForAlias propertyFlags->isWritable = !(alias.flags & QV4::CompiledData::Property::IsReadOnly) && writable; propertyFlags->isResettable = resettable; + return QQmlCompileError(); } template -inline void QQmlPropertyCacheAliasCreator::appendAliasesToPropertyCache( +inline QQmlCompileError QQmlPropertyCacheAliasCreator::appendAliasesToPropertyCache( const CompiledObject &component, int objectIndex) { const CompiledObject &object = *objectContainer->objectAt(objectIndex); if (!object.aliasCount()) - return; + return QQmlCompileError(); QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex); Q_ASSERT(propertyCache); @@ -742,7 +747,9 @@ inline void QQmlPropertyCacheAliasCreator::appendAliasesToPrope int type = 0; QQmlPropertyData::Flags propertyFlags; - propertyDataForAlias(component, *alias, &type, &propertyFlags); + QQmlCompileError error = propertyDataForAlias(component, *alias, &type, &propertyFlags); + if (error.isSet()) + return error; const QString propertyName = objectContainer->stringAt(alias->nameIndex); @@ -752,6 +759,8 @@ inline void QQmlPropertyCacheAliasCreator::appendAliasesToPrope propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, type, effectiveSignalIndex++); } + + return QQmlCompileError(); } template diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index d152d26968..0eae909cf7 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -1010,7 +1010,11 @@ bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex) } if (result == AllAliasesResolved) { - aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex); + QQmlCompileError error = aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex); + if (error.isSet()) { + recordError(error); + return false; + } atLeastOneAliasResolved = true; } else if (result == SomeAliasesResolved) { atLeastOneAliasResolved = true; -- cgit v1.2.3 From f42f1366dcd4b070c69c9e7fe42a704ef23da14d Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Fri, 13 Jan 2017 12:45:08 +0100 Subject: Use the image handler to return a scaled size for the SVG When the SVG was made to be drawn at a small width and a large height then it would lead to blurring in the rendering of the SVG. By having the image handler deal with returning the image we want for the scaled size it will ensure this is rendered correctly since it is able to account for the ratio already inside the SVG image handler. Task-number: QTBUG-65789 Change-Id: Ib8627c0537679aab022e88a0eea73a21d8cbc564 Reviewed-by: Shawn Rutledge --- src/quick/util/qquickimageprovider.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp index 6ee5b95dc7..a1513336a5 100644 --- a/src/quick/util/qquickimageprovider.cpp +++ b/src/quick/util/qquickimageprovider.cpp @@ -683,13 +683,15 @@ QSize QQuickImageProviderWithOptions::loadSize(const QSize &originalSize, const return res; const bool preserveAspectCropOrFit = options.preserveAspectRatioCrop() || options.preserveAspectRatioFit(); - const bool force_scale = (format == "svg" || format == "svgz"); + + if (!preserveAspectCropOrFit && (format == "svg" || format == "svgz")) + return requestedSize; qreal ratio = 0.0; - if (requestedSize.width() && (preserveAspectCropOrFit || force_scale || requestedSize.width() < originalSize.width())) { + if (requestedSize.width() && (preserveAspectCropOrFit || requestedSize.width() < originalSize.width())) { ratio = qreal(requestedSize.width()) / originalSize.width(); } - if (requestedSize.height() && (preserveAspectCropOrFit || force_scale || requestedSize.height() < originalSize.height())) { + if (requestedSize.height() && (preserveAspectCropOrFit || requestedSize.height() < originalSize.height())) { qreal hr = qreal(requestedSize.height()) / originalSize.height(); if (ratio == 0.0) ratio = hr; -- cgit v1.2.3 From 367c82b541ccb433a8b5ac3b26ad95b6d50769d2 Mon Sep 17 00:00:00 2001 From: Paolo Angelelli Date: Mon, 4 Dec 2017 17:31:45 +0100 Subject: Fix Shapes not playing well with QtGraphicalEffects This patch allow shapes to skip the sync optimization in situations where the shape is added to a shader effect either directly or as nested inside another item, and is set to be invisible. Task-number: QTBUG-63105 Change-Id: I595fbc052032f420982be1267d22a24bcffb7212 Reviewed-by: Robin Burchell --- src/imports/shapes/qquickshape.cpp | 7 +++++-- src/imports/shapes/qquickshape_p_p.h | 1 + src/quick/items/qquickitem.cpp | 31 +++++++++++++++++++++++++++---- src/quick/items/qquickitem_p.h | 4 ++++ 4 files changed, 37 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/imports/shapes/qquickshape.cpp b/src/imports/shapes/qquickshape.cpp index c749357cc5..de49baed48 100644 --- a/src/imports/shapes/qquickshape.cpp +++ b/src/imports/shapes/qquickshape.cpp @@ -632,6 +632,7 @@ void QQuickShapePath::resetFillGradient() QQuickShapePrivate::QQuickShapePrivate() : spChanged(false), + effectRefCount(0), rendererType(QQuickShape::UnknownRenderer), async(false), status(QQuickShape::Null), @@ -857,10 +858,12 @@ void QQuickShape::updatePolish() { Q_D(QQuickShape); - if (!d->spChanged) + const int currentEffectRefCount = d->extra.isAllocated() ? d->extra->recursiveEffectRefCount : 0; + if (!d->spChanged && currentEffectRefCount <= d->effectRefCount) return; d->spChanged = false; + d->effectRefCount = currentEffectRefCount; if (!d->renderer) { d->createRenderer(); @@ -872,7 +875,7 @@ void QQuickShape::updatePolish() // endSync() is where expensive calculations may happen (or get kicked off // on worker threads), depending on the backend. Therefore do this only // when the item is visible. - if (isVisible()) + if (isVisible() || d->effectRefCount > 0) d->sync(); update(); diff --git a/src/imports/shapes/qquickshape_p_p.h b/src/imports/shapes/qquickshape_p_p.h index f43831516a..350c2756bb 100644 --- a/src/imports/shapes/qquickshape_p_p.h +++ b/src/imports/shapes/qquickshape_p_p.h @@ -171,6 +171,7 @@ public: static void asyncShapeReady(void *data); bool spChanged; + int effectRefCount; QQuickShape::RendererType rendererType; bool async; QQuickShape::Status status; diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index dac37e284b..07bba46c25 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2943,6 +2943,7 @@ void QQuickItemPrivate::addChild(QQuickItem *child) if (childPrivate->subtreeHoverEnabled && !subtreeHoverEnabled) setHasHoverInChild(true); + childPrivate->recursiveRefFromEffectItem(extra.value().recursiveEffectRefCount); markSortedChildrenDirty(child); dirty(QQuickItemPrivate::ChildrenChanged); @@ -2971,6 +2972,7 @@ void QQuickItemPrivate::removeChild(QQuickItem *child) if (childPrivate->subtreeHoverEnabled && subtreeHoverEnabled) setHasHoverInChild(false); + childPrivate->recursiveRefFromEffectItem(-extra.value().recursiveEffectRefCount); markSortedChildrenDirty(child); dirty(QQuickItemPrivate::ChildrenChanged); @@ -6071,28 +6073,48 @@ void QQuickItemPrivate::removeFromDirtyList() void QQuickItemPrivate::refFromEffectItem(bool hide) { ++extra.value().effectRefCount; - if (1 == extra->effectRefCount) { + if (extra->effectRefCount == 1) { dirty(EffectReference); - if (parentItem) QQuickItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged); + if (parentItem) + QQuickItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged); } if (hide) { if (++extra->hideRefCount == 1) dirty(HideReference); } + recursiveRefFromEffectItem(1); +} + +void QQuickItemPrivate::recursiveRefFromEffectItem(int refs) +{ + Q_Q(QQuickItem); + if (!refs) + return; + extra.value().recursiveEffectRefCount += refs; + for (int ii = 0; ii < childItems.count(); ++ii) { + QQuickItem *child = childItems.at(ii); + QQuickItemPrivate::get(child)->recursiveRefFromEffectItem(refs); + } + // Polish may rely on the effect ref count so trigger one, if item is not visible + // (if visible, it will be triggered automatically). + if (!effectiveVisible && refs > 0 && extra.value().recursiveEffectRefCount == 1) // it wasn't referenced, now it's referenced + q->polish(); } void QQuickItemPrivate::derefFromEffectItem(bool unhide) { Q_ASSERT(extra->effectRefCount); --extra->effectRefCount; - if (0 == extra->effectRefCount) { + if (extra->effectRefCount == 0) { dirty(EffectReference); - if (parentItem) QQuickItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged); + if (parentItem) + QQuickItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged); } if (unhide) { if (--extra->hideRefCount == 0) dirty(HideReference); } + recursiveRefFromEffectItem(-1); } void QQuickItemPrivate::setCulled(bool cull) @@ -8534,6 +8556,7 @@ QQuickItemPrivate::ExtraData::ExtraData() layer(0), #endif effectRefCount(0), hideRefCount(0), + recursiveEffectRefCount(0), opacityNode(0), clipNode(0), rootNode(0), acceptedMouseButtons(0), origin(QQuickItem::Center), transparentForPositioner(false) diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index 285e86048c..adc9d22610 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -360,8 +360,11 @@ public: #endif QPointF userTransformOriginPoint; + // these do not include child items int effectRefCount; int hideRefCount; + // updated recursively for child items as well + int recursiveEffectRefCount; QSGOpacityNode *opacityNode; QQuickDefaultClipNode *clipNode; @@ -607,6 +610,7 @@ public: // A reference from an effect item means that this item is used by the effect, so // it should insert a root node. void refFromEffectItem(bool hide); + void recursiveRefFromEffectItem(int refs); void derefFromEffectItem(bool unhide); void itemChange(QQuickItem::ItemChange, const QQuickItem::ItemChangeData &); -- cgit v1.2.3 From 406ef45aaa3e84eb402a451eb4900afa17d20ea9 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 30 Jan 2018 09:47:06 +0100 Subject: Fix exposure of -1 as enum value in QML exposed C++ singletons When a C++ singleton has an enum with the value -1, we would expose that value correctly when taking the accelerated property access code path in the optimizer, but when going through the slower QQmlTypeWrapper we would return undefined. This turned out to be a silly logic error that assumed that -1 is not a valid value for an enum and instead indicates an enum value not present. [ChangeLog][Qml] Fix -1 as enum value in QML exposed C++ singletons showing up as undefined. Task-number: QTBUG-66067 Change-Id: Ib66dad7a4b59822b2c40ad6bd9af4b72469582e9 Reviewed-by: Lars Knoll Reviewed-by: Michael Brasser --- src/qml/qml/qqmltypewrapper.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index d4e1910a72..0fae76066d 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -133,11 +133,11 @@ ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, Q } static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, QObject *qobjectSingleton, - const QQmlType &type) + const QQmlType &type, bool *ok) { - bool ok; - int value = type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); - if (ok) + Q_ASSERT(ok != nullptr); + int value = type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, ok); + if (*ok) return value; // ### Optimize @@ -145,10 +145,11 @@ static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, QObject *qob const QMetaObject *metaObject = qobjectSingleton->metaObject(); for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) { QMetaEnum e = metaObject->enumerator(ii); - value = e.keyToValue(enumName.constData(), &ok); - if (ok) + value = e.keyToValue(enumName.constData(), ok); + if (*ok) return value; } + *ok = false; return -1; } @@ -191,8 +192,9 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope // check for enum value const bool includeEnums = w->d()->mode == Heap::QmlTypeWrapper::IncludeEnums; if (includeEnums && name->startsWithUpper()) { - const int value = enumForSingleton(v4, name, qobjectSingleton, type); - if (value != -1) + bool ok = false; + const int value = enumForSingleton(v4, name, qobjectSingleton, type, &ok); + if (ok) return QV4::Primitive::fromInt32(value).asReturnedValue(); } @@ -204,8 +206,8 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope // Warn when attempting to access a lowercased enum value, singleton case if (!ok && includeEnums && !name->startsWithUpper()) { - const int value = enumForSingleton(v4, name, qobjectSingleton, type); - if (value != -1) + enumForSingleton(v4, name, qobjectSingleton, type, &ok); + if (ok) return throwLowercaseEnumError(v4, name, type); } -- cgit v1.2.3 From 6a7c662bd5f7fe4a223aba2e15bb24a9ffc92df6 Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Thu, 22 Jun 2017 10:12:56 +0200 Subject: Do not stop delivering to handlers if all points are accepted Some Pointer Handlers can perform the desired interaction using only passive grabs. When such a handler is used to modify behavior of another event-handling Item or Handler which needs to take the exclusive grab, this allows them to cooperate: both can see the updates, and neither prevents delivery of events to both. Change-Id: I312cc301c52fcdf805245bbe0ac60fd28f92c01f Reviewed-by: Shawn Rutledge --- src/quick/items/qquickwindow.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 2d0f1218bf..8582dd8d2c 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQuick module of the Qt Toolkit. @@ -2422,8 +2422,6 @@ void QQuickWindowPrivate::deliverUpdatedTouchPoints(QQuickPointerTouchEvent *eve done = true; event->localize(receiver); handler->handlePointerEvent(event); - if (event->allPointsAccepted()) - done = true; } if (done) break; @@ -2524,8 +2522,6 @@ void QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo } if (handlersOnly) return; - if (pointerEvent->allPointsAccepted() && !pointerEvent->isReleaseEvent()) - return; // If all points are released and the item is not the grabber, it doesn't get the event. // But if at least one point is still pressed, we might be in a potential gesture-takeover scenario. @@ -2537,8 +2533,6 @@ void QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo auto event = pointerEvent->asPointerMouseEvent(); if (event && item->acceptedMouseButtons() & event->button()) { auto point = event->point(0); - if (point->isAccepted()) - return; // The only reason to already have a mouse grabber here is // synthetic events - flickable sends one when setPressDelay is used. auto oldMouseGrabber = q->mouseGrabberItem(); -- cgit v1.2.3 From 6eaa95662c2d4ba287ac5d1de5ec49bd3a9f59e6 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 22 Jan 2018 20:00:27 +0100 Subject: Change default TapHandler.gesturePolicy to DragThreshold This is based on the idea that TapHandler may be more often used to modify existing behavior rather than building Button controls from scratch. DragThreshold is reasonable newbie-friendly default behavior for both use cases. The drag-off-drag-back-release-and-click behavior is more advanced, and the designers of the best-behaving Button controls can be expected to discover the need to change gesturePolicy to get it. Change-Id: If220acf080e04f664d020d5e832f8d16a16b857a Reviewed-by: Shawn Rutledge --- src/quick/handlers/qquicktaphandler.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp index 8313b415bf..a1b4f961ed 100644 --- a/src/quick/handlers/qquicktaphandler.cpp +++ b/src/quick/handlers/qquicktaphandler.cpp @@ -61,14 +61,20 @@ int QQuickTapHandler::m_touchMultiTapDistanceSquared(-1); TapHandler is a handler for taps on a touchscreen or clicks on a mouse. - Detection of a valid tap gesture depends on \l gesturePolicy. + Detection of a valid tap gesture depends on \l gesturePolicy. The default + value is DragThreshold, which requires the press and release to be close + together in both space and time. In this case, DragHandler is able to + function using only a passive grab, and therefore does not interfere with + event delivery to any other Items or Pointer Handlers. So the default + gesturePolicy is useful when you want to modify behavior of an existing + control or Item by adding a TapHandler with bindings and/or JavaScript + callbacks. + Note that buttons (such as QPushButton) are often implemented not to care whether the press and release occur close together: if you press the button and then change your mind, you need to drag all the way off the edge of the - button in order to cancel the click. Therefore the default - \l gesturePolicy is \c TapHandler.ReleaseWithinBounds. If you want to require - that the press and release are close together in both space and time, - set it to \c TapHandler.DragThreshold. + button in order to cancel the click. For this use case, set the + \l gesturePolicy to \c TapHandler.ReleaseWithinBounds. For multi-tap gestures (double-tap, triple-tap etc.), the distance moved must not exceed QPlatformTheme::MouseDoubleClickDistance with mouse and @@ -81,7 +87,7 @@ int QQuickTapHandler::m_touchMultiTapDistanceSquared(-1); QQuickTapHandler::QQuickTapHandler(QObject *parent) : QQuickSinglePointHandler(parent) , m_pressed(false) - , m_gesturePolicy(ReleaseWithinBounds) + , m_gesturePolicy(DragThreshold) , m_tapCount(0) , m_longPressThreshold(-1) , m_lastTapTimestamp(0.0) -- cgit v1.2.3 From 1e350a8c98d9c98823dde83a6745d2f26a9c0785 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 24 Jan 2018 17:23:03 +0100 Subject: Disallow registration of types beginning with lowercase letters Allowing types with lowercase names causes ambiguity, as can be seen in QTBUG-43567 and the comment in IRBuilder::visit(), which explains that "the grammar can't distinguish between two different definitions" whose only difference is casing of the first letter. - Prevent registration (return -1 with e.g. qmlRegisterType()) when a type name doesn't begin with an uppercase letter. - Document the uppercase type name rule in more places. Change-Id: I4e522c65990f418eaafa45a256e3cb07a3e01ba4 Reviewed-by: Shawn Rutledge --- src/qml/doc/src/qmllanguageref/syntax/basics.qdoc | 2 ++ src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc | 2 ++ src/qml/qml/qqmlmetatype.cpp | 9 +++++++++ 3 files changed, 13 insertions(+) (limited to 'src') diff --git a/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc b/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc index 1b645a94c0..9eb8f72cf2 100644 --- a/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc +++ b/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc @@ -38,6 +38,8 @@ imperative code, in the case where complex custom application behavior is needed QML source code is generally loaded by the engine through QML \e documents, which are standalone documents of QML code. These can be used to define \l {QML Object Types}{QML object types} that can then be reused throughout an application. +Note that type names must begin with an uppercase letter in order +to be declared as QML object types in a QML file. \section1 Import Statements diff --git a/src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc b/src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc index b74646b7d0..5f089b5ebc 100644 --- a/src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc +++ b/src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc @@ -45,6 +45,8 @@ type, as discussed in \l {qtqml-documents-definetypes.html} {Documents as QML object type definitions}, or by defining a QML type from C++ and registering the type with the QML engine, as discussed in \l{qtqml-cppintegration-definetypes.html}{Defining QML Types from C++}. +Note that in both cases, the type name must begin with an uppercase letter in +order to be declared as a QML object type in a QML file. \section1 Defining Object Types from QML diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 3a0d5c3daf..89f3ced2d6 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -1405,6 +1405,12 @@ QString registrationTypeString(QQmlType::RegistrationType typeType) bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, const char *uri, const QString &typeName, int majorVersion = -1) { if (!typeName.isEmpty()) { + if (typeName.at(0).isLower()) { + QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\"; type names must begin with an uppercase letter")); + data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName)); + return false; + } + int typeNameLen = typeName.length(); for (int ii = 0; ii < typeNameLen; ++ii) { if (!(typeName.at(ii).isLetterOrNumber() || typeName.at(ii) == '_')) { @@ -1650,6 +1656,9 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data) else return -1; + if (!dtype.isValid()) + return -1; + QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *typeData = metaTypeData(); typeData->undeletableTypes.insert(dtype); -- cgit v1.2.3 From 922ce0ef39302a8d6d306a09295cbae857becbc4 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 19 Jan 2018 15:13:38 +0100 Subject: Improve persistent/weak value allocation performance When the persistent storage becomes fragmented, we would find the page with a hole in it, but we wouldn't put it to the front of the page list. So upon the next allocation we would begin iterating through firstPage again. This wasn't quite visible in callgrind as overall not many instructions were executed, but in perf this function showed up as hotspot because the search for free pages ends up with a lot of cache misses. In delegates_item_states.qml this was about ~7% of measured cycles with perf. Change-Id: I2bfa337ea9be14d1321756963c72d31336790a0a Done-with: Erik Task-number: QTBUG-65708 Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4persistent.cpp | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp index 987c322e47..75f7c95dde 100644 --- a/src/qml/jsruntime/qv4persistent.cpp +++ b/src/qml/jsruntime/qv4persistent.cpp @@ -68,6 +68,22 @@ Page *getPage(Value *val) { return reinterpret_cast(reinterpret_cast(val) & ~((quintptr)(WTF::pageSize() - 1))); } +QML_NEARLY_ALWAYS_INLINE void insertInFront(PersistentValueStorage *storage, Page *p) +{ + p->header.next = reinterpret_cast(storage->firstPage); + p->header.prev = reinterpret_cast(&storage->firstPage); + if (p->header.next) + p->header.next->header.prev = &p->header.next; + storage->firstPage = p; +} + +QML_NEARLY_ALWAYS_INLINE void unlink(Page *p) +{ + if (p->header.prev) + *p->header.prev = p->header.next; + if (p->header.next) + p->header.next->header.prev = p->header.prev; +} Page *allocatePage(PersistentValueStorage *storage) { @@ -78,19 +94,14 @@ Page *allocatePage(PersistentValueStorage *storage) p->header.engine = storage->engine; p->header.alloc = page; - p->header.next = reinterpret_cast(storage->firstPage); - p->header.prev = reinterpret_cast(&storage->firstPage); p->header.refCount = 0; p->header.freeList = 0; - if (p->header.next) - p->header.next->header.prev = &p->header.next; + insertInFront(storage, p); for (int i = 0; i < kEntriesPerPage - 1; ++i) { p->values[i].setEmpty(i + 1); } p->values[kEntriesPerPage - 1].setEmpty(-1); - storage->firstPage = p; - return p; } @@ -195,6 +206,12 @@ Value *PersistentValueStorage::allocate() Value *v = p->values + p->header.freeList; p->header.freeList = v->int_32(); + + if (p->header.freeList != -1 && p != firstPage) { + unlink(p); + insertInFront(this, p); + } + ++p->header.refCount; v->setRawValue(Encode::undefined()); @@ -248,10 +265,7 @@ ExecutionEngine *PersistentValueStorage::getEngine(Value *v) void PersistentValueStorage::freePage(void *page) { Page *p = static_cast(page); - if (p->header.prev) - *p->header.prev = p->header.next; - if (p->header.next) - p->header.next->header.prev = p->header.prev; + unlink(p); p->header.alloc.deallocate(); } -- cgit v1.2.3 From 9c08bd6dd6666164089595ffa01dae1bcbf73097 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 31 Jan 2018 17:21:08 +0100 Subject: Add a link to the "Using C++ Models in QML Tutorial" video Change-Id: I1e1d8f3996bf2d187491d50a76852fb82257a42b Reviewed-by: Venugopal Shivashankar --- src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc index 27c8e51381..2705ca5e34 100644 --- a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc +++ b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc @@ -41,6 +41,10 @@ QObjectList or a \l QAbstractItemModel. The first three are useful for exposing simpler datasets, while QAbstractItemModel provides a more flexible solution for more complex models. +For a video tutorial that takes you through the whole process of exposing a C++ +model to QML, see the +\l {https://youtu.be/9BcAYDlpuT8}{Using C++ Models in QML Tutorial}. + \section2 QStringList-based Model A model may be a simple \l QStringList, which provides the contents of the list -- cgit v1.2.3 From 5a10cf060e6c843f05d8bd820a4be4bb08f277ec Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Tue, 21 Nov 2017 13:05:45 +0100 Subject: Prevent invalid characters being entered at the appropriate times When a validator does not allow for certain characters to be entered, then it should not allow these to be entered in even if an input mask is set. This fixes a regression introduced in 1b21b73e89942d567c90a17a3bf7a7ecae3de258. The test modified is because this is in fact a general limitation when combining validators and input masks, when a separator is used. Whereas the original patch did allow this to be possible, this is now not possible again. Task-number: QTBUG-64616 Change-Id: Ic6a3f40a9faa7c04abc055cfc2752044fddd33a0 Reviewed-by: Frederik Gladhorn Reviewed-by: Robin Burchell --- src/quick/items/qquicktextinput.cpp | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 28b089da49..0c1cb7a146 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -1077,7 +1077,8 @@ void QQuickTextInputPrivate::checkIsValid() Q_Q(QQuickTextInput); ValidatorState state = hasAcceptableInput(m_text); - m_validInput = state != InvalidInput; + if (!m_maskData) + m_validInput = state != InvalidInput; if (state != AcceptableInput) { if (m_acceptableInput) { m_acceptableInput = false; @@ -3530,11 +3531,15 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo #if QT_CONFIG(validator) if (m_validator) { QString textCopy = m_text; + if (m_maskData) + textCopy = maskString(0, m_text, true); int cursorCopy = m_cursor; QValidator::State state = m_validator->validate(textCopy, cursorCopy); + if (m_maskData) + textCopy = m_text; m_validInput = state != QValidator::Invalid; m_acceptableInput = state == QValidator::Acceptable; - if (m_validInput) { + if (m_validInput && !m_maskData) { if (m_text != textCopy) { internalSetText(textCopy, cursorCopy); return true; @@ -3543,31 +3548,8 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo } } #endif - - if (m_maskData) { - m_validInput = true; - if (m_text.length() != m_maxLength) { - m_validInput = false; - m_acceptableInput = false; - } else { - for (int i = 0; i < m_maxLength; ++i) { - if (m_maskData[i].separator) { - if (m_text.at(i) != m_maskData[i].maskChar) { - m_validInput = false; - m_acceptableInput = false; - break; - } - } else { - if (!isValidInput(m_text.at(i), m_maskData[i].maskChar)) { - m_acceptableInput = false; - if (m_text.at(i) != m_blank) - m_validInput = false; - break; - } - } - } - } - } + if (m_maskData) + checkIsValid(); if (validateFromState >= 0 && wasValidInput && !m_validInput) { if (m_transactions.count()) -- cgit v1.2.3 From 8c0501855787986365519da12e9e580b30fb26af Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 29 Jan 2018 11:42:40 +0100 Subject: Fix dead lock / race in QML type loader when importing plugins When importing modules - in the QML loader thread - with plugins we keep globally track of the Qt plugins that we have loaded that contain QML modules, to ensure that we don't call the engine-independent registerTypes() function on the plugin multiple times. After registerTypes() we may also call initializeEngine() on the plugin for the engine-specific initialization, which - as a QQmlEngine is provided as parameter - must happen in the gui thread. For that we issue a thread-blocking call that waits until the gui thread has woken up and processed the event/call. During that time the global plugin lock is held by that QML loader thread. If meanwhile the gui thread instantiates a second QQmlEngine and attempts to issue a synchronous type compilation (using QQmlComponent::CompilationMode::PreferSynchronous), then gui thread is blocking and waiting for its own QML loader thread to complete the type compilation, which may involve processing an import that requires loading a plugin. Now this second QML loader thread is blocked by trying to acquire the global plugin registry lock (qmlEnginePluginsWithRegisteredTypes()->mutex) in qqmlimports.cpp. Now the first QML loader thread is blocked because the gui thread is not processing the call events for the first engine. The gui thread is blocked waiting for the second QML loader thread, which in turn is stuck trying to acquire the lock held by the first QML loader thread. The provided test case triggers this scenario, although through a slightly different way. It's not possible to wait in the gui thread for the plugin lock to be held in a loader thread via the registerTypes callback, as that also acquires the QQmlMetaType lock that will interfere with the test-case. However the same plugin lock issue appears when the first QML engine is located in a different thread altogether. In that case the dispatch to the engine thread /works/, but it won't be the gui thread but instead the secondary helper thread of the test case that will sit in our initializeEngine() callback. This bug was spotted in production customer code with backtraces pointing into the three locations described above: One QML loader thread blocking on a call to the gui thread, the gui thread blocking on a second QML loader thread and that one blocking on acquisition of the plugin lock held by the first. Fortunately it is not necessary to hold on to the global plugin lock when doing the engine specific initialization. That allows the second QML loader thread to complete its work and finally resume the GUI thread's event loop. Change-Id: If757b3fc9b473f42b266427e55d7a1572b937515 Reviewed-by: Ulf Hermann --- src/qml/qml/qqmlimport.cpp | 150 +++++++++++++++++++++++++-------------------- 1 file changed, 84 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index c8d17c4b8e..f43ffb4c3c 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -2056,29 +2056,38 @@ bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &ba // Dynamic plugins are differentiated by their filepath. For static plugins we // don't have that information so we use their address as key instead. const QString uniquePluginID = QString::asprintf("%p", instance); - StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes(); - QMutexLocker lock(&plugins->mutex); + { + StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes(); + QMutexLocker lock(&plugins->mutex); - // Plugin types are global across all engines and should only be - // registered once. But each engine still needs to be initialized. - bool typesRegistered = plugins->contains(uniquePluginID); - bool engineInitialized = initializedPlugins.contains(uniquePluginID); + // Plugin types are global across all engines and should only be + // registered once. But each engine still needs to be initialized. + bool typesRegistered = plugins->contains(uniquePluginID); - if (typesRegistered) { - Q_ASSERT_X(plugins->value(uniquePluginID).uri == uri, - "QQmlImportDatabase::importStaticPlugin", - "Internal error: Static plugin imported previously with different uri"); - } else { - RegisteredPlugin plugin; - plugin.uri = uri; - plugin.loader = 0; - plugins->insert(uniquePluginID, plugin); + if (typesRegistered) { + Q_ASSERT_X(plugins->value(uniquePluginID).uri == uri, + "QQmlImportDatabase::importStaticPlugin", + "Internal error: Static plugin imported previously with different uri"); + } else { + RegisteredPlugin plugin; + plugin.uri = uri; + plugin.loader = 0; + plugins->insert(uniquePluginID, plugin); - if (!registerPluginTypes(instance, basePath, uri, typeNamespace, vmaj, errors)) - return false; + if (!registerPluginTypes(instance, basePath, uri, typeNamespace, vmaj, errors)) + return false; + } + + // Release the lock on plugins early as we're done with the global part. Releasing the lock + // also allows other QML loader threads to acquire the lock while this thread is blocking + // in the initializeEngine call to the gui thread (which in turn may be busy waiting for + // other QML loader threads and thus not process the initializeEngine call). } - if (!engineInitialized) { + // The plugin's per-engine initialization does not need lock protection, as this function is + // only called from the engine specific loader thread and importDynamicPlugin as well as + // importStaticPlugin are the only places of access. + if (!initializedPlugins.contains(uniquePluginID)) { initializedPlugins.insert(uniquePluginID); if (QQmlExtensionInterface *eiface = qobject_cast(instance)) { @@ -2100,68 +2109,77 @@ bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QStr QFileInfo fileInfo(filePath); const QString absoluteFilePath = fileInfo.absoluteFilePath(); + QObject *instance = nullptr; bool engineInitialized = initializedPlugins.contains(absoluteFilePath); - StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes(); - QMutexLocker lock(&plugins->mutex); - bool typesRegistered = plugins->contains(absoluteFilePath); - - if (typesRegistered) { - Q_ASSERT_X(plugins->value(absoluteFilePath).uri == uri, - "QQmlImportDatabase::importDynamicPlugin", - "Internal error: Plugin imported previously with different uri"); - } - - if (!engineInitialized || !typesRegistered) { - if (!QQml_isFileCaseCorrect(absoluteFilePath)) { - if (errors) { - QQmlError error; - error.setDescription(tr("File name case mismatch for \"%1\"").arg(absoluteFilePath)); - errors->prepend(error); - } - return false; + { + StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes(); + QMutexLocker lock(&plugins->mutex); + bool typesRegistered = plugins->contains(absoluteFilePath); + + if (typesRegistered) { + Q_ASSERT_X(plugins->value(absoluteFilePath).uri == uri, + "QQmlImportDatabase::importDynamicPlugin", + "Internal error: Plugin imported previously with different uri"); } - QPluginLoader* loader = 0; - if (!typesRegistered) { - loader = new QPluginLoader(absoluteFilePath); - - if (!loader->load()) { + if (!engineInitialized || !typesRegistered) { + if (!QQml_isFileCaseCorrect(absoluteFilePath)) { if (errors) { QQmlError error; - error.setDescription(loader->errorString()); + error.setDescription(tr("File name case mismatch for \"%1\"").arg(absoluteFilePath)); errors->prepend(error); } - delete loader; return false; } - } else { - loader = plugins->value(absoluteFilePath).loader; - } - QObject *instance = loader->instance(); + QPluginLoader* loader = 0; + if (!typesRegistered) { + loader = new QPluginLoader(absoluteFilePath); - if (!typesRegistered) { - RegisteredPlugin plugin; - plugin.uri = uri; - plugin.loader = loader; - plugins->insert(absoluteFilePath, plugin); + if (!loader->load()) { + if (errors) { + QQmlError error; + error.setDescription(loader->errorString()); + errors->prepend(error); + } + delete loader; + return false; + } + } else { + loader = plugins->value(absoluteFilePath).loader; + } - // Continue with shared code path for dynamic and static plugins: - if (!registerPluginTypes(instance, fileInfo.absolutePath(), uri, typeNamespace, vmaj, errors)) - return false; + instance = loader->instance(); + + if (!typesRegistered) { + RegisteredPlugin plugin; + plugin.uri = uri; + plugin.loader = loader; + plugins->insert(absoluteFilePath, plugin); + + // Continue with shared code path for dynamic and static plugins: + if (!registerPluginTypes(instance, fileInfo.absolutePath(), uri, typeNamespace, vmaj, errors)) + return false; + } } - if (!engineInitialized) { - // things on the engine (eg. adding new global objects) have to be done for every - // engine. - // XXX protect against double initialization - initializedPlugins.insert(absoluteFilePath); - - if (QQmlExtensionInterface *eiface = qobject_cast(instance)) { - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); - ep->typeLoader.initializeEngine(eiface, uri.toUtf8().constData()); - } - } + // Release the lock on plugins early as we're done with the global part. Releasing the lock + // also allows other QML loader threads to acquire the lock while this thread is blocking + // in the initializeEngine call to the gui thread (which in turn may be busy waiting for + // other QML loader threads and thus not process the initializeEngine call). + } + + + if (!engineInitialized) { + // The plugin's per-engine initialization does not need lock protection, as this function is + // only called from the engine specific loader thread and importDynamicPlugin as well as + // importStaticPlugin are the only places of access. + initializedPlugins.insert(absoluteFilePath); + + if (QQmlExtensionInterface *eiface = qobject_cast(instance)) { + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); + ep->typeLoader.initializeEngine(eiface, uri.toUtf8().constData()); + } } return true; -- cgit v1.2.3 From f7ffed94c1540e015794a8d6d4910e8ca87c15e1 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 31 Jan 2018 12:29:42 +0100 Subject: Fix memory leak with value types Commit 3b14e2ffdd8eb4b7f7f4508768b75f2acc399370 replaced the QQmlRefPointer with a raw QQmlPropertyCache pointer and added a V4_NEEDS_DESTROY tag. However unfortunately the destroy() method in the heap class does not decrease the reference count. Change-Id: I90a8c56cd638592b67aae7041fbb57c879c4146c Reviewed-by: Lars Knoll --- src/qml/qml/qqmlvaluetypewrapper.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index 41bb85c351..b2b49f7909 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -96,6 +96,8 @@ void Heap::QQmlValueTypeWrapper::destroy() valueType->metaType.destruct(gadgetPtr); ::operator delete(gadgetPtr); } + if (_propertyCache) + _propertyCache->release(); Object::destroy(); } -- cgit v1.2.3 From 7bd5d93899ca6c2175d6937f2011428c654bff02 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 31 Jan 2018 15:41:58 +0100 Subject: Fix memory leak with QtQuick compiler generated files When for the QQC code path we do QML type re-compilation, we allocate a new QV4::CompiledData::Unit. We must make sure that this dynamically allocated memory is released in QV4::CompiledData::CompilationUnit's destructor, by ensuring that the StaticData flag is not set. This isn't directly applicable to the ahead-of-time generated cache file unit data as they will always be re-generated (and thus the unsetting of StaticData at the end of createCompilationUnit::createUnitData()), but I've added a test-case nevertheless to ensure the correct engine behavior. Change-Id: I16973d7989567892bf8bf9dd6214bf293055d260 Reviewed-by: Lars Knoll --- src/qml/compiler/qqmlirbuilder.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 9749324060..e82fe71934 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1397,6 +1397,9 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4: QV4::CompiledData::Unit *qmlUnit = reinterpret_cast(data); qmlUnit->unitSize = totalSize; qmlUnit->flags |= QV4::CompiledData::Unit::IsQml; + // This unit's memory was allocated with malloc on the heap, so it's + // definitely not suitable for StaticData access. + qmlUnit->flags &= ~QV4::CompiledData::Unit::StaticData; qmlUnit->offsetToImports = unitSize; qmlUnit->nImports = output.imports.count(); qmlUnit->offsetToObjects = unitSize + importSize; -- cgit v1.2.3 From 4b014effe1f27407f5073ba738498ce87b918b9d Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 15 Dec 2017 13:26:28 +0100 Subject: If Loader loads Window, set its transient parent to the Loader's window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes the Item { Loader { sourceComponent: Window { } } } case consistent with the Item { Window { } } case: the inner Window is transient for the outer Window. It works even if the Loader's Window has a visible: true declaration: in that case, until now, the Loader's Window would become visible at component creation time, before the outer Item became visible. So the test to check whether it had a transient parent did not work. We now change the delayed-visibility mechanism in QQuickWindowQmlImpl to wait for the parent Item to acquire a window of its own rather than waiting for the transient-parent-if-any to become visible. It should still take care of all the old cases too, e.g. in the Window { Window { } } case, the inner Window's QObject parent is actually the QQuickRootItem. (Amends 701255c76f671f100338a799f0194bf10e26c9d1) [ChangeLog][QtQuick][QQuickWindow] When a Window is declared inside another Item or Window, the window will not be created until the parent window is created. This allows it to have the correct transientParent and be managed as a transient window. Task-number: QTBUG-52944 Change-Id: Iaf4aafbd696f6e8dd0eec1d02db8bd181483bd07 Reviewed-by: Morten Johan Sørvig Reviewed-by: Shawn Rutledge --- src/quick/items/qquickloader.cpp | 19 +++++++++++++++++++ src/quick/items/qquickloader_p.h | 1 + src/quick/items/qquickwindowmodule.cpp | 15 +++++++++++---- 3 files changed, 31 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index 414103c63e..a3e8379368 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -674,6 +674,13 @@ void QQuickLoaderPrivate::incubatorStateChanged(QQmlIncubator::Status status) if (status == QQmlIncubator::Ready) { object = incubator->object(); item = qmlobject_cast(object); + if (!item) { + QQuickWindow *window = qmlobject_cast(object); + if (window) { + qCDebug(lcTransient) << window << "is transient for" << q->window(); + window->setTransientParent(q->window()); + } + } emit q->itemChanged(); initResize(); incubator->clear(); @@ -818,6 +825,18 @@ void QQuickLoader::componentComplete() } } +void QQuickLoader::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) +{ + if (change == ItemSceneChange) { + QQuickWindow *loadedWindow = qmlobject_cast(item()); + if (loadedWindow) { + qCDebug(lcTransient) << loadedWindow << "is transient for" << value.window; + loadedWindow->setTransientParent(value.window); + } + } + QQuickItem::itemChange(change, value); +} + /*! \qmlsignal QtQuick::Loader::loaded() diff --git a/src/quick/items/qquickloader_p.h b/src/quick/items/qquickloader_p.h index db171dcd1e..8f0a9980b9 100644 --- a/src/quick/items/qquickloader_p.h +++ b/src/quick/items/qquickloader_p.h @@ -107,6 +107,7 @@ Q_SIGNALS: protected: void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; void componentComplete() Q_DECL_OVERRIDE; + void itemChange(ItemChange change, const ItemChangeData &value) override; private: void setSource(const QUrl &sourceUrl, bool needsClear); diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp index 1981ed2f70..e702cc5a3e 100644 --- a/src/quick/items/qquickwindowmodule.cpp +++ b/src/quick/items/qquickwindowmodule.cpp @@ -123,7 +123,13 @@ void QQuickWindowQmlImpl::componentComplete() { Q_D(QQuickWindowQmlImpl); d->complete = true; - if (transientParent() && !transientParent()->isVisible()) { + QQuickItem *itemParent = qmlobject_cast(QObject::parent()); + if (itemParent && !itemParent->window()) { + qCDebug(lcTransient) << "window" << title() << "has invisible Item parent" << itemParent << "transientParent" + << transientParent() << "declared visibility" << d->visibility << "; delaying show"; + connect(itemParent, &QQuickItem::windowChanged, this, + &QQuickWindowQmlImpl::setWindowVisibility, Qt::QueuedConnection); + } else if (transientParent() && !transientParent()->isVisible()) { connect(transientParent(), &QQuickWindow::visibleChanged, this, &QQuickWindowQmlImpl::setWindowVisibility, Qt::QueuedConnection); } else { @@ -137,9 +143,10 @@ void QQuickWindowQmlImpl::setWindowVisibility() if (transientParent() && !transientParent()->isVisible()) return; - if (sender()) { - disconnect(transientParent(), &QWindow::visibleChanged, this, - &QQuickWindowQmlImpl::setWindowVisibility); + if (QQuickItem *senderItem = qmlobject_cast(sender())) { + disconnect(senderItem, &QQuickItem::windowChanged, this, &QQuickWindowQmlImpl::setWindowVisibility); + } else if (sender()) { + disconnect(transientParent(), &QWindow::visibleChanged, this, &QQuickWindowQmlImpl::setWindowVisibility); } // We have deferred window creation until we have the full picture of what -- cgit v1.2.3 From 23ea4cf5a3babd73a4d398410e2a21685245e0a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kari=20Hautam=C3=A4ki?= Date: Mon, 15 Jan 2018 17:01:19 +0200 Subject: Fix transition when removing the last item from ListView/GridView Use the previous item view boundaries (before a remove was applied) when defining transition properties. Task-number: QTBUG-64311 Change-Id: I66870a7267ac26ea430c364383f32fd5c47d4a5d Reviewed-by: Shawn Rutledge --- src/quick/items/qquickitemview.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 856070634c..17a1d124ab 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -1894,6 +1894,9 @@ void QQuickItemViewPrivate::layout() inLayout = true; + // viewBounds contains bounds before any add/remove/move operation to the view + QRectF viewBounds(q->contentX(), q->contentY(), q->width(), q->height()); + if (!isValid() && !visibleItems.count()) { clear(); setPosition(contentStartOffset()); @@ -1960,7 +1963,6 @@ void QQuickItemViewPrivate::layout() prepareVisibleItemTransitions(); - QRectF viewBounds(q->contentX(), q->contentY(), q->width(), q->height()); for (QList::Iterator it = releasePendingTransition.begin(); it != releasePendingTransition.end(); ) { FxViewItem *item = *it; -- cgit v1.2.3 From 6958308c09ceda855a30c5a2d491f078c5104071 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 29 Jan 2018 16:58:22 +0100 Subject: Doc: add C++11 lambda examples for qmlRegisterSingletonType() Change-Id: I444137fd10041781df232447b8e2bf712582f079 Reviewed-by: Mitch Curtis Reviewed-by: Shawn Rutledge --- src/qml/doc/src/qmlfunctions.qdoc | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'src') diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc index 8a62a18eec..f939ddbcf3 100644 --- a/src/qml/doc/src/qmlfunctions.qdoc +++ b/src/qml/doc/src/qmlfunctions.qdoc @@ -324,6 +324,19 @@ qmlRegisterSingletonType("Qt.example.qjsvalueApi", 1, 0, "MyApi", example_qjsvalue_singletontype_provider); \endcode + Alternatively, you can use a C++11 lambda: + + \code + qmlRegisterSingletonType("Qt.example.qjsvalueApi", 1, 0, "MyApi", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QJSValue { + Q_UNUSED(engine) + + static int seedValue = 5; + QJSValue example = scriptEngine->newObject(); + example.setProperty("someProperty", seedValue++); + return example; + }); + \endcode + In order to use the registered singleton type in QML, you must import the singleton type. \qml import QtQuick 2.0 @@ -423,6 +436,18 @@ qmlRegisterSingletonType("Qt.example.qobjectSingleton", 1, 0, "MyApi", example_qobject_singletontype_provider); \endcode + Alternatively, you can use a C++11 lambda: + + \code + qmlRegisterSingletonType("Qt.example.qjsvalueApi", 1, 0, "MyApi", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + + SingletonTypeExample *example = new SingletonTypeExample(); + return example; + }); + \endcode + In order to use the registered singleton type in QML, you must import the singleton type. \qml import QtQuick 2.0 -- cgit v1.2.3 From 8501993e5275076d9163a7e2f8bab9ba2f187f72 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Fri, 26 Jan 2018 11:28:06 +0100 Subject: QML: Collapse all NaNs into one single (encoded) NaN The idea of NaN boxing is to use one single NaN as a "true" NaN, and all others as a boxed value. So when encoding some NaN, be sure to use that one "true" NaN. Otherwise, it will be interpreted as an encoded value. Task-number: QTBUG-65998 Change-Id: Ia6e4641be180f3d626c40a57b473f181358e04db Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4value_p.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 9adad881a1..94233d4ddb 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -56,6 +56,8 @@ #include "qv4global_p.h" #include +#include + #if QT_POINTER_SIZE == 8 #define QV4_USE_64_BIT_VALUE_ENCODING #endif @@ -362,6 +364,8 @@ public: return d; } QML_NEARLY_ALWAYS_INLINE void setDouble(double d) { + if (qt_is_nan(d)) + d = qt_qnan(); memcpy(&_val, &d, 8); #ifdef QV4_USE_64_BIT_VALUE_ENCODING _val ^= NaNEncodeMask; -- cgit v1.2.3 From 23cca59848087875ae3486f61d1cd4fe0d90fe7c Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 30 Jan 2018 16:08:30 +0100 Subject: Document that Q_GADGET classes cannot be used with newQMetaObject() Task-number: QTBUG-62007 Change-Id: I63d5a57163b36bc8629930e1cda8d5afa1e77d15 Reviewed-by: Simon Hausmann --- src/qml/doc/snippets/code/src_script_qjsengine.cpp | 20 ++++++++++++++++++ src/qml/jsapi/qjsengine.cpp | 24 +++++++++++++++++----- 2 files changed, 39 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/qml/doc/snippets/code/src_script_qjsengine.cpp b/src/qml/doc/snippets/code/src_script_qjsengine.cpp index 876990fb3f..0310ae042c 100644 --- a/src/qml/doc/snippets/code/src_script_qjsengine.cpp +++ b/src/qml/doc/snippets/code/src_script_qjsengine.cpp @@ -114,3 +114,23 @@ engine.globalObject().setProperty("myObject", myScriptQObject); qDebug() << engine.evaluate("myObject.dynamicProperty").toInt(); //! [6] + + +//! [7] +class MyObject : public QObject +{ + Q_OBJECT + +public: + Q_INVOKABLE MyObject() {} +}; +//! [7] + +//! [8] +QJSValue jsMetaObject = engine.newQMetaObject(&MyObject::staticMetaObject); +engine.globalObject().setProperty("MyObject", jsMetaObject); +//! [8] + +//! [9] +engine.evaluate("var myObject = new MyObject()"); +//! [9] diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index d5b8b295a7..6cab8def4f 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -166,16 +166,30 @@ Q_DECLARE_METATYPE(QList) properties of the proxy object. No binding code is needed because it is done dynamically using the Qt meta object system. + \snippet code/src_script_qjsengine.cpp 5 + Use newQMetaObject() to wrap a QMetaObject; this gives you a "script representation" of a QObject-based class. newQMetaObject() returns a proxy script object; enum values of the class are available as properties of the proxy object. - Constructors exposed to the meta-object system ( using Q_INVOKABLE ) can be + Constructors exposed to the meta-object system (using Q_INVOKABLE) can be called from the script to create a new QObject instance with - JavaScriptOwnership. + JavaScriptOwnership. For example, given the following class definition: - \snippet code/src_script_qjsengine.cpp 5 + \snippet code/src_script_qjsengine.cpp 7 + + The \c staticMetaObject for the class can be exposed to JavaScript like so: + + \snippet code/src_script_qjsengine.cpp 8 + + Instances of the class can then be created in JavaScript: + + \snippet code/src_script_qjsengine.cpp 9 + + \note Currently only classes using the Q_OBJECT macro are supported; it is + not possible to expose the \c staticMetaObject of a Q_GADGET class to + JavaScript. \section2 Dynamic QObject Properties @@ -537,7 +551,7 @@ QJSValue QJSEngine::newQObject(QObject *object) When called as a constructor, a new instance of the class will be created. Only constructors exposed by Q_INVOKABLE will be visible from the script engine. - \sa newQObject() + \sa newQObject(), {QObject Integration} */ QJSValue QJSEngine::newQMetaObject(const QMetaObject* metaObject) { @@ -554,7 +568,7 @@ QJSValue QJSEngine::newQMetaObject(const QMetaObject* metaObject) { Creates a JavaScript object that wraps the static QMetaObject associated with class \c{T}. - \sa newQObject() + \sa newQObject(), {QObject Integration} */ -- cgit v1.2.3 From e227e3a6ce9e18093fd74fabe0c4235b70f7b8f7 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 18 Jan 2018 14:42:41 +0100 Subject: Use the GL context shared in the render context .. instead of calling QOpenGLContext::currentContext(), which in turn accesses the thread-local storage. Change-Id: I773686deb2a745e066b0878a6ccb087afb81774d Reviewed-by: Simon Hausmann Reviewed-by: Tuukka Turunen --- src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 35 +++++++++++++---------- 1 file changed, 20 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index d016e79641..a8b60c9e55 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -143,7 +143,7 @@ ShaderManager::Shader *ShaderManager::prepareMaterial(QSGMaterial *material) Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphContextFrame); QSGMaterialShader *s = material->createShader(); - QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QOpenGLContext *ctx = context->openglContext(); QSurfaceFormat::OpenGLContextProfile profile = ctx->format().profile(); QOpenGLShaderProgram *p = s->program(); @@ -2031,7 +2031,7 @@ Renderer::ClipType Renderer::updateStencilClip(const QSGClipNode *clip) int vboSize = 0; bool useVBO = false; - QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QOpenGLContext *ctx = m_context->openglContext(); QSurfaceFormat::OpenGLContextProfile profile = ctx->format().profile(); if (!ctx->isOpenGLES() && profile == QSurfaceFormat::CoreProfile) { @@ -2493,18 +2493,21 @@ void Renderer::updateLineWidth(QSGGeometry *g) if (g->drawingMode() == GL_LINE_STRIP || g->drawingMode() == GL_LINE_LOOP || g->drawingMode() == GL_LINES) glLineWidth(g->lineWidth()); #if !defined(QT_OPENGL_ES_2) - else if (!QOpenGLContext::currentContext()->isOpenGLES() && g->drawingMode() == GL_POINTS) { - QOpenGLFunctions_1_0 *gl1funcs = 0; - QOpenGLFunctions_3_2_Core *gl3funcs = 0; - if (QOpenGLContext::currentContext()->format().profile() == QSurfaceFormat::CoreProfile) - gl3funcs = QOpenGLContext::currentContext()->versionFunctions(); - else - gl1funcs = QOpenGLContext::currentContext()->versionFunctions(); - Q_ASSERT(gl1funcs || gl3funcs); - if (gl1funcs) - gl1funcs->glPointSize(g->lineWidth()); - else - gl3funcs->glPointSize(g->lineWidth()); + else { + QOpenGLContext *ctx = m_context->openglContext(); + if (!ctx->isOpenGLES() && g->drawingMode() == GL_POINTS) { + QOpenGLFunctions_1_0 *gl1funcs = 0; + QOpenGLFunctions_3_2_Core *gl3funcs = 0; + if (ctx->format().profile() == QSurfaceFormat::CoreProfile) + gl3funcs = ctx->versionFunctions(); + else + gl1funcs = ctx->versionFunctions(); + Q_ASSERT(gl1funcs || gl3funcs); + if (gl1funcs) + gl1funcs->glPointSize(g->lineWidth()); + else + gl3funcs->glPointSize(g->lineWidth()); + } } #endif } @@ -2610,6 +2613,8 @@ void Renderer::deleteRemovedElements() void Renderer::render() { + Q_ASSERT(m_context->openglContext() == QOpenGLContext::currentContext()); + if (Q_UNLIKELY(debug_dump())) { qDebug("\n"); QSGNodeDumper::dump(rootNode()); @@ -3152,7 +3157,7 @@ void Renderer::visualizeOverdraw() visualizeOverdraw_helper(m_nodes.value(rootNode())); // Animate the view... - QSurface *surface = QOpenGLContext::currentContext()->surface(); + QSurface *surface = m_context->openglContext()->surface(); if (surface->surfaceClass() == QSurface::Window) if (QQuickWindow *window = qobject_cast(static_cast(surface))) window->update(); -- cgit v1.2.3 From 43b6e0323ac5252dd29b193a7965a0ef3252736e Mon Sep 17 00:00:00 2001 From: Andras Mantia Date: Thu, 1 Feb 2018 20:01:13 +0200 Subject: Add back the optional heaptrack trace points This approach tracks object allocations only, when slots from already allocated memory segment are used. Change-Id: I514b974d7580c1236264bec96dc1abe594585e86 Reviewed-by: Milian Wolff Reviewed-by: Ulf Hermann Reviewed-by: Simon Hausmann --- src/qml/memory/qv4mm.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src') diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 4f4124d505..418c3444a4 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -321,6 +321,9 @@ bool Chunk::sweep(ExecutionEngine *engine) b->vtable()->destroy(b); b->_checkIsDestroyed(); } +#ifdef V4_USE_HEAPTRACK + heaptrack_report_free(itemToFree); +#endif } Q_V4_PROFILE_DEALLOC(engine, qPopulationCount((objectBitmap[i] | extendsBitmap[i]) - (blackBitmap[i] | e)) * Chunk::SlotSize, @@ -369,6 +372,9 @@ void Chunk::freeAll(ExecutionEngine *engine) b->vtable()->destroy(b); b->_checkIsDestroyed(); } +#ifdef V4_USE_HEAPTRACK + heaptrack_report_free(itemToFree); +#endif } Q_V4_PROFILE_DEALLOC(engine, (qPopulationCount(objectBitmap[i]|extendsBitmap[i]) - qPopulationCount(e)) * Chunk::SlotSize, Profiling::SmallItem); @@ -583,6 +589,9 @@ HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) { done: m->setAllocatedSlots(slotsRequired); Q_V4_PROFILE_ALLOC(engine, slotsRequired * Chunk::SlotSize, Profiling::SmallItem); +#ifdef V4_USE_HEAPTRACK + heaptrack_report_alloc(m, slotsRequired * Chunk::SlotSize); +#endif // DEBUG << " " << hex << m->chunk() << m->chunk()->objectBitmap[0] << m->chunk()->extendsBitmap[0] << (m - m->chunk()->realBase()); return m; } @@ -628,6 +637,9 @@ HeapItem *HugeItemAllocator::allocate(size_t size) { chunks.push_back(HugeChunk{c, size}); Chunk::setBit(c->objectBitmap, c->first() - c->realBase()); Q_V4_PROFILE_ALLOC(engine, size, Profiling::LargeItem); +#ifdef V4_USE_HEAPTRACK + heaptrack_report_alloc(c, size); +#endif return c->first(); } @@ -640,6 +652,9 @@ static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocato b->_checkIsDestroyed(); } chunkAllocator->free(c.chunk, c.size); +#ifdef V4_USE_HEAPTRACK + heaptrack_report_free(c.chunk); +#endif } void HugeItemAllocator::sweep() { -- cgit v1.2.3 From 5b0a98fa16330f220d3fbf67e9a55c8632d30129 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 5 Feb 2018 14:18:18 +0100 Subject: Clean up manual refcounting of compilation units Replace manual use in QQmlData and QQmlData::DeferredData with QQmlRefPointer. Due to forward declaration trouble this required declaring a non-inline constructor/destructor for QQmlData and DeferedData and disabling copying, so that not every C++ compilation unit including qqmldata_p.h needs to instantiate the QQmlRefPointer destructor and thus know whether QV4::CompiledData::CompilationUnit has release(), etc. The out-of-line declarations however should not have any negative impact as the only call sites are within qqmlengine.cpp, too. Change-Id: I2e8295cb0d7f876a5d7d18765dbac285184e6c99 Reviewed-by: Lars Knoll --- src/qml/qml/qqmldata_p.h | 10 ++++++++-- src/qml/qml/qqmlengine.cpp | 21 ++++++++++++++------- src/qml/qml/qqmlobjectcreator.cpp | 3 --- src/qml/qml/qqmlobjectcreator_p.h | 2 +- 4 files changed, 23 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index 5794e6f0c5..17d145f939 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -116,6 +117,7 @@ class Q_QML_PRIVATE_EXPORT QQmlData : public QAbstractDeclarativeData { public: QQmlData(); + ~QQmlData(); static inline void init() { static bool initialized = false; @@ -219,12 +221,15 @@ public: quint32 jsEngineId; // id of the engine that created the jsWrapper struct DeferredData { + DeferredData(); + ~DeferredData(); unsigned int deferredIdx; QMultiHash bindings; - QV4::CompiledData::CompilationUnit *compilationUnit;//Not always the same as the other compilation unit + QQmlRefPointer compilationUnit;//Not always the same as the other compilation unit QQmlContextData *context;//Could be either context or outerContext + Q_DISABLE_COPY(DeferredData); }; - QV4::CompiledData::CompilationUnit *compilationUnit; + QQmlRefPointer compilationUnit; QVector deferredData; void deferData(int objectIndex, QV4::CompiledData::CompilationUnit *, QQmlContextData *); @@ -299,6 +304,7 @@ private: const BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits; return bits[offset] & bitFlagForBit(bit); } + Q_DISABLE_COPY(QQmlData); }; bool QQmlData::wasDeleted(const QObject *object) diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index c09c048307..7dac0b3c8d 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -746,13 +746,17 @@ QQmlData::QQmlData() hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false), bindingBitsArraySize(InlineBindingArraySize), notifyList(0), bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0), - lineNumber(0), columnNumber(0), jsEngineId(0), compilationUnit(0), + lineNumber(0), columnNumber(0), jsEngineId(0), propertyCache(0), guards(0), extendedData(0) { memset(bindingBitsValue, 0, sizeof(bindingBitsValue)); init(); } +QQmlData::~QQmlData() +{ +} + void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o) { QQmlData *ddata = static_cast(d); @@ -924,6 +928,14 @@ void QQmlData::flushPendingBindingImpl(QQmlPropertyIndex index) QQmlPropertyData::DontRemoveBinding); } +QQmlData::DeferredData::DeferredData() +{ +} + +QQmlData::DeferredData::~DeferredData() +{ +} + bool QQmlEnginePrivate::baseModulesUninitialized = true; void QQmlEnginePrivate::init() { @@ -1651,7 +1663,6 @@ void QQmlData::deferData(int objectIndex, QV4::CompiledData::CompilationUnit *co QQmlData::DeferredData *deferData = new QQmlData::DeferredData; deferData->deferredIdx = objectIndex; deferData->compilationUnit = compilationUnit; - deferData->compilationUnit->addref(); deferData->context = context; const QV4::CompiledData::Object *compiledObject = compilationUnit->objectAt(objectIndex); @@ -1673,7 +1684,6 @@ void QQmlData::releaseDeferredData() while (it != deferredData.end()) { DeferredData *deferData = *it; if (deferData->bindings.isEmpty()) { - deferData->compilationUnit->release(); delete deferData; it = deferredData.erase(it); } else { @@ -1751,10 +1761,7 @@ void QQmlData::destroyed(QObject *object) if (bindings && !bindings->ref.deref()) delete bindings; - if (compilationUnit) { - compilationUnit->release(); - compilationUnit = 0; - } + compilationUnit = nullptr; releaseDeferredData(); diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index ad9687574f..78d732d02c 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -203,10 +203,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI if (instance) { QQmlData *ddata = QQmlData::get(instance); Q_ASSERT(ddata); - if (ddata->compilationUnit) - ddata->compilationUnit->release(); ddata->compilationUnit = compilationUnit; - ddata->compilationUnit->addref(); } if (topLevelCreator) diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 82fe22af72..21ee30acd0 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -137,7 +137,7 @@ private: QQmlEngine *engine; QV4::ExecutionEngine *v4; - QV4::CompiledData::CompilationUnit *compilationUnit; + QQmlRefPointer compilationUnit; const QV4::CompiledData::Unit *qmlUnit; QQmlGuardedContextData parentContext; QQmlContextData *context; -- cgit v1.2.3 From c6b3c69e014f846a142c2429cd2d675c75b74245 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 5 Feb 2018 14:49:46 +0100 Subject: Fix memory leak with deferred properties This is a regression introduced with commit 3b6eeee177b64eebe240d51be0c7bb5f031471d8 in the 5.9 branch. When constructing an object with deferred properties and not running qmlExecuteDeferred, then the deferred data would never get deleted because the bindings list remains non-empty and we would leak the deferred data as well as the entire compilation unit behind it. This happens for example when declaring when instantiating a QML file with states: states: [ State { ... }, State { ... }, ... } Unless every state is entered, its deferred changes property is never applied (via qmlExecuteDeferred) and thus the defer data is leaked. Task-number: QTBUG-66189 Change-Id: I1b2119c601d1e0ab4e37f53d4cf2f569586ee883 Reviewed-by: J-P Nurmi Reviewed-by: Lars Knoll --- src/qml/qml/qqmlengine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 7dac0b3c8d..f4656bafd2 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -1763,7 +1763,8 @@ void QQmlData::destroyed(QObject *object) compilationUnit = nullptr; - releaseDeferredData(); + qDeleteAll(deferredData); + deferredData.clear(); QQmlBoundSignal *signalHandler = signalHandlers; while (signalHandler) { -- cgit v1.2.3 From b704faaa45d3e3ca8bc7ce11aeb1e533a9563a0f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 13 Feb 2018 13:21:06 +0100 Subject: Fix typos Change-Id: I8afc27444e5c92b7c6aed3ff987dffb135bdfe46 Reviewed-by: Leena Miettinen --- src/3rdparty/masm/yarr/YarrPattern.cpp | 2 +- src/qml/jsruntime/qv4qmlcontext.cpp | 8 ++++---- src/qml/qml/qqmlerror.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/3rdparty/masm/yarr/YarrPattern.cpp b/src/3rdparty/masm/yarr/YarrPattern.cpp index ae527f065f..c7e5b6b09b 100644 --- a/src/3rdparty/masm/yarr/YarrPattern.cpp +++ b/src/3rdparty/masm/yarr/YarrPattern.cpp @@ -233,7 +233,7 @@ private: ranges.insert(i, CharacterRange(lo, hi)); return; } - // Okay, since we didn't hit the last case, the end of the new range is definitely at or after the begining + // Okay, since we didn't hit the last case, the end of the new range is definitely at or after the beginning // If the new range start at or before the end of the last range, then the overlap (if it starts one after the // end of the last range they concatenate, which is just as good. if (lo <= (ranges[i].end + 1)) { diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index 21af4270fd..9c33966cf7 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -108,8 +108,8 @@ ReturnedValue QQmlContextWrapper::get(const Managed *m, String *name, bool *hasP return result->asReturnedValue(); } - // Its possible we could delay the calculation of the "actual" context (in the case - // of sub contexts) until it is definately needed. + // It's possible we could delay the calculation of the "actual" context (in the case + // of sub contexts) until it is definitely needed. QQmlContextData *context = resource->getContext(); QQmlContextData *expressionContext = context; @@ -248,8 +248,8 @@ bool QQmlContextWrapper::put(Managed *m, String *name, const Value &value) return Object::put(m, name, value); } - // Its possible we could delay the calculation of the "actual" context (in the case - // of sub contexts) until it is definately needed. + // It's possible we could delay the calculation of the "actual" context (in the case + // of sub contexts) until it is definitely needed. QQmlContextData *context = wrapper->getContext(); QQmlContextData *expressionContext = context; diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp index 64f008cd32..1b264b025c 100644 --- a/src/qml/qml/qqmlerror.cpp +++ b/src/qml/qml/qqmlerror.cpp @@ -268,7 +268,7 @@ QtMsgType QQmlError::messageType() const \since 5.9 Sets the \a messageType for this message. The message type determines which - QDebug handlers are responsible for recieving the message. + QDebug handlers are responsible for receiving the message. */ void QQmlError::setMessageType(QtMsgType messageType) { -- cgit v1.2.3 From 874cd47ae427e6f08a6e362f28af5038a2bc9872 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Tue, 13 Feb 2018 11:05:22 +0100 Subject: doc: Add documentation for undocumented things There were several undocumented elements in the API that clang-qdoc warned about. These are now documented, although original authors might want to contribute better descriptions. A few uses of a macro "qdoc" were corrected to Q_CLANG_QDOC. Change-Id: I4e1d4c5f3266a334d7286e55ed1b113319de2273 Reviewed-by: Laszlo Agocs --- src/quick/scenegraph/coreapi/qsggeometry.cpp | 13 +++++++++++++ src/quick/scenegraph/coreapi/qsgmaterial.cpp | 5 +++++ src/quick/scenegraph/coreapi/qsgnode.cpp | 8 ++++++++ src/quick/scenegraph/coreapi/qsgnode.h | 7 +------ src/quick/scenegraph/coreapi/qsgrendernode.cpp | 18 +++++++++++++++++- src/quick/scenegraph/util/qsgimagenode.cpp | 11 ++++++++++- src/quick/scenegraph/util/qsgsimplematerial.h | 2 +- src/quick/scenegraph/util/qsgtexturematerial.cpp | 10 ++++++++++ 8 files changed, 65 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/quick/scenegraph/coreapi/qsggeometry.cpp b/src/quick/scenegraph/coreapi/qsggeometry.cpp index 69a8c21ed2..52366bfc35 100644 --- a/src/quick/scenegraph/coreapi/qsggeometry.cpp +++ b/src/quick/scenegraph/coreapi/qsggeometry.cpp @@ -768,6 +768,19 @@ void QSGGeometry::updateColoredRectGeometry(QSGGeometry *g, const QRectF &rect) v[3].y = rect.bottom(); } +/*! + \enum QSGGeometry::AttributeType + + This enum identifies several attribute types. + + \value UnknownAttribute Don't care + \value PositionAttribute Position + \value ColorAttribute Color + \value TexCoordAttribute Texture coordinate + \value TexCoord1Attribute Texture coordinate 1 + \value TexCoord2Attribute Texture coordinate 2 + + */ /*! \enum QSGGeometry::DataPattern diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp index 07dc87a643..5c28f4c82f 100644 --- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp +++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp @@ -443,7 +443,12 @@ void QSGMaterialShader::compile() otherwise returns \c false. */ +/*! + \fn bool QSGMaterialShader::RenderState::isCachedMaterialDataDirty() const + Returns \c true if the dirtyStates() contains the dirty cached material state, + otherwise returns \c false. + */ /*! \fn QSGMaterialShader::RenderState::DirtyStates QSGMaterialShader::RenderState::dirtyStates() const diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp index 22d57001fc..550a2182f8 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.cpp +++ b/src/quick/scenegraph/coreapi/qsgnode.cpp @@ -114,6 +114,10 @@ static void qt_print_node_count() \value DirtyOpacity The opacity of a QSGOpacityNode has changed. \value DirtySubtreeBlocked The subtree has been blocked. + \omitvalue DirtyForceUpdate + \omitvalue DirtyUsePreprocess + \omitvalue DirtyPropagationMask + \sa QSGNode::markDirty() */ @@ -135,6 +139,8 @@ static void qt_print_node_count() ownership over the opaque material and will delete it when the node is destroyed or a material is assigned. \value InternalReserved Reserved for internal use. + + \omitvalue IsVisitableNode */ /*! @@ -149,6 +155,8 @@ static void qt_print_node_count() \value OpacityNodeType The type of QSGOpacityNode \value RenderNodeType The type of QSGRenderNode + \omitvalue RootNodeType + \sa type() */ diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h index f2708b2b96..cd9d689dc1 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.h +++ b/src/quick/scenegraph/coreapi/qsgnode.h @@ -77,9 +77,7 @@ public: TransformNodeType, ClipNodeType, OpacityNodeType, -#ifndef qdoc RootNodeType, -#endif RenderNodeType }; @@ -96,9 +94,8 @@ public: OwnsOpaqueMaterial = 0x00040000, // Uppermost 8 bits are reserved for internal use. -#ifndef qdoc IsVisitableNode = 0x01000000 -#else +#ifdef Q_CLANG_QDOC InternalReserved = 0x01000000 #endif }; @@ -113,7 +110,6 @@ public: DirtyMaterial = 0x2000, DirtyOpacity = 0x4000, -#ifndef qdoc DirtyForceUpdate = 0x8000, DirtyUsePreprocess = UsePreprocess, @@ -122,7 +118,6 @@ public: | DirtyNodeAdded | DirtyOpacity | DirtyForceUpdate -#endif }; Q_DECLARE_FLAGS(DirtyState, DirtyStateBit) diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.cpp b/src/quick/scenegraph/coreapi/qsgrendernode.cpp index a8954848d6..5e259f2083 100644 --- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp +++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp @@ -212,6 +212,22 @@ void QSGRenderNode::releaseResources() { } +/*! + \enum QSGRenderNode::StateFlag + + This enum is a bit mask identifying several states. + + \value DepthState Depth + \value StencilState Stencil + \value ScissorState Scissor + \value ColorState Color + \value BlendState Blend + \value CullState Cull + \value ViewportState View poirt + \value RenderTargetState Render target + + */ + /*! \enum QSGRenderNode::RenderingFlag @@ -354,7 +370,7 @@ QSGRenderNode::RenderState::~RenderState() */ /*! - \fn const QRegion *QSGRenderNode::clipRegion() const + \fn const QRegion *QSGRenderNode::RenderState::clipRegion() const \return the current clip region or null for backends where clipping is implemented via stencil or scissoring. diff --git a/src/quick/scenegraph/util/qsgimagenode.cpp b/src/quick/scenegraph/util/qsgimagenode.cpp index c03c91d1cb..b154023247 100644 --- a/src/quick/scenegraph/util/qsgimagenode.cpp +++ b/src/quick/scenegraph/util/qsgimagenode.cpp @@ -168,7 +168,7 @@ QT_BEGIN_NAMESPACE */ /*! - \fn QSGImageNode::TextureCoordinatesTransformMode textureCoordinatesTransform() const + \fn QSGImageNode::TextureCoordinatesTransformMode QSGImageNode::textureCoordinatesTransform() const Returns the mode used to generate texture coordinates for this node. */ @@ -187,6 +187,15 @@ QT_BEGIN_NAMESPACE \return \c true if the node takes ownership of the texture; otherwise \c false. */ +/*! + Updates the geometry \a g with the \a texture, the coordinates + in \a rect, and the texture coordinates from \a sourceRect. + + \a g is assumed to be a triangle strip of four vertices of type + QSGGeometry::TexturedPoint2D. + + \a texCoordMode is used for normalizing the \a sourceRect. + */ void QSGImageNode::rebuildGeometry(QSGGeometry *g, QSGTexture *texture, const QRectF &rect, diff --git a/src/quick/scenegraph/util/qsgsimplematerial.h b/src/quick/scenegraph/util/qsgsimplematerial.h index b5b8815b4a..8a81917bd2 100644 --- a/src/quick/scenegraph/util/qsgsimplematerial.h +++ b/src/quick/scenegraph/util/qsgsimplematerial.h @@ -138,7 +138,7 @@ template class QSGSimpleMaterial : public QSGMaterial { public: -#ifndef qdoc +#ifndef Q_CLANG_QDOC QSGSimpleMaterial(const State &aState, PtrShaderCreateFunc func) : m_state(aState) , m_func(func) diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp index fbc8f27a63..0f9ee9cfde 100644 --- a/src/quick/scenegraph/util/qsgtexturematerial.cpp +++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp @@ -304,7 +304,17 @@ void QSGOpaqueTextureMaterial::setTexture(QSGTexture *texture) The default vertical wrap mode is \c QSGTexture::ClampToEdge. */ +/*! + \fn void QSGOpaqueTextureMaterial::setAnisotropyLevel(QSGTexture::AnisotropyLevel level) + + Sets this material's anistropy level to \a level. +*/ + +/*! + \fn QSGTexture::AnisotropyLevel QSGOpaqueTextureMaterial::anisotropyLevel() const + Returns this material's anistropy level. +*/ /*! \internal -- cgit v1.2.3 From 9e32901835de1c6729ac8bf228148c1e03c4c5a5 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 13 Feb 2018 15:20:22 +0100 Subject: Clear the last value when removing properties When we remove a property from an object, we shrink the used entries by one (or 2 when an accessor is defined) by moving subsequent entries "down" over the removed entry. We also have to set the last entry (or 2) to Undefined, otherwise any heap objects referenced there would be retained. Task-number: QTBUG-66090 Change-Id: I75905fafd0d88891820d894a869b9714bc9807e0 Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4internalclass.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index d439884ca2..4041052344 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -149,6 +149,9 @@ static void removeFromPropertyData(Object *object, int idx, bool accessor = fals int size = o->internalClass->size; for (int i = idx; i < size; ++i) o->setProperty(v4, i, *o->propertyData(i + (accessor ? 2 : 1))); + o->setProperty(v4, size, Primitive::undefinedValue()); + if (accessor) + o->setProperty(v4, size + 1, Primitive::undefinedValue()); } void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index) -- cgit v1.2.3 From 8190fd16f8d77b22424e3a46d9aac453ecb0fe34 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 14 Feb 2018 13:21:49 +0100 Subject: qqmlprofilereventreceiver_p.h: Add "We mean it" comment Fix warning: QtQmlDebug: WARNING: .../src/qmldebug/qqmlprofilereventreceiver_p.h does not have the "We mean it." warning Amends b82296f825daf0ba110fea4aa1b61f96d63f371b. Change-Id: I540bee466be96ba787283bfc7b1d5c36066df2ed Reviewed-by: Ulf Hermann --- src/qmldebug/qqmlprofilereventreceiver_p.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src') diff --git a/src/qmldebug/qqmlprofilereventreceiver_p.h b/src/qmldebug/qqmlprofilereventreceiver_p.h index ee8e592858..defe64a42e 100644 --- a/src/qmldebug/qqmlprofilereventreceiver_p.h +++ b/src/qmldebug/qqmlprofilereventreceiver_p.h @@ -45,6 +45,17 @@ #include +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + QT_BEGIN_NAMESPACE class QQmlProfilerEventReceiver : public QObject -- cgit v1.2.3 From 238cc098d785b4fe76fbc8422b340d98ff8c1a1b Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 15 Feb 2018 11:12:36 +0100 Subject: Fix crash with the software renderer and windows with QObject parent When a QQuickWindow is a child of another QObject (such as a Loader) and is scheduled for deletion using a deferred delete event, then a deletion via the parent ends up calling the window's destructor, which will finally end up in ~QObject(), which takes care of removing the posted deferred deletion event from the event queue. In the case of QQuickWindow, the destructor - called before ~QObject - calls windowDestroyed(this) on the SG render loop. The implementation in the software renderer calls QCoreApplication::sendPostedEvents() with QEvent::DeferedDelete, which ends up deleting the same window a second time and resulting in a crash. I can't see a good reason for the existence of the sendPostedEvents() call there. It is not present in the other render loops and according to git blame it stems from the very early first implementation of the software renderer where surely copy & paste from other render loop code was involved back then. The same fix is applied to the single-threaded VG and D3D12 render loops, as they are most likely copy & paste from the software render loop implementation. ASAN trace for tst_qquickwindow::unloadSubWindow() on 5.11 branch that shows invalid access to the QObjectPrivate/QQuickWindowPrivate, which follows the QObject in terms of life-cycle: ==4736==ERROR: AddressSanitizer: heap-use-after-free on address 0x617000011778 at pc 0x7fdd211cfbb3 bp 0x7fffecb47ea0 sp 0x7fffecb47e90 READ of size 8 at 0x617000011778 thread T0 #0 0x7fdd211cfbb2 in QQuickWindow::~QQuickWindow() items/qquickwindow.cpp:1308 #1 0x7fdd21470974 in QQuickWindowQmlImpl::~QQuickWindowQmlImpl() items/qquickwindowmodule_p.h:63 #2 0x7fdd21470974 in QQmlPrivate::QQmlElement::~QQmlElement() .../qqmlprivate.h:103 #3 0x7fdd21470974 in QQmlPrivate::QQmlElement::~QQmlElement() .../qqmlprivate.h:103 #4 0x7fdd1e24da24 in qDeleteInEventHandler(QObject*) kernel/qobject.cpp:4601 #5 0x7fdd1e253d2f in QObject::event(QEvent*) kernel/qobject.cpp:1240 #6 0x7fdd1fbd1d41 in QWindow::event(QEvent*) kernel/qwindow.cpp:2356 #7 0x7fdd211f778e in QQuickWindow::event(QEvent*) items/qquickwindow.cpp:1628 #8 0x7fdd1e1a4e3c in QCoreApplicationPrivate::notify_helper(QObject*, QEvent*) kernel/qcoreapplication.cpp:1216 #9 0x7fdd1e1a508b in doNotify kernel/qcoreapplication.cpp:1157 #10 0x7fdd1e1a555a in QCoreApplication::notify(QObject*, QEvent*) kernel/qcoreapplication.cpp:1143 #11 0x7fdd1fb87665 in QGuiApplication::notify(QObject*, QEvent*) kernel/qguiapplication.cpp:1723 #12 0x7fdd1e1a52fa in QCoreApplication::notifyInternal2(QObject*, QEvent*) kernel/qcoreapplication.cpp:1067 #13 0x7fdd1e1b6ed2 in QCoreApplication::sendEvent(QObject*, QEvent*) ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:234 #14 0x7fdd1e1b6ed2 in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) kernel/qcoreapplication.cpp:1764 #15 0x7fdd1e1b8cda in QCoreApplication::sendPostedEvents(QObject*, int) kernel/qcoreapplication.cpp:1618 #16 0x7fdd210cb034 in QSGSoftwareRenderLoop::windowDestroyed(QQuickWindow*) scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp:100 #17 0x7fdd211cfb8c in QQuickWindow::~QQuickWindow() items/qquickwindow.cpp:1305 [...] 0x617000011778 is located 632 bytes inside of 704-byte region [0x617000011500,0x6170000117c0) freed by thread T0 here: #0 0x7fdd21a8a9d8 in operator delete(void*, unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xe19d8) #1 0x7fdd2146fa3c in QQuickWindowQmlImplPrivate::~QQuickWindowQmlImplPrivate() items/qquickwindowmodule.cpp:57 #2 0x7fdd1e26b252 in QScopedPointerDeleter::cleanup(QObjectData*) [...] #3 0x7fdd1e26b252 in QScopedPointer >::~QScopedPointer() [...] #4 0x7fdd1e26b252 in QObject::~QObject() kernel/qobject.cpp:882 #5 0x7fdd1fbcf51c in QWindow::~QWindow() kernel/qwindow.cpp:211 #6 0x7fdd211d0466 in QQuickWindow::~QQuickWindow() items/qquickwindow.cpp:1297 #7 0x7fdd211d0644 in QQuickWindow::~QQuickWindow() items/qquickwindow.cpp:1335 #8 0x7fdd1e2666b4 in QObjectPrivate::deleteChildren() kernel/qobject.cpp:1995 #9 0x7fdd1e26b329 in QObject::~QObject() kernel/qobject.cpp:1023 [...] Change-Id: Iffa90d365d02b074e2a78c5be2895c9f86a4b80e Task-number: QTBUG-66381 Reviewed-by: Shawn Rutledge Reviewed-by: Andy Nichols --- src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp | 3 --- src/plugins/scenegraph/openvg/qsgopenvgrenderloop.cpp | 1 - src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp | 1 - 3 files changed, 5 deletions(-) (limited to 'src') diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp index 0d3f78d95d..0d501f48c0 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp @@ -145,9 +145,6 @@ void QSGD3D12RenderLoop::windowDestroyed(QQuickWindow *window) rc->invalidate(); - if (m_windows.isEmpty()) - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); - delete rc; delete engine; diff --git a/src/plugins/scenegraph/openvg/qsgopenvgrenderloop.cpp b/src/plugins/scenegraph/openvg/qsgopenvgrenderloop.cpp index d31156f0eb..9493920100 100644 --- a/src/plugins/scenegraph/openvg/qsgopenvgrenderloop.cpp +++ b/src/plugins/scenegraph/openvg/qsgopenvgrenderloop.cpp @@ -91,7 +91,6 @@ void QSGOpenVGRenderLoop::windowDestroyed(QQuickWindow *window) rc->invalidate(); delete vg; vg = nullptr; - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); } else if (vg && window == vg->window()) { vg->doneCurrent(); } diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp index 3f0d1383b9..423f5f7321 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp @@ -97,7 +97,6 @@ void QSGSoftwareRenderLoop::windowDestroyed(QQuickWindow *window) if (m_windows.size() == 0) { rc->invalidate(); - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); } } -- cgit v1.2.3