Timo Jyrinki has proposed merging lp:~timo-jyrinki/kubuntu-packaging/qtdeclarative-opensource-src_530ubuntu8 into lp:~kubuntu-packagers/kubuntu-packaging/qtdeclarative-opensource-src.
Requested reviews: Kubuntu Packagers (kubuntu-packagers) Related bugs: Bug #1349297 in qtdeclarative-opensource-src (Ubuntu): "Better fix for crash due to wrong objects being garbage collected" https://bugs.launchpad.net/ubuntu/+source/qtdeclarative-opensource-src/+bug/1349297 For more details, see: https://code.launchpad.net/~timo-jyrinki/kubuntu-packaging/qtdeclarative-opensource-src_530ubuntu8/+merge/229651 -- https://code.launchpad.net/~timo-jyrinki/kubuntu-packaging/qtdeclarative-opensource-src_530ubuntu8/+merge/229651 Your team Kubuntu Packagers is requested to review the proposed merge of lp:~timo-jyrinki/kubuntu-packaging/qtdeclarative-opensource-src_530ubuntu8 into lp:~kubuntu-packagers/kubuntu-packaging/qtdeclarative-opensource-src.
=== modified file 'debian/changelog' --- debian/changelog 2014-07-07 08:43:27 +0000 +++ debian/changelog 2014-08-05 16:02:47 +0000 @@ -1,3 +1,21 @@ +qtdeclarative-opensource-src (5.3.0-3ubuntu8) utopic; urgency=medium + + [ MichaĆ Sawicz ] + * debian/patches/8454a21b-Flickable-Cancel-interaction-on-interactive-changes.patch + - Fix flickable interaction (LP: #1349705) + * debian/control + * debian/rules + - Force gcc-4.8 to avoid symbols changes + + [ Timo Jyrinki ] + * debian/patches/parenttosubcreator_qqmlobjectcreator.patch: + - Drop, rejected by upstream + * debian/patches/Fix-crash-when-deleting-component-in-Component.onCom.patch + debian/patches/Fix-interaction-of-garbage-collector-with-JS-objects.patch: + - Replace the old patch with accepted upstream approach (LP: #1349297) + + -- Timo Jyrinki <timo-jyri...@ubuntu.com> Mon, 04 Aug 2014 10:58:28 +0000 + qtdeclarative-opensource-src (5.3.0-3ubuntu7) utopic; urgency=medium * debian/patches/Support-RFC2822Date-date-format-similar-to-V8.patch === modified file 'debian/control' --- debian/control 2014-06-19 19:14:47 +0000 +++ debian/control 2014-08-05 16:02:47 +0000 @@ -11,6 +11,8 @@ Timo Jyrinki <t...@debian.org> Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1), +# Avoiding symbols updates due to switch to gcc 4.9 by default. + g++-4.8, libqt5xmlpatterns5-private-dev (>= 5.3.0-0~), pkg-kde-tools (>= 0.15.12~), python, === added file 'debian/patches/8454a21b-Flickable-Cancel-interaction-on-interactive-changes.patch' --- debian/patches/8454a21b-Flickable-Cancel-interaction-on-interactive-changes.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/8454a21b-Flickable-Cancel-interaction-on-interactive-changes.patch 2014-08-05 16:02:47 +0000 @@ -0,0 +1,152 @@ +From 8454a21b837ccf3968f6dbc56ed4f06d60d63c8f Mon Sep 17 00:00:00 2001 +From: Albert Astals Cid <albert.ast...@canonical.com> +Date: Wed, 23 Jul 2014 15:40:42 +0200 +Subject: [PATCH] Flickable: Cancel interaction on interactive changes + +Otherwise if you have a listview with a flickable inside with a mouseare inside +the pressed is never set to false if you make the interactive property of the +outer list depend on the moving of the inner flickable. This makes that when +later you change currentIndex of the list and you have +StrictlyEnforceRange set, the list won't move because it still thinks it is pressed + +Change-Id: I2c2021f486fc0a31840c3f2199bc7cb76dc01e3e +Reviewed-by: Martin Jones <martin.jo...@jollamobile.com> +--- + src/quick/items/qquickflickable.cpp | 41 ++++++++++++++-------------- + src/quick/items/qquickflickable_p_p.h | 2 ++ + tests/auto/qmltest/listview/tst_listview.qml | 41 ++++++++++++++++++++++++++++ + 3 files changed, 63 insertions(+), 21 deletions(-) + +diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp +index ee71ea8..63dde66 100644 +--- a/src/quick/items/qquickflickable.cpp ++++ b/src/quick/items/qquickflickable.cpp +@@ -763,15 +763,8 @@ void QQuickFlickable::setInteractive(bool interactive) + Q_D(QQuickFlickable); + if (interactive != d->interactive) { + d->interactive = interactive; +- if (!interactive && (d->hData.flicking || d->vData.flicking)) { +- d->clearTimeline(); +- d->hData.vTime = d->vData.vTime = d->timeline.time(); +- d->hData.flicking = false; +- d->vData.flicking = false; +- emit flickingChanged(); +- emit flickingHorizontallyChanged(); +- emit flickingVerticallyChanged(); +- emit flickEnded(); ++ if (!interactive) { ++ d->cancelInteraction(); + } + emit interactiveChanged(); + } +@@ -2015,18 +2008,24 @@ bool QQuickFlickable::yflick() const + void QQuickFlickable::mouseUngrabEvent() + { + Q_D(QQuickFlickable); +- if (d->pressed) { +- // if our mouse grab has been removed (probably by another Flickable), +- // fix our state +- d->clearDelayedPress(); +- d->pressed = false; +- d->draggingEnding(); +- d->stealMouse = false; +- setKeepMouseGrab(false); +- d->fixupX(); +- d->fixupY(); +- if (!d->isViewMoving()) +- movementEnding(); ++ // if our mouse grab has been removed (probably by another Flickable), ++ // fix our state ++ d->cancelInteraction(); ++} ++ ++void QQuickFlickablePrivate::cancelInteraction() ++{ ++ Q_Q(QQuickFlickable); ++ if (pressed) { ++ clearDelayedPress(); ++ pressed = false; ++ draggingEnding(); ++ stealMouse = false; ++ q->setKeepMouseGrab(false); ++ fixupX(); ++ fixupY(); ++ if (!isViewMoving()) ++ q->movementEnding(); + } + } + +diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h +index 33a642e..13af2e0 100644 +--- a/src/quick/items/qquickflickable_p_p.h ++++ b/src/quick/items/qquickflickable_p_p.h +@@ -200,6 +200,8 @@ public: + + bool isViewMoving() const; + ++ void cancelInteraction(); ++ + public: + QQuickItem *contentItem; + +diff --git a/tests/auto/qmltest/listview/tst_listview.qml b/tests/auto/qmltest/listview/tst_listview.qml +index 03be579..069b62a 100644 +--- a/tests/auto/qmltest/listview/tst_listview.qml ++++ b/tests/auto/qmltest/listview/tst_listview.qml +@@ -108,6 +108,33 @@ Item { + property int createdDelegates: 0 + } + ++ ListView ++ { ++ id: listInteractiveCurrentIndexEnforce ++ width: 600 ++ height: 600 ++ ++ snapMode: ListView.SnapOneItem ++ orientation: ListView.Horizontal ++ interactive: !currentItem.moving ++ highlightRangeMode: ListView.StrictlyEnforceRange ++ ++ model: 4 ++ ++ focus: true ++ Keys.onPressed: if (event.key == Qt.Key_K) currentIndex = currentIndex + 1; ++ ++ delegate: Flickable { ++ width: 600 ++ height: 600 ++ contentWidth: 600 ++ contentHeight: 1200 ++ ++ MouseArea { anchors.fill: parent } ++ Rectangle { anchors.fill: parent; color: index == 0 ? "red" : index == 1 ? "green" : index == 2 ? "blue" : "white" } ++ } ++ } ++ + Component { + id: delegateModelAfterCreateComponent + Rectangle { +@@ -272,5 +299,19 @@ Item { + listViewDelegateModelAfterCreate.model = 40; + verify(listViewDelegateModelAfterCreate.createdDelegates > 0); + } ++ ++ function test_listInteractiveCurrentIndexEnforce() { ++ mousePress(listInteractiveCurrentIndexEnforce, 10, 50); ++ mouseMove(listInteractiveCurrentIndexEnforce, 10, 40); ++ mouseMove(listInteractiveCurrentIndexEnforce, 10, 30); ++ mouseMove(listInteractiveCurrentIndexEnforce, 10, 20); ++ mouseMove(listInteractiveCurrentIndexEnforce, 10, 10); ++ compare(listInteractiveCurrentIndexEnforce.interactive, false); ++ mouseRelease(listInteractiveCurrentIndexEnforce, 10, 10); ++ tryCompare(listInteractiveCurrentIndexEnforce, "interactive", true); ++ keyClick("k"); ++ compare(listInteractiveCurrentIndexEnforce.currentIndex, 1); ++ tryCompare(listInteractiveCurrentIndexEnforce, "contentX", listInteractiveCurrentIndexEnforce.width); ++ } + } + } +-- +2.0.1 + === added file 'debian/patches/Fix-crash-when-deleting-component-in-Component.onCom.patch' --- debian/patches/Fix-crash-when-deleting-component-in-Component.onCom.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/Fix-crash-when-deleting-component-in-Component.onCom.patch 2014-08-05 16:02:47 +0000 @@ -0,0 +1,129 @@ +From 195b998175b629e6e915588e66991f74cffa4e48 Mon Sep 17 00:00:00 2001 +From: Simon Hausmann <simon.hausm...@digia.com> +Date: Fri, 20 Jun 2014 17:26:57 +0200 +Subject: [PATCH] Fix crash when deleting component in Component.onComplete + through loader + +This is a regression introduced with Qt 5.3.0. The recursion watcher code that +is supposed to handle the test case of QTBUG-39775 can detect the recursion +into the object creator. However the boolean that indicates the recursion is a +member of a structure that's deleted afterwards. To avoid access to deleted +memory, this patch simply reference counts data structure shared between the +creators and also wraps the recursion watcher into a convenience class that +also increases/decreases the reference count accordingly. + +Change-Id: I8d2e3e200ab1295e89d951e09f187d382a056d5a +Task-number: QTBUG-39775 +Reviewed-by: Lars Knoll <lars.kn...@digia.com> +--- + src/qml/qml/qqmlobjectcreator.cpp | 17 ++++++++++++----- + src/qml/qml/qqmlobjectcreator_p.h | 18 ++++++++++++++++-- + 2 files changed, 28 insertions(+), 7 deletions(-) + +diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp +index 16c9dd7..36c7dfb 100644 +--- a/src/qml/qml/qqmlobjectcreator.cpp ++++ b/src/qml/qml/qqmlobjectcreator.cpp +@@ -91,7 +91,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile + init(parentContext); + + sharedState = new QQmlObjectCreatorSharedState; +- sharedState.setFlag(); // We own it, so we must delete it ++ topLevelCreator = true; + sharedState->componentAttached = 0; + sharedState->allCreatedBindings.allocate(compiledData->totalBindingsCount); + sharedState->allParserStatusCallbacks.allocate(compiledData->totalParserStatusCount); +@@ -115,6 +115,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile + init(parentContext); + + sharedState = inheritedSharedState; ++ topLevelCreator = false; + } + + void QQmlObjectCreator::init(QQmlContextData *providedParentContext) +@@ -139,9 +140,9 @@ void QQmlObjectCreator::init(QQmlContextData *providedParentContext) + + QQmlObjectCreator::~QQmlObjectCreator() + { +- if (sharedState.flag()) { ++ if (topLevelCreator) { + { +- QRecursionWatcher<QQmlObjectCreatorSharedState, &QQmlObjectCreatorSharedState::recursionNode> watcher(sharedState.data()); ++ QQmlObjectCreatorRecursionWatcher watcher(this); + } + for (int i = 0; i < sharedState->allCreatedBindings.count(); ++i) { + QQmlAbstractBinding *b = sharedState->allCreatedBindings.at(i); +@@ -157,7 +158,6 @@ QQmlObjectCreator::~QQmlObjectCreator() + QQmlComponentAttached *a = sharedState->componentAttached; + a->rem(); + } +- delete sharedState.data(); + } + } + +@@ -1172,7 +1172,7 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru + Q_ASSERT(phase == ObjectsCreated || phase == Finalizing); + phase = Finalizing; + +- QRecursionWatcher<QQmlObjectCreatorSharedState, &QQmlObjectCreatorSharedState::recursionNode> watcher(sharedState.data()); ++ QQmlObjectCreatorRecursionWatcher watcher(this); + ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine)); + + { +@@ -1334,3 +1334,10 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * + } + + ++ ++ ++QQmlObjectCreatorRecursionWatcher::QQmlObjectCreatorRecursionWatcher(QQmlObjectCreator *creator) ++ : sharedState(creator->sharedState) ++ , watcher(creator->sharedState.data()) ++{ ++} +diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h +index 379a3b2..ad2d676 100644 +--- a/src/qml/qml/qqmlobjectcreator_p.h ++++ b/src/qml/qml/qqmlobjectcreator_p.h +@@ -57,7 +57,7 @@ struct QQmlTypeCompiler; + class QQmlInstantiationInterrupt; + struct QQmlVmeProfiler; + +-struct QQmlObjectCreatorSharedState ++struct QQmlObjectCreatorSharedState : public QSharedData + { + QQmlContextData *rootContext; + QQmlContextData *creationContext; +@@ -128,7 +128,8 @@ private: + const QVector<QQmlPropertyCache *> &propertyCaches; + const QVector<QByteArray> &vmeMetaObjectData; + QHash<int, int> objectIndexToId; +- QFlagPointer<QQmlObjectCreatorSharedState> sharedState; ++ QExplicitlySharedDataPointer<QQmlObjectCreatorSharedState> sharedState; ++ bool topLevelCreator; + void *activeVMEDataForRootContext; + + QObject *_qobject; +@@ -142,6 +143,19 @@ private: + QQmlVMEMetaObject *_vmeMetaObject; + QQmlListProperty<void> _currentList; + QV4::ExecutionContext *_qmlContext; ++ ++ friend struct QQmlObjectCreatorRecursionWatcher; ++}; ++ ++struct QQmlObjectCreatorRecursionWatcher ++{ ++ QQmlObjectCreatorRecursionWatcher(QQmlObjectCreator *creator); ++ ++ bool hasRecursed() const { return watcher.hasRecursed(); } ++ ++private: ++ QExplicitlySharedDataPointer<QQmlObjectCreatorSharedState> sharedState; ++ QRecursionWatcher<QQmlObjectCreatorSharedState, &QQmlObjectCreatorSharedState::recursionNode> watcher; + }; + + QT_END_NAMESPACE +-- +2.0.1 + === added file 'debian/patches/Fix-interaction-of-garbage-collector-with-JS-objects.patch' --- debian/patches/Fix-interaction-of-garbage-collector-with-JS-objects.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/Fix-interaction-of-garbage-collector-with-JS-objects.patch 2014-08-05 16:02:47 +0000 @@ -0,0 +1,335 @@ +From 14bc8dc3f3016889cfcbdbe7309b09be7687ebe0 Mon Sep 17 00:00:00 2001 +From: Simon Hausmann <simon.hausm...@digia.com> +Date: Wed, 14 May 2014 16:04:33 +0200 +Subject: [PATCH] Fix interaction of garbage collector with JS objects during + QML type instantiation + +It may happen that during the lengthy process of instantiating a tree of +objects for QML, the garbage collector runs. + +For objects created by QML we support different ownership models, for example +in QtQuick visual parents keep their visual children alive, despite perhaps a +lack of QObject parentship. That ownership becomes active once the QML +autoparent function has assigned the correct visual parent, which happens after +object instantiation (after QQmlObjectCreator). + +Similarly when a composite type is created, its QObject parent is only set +after all properties have been set. The root QObject is kept alive through a +special boolean, but if the sub-objects aren't children yet, their JS wrapper +might get deleted. For composite types with var properties, that also means +their var properties get deleted, such as the model property of TableView.qml +in the bug report. + +In the future we want to support creating QWidget hierarchies with QML, which +also for layouts may rely on a delayed parent assignment for layouts. + +To accommodate all this, this patch introduces an array on the JS stack that +keeps track of all JS wrappers for all QObjects created. This array is alive +during object tree creation. Afterwards, the different ownership models take +over, for example the auto parent function assigning a visual parent. + +This patch also fixes an off-by-one in the total object count calculation +for composite types, where when instantiating a composite type as a sub-object +we counted the sub composite's object count but forgot the object itself. + +Task-number: QTBUG-38835 +Task-number: QTBUG-39966 +Change-Id: I6104b2434510642081e0c54793ed296adeca7481 +Reviewed-by: Lars Knoll <lars.kn...@digia.com> +--- + src/qml/compiler/qqmltypecompiler.cpp | 4 +- + src/qml/qml/qqmlobjectcreator.cpp | 27 +++++++--- + src/qml/qml/qqmlobjectcreator_p.h | 1 + + tests/auto/qml/qqmlecmascript/testtypes.cpp | 60 ++++++++++++++++++++++ + tests/auto/qml/qqmlecmascript/testtypes.h | 45 ++++++++++++++++ + .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 28 ++++++++++ + 6 files changed, 157 insertions(+), 8 deletions(-) + +diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp +index 60a0829..dacaa14 100644 +--- a/src/qml/compiler/qqmltypecompiler.cpp ++++ b/src/qml/compiler/qqmltypecompiler.cpp +@@ -277,12 +277,12 @@ bool QQmlTypeCompiler::compile() + if (qmlType->parserStatusCast() != -1) + ++parserStatusCount; + } ++ ++objectCount; + if (typeRef->component) { + bindingCount += typeRef->component->totalBindingsCount; + parserStatusCount += typeRef->component->totalParserStatusCount; + objectCount += typeRef->component->totalObjectCount; +- } else +- ++objectCount; ++ } + } + } + +diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp +index 36c7dfb..1de467b 100644 +--- a/src/qml/qml/qqmlobjectcreator.cpp ++++ b/src/qml/qml/qqmlobjectcreator.cpp +@@ -96,6 +96,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile + sharedState->allCreatedBindings.allocate(compiledData->totalBindingsCount); + sharedState->allParserStatusCallbacks.allocate(compiledData->totalParserStatusCount); + sharedState->allCreatedObjects.allocate(compiledData->totalObjectCount); ++ sharedState->allJavaScriptObjects = 0; + sharedState->creationContext = creationContext; + sharedState->rootContext = 0; + +@@ -195,6 +196,13 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI + sharedState->rootContext->isRootObjectInCreation = true; + } + ++ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); ++ QV4::Scope scope(v4); ++ ++ Q_ASSERT(sharedState->allJavaScriptObjects || topLevelCreator); ++ if (topLevelCreator) ++ sharedState->allJavaScriptObjects = scope.alloc(compiledData->totalObjectCount); ++ + QVector<QQmlContextData::ObjectIdMapping> mapping(objectIndexToId.count()); + for (QHash<int, int>::ConstIterator it = objectIndexToId.constBegin(), end = objectIndexToId.constEnd(); + it != end; ++it) { +@@ -208,8 +216,6 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI + context->setIdPropertyData(mapping); + + if (subComponentIndex == -1) { +- QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); +- QV4::Scope scope(v4); + QV4::ScopedObject scripts(scope, v4->newArrayObject(compiledData->scripts.count())); + context->importedScripts = scripts; + for (int i = 0; i < compiledData->scripts.count(); ++i) { +@@ -230,6 +236,9 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI + ddata->compiledData->addref(); + } + ++ if (topLevelCreator) ++ sharedState->allJavaScriptObjects = 0; ++ + phase = CreatingObjectsPhase2; + + if (interrupt && interrupt->shouldInterrupt()) +@@ -258,8 +267,11 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance) + + QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); + QV4::Scope valueScope(v4); +- QV4::ScopedValue scopeObjectProtector(valueScope, declarativeData->jsWrapper.value()); +- Q_UNUSED(scopeObjectProtector); ++ ++ Q_ASSERT(topLevelCreator); ++ Q_ASSERT(!sharedState->allJavaScriptObjects); ++ sharedState->allJavaScriptObjects = valueScope.alloc(compiledData->totalObjectCount); ++ + QV4::ScopedObject qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, _scopeObject)); + QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, qmlScope)); + QV4::ExecutionContext *qmlContext = qmlBindingWrapper->context(); +@@ -1150,9 +1162,12 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo + qSwap(_scopeObject, scopeObject); + + QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); ++ ++ Q_ASSERT(sharedState->allJavaScriptObjects); ++ QV4::ValueRef ref = QV4::ValueRef::fromRawValue(sharedState->allJavaScriptObjects++); ++ ref = QV4::QObjectWrapper::wrap(v4, instance); ++ + QV4::Scope valueScope(v4); +- QV4::ScopedValue scopeObjectProtector(valueScope, ddata ? ddata->jsWrapper.value() : 0); +- Q_UNUSED(scopeObjectProtector); + QV4::ScopedObject qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, _scopeObject)); + QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, qmlScope)); + QV4::ExecutionContext *qmlContext = qmlBindingWrapper->context(); +diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h +index ad2d676..fb4d71d 100644 +--- a/src/qml/qml/qqmlobjectcreator_p.h ++++ b/src/qml/qml/qqmlobjectcreator_p.h +@@ -64,6 +64,7 @@ struct QQmlObjectCreatorSharedState : public QSharedData + QFiniteStack<QQmlAbstractBinding*> allCreatedBindings; + QFiniteStack<QQmlParserStatus*> allParserStatusCallbacks; + QFiniteStack<QObject*> allCreatedObjects; ++ QV4::Value *allJavaScriptObjects; // pointer to vector on JS stack to reference JS wrappers during creation phase. + QQmlComponentAttached *componentAttached; + QList<QQmlEnginePrivate::FinalizeCallback> finalizeCallbacks; + QQmlVmeProfiler profiler; +diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp +index eb06b9e..560d860 100644 +--- a/tests/auto/qml/qqmlecmascript/testtypes.cpp ++++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp +@@ -300,6 +300,62 @@ static QObject *create_singletonWithEnum(QQmlEngine *, QJSEngine *) + return new SingletonWithEnum; + } + ++QObjectContainer::QObjectContainer() ++ : widgetParent(0) ++ , gcOnAppend(false) ++{} ++ ++QQmlListProperty<QObject> QObjectContainer::data() ++{ ++ return QQmlListProperty<QObject>(this, 0, children_append, children_count, children_at, children_clear); ++} ++ ++void QObjectContainer::children_append(QQmlListProperty<QObject> *prop, QObject *o) ++{ ++ QObjectContainer *that = static_cast<QObjectContainer*>(prop->object); ++ that->dataChildren.append(o); ++ QObject::connect(o, SIGNAL(destroyed(QObject*)), prop->object, SLOT(childDestroyed(QObject*))); ++ ++ if (that->gcOnAppend) { ++ QQmlEngine *engine = qmlEngine(that); ++ engine->collectGarbage(); ++ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); ++ QCoreApplication::processEvents(); ++ } ++} ++ ++int QObjectContainer::children_count(QQmlListProperty<QObject> *prop) ++{ ++ return static_cast<QObjectContainer*>(prop->object)->dataChildren.count(); ++} ++ ++QObject *QObjectContainer::children_at(QQmlListProperty<QObject> *prop, int index) ++{ ++ return static_cast<QObjectContainer*>(prop->object)->dataChildren.at(index); ++} ++ ++void QObjectContainer::children_clear(QQmlListProperty<QObject> *prop) ++{ ++ QObjectContainer *that = static_cast<QObjectContainer*>(prop->object); ++ foreach (QObject *c, that->dataChildren) ++ QObject::disconnect(c, SIGNAL(destroyed(QObject*)), that, SLOT(childDestroyed(QObject*))); ++ that->dataChildren.clear(); ++} ++ ++void QObjectContainer::childDestroyed(QObject *child) { ++ dataChildren.removeAll(child); ++} ++ ++void FloatingQObject::classBegin() ++{ ++ setParent(0); ++} ++ ++void FloatingQObject::componentComplete() ++{ ++ Q_ASSERT(!parent()); ++} ++ + void registerTypes() + { + qmlRegisterType<MyQmlObject>("Qt.test", 1,0, "MyQmlObjectAlias"); +@@ -381,6 +437,10 @@ void registerTypes() + qmlRegisterSingletonType<testImportOrderApi>("Qt.test.importOrderApi2",1,0,"Data",testImportOrder_api2); + + qmlRegisterSingletonType<SingletonWithEnum>("Qt.test.singletonWithEnum", 1, 0, "SingletonWithEnum", create_singletonWithEnum); ++ ++ qmlRegisterType<QObjectContainer>("Qt.test", 1, 0, "QObjectContainer"); ++ qmlRegisterType<QObjectContainerWithGCOnAppend>("Qt.test", 1, 0, "QObjectContainerWithGCOnAppend"); ++ qmlRegisterType<FloatingQObject>("Qt.test", 1, 0, "FloatingQObject"); + } + + #include "testtypes.moc" +diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h +index 928d594..d5a1220 100644 +--- a/tests/auto/qml/qqmlecmascript/testtypes.h ++++ b/tests/auto/qml/qqmlecmascript/testtypes.h +@@ -1661,6 +1661,51 @@ public: + }; + }; + ++// Like QtObject, but with default property ++class QObjectContainer : public QObject ++{ ++ Q_OBJECT ++ Q_CLASSINFO("DefaultProperty", "data") ++ Q_PROPERTY(QQmlListProperty<QObject> data READ data DESIGNABLE false) ++public: ++ QObjectContainer(); ++ ++ QQmlListProperty<QObject> data(); ++ ++ static void children_append(QQmlListProperty<QObject> *prop, QObject *o); ++ static int children_count(QQmlListProperty<QObject> *prop); ++ static QObject *children_at(QQmlListProperty<QObject> *prop, int index); ++ static void children_clear(QQmlListProperty<QObject> *prop); ++ ++ QList<QObject*> dataChildren; ++ QWidget *widgetParent; ++ bool gcOnAppend; ++ ++protected slots: ++ void childDestroyed(QObject *child); ++}; ++ ++class QObjectContainerWithGCOnAppend : public QObjectContainer ++{ ++ Q_OBJECT ++public: ++ QObjectContainerWithGCOnAppend() ++ { ++ gcOnAppend = true; ++ } ++}; ++ ++class FloatingQObject : public QObject, public QQmlParserStatus ++{ ++ Q_OBJECT ++ Q_INTERFACES(QQmlParserStatus) ++public: ++ FloatingQObject() {} ++ ++ virtual void classBegin(); ++ virtual void componentComplete(); ++}; ++ + void registerTypes(); + + #endif // TESTTYPES_H +diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +index a1e36b4..a9486a8 100644 +--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp ++++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +@@ -322,6 +322,7 @@ private slots: + void varPropertyAccessOnObjectWithInvalidContext(); + void importedScriptsAccessOnObjectWithInvalidContext(); + void contextObjectOnLazyBindings(); ++ void garbageCollectionDuringCreation(); + + private: + // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); +@@ -7603,6 +7604,33 @@ void tst_qqmlecmascript::contextObjectOnLazyBindings() + QCOMPARE(subObject->property("testValue").toInt(), int(42)); + } + ++void tst_qqmlecmascript::garbageCollectionDuringCreation() ++{ ++ QQmlComponent component(&engine); ++ component.setData("import Qt.test 1.0\n" ++ "QObjectContainerWithGCOnAppend {\n" ++ " objectName: \"root\"\n" ++ " FloatingQObject {\n" ++ " objectName: \"parentLessChild\"\n" ++ " property var blah;\n" // Ensure we have JS wrapper ++ " }\n" ++ "}\n", ++ QUrl()); ++ ++ QScopedPointer<QObject> object(component.create()); ++ QVERIFY(!object.isNull()); ++ ++ QObjectContainer *container = qobject_cast<QObjectContainer*>(object.data()); ++ QCOMPARE(container->dataChildren.count(), 1); ++ ++ QObject *child = container->dataChildren.first(); ++ QQmlData *ddata = QQmlData::get(child); ++ QVERIFY(!ddata->jsWrapper.isNullOrUndefined()); ++ ++ gc(engine); ++ QCOMPARE(container->dataChildren.count(), 0); ++} ++ + QTEST_MAIN(tst_qqmlecmascript) + + #include "tst_qqmlecmascript.moc" +-- +2.0.1 + === removed file 'debian/patches/parenttosubcreator_qqmlobjectcreator.patch' --- debian/patches/parenttosubcreator_qqmlobjectcreator.patch 2014-07-01 08:22:15 +0000 +++ debian/patches/parenttosubcreator_qqmlobjectcreator.patch 1970-01-01 00:00:00 +0000 @@ -1,24 +0,0 @@ -commit 249b1a73fdb01fc27e036fc4334925674c281793 -Author: Albert Astals Cid <albert.ast...@canonical.com> -Date: Mon Jun 30 17:22:55 2014 +0200 - - Pass down parent to subCreator - - Otherwise the object might get garbage collected while it's being created - - Change-Id: I553c3432d5242bcd89723b72d8f8ae82577abaf9 - Task-number: QTBUG-39966 - -diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp -index 36c7dfb..cceb9b2 100644 ---- a/src/qml/qml/qqmlobjectcreator.cpp -+++ b/src/qml/qml/qqmlobjectcreator.cpp -@@ -1076,7 +1076,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo - } - - QQmlObjectCreator subCreator(context, typeRef->component, sharedState.data()); -- instance = subCreator.create(); -+ instance = subCreator.create(-1, parent); - if (!instance) { - errors += subCreator.errors; - return 0; === modified file 'debian/patches/series' --- debian/patches/series 2014-07-07 08:45:33 +0000 +++ debian/patches/series 2014-08-05 16:02:47 +0000 @@ -6,5 +6,7 @@ v4_yarr_jit_push_pop_addressTempRegister.patch fix_qqmlobjectcreator.patch Implement-proper-support-for-layoutChange-in-QQmlDel.patch -parenttosubcreator_qqmlobjectcreator.patch +Fix-crash-when-deleting-component-in-Component.onCom.patch +Fix-interaction-of-garbage-collector-with-JS-objects.patch Support-RFC2822Date-date-format-similar-to-V8.patch +8454a21b-Flickable-Cancel-interaction-on-interactive-changes.patch === modified file 'debian/rules' --- debian/rules 2014-05-28 05:57:55 +0000 +++ debian/rules 2014-08-05 16:02:47 +0000 @@ -1,10 +1,17 @@ #!/usr/bin/make -f +include /usr/share/dpkg/default.mk + # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) +# Explicitly selecting a G{CC,++}-version here to avoid symbol changes +# because of the default gcc switch. +export CC=$(DEB_HOST_GNU_TYPE)-gcc-4.8 +export CXX=$(DEB_HOST_GNU_TYPE)-g++-4.8 + export CFLAGS := $(shell dpkg-buildflags --get CFLAGS) $(shell dpkg-buildflags --get CPPFLAGS) export CXXFLAGS := $(shell dpkg-buildflags --get CXXFLAGS) $(shell dpkg-buildflags --get CPPFLAGS) export LDFLAGS := $(shell dpkg-buildflags --get LDFLAGS) -Wl,--as-needed @@ -14,7 +21,7 @@ dh $@ --parallel --with pkgkde_symbolshelper --dbg-package=qtdeclarative5-dbg override_dh_auto_configure: - qmake QT_BUILD_PARTS+=tests + qmake QT_BUILD_PARTS+=tests QMAKE_CC=$(CC) QMAKE_CXX=$(CXX) override_dh_auto_build-indep: dh_auto_build -Smakefile -- html_docs
-- kubuntu-devel mailing list kubuntu-devel@lists.ubuntu.com Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/kubuntu-devel