diff options
author | Simon Hausmann <simon.hausmann@theqtcompany.com> | 2016-05-02 16:55:36 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2016-09-30 08:17:39 +0000 |
commit | c9ffed92a0dee0ae00a9632177ea42f85ea8a48c (patch) | |
tree | cf56b80e4d9771193ca179f58108ecb2a94671fb /src/qml/qml | |
parent | 79cfc8788d6267eeb263983466ba21758f618dcd (diff) |
Fix crash with window-less QQuickItems
Mark QQuickItem visual children directly in QQuickItem instead of
relying on the item being a (grand) child of a window.
[ChangeLog][QtQuick] Fix crash with QQuickItems created via JavaScript being
garbage collected sometimes when they're not assigned to a window.
This may happen even in qmlscene when between the creation of the root item and
the assignment to the QQuickWindow the garbage collector runs.
The previous approach of a persistent in QQuickView marking the visual item
hierarchy relies on the existence of a view. The only thing left to do in the
view and qml window implementation is enforcing the CppOwnership policy set on
the content item in QQuickWindow by ensuring the presence of the JS wrapper,
replacing the persistent with a weak value.
This also introduces a new internal mechanism for QObject sub-classes to
provide their own V4 JS wrapper types.
Task-number: QTBUG-39888
Change-Id: Icd45a636a6d4e4528fc19165b13f4e1ca7967087
Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
Diffstat (limited to 'src/qml/qml')
-rw-r--r-- | src/qml/qml/qqmldata_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 11 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycache.cpp | 14 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycache_p.h | 16 |
4 files changed, 33 insertions, 10 deletions
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index ef05dd1fd7..e0e5b221ec 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -217,7 +217,7 @@ public: static inline void flushPendingBinding(QObject *, int coreIndex); - static void ensurePropertyCache(QJSEngine *engine, QObject *object); + static QQmlPropertyCache *ensurePropertyCache(QJSEngine *engine, QObject *object); private: // For attachedProperties diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 8f22533472..5db918dd73 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -1808,14 +1808,15 @@ void QQmlData::setPendingBindingBit(QObject *obj, int coreIndex) QQmlData_setBit(this, obj, coreIndex * 2 + 1); } -void QQmlData::ensurePropertyCache(QJSEngine *engine, QObject *object) +QQmlPropertyCache *QQmlData::ensurePropertyCache(QJSEngine *engine, QObject *object) { Q_ASSERT(engine); QQmlData *ddata = QQmlData::get(object, /*create*/true); - if (ddata->propertyCache) - return; - ddata->propertyCache = QJSEnginePrivate::get(engine)->cache(object); - if (ddata->propertyCache) ddata->propertyCache->addref(); + if (!ddata->propertyCache){ + ddata->propertyCache = QJSEnginePrivate::get(engine)->cache(object); + if (ddata->propertyCache) ddata->propertyCache->addref(); + } + return ddata->propertyCache; } void QQmlEnginePrivate::sendQuit() diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index e8c9989fdf..be730c7ac9 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -234,7 +234,7 @@ Creates a new empty QQmlPropertyCache. QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e) : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false), - _metaObject(0), argumentsCache(0) + _metaObject(0), argumentsCache(0), _jsFactoryMethodIndex(-1) { Q_ASSERT(engine); } @@ -245,7 +245,7 @@ Creates a new QQmlPropertyCache of \a metaObject. QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e, const QMetaObject *metaObject) : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false), - _metaObject(0), argumentsCache(0) + _metaObject(0), argumentsCache(0), _jsFactoryMethodIndex(-1) { Q_ASSERT(engine); Q_ASSERT(metaObject); @@ -518,10 +518,16 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, for (int ii = 0; ii < classInfoCount; ++ii) { int idx = ii + classInfoOffset; - if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) { + const char * const classInfoName = metaObject->classInfo(idx).name(); + if (0 == qstrcmp(classInfoName, "qt_HasQmlAccessors")) { hasFastProperty = true; - } else if (0 == qstrcmp(metaObject->classInfo(idx).name(), "DefaultProperty")) { + } else if (0 == qstrcmp(classInfoName, "DefaultProperty")) { _defaultPropertyName = QString::fromUtf8(metaObject->classInfo(idx).value()); + } else if (0 == qstrcmp(classInfoName, "qt_QmlJSWrapperFactoryMethod")) { + const char * const factoryMethod = metaObject->classInfo(idx).value(); + _jsFactoryMethodIndex = metaObject->indexOfSlot(factoryMethod); + if (_jsFactoryMethodIndex != -1) + _jsFactoryMethodIndex -= metaObject->methodOffset(); } } diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 610709ef7f..046e75ad3a 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -75,6 +75,8 @@ class QQmlPropertyCacheCreator; class QQmlPropertyRawData { public: + typedef QObjectPrivate::StaticMetaCallFunction StaticMetaCallFunction; + enum Flag { NoFlags = 0x00000000, ValueTypeFlagMask = 0x0000FFFF, // Flags in valueTypeFlags must fit in this mask @@ -322,6 +324,8 @@ public: void toMetaObjectBuilder(QMetaObjectBuilder &); + inline bool callJSFactoryMethod(QObject *object, void **args) const; + protected: virtual void destroy(); virtual void clear(); @@ -390,6 +394,7 @@ private: QByteArray _dynamicStringData; QString _defaultPropertyName; QQmlPropertyCacheMethodArguments *argumentsCache; + int _jsFactoryMethodIndex; }; // QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache. @@ -538,6 +543,17 @@ int QQmlPropertyCache::signalOffset() const return signalHandlerIndexCacheStart; } +bool QQmlPropertyCache::callJSFactoryMethod(QObject *object, void **args) const +{ + if (_jsFactoryMethodIndex != -1) { + _metaObject->d.static_metacall(object, QMetaObject::InvokeMetaMethod, _jsFactoryMethodIndex, args); + return true; + } + if (_parent) + return _parent->callJSFactoryMethod(object, args); + return false; +} + QQmlMetaObject::QQmlMetaObject() { } |