Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / v8 / qv8valuetypewrapper.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qv8valuetypewrapper_p.h"
43 #include "qv8engine_p.h"
44
45 #include <private/qdeclarativevaluetype_p.h>
46 #include <private/qdeclarativebinding_p.h>
47
48 QT_BEGIN_NAMESPACE
49
50 class QV8ValueTypeResource : public QV8ObjectResource
51 {
52     V8_RESOURCE_TYPE(ValueTypeType);
53
54 public:
55     enum ObjectType { Reference, Copy };
56
57     QV8ValueTypeResource(QV8Engine *engine, ObjectType objectType);
58
59     ObjectType objectType;
60     QDeclarativeValueType *type;
61 };
62
63 class QV8ValueTypeReferenceResource : public QV8ValueTypeResource
64 {
65 public:
66     QV8ValueTypeReferenceResource(QV8Engine *engine);
67
68     QDeclarativeGuard<QObject> object;
69     int property;
70 };
71
72 class QV8ValueTypeCopyResource : public QV8ValueTypeResource
73 {
74 public:
75     QV8ValueTypeCopyResource(QV8Engine *engine);
76
77     QVariant value;
78 };
79
80 QV8ValueTypeResource::QV8ValueTypeResource(QV8Engine *engine, ObjectType objectType)
81 : QV8ObjectResource(engine), objectType(objectType)
82 {
83 }
84
85 QV8ValueTypeReferenceResource::QV8ValueTypeReferenceResource(QV8Engine *engine)
86 : QV8ValueTypeResource(engine, Reference)
87 {
88 }
89
90 QV8ValueTypeCopyResource::QV8ValueTypeCopyResource(QV8Engine *engine)
91 : QV8ValueTypeResource(engine, Copy)
92 {
93 }
94
95 QV8ValueTypeWrapper::QV8ValueTypeWrapper()
96 : m_engine(0)
97 {
98 }
99
100 QV8ValueTypeWrapper::~QV8ValueTypeWrapper()
101 {
102 }
103
104 void QV8ValueTypeWrapper::destroy()
105 {
106     qPersistentDispose(m_toString);
107     qPersistentDispose(m_constructor);
108     qPersistentDispose(m_toStringSymbol);
109 }
110
111 static quint32 toStringHash = -1;
112
113 void QV8ValueTypeWrapper::init(QV8Engine *engine)
114 {
115     m_engine = engine;
116     m_toString = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ToString)->GetFunction());
117     v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
118     ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
119     ft->InstanceTemplate()->SetHasExternalResource(true);
120     ft->InstanceTemplate()->MarkAsUseUserObjectComparison();
121     ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0,
122                                         m_toString, v8::DEFAULT,
123                                         v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
124     m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
125
126     m_toStringSymbol = qPersistentNew<v8::String>(v8::String::NewSymbol("toString"));
127     m_toStringString = QHashedV8String(m_toStringSymbol);
128     toStringHash = m_toStringString.hash();
129 }
130
131 v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(QObject *object, int property, QDeclarativeValueType *type)
132 {
133     // XXX NewInstance() should be optimized
134     v8::Local<v8::Object> rv = m_constructor->NewInstance(); 
135     QV8ValueTypeReferenceResource *r = new QV8ValueTypeReferenceResource(m_engine);
136     r->type = type; r->object = object; r->property = property;
137     rv->SetExternalResource(r);
138     return rv;
139 }
140
141 v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(const QVariant &value, QDeclarativeValueType *type)
142 {
143     // XXX NewInstance() should be optimized
144     v8::Local<v8::Object> rv = m_constructor->NewInstance(); 
145     QV8ValueTypeCopyResource *r = new QV8ValueTypeCopyResource(m_engine);
146     r->type = type; r->value = value;
147     rv->SetExternalResource(r);
148     return rv;
149 }
150
151 QVariant QV8ValueTypeWrapper::toVariant(v8::Handle<v8::Object> obj)
152 {
153     QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(obj);
154     if (r) return toVariant(r);
155     else return QVariant();
156 }
157
158 QVariant QV8ValueTypeWrapper::toVariant(QV8ObjectResource *r)
159 {
160     Q_ASSERT(r->resourceType() == QV8ObjectResource::ValueTypeType);
161     QV8ValueTypeResource *resource = static_cast<QV8ValueTypeResource *>(r);
162     
163     if (resource->objectType == QV8ValueTypeResource::Reference) {
164         QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource);
165
166         if (reference->object) {
167             reference->type->read(reference->object, reference->property);
168             return reference->type->value();
169         } else {
170             return QVariant();
171         }
172
173     } else {
174         Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy);
175
176         QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource);
177
178         return copy->value;
179     }
180 }
181
182 bool QV8ValueTypeWrapper::isEqual(QV8ObjectResource *r, const QVariant& value)
183 {
184     Q_ASSERT(r->resourceType() == QV8ObjectResource::ValueTypeType);
185     QV8ValueTypeResource *resource = static_cast<QV8ValueTypeResource *>(r);
186
187     if (resource->objectType == QV8ValueTypeResource::Reference) {
188         QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource);
189         if (reference->object) {
190             reference->type->read(reference->object, reference->property);
191             return reference->type->isEqual(value);
192         } else {
193             return false;
194         }
195     } else {
196         Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy);
197         QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource);
198         return (value == copy->value);
199     }
200 }
201
202 v8::Handle<v8::Value> QV8ValueTypeWrapper::ToStringGetter(v8::Local<v8::String> property,
203                                                         const v8::AccessorInfo &info)
204 {
205     Q_UNUSED(property);
206     return info.Data();
207 }
208
209 v8::Handle<v8::Value> QV8ValueTypeWrapper::ToString(const v8::Arguments &args)
210 {
211     QV8ValueTypeResource *resource = v8_resource_cast<QV8ValueTypeResource>(args.This());
212     if (resource) {
213         if (resource->objectType == QV8ValueTypeResource::Reference) {
214             QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource);
215             if (reference->object) {
216                 reference->type->read(reference->object, reference->property);
217                 return resource->engine->toString(resource->type->toString());
218             } else {
219                 return v8::Undefined();
220             }
221         } else {
222             Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy);
223             QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource);
224             QString result = copy->value.toString();
225             if (result.isEmpty() && !copy->value.canConvert(QVariant::String)) {
226                 result = QString::fromLatin1("QVariant(%0)").arg(QString::fromLatin1(copy->value.typeName()));
227             }
228             return resource->engine->toString(result);
229         }
230     } else {
231         return v8::Undefined();
232     }
233 }
234
235 v8::Handle<v8::Value> QV8ValueTypeWrapper::Getter(v8::Local<v8::String> property, 
236                                                   const v8::AccessorInfo &info)
237 {
238     QV8ValueTypeResource *r =  v8_resource_cast<QV8ValueTypeResource>(info.This());
239     if (!r) return v8::Handle<v8::Value>();
240
241     QHashedV8String propertystring(property);
242
243     {
244         // Comparing the hash first actually makes a measurable difference here, at least on x86
245         quint32 hash = propertystring.hash();
246         if (hash == toStringHash &&
247             r->engine->valueTypeWrapper()->m_toStringString == propertystring) {
248             return r->engine->valueTypeWrapper()->m_toString;
249         }
250     }
251
252     QDeclarativePropertyData local;
253     QDeclarativePropertyData *result = 0;
254     {
255         QDeclarativeData *ddata = QDeclarativeData::get(r->type, false);
256         if (ddata && ddata->propertyCache)
257             result = ddata->propertyCache->property(propertystring);
258         else
259             result = QDeclarativePropertyCache::property(r->engine->engine(), r->type,
260                                                          propertystring, local);
261     }
262
263     if (!result)
264         return v8::Handle<v8::Value>();
265
266     if (r->objectType == QV8ValueTypeResource::Reference) {
267         QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
268
269         if (!reference->object)
270             return v8::Handle<v8::Value>();
271
272         r->type->read(reference->object, reference->property);
273     } else {
274         Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
275
276         QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
277
278         r->type->setValue(copy->value);
279     }
280
281 #define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
282     if (result->propType == metatype) { \
283         cpptype v; \
284         void *args[] = { &v, 0 }; \
285         r->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args); \
286         return constructor(v); \
287     }
288
289     // These four types are the most common used by the value type wrappers
290     VALUE_TYPE_LOAD(QMetaType::QReal, qreal, v8::Number::New);
291     VALUE_TYPE_LOAD(QMetaType::Int, int, v8::Integer::New);
292     VALUE_TYPE_LOAD(QMetaType::QString, QString, r->engine->toString);
293     VALUE_TYPE_LOAD(QMetaType::Bool, bool, v8::Boolean::New);
294
295     QVariant v(result->propType, (void *)0);
296     void *args[] = { v.data(), 0 };
297     r->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args);
298     return r->engine->fromVariant(v);
299 #undef VALUE_TYPE_ACCESSOR
300 }
301
302 v8::Handle<v8::Value> QV8ValueTypeWrapper::Setter(v8::Local<v8::String> property, 
303                                                   v8::Local<v8::Value> value,
304                                                   const v8::AccessorInfo &info)
305 {
306     QV8ValueTypeResource *r =  v8_resource_cast<QV8ValueTypeResource>(info.This());
307     if (!r) return value;
308
309     QByteArray propName = r->engine->toString(property).toUtf8();
310     int index = r->type->metaObject()->indexOfProperty(propName.constData());
311     if (index == -1)
312         return value;
313
314     if (r->objectType == QV8ValueTypeResource::Reference) {
315         QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
316
317         if (!reference->object || 
318             !reference->object->metaObject()->property(reference->property).isWritable())
319             return value;
320
321         r->type->read(reference->object, reference->property);
322         QMetaProperty p = r->type->metaObject()->property(index);
323
324         QDeclarativeBinding *newBinding = 0;
325
326         if (value->IsFunction()) {
327             QDeclarativeContextData *context = r->engine->callingContext();
328             v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
329
330             QDeclarativePropertyData cacheData;
331             cacheData.setFlags(QDeclarativePropertyData::IsWritable |
332                                QDeclarativePropertyData::IsValueTypeVirtual);
333             cacheData.propType = reference->object->metaObject()->property(reference->property).userType();
334             cacheData.coreIndex = reference->property;
335             cacheData.valueTypeFlags = 0;
336             cacheData.valueTypeCoreIndex = index;
337             cacheData.valueTypePropType = p.userType();
338
339             v8::Local<v8::StackTrace> trace = 
340                 v8::StackTrace::CurrentStackTrace(1, 
341                         (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber | 
342                                                             v8::StackTrace::kScriptName));
343             v8::Local<v8::StackFrame> frame = trace->GetFrame(0);
344             int lineNumber = frame->GetLineNumber();
345             int columnNumber = frame->GetColumn();
346             QString url = r->engine->toString(frame->GetScriptName());
347
348             newBinding = new QDeclarativeBinding(&function, reference->object, context);
349             newBinding->setSourceLocation(url, lineNumber, columnNumber);
350             newBinding->setTarget(reference->object, cacheData, context);
351             newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
352                                          QDeclarativeBinding::RequiresThisObject);
353         }
354
355         QDeclarativeAbstractBinding *oldBinding = 
356             QDeclarativePropertyPrivate::setBinding(reference->object, reference->property, index, newBinding);
357         if (oldBinding)
358             oldBinding->destroy();
359
360         if (!value->IsFunction()) {
361             QVariant v = r->engine->toVariant(value, -1);
362
363             if (p.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double)
364                 v = v.toInt();
365
366             p.write(reference->type, v);
367
368             reference->type->write(reference->object, reference->property, 0);
369         }
370
371     } else {
372         Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
373
374         QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
375
376         QVariant v = r->engine->toVariant(value, -1);
377
378         r->type->setValue(copy->value);
379         QMetaProperty p = r->type->metaObject()->property(index);
380         p.write(r->type, v);
381         copy->value = r->type->value();
382     }
383
384     return value;
385 }
386
387 QT_END_NAMESPACE