1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
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.
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.
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.
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.
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_toString);
107 qPersistentDispose(m_constructor);
108 qPersistentDispose(m_toStringSymbol);
111 static quint32 toStringHash = -1;
113 void QV8ValueTypeWrapper::init(QV8Engine *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());
126 m_toStringSymbol = qPersistentNew<v8::String>(v8::String::NewSymbol("toString"));
127 m_toStringString = QHashedV8String(m_toStringSymbol);
128 toStringHash = m_toStringString.hash();
131 v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(QObject *object, int property, QDeclarativeValueType *type)
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);
141 v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(const QVariant &value, QDeclarativeValueType *type)
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);
151 QVariant QV8ValueTypeWrapper::toVariant(v8::Handle<v8::Object> obj)
153 QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(obj);
154 if (r) return toVariant(r);
155 else return QVariant();
158 QVariant QV8ValueTypeWrapper::toVariant(QV8ObjectResource *r)
160 Q_ASSERT(r->resourceType() == QV8ObjectResource::ValueTypeType);
161 QV8ValueTypeResource *resource = static_cast<QV8ValueTypeResource *>(r);
163 if (resource->objectType == QV8ValueTypeResource::Reference) {
164 QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource);
166 if (reference->object) {
167 reference->type->read(reference->object, reference->property);
168 return reference->type->value();
174 Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy);
176 QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource);
182 bool QV8ValueTypeWrapper::isEqual(QV8ObjectResource *r, const QVariant& value)
184 Q_ASSERT(r->resourceType() == QV8ObjectResource::ValueTypeType);
185 QV8ValueTypeResource *resource = static_cast<QV8ValueTypeResource *>(r);
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);
196 Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy);
197 QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource);
198 return (value == copy->value);
202 v8::Handle<v8::Value> QV8ValueTypeWrapper::ToStringGetter(v8::Local<v8::String> property,
203 const v8::AccessorInfo &info)
209 v8::Handle<v8::Value> QV8ValueTypeWrapper::ToString(const v8::Arguments &args)
211 QV8ValueTypeResource *resource = v8_resource_cast<QV8ValueTypeResource>(args.This());
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());
219 return v8::Undefined();
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()));
228 return resource->engine->toString(result);
231 return v8::Undefined();
235 v8::Handle<v8::Value> QV8ValueTypeWrapper::Getter(v8::Local<v8::String> property,
236 const v8::AccessorInfo &info)
238 QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(info.This());
239 if (!r) return v8::Handle<v8::Value>();
241 QHashedV8String propertystring(property);
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;
252 QDeclarativePropertyData local;
253 QDeclarativePropertyData *result = 0;
255 QDeclarativeData *ddata = QDeclarativeData::get(r->type, false);
256 if (ddata && ddata->propertyCache)
257 result = ddata->propertyCache->property(propertystring);
259 result = QDeclarativePropertyCache::property(r->engine->engine(), r->type,
260 propertystring, local);
264 return v8::Handle<v8::Value>();
266 if (r->objectType == QV8ValueTypeResource::Reference) {
267 QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
269 if (!reference->object)
270 return v8::Handle<v8::Value>();
272 r->type->read(reference->object, reference->property);
274 Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
276 QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
278 r->type->setValue(copy->value);
281 #define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
282 if (result->propType == metatype) { \
284 void *args[] = { &v, 0 }; \
285 r->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args); \
286 return constructor(v); \
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);
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
302 v8::Handle<v8::Value> QV8ValueTypeWrapper::Setter(v8::Local<v8::String> property,
303 v8::Local<v8::Value> value,
304 const v8::AccessorInfo &info)
306 QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(info.This());
307 if (!r) return value;
309 QByteArray propName = r->engine->toString(property).toUtf8();
310 int index = r->type->metaObject()->indexOfProperty(propName.constData());
314 if (r->objectType == QV8ValueTypeResource::Reference) {
315 QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
317 if (!reference->object ||
318 !reference->object->metaObject()->property(reference->property).isWritable())
321 r->type->read(reference->object, reference->property);
322 QMetaProperty p = r->type->metaObject()->property(index);
324 QDeclarativeBinding *newBinding = 0;
326 if (value->IsFunction()) {
327 QDeclarativeContextData *context = r->engine->callingContext();
328 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
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();
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());
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);
355 QDeclarativeAbstractBinding *oldBinding =
356 QDeclarativePropertyPrivate::setBinding(reference->object, reference->property, index, newBinding);
358 oldBinding->destroy();
360 if (!value->IsFunction()) {
361 QVariant v = r->engine->toVariant(value, -1);
363 if (p.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double)
366 p.write(reference->type, v);
368 reference->type->write(reference->object, reference->property, 0);
372 Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
374 QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
376 QVariant v = r->engine->toVariant(value, -1);
378 r->type->setValue(copy->value);
379 QMetaProperty p = r->type->metaObject()->property(index);
381 copy->value = r->type->value();