/**************************************************************************** ** ** 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$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, 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. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qv8valuetypewrapper_p.h" #include "qv8engine_p.h" #include #include QT_BEGIN_NAMESPACE class QV8ValueTypeResource : public QV8ObjectResource { V8_RESOURCE_TYPE(ValueTypeType); public: enum ObjectType { Reference, Copy }; QV8ValueTypeResource(QV8Engine *engine, ObjectType objectType); ObjectType objectType; QDeclarativeValueType *type; }; class QV8ValueTypeReferenceResource : public QV8ValueTypeResource { public: QV8ValueTypeReferenceResource(QV8Engine *engine); QDeclarativeGuard object; int property; }; class QV8ValueTypeCopyResource : public QV8ValueTypeResource { public: QV8ValueTypeCopyResource(QV8Engine *engine); QVariant value; }; QV8ValueTypeResource::QV8ValueTypeResource(QV8Engine *engine, ObjectType objectType) : QV8ObjectResource(engine), objectType(objectType) { } QV8ValueTypeReferenceResource::QV8ValueTypeReferenceResource(QV8Engine *engine) : QV8ValueTypeResource(engine, Reference) { } QV8ValueTypeCopyResource::QV8ValueTypeCopyResource(QV8Engine *engine) : QV8ValueTypeResource(engine, Copy) { } QV8ValueTypeWrapper::QV8ValueTypeWrapper() : m_engine(0) { } QV8ValueTypeWrapper::~QV8ValueTypeWrapper() { } void QV8ValueTypeWrapper::destroy() { qPersistentDispose(m_constructor); } void QV8ValueTypeWrapper::init(QV8Engine *engine) { m_engine = engine; v8::Local ft = v8::FunctionTemplate::New(); ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter); ft->InstanceTemplate()->SetHasExternalResource(true); m_constructor = qPersistentNew(ft->GetFunction()); } v8::Local QV8ValueTypeWrapper::newValueType(QObject *object, int property, QDeclarativeValueType *type) { // XXX NewInstance() should be optimized v8::Local rv = m_constructor->NewInstance(); QV8ValueTypeReferenceResource *r = new QV8ValueTypeReferenceResource(m_engine); r->type = type; r->object = object; r->property = property; rv->SetExternalResource(r); return rv; } v8::Local QV8ValueTypeWrapper::newValueType(const QVariant &value, QDeclarativeValueType *type) { // XXX NewInstance() should be optimized v8::Local rv = m_constructor->NewInstance(); QV8ValueTypeCopyResource *r = new QV8ValueTypeCopyResource(m_engine); r->type = type; r->value = value; rv->SetExternalResource(r); return rv; } QVariant QV8ValueTypeWrapper::toVariant(v8::Handle obj) { QV8ValueTypeResource *r = v8_resource_cast(obj); if (r) return toVariant(r); else return QVariant(); } QVariant QV8ValueTypeWrapper::toVariant(QV8ObjectResource *r) { Q_ASSERT(r->resourceType() == QV8ObjectResource::ValueTypeType); QV8ValueTypeResource *resource = static_cast(r); if (resource->objectType == QV8ValueTypeResource::Reference) { QV8ValueTypeReferenceResource *reference = static_cast(resource); if (reference->object) { reference->type->read(reference->object, reference->property); return reference->type->value(); } else { return QVariant(); } } else { Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy); QV8ValueTypeCopyResource *copy = static_cast(resource); return copy->value; } } v8::Handle QV8ValueTypeWrapper::Getter(v8::Local property, const v8::AccessorInfo &info) { QV8ValueTypeResource *r = v8_resource_cast(info.This()); if (!r) return v8::Undefined(); // XXX This is horribly inefficient. Sadly people seem to have taken a liking to // value type properties, so we should probably try and optimize it a little. // We should probably just replace all value properties with dedicated accessors. QByteArray propName = r->engine->toString(property).toUtf8(); int index = r->type->metaObject()->indexOfProperty(propName.constData()); if (index == -1) return v8::Undefined(); if (r->objectType == QV8ValueTypeResource::Reference) { QV8ValueTypeReferenceResource *reference = static_cast(r); if (!reference->object) return v8::Undefined(); r->type->read(reference->object, reference->property); } else { Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy); QV8ValueTypeCopyResource *copy = static_cast(r); r->type->setValue(copy->value); } QMetaProperty prop = r->type->metaObject()->property(index); QVariant result = prop.read(r->type); return r->engine->fromVariant(result); } v8::Handle QV8ValueTypeWrapper::Setter(v8::Local property, v8::Local value, const v8::AccessorInfo &info) { QV8ValueTypeResource *r = v8_resource_cast(info.This()); if (!r) return value; QByteArray propName = r->engine->toString(property).toUtf8(); int index = r->type->metaObject()->indexOfProperty(propName.constData()); if (index == -1) return value; if (r->objectType == QV8ValueTypeResource::Reference) { QV8ValueTypeReferenceResource *reference = static_cast(r); if (!reference->object || !reference->object->metaObject()->property(reference->property).isWritable()) return value; r->type->read(reference->object, reference->property); QMetaProperty p = r->type->metaObject()->property(index); QDeclarativeBinding *newBinding = 0; if (value->IsFunction()) { QDeclarativeContextData *context = r->engine->callingContext(); v8::Handle function = v8::Handle::Cast(value); QDeclarativePropertyCache::Data cacheData; cacheData.setFlags(QDeclarativePropertyCache::Data::IsWritable); cacheData.propType = reference->object->metaObject()->property(reference->property).userType(); cacheData.coreIndex = reference->property; QDeclarativePropertyCache::ValueTypeData valueTypeData; valueTypeData.valueTypeCoreIdx = index; valueTypeData.valueTypePropType = p.userType(); v8::Local trace = v8::StackTrace::CurrentStackTrace(1, (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber | v8::StackTrace::kScriptName)); v8::Local frame = trace->GetFrame(0); int lineNumber = frame->GetLineNumber(); QString url = r->engine->toString(frame->GetScriptName()); newBinding = new QDeclarativeBinding(&function, reference->object, context); newBinding->setSourceLocation(url, lineNumber); newBinding->setTarget(QDeclarativePropertyPrivate::restore(cacheData, valueTypeData, reference->object, context)); newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject); } QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::setBinding(reference->object, reference->property, index, newBinding); if (oldBinding) oldBinding->destroy(); if (!value->IsFunction()) { QVariant v = r->engine->toVariant(value, -1); if (p.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double) v = v.toInt(); p.write(reference->type, v); reference->type->write(reference->object, reference->property, 0); } } else { Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy); QV8ValueTypeCopyResource *copy = static_cast(r); QVariant v = r->engine->toVariant(value, -1); r->type->setValue(copy->value); QMetaProperty p = r->type->metaObject()->property(index); p.write(r->type, v); copy->value = r->type->value(); } return value; } QT_END_NAMESPACE