4#ifndef QQMLPROPERTYBINDING_P_H
5#define QQMLPROPERTYBINDING_P_H
18#include <private/qqmljavascriptexpression_p.h>
19#include <private/qqmlpropertydata_p.h>
20#include <private/qv4alloca_p.h>
21#include <private/qqmltranslation_p.h>
23#include <QtCore/qproperty.h>
33class QQmlPropertyBinding;
34class QQmlScriptString;
38 bool mustCaptureBindableProperty()
const final {
return false;}
40 friend class QQmlPropertyBinding;
41 void expressionChanged() override;
42 QQmlPropertyBinding *asBinding()
44 return const_cast<QQmlPropertyBinding *>(
static_cast<
const QQmlPropertyBindingJS *>(
this)->asBinding());
47 inline QQmlPropertyBinding
const *asBinding()
const;
53 QV4::ReturnedValue evaluate(
bool *isUndefined);
54 QV4::PersistentValue m_boundFunction;
60 friend class QQmlPropertyBindingJS;
62 static constexpr std::size_t jsExpressionOffsetLength() {
63 struct composite { QQmlPropertyBinding b; QQmlPropertyBindingJS js; };
64 QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF
65 return sizeof (QQmlPropertyBinding) - offsetof(composite, js);
71 QQmlPropertyBindingJS *jsExpression()
73 return const_cast<QQmlPropertyBindingJS *>(
static_cast<
const QQmlPropertyBinding *>(
this)->jsExpression());
76 QQmlPropertyBindingJS
const *jsExpression()
const
78 return std::launder(
reinterpret_cast<QQmlPropertyBindingJS
const *>(
79 reinterpret_cast<std::byte
const*>(
this)
80 + QPropertyBindingPrivate::getSizeEnsuringAlignment()
81 + jsExpressionOffsetLength()));
84 static QUntypedPropertyBinding create(
const QQmlPropertyData *pd, QV4::Function *function,
85 QObject *obj,
const QQmlRefPointer<QQmlContextData> &ctxt,
86 QV4::ExecutionContext *scope, QObject *target,
87 QQmlPropertyIndex targetIndex);
88 static QUntypedPropertyBinding create(QMetaType propertyType, QV4::Function *function,
89 QObject *obj,
const QQmlRefPointer<QQmlContextData> &ctxt,
90 QV4::ExecutionContext *scope, QObject *target,
91 QQmlPropertyIndex targetIndex);
92 static QUntypedPropertyBinding createFromCodeString(
const QQmlPropertyData *property,
93 const QString &str, QObject *obj,
94 const QQmlRefPointer<QQmlContextData> &ctxt,
95 const QString &url, quint16 lineNumber,
96 QObject *target, QQmlPropertyIndex targetIndex);
97 static QUntypedPropertyBinding createFromScriptString(
const QQmlPropertyData *property,
98 const QQmlScriptString& script, QObject *obj,
99 QQmlContext *ctxt, QObject *target,
100 QQmlPropertyIndex targetIndex);
102 static QUntypedPropertyBinding createFromBoundFunction(
const QQmlPropertyData *pd, QV4::BoundFunction *function,
103 QObject *obj,
const QQmlRefPointer<QQmlContextData> &ctxt,
104 QV4::ExecutionContext *scope, QObject *target,
105 QQmlPropertyIndex targetIndex);
107 static bool isUndefined(
const QUntypedPropertyBinding &binding)
109 return isUndefined(QPropertyBindingPrivate::get(binding));
112 static bool isUndefined(
const QPropertyBindingPrivate *binding)
114 if (!(binding && binding->hasCustomVTable()))
116 return static_cast<
const QQmlPropertyBinding *>(binding)->isUndefined();
119 template<QMetaType::Type type>
120 static bool doEvaluate(QMetaType metaType, QUntypedPropertyData *dataPtr,
void *f) {
121 auto address =
static_cast<std::byte*>(f);
122 address -= QPropertyBindingPrivate::getSizeEnsuringAlignment();
124 return reinterpret_cast<QQmlPropertyBinding *>(address)->evaluate<type>(metaType, dataPtr);
127 bool hasDependencies()
129 return (dependencyObserverCount > 0) || !jsExpression()->activeGuards.isEmpty();
133 template <QMetaType::Type type>
134 bool evaluate(QMetaType metaType,
void *dataPtr);
136 Q_NEVER_INLINE
void handleUndefinedAssignment(QQmlEnginePrivate *ep,
void *dataPtr);
138 QString createBindingLoopErrorDescription();
141 enum BoundFunction :
bool {
142 WithoutBoundFunction =
false,
143 HasBoundFunction =
true,
145 TargetData(QObject *target, QQmlPropertyIndex index, BoundFunction state)
146 : target(target), targetIndex(index), hasBoundFunction(state)
149 QQmlPropertyIndex targetIndex;
150 bool hasBoundFunction;
151 bool isUndefined =
false;
153 QQmlPropertyBinding(QMetaType metaType, QObject *target, QQmlPropertyIndex targetIndex, TargetData::BoundFunction hasBoundFunction);
157 return std::launder(
reinterpret_cast<TargetData *>(&declarativeExtraData))->target;
160 QQmlPropertyIndex targetIndex()
162 return std::launder(
reinterpret_cast<TargetData *>(&declarativeExtraData))->targetIndex;
165 bool hasBoundFunction()
167 return std::launder(
reinterpret_cast<TargetData *>(&declarativeExtraData))->hasBoundFunction;
170 bool isUndefined()
const
172 return std::launder(
reinterpret_cast<TargetData
const *>(&declarativeExtraData))->isUndefined;
175 void setIsUndefined(
bool isUndefined)
177 std::launder(
reinterpret_cast<TargetData *>(&declarativeExtraData))->isUndefined = isUndefined;
180 static void bindingErrorCallback(QPropertyBindingPrivate *);
197 [](
void *,
void *){},
204#define FOR_TYPE(TYPE)
205 case TYPE: return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<TYPE>
213 if (type.flags() & QMetaType::PointerToQObject)
214 return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<QMetaType::QObjectStar>;
215 return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<QMetaType::UnknownType>;
226 static QUntypedPropertyBinding Q_QML_EXPORT
232inline const QQmlPropertyBinding *QQmlPropertyBindingJS::asBinding()
const
234 return std::launder(
reinterpret_cast<QQmlPropertyBinding
const *>(
235 reinterpret_cast<std::byte
const*>(
this)
236 - QPropertyBindingPrivate::getSizeEnsuringAlignment()
237 - QQmlPropertyBinding::jsExpressionOffsetLength()));
240static_assert(
sizeof(QQmlPropertyBinding) ==
sizeof(QPropertyBindingPrivate));
244 if (*
static_cast<
const T *>(result) == *
static_cast<
const T *>(dataPtr))
246 *
static_cast<T *>(dataPtr) = *
static_cast<
const T *>(result);
250template <QMetaType::Type type>
251bool QQmlPropertyBinding::evaluate(QMetaType metaType,
void *dataPtr)
253 const auto ctxt = jsExpression()->context();
254 QQmlEngine *engine = ctxt ? ctxt->engine() :
nullptr;
256 QPropertyBindingError error(QPropertyBindingError::EvaluationError);
257 if (
auto currentBinding = QPropertyBindingPrivate::currentlyEvaluatingBinding())
258 currentBinding->setError(std::move(error));
261 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
262 ep->referenceScarceResources();
264 const auto handleErrorAndUndefined = [&](
bool evaluatedToUndefined) {
265 ep->dereferenceScarceResources();
266 if (jsExpression()->hasError()) {
267 QPropertyBindingError error(QPropertyBindingError::UnknownError,
268 jsExpression()->delayedError()->error().description());
269 QPropertyBindingPrivate::currentlyEvaluatingBinding()->setError(std::move(error));
270 bindingErrorCallback(
this);
274 if (evaluatedToUndefined) {
275 handleUndefinedAssignment(ep, dataPtr);
279 }
else if (isUndefined()) {
280 setIsUndefined(
false);
286 if (!hasBoundFunction()) {
287 Q_ASSERT(metaType.sizeOf() > 0);
289 using Tuple = std::tuple<qsizetype,
bool,
bool>;
290 const auto [size, needsConstruction, needsDestruction] = [&]() -> Tuple {
292 case QMetaType::QObjectStar:
return Tuple(
sizeof(QObject *),
false,
false);
293 case QMetaType::Bool:
return Tuple(
sizeof(
bool),
false,
false);
294 case QMetaType::Int:
return Tuple(
sizeof(
int),
false,
false);
295 case QMetaType::Double:
return Tuple(
sizeof(
double),
false,
false);
296 case QMetaType::Float:
return Tuple(
sizeof(
float),
false,
false);
297 case QMetaType::QString:
return Tuple(
sizeof(QString),
true,
true);
299 const auto flags = metaType.flags();
302 flags & QMetaType::NeedsConstruction,
303 flags & QMetaType::NeedsDestruction);
307 Q_ALLOCA_VAR(
void, result, size);
308 if (needsConstruction)
309 metaType.construct(result);
311 const bool evaluatedToUndefined = !jsExpression()->evaluate(&result, &metaType, 0);
312 if (!handleErrorAndUndefined(evaluatedToUndefined))
316 case QMetaType::QObjectStar:
317 return compareAndAssign<QObject *>(dataPtr, result);
318 case QMetaType::Bool:
319 return compareAndAssign<
bool>(dataPtr, result);
321 return compareAndAssign<
int>(dataPtr, result);
322 case QMetaType::Double:
323 return compareAndAssign<
double>(dataPtr, result);
324 case QMetaType::Float:
325 return compareAndAssign<
float>(dataPtr, result);
326 case QMetaType::QString: {
327 const bool hasChanged = compareAndAssign<QString>(dataPtr, result);
328 static_cast<QString *>(result)->~QString();
335 const bool hasChanged = !metaType.equals(result, dataPtr);
337 if (needsDestruction)
338 metaType.destruct(dataPtr);
339 metaType.construct(dataPtr, result);
341 if (needsDestruction)
342 metaType.destruct(result);
346 bool evaluatedToUndefined =
false;
347 QV4::Scope scope(engine->handle());
348 QV4::ScopedValue result(scope,
static_cast<QQmlPropertyBindingJSForBoundFunction *>(
349 jsExpression())->evaluate(&evaluatedToUndefined));
351 if (!handleErrorAndUndefined(evaluatedToUndefined))
355 case QMetaType::Bool: {
357 if (result->isBoolean())
358 b = result->booleanValue();
360 b = result->toBoolean();
361 if (b == *
static_cast<
bool *>(dataPtr))
363 *
static_cast<
bool *>(dataPtr) = b;
366 case QMetaType::Int: {
368 if (result->isInteger())
369 i = result->integerValue();
370 else if (result->isNumber()) {
371 i = QV4::StaticValue::toInteger(result->doubleValue());
375 if (i == *
static_cast<
int *>(dataPtr))
377 *
static_cast<
int *>(dataPtr) = i;
380 case QMetaType::Double:
381 if (result->isNumber()) {
382 double d = result->asDouble();
383 if (d == *
static_cast<
double *>(dataPtr))
385 *
static_cast<
double *>(dataPtr) = d;
389 case QMetaType::Float:
390 if (result->isNumber()) {
391 float d =
float(result->asDouble());
392 if (d == *
static_cast<
float *>(dataPtr))
394 *
static_cast<
float *>(dataPtr) = d;
398 case QMetaType::QString:
399 if (result->isString()) {
400 QString s = result->toQStringNoThrow();
401 if (s == *
static_cast<QString *>(dataPtr))
403 *
static_cast<QString *>(dataPtr) = s;
411 QVariant resultVariant(QV4::ExecutionEngine::toVariant(result, metaType));
412 resultVariant.convert(metaType);
413 const bool hasChanged = !metaType.equals(resultVariant.constData(), dataPtr);
414 metaType.destruct(dataPtr);
415 metaType.construct(dataPtr, resultVariant.constData());
Combined button and popup list for selecting options.
constexpr BindingFunctionVTable bindingFunctionVTableForQQmlPropertyBinding
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")
static QtPrivate::QPropertyBindingData * bindingDataFromPropertyData(QUntypedPropertyData *dataPtr, QMetaType type)
auto qQmlTranslationPropertyBindingCreateBinding(const QQmlRefPointer< QV4::ExecutableCompilationUnit > &compilationUnit, TranslateWithUnit &&translateWithUnit)
const QtPrivate::BindingFunctionVTable * bindingFunctionVTableForQQmlPropertyBinding(QMetaType type)
bool compareAndAssign(void *dataPtr, const void *result)