1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qqmlvaluetypewrapper_p.h"
41
42#include <private/qqmlvaluetype_p.h>
43#include <private/qqmlbinding_p.h>
44#include <private/qqmlglobal_p.h>
45#include <private/qqmlbuiltinfunctions_p.h>
46
47#include <private/qv4engine_p.h>
48#include <private/qv4functionobject_p.h>
49#include <private/qv4variantobject_p.h>
50#include <private/qv4alloca_p.h>
51#include <private/qv4stackframe_p.h>
52#include <private/qv4objectiterator_p.h>
53#include <private/qv4qobjectwrapper_p.h>
54#include <private/qv4identifiertable_p.h>
55#include <private/qv4lookup_p.h>
56#include <QtCore/qloggingcategory.h>
57
58QT_BEGIN_NAMESPACE
59
60Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval)
61
62DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeWrapper);
63
64namespace QV4 {
65namespace Heap {
66
67struct QQmlValueTypeReference : QQmlValueTypeWrapper
68{
69 void init() {
70 QQmlValueTypeWrapper::init();
71 object.init();
72 }
73 void destroy() {
74 object.destroy();
75 QQmlValueTypeWrapper::destroy();
76 }
77 QQmlQPointer<QObject> object;
78 int property;
79};
80
81}
82
83struct QQmlValueTypeReference : public QQmlValueTypeWrapper
84{
85 V4_OBJECT2(QQmlValueTypeReference, QQmlValueTypeWrapper)
86 V4_NEEDS_DESTROY
87
88 bool readReferenceValue() const;
89};
90
91}
92
93DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeReference);
94
95using namespace QV4;
96
97void Heap::QQmlValueTypeWrapper::destroy()
98{
99 if (m_gadgetPtr) {
100 m_valueType->metaType.destruct(data: m_gadgetPtr);
101 ::operator delete(m_gadgetPtr);
102 }
103 if (m_propertyCache)
104 m_propertyCache->release();
105 Object::destroy();
106}
107
108void Heap::QQmlValueTypeWrapper::setValue(const QVariant &value) const
109{
110 Q_ASSERT(valueType()->metaType.id() == value.userType());
111 if (auto *gadget = gadgetPtr())
112 valueType()->metaType.destruct(data: gadget);
113 if (!gadgetPtr())
114 setGadgetPtr(::operator new(valueType()->metaType.sizeOf()));
115 valueType()->metaType.construct(where: gadgetPtr(), copy: value.constData());
116}
117
118QVariant Heap::QQmlValueTypeWrapper::toVariant() const
119{
120 Q_ASSERT(gadgetPtr());
121 return QVariant(valueType()->metaType.id(), gadgetPtr());
122}
123
124
125bool QQmlValueTypeReference::readReferenceValue() const
126{
127 if (!d()->object)
128 return false;
129 // A reference resource may be either a "true" reference (eg, to a QVector3D property)
130 // or a "variant" reference (eg, to a QVariant property which happens to contain a value-type).
131 QMetaProperty writebackProperty = d()->object->metaObject()->property(index: d()->property);
132 if (writebackProperty.userType() == QMetaType::QVariant) {
133 // variant-containing-value-type reference
134 QVariant variantReferenceValue;
135
136 void *a[] = { &variantReferenceValue, nullptr };
137 QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->property, a);
138
139 int variantReferenceType = variantReferenceValue.userType();
140 if (variantReferenceType != typeId()) {
141 // This is a stale VariantReference. That is, the variant has been
142 // overwritten with a different type in the meantime.
143 // We need to modify this reference to the updated value type, if
144 // possible, or return false if it is not a value type.
145 if (QQmlValueTypeFactory::isValueType(idx: variantReferenceType)) {
146 QQmlPropertyCache *cache = nullptr;
147 if (const QMetaObject *mo = QQmlValueTypeFactory::metaObjectForMetaType(type: variantReferenceType))
148 cache = QJSEnginePrivate::get(e: engine())->cache(metaObject: mo);
149 if (d()->gadgetPtr()) {
150 d()->valueType()->metaType.destruct(data: d()->gadgetPtr());
151 ::operator delete(d()->gadgetPtr());
152 }
153 d()->setGadgetPtr(nullptr);
154 d()->setPropertyCache(cache);
155 d()->setValueType(QQmlValueTypeFactory::valueType(idx: variantReferenceType));
156 if (!cache)
157 return false;
158 } else {
159 return false;
160 }
161 }
162 d()->setValue(variantReferenceValue);
163 } else {
164 if (!d()->gadgetPtr()) {
165 d()->setGadgetPtr(::operator new(d()->valueType()->metaType.sizeOf()));
166 d()->valueType()->metaType.construct(where: d()->gadgetPtr(), copy: nullptr);
167 }
168 // value-type reference
169 void *args[] = { d()->gadgetPtr(), nullptr };
170 QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->property, args);
171 }
172 return true;
173}
174
175void QQmlValueTypeWrapper::initProto(ExecutionEngine *v4)
176{
177 if (v4->valueTypeWrapperPrototype()->d_unchecked())
178 return;
179
180 Scope scope(v4);
181 ScopedObject o(scope, v4->newObject());
182 o->defineDefaultProperty(name: v4->id_toString(), code: method_toString, argumentCount: 1);
183 v4->jsObjects[QV4::ExecutionEngine::ValueTypeProto] = o->d();
184}
185
186ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *object, int property, const QMetaObject *metaObject, int typeId)
187{
188 Scope scope(engine);
189 initProto(v4: engine);
190
191 Scoped<QQmlValueTypeReference> r(scope, engine->memoryManager->allocate<QQmlValueTypeReference>());
192 r->d()->object = object;
193 r->d()->property = property;
194 r->d()->setPropertyCache(QJSEnginePrivate::get(e: engine)->cache(metaObject));
195 auto valueType = QQmlValueTypeFactory::valueType(idx: typeId);
196 if (!valueType) {
197 return engine->throwTypeError(message: QLatin1String("Type %1 is not a value type")
198 .arg(args: QString::fromUtf8(str: QMetaType(typeId).name())));
199 }
200 r->d()->setValueType(valueType);
201 r->d()->setGadgetPtr(nullptr);
202 return r->asReturnedValue();
203}
204
205ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, const QVariant &value, const QMetaObject *metaObject, int typeId)
206{
207 Scope scope(engine);
208 initProto(v4: engine);
209
210 Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>());
211 r->d()->setPropertyCache(QJSEnginePrivate::get(e: engine)->cache(metaObject));
212 auto valueType = QQmlValueTypeFactory::valueType(idx: typeId);
213 if (!valueType) {
214 return engine->throwTypeError(message: QLatin1String("Type %1 is not a value type")
215 .arg(args: QString::fromUtf8(str: QMetaType(typeId).name())));
216 }
217 r->d()->setValueType(valueType);
218 r->d()->setGadgetPtr(nullptr);
219 r->d()->setValue(value);
220 return r->asReturnedValue();
221}
222
223QVariant QQmlValueTypeWrapper::toVariant() const
224{
225 if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>())
226 if (!ref->readReferenceValue())
227 return QVariant();
228 return d()->toVariant();
229}
230
231bool QQmlValueTypeWrapper::toGadget(void *data) const
232{
233 if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>())
234 if (!ref->readReferenceValue())
235 return false;
236 const int typeId = d()->valueType()->metaType.id();
237 QMetaType::destruct(type: typeId, where: data);
238 QMetaType::construct(type: typeId, where: data, copy: d()->gadgetPtr());
239 return true;
240}
241
242bool QQmlValueTypeWrapper::virtualIsEqualTo(Managed *m, Managed *other)
243{
244 Q_ASSERT(m && m->as<QQmlValueTypeWrapper>() && other);
245 QV4::QQmlValueTypeWrapper *lv = static_cast<QQmlValueTypeWrapper *>(m);
246
247 if (QV4::VariantObject *rv = other->as<VariantObject>())
248 return lv->isEqual(value: rv->d()->data());
249
250 if (QV4::QQmlValueTypeWrapper *v = other->as<QQmlValueTypeWrapper>())
251 return lv->isEqual(value: v->toVariant());
252
253 return false;
254}
255
256PropertyAttributes QQmlValueTypeWrapper::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
257{
258 if (id.isString()) {
259 Scope scope(m);
260 ScopedString n(scope, id.asStringOrSymbol());
261 const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m);
262 QQmlPropertyData *result = r->d()->propertyCache()->property(key: n.getPointer(), object: nullptr, context: nullptr);
263 return result ? Attr_Data : Attr_Invalid;
264 }
265
266 return QV4::Object::virtualGetOwnProperty(m, id, p);
267}
268
269struct QQmlValueTypeWrapperOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
270{
271 int propertyIndex = 0;
272 ~QQmlValueTypeWrapperOwnPropertyKeyIterator() override = default;
273 PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override;
274
275};
276
277PropertyKey QQmlValueTypeWrapperOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs) {
278 const QQmlValueTypeWrapper *that = static_cast<const QQmlValueTypeWrapper *>(o);
279
280 if (const QQmlValueTypeReference *ref = that->as<QQmlValueTypeReference>()) {
281 if (!ref->readReferenceValue())
282 return PropertyKey::invalid();
283 }
284
285 if (that->d()->propertyCache()) {
286 const QMetaObject *mo = that->d()->propertyCache()->createMetaObject();
287 const int propertyCount = mo->propertyCount();
288 if (propertyIndex < propertyCount) {
289 Scope scope(that->engine());
290 ScopedString propName(scope, that->engine()->newString(s: QString::fromUtf8(str: mo->property(index: propertyIndex).name())));
291 ++propertyIndex;
292 if (attrs)
293 *attrs = QV4::Attr_Data;
294 if (pd)
295 pd->value = that->QV4::Object::get(name: propName);
296 return propName->toPropertyKey();
297 }
298 }
299
300 return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
301}
302
303
304OwnPropertyKeyIterator *QQmlValueTypeWrapper::virtualOwnPropertyKeys(const Object *m, Value *target)
305{
306 *target = *m;
307 return new QQmlValueTypeWrapperOwnPropertyKeyIterator;
308}
309
310bool QQmlValueTypeWrapper::isEqual(const QVariant& value) const
311{
312 if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>())
313 if (!ref->readReferenceValue())
314 return false;
315 return (value == d()->toVariant());
316}
317
318int QQmlValueTypeWrapper::typeId() const
319{
320 return d()->valueType()->metaType.id();
321}
322
323bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
324{
325 bool destructGadgetOnExit = false;
326 Q_ALLOCA_DECLARE(void, gadget);
327 if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>()) {
328 if (!d()->gadgetPtr()) {
329 Q_ALLOCA_ASSIGN(void, gadget, d()->valueType()->metaType.sizeOf());
330 d()->setGadgetPtr(gadget);
331 d()->valueType()->metaType.construct(where: d()->gadgetPtr(), copy: nullptr);
332 destructGadgetOnExit = true;
333 }
334 if (!ref->readReferenceValue())
335 return false;
336 }
337
338 int flags = 0;
339 int status = -1;
340 void *a[] = { d()->gadgetPtr(), nullptr, &status, &flags };
341 QMetaObject::metacall(target, QMetaObject::WriteProperty, propertyIndex, a);
342
343 if (destructGadgetOnExit) {
344 d()->valueType()->metaType.destruct(data: d()->gadgetPtr());
345 d()->setGadgetPtr(nullptr);
346 }
347 return true;
348}
349
350ReturnedValue QQmlValueTypeWrapper::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
351{
352 const Object *o = thisObject->as<Object>();
353 if (!o)
354 return b->engine()->throwTypeError();
355 const QQmlValueTypeWrapper *w = o->as<QQmlValueTypeWrapper>();
356 if (!w)
357 return b->engine()->throwTypeError();
358
359 if (const QQmlValueTypeReference *ref = w->as<QQmlValueTypeReference>())
360 if (!ref->readReferenceValue())
361 RETURN_UNDEFINED();
362
363 QString result;
364 // Prepare a buffer to pass to QMetaType::convert()
365 QString convertResult;
366 convertResult.~QString();
367 if (QMetaType::convert(from: w->d()->gadgetPtr(), fromTypeId: w->d()->valueType()->metaType.id(), to: &convertResult, toTypeId: QMetaType::QString)) {
368 result = convertResult;
369 } else {
370 result += QString::fromUtf8(str: QMetaType::typeName(type: w->d()->valueType()->metaType.id()))
371 + QLatin1Char('(');
372 const QMetaObject *mo = w->d()->propertyCache()->metaObject();
373 const int propCount = mo->propertyCount();
374 for (int i = 0; i < propCount; ++i) {
375 if (mo->property(index: i).isDesignable()) {
376 QVariant value = mo->property(index: i).readOnGadget(gadget: w->d()->gadgetPtr());
377 if (i > 0)
378 result += QLatin1String(", ");
379 result += value.toString();
380 }
381 }
382 result += QLatin1Char(')');
383 }
384 return Encode(b->engine()->newString(s: result));
385}
386
387Q_ALWAYS_INLINE static ReturnedValue getGadgetProperty(ExecutionEngine *engine,
388 Heap::QQmlValueTypeWrapper *valueTypeWrapper,
389 QQmlPropertyData *property)
390{
391 if (property->isFunction()) {
392 // calling a Q_INVOKABLE function of a value type
393 return QV4::QObjectMethod::create(scope: engine->rootContext(), valueType: valueTypeWrapper, index: property->coreIndex());
394 }
395
396#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
397 if (property->propType() == metatype) { \
398 cpptype v; \
399 void *args[] = { &v, nullptr }; \
400 metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr()), \
401 QMetaObject::ReadProperty, index, args); \
402 return QV4::Encode(constructor(v)); \
403 }
404
405 const QMetaObject *metaObject = valueTypeWrapper->propertyCache()->metaObject();
406
407 int index = property->coreIndex();
408 QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type: QMetaObject::ReadProperty, metaObject: &metaObject, index: &index);
409
410 // These four types are the most common used by the value type wrappers
411 VALUE_TYPE_LOAD(QMetaType::QReal, qreal, qreal);
412 VALUE_TYPE_LOAD(QMetaType::Int || property->isEnum(), int, int);
413 VALUE_TYPE_LOAD(QMetaType::Int, int, int);
414 VALUE_TYPE_LOAD(QMetaType::QString, QString, engine->newString);
415 VALUE_TYPE_LOAD(QMetaType::Bool, bool, bool);
416
417 QVariant v;
418 void *args[] = { nullptr, nullptr };
419 if (property->propType() == QMetaType::QVariant) {
420 args[0] = &v;
421 } else {
422 v = QVariant(property->propType(), static_cast<void *>(nullptr));
423 args[0] = v.data();
424 }
425 metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr()), QMetaObject::ReadProperty,
426 index, args);
427 return engine->fromVariant(v);
428#undef VALUE_TYPE_LOAD
429}
430
431ReturnedValue QQmlValueTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine,
432 Lookup *lookup)
433{
434 PropertyKey id = engine->identifierTable->asPropertyKey(str: engine->currentStackFrame->v4Function->compilationUnit->
435 runtimeStrings[lookup->nameIndex]);
436 if (!id.isString())
437 return Object::virtualResolveLookupGetter(object, engine, lookup);
438
439 const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(object);
440 QV4::ExecutionEngine *v4 = r->engine();
441 Scope scope(v4);
442 ScopedString name(scope, id.asStringOrSymbol());
443
444 // Note: readReferenceValue() can change the reference->type.
445 if (const QQmlValueTypeReference *reference = r->as<QQmlValueTypeReference>()) {
446 if (!reference->readReferenceValue())
447 return Value::undefinedValue().asReturnedValue();
448 }
449
450 QQmlPropertyData *result = r->d()->propertyCache()->property(key: name.getPointer(), object: nullptr, context: nullptr);
451 if (!result)
452 return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
453
454 lookup->qgadgetLookup.ic = r->internalClass();
455 lookup->qgadgetLookup.propertyCache = r->d()->propertyCache();
456 lookup->qgadgetLookup.propertyCache->addref();
457 lookup->qgadgetLookup.propertyData = result;
458 lookup->getter = QQmlValueTypeWrapper::lookupGetter;
459 return lookup->getter(lookup, engine, *object);
460}
461
462ReturnedValue QQmlValueTypeWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object)
463{
464 const auto revertLookup = [lookup, engine, &object]() {
465 lookup->qgadgetLookup.propertyCache->release();
466 lookup->qgadgetLookup.propertyCache = nullptr;
467 lookup->getter = Lookup::getterGeneric;
468 return Lookup::getterGeneric(l: lookup, engine, object);
469 };
470
471 // we can safely cast to a QV4::Object here. If object is something else,
472 // the internal class won't match
473 Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
474 if (!o || o->internalClass != lookup->qgadgetLookup.ic)
475 return revertLookup();
476
477 Heap::QQmlValueTypeWrapper *valueTypeWrapper =
478 const_cast<Heap::QQmlValueTypeWrapper*>(static_cast<const Heap::QQmlValueTypeWrapper *>(o));
479 if (valueTypeWrapper->propertyCache() != lookup->qgadgetLookup.propertyCache)
480 return revertLookup();
481
482 if (lookup->qgadgetLookup.ic->vtable == QQmlValueTypeReference::staticVTable()) {
483 Scope scope(engine);
484 Scoped<QQmlValueTypeReference> referenceWrapper(scope, valueTypeWrapper);
485 referenceWrapper->readReferenceValue();
486 }
487
488 QQmlPropertyData *property = lookup->qgadgetLookup.propertyData;
489 return getGadgetProperty(engine, valueTypeWrapper, property);
490}
491
492bool QQmlValueTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup,
493 const Value &value)
494{
495 return Object::virtualResolveLookupSetter(object, engine, lookup, value);
496}
497
498ReturnedValue QQmlValueTypeWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
499{
500 Q_ASSERT(m->as<QQmlValueTypeWrapper>());
501
502 if (!id.isString())
503 return Object::virtualGet(m, id, receiver, hasProperty);
504
505 const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m);
506 QV4::ExecutionEngine *v4 = r->engine();
507 Scope scope(v4);
508 ScopedString name(scope, id.asStringOrSymbol());
509
510 // Note: readReferenceValue() can change the reference->type.
511 if (const QQmlValueTypeReference *reference = r->as<QQmlValueTypeReference>()) {
512 if (!reference->readReferenceValue())
513 return Value::undefinedValue().asReturnedValue();
514 }
515
516 QQmlPropertyData *result = r->d()->propertyCache()->property(key: name.getPointer(), object: nullptr, context: nullptr);
517 if (!result)
518 return Object::virtualGet(m, id, receiver, hasProperty);
519
520 if (hasProperty)
521 *hasProperty = true;
522
523 return getGadgetProperty(engine: v4, valueTypeWrapper: r->d(), property: result);
524}
525
526bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
527{
528 if (!id.isString())
529 return Object::virtualPut(m, id, value, receiver);
530
531 Q_ASSERT(m->as<QQmlValueTypeWrapper>());
532 ExecutionEngine *v4 = static_cast<QQmlValueTypeWrapper *>(m)->engine();
533 Scope scope(v4);
534 if (scope.hasException())
535 return false;
536
537 Scoped<QQmlValueTypeWrapper> r(scope, static_cast<QQmlValueTypeWrapper *>(m));
538 Scoped<QQmlValueTypeReference> reference(scope, m->d());
539
540 int writeBackPropertyType = -1;
541
542 if (reference) {
543 QMetaProperty writebackProperty = reference->d()->object->metaObject()->property(index: reference->d()->property);
544
545 if (!writebackProperty.isWritable() || !reference->readReferenceValue())
546 return false;
547
548 writeBackPropertyType = writebackProperty.userType();
549 }
550
551 ScopedString name(scope, id.asStringOrSymbol());
552
553 const QMetaObject *metaObject = r->d()->propertyCache()->metaObject();
554 const QQmlPropertyData *pd = r->d()->propertyCache()->property(key: name.getPointer(), object: nullptr, context: nullptr);
555 if (!pd)
556 return false;
557
558 if (reference) {
559 QV4::ScopedFunctionObject f(scope, value);
560 const QQmlQPointer<QObject> &referenceObject = reference->d()->object;
561 const int referencePropertyIndex = reference->d()->property;
562
563 if (f) {
564 if (!f->isBinding()) {
565 // assigning a JS function to a non-var-property is not allowed.
566 QString error = QStringLiteral("Cannot assign JavaScript function to value-type property");
567 ScopedString e(scope, v4->newString(s: error));
568 v4->throwError(value: e);
569 return false;
570 }
571
572 QQmlContextData *context = v4->callingQmlContext();
573
574 QQmlPropertyData cacheData;
575 cacheData.setWritable(true);
576 cacheData.setPropType(writeBackPropertyType);
577 cacheData.setCoreIndex(referencePropertyIndex);
578
579 QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
580
581 QV4::ScopedFunctionObject f(scope, bindingFunction->bindingFunction());
582 QV4::ScopedContext ctx(scope, f->scope());
583 QQmlBinding *newBinding = QQmlBinding::create(property: &cacheData, function: f->function(), obj: referenceObject, ctxt: context, scope: ctx);
584 newBinding->setSourceLocation(bindingFunction->currentLocation());
585 if (f->isBoundFunction())
586 newBinding->setBoundFunction(static_cast<QV4::BoundFunction *>(f.getPointer()));
587 newBinding->setSourceLocation(bindingFunction->currentLocation());
588 newBinding->setTarget(referenceObject, cacheData, valueType: pd);
589 QQmlPropertyPrivate::setBinding(binding: newBinding);
590 return true;
591 } else {
592 if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
593 if (auto binding = QQmlPropertyPrivate::binding(referenceObject, index: QQmlPropertyIndex(referencePropertyIndex, pd->coreIndex()))) {
594 Q_ASSERT(!binding->isValueTypeProxy());
595 const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
596 const auto stackFrame = v4->currentStackFrame;
597 qCInfo(lcBindingRemoval,
598 "Overwriting binding on %s::%s which was initially bound at %s by setting \"%s\" at %s:%d",
599 referenceObject->metaObject()->className(), referenceObject->metaObject()->property(referencePropertyIndex).name(),
600 qPrintable(qmlBinding->expressionIdentifier()),
601 metaObject->property(pd->coreIndex()).name(),
602 qPrintable(stackFrame->source()), stackFrame->lineNumber());
603 }
604 }
605 QQmlPropertyPrivate::removeBinding(o: referenceObject, index: QQmlPropertyIndex(referencePropertyIndex, pd->coreIndex()));
606 }
607 }
608
609 QMetaProperty property = metaObject->property(index: pd->coreIndex());
610 Q_ASSERT(property.isValid());
611
612 QVariant v = v4->toVariant(value, typeHint: property.userType());
613
614 if (property.isEnumType() && (QMetaType::Type)v.userType() == QMetaType::Double)
615 v = v.toInt();
616
617 void *gadget = r->d()->gadgetPtr();
618 property.writeOnGadget(gadget, value: v);
619
620
621 if (reference) {
622 if (writeBackPropertyType == QMetaType::QVariant) {
623 QVariant variantReferenceValue = r->d()->toVariant();
624
625 int flags = 0;
626 int status = -1;
627 void *a[] = { &variantReferenceValue, nullptr, &status, &flags };
628 QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a);
629
630 } else {
631 int flags = 0;
632 int status = -1;
633 void *a[] = { r->d()->gadgetPtr(), nullptr, &status, &flags };
634 QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a);
635 }
636 }
637
638 return true;
639}
640
641QT_END_NAMESPACE
642

source code of qtdeclarative/src/qml/qml/qqmlvaluetypewrapper.cpp