Ensure that scarce resources work with var properties
[profile/ivi/qtdeclarative.git] / src / declarative / qml / v8 / qv8variantwrapper.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qv8variantwrapper_p.h"
43 #include "qv8variantresource_p.h"
44 #include "qv8engine_p.h"
45 #include <private/qdeclarativeengine_p.h>
46
47 QT_BEGIN_NAMESPACE
48
49 QV8VariantResource::QV8VariantResource(QV8Engine *engine, const QVariant &data)
50 : QV8ObjectResource(engine), QDeclarativeEnginePrivate::ScarceResourceData(data), m_isScarceResource(false), m_vmePropertyReferenceCount(0)
51 {
52 }
53
54 void QV8VariantResource::addVmePropertyReference()
55 {
56     if (m_isScarceResource && ++m_vmePropertyReferenceCount == 1) {
57         // remove from the ep->scarceResources list
58         // since it is now no longer eligible to be
59         // released automatically by the engine.
60         node.remove();
61     }
62 }
63
64 void QV8VariantResource::removeVmePropertyReference()
65 {
66     if (m_isScarceResource && --m_vmePropertyReferenceCount == 0) {
67         // and add to the ep->scarceResources list
68         // since it is now eligible to be released
69         // automatically by the engine.
70         QDeclarativeEnginePrivate::get(engine->engine())->scarceResources.insert(this);
71     }
72 }
73
74 QV8VariantWrapper::QV8VariantWrapper()
75 : m_engine(0)
76 {
77 }
78
79 QV8VariantWrapper::~QV8VariantWrapper()
80 {
81 }
82
83 void QV8VariantWrapper::init(QV8Engine *engine)
84 {
85     m_engine = engine;
86     m_toString = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ToString)->GetFunction());
87     m_valueOf = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ValueOf)->GetFunction());
88
89     {
90     v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
91     ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
92     ft->InstanceTemplate()->SetHasExternalResource(true);
93     ft->InstanceTemplate()->MarkAsUseUserObjectComparison();
94     ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0, 
95                                         m_toString, v8::DEFAULT, 
96                                         v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
97     ft->InstanceTemplate()->SetAccessor(v8::String::New("valueOf"), ValueOfGetter, 0,
98                                         m_valueOf, v8::DEFAULT,
99                                         v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
100     m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
101     }
102     {
103     m_preserve = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(Preserve)->GetFunction());
104     m_destroy = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(Destroy)->GetFunction());
105     v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
106     ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
107     ft->InstanceTemplate()->SetHasExternalResource(true);
108     ft->InstanceTemplate()->MarkAsUseUserObjectComparison();
109     ft->InstanceTemplate()->SetAccessor(v8::String::New("preserve"), PreserveGetter, 0, 
110                                         m_preserve, v8::DEFAULT, 
111                                         v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
112     ft->InstanceTemplate()->SetAccessor(v8::String::New("destroy"), DestroyGetter, 0, 
113                                         m_destroy, v8::DEFAULT, 
114                                         v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
115     ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0, 
116                                         m_toString, v8::DEFAULT, 
117                                         v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
118     ft->InstanceTemplate()->SetAccessor(v8::String::New("valueOf"), ValueOfGetter, 0,
119                                         m_valueOf, v8::DEFAULT,
120                                         v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
121     m_scarceConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
122     }
123
124 }
125
126 void QV8VariantWrapper::destroy()
127 {
128     qPersistentDispose(m_valueOf);
129     qPersistentDispose(m_toString);
130     qPersistentDispose(m_destroy);
131     qPersistentDispose(m_preserve);
132     qPersistentDispose(m_scarceConstructor);
133     qPersistentDispose(m_constructor);
134 }
135
136 v8::Local<v8::Object> QV8VariantWrapper::newVariant(const QVariant &value)
137 {
138     bool scarceResource = value.type() == QVariant::Pixmap ||
139                           value.type() == QVariant::Image;
140
141     // XXX NewInstance() should be optimized
142     v8::Local<v8::Object> rv;
143     QV8VariantResource *r = new QV8VariantResource(m_engine, value);
144
145     if (scarceResource) {
146         QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_engine->engine());
147         Q_ASSERT(ep->scarceResourcesRefCount);
148         rv = m_scarceConstructor->NewInstance();
149         r->m_isScarceResource = true;
150         ep->scarceResources.insert(r);
151     } else {
152         rv = m_constructor->NewInstance();
153     }
154
155     rv->SetExternalResource(r);
156     return rv;
157 }
158
159 bool QV8VariantWrapper::isVariant(v8::Handle<v8::Value> value)
160 {
161     return value->IsObject() && v8_resource_cast<QV8VariantResource>(value->ToObject());
162 }
163
164 QVariant QV8VariantWrapper::toVariant(v8::Handle<v8::Object> obj)
165 {
166     QV8VariantResource *r =  v8_resource_cast<QV8VariantResource>(obj);
167     return r?r->data:QVariant();
168 }
169
170 QVariant QV8VariantWrapper::toVariant(QV8ObjectResource *r)
171 {
172     Q_ASSERT(r->resourceType() == QV8ObjectResource::VariantType);
173     return static_cast<QV8VariantResource *>(r)->data;
174 }
175
176 QVariant &QV8VariantWrapper::variantValue(v8::Handle<v8::Value> value)
177 {
178     Q_ASSERT(isVariant(value));
179     QV8VariantResource *r =  v8_resource_cast<QV8VariantResource>(value->ToObject());
180     return static_cast<QV8VariantResource *>(r)->data;
181 }
182
183 v8::Handle<v8::Value> QV8VariantWrapper::Getter(v8::Local<v8::String> /* property */,
184                                                 const v8::AccessorInfo & /* info */)
185 {
186     return v8::Handle<v8::Value>();
187 }
188
189 v8::Handle<v8::Value> QV8VariantWrapper::Setter(v8::Local<v8::String> /* property */,
190                                                 v8::Local<v8::Value> value,
191                                                 const v8::AccessorInfo & /* info */)
192 {
193     return value;
194 }
195
196 v8::Handle<v8::Value> QV8VariantWrapper::PreserveGetter(v8::Local<v8::String> property, 
197                                                         const v8::AccessorInfo &info)
198 {
199     Q_UNUSED(property);
200     return info.Data();
201 }
202
203 v8::Handle<v8::Value> QV8VariantWrapper::DestroyGetter(v8::Local<v8::String> property, 
204                                                        const v8::AccessorInfo &info)
205 {
206     Q_UNUSED(property);
207     return info.Data();
208 }
209
210 v8::Handle<v8::Value> QV8VariantWrapper::ToStringGetter(v8::Local<v8::String> property, 
211                                                         const v8::AccessorInfo &info)
212 {
213     Q_UNUSED(property);
214     return info.Data();
215 }
216
217 v8::Handle<v8::Value> QV8VariantWrapper::ValueOfGetter(v8::Local<v8::String> property,
218                                                        const v8::AccessorInfo &info)
219 {
220     Q_UNUSED(property);
221     return info.Data();
222 }
223
224 v8::Handle<v8::Value> QV8VariantWrapper::Preserve(const v8::Arguments &args)
225 {
226     QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This());
227     if (resource) {
228         resource->node.remove();
229     }
230     return v8::Undefined();
231 }
232
233 v8::Handle<v8::Value> QV8VariantWrapper::Destroy(const v8::Arguments &args)
234 {
235     QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This());
236     if (resource) {
237         resource->data = QVariant();
238         resource->node.remove();
239     }
240     return v8::Undefined();
241 }
242
243 v8::Handle<v8::Value> QV8VariantWrapper::ToString(const v8::Arguments &args)
244 {
245     QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This());
246     if (resource) {
247         QString result = resource->data.toString();
248         if (result.isEmpty() && !resource->data.canConvert(QVariant::String))
249             result = QString::fromLatin1("QVariant(%0)").arg(QString::fromLatin1(resource->data.typeName()));
250         return resource->engine->toString(result);
251     } else {
252         return v8::Undefined();
253     }
254 }
255
256 v8::Handle<v8::Value> QV8VariantWrapper::ValueOf(const v8::Arguments &args)
257 {
258     QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This());
259     if (resource) {
260         QVariant v = resource->data;
261         switch (v.type()) {
262         case QVariant::Invalid:
263             return v8::Undefined();
264         case QVariant::String:
265             return resource->engine->toString(v.toString());
266         case QVariant::Int:
267         case QVariant::Double:
268         case QVariant::UInt:
269             return v8::Number::New(v.toDouble());
270         case QVariant::Bool:
271             return v8::Boolean::New(v.toBool());
272         default:
273             break;
274         }
275     }
276     return args.This();
277 }
278
279 QT_END_NAMESPACE