aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp156
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h31
2 files changed, 100 insertions, 87 deletions
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 0cef04ab89..a86c249e40 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -272,9 +272,7 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
QQmlInterceptorMetaObject::QQmlInterceptorMetaObject(QObject *obj, const QQmlRefPointer<QQmlPropertyCache> &cache)
: object(obj),
- cache(cache),
- interceptors(nullptr),
- metaObject(nullptr)
+ cache(cache)
{
QObjectPrivate *op = QObjectPrivate::get(obj);
@@ -312,90 +310,86 @@ int QQmlInterceptorMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id,
return object->qt_metacall(c, id, a);
}
-bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a)
+bool QQmlInterceptorMetaObject::doIntercept(QMetaObject::Call c, int id, void **a)
{
- if ( ( (c == QMetaObject::WriteProperty &&
- !(*reinterpret_cast<int*>(a[3]) & QQmlPropertyData::BypassInterceptor)) || c == QMetaObject::BindableProperty )
- && interceptors ) {
-
- for (QQmlPropertyValueInterceptor *vi = interceptors; vi; vi = vi->m_next) {
- if (vi->m_propertyIndex.coreIndex() != id)
- continue;
-
- const int valueIndex = vi->m_propertyIndex.valueTypeIndex();
- const QQmlData *data = QQmlData::get(object);
- const QMetaType metaType = data->propertyCache->property(id)->propType();
-
- if (metaType.isValid()) {
- if (valueIndex != -1 && c == QMetaObject::WriteProperty) {
- // TODO: handle intercepting bindable properties for value types?
- QQmlGadgetPtrWrapper *valueType = QQmlGadgetPtrWrapper::instance(
- data->context->engine(), metaType);
- Q_ASSERT(valueType);
-
- //
- // Consider the following case:
- // color c = { 0.1, 0.2, 0.3 }
- // interceptor exists on c.r
- // write { 0.2, 0.4, 0.6 }
- //
- // The interceptor may choose not to update the r component at this
- // point (for example, a behavior that creates an animation). But we
- // need to ensure that the g and b components are updated correctly.
- //
- // So we need to perform a full write where the value type is:
- // r = old value, g = new value, b = new value
- //
- // And then call the interceptor which may or may not write the
- // new value to the r component.
- //
- // This will ensure that the other components don't contain stale data
- // and any relevant signals are emitted.
- //
- // To achieve this:
- // (1) Store the new value type as a whole (needed due to
- // aliasing between a[0] and static storage in value type).
- // (2) Read the entire existing value type from object -> valueType temp.
- // (3) Read the previous value of the component being changed
- // from the valueType temp.
- // (4) Write the entire new value type into the temp.
- // (5) Overwrite the component being changed with the old value.
- // (6) Perform a full write to the value type (which may emit signals etc).
- // (7) Issue the interceptor call with the new component value.
- //
-
- QMetaProperty valueProp = valueType->property(valueIndex);
- QVariant newValue(metaType, a[0]);
-
- valueType->read(object, id);
- QVariant prevComponentValue = valueProp.read(valueType);
-
- valueType->setValue(newValue);
- QVariant newComponentValue = valueProp.read(valueType);
-
- // Don't apply the interceptor if the intercepted value has not changed
- bool updated = false;
- if (newComponentValue != prevComponentValue) {
- valueProp.write(valueType, prevComponentValue);
- valueType->write(object, id, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
-
- vi->write(newComponentValue);
- updated = true;
- }
+ for (QQmlPropertyValueInterceptor *vi = interceptors; vi; vi = vi->m_next) {
+ if (vi->m_propertyIndex.coreIndex() != id)
+ continue;
+
+ const int valueIndex = vi->m_propertyIndex.valueTypeIndex();
+ const QQmlData *data = QQmlData::get(object);
+ const QMetaType metaType = data->propertyCache->property(id)->propType();
+
+ if (metaType.isValid()) {
+ if (valueIndex != -1 && c == QMetaObject::WriteProperty) {
+ // TODO: handle intercepting bindable properties for value types?
+ QQmlGadgetPtrWrapper *valueType = QQmlGadgetPtrWrapper::instance(
+ data->context->engine(), metaType);
+ Q_ASSERT(valueType);
+
+ //
+ // Consider the following case:
+ // color c = { 0.1, 0.2, 0.3 }
+ // interceptor exists on c.r
+ // write { 0.2, 0.4, 0.6 }
+ //
+ // The interceptor may choose not to update the r component at this
+ // point (for example, a behavior that creates an animation). But we
+ // need to ensure that the g and b components are updated correctly.
+ //
+ // So we need to perform a full write where the value type is:
+ // r = old value, g = new value, b = new value
+ //
+ // And then call the interceptor which may or may not write the
+ // new value to the r component.
+ //
+ // This will ensure that the other components don't contain stale data
+ // and any relevant signals are emitted.
+ //
+ // To achieve this:
+ // (1) Store the new value type as a whole (needed due to
+ // aliasing between a[0] and static storage in value type).
+ // (2) Read the entire existing value type from object -> valueType temp.
+ // (3) Read the previous value of the component being changed
+ // from the valueType temp.
+ // (4) Write the entire new value type into the temp.
+ // (5) Overwrite the component being changed with the old value.
+ // (6) Perform a full write to the value type (which may emit signals etc).
+ // (7) Issue the interceptor call with the new component value.
+ //
+
+ QMetaProperty valueProp = valueType->property(valueIndex);
+ QVariant newValue(metaType, a[0]);
+
+ valueType->read(object, id);
+ QVariant prevComponentValue = valueProp.read(valueType);
+
+ valueType->setValue(newValue);
+ QVariant newComponentValue = valueProp.read(valueType);
+
+ // Don't apply the interceptor if the intercepted value has not changed
+ bool updated = false;
+ if (newComponentValue != prevComponentValue) {
+ valueProp.write(valueType, prevComponentValue);
+ valueType->write(object, id, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
+
+ vi->write(newComponentValue);
+ updated = true;
+ }
- if (updated)
- return true;
- } else if (c == QMetaObject::WriteProperty) {
- vi->write(QVariant(metaType, a[0]));
+ if (updated)
return true;
- } else {
- object->qt_metacall(c, id, a);
- QUntypedBindable target = *reinterpret_cast<QUntypedBindable *>(a[0]);
- return vi->bindable(reinterpret_cast<QUntypedBindable *>(a[0]), target);
- }
+ } else if (c == QMetaObject::WriteProperty) {
+ vi->write(QVariant(metaType, a[0]));
+ return true;
+ } else {
+ object->qt_metacall(c, id, a);
+ QUntypedBindable target = *reinterpret_cast<QUntypedBindable *>(a[0]);
+ return vi->bindable(reinterpret_cast<QUntypedBindable *>(a[0]), target);
}
}
}
+
return false;
}
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index 0a5b8c6785..19aba84258 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -115,17 +115,36 @@ public:
return false;
}
+ QObject *object = nullptr;
+ QQmlRefPointer<QQmlPropertyCache> cache;
+
protected:
int metaCall(QObject *o, QMetaObject::Call c, int id, void **a) override;
- bool intercept(QMetaObject::Call c, int id, void **a);
+ bool intercept(QMetaObject::Call c, int id, void **a)
+ {
+ if (!interceptors)
+ return false;
+
+ switch (c) {
+ case QMetaObject::WriteProperty:
+ if (*reinterpret_cast<int*>(a[3]) & QQmlPropertyData::BypassInterceptor)
+ return false;
+ break;
+ case QMetaObject::BindableProperty:
+ break;
+ default:
+ return false;
+ }
+
+ return doIntercept(c, id, a);
+ }
-public:
- QObject *object;
- QQmlRefPointer<QQmlPropertyCache> cache;
QBiPointer<QDynamicMetaObjectData, const QMetaObject> parent;
+ const QMetaObject *metaObject = nullptr;
- QQmlPropertyValueInterceptor *interceptors;
- const QMetaObject *metaObject;
+private:
+ bool doIntercept(QMetaObject::Call c, int id, void **a);
+ QQmlPropertyValueInterceptor *interceptors = nullptr;
};
inline QQmlInterceptorMetaObject *QQmlInterceptorMetaObject::get(QObject *obj)