void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *)
{
if (m_target && m_index >= 0)
- m_target->activate(m_target->object, m_target->methodOffset + m_index, 0);
+ m_target->activate(m_target->object, m_target->methodOffset() + m_index, 0);
}
void QQmlVMEVariantQObjectPtr::setGuardedValue(QObject *obj, QQmlVMEMetaObject *target, int index)
inline const QTime &asQTime();
inline const QDate &asQDate();
inline const QDateTime &asQDateTime();
+ inline const QRectF &asQRectF();
inline const QJSValue &asQJSValue();
inline void setValue(QObject *v, QQmlVMEMetaObject *target, int index);
inline void setValue(const QTime &);
inline void setValue(const QDate &);
inline void setValue(const QDateTime &);
+ inline void setValue(const QRectF &);
inline void setValue(const QJSValue &);
inline void setDataType(int t);
+ inline void ensureValueType(int);
+
private:
int type;
- void *data[6]; // Large enough to hold all types
+ void *data[8]; // Large enough to hold all types
inline void cleanup();
};
{
public:
QQmlVMEMetaObjectEndpoint();
- static void vmecallback(QQmlNotifierEndpoint *);
+ static void vmecallback(QQmlNotifierEndpoint *, void **);
void tryConnect();
QFlagPointer<QQmlVMEMetaObject> metaObject;
} else if (type == QMetaType::QDateTime) {
((QDateTime *)dataPtr())->~QDateTime();
type = QVariant::Invalid;
+ } else if (type == QMetaType::QRectF) {
+ ((QRectF *)dataPtr())->~QRectF();
+ type = QVariant::Invalid;
} else if (type == qMetaTypeId<QVariant>()) {
((QVariant *)dataPtr())->~QVariant();
type = QVariant::Invalid;
return *(QDateTime *)(dataPtr());
}
+const QRectF &QQmlVMEVariant::asQRectF()
+{
+ if (type != QMetaType::QRectF)
+ setValue(QRectF());
+
+ return *(QRectF *)(dataPtr());
+}
+
const QJSValue &QQmlVMEVariant::asQJSValue()
{
if (type != qMetaTypeId<QJSValue>())
}
}
+void QQmlVMEVariant::setValue(const QRectF &v)
+{
+ if (type != QMetaType::QRectF) {
+ cleanup();
+ type = QMetaType::QRectF;
+ new (dataPtr()) QRectF(v);
+ } else {
+ *(QRectF *)(dataPtr()) = v;
+ }
+}
+
void QQmlVMEVariant::setValue(const QJSValue &v)
{
if (type != qMetaTypeId<QJSValue>()) {
type = t;
}
+void QQmlVMEVariant::ensureValueType(int t)
+{
+ if (type != t) {
+ cleanup();
+ type = t;
+ QQml_valueTypeProvider()->initValueType(t, dataPtr(), dataSize());
+ }
+}
+
QQmlVMEMetaObjectEndpoint::QQmlVMEMetaObjectEndpoint()
{
- callback = &vmecallback;
+ setCallback(QQmlNotifierEndpoint::QQmlVMEMetaObjectEndpoint);
}
-void QQmlVMEMetaObjectEndpoint::vmecallback(QQmlNotifierEndpoint *e)
+void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *e, void **)
{
QQmlVMEMetaObjectEndpoint *vmee = static_cast<QQmlVMEMetaObjectEndpoint*>(e);
vmee->tryConnect();
if (metaObject.flag()) {
// This is actually notify
- int sigIdx = metaObject->methodOffset + aliasId + metaObject->metaData->propertyCount;
- QMetaObject::activate(metaObject->object, sigIdx, 0);
+ int sigIdx = metaObject->methodOffset() + aliasId + metaObject->metaData->propertyCount;
+ metaObject->activate(metaObject->object, sigIdx, 0);
} else {
QQmlVMEMetaData::AliasData *d = metaObject->metaData->aliasData() + aliasId;
if (!d->isObjectAlias()) {
if (!target)
return;
- QMetaProperty prop = target->metaObject()->property(d->propertyIndex());
- if (prop.hasNotifySignal())
- connect(target, prop.notifySignalIndex());
+ if (d->notifySignal != -1)
+ connect(target, d->notifySignal, ctxt->engine);
}
metaObject.setFlag();
}
}
-QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
- const QMetaObject *other,
- const QQmlVMEMetaData *meta,
- QQmlCompiledData *cdata)
-: QV8GCCallback::Node(GcPrologueCallback), object(obj), compiledData(cdata),
- ctxt(QQmlData::get(obj, true)->outerContext), metaData(meta), data(0),
- aliasEndpoints(0), firstVarPropertyIndex(-1), varPropertiesInitialized(false),
- v8methods(0), parent(0)
+QAbstractDynamicMetaObject *QQmlVMEMetaObject::toDynamicMetaObject(QObject *o)
{
- compiledData->addref();
+ if (!hasAssignedMetaObjectData) {
+ *static_cast<QMetaObject *>(this) = *cache->createMetaObject();
+
+ if (parent.isT1())
+ this->d.superdata = parent.asT1()->toDynamicMetaObject(o);
+ else
+ this->d.superdata = parent.asT2();
+
+ hasAssignedMetaObjectData = true;
+ }
- *static_cast<QMetaObject *>(this) = *other;
- this->d.superdata = obj->metaObject();
+ return this;
+}
+QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
+ QQmlPropertyCache *cache,
+ const QQmlVMEMetaData *meta)
+: QV8GCCallback::Node(GcPrologueCallback), object(obj),
+ ctxt(QQmlData::get(obj, true)->outerContext), cache(cache), metaData(meta),
+ hasAssignedMetaObjectData(false), data(0), aliasEndpoints(0), firstVarPropertyIndex(-1),
+ varPropertiesInitialized(false), interceptors(0), v8methods(0)
+{
QObjectPrivate *op = QObjectPrivate::get(obj);
- if (op->metaObject)
- parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject);
- op->metaObject = this;
- propOffset = QAbstractDynamicMetaObject::propertyOffset();
- methodOffset = QAbstractDynamicMetaObject::methodOffset();
+ if (op->metaObject) parent = op->metaObject;
+ else parent = obj->metaObject();
+
+ op->metaObject = this;
+ QQmlData::get(obj)->hasVMEMetaObject = true;
data = new QQmlVMEVariant[metaData->propertyCount - metaData->varPropertyCount];
aConnected.resize(metaData->aliasCount);
int list_type = qMetaTypeId<QQmlListProperty<QObject> >();
+ int qobject_type = qMetaTypeId<QObject*>();
+ int variant_type = qMetaTypeId<QVariant>();
+ bool needsGcCallback = (metaData->varPropertyCount > 0);
// ### Optimize
for (int ii = 0; ii < metaData->propertyCount - metaData->varPropertyCount; ++ii) {
int t = (metaData->propertyData() + ii)->propertyType;
if (t == list_type) {
- listProperties.append(List(methodOffset + ii));
+ listProperties.append(List(methodOffset() + ii, this));
data[ii].setValue(listProperties.count() - 1);
- }
+ } else if (!needsGcCallback && (t == qobject_type || t == variant_type)) {
+ needsGcCallback = true;
+ }
}
firstVarPropertyIndex = metaData->propertyCount - metaData->varPropertyCount;
- if (metaData->varPropertyCount)
+
+ // both var properties and variant properties can keep references to
+ // other QObjects, and var properties can also keep references to
+ // JavaScript objects. If we have any properties, we need to hook
+ // the gc() to ensure that references keep objects alive as needed.
+ if (needsGcCallback) {
QV8GCCallback::addGcCallbackNode(this);
+ }
}
QQmlVMEMetaObject::~QQmlVMEMetaObject()
{
- compiledData->release();
- delete parent;
+ if (parent.isT1()) parent.asT1()->objectDestroyed(object);
delete [] data;
delete [] aliasEndpoints;
int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
{
int id = _id;
- if(c == QMetaObject::WriteProperty) {
- int flags = *reinterpret_cast<int*>(a[3]);
- if (!(flags & QQmlPropertyPrivate::BypassInterceptor)
- && !aInterceptors.isEmpty()
- && aInterceptors.testBit(id)) {
- QPair<int, QQmlPropertyValueInterceptor*> pair = interceptors.value(id);
- int valueIndex = pair.first;
- QQmlPropertyValueInterceptor *vi = pair.second;
- int type = property(id).userType();
+ if (c == QMetaObject::WriteProperty && interceptors &&
+ !(*reinterpret_cast<int*>(a[3]) & QQmlPropertyPrivate::BypassInterceptor)) {
+
+ for (QQmlPropertyValueInterceptor *vi = interceptors; vi; vi = vi->m_next) {
+ if (vi->m_coreIndex != id)
+ continue;
+
+ int valueIndex = vi->m_valueTypeCoreIndex;
+ int type = QQmlData::get(object)->propertyCache->property(id)->propType;
if (type != QVariant::Invalid) {
if (valueIndex != -1) {
}
}
if (c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty) {
- if (id >= propOffset) {
- id -= propOffset;
+ if (id >= propOffset()) {
+ id -= propOffset();
if (id < metaData->propertyCount) {
int t = (metaData->propertyData() + id)->propertyType;
case QVariant::DateTime:
*reinterpret_cast<QDateTime *>(a[0]) = data[id].asQDateTime();
break;
+ case QVariant::RectF:
+ *reinterpret_cast<QRectF *>(a[0]) = data[id].asQRectF();
+ break;
case QMetaType::QObjectStar:
*reinterpret_cast<QObject **>(a[0]) = data[id].asQObject();
break;
needActivate = *reinterpret_cast<QDateTime *>(a[0]) != data[id].asQDateTime();
data[id].setValue(*reinterpret_cast<QDateTime *>(a[0]));
break;
+ case QVariant::RectF:
+ needActivate = *reinterpret_cast<QRectF *>(a[0]) != data[id].asQRectF();
+ data[id].setValue(*reinterpret_cast<QRectF *>(a[0]));
+ break;
case QMetaType::QObjectStar:
needActivate = *reinterpret_cast<QObject **>(a[0]) != data[id].asQObject();
data[id].setValue(*reinterpret_cast<QObject **>(a[0]), this, id);
writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
break;
default:
- needActivate = QQml_valueTypeProvider()->writeValueType(t, a[0], data[id].dataPtr(), data[id].dataSize());
- if (needActivate) {
- data[id].setDataType(t);
- }
+ data[id].ensureValueType(t);
+ needActivate = !QQml_valueTypeProvider()->equalValueType(t, a[0], data[id].dataPtr());
+ QQml_valueTypeProvider()->writeValueType(t, a[0], data[id].dataPtr(), data[id].dataSize());
break;
}
}
}
if (c == QMetaObject::WriteProperty && needActivate) {
- activate(object, methodOffset + id, 0);
+ activate(object, methodOffset() + id, 0);
}
return -1;
} else if(c == QMetaObject::InvokeMetaMethod) {
- if (id >= methodOffset) {
+ if (id >= methodOffset()) {
- id -= methodOffset;
+ id -= methodOffset();
int plainSignals = metaData->signalCount + metaData->propertyCount +
metaData->aliasCount;
if (id < plainSignals) {
- QMetaObject::activate(object, _id, a);
+ activate(object, _id, a);
return -1;
}
}
}
- if (parent)
- return parent->metaCall(c, _id, a);
+ if (parent.isT1())
+ return parent.asT1()->metaCall(object, c, _id, a);
else
return object->qt_metacall(c, _id, a);
}
v8::Handle<v8::Function> QQmlVMEMetaObject::method(int index)
{
+ if (!ctxt || !ctxt->isValid()) {
+ qWarning("QQmlVMEMetaObject: Internal error - attempted to evaluate a function in an invalid context");
+ return v8::Handle<v8::Function>();
+ }
+
if (!v8methods)
v8methods = new v8::Persistent<v8::Function>[metaData->methodCount];
// Write the value and emit change signal as appropriate.
varProperties->Set(id - firstVarPropertyIndex, value);
- activate(object, methodOffset + id, 0);
+ activate(object, methodOffset() + id, 0);
}
void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
QVariant currentValue = readPropertyAsVariant(id);
varProperties->Set(id - firstVarPropertyIndex, newv);
if ((currentValue.userType() != value.userType() || currentValue != value))
- activate(object, methodOffset + id, 0);
+ activate(object, methodOffset() + id, 0);
} else {
bool needActivate = false;
if (value.userType() == QMetaType::QObjectStar) {
- QObject *o = qvariant_cast<QObject *>(value);
+ QObject *o = *(QObject **)value.data();
needActivate = (data[id].dataType() != QMetaType::QObjectStar || data[id].asQObject() != o);
- data[id].setValue(qvariant_cast<QObject *>(value), this, id);
+ data[id].setValue(o, this, id);
} else {
needActivate = (data[id].dataType() != qMetaTypeId<QVariant>() ||
data[id].asQVariant().userType() != value.userType() ||
}
if (needActivate)
- activate(object, methodOffset + id, 0);
+ activate(object, methodOffset() + id, 0);
}
}
void QQmlVMEMetaObject::listChanged(int id)
{
- activate(object, methodOffset + id, 0);
+ activate(object, methodOffset() + id, 0);
}
void QQmlVMEMetaObject::list_append(QQmlListProperty<QObject> *prop, QObject *o)
{
List *list = static_cast<List *>(prop->data);
list->append(o);
- QMetaObject::activate(prop->object, list->notifyIndex, 0);
+ list->mo->activate(prop->object, list->notifyIndex, 0);
}
int QQmlVMEMetaObject::list_count(QQmlListProperty<QObject> *prop)
{
List *list = static_cast<List *>(prop->data);
list->clear();
- QMetaObject::activate(prop->object, list->notifyIndex, 0);
+ list->mo->activate(prop->object, list->notifyIndex, 0);
}
void QQmlVMEMetaObject::registerInterceptor(int index, int valueIndex, QQmlPropertyValueInterceptor *interceptor)
{
- if (aInterceptors.isEmpty())
- aInterceptors.resize(propertyCount() + metaData->propertyCount);
- aInterceptors.setBit(index);
- interceptors.insert(index, qMakePair(valueIndex, interceptor));
+ interceptor->m_coreIndex = index;
+ interceptor->m_valueTypeCoreIndex = valueIndex;
+ interceptor->m_next = interceptors;
+ interceptors = interceptor;
}
int QQmlVMEMetaObject::vmeMethodLineNumber(int index)
{
- if (index < methodOffset) {
- Q_ASSERT(parent);
- return static_cast<QQmlVMEMetaObject *>(parent)->vmeMethodLineNumber(index);
+ if (index < methodOffset()) {
+ Q_ASSERT(parent.isT1());
+ return static_cast<QQmlVMEMetaObject *>(parent.asT1())->vmeMethodLineNumber(index);
}
int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
- Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
+ Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount));
- int rawIndex = index - methodOffset - plainSignals;
+ int rawIndex = index - methodOffset() - plainSignals;
QQmlVMEMetaData::MethodData *data = metaData->methodData() + rawIndex;
return data->lineNumber;
v8::Handle<v8::Function> QQmlVMEMetaObject::vmeMethod(int index)
{
- if (index < methodOffset) {
- Q_ASSERT(parent);
- return static_cast<QQmlVMEMetaObject *>(parent)->vmeMethod(index);
+ if (index < methodOffset()) {
+ Q_ASSERT(parent.isT1());
+ return static_cast<QQmlVMEMetaObject *>(parent.asT1())->vmeMethod(index);
}
int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
- Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
- return method(index - methodOffset - plainSignals);
+ Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount));
+ return method(index - methodOffset() - plainSignals);
}
// Used by debugger
void QQmlVMEMetaObject::setVmeMethod(int index, v8::Persistent<v8::Function> value)
{
- if (index < methodOffset) {
- Q_ASSERT(parent);
- return static_cast<QQmlVMEMetaObject *>(parent)->setVmeMethod(index, value);
+ if (index < methodOffset()) {
+ Q_ASSERT(parent.isT1());
+ return static_cast<QQmlVMEMetaObject *>(parent.asT1())->setVmeMethod(index, value);
}
int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
- Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
+ Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount));
if (!v8methods)
v8methods = new v8::Persistent<v8::Function>[metaData->methodCount];
- int methodIndex = index - methodOffset - plainSignals;
+ int methodIndex = index - methodOffset() - plainSignals;
if (!v8methods[methodIndex].IsEmpty())
qPersistentDispose(v8methods[methodIndex]);
v8methods[methodIndex] = value;
v8::Handle<v8::Value> QQmlVMEMetaObject::vmeProperty(int index)
{
- if (index < propOffset) {
- Q_ASSERT(parent);
- return static_cast<QQmlVMEMetaObject *>(parent)->vmeProperty(index);
+ if (index < propOffset()) {
+ Q_ASSERT(parent.isT1());
+ return static_cast<QQmlVMEMetaObject *>(parent.asT1())->vmeProperty(index);
}
- return readVarProperty(index - propOffset);
+ return readVarProperty(index - propOffset());
}
void QQmlVMEMetaObject::setVMEProperty(int index, v8::Handle<v8::Value> v)
{
- if (index < propOffset) {
- Q_ASSERT(parent);
- static_cast<QQmlVMEMetaObject *>(parent)->setVMEProperty(index, v);
+ if (index < propOffset()) {
+ Q_ASSERT(parent.isT1());
+ static_cast<QQmlVMEMetaObject *>(parent.asT1())->setVMEProperty(index, v);
return;
}
- return writeVarProperty(index - propOffset, v);
+ return writeVarProperty(index - propOffset(), v);
}
bool QQmlVMEMetaObject::ensureVarPropertiesAllocated()
{
QQmlVMEMetaObject *vmemo = static_cast<QQmlVMEMetaObject*>(node);
Q_ASSERT(vmemo);
- if (!vmemo->varPropertiesInitialized || vmemo->varProperties.IsEmpty() || !vmemo->ctxt || !vmemo->ctxt->engine)
+
+ if (!vmemo->ctxt || !vmemo->ctxt->engine)
return;
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(vmemo->ctxt->engine);
+
+ // add references created by VMEVariant properties
+ int maxDataIdx = vmemo->metaData->propertyCount - vmemo->metaData->varPropertyCount;
+ for (int ii = 0; ii < maxDataIdx; ++ii) { // XXX TODO: optimise?
+ if (vmemo->data[ii].dataType() == QMetaType::QObjectStar) {
+ // possible QObject reference.
+ QObject *ref = vmemo->data[ii].asQObject();
+ if (ref) {
+ ep->v8engine()->addRelationshipForGC(vmemo->object, ref);
+ }
+ }
+ }
+
+ // add references created by var properties
+ if (!vmemo->varPropertiesInitialized || vmemo->varProperties.IsEmpty())
+ return;
ep->v8engine()->addRelationshipForGC(vmemo->object, vmemo->varProperties);
}
bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const
{
- Q_ASSERT(index >= propOffset + metaData->propertyCount);
+ Q_ASSERT(index >= propOffset() + metaData->propertyCount);
*target = 0;
*coreIndex = -1;
if (!ctxt)
return false;
- QQmlVMEMetaData::AliasData *d = metaData->aliasData() + (index - propOffset - metaData->propertyCount);
+ QQmlVMEMetaData::AliasData *d = metaData->aliasData() + (index - propOffset() - metaData->propertyCount);
QQmlContext *context = ctxt->asQQmlContext();
QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context);
void QQmlVMEMetaObject::connectAliasSignal(int index)
{
- int aliasId = (index - methodOffset) - metaData->propertyCount;
+ int aliasId = (index - methodOffset()) - metaData->propertyCount;
if (aliasId < 0 || aliasId >= metaData->aliasCount)
return;
connectAlias(aliasId);
}
+void QQmlVMEMetaObject::activate(QObject *object, int index, void **args)
+{
+ int signalOffset = cache->signalOffset();
+ int methodOffset = cache->methodOffset();
+
+ QMetaObject::activate(object, methodOffset, signalOffset, index - methodOffset, args);
+}
+
+QQmlVMEMetaObject *QQmlVMEMetaObject::getForProperty(QObject *o, int coreIndex)
+{
+ QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
+ while (vme->propOffset() > coreIndex) {
+ Q_ASSERT(vme->parent.isT1());
+ vme = static_cast<QQmlVMEMetaObject *>(vme->parent.asT1());
+ }
+ return vme;
+}
+
+QQmlVMEMetaObject *QQmlVMEMetaObject::getForMethod(QObject *o, int coreIndex)
+{
+ QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
+ while (vme->methodOffset() > coreIndex) {
+ Q_ASSERT(vme->parent.isT1());
+ vme = static_cast<QQmlVMEMetaObject *>(vme->parent.asT1());
+ }
+ return vme;
+}
+
QT_END_NAMESPACE