Ensure that scarce resources work with var properties
authorChris Adams <christopher.adams@nokia.com>
Mon, 10 Oct 2011 02:11:21 +0000 (12:11 +1000)
committerQt by Nokia <qt-info@nokia.com>
Tue, 6 Dec 2011 01:46:28 +0000 (02:46 +0100)
Now that we have a new property type which stores JavaScript handles,
we need to ensure that scarce resources can be used with them.

Task-number: QMLNG-18
Task-number: QTBUG-21843
Change-Id: I4a920ae39e7d33cf5e33362e5e0ee21c74cb35e3
Reviewed-by: Martin Jones <martin.jones@nokia.com>

61 files changed:
doc/src/declarative/basictypes.qdoc
doc/src/declarative/javascriptblocks.qdoc
doc/src/snippets/declarative/integrating-javascript/scarceresources/avatarExample.cpp [new file with mode: 0644]
doc/src/snippets/declarative/integrating-javascript/scarceresources/avatarExample.h [new file with mode: 0644]
doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleFive.qml [new file with mode: 0644]
doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleFour.js [new file with mode: 0644]
doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleFour.qml [new file with mode: 0644]
doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleOne.qml [new file with mode: 0644]
doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleThree.js [new file with mode: 0644]
doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleThree.qml [new file with mode: 0644]
doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleTwo.qml [new file with mode: 0644]
src/declarative/qml/qdeclarativevmemetaobject.cpp
src/declarative/qml/v8/qv8variantresource_p.h [new file with mode: 0644]
src/declarative/qml/v8/qv8variantwrapper.cpp
src/declarative/qml/v8/v8.pri
tests/auto/declarative/qdeclarativeecmascript/data/ScarceResourceSignalComponentVar.qml [copied from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/ScarceResourceSignalComponent.qml with 72% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/ScarceResourceSignalComponentVariant.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/ScarceResourceSignalComponent.qml with 100% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/ScarceResourceVarComponent.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopy.var.qml [copied from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopy.qml with 82% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopy.variant.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopy.qml with 100% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyFromJs.var.qml [copied from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyFromJs.qml with 66% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyFromJs.variant.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyFromJs.qml with 87% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImport.var.js [copied from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImport.js with 92% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImport.var.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImport.variant.js [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImport.js with 92% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImport.variant.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImport.qml with 77% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImportDifferent.var.js [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImportDifferent.var.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImportFail.var.js [copied from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportFail.js with 91% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImportFail.var.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImportFail.variant.js [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportFail.js with 91% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImportFail.variant.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportFail.qml with 64% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImportNoBinding.var.js [copied from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportNoBinding.js with 98% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImportNoBinding.var.qml [copied from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportNoBinding.qml with 77% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImportNoBinding.variant.js [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportNoBinding.js with 97% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImportNoBinding.variant.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyImportNoBinding.qml with 77% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyNoBinding.var.qml [copied from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyNoBinding.qml with 100% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyNoBinding.variant.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceCopyNoBinding.qml with 100% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceDestroyedCopy.var.qml [copied from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceDestroyedCopy.qml with 64% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceDestroyedCopy.variant.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceDestroyedCopy.qml with 86% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceFunction.var.qml [copied from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceFunction.qml with 93% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceFunction.variant.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceFunction.qml with 100% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceFunctionFail.var.qml [copied from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceFunctionFail.qml with 86% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceFunctionFail.variant.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceFunctionFail.qml with 91% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceMultipleDifferentNoBinding.var.js [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceMultipleDifferentNoBinding.var.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceMultipleSameNoBinding.var.js [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceMultipleSameNoBinding.var.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceMultipleSameWithBinding.var.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceObjectGc.var.qml [new file with mode: 0644]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceSignal.var.qml [copied from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceSignal.qml with 90% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceSignal.variant.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceSignal.qml with 89% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceTest.var.js [copied from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTest.js with 100% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceTest.var.qml [copied from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTest.qml with 100% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceTest.variant.js [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTest.js with 100% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceTest.variant.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTest.qml with 100% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceTestMultiple.var.qml [copied from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTestMultiple.qml with 90% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceTestMultiple.variant.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTestMultiple.qml with 89% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceTestPreserve.var.qml [copied from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTestPreserve.qml with 89% similarity]
tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceTestPreserve.variant.qml [moved from tests/auto/declarative/qdeclarativeecmascript/data/scarceresources/scarceResourceTestPreserve.qml with 89% similarity]
tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp

index 98eea78..a908e73 100644 (file)
     }
     \endqml
 
+    A \c var type property can also hold an image or pixmap.
+    A \c var which contains a QPixmap or QImage is known as a
+    "scarce resource" and the declarative engine will attempt to
+    automatically release such resources after evaluation of any JavaScript
+    expression which requires one to be copied has completed.
+
+    Clients may explicitly release such a scarce resource by calling the
+    "destroy" method on the \c var property from within JavaScript.  They
+    may also explicitly preserve the scarce resource by calling the
+    "preserve" method on the \c var property from within JavaScript.
+    For more information regarding the usage of a scarce resource, please
+    see \l{Scarce Resources in JavaScript}.
+
     \sa {QML Basic Types}
 */
 
index a9e383c..34a1986 100644 (file)
@@ -362,7 +362,7 @@ Item {
 
 \section1 Scarce Resources in JavaScript
 
-As described in the documentation for \l{QML Basic Types}, a \c variant type
+As described in the documentation for \l{QML Basic Types}, a \c var type
 property may hold a "scarce resource" (image or pixmap).  There are several
 important semantics of scarce resources which should be noted:
 
@@ -379,30 +379,12 @@ may be necessary for clients to manually preserve or destroy resources for
 themselves.
 
 For the following examples, imagine that we have defined the following class:
-\code
-class AvatarExample : public QObject
-{
-    Q_OBJECT
-    Q_PROPERTY(QPixmap avatar READ avatar WRITE setAvatar NOTIFY avatarChanged)
-public:
-    AvatarExample(QObject *parent = 0) : QObject(parent), m_value(100, 100) { m_value.fill(Qt::blue); }
-    ~AvatarExample() {}
-
-    QPixmap avatar() const { return m_value; }
-    void setAvatar(QPixmap v) { m_value = v; emit avatarChanged(); }
-
-signals:
-    void avatarChanged();
-
-private:
-    QPixmap m_value;
-};
-\endcode
+
+\snippet doc/src/snippets/declarative/integrating-javascript/scarceresources/avatarExample.h 0
 
 and that we have registered it with the QML type-system as follows:
-\code
-qmlRegisterType<AvatarExample>("Qt.example", 1, 0, "AvatarExample");
-\endcode
+
+\snippet doc/src/snippets/declarative/integrating-javascript/scarceresources/avatarExample.cpp 0
 
 The AvatarExample class has a property which is a pixmap.  When the property
 is accessed in JavaScript scope, a copy of the resource will be created and
@@ -414,141 +396,59 @@ unless the client explicitly preserves it.
 
 \section2 Example One: Automatic Release
 
-In this example, the resource will be automatically
+In the following example, the scarce resource will be automatically released
+after the binding evaluation is complete.
+
+\snippet doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleOne.qml 0
+
+\snippet doc/src/snippets/declarative/integrating-javascript/scarceresources/avatarExample.cpp 1
+
+\section2 Example Two: Automatic Release Prevented By Reference
+
+In this example, the resource will not be automatically
 released after the binding expression evaluation is
-complete.
+complete, because there is a property var referencing the
+scarce resource.
 
-\qml
-// exampleOne.qml
-import QtQuick 1.0
-import Qt.example 1.0
-
-QtObject {
-    property AvatarExample a;
-    a: AvatarExample { id: example }
-    property variant avatar: example.avatar
-}
-\endqml
+\snippet doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleTwo.qml 0
 
-\code
-QDeclarativeComponent component(&engine, "exampleOne.qml");
-QObject *object = component.create();
-// The scarce resource will have been released automatically
-// after the binding expression was evaluated.
-// Since the scarce resource was not released explicitly prior
-// to the binding expression being evaluated, we get the
-// expected result:
-//object->property("scarceResourceCopy").isValid() == true
-delete object;
-\endcode
+\snippet doc/src/snippets/declarative/integrating-javascript/scarceresources/avatarExample.cpp 2
 
-\section2 Example Two: Explicit Preservation
+\section2 Example Three: Explicit Preservation
 
 In this example, the resource must be explicitly preserved in order
 to prevent the declarative engine from automatically releasing the
 resource after evaluation of the imported script.
 
-\code
-// exampleTwo.js
-.import Qt.example 1.0 as QtExample
-
-var component = Qt.createComponent("exampleOne.qml");
-var exampleOneElement = component.createObject(null);
-var avatarExample = exampleOneElement.a;
-var retn = avatarExample.avatar;
-
-// without the following call, the scarce resource held
-// by retn would be automatically released by the engine
-// after the import statement in exampleTwo.qml, prior
-// to the variable assignment.
-retn.preserve();
-
-function importAvatar() {
-    return retn;
-}
-\endcode
+\snippet doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleThree.js 0
 
-\qml
-// exampleTwo.qml
-import QtQuick 1.0
-import Qt.example 1.0
-import "exampleTwo.js" as ExampleTwoJs
+\snippet doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleThree.qml 0
 
-QtObject {
-    property variant avatar: ExampleTwoJs.importAvatar()
-}
-\endqml
+\snippet doc/src/snippets/declarative/integrating-javascript/scarceresources/avatarExample.cpp 3
 
-\code
-QDeclarativeComponent component(&engine, "exampleTwo.qml");
-QObject *object = component.create();
-// The resource was preserved explicitly during evaluation of the
-// JavaScript expression.  Thus, during property assignment, the
-// scarce resource was still valid, and so we get the expected result:
-//object->property("avatar").isValid() == true
-// The scarce resource may not have been cleaned up by the JS GC yet;
-// it will continue to consume system resources until the JS GC runs.
-delete object;
-\endcode
-
-\section2 Example Three: Explicit Destruction
+\section2 Example Four: Explicit Destruction
 
 In the following example, we release (via destroy()) an explicitly preserved
 scarce resource variant.  This example shows how a client may free system
 resources by releasing the scarce resource held in a JavaScript object, if
 required, during evaluation of a JavaScript expression.
 
-\code
-// exampleThree.js
-.import Qt.example 1.0 as QtExample
+\snippet doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleFour.js 0
 
-var component = Qt.createComponent("exampleOne.qml");
-var exampleOneElement = component.createObject(null);
-var avatarExample = exampleOneElement.a;
-var retn = avatarExample.avatar;
-retn.preserve();
+\snippet doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleFour.qml 0
 
-function importAvatar() {
-    return retn;
-}
+\snippet doc/src/snippets/declarative/integrating-javascript/scarceresources/avatarExample.cpp 4
 
-function releaseAvatar() {
-    retn.destroy();
-}
-\endcode
+\section2 Example Five: Explicit Destruction And JavaScript References
 
-\qml
-// exampleThree.qml
-import QtQuick 1.0
-import Qt.example 1.0
-import "exampleThree.js" as ExampleThreeJs
-
-QtObject {
-    property variant avatarOne
-    property variant avatarTwo
-
-    Component.onCompleted: {
-        avatarOne = ExampleThreeJs.importAvatar(); // valid at this stage
-        ExampleThreeJs.releaseAvatar();            // explicit release
-        avatarTwo = ExampleThreeJs.importAvatar(); // invalid at this stage
-    }
-}
-\endqml
+One thing to be aware of when using "var" type properties is that they
+hold references to JavaScript objects.  As such, if multiple references
+to one scarce resource is held, and the client calls destroy() on one
+of those references (to explicitly release the scarce resource), all of
+the references will be affected.
 
-\code
-QDeclarativeComponent component(&engine, "exampleThree.qml");
-QObject *object = component.create();
-// The scarce resource was explicitly preserved by the client during
-// the evaluation of the imported script, and so the scarce resource
-// remains valid until the explicit call to releaseAvatar().  As such,
-// we get the expected results:
-//object->property("avatarOne").isValid() == true
-//object->property("avatarTwo").isValid() == false
-// Because the scarce resource was released explicitly, it will no longer
-// be consuming any system resources (beyond what a normal JS Object would;
-// that small overhead will exist until the JS GC runs, as per any other
-// JavaScript object).
-delete object;
-\endcode
+\snippet doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleFive.qml 0
+
+\snippet doc/src/snippets/declarative/integrating-javascript/scarceresources/avatarExample.cpp 5
 
 */
diff --git a/doc/src/snippets/declarative/integrating-javascript/scarceresources/avatarExample.cpp b/doc/src/snippets/declarative/integrating-javascript/scarceresources/avatarExample.cpp
new file mode 100644 (file)
index 0000000..eb521e1
--- /dev/null
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "avatarExample.h"
+#include <QDeclarativeEngine>
+#include <QDeclarativeComponent>
+
+void registerTypes()
+{
+//![0]
+    qmlRegisterType<AvatarExample>("Qt.example", 1, 0, "AvatarExample");
+//![0]
+}
+
+void expectOne()
+{
+//![1]
+QDeclarativeComponent component(&engine, "exampleOne.qml");
+QObject *object = component.create();
+// The scarce resource will have been released automatically
+// by this point, after the binding expression was evaluated.
+delete object;
+//![1]
+}
+
+void expectTwo()
+{
+//![2]
+QDeclarativeComponent component(&engine, "exampleTwo.qml");
+QObject *object = component.create();
+// The scarce resource will not have been released automatically
+// after the binding expression was evaluated.
+// Since the scarce resource was not released explicitly prior
+// to the binding expression being evaluated, we get:
+bool expectedResult = (object->property("avatar").isValid() == true);
+delete object;
+//![2]
+}
+
+void expectThree()
+{
+//![3]
+QDeclarativeComponent component(&engine, "exampleThree.qml");
+QObject *object = component.create();
+// The resource was preserved explicitly during evaluation of the
+// JavaScript expression.  Thus, during property assignment, the
+// scarce resource was still valid, and so we get:
+bool expectedResult = (object->property("avatar").isValid() == true);
+// The scarce resource will not be released until all references to
+// the resource are released, and the JavaScript garbage collector runs.
+delete object;
+//![3]
+}
+
+void expectFour()
+{
+//![4]
+QDeclarativeComponent component(&engine, "exampleFour.qml");
+QObject *object = component.create();
+// The scarce resource was explicitly preserved by the client during
+// the importAvatar() function, and so the scarce resource
+// remains valid until the explicit call to releaseAvatar().  As such,
+// we get the expected results:
+bool expectedResultOne = (object->property("avatarOne").isValid() == true);
+bool expectedResultTwo = (object->property("avatarTwo").isValid() == false);
+// Because the scarce resource referenced by avatarTwo was released explicitly,
+// it will no longer be consuming any system resources (beyond what a normal
+// JS Object would; that small overhead will exist until the JS GC runs, as per
+// any other JavaScript object).
+delete object;
+//![4]
+}
+
+void expectFive()
+{
+//![5]
+QDeclarativeComponent component(&engine, "exampleFive.qml");
+QObject *object = component.create();
+// We have the expected results:
+bool expectedResultOne = (object->property("avatarOne").isValid() == false);
+bool expectedResultTwo = (object->property("avatarTwo").isValid() == false);
+// Because although only avatarTwo was explicitly released,
+// avatarOne and avatarTwo were referencing the same
+// scarce resource.
+delete object;
+//![5]
+}
diff --git a/doc/src/snippets/declarative/integrating-javascript/scarceresources/avatarExample.h b/doc/src/snippets/declarative/integrating-javascript/scarceresources/avatarExample.h
new file mode 100644 (file)
index 0000000..17cef5e
--- /dev/null
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef AVATAREXAMPLE_P_H
+#define AVATAREXAMPLE_P_H
+
+#include <QObject>
+#include <QPixmap>
+
+//![0]
+// avatarExample.h
+class AvatarExample : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(QPixmap avatar READ avatar WRITE setAvatar NOTIFY avatarChanged)
+public:
+    AvatarExample(QObject *parent = 0)
+        : QObject(parent), m_value(100, 100)
+    {
+        m_value.fill(Qt::blue);
+    }
+
+    ~AvatarExample() {}
+
+    QPixmap avatar() const { return m_value; }
+    void setAvatar(QPixmap v) { m_value = v; emit avatarChanged(); }
+
+signals:
+    void avatarChanged();
+
+private:
+    QPixmap m_value;
+};
+//![0]
+
+#endif
diff --git a/doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleFive.qml b/doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleFive.qml
new file mode 100644 (file)
index 0000000..33326b7
--- /dev/null
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+// exampleFive.qml
+import QtQuick 2.0
+import Qt.example 1.0
+import "exampleFour.js" as ExampleFourJs // use factory from example four
+
+QtObject {
+    property var avatarOne: ExampleFourJs.importAvatar()
+    property var avatarTwo: avatarOne
+
+    Component.onCompleted: {
+        ExampleFourJs.releaseAvatar(avatarTwo);
+    }
+}
+//![0]
\ No newline at end of file
diff --git a/doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleFour.js b/doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleFour.js
new file mode 100644 (file)
index 0000000..476e03f
--- /dev/null
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+// exampleFour.js
+.import Qt.example 1.0 as QtExample
+
+function importAvatar() {
+    var component = Qt.createComponent("exampleTwo.qml");
+    var exampleOneElement = component.createObject(null);
+    var avatarExample = exampleOneElement.a;
+    var retn = avatarExample.avatar;
+    retn.preserve();
+    return retn;
+}
+
+function releaseAvatar(avatar) {
+    avatar.destroy();
+}
+//![0]
\ No newline at end of file
diff --git a/doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleFour.qml b/doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleFour.qml
new file mode 100644 (file)
index 0000000..e423771
--- /dev/null
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+// exampleFour.qml
+import QtQuick 2.0
+import Qt.example 1.0
+import "exampleFour.js" as ExampleFourJs
+
+QtObject {
+    property var avatarOne
+    property var avatarTwo
+
+    Component.onCompleted: {
+        avatarOne = ExampleFourJs.importAvatar();
+        avatarTwo = ExampleFourJs.importAvatar();
+        ExampleFourJs.releaseAvatar(avatarTwo);
+    }
+}
+//![0]
\ No newline at end of file
diff --git a/doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleOne.qml b/doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleOne.qml
new file mode 100644 (file)
index 0000000..c8579b7
--- /dev/null
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+// exampleOne.qml
+import QtQuick 1.0
+import Qt.example 1.0
+
+QtObject {
+    property AvatarExample a;
+    a: AvatarExample { id: example }
+    property var avatarWidth: example.avatar,100
+    // Here, we use "example.avatar,100" purely for illustration.
+    // The value of `avatarWidth' will be 100 after evaluation.
+    // E.g., you could imagine some js function which takes
+    // an avatar, and returns the width of the avatar.
+}
+//![0]
\ No newline at end of file
diff --git a/doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleThree.js b/doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleThree.js
new file mode 100644 (file)
index 0000000..4fefb1e
--- /dev/null
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+// exampleThree.js
+.import Qt.example 1.0 as QtExample
+
+var component = Qt.createComponent("exampleTwo.qml");
+var exampleOneElement = component.createObject(null);
+var avatarExample = exampleOneElement.a;
+var retn = avatarExample.avatar;
+
+// without the following call, the scarce resource held
+// by retn would be automatically released by the engine
+// after the import statement in exampleTwo.qml, prior
+// to the variable assignment.
+retn.preserve();
+
+function importAvatar() {
+    return retn;
+}
+//![0]
\ No newline at end of file
diff --git a/doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleThree.qml b/doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleThree.qml
new file mode 100644 (file)
index 0000000..5838290
--- /dev/null
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+// exampleThree.qml
+import QtQuick 1.0
+import Qt.example 1.0
+import "exampleThree.js" as ExampleThreeJs
+
+QtObject {
+    property var avatar: ExampleThreeJs.importAvatar()
+}
+//![0]
\ No newline at end of file
diff --git a/doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleTwo.qml b/doc/src/snippets/declarative/integrating-javascript/scarceresources/exampleTwo.qml
new file mode 100644 (file)
index 0000000..610a75b
--- /dev/null
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+// exampleTwo.qml
+import QtQuick 1.0
+import Qt.example 1.0
+
+QtObject {
+    property AvatarExample a;
+    a: AvatarExample { id: example }
+    property var avatar: example.avatar
+    // Now `avatar' contains a reference to the scarce resource.
+}
+//![0]
\ No newline at end of file
index 229a93b..0ff6ad5 100644 (file)
@@ -50,6 +50,8 @@
 #include "qdeclarativebinding_p.h"
 #include "qdeclarativepropertyvalueinterceptor_p.h"
 
+#include <private/qv8variantresource_p.h>
+
 Q_DECLARE_METATYPE(QJSValue);
 
 QT_BEGIN_NAMESPACE
@@ -819,8 +821,28 @@ QVariant QDeclarativeVMEMetaObject::readPropertyAsVariant(int id)
 void QDeclarativeVMEMetaObject::writeVarProperty(int id, v8::Handle<v8::Value> value)
 {
     Q_ASSERT(id >= firstVarPropertyIndex);
-
     ensureVarPropertiesAllocated();
+
+    // Importantly, if the current value is a scarce resource, we need to ensure that it
+    // gets automatically released by the engine if no other references to it exist.
+    v8::Local<v8::Value> oldv = varProperties->Get(id - firstVarPropertyIndex);
+    if (oldv->IsObject()) {
+        QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(oldv));
+        if (r) {
+            r->removeVmePropertyReference();
+        }
+    }
+
+    // And, if the new value is a scarce resource, we need to ensure that it does not get
+    // automatically released by the engine until no other references to it exist.
+    if (value->IsObject()) {
+        QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(value));
+        if (r) {
+            r->addVmePropertyReference();
+        }
+    }
+
+    // Write the value and emit change signal as appropriate.
     varProperties->Set(id - firstVarPropertyIndex, value);
     activate(object, methodOffset + id, 0);
 }
@@ -829,8 +851,30 @@ void QDeclarativeVMEMetaObject::writeProperty(int id, const QVariant &value)
 {
     if (id >= firstVarPropertyIndex) {
         ensureVarPropertiesAllocated();
+
+        // Importantly, if the current value is a scarce resource, we need to ensure that it
+        // gets automatically released by the engine if no other references to it exist.
+        v8::Local<v8::Value> oldv = varProperties->Get(id - firstVarPropertyIndex);
+        if (oldv->IsObject()) {
+            QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(oldv));
+            if (r) {
+                r->removeVmePropertyReference();
+            }
+        }
+
+        // And, if the new value is a scarce resource, we need to ensure that it does not get
+        // automatically released by the engine until no other references to it exist.
+        v8::Handle<v8::Value> newv = QDeclarativeEnginePrivate::get(ctxt->engine)->v8engine()->fromVariant(value);
+        if (newv->IsObject()) {
+            QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(newv));
+            if (r) {
+                r->addVmePropertyReference();
+            }
+        }
+
+        // Write the value and emit change signal as appropriate.
         QVariant currentValue = readPropertyAsVariant(id);
-        varProperties->Set(id - firstVarPropertyIndex, QDeclarativeEnginePrivate::get(ctxt->engine)->v8engine()->fromVariant(value));
+        varProperties->Set(id - firstVarPropertyIndex, newv);
         if ((currentValue.userType() != value.userType() || currentValue != value))
             activate(object, methodOffset + id, 0);
     } else {
diff --git a/src/declarative/qml/v8/qv8variantresource_p.h b/src/declarative/qml/v8/qv8variantresource_p.h
new file mode 100644 (file)
index 0000000..d1a5f92
--- /dev/null
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8VARIANTRESOURCE_P_H
+#define QV8VARIANTRESOURCE_P_H
+
+//
+//  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.
+//
+
+#include <QtCore/qglobal.h>
+#include <private/qv8_p.h>
+#include <private/qv8engine_p.h>
+#include <private/qdeclarativeengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8VariantResource : public QV8ObjectResource,
+                           public QDeclarativeEnginePrivate::ScarceResourceData
+{
+    V8_RESOURCE_TYPE(VariantType)
+
+public:
+    QV8VariantResource(QV8Engine *engine, const QVariant &data);
+
+    void addVmePropertyReference();
+    void removeVmePropertyReference();
+
+    bool m_isScarceResource;
+    int m_vmePropertyReferenceCount;
+};
+
+QT_END_NAMESPACE
+
+#endif // QV8VARIANTRESOURCE_P_H
+
index 671e4d3..28bcccb 100644 (file)
 ****************************************************************************/
 
 #include "qv8variantwrapper_p.h"
+#include "qv8variantresource_p.h"
 #include "qv8engine_p.h"
 #include <private/qdeclarativeengine_p.h>
 
 QT_BEGIN_NAMESPACE
 
-class QV8VariantResource : public QV8ObjectResource, 
-                           public QDeclarativeEnginePrivate::ScarceResourceData
+QV8VariantResource::QV8VariantResource(QV8Engine *engine, const QVariant &data)
+: QV8ObjectResource(engine), QDeclarativeEnginePrivate::ScarceResourceData(data), m_isScarceResource(false), m_vmePropertyReferenceCount(0)
 {
-    V8_RESOURCE_TYPE(VariantType);
-public:
-    QV8VariantResource(QV8Engine *engine, const QVariant &data);
-};
+}
 
-QV8VariantResource::QV8VariantResource(QV8Engine *engine, const QVariant &data)
-: QV8ObjectResource(engine), QDeclarativeEnginePrivate::ScarceResourceData(data)
+void QV8VariantResource::addVmePropertyReference()
+{
+    if (m_isScarceResource && ++m_vmePropertyReferenceCount == 1) {
+        // remove from the ep->scarceResources list
+        // since it is now no longer eligible to be
+        // released automatically by the engine.
+        node.remove();
+    }
+}
+
+void QV8VariantResource::removeVmePropertyReference()
 {
+    if (m_isScarceResource && --m_vmePropertyReferenceCount == 0) {
+        // and add to the ep->scarceResources list
+        // since it is now eligible to be released
+        // automatically by the engine.
+        QDeclarativeEnginePrivate::get(engine->engine())->scarceResources.insert(this);
+    }
 }
 
 QV8VariantWrapper::QV8VariantWrapper()
@@ -133,6 +146,7 @@ v8::Local<v8::Object> QV8VariantWrapper::newVariant(const QVariant &value)
         QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_engine->engine());
         Q_ASSERT(ep->scarceResourcesRefCount);
         rv = m_scarceConstructor->NewInstance();
+        r->m_isScarceResource = true;
         ep->scarceResources.insert(r);
     } else {
         rv = m_constructor->NewInstance();
index 924602e..e3488cd 100644 (file)
@@ -16,6 +16,7 @@ HEADERS += \
     $$PWD/qv8typewrapper_p.h \
     $$PWD/qv8listwrapper_p.h \
     $$PWD/qv8variantwrapper_p.h \
+    $$PWD/qv8variantresource_p.h \
     $$PWD/qv8valuetypewrapper_p.h \
     $$PWD/qv8include_p.h \
     $$PWD/qv8worker_p.h \
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/ScarceResourceVarComponent.qml b/tests/auto/declarative/qdeclarativeecmascript/data/ScarceResourceVarComponent.qml
new file mode 100644 (file)
index 0000000..2cf6b42
--- /dev/null
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+    id: first
+    property var vp: Item {
+        id: second
+        property MyScarceResourceObject srp;
+        srp: MyScarceResourceObject { id: scarceResourceProvider }
+        property var sr: scarceResourceProvider.scarceResource
+        property var canary: 5
+    }
+}
@@ -10,6 +10,5 @@ import Qt.test 1.0
 QtObject {
     property MyScarceResourceObject a;
     a: MyScarceResourceObject { id: scarceResourceProvider }
-    property variant scarceResourceCopy: scarceResourceProvider.scarceResource
-}
-
+    property var scarceResourceCopy: scarceResourceProvider.scarceResource
+}
\ No newline at end of file
@@ -1,6 +1,6 @@
 import QtQuick 2.0
 import Qt.test 1.0
-import "scarceResourceTest.js" as ScarceResourceProviderJs
+import "scarceResourceTest.var.js" as ScarceResourceProviderJs
 
 // Here we import a scarce resource directly, from JS module.
 // It is not preserved or released manually, so it should be
@@ -10,6 +10,5 @@ import "scarceResourceTest.js" as ScarceResourceProviderJs
 QtObject {
     property MyScarceResourceObject a;
     a: MyScarceResourceObject { id: scarceResourceProvider }
-    property variant scarceResourceCopy: ScarceResourceProviderJs.importScarceResource(scarceResourceProvider)
-}
-
+    property var scarceResourceCopy: ScarceResourceProviderJs.importScarceResource(scarceResourceProvider)
+}
\ No newline at end of file
@@ -1,6 +1,6 @@
 import QtQuick 2.0
 import Qt.test 1.0
-import "scarceResourceTest.js" as ScarceResourceProviderJs
+import "scarceResourceTest.variant.js" as ScarceResourceProviderJs
 
 // Here we import a scarce resource directly, from JS module.
 // It is not preserved or released manually, so it should be
@@ -6,7 +6,7 @@
 // resource would automatically be released after import completes
 // but before the binding is evaluated.
 
-var component = Qt.createComponent("scarceResourceCopy.qml");
+var component = Qt.createComponent("scarceResourceCopy.var.qml");
 var scarceResourceElement = component.createObject(null);
 var scarceResourceProvider = scarceResourceElement.a;
 var retn = scarceResourceProvider.scarceResource;
@@ -22,3 +22,4 @@ function importScarceResource() {
 function destroyScarceResource() {
     retn.destroy();
 }
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImport.var.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImport.var.qml
new file mode 100644 (file)
index 0000000..9321481
--- /dev/null
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceCopyImport.var.js" as ScarceResourceCopyImportJs
+
+QtObject {
+    // this binding is evaluated once, prior to the resource being released
+    property var scarceResourceImportedCopy: ScarceResourceCopyImportJs.importScarceResource()
+
+    property bool arePropertiesEqual
+    property var scarceResourceAssignedCopyOne;
+    property var scarceResourceAssignedCopyTwo;
+    Component.onCompleted: {
+        scarceResourceAssignedCopyOne = ScarceResourceCopyImportJs.importScarceResource();
+        arePropertiesEqual = (scarceResourceAssignedCopyOne == scarceResourceImportedCopy);
+        ScarceResourceCopyImportJs.destroyScarceResource(); // makes all properties invalid.
+        scarceResourceAssignedCopyTwo = ScarceResourceCopyImportJs.importScarceResource();
+    }
+}
\ No newline at end of file
@@ -6,7 +6,7 @@
 // resource would automatically be released after import completes
 // but before the binding is evaluated.
 
-var component = Qt.createComponent("scarceResourceCopy.qml");
+var component = Qt.createComponent("scarceResourceCopy.variant.qml");
 var scarceResourceElement = component.createObject(null);
 var scarceResourceProvider = scarceResourceElement.a;
 var retn = scarceResourceProvider.scarceResource;
@@ -22,3 +22,4 @@ function importScarceResource() {
 function destroyScarceResource() {
     retn.destroy();
 }
+
@@ -1,10 +1,10 @@
 import QtQuick 2.0
 import Qt.test 1.0
-import "scarceResourceCopyImport.js" as ScarceResourceCopyImportJs
+import "scarceResourceCopyImport.variant.js" as ScarceResourceCopyImportJs
 
 QtObject {
     // this binding is evaluated once, prior to the resource being released
-    property variant scarceResourceCopy: ScarceResourceCopyImportJs.importScarceResource()
+    property variant scarceResourceImportedCopy: ScarceResourceCopyImportJs.importScarceResource()
 
     // this code is evaluated on completion, and so copy one should be valid, copy two invalid.
     property variant scarceResourceAssignedCopyOne;
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImportDifferent.var.js b/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImportDifferent.var.js
new file mode 100644 (file)
index 0000000..000eedd
--- /dev/null
@@ -0,0 +1,19 @@
+.import Qt.test 1.0 as JsQtTest
+
+// In this case, we create the returned scarce resource each call,
+// so the object will be different every time it is returned.
+
+var mostRecent
+
+function importScarceResource() {
+    var component = Qt.createComponent("scarceResourceCopy.var.qml");
+    var scarceResourceElement = component.createObject(null);
+    var scarceResourceProvider = scarceResourceElement.a;
+    var retn = scarceResourceProvider.scarceResource;
+    mostRecent = retn;
+    return retn;
+}
+
+function destroyScarceResource() {
+    mostRecent.destroy();
+}
\ No newline at end of file
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImportDifferent.var.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImportDifferent.var.qml
new file mode 100644 (file)
index 0000000..082d132
--- /dev/null
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceCopyImportDifferent.var.js" as ScarceResourceCopyImportJs
+
+// in this case, the ScarceResourceCopyImportJs returns a _new_, different
+// scarce resource each time.  Invalidating one will not invalidate the others.
+
+QtObject {
+    // this binding is evaluated once, prior to the resource being released
+    property var scarceResourceImportedCopy: ScarceResourceCopyImportJs.importScarceResource()
+
+    // the following properties are assigned on component completion.
+    property bool arePropertiesEqual
+    property var scarceResourceAssignedCopyOne;
+    property var scarceResourceAssignedCopyTwo;
+    Component.onCompleted: {
+        scarceResourceAssignedCopyOne = ScarceResourceCopyImportJs.importScarceResource();
+        arePropertiesEqual = (scarceResourceAssignedCopyOne != scarceResourceImportedCopy); // they're not the same object.
+        ScarceResourceCopyImportJs.destroyScarceResource(); // makes the MOST RECENT resource invalid (ie, assignedCopyOne).
+        scarceResourceAssignedCopyTwo = ScarceResourceCopyImportJs.importScarceResource();
+    }
+}
\ No newline at end of file
@@ -8,7 +8,7 @@
 // Thus, "importScarceResource()" will return a released (invalid)
 // scarce resource.
 
-var component = Qt.createComponent("scarceResourceCopy.qml");
+var component = Qt.createComponent("scarceResourceCopy.var.qml");
 var scarceResourceElement = component.createObject(null);
 var scarceResourceProvider = scarceResourceElement.a;
 var retn = scarceResourceProvider.scarceResource;
@@ -16,3 +16,4 @@ var retn = scarceResourceProvider.scarceResource;
 function importScarceResource() {
     return retn; // should return a released (invalid) scarce resource
 }
+
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImportFail.var.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceCopyImportFail.var.qml
new file mode 100644 (file)
index 0000000..a1a3c1d
--- /dev/null
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceCopyImportFail.var.js" as ScarceResourceCopyImportFailJs
+
+QtObject {
+    property var scarceResourceCopy: ScarceResourceCopyImportFailJs.importScarceResource()
+}
\ No newline at end of file
@@ -8,7 +8,7 @@
 // Thus, "importScarceResource()" will return a released (invalid)
 // scarce resource.
 
-var component = Qt.createComponent("scarceResourceCopy.qml");
+var component = Qt.createComponent("scarceResourceCopy.variant.qml");
 var scarceResourceElement = component.createObject(null);
 var scarceResourceProvider = scarceResourceElement.a;
 var retn = scarceResourceProvider.scarceResource;
@@ -16,3 +16,4 @@ var retn = scarceResourceProvider.scarceResource;
 function importScarceResource() {
     return retn; // should return a released (invalid) scarce resource
 }
+
@@ -1,6 +1,6 @@
 import QtQuick 2.0
 import Qt.test 1.0
-import "scarceResourceCopyImportFail.js" as ScarceResourceCopyImportFailJs
+import "scarceResourceCopyImportFail.variant.js" as ScarceResourceCopyImportFailJs
 
 QtObject {
     property variant scarceResourceCopy: ScarceResourceCopyImportFailJs.importScarceResource()
@@ -8,7 +8,8 @@
 // Thus, "importScarceResource()" will return a released (invalid)
 // scarce resource.
 
-var component = Qt.createComponent("scarceResourceCopyNoBinding.qml");
+var component = Qt.createComponent("scarceResourceCopyNoBinding.var.qml");
 var scarceResourceElement = component.createObject(null);
 var scarceResourceProvider = scarceResourceElement.a;
 var retn = scarceResourceProvider.scarceResource;
+
@@ -2,7 +2,7 @@ import QtQuick 2.0
 import Qt.test 1.0
 
 // the following js import doesn't manually preserve or destroy any resources
-import "scarceResourceCopyImportNoBinding.js" as ScarceResourceCopyImportNoBindingJs
+import "scarceResourceCopyImportNoBinding.var.js" as ScarceResourceCopyImportNoBindingJs
 
 QtObject {
     // in this case, there is an import but no binding evaluated.
@@ -8,7 +8,8 @@
 // Thus, "importScarceResource()" will return a released (invalid)
 // scarce resource.
 
-var component = Qt.createComponent("scarceResourceCopyNoBinding.qml");
+var component = Qt.createComponent("scarceResourceCopyNoBinding.variant.qml");
 var scarceResourceElement = component.createObject(null);
 var scarceResourceProvider = scarceResourceElement.a;
 var retn = scarceResourceProvider.scarceResource;
+
@@ -2,7 +2,7 @@ import QtQuick 2.0
 import Qt.test 1.0
 
 // the following js import doesn't manually preserve or destroy any resources
-import "scarceResourceCopyImportNoBinding.js" as ScarceResourceCopyImportNoBindingJs
+import "scarceResourceCopyImportNoBinding.variant.js" as ScarceResourceCopyImportNoBindingJs
 
 QtObject {
     // in this case, there is an import but no binding evaluated.
@@ -1,6 +1,6 @@
 import QtQuick 2.0
 import Qt.test 1.0
-import "scarceResourceTest.js" as ScarceResourceProviderJs
+import "scarceResourceTest.var.js" as ScarceResourceProviderJs
 
 // In this case, following the evaluation of the binding,
 // the scarceResourceTest value should be an invalid variant,
@@ -9,6 +9,5 @@ import "scarceResourceTest.js" as ScarceResourceProviderJs
 QtObject {
     property MyScarceResourceObject a;
     a: MyScarceResourceObject { id: scarceResourceProvider }
-    property variant scarceResourceCopy: ScarceResourceProviderJs.importReleasedScarceResource(scarceResourceProvider);
-}
-
+    property var scarceResourceCopy: ScarceResourceProviderJs.importReleasedScarceResource(scarceResourceProvider);
+}
\ No newline at end of file
@@ -1,6 +1,6 @@
 import QtQuick 2.0
 import Qt.test 1.0
-import "scarceResourceTest.js" as ScarceResourceProviderJs
+import "scarceResourceTest.variant.js" as ScarceResourceProviderJs
 
 // In this case, following the evaluation of the binding,
 // the scarceResourceTest value should be an invalid variant,
@@ -10,7 +10,7 @@ import Qt.test 1.0
 QtObject {
     id: root
     property MyScarceResourceObject a: MyScarceResourceObject { id: scarceResourceProvider }
-    property variant scarceResourceCopy;
+    property var scarceResourceCopy;
 
     function retrieveScarceResource() {
         root.scarceResourceCopy = scarceResourceProvider.scarceResource;
@@ -4,13 +4,12 @@ import Qt.test 1.0
 // In this example, a common syntax error will only be "caught"
 // when the function is called via:
 // QDeclarativeVMEMetaObject::metaCall->invokeMetaMethod()
-// We would like to ensure that a useful error message is printed,
-// rather than having QScriptValue::call() function fail silently.
+// We would like to ensure that a useful error message is printed.
 
 QtObject {
     id: root
     property MyScarceResourceObject a: MyScarceResourceObject { id: scarceResourceProvider }
-    property variant scarceResourceCopy;
+    property var scarceResourceCopy;
     property string srp_name: a.toString();
 
     function retrieveScarceResource() {
@@ -4,8 +4,7 @@ import Qt.test 1.0
 // In this example, a common syntax error will only be "caught"
 // when the function is called via:
 // QDeclarativeVMEMetaObject::metaCall->invokeMetaMethod()
-// We would like to ensure that a useful error message is printed,
-// rather than having QScriptValue::call() function fail silently.
+// We would like to ensure that a useful error message is printed.
 
 QtObject {
     id: root
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceMultipleDifferentNoBinding.var.js b/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceMultipleDifferentNoBinding.var.js
new file mode 100644 (file)
index 0000000..217f693
--- /dev/null
@@ -0,0 +1,14 @@
+.import Qt.test 1.0 as JsQtTest
+
+function importScarceResource() {
+    var component = Qt.createComponent("scarceResourceCopy.var.qml");
+    var scarceResourceElement = component.createObject(null);
+    var scarceResourceProvider = scarceResourceElement.a;
+    var retn = scarceResourceProvider.scarceResource;
+    retn.preserve();
+    return retn;
+}
+
+function releaseScarceResource(resource) {
+    resource.destroy();
+}
\ No newline at end of file
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceMultipleDifferentNoBinding.var.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceMultipleDifferentNoBinding.var.qml
new file mode 100644 (file)
index 0000000..2051316
--- /dev/null
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceMultipleDifferentNoBinding.var.js" as ScarceResourcesMultipleDifferentNoBinding
+
+QtObject {
+    property var resourceOne
+    property var resourceTwo
+
+    Component.onCompleted: {
+        resourceOne = ScarceResourcesMultipleDifferentNoBinding.importScarceResource();
+        resourceTwo = ScarceResourcesMultipleDifferentNoBinding.importScarceResource();
+        ScarceResourcesMultipleDifferentNoBinding.releaseScarceResource(resourceTwo);
+    }
+}
\ No newline at end of file
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceMultipleSameNoBinding.var.js b/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceMultipleSameNoBinding.var.js
new file mode 100644 (file)
index 0000000..5b2494c
--- /dev/null
@@ -0,0 +1,15 @@
+.import Qt.test 1.0 as JsQtTest
+
+var component = Qt.createComponent("scarceResourceCopy.var.qml");
+var scarceResourceElement = component.createObject(null);
+var scarceResourceProvider = scarceResourceElement.a;
+var retn = scarceResourceProvider.scarceResource;
+retn.preserve();
+
+function importScarceResource() {
+    return retn;
+}
+
+function releaseScarceResource(resource) {
+    resource.destroy();
+}
\ No newline at end of file
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceMultipleSameNoBinding.var.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceMultipleSameNoBinding.var.qml
new file mode 100644 (file)
index 0000000..e7f6d78
--- /dev/null
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceMultipleSameNoBinding.var.js" as ScarceResourcesMultipleSameNoBinding
+
+QtObject {
+    property var resourceOne
+    property var resourceTwo
+
+    Component.onCompleted: {
+        resourceOne = ScarceResourcesMultipleSameNoBinding.importScarceResource();
+        resourceTwo = ScarceResourcesMultipleSameNoBinding.importScarceResource();
+        ScarceResourcesMultipleSameNoBinding.releaseScarceResource(resourceTwo);
+    }
+}
\ No newline at end of file
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceMultipleSameWithBinding.var.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceMultipleSameWithBinding.var.qml
new file mode 100644 (file)
index 0000000..34cb97f
--- /dev/null
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceMultipleDifferentNoBinding.var.js" as ScarceResourcesMultipleDifferentNoBinding
+
+QtObject {
+    property var resourceOne: ScarceResourcesMultipleDifferentNoBinding.importScarceResource()
+    property var resourceTwo: resourceOne
+
+    Component.onCompleted: {
+        ScarceResourcesMultipleDifferentNoBinding.releaseScarceResource(resourceTwo);
+    }
+}
\ No newline at end of file
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceObjectGc.var.qml b/tests/auto/declarative/qdeclarativeecmascript/data/scarceResourceObjectGc.var.qml
new file mode 100644 (file)
index 0000000..7ec98e6
--- /dev/null
@@ -0,0 +1,30 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+    id: testScarce
+
+    property var varProperty
+
+    property var canary: 4
+
+    // constructs an Item which contains a scarce resource.
+    function constructScarceObject() {
+        var retn = 1;
+        var component = Qt.createComponent("ScarceResourceVarComponent.qml");
+        if (component.status == Component.Ready) {
+            retn = component.createObject(null); // has JavaScript ownership
+        }
+        return retn;
+    }
+
+    function assignVarProperty() {
+        varProperty = constructScarceObject();
+        gc();
+    }
+
+    function deassignVarProperty() {
+        varProperty = 2; // causes the original object to be garbage collected.
+        gc();            // image should be detached; ep->sr should be empty!
+    }
+}
@@ -7,8 +7,8 @@ QtObject {
     property MyScarceResourceObject a;
     a: MyScarceResourceObject { id: scarceResourceProvider }
 
-    property ScarceResourceSignalComponent b;
-    b: ScarceResourceSignalComponent {
+    property ScarceResourceSignalComponentVar b;
+    b: ScarceResourceSignalComponentVar {
         objectName: "srsc"
 
         onTestSignal: {
@@ -7,8 +7,8 @@ QtObject {
     property MyScarceResourceObject a;
     a: MyScarceResourceObject { id: scarceResourceProvider }
 
-    property ScarceResourceSignalComponent b;
-    b: ScarceResourceSignalComponent {
+    property ScarceResourceSignalComponentVariant b;
+    b: ScarceResourceSignalComponentVariant {
         objectName: "srsc"
 
         onTestSignal: {
@@ -1,6 +1,6 @@
 import QtQuick 2.0
 import Qt.test 1.0
-import "scarceResourceTest.js" as ScarceResourceProviderJs
+import "scarceResourceTest.var.js" as ScarceResourceProviderJs
 
 // In this case, multiple scarce resource are explicity preserved
 // and then explicitly destroyed, while others are automatically
@@ -1,6 +1,6 @@
 import QtQuick 2.0
 import Qt.test 1.0
-import "scarceResourceTest.js" as ScarceResourceProviderJs
+import "scarceResourceTest.variant.js" as ScarceResourceProviderJs
 
 // In this case, multiple scarce resource are explicity preserved
 // and then explicitly destroyed, while others are automatically
@@ -13,4 +13,3 @@ QtObject {
     a: MyScarceResourceObject { id: scarceResourceProvider }
     property int scarceResourceTest: ScarceResourceProviderJs.importPreservedScarceResourceFromMultiple(scarceResourceProvider), 100
 }
-
@@ -1,6 +1,6 @@
 import QtQuick 2.0
 import Qt.test 1.0
-import "scarceResourceTest.js" as ScarceResourceProviderJs
+import "scarceResourceTest.var.js" as ScarceResourceProviderJs
 
 // In this case, the scarce resource is explicity preserved.
 // It should not be automatically released after the evaluation
@@ -1,6 +1,6 @@
 import QtQuick 2.0
 import Qt.test 1.0
-import "scarceResourceTest.js" as ScarceResourceProviderJs
+import "scarceResourceTest.variant.js" as ScarceResourceProviderJs
 
 // In this case, the scarce resource is explicity preserved.
 // It should not be automatically released after the evaluation
index 3d50d6e..5e62ec6 100644 (file)
@@ -152,6 +152,8 @@ private slots:
     void importScripts_data();
     void importScripts();
     void scarceResources();
+    void scarceResources_data();
+    void scarceResources_other();
     void propertyChangeSlots();
     void propertyVar_data();
     void propertyVar();
@@ -1412,15 +1414,15 @@ void tst_qdeclarativeecmascript::functionErrors()
     delete object;
 
     // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
-    QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
+    QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceResourceFunctionFail.var.qml"));
     url = componentTwo.url().toString();
     object = componentTwo.create();
     QVERIFY(object != 0);
 
     QString srpname = object->property("srp_name").toString();
     
-    warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname + 
-              QLatin1String(" is not a function");
+    warning = url + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srpname
+                  + QLatin1String(" is not a function");
     QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
     QMetaObject::invokeMethod(object, "retrieveScarceResource");
     delete object;
@@ -3197,110 +3199,98 @@ void tst_qdeclarativeecmascript::importScripts()
     }
 }
 
-void tst_qdeclarativeecmascript::scarceResources()
+void tst_qdeclarativeecmascript::scarceResources_other()
 {
+    /* These tests require knowledge of state, since we test values after
+       performing signal or function invocation. */
+
     QPixmap origPixmap(100, 100);
     origPixmap.fill(Qt::blue);
-
+    QString srp_name, expectedWarning;
     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
     ScarceResourceObject *eo = 0;
+    QObject *srsc = 0;
     QObject *object = 0;
 
-    // in the following three cases, the instance created from the component
-    // has a property which is a copy of the scarce resource; hence, the
-    // resource should NOT be detached prior to deletion of the object instance,
-    // unless the resource is destroyed explicitly.
-    QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
-    object = component.create();
-    QVERIFY(object != 0);
-    QVERIFY(object->property("scarceResourceCopy").isValid());
-    QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
-    QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+    /* property var semantics */
+
+    // test that scarce resources are handled properly in signal invocation
+    QDeclarativeComponent varComponentTen(&engine, TEST_FILE("scarceResourceSignal.var.qml"));
+    object = varComponentTen.create();
+    srsc = object->findChild<QObject*>("srsc");
+    QVERIFY(srsc);
+    QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
+    QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
+    eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+    QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+    QMetaObject::invokeMethod(srsc, "testSignal");
+    QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
+    QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
-    QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
+    QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
+    QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
+    QVERIFY(srsc->property("scarceResourceCopy").isValid());
+    QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
+    eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+    QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
+    QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
     delete object;
 
-    QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
-    object = componentTwo.create();
+    // test that scarce resources are handled properly from js functions in qml files
+    QDeclarativeComponent varComponentEleven(&engine, TEST_FILE("scarceResourceFunction.var.qml"));
+    object = varComponentEleven.create();
     QVERIFY(object != 0);
-    QVERIFY(object->property("scarceResourceCopy").isValid());
+    QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
+    eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+    QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+    QMetaObject::invokeMethod(object, "retrieveScarceResource");
+    QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
     QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
-    QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
-    QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
-    delete object;
-
-    QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
-    object = componentThree.create();
-    QVERIFY(object != 0);
-    QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
-    QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+    QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
+    QMetaObject::invokeMethod(object, "releaseScarceResource");
+    QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
-    QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
-    delete object;
-
-    // in the following three cases, no other copy should exist in memory,
-    // and so it should be detached (unless explicitly preserved).
-    QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
-    object = componentFour.create();
-    QVERIFY(object != 0);
-    QVERIFY(object->property("scarceResourceTest").isValid());
-    QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
+    QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
-    eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
-    QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
     delete object;
 
-    QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
-    object = componentFive.create();
+    // test that if an exception occurs while invoking js function from cpp, that the resources are released.
+    QDeclarativeComponent varComponentTwelve(&engine, TEST_FILE("scarceResourceFunctionFail.var.qml"));
+    object = varComponentTwelve.create();
     QVERIFY(object != 0);
-    QVERIFY(object->property("scarceResourceTest").isValid());
-    QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
-    QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+    QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
-    QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
-    delete object;
-
-    QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
-    object = componentSix.create();
-    QVERIFY(object != 0);
-    QVERIFY(object->property("scarceResourceTest").isValid());
-    QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
-    QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+    QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+    srp_name = object->property("srp_name").toString();
+    expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
+    QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
+    QMetaObject::invokeMethod(object, "retrieveScarceResource");
+    QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
-    QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
-    delete object;
-
-    // test that scarce resources are handled correctly for imports
-    QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
-    object = componentSeven.create();
-    QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
-    QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
-    delete object;
-
-    QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
-    object = componentEight.create();
-    QVERIFY(object != 0);
-    QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
+    QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
     QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
     delete object;
 
-    QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
-    object = componentNine.create();
+    // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
+    // that the scarce resource is removed from the engine's list of scarce resources to clean up.
+    QDeclarativeComponent varComponentThirteen(&engine, TEST_FILE("scarceResourceObjectGc.var.qml"));
+    object = varComponentThirteen.create();
     QVERIFY(object != 0);
-    QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
-    QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
-    QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
-    QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
-    QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
-    QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
+    QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
+    QMetaObject::invokeMethod(object, "assignVarProperty");
+    QVERIFY(ep->scarceResources.isEmpty());             // the scarce resource is a VME property.
+    QMetaObject::invokeMethod(object, "deassignVarProperty");
+    QVERIFY(ep->scarceResources.isEmpty());             // should still be empty; the resource should have been released on gc.
     delete object;
 
+    /* property variant semantics */
+
     // test that scarce resources are handled properly in signal invocation
-    QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
-    object = componentTen.create();
+    QDeclarativeComponent variantComponentTen(&engine, TEST_FILE("scarceResourceSignal.variant.qml"));
+    object = variantComponentTen.create();
     QVERIFY(object != 0);
-    QObject *srsc = object->findChild<QObject*>("srsc");
+    srsc = object->findChild<QObject*>("srsc");
     QVERIFY(srsc);
     QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
     QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
@@ -3320,8 +3310,8 @@ void tst_qdeclarativeecmascript::scarceResources()
     delete object;
 
     // test that scarce resources are handled properly from js functions in qml files
-    QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
-    object = componentEleven.create();
+    QDeclarativeComponent variantComponentEleven(&engine, TEST_FILE("scarceResourceFunction.variant.qml"));
+    object = variantComponentEleven.create();
     QVERIFY(object != 0);
     QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
@@ -3339,14 +3329,14 @@ void tst_qdeclarativeecmascript::scarceResources()
     delete object;
 
     // test that if an exception occurs while invoking js function from cpp, that the resources are released.
-    QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
-    object = componentTwelve.create();
+    QDeclarativeComponent variantComponentTwelve(&engine, TEST_FILE("scarceResourceFunctionFail.variant.qml"));
+    object = variantComponentTwelve.create();
     QVERIFY(object != 0);
     QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
     eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
     QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
-    QString srp_name = object->property("srp_name").toString();
-    QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
+    srp_name = object->property("srp_name").toString();
+    expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
     QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
     QMetaObject::invokeMethod(object, "retrieveScarceResource");
     QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
@@ -3356,6 +3346,266 @@ void tst_qdeclarativeecmascript::scarceResources()
     delete object;
 }
 
+void tst_qdeclarativeecmascript::scarceResources_data()
+{
+    QTest::addColumn<QUrl>("qmlFile");
+    QTest::addColumn<bool>("readDetachStatus");
+    QTest::addColumn<bool>("expectedDetachStatus");
+    QTest::addColumn<QStringList>("propertyNames");
+    QTest::addColumn<QVariantList>("expectedValidity");
+    QTest::addColumn<QVariantList>("expectedValues");
+    QTest::addColumn<QStringList>("expectedErrors");
+
+    QPixmap origPixmap(100, 100);
+    origPixmap.fill(Qt::blue);
+
+    /* property var semantics */
+
+    // in the following three cases, the instance created from the component
+    // has a property which is a copy of the scarce resource; hence, the
+    // resource should NOT be detached prior to deletion of the object instance,
+    // unless the resource is destroyed explicitly.
+    QTest::newRow("var: import scarce resource copy directly")
+        << TEST_FILE("scarceResourceCopy.var.qml")
+        << true
+        << false // won't be detached, because assigned to property and not explicitly released
+        << (QStringList() << QLatin1String("scarceResourceCopy"))
+        << (QList<QVariant>() << true)
+        << (QList<QVariant>() << origPixmap)
+        << QStringList();
+
+    QTest::newRow("var: import scarce resource copy from JS")
+        << TEST_FILE("scarceResourceCopyFromJs.var.qml")
+        << true
+        << false // won't be detached, because assigned to property and not explicitly released
+        << (QStringList() << QLatin1String("scarceResourceCopy"))
+        << (QList<QVariant>() << true)
+        << (QList<QVariant>() << origPixmap)
+        << QStringList();
+
+    QTest::newRow("var: import released scarce resource copy from JS")
+        << TEST_FILE("scarceResourceDestroyedCopy.var.qml")
+        << true
+        << true // explicitly released, so it will be detached
+        << (QStringList() << QLatin1String("scarceResourceCopy"))
+        << (QList<QVariant>() << false)
+        << (QList<QVariant>() << QVariant())
+        << QStringList();
+
+    // in the following three cases, no other copy should exist in memory,
+    // and so it should be detached (unless explicitly preserved).
+    QTest::newRow("var: import auto-release SR from JS in binding side-effect")
+        << TEST_FILE("scarceResourceTest.var.qml")
+        << true
+        << true // auto released, so it will be detached
+        << (QStringList() << QLatin1String("scarceResourceTest"))
+        << (QList<QVariant>() << true)
+        << (QList<QVariant>() << QVariant(100))
+        << QStringList();
+    QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
+        << TEST_FILE("scarceResourceTestPreserve.var.qml")
+        << true
+        << false // won't be detached because we explicitly preserve it
+        << (QStringList() << QLatin1String("scarceResourceTest"))
+        << (QList<QVariant>() << true)
+        << (QList<QVariant>() << QVariant(100))
+        << QStringList();
+    QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
+        << TEST_FILE("scarceResourceTestMultiple.var.qml")
+        << true
+        << true // will be detached because all resources were released manually or automatically.
+        << (QStringList() << QLatin1String("scarceResourceTest"))
+        << (QList<QVariant>() << true)
+        << (QList<QVariant>() << QVariant(100))
+        << QStringList();
+
+    // In the following three cases, test that scarce resources are handled
+    // correctly for imports.
+    QTest::newRow("var: import with no binding")
+        << TEST_FILE("scarceResourceCopyImportNoBinding.var.qml")
+        << false // cannot check detach status.
+        << false
+        << QStringList()
+        << QList<QVariant>()
+        << QList<QVariant>()
+        << QStringList();
+    QTest::newRow("var: import with binding without explicit preserve")
+        << TEST_FILE("scarceResourceCopyImportNoBinding.var.qml")
+        << false
+        << false
+        << (QStringList() << QLatin1String("scarceResourceCopy"))
+        << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
+        << (QList<QVariant>() << QVariant())
+        << QStringList();
+    QTest::newRow("var: import with explicit release after binding evaluation")
+        << TEST_FILE("scarceResourceCopyImport.var.qml")
+        << false
+        << false
+        << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
+        << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
+        << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
+        << QStringList();
+    QTest::newRow("var: import with different js objects")
+        << TEST_FILE("scarceResourceCopyImportDifferent.var.qml")
+        << false
+        << false
+        << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
+        << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
+        << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
+        << QStringList();
+    QTest::newRow("var: import with different js objects and explicit release")
+        << TEST_FILE("scarceResourceMultipleDifferentNoBinding.var.qml")
+        << false
+        << false
+        << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
+        << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
+        << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
+        << QStringList();
+    QTest::newRow("var: import with same js objects and explicit release")
+        << TEST_FILE("scarceResourceMultipleSameNoBinding.var.qml")
+        << false
+        << false
+        << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
+        << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
+        << (QList<QVariant>() << QVariant() << QVariant())
+        << QStringList();
+    QTest::newRow("var: binding with same js objects and explicit release")
+        << TEST_FILE("scarceResourceMultipleSameWithBinding.var.qml")
+        << false
+        << false
+        << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
+        << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
+        << (QList<QVariant>() << QVariant() << QVariant())
+        << QStringList();
+
+
+    /* property variant semantics */
+
+    // in the following three cases, the instance created from the component
+    // has a property which is a copy of the scarce resource; hence, the
+    // resource should NOT be detached prior to deletion of the object instance,
+    // unless the resource is destroyed explicitly.
+    QTest::newRow("variant: import scarce resource copy directly")
+        << TEST_FILE("scarceResourceCopy.variant.qml")
+        << true
+        << false // won't be detached, because assigned to property and not explicitly released
+        << (QStringList() << QLatin1String("scarceResourceCopy"))
+        << (QList<QVariant>() << true)
+        << (QList<QVariant>() << origPixmap)
+        << QStringList();
+
+    QTest::newRow("variant: import scarce resource copy from JS")
+        << TEST_FILE("scarceResourceCopyFromJs.variant.qml")
+        << true
+        << false // won't be detached, because assigned to property and not explicitly released
+        << (QStringList() << QLatin1String("scarceResourceCopy"))
+        << (QList<QVariant>() << true)
+        << (QList<QVariant>() << origPixmap)
+        << QStringList();
+
+    QTest::newRow("variant: import released scarce resource copy from JS")
+        << TEST_FILE("scarceResourceDestroyedCopy.variant.qml")
+        << true
+        << true // explicitly released, so it will be detached
+        << (QStringList() << QLatin1String("scarceResourceCopy"))
+        << (QList<QVariant>() << false)
+        << (QList<QVariant>() << QVariant())
+        << QStringList();
+
+    // in the following three cases, no other copy should exist in memory,
+    // and so it should be detached (unless explicitly preserved).
+    QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
+        << TEST_FILE("scarceResourceTest.variant.qml")
+        << true
+        << true // auto released, so it will be detached
+        << (QStringList() << QLatin1String("scarceResourceTest"))
+        << (QList<QVariant>() << true)
+        << (QList<QVariant>() << QVariant(100))
+        << QStringList();
+    QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
+        << TEST_FILE("scarceResourceTestPreserve.variant.qml")
+        << true
+        << false // won't be detached because we explicitly preserve it
+        << (QStringList() << QLatin1String("scarceResourceTest"))
+        << (QList<QVariant>() << true)
+        << (QList<QVariant>() << QVariant(100))
+        << QStringList();
+    QTest::newRow("variant: import multiple scarce resources")
+        << TEST_FILE("scarceResourceTestMultiple.variant.qml")
+        << true
+        << true // will be detached because all resources were released manually or automatically.
+        << (QStringList() << QLatin1String("scarceResourceTest"))
+        << (QList<QVariant>() << true)
+        << (QList<QVariant>() << QVariant(100))
+        << QStringList();
+
+    // In the following three cases, test that scarce resources are handled
+    // correctly for imports.
+    QTest::newRow("variant: import with no binding")
+        << TEST_FILE("scarceResourceCopyImportNoBinding.variant.qml")
+        << false // cannot check detach status.
+        << false
+        << QStringList()
+        << QList<QVariant>()
+        << QList<QVariant>()
+        << QStringList();
+    QTest::newRow("variant: import with binding without explicit preserve")
+        << TEST_FILE("scarceResourceCopyImportNoBinding.variant.qml")
+        << false
+        << false
+        << (QStringList() << QLatin1String("scarceResourceCopy"))
+        << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
+        << (QList<QVariant>() << QVariant())
+        << QStringList();
+    QTest::newRow("variant: import with explicit release after binding evaluation")
+        << TEST_FILE("scarceResourceCopyImport.variant.qml")
+        << false
+        << false
+        << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
+        << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
+        << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
+        << QStringList();
+}
+
+void tst_qdeclarativeecmascript::scarceResources()
+{
+    QFETCH(QUrl, qmlFile);
+    QFETCH(bool, readDetachStatus);
+    QFETCH(bool, expectedDetachStatus);
+    QFETCH(QStringList, propertyNames);
+    QFETCH(QVariantList, expectedValidity);
+    QFETCH(QVariantList, expectedValues);
+    QFETCH(QStringList, expectedErrors);
+
+    QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
+    ScarceResourceObject *eo = 0;
+    QObject *object = 0;
+
+    QDeclarativeComponent c(&engine, qmlFile);
+    object = c.create();
+    QVERIFY(object != 0);
+    for (int i = 0; i < propertyNames.size(); ++i) {
+        QString prop = propertyNames.at(i);
+        bool validity = expectedValidity.at(i).toBool();
+        QVariant value = expectedValues.at(i);
+
+        QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
+        if (value.type() == QVariant::Int) {
+            QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
+        } else if (value.type() == QVariant::Pixmap) {
+            QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
+        }
+    }
+
+    if (readDetachStatus) {
+        eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+        QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
+    }
+
+    QVERIFY(ep->scarceResources.isEmpty());
+    delete object;
+}
+
 void tst_qdeclarativeecmascript::propertyChangeSlots()
 {
     // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.