1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "qv8valuetypewrapper_p.h"
43 #include "qv8engine_p.h"
45 #include <private/qdeclarativevaluetype_p.h>
46 #include <private/qdeclarativebinding_p.h>
50 class QV8ValueTypeResource : public QV8ObjectResource
52 V8_RESOURCE_TYPE(ValueTypeType);
55 enum ObjectType { Reference, Copy };
57 QV8ValueTypeResource(QV8Engine *engine, ObjectType objectType);
59 ObjectType objectType;
60 QDeclarativeValueType *type;
63 class QV8ValueTypeReferenceResource : public QV8ValueTypeResource
66 QV8ValueTypeReferenceResource(QV8Engine *engine);
68 QDeclarativeGuard<QObject> object;
72 class QV8ValueTypeCopyResource : public QV8ValueTypeResource
75 QV8ValueTypeCopyResource(QV8Engine *engine);
80 QV8ValueTypeResource::QV8ValueTypeResource(QV8Engine *engine, ObjectType objectType)
81 : QV8ObjectResource(engine), objectType(objectType)
85 QV8ValueTypeReferenceResource::QV8ValueTypeReferenceResource(QV8Engine *engine)
86 : QV8ValueTypeResource(engine, Reference)
90 QV8ValueTypeCopyResource::QV8ValueTypeCopyResource(QV8Engine *engine)
91 : QV8ValueTypeResource(engine, Copy)
95 QV8ValueTypeWrapper::QV8ValueTypeWrapper()
100 QV8ValueTypeWrapper::~QV8ValueTypeWrapper()
104 void QV8ValueTypeWrapper::destroy()
106 qPersistentDispose(m_constructor);
109 void QV8ValueTypeWrapper::init(QV8Engine *engine)
112 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
113 ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
114 ft->InstanceTemplate()->SetHasExternalResource(true);
115 m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
118 v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(QObject *object, int property, QDeclarativeValueType *type)
120 // XXX NewInstance() should be optimized
121 v8::Local<v8::Object> rv = m_constructor->NewInstance();
122 QV8ValueTypeReferenceResource *r = new QV8ValueTypeReferenceResource(m_engine);
123 r->type = type; r->object = object; r->property = property;
124 rv->SetExternalResource(r);
128 v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(const QVariant &value, QDeclarativeValueType *type)
130 // XXX NewInstance() should be optimized
131 v8::Local<v8::Object> rv = m_constructor->NewInstance();
132 QV8ValueTypeCopyResource *r = new QV8ValueTypeCopyResource(m_engine);
133 r->type = type; r->value = value;
134 rv->SetExternalResource(r);
138 QVariant QV8ValueTypeWrapper::toVariant(v8::Handle<v8::Object> obj)
140 QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(obj);
141 if (r) return toVariant(r);
142 else return QVariant();
145 QVariant QV8ValueTypeWrapper::toVariant(QV8ObjectResource *r)
147 Q_ASSERT(r->resourceType() == QV8ObjectResource::ValueTypeType);
148 QV8ValueTypeResource *resource = static_cast<QV8ValueTypeResource *>(r);
150 if (resource->objectType == QV8ValueTypeResource::Reference) {
151 QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource);
153 if (reference->object) {
154 reference->type->read(reference->object, reference->property);
155 return reference->type->value();
161 Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy);
163 QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource);
169 v8::Handle<v8::Value> QV8ValueTypeWrapper::Getter(v8::Local<v8::String> property,
170 const v8::AccessorInfo &info)
172 QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(info.This());
173 if (!r) return v8::Undefined();
175 // XXX This is horribly inefficient. Sadly people seem to have taken a liking to
176 // value type properties, so we should probably try and optimize it a little.
177 // We should probably just replace all value properties with dedicated accessors.
179 QByteArray propName = r->engine->toString(property).toUtf8();
180 int index = r->type->metaObject()->indexOfProperty(propName.constData());
182 return v8::Undefined();
184 if (r->objectType == QV8ValueTypeResource::Reference) {
185 QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
187 if (!reference->object)
188 return v8::Undefined();
190 r->type->read(reference->object, reference->property);
192 Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
194 QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
196 r->type->setValue(copy->value);
199 QMetaProperty prop = r->type->metaObject()->property(index);
200 QVariant result = prop.read(r->type);
202 return r->engine->fromVariant(result);
205 v8::Handle<v8::Value> QV8ValueTypeWrapper::Setter(v8::Local<v8::String> property,
206 v8::Local<v8::Value> value,
207 const v8::AccessorInfo &info)
209 QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(info.This());
210 if (!r) return value;
212 QByteArray propName = r->engine->toString(property).toUtf8();
213 int index = r->type->metaObject()->indexOfProperty(propName.constData());
217 if (r->objectType == QV8ValueTypeResource::Reference) {
218 QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
220 if (!reference->object ||
221 !reference->object->metaObject()->property(reference->property).isWritable())
224 r->type->read(reference->object, reference->property);
225 QMetaProperty p = r->type->metaObject()->property(index);
227 QDeclarativeBinding *newBinding = 0;
229 if (value->IsFunction()) {
230 QDeclarativeContextData *context = r->engine->callingContext();
231 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
233 QDeclarativePropertyCache::Data cacheData;
234 cacheData.flags = QDeclarativePropertyCache::Data::IsWritable;
235 cacheData.propType = reference->object->metaObject()->property(reference->property).userType();
236 cacheData.coreIndex = reference->property;
238 QDeclarativePropertyCache::ValueTypeData valueTypeData;
239 valueTypeData.valueTypeCoreIdx = index;
240 valueTypeData.valueTypePropType = p.userType();
242 v8::Local<v8::StackTrace> trace =
243 v8::StackTrace::CurrentStackTrace(1,
244 (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber |
245 v8::StackTrace::kScriptName));
246 v8::Local<v8::StackFrame> frame = trace->GetFrame(0);
247 int lineNumber = frame->GetLineNumber();
248 QString url = r->engine->toString(frame->GetScriptName());
250 newBinding = new QDeclarativeBinding(&function, reference->object, context);
251 newBinding->setSourceLocation(url, lineNumber);
252 newBinding->setTarget(QDeclarativePropertyPrivate::restore(cacheData, valueTypeData,
253 reference->object, context));
254 newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject);
257 QDeclarativeAbstractBinding *oldBinding =
258 QDeclarativePropertyPrivate::setBinding(reference->object, reference->property, index, newBinding);
260 oldBinding->destroy();
262 if (!value->IsFunction()) {
263 QVariant v = r->engine->toVariant(value, -1);
265 if (p.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double)
268 p.write(reference->type, v);
270 reference->type->write(reference->object, reference->property, 0);
274 Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
276 QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
278 QVariant v = r->engine->toVariant(value, -1);
280 r->type->setValue(copy->value);
281 QMetaProperty p = r->type->metaObject()->property(index);
283 copy->value = r->type->value();