diff options
author | Matthew Vogt <matthew.vogt@nokia.com> | 2012-02-16 14:43:03 +1000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-02-24 04:51:31 +0100 |
commit | b855240b782395f94315f43ea3e7e182299fac48 (patch) | |
tree | bc594c04449be8cd14cd0ab0bb72dafc2be0ffb2 /src/qml/qml/v8/qv8valuetypewrapper.cpp | |
parent | 6a42a6e0a9a1abdda0d07a5a20b4ac7e45348684 (diff) |
Rename QDeclarative symbols to QQuick and QQml
Symbols beginning with QDeclarative are already exported
by the quick1 module.
Users can apply the bin/rename-qtdeclarative-symbols.sh
script to modify client code using the previous names of the
renamed symbols.
Task-number: QTBUG-23737
Change-Id: Ifaa482663767634931e8711a8e9bf6e404859e66
Reviewed-by: Martin Jones <martin.jones@nokia.com>
Diffstat (limited to 'src/qml/qml/v8/qv8valuetypewrapper.cpp')
-rw-r--r-- | src/qml/qml/v8/qv8valuetypewrapper.cpp | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/src/qml/qml/v8/qv8valuetypewrapper.cpp b/src/qml/qml/v8/qv8valuetypewrapper.cpp new file mode 100644 index 0000000000..54d871d5f0 --- /dev/null +++ b/src/qml/qml/v8/qv8valuetypewrapper.cpp @@ -0,0 +1,387 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qv8valuetypewrapper_p.h" +#include "qv8engine_p.h" + +#include <private/qqmlvaluetype_p.h> +#include <private/qqmlbinding_p.h> + +QT_BEGIN_NAMESPACE + +class QV8ValueTypeResource : public QV8ObjectResource +{ + V8_RESOURCE_TYPE(ValueTypeType); + +public: + enum ObjectType { Reference, Copy }; + + QV8ValueTypeResource(QV8Engine *engine, ObjectType objectType); + + ObjectType objectType; + QQmlValueType *type; +}; + +class QV8ValueTypeReferenceResource : public QV8ValueTypeResource +{ +public: + QV8ValueTypeReferenceResource(QV8Engine *engine); + + QQmlGuard<QObject> 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_toString); + qPersistentDispose(m_constructor); + qPersistentDispose(m_toStringSymbol); +} + +static quint32 toStringHash = -1; + +void QV8ValueTypeWrapper::init(QV8Engine *engine) +{ + m_engine = engine; + m_toString = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ToString)->GetFunction()); + v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(); + ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter); + ft->InstanceTemplate()->SetHasExternalResource(true); + ft->InstanceTemplate()->MarkAsUseUserObjectComparison(); + ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0, + m_toString, v8::DEFAULT, + v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete)); + m_constructor = qPersistentNew<v8::Function>(ft->GetFunction()); + + m_toStringSymbol = qPersistentNew<v8::String>(v8::String::NewSymbol("toString")); + m_toStringString = QHashedV8String(m_toStringSymbol); + toStringHash = m_toStringString.hash(); +} + +v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(QObject *object, int property, QQmlValueType *type) +{ + // XXX NewInstance() should be optimized + v8::Local<v8::Object> 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<v8::Object> QV8ValueTypeWrapper::newValueType(const QVariant &value, QQmlValueType *type) +{ + // XXX NewInstance() should be optimized + v8::Local<v8::Object> 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<v8::Object> obj) +{ + QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(obj); + if (r) return toVariant(r); + else return QVariant(); +} + +QVariant QV8ValueTypeWrapper::toVariant(QV8ObjectResource *r) +{ + Q_ASSERT(r->resourceType() == QV8ObjectResource::ValueTypeType); + QV8ValueTypeResource *resource = static_cast<QV8ValueTypeResource *>(r); + + if (resource->objectType == QV8ValueTypeResource::Reference) { + QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(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<QV8ValueTypeCopyResource *>(resource); + + return copy->value; + } +} + +bool QV8ValueTypeWrapper::isEqual(QV8ObjectResource *r, const QVariant& value) +{ + Q_ASSERT(r->resourceType() == QV8ObjectResource::ValueTypeType); + QV8ValueTypeResource *resource = static_cast<QV8ValueTypeResource *>(r); + + if (resource->objectType == QV8ValueTypeResource::Reference) { + QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource); + if (reference->object) { + reference->type->read(reference->object, reference->property); + return reference->type->isEqual(value); + } else { + return false; + } + } else { + Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy); + QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource); + return (value == copy->value); + } +} + +v8::Handle<v8::Value> QV8ValueTypeWrapper::ToStringGetter(v8::Local<v8::String> property, + const v8::AccessorInfo &info) +{ + Q_UNUSED(property); + return info.Data(); +} + +v8::Handle<v8::Value> QV8ValueTypeWrapper::ToString(const v8::Arguments &args) +{ + QV8ValueTypeResource *resource = v8_resource_cast<QV8ValueTypeResource>(args.This()); + if (resource) { + if (resource->objectType == QV8ValueTypeResource::Reference) { + QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource); + if (reference->object) { + reference->type->read(reference->object, reference->property); + return resource->engine->toString(resource->type->toString()); + } else { + return v8::Undefined(); + } + } else { + Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy); + QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource); + QString result = copy->value.toString(); + if (result.isEmpty() && !copy->value.canConvert(QVariant::String)) { + result = QString::fromLatin1("QVariant(%0)").arg(QString::fromLatin1(copy->value.typeName())); + } + return resource->engine->toString(result); + } + } else { + return v8::Undefined(); + } +} + +v8::Handle<v8::Value> QV8ValueTypeWrapper::Getter(v8::Local<v8::String> property, + const v8::AccessorInfo &info) +{ + QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(info.This()); + if (!r) return v8::Handle<v8::Value>(); + + QHashedV8String propertystring(property); + + { + // Comparing the hash first actually makes a measurable difference here, at least on x86 + quint32 hash = propertystring.hash(); + if (hash == toStringHash && + r->engine->valueTypeWrapper()->m_toStringString == propertystring) { + return r->engine->valueTypeWrapper()->m_toString; + } + } + + QQmlPropertyData local; + QQmlPropertyData *result = 0; + { + QQmlData *ddata = QQmlData::get(r->type, false); + if (ddata && ddata->propertyCache) + result = ddata->propertyCache->property(propertystring); + else + result = QQmlPropertyCache::property(r->engine->engine(), r->type, + propertystring, local); + } + + if (!result) + return v8::Handle<v8::Value>(); + + if (r->objectType == QV8ValueTypeResource::Reference) { + QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r); + + if (!reference->object) + return v8::Handle<v8::Value>(); + + r->type->read(reference->object, reference->property); + } else { + Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy); + + QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r); + + r->type->setValue(copy->value); + } + +#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \ + if (result->propType == metatype) { \ + cpptype v; \ + void *args[] = { &v, 0 }; \ + r->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args); \ + return constructor(v); \ + } + + // These four types are the most common used by the value type wrappers + VALUE_TYPE_LOAD(QMetaType::QReal, qreal, v8::Number::New); + VALUE_TYPE_LOAD(QMetaType::Int, int, v8::Integer::New); + VALUE_TYPE_LOAD(QMetaType::QString, QString, r->engine->toString); + VALUE_TYPE_LOAD(QMetaType::Bool, bool, v8::Boolean::New); + + QVariant v(result->propType, (void *)0); + void *args[] = { v.data(), 0 }; + r->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args); + return r->engine->fromVariant(v); +#undef VALUE_TYPE_ACCESSOR +} + +v8::Handle<v8::Value> QV8ValueTypeWrapper::Setter(v8::Local<v8::String> property, + v8::Local<v8::Value> value, + const v8::AccessorInfo &info) +{ + QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(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<QV8ValueTypeReferenceResource *>(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); + + QQmlBinding *newBinding = 0; + + if (value->IsFunction()) { + QQmlContextData *context = r->engine->callingContext(); + v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value); + + QQmlPropertyData cacheData; + cacheData.setFlags(QQmlPropertyData::IsWritable | + QQmlPropertyData::IsValueTypeVirtual); + cacheData.propType = reference->object->metaObject()->property(reference->property).userType(); + cacheData.coreIndex = reference->property; + cacheData.valueTypeFlags = 0; + cacheData.valueTypeCoreIndex = index; + cacheData.valueTypePropType = p.userType(); + + v8::Local<v8::StackTrace> trace = + v8::StackTrace::CurrentStackTrace(1, + (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber | + v8::StackTrace::kScriptName)); + v8::Local<v8::StackFrame> frame = trace->GetFrame(0); + int lineNumber = frame->GetLineNumber(); + int columnNumber = frame->GetColumn(); + QString url = r->engine->toString(frame->GetScriptName()); + + newBinding = new QQmlBinding(&function, reference->object, context); + newBinding->setSourceLocation(url, lineNumber, columnNumber); + newBinding->setTarget(reference->object, cacheData, context); + newBinding->setEvaluateFlags(newBinding->evaluateFlags() | + QQmlBinding::RequiresThisObject); + } + + QQmlAbstractBinding *oldBinding = + QQmlPropertyPrivate::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<QV8ValueTypeCopyResource *>(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 |