aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlvmemetaobject.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-01-05 12:37:33 +0100
committerUlf Hermann <ulf.hermann@qt.io>2022-01-18 12:51:37 +0100
commit7b00dd860728fa078dac78359811b7c718d5e20f (patch)
treec3e72e8e288719e8c3ee62430202fb054e7e696f /src/qml/qml/qqmlvmemetaobject.cpp
parentcee66a1514156b0a8d656b8183638088fa152cc5 (diff)
Inline the pre-checks for QQmlInterceptorMetaObject::intercept
In most cases we won't intercept. Calling a function just to figure out that there are no interceptors or that the call type doesn't match is expensive. Also, better encapsulate the class and initialize members inline where possible. Pick-to: 6.3 Change-Id: Id545c98bc52690c75014b1283edb72a241750960 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/qml/qqmlvmemetaobject.cpp')
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp156
1 files changed, 75 insertions, 81 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;
}