Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmlvaluetypewrapper.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <private/qqmlvaluetype_p.h>
7#include <private/qqmlbinding_p.h>
8#include <private/qqmlglobal_p.h>
9#include <private/qqmlbuiltinfunctions_p.h>
10
11#include <private/qv4engine_p.h>
12#include <private/qv4functionobject_p.h>
13#include <private/qv4variantobject_p.h>
14#include <private/qv4alloca_p.h>
15#include <private/qv4stackframe_p.h>
16#include <private/qv4objectiterator_p.h>
17#include <private/qv4qobjectwrapper_p.h>
18#include <private/qv4identifiertable_p.h>
19#include <private/qv4lookup_p.h>
20#include <private/qv4sequenceobject_p.h>
21#include <private/qv4arraybuffer_p.h>
22#include <private/qv4dateobject_p.h>
23#include <private/qv4jsonobject_p.h>
24#if QT_CONFIG(regularexpression)
25#include <private/qv4regexpobject_p.h>
26#endif
27#if QT_CONFIG(qml_locale)
28#include <private/qqmllocale_p.h>
29#endif
30#include <QtCore/qloggingcategory.h>
31#include <QtCore/qdatetime.h>
32#include <QtCore/QLine>
33#include <QtCore/QLineF>
34#include <QtCore/QSize>
35#include <QtCore/QSizeF>
36#include <QtCore/QTimeZone>
37
39
40Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval)
41
42DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeWrapper);
43
44namespace QV4 {
45
46Heap::QQmlValueTypeWrapper *Heap::QQmlValueTypeWrapper::detached() const
47{
48 return internalClass->engine->memoryManager->allocate<QV4::QQmlValueTypeWrapper>(
49 m_gadgetPtr, QMetaType(m_metaType), m_metaObject, nullptr, -1, NoFlag);
50}
51
52void Heap::QQmlValueTypeWrapper::destroy()
53{
54 if (m_gadgetPtr) {
55 metaType().destruct(m_gadgetPtr);
56 ::operator delete(m_gadgetPtr);
57 }
58 ReferenceObject::destroy();
59}
60
61QVariant Heap::QQmlValueTypeWrapper::toVariant() const
62{
63 Q_ASSERT(gadgetPtr());
64 return QVariant(metaType(), gadgetPtr());
65}
66
67bool Heap::QQmlValueTypeWrapper::setVariant(const QVariant &variant)
68{
69 Q_ASSERT(isVariant());
70
71 const QMetaType variantReferenceType = variant.metaType();
72 if (variantReferenceType != metaType()) {
73 // This is a stale VariantReference. That is, the variant has been
74 // overwritten with a different type in the meantime.
75 // We need to modify this reference to the updated value type, if
76 // possible, or return false if it is not a value type.
77 if (QQmlMetaType::isValueType(variantReferenceType)) {
78 const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(variantReferenceType);
79 if (gadgetPtr()) {
80 metaType().destruct(gadgetPtr());
81 ::operator delete(gadgetPtr());
82 }
83 setGadgetPtr(nullptr);
84 setMetaObject(mo);
85 setMetaType(variantReferenceType);
86 if (!mo)
87 return false;
88 } else {
89 return false;
90 }
91 }
92
94 return true;
95}
96
97void *Heap::QQmlValueTypeWrapper::storagePointer()
98{
99 if (!gadgetPtr()) {
100 setGadgetPtr(::operator new(metaType().sizeOf()));
101 metaType().construct(gadgetPtr(), nullptr);
102 }
103 return gadgetPtr();
104}
105
106bool Heap::QQmlValueTypeWrapper::readReference()
107{
108 // If locations are enforced we only read once
109 return enforcesLocation() || QV4::ReferenceObject::readReference(this);
110}
111
112bool Heap::QQmlValueTypeWrapper::writeBack(int propertyIndex)
113{
114 return isAttachedToProperty() && QV4::ReferenceObject::writeBack(this, propertyIndex);
115}
116
117ReturnedValue QQmlValueTypeWrapper::create(
118 ExecutionEngine *engine, Heap::QQmlValueTypeWrapper *cloneFrom, Heap::Object *object)
119{
120 QV4::Scope scope(engine);
121 initProto(engine);
122
123 // Either we're enforcing the location, then we have to read right away.
124 // Or we don't then we lazy-load. In neither case we pass any data.
125 Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>(
126 nullptr, cloneFrom->metaType(), cloneFrom->metaObject(),
127 object, cloneFrom->property(), cloneFrom->flags()));
128 r->d()->setLocation(cloneFrom->function(), cloneFrom->statementIndex());
129 if (cloneFrom->enforcesLocation())
131 return r->asReturnedValue();
132}
133
134void QQmlValueTypeWrapper::initProto(ExecutionEngine *v4)
135{
136 if (v4->valueTypeWrapperPrototype()->d_unchecked())
137 return;
138
139 Scope scope(v4);
140 ScopedObject o(scope, v4->newObject());
141 o->defineDefaultProperty(v4->id_toString(), method_toString, 1);
143}
144
145int QQmlValueTypeWrapper::virtualMetacall(
146 Object *object, QMetaObject::Call call, int index, void **a)
147{
150
151 switch (call) {
156 if (wrapper->d()->object())
157 wrapper->d()->readReference();
158 break;
159 default:
160 break;
161 }
162
163 const QMetaObject *mo = wrapper->d()->metaObject();
164 if (!mo->d.static_metacall)
165 return 0;
166
167 mo->d.static_metacall(static_cast<QObject *>(wrapper->d()->gadgetPtr()), call, index, a);
168
169 switch (call) {
171 break;
174 if (wrapper->d()->object())
175 wrapper->d()->writeBack(index);
176 break;
179 if (wrapper->d()->object())
180 wrapper->d()->writeBack();
181 break;
182 default:
183 break;
184 }
185
186 return -1;
187}
188
189ReturnedValue QQmlValueTypeWrapper::create(
191 Heap::Object *object, int property, Heap::ReferenceObject::Flags flags)
192{
193 Scope scope(engine);
194 initProto(engine);
195
196 if (!type.isValid()) {
197 return engine->throwTypeError(QLatin1String("Type %1 is not a value type")
198 .arg(QString::fromUtf8(type.name())));
199 }
200
201 // If data is given explicitly, we assume it has just been read from the property
202 Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>(
203 data, type, metaObject, object, property, flags));
204 if (CppStackFrame *frame = engine->currentStackFrame)
205 r->d()->setLocation(frame->v4Function, frame->statementNumber());
206 if (!data && r->d()->enforcesLocation())
208 return r->asReturnedValue();
209}
210
211ReturnedValue QQmlValueTypeWrapper::create(
213{
214 Scope scope(engine);
215 initProto(engine);
216
217 if (!type.isValid()) {
218 return engine->throwTypeError(QLatin1String("Type %1 is not a value type")
219 .arg(QString::fromUtf8(type.name())));
220 }
221
222 Scoped<QQmlValueTypeWrapper> r(
223 scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>(
224 data, type, metaObject, nullptr, -1, Heap::ReferenceObject::NoFlag));
225 return r->asReturnedValue();
226}
227
228QVariant QQmlValueTypeWrapper::toVariant() const
229{
230 if (d()->isReference() && !readReferenceValue())
231 return QVariant();
232 return d()->toVariant();
233}
234
235bool QQmlValueTypeWrapper::toGadget(void *data) const
236{
237 if (d()->isReference() && !readReferenceValue())
238 return false;
239 const QMetaType type = d()->metaType();
241 type.construct(data, d()->gadgetPtr());
242 return true;
243}
244
245bool QQmlValueTypeWrapper::virtualIsEqualTo(Managed *m, Managed *other)
246{
247 Q_ASSERT(m && m->as<QQmlValueTypeWrapper>() && other);
249
250 if (QV4::VariantObject *rv = other->as<VariantObject>())
251 return lv->isEqual(rv->d()->data());
252
254 return lv->isEqual(v->toVariant());
255
256 return false;
257}
258
259bool QQmlValueTypeWrapper::virtualHasProperty(const Managed *m, PropertyKey id)
260{
261 if (!id.isString())
262 return Object::virtualHasProperty(m, id);
263 Q_ASSERT(m && m->as<QQmlValueTypeWrapper>());
264 auto wrapper = static_cast<const QQmlValueTypeWrapper *>(m);
265 if (auto mo = wrapper->d()->metaObject())
266 if (mo->indexOfProperty(id.toQString().toUtf8()) != -1)
267 return true;
268
269 /* we don't want to fallback to QObject::virtualHasProperty
270 as that would end up calling getOwnProperty which is wasteful,
271 as it calls our own virtualGetOwnProperty.
272 As we know that our own properties are only those found on the meta-object,
273 we can instead skip the call, and simply check whether the property exists
274 on the prototype.
275 */
276 Scope scope(m->engine());
277 ScopedObject o(scope, m);
278 o = o->getPrototypeOf();
279 if (o)
280 return o->hasProperty(id);
281
282 return false;
283}
284
285static Heap::ReferenceObject::Flags referenceFlags(const QMetaObject *metaObject, int index)
286{
287 return metaObject->property(index).isWritable()
288 ? (Heap::ReferenceObject::CanWriteBack | Heap::ReferenceObject::EnforcesLocation)
289 : Heap::ReferenceObject::EnforcesLocation;
290}
291
293 const QMetaObject *metaObject, Heap::QQmlValueTypeWrapper *valueTypeWrapper,
294 int index, void **args)
295{
296 metaObject->d.static_metacall(
297 reinterpret_cast<QObject*>(
298 valueTypeWrapper->gadgetPtr()), QMetaObject::ReadProperty, index, args);
299}
300
302 Heap::QQmlValueTypeWrapper *valueTypeWrapper,
303 QMetaType metaType, quint16 coreIndex, bool isFunction, bool isEnum)
304{
305 if (isFunction) {
306 // calling a Q_INVOKABLE function of a value type
307 return QV4::QObjectMethod::create(engine, valueTypeWrapper, coreIndex);
308 }
309
310 const QMetaObject *metaObject = valueTypeWrapper->metaObject();
311 int index = coreIndex;
312
313 const auto wrapChar16 = [engine](char16_t c) {
314 return engine->newString(QChar(c));
315 };
316 const auto wrapQObject = [engine](QObject *object) {
317 return QObjectWrapper::wrap(engine, object);
318 };
319 const auto wrapJsonValue = [engine](const QJsonValue &value) {
320 return JsonObject::fromJsonValue(engine, value);
321 };
322 const auto wrapJsonObject = [engine](const QJsonObject &object) {
323 return JsonObject::fromJsonObject(engine, object);
324 };
325 const auto wrapJsonArray = [engine](const QJsonArray &array) {
326 return JsonObject::fromJsonArray(engine, array);
327 };
328
329 const auto wrapQDateTime = [&](const QDateTime &dateTime) {
330 return engine->newDateObject(
331 dateTime, valueTypeWrapper, index, referenceFlags(metaObject, index));
332 };
333 const auto wrapQDate = [&](QDate date) {
334 return engine->newDateObject(
335 date, valueTypeWrapper, index, referenceFlags(metaObject, index));
336 };
337 const auto wrapQTime = [&](QTime time) {
338 return engine->newDateObject(
339 time, valueTypeWrapper, index, referenceFlags(metaObject, index));
340 };
341
342#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
343 case metatype: { \
344 cpptype v; \
345 void *args[] = { &v, nullptr }; \
346 doStaticReadCall(metaObject, valueTypeWrapper, index, args); \
347 return QV4::Encode(constructor(v)); \
348 }
349
352
353 const int metaTypeId = isEnum
354 ? metaType.underlyingType().id()
355 : (metaType.flags() & QMetaType::PointerToQObject)
356 ? QMetaType::QObjectStar
357 : metaType.id();
358
359 switch (metaTypeId) {
361 case QMetaType::Void:
362 return Encode::undefined();
363 case QMetaType::Nullptr:
364 case QMetaType::VoidStar:
365 return Encode::null();
366 VALUE_TYPE_LOAD(QMetaType::Bool, bool, bool);
367 VALUE_TYPE_LOAD(QMetaType::Int, int, int);
368 VALUE_TYPE_LOAD(QMetaType::UInt, uint, uint);
369 VALUE_TYPE_LOAD(QMetaType::Long, long, double);
370 VALUE_TYPE_LOAD(QMetaType::ULong, ulong, double);
371 VALUE_TYPE_LOAD(QMetaType::LongLong, qlonglong, double);
372 VALUE_TYPE_LOAD(QMetaType::ULongLong, qulonglong, double);
373 VALUE_TYPE_LOAD(QMetaType::Double, double, double);
374 VALUE_TYPE_LOAD(QMetaType::QString, QString, engine->newString);
375 VALUE_TYPE_LOAD(QMetaType::QByteArray, QByteArray, engine->newArrayBuffer);
376 VALUE_TYPE_LOAD(QMetaType::Float, float, float);
377 VALUE_TYPE_LOAD(QMetaType::Short, short, int);
378 VALUE_TYPE_LOAD(QMetaType::UShort, unsigned short, int);
379 VALUE_TYPE_LOAD(QMetaType::Char, char, int);
380 VALUE_TYPE_LOAD(QMetaType::UChar, unsigned char, int);
381 VALUE_TYPE_LOAD(QMetaType::SChar, signed char, int);
382 VALUE_TYPE_LOAD(QMetaType::QChar, QChar, engine->newString);
383 VALUE_TYPE_LOAD(QMetaType::Char16, char16_t, wrapChar16);
384 VALUE_TYPE_LOAD(QMetaType::QDateTime, QDateTime, wrapQDateTime);
385 VALUE_TYPE_LOAD(QMetaType::QDate, QDate, wrapQDate);
386 VALUE_TYPE_LOAD(QMetaType::QTime, QTime, wrapQTime);
387#if QT_CONFIG(regularexpression)
388 VALUE_TYPE_LOAD(QMetaType::QRegularExpression, QRegularExpression, engine->newRegExpObject);
389#endif
390 VALUE_TYPE_LOAD(QMetaType::QObjectStar, QObject*, wrapQObject);
391 VALUE_TYPE_LOAD(QMetaType::QJsonValue, QJsonValue, wrapJsonValue);
392 VALUE_TYPE_LOAD(QMetaType::QJsonObject, QJsonObject, wrapJsonObject);
393 VALUE_TYPE_LOAD(QMetaType::QJsonArray, QJsonArray, wrapJsonArray);
394 case QMetaType::QPixmap:
395 case QMetaType::QImage: {
396 QVariant v(metaType);
397 void *args[] = { v.data(), nullptr };
398 doStaticReadCall(metaObject, valueTypeWrapper, index, args);
399 return Encode(engine->newVariantObject(metaType, v.data()));
400 }
401 case QMetaType::QVariant: {
402 QVariant v;
403 void *args[] = { &v, nullptr };
404 doStaticReadCall(metaObject, valueTypeWrapper, index, args);
405 return engine->fromVariant(
406 v, valueTypeWrapper, index,
407 referenceFlags(metaObject, index) | Heap::ReferenceObject::IsVariant);
408 }
409 default:
410 break;
411 }
412
413 QVariant v(metaType);
414 void *args[] = { v.data(), nullptr };
415 doStaticReadCall(metaObject, valueTypeWrapper, index, args);
416 return engine->fromVariant(v, valueTypeWrapper, index, referenceFlags(metaObject, index));
417#undef VALUE_TYPE_LOAD
418}
419
420PropertyAttributes QQmlValueTypeWrapper::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
421{
422 if (id.isString()) {
423 const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m);
424 Q_ASSERT(r);
425
426 const QQmlPropertyData result = r->dataForPropertyKey(id);
427 if (!result.isValid())
428 return Attr_Invalid; // Property doesn't exist. Object shouldn't meddle with it.
429
430 if (!p)
431 return Attr_Data; // Property exists, but we're not interested in the value
432
433 if (!r->d()->isReference() || r->readReferenceValue()) {
434 // Property exists, and we can retrieve it
435 p->value = getGadgetProperty(
436 r->engine(), r->d(), result.propType(), result.coreIndex(),
437 result.isFunction(), result.isEnum());
438 } else {
439 // Property exists, but we can't retrieve it. Make it undefined.
440 p->value = Encode::undefined();
441 }
442
443 return Attr_Data;
444 }
445
447}
448
450{
451 int propertyIndex = 0;
453 PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override;
454
455};
456
457PropertyKey QQmlValueTypeWrapperOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs) {
458 const QQmlValueTypeWrapper *that = static_cast<const QQmlValueTypeWrapper *>(o);
459
460 if (that->d()->isReference() && !that->readReferenceValue())
461 return PropertyKey::invalid();
462
463 const QMetaObject *mo = that->d()->metaObject();
464 // We don't return methods, ie. they are not visible when iterating
465 const int propertyCount = mo->propertyCount();
466 if (propertyIndex < propertyCount) {
467 Scope scope(that->engine());
468 QMetaProperty p = mo->property(propertyIndex); // TODO: Implement and use QBasicMetaProperty
469 ScopedString propName(scope, that->engine()->newString(QString::fromUtf8(p.name())));
470 ++propertyIndex;
471 if (attrs)
473 if (pd) {
475 data.load(p);
476 pd->value = getGadgetProperty(that->engine(), that->d(), data.propType(), data.coreIndex(), data.isFunction(), data.isEnum());
477 }
478 return propName->toPropertyKey();
479 }
480
481 return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
482}
483
484
485OwnPropertyKeyIterator *QQmlValueTypeWrapper::virtualOwnPropertyKeys(const Object *m, Value *target)
486{
487 *target = *m;
489}
490
491bool QQmlValueTypeWrapper::isEqual(const QVariant& value) const
492{
493 if (d()->isReference() && !readReferenceValue())
494 return false;
495 int id1 = value.metaType().id();
496 QVariant v = d()->toVariant();
497 int id2 = v.metaType().id();
498 if (id1 != id2) {
499 // conversions for weak comparison
500 switch (id1) {
501 case QMetaType::QPoint:
502 if (id2 == QMetaType::QPointF)
503 return value.value<QPointF>() == v.value<QPointF>();
504 break;
505 case QMetaType::QPointF:
506 if (id2 == QMetaType::QPoint)
507 return value.value<QPointF>() == v.value<QPointF>();
508 break;
509 case QMetaType::QRect:
510 if (id2 == QMetaType::QRectF)
511 return value.value<QRectF>() == v.value<QRectF>();
512 break;
513 case QMetaType::QRectF:
514 if (id2 == QMetaType::QRect)
515 return value.value<QRectF>() == v.value<QRectF>();
516 break;
517 case QMetaType::QLine:
518 if (id2 == QMetaType::QLineF)
519 return value.value<QLineF>() == v.value<QLineF>();
520 break;
521 case QMetaType::QLineF:
522 if (id2 == QMetaType::QLine)
523 return value.value<QLineF>() == v.value<QLineF>();
524 break;
525 case QMetaType::QSize:
526 if (id2 == QMetaType::QSizeF)
527 return value.value<QSizeF>() == v.value<QSizeF>();
528 break;
529 case QMetaType::QSizeF:
530 if (id2 == QMetaType::QSize)
531 return value.value<QSizeF>() == v.value<QSizeF>();
532 break;
533 default:
534 break;
535 }
536 }
537 return (value == v);
538}
539
540int QQmlValueTypeWrapper::typeId() const
541{
542 return d()->metaType().id();
543}
544
545QMetaType QQmlValueTypeWrapper::type() const
546{
547 return d()->metaType();
548}
549
550bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
551{
552 bool destructGadgetOnExit = false;
553 Q_ALLOCA_DECLARE(void, gadget);
554 if (d()->isReference()) {
555 if (!d()->gadgetPtr()) {
556 Q_ALLOCA_ASSIGN(void, gadget, d()->metaType().sizeOf());
557 d()->setGadgetPtr(gadget);
558 d()->metaType().construct(d()->gadgetPtr(), nullptr);
559 destructGadgetOnExit = true;
560 }
561 if (!readReferenceValue())
562 return false;
563 }
564
565 int flags = 0;
566 int status = -1;
567 void *a[] = { d()->gadgetPtr(), nullptr, &status, &flags };
569
570 if (destructGadgetOnExit) {
571 d()->metaType().destruct(d()->gadgetPtr());
572 d()->setGadgetPtr(nullptr);
573 }
574 return true;
575}
576
577QQmlPropertyData QQmlValueTypeWrapper::dataForPropertyKey(PropertyKey id) const
578{
579 if (!id.isStringOrSymbol())
580 return QQmlPropertyData {};
581 QByteArray name = id.asStringOrSymbol()->toQString().toUtf8();
582 const QMetaObject *mo = d()->metaObject();
585 if (metaMethod.isValid()) {
586 result.load(metaMethod);
587 } else {
588 int propertyIndex = d()->metaObject()->indexOfProperty(name.constData());
589 if (propertyIndex >= 0)
590 result.load(mo->property(propertyIndex));
591 }
592 return result;
593}
594
595ReturnedValue QQmlValueTypeWrapper::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
596{
597 const Object *o = thisObject->as<Object>();
598 if (!o)
599 return b->engine()->throwTypeError();
601 if (!w)
602 return b->engine()->throwTypeError();
603
604 if (w->d()->isReference() && !w->readReferenceValue())
606
608 if (!QMetaType::convert(w->d()->metaType(), w->d()->gadgetPtr(),
609 QMetaType(QMetaType::QString), &result)) {
610 result = QString::fromUtf8(w->d()->metaType().name()) + QLatin1Char('(');
611 const QMetaObject *mo = w->d()->metaObject();
612 const int propCount = mo->propertyCount();
613 for (int i = 0; i < propCount; ++i) {
614 if (mo->property(i).isDesignable()) {
615 QVariant value = mo->property(i).readOnGadget(w->d()->gadgetPtr());
616 if (i > 0)
617 result += QLatin1String(", ");
618 result += value.toString();
619 }
620 }
621 result += QLatin1Char(')');
622 }
623 return Encode(b->engine()->newString(result));
624}
625
626ReturnedValue QQmlValueTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine,
627 Lookup *lookup)
628{
629 PropertyKey id = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->
630 runtimeStrings[lookup->nameIndex]);
631 if (!id.isString())
632 return Object::virtualResolveLookupGetter(object, engine, lookup);
633
634 const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(object);
635 QV4::ExecutionEngine *v4 = r->engine();
636 Scope scope(v4);
637 ScopedString name(scope, id.asStringOrSymbol());
638
639 // Note: readReferenceValue() can change the reference->type.
640 if (r->d()->isReference() && !r->readReferenceValue())
641 return Value::undefinedValue().asReturnedValue();
642
643 QQmlPropertyData result = r->dataForPropertyKey(id);
644 if (!result.isValid())
645 return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
646
647 lookup->qgadgetLookup.ic.set(engine, r->internalClass());
648 // & 1 to tell the gc that this is not heap allocated; see markObjects in qv4lookup_p.h
649 lookup->qgadgetLookup.metaObject = quintptr(r->d()->metaObject()) + 1;
650 lookup->qgadgetLookup.metaType = result.propType().iface();
651 lookup->qgadgetLookup.coreIndex = result.coreIndex();
652 lookup->qgadgetLookup.isFunction = result.isFunction();
653 lookup->qgadgetLookup.isEnum = result.isEnum();
654 lookup->getter = QQmlValueTypeWrapper::lookupGetter;
655 return lookup->getter(lookup, engine, *object);
656}
657
658ReturnedValue QQmlValueTypeWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object)
659{
660 const auto revertLookup = [lookup, engine, &object]() {
661 lookup->qgadgetLookup.metaObject = quintptr(0);
662 lookup->getter = Lookup::getterGeneric;
663 return Lookup::getterGeneric(lookup, engine, object);
664 };
665
666 // we can safely cast to a QV4::Object here. If object is something else,
667 // the internal class won't match
668 Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
669 if (!o || o->internalClass != lookup->qgadgetLookup.ic)
670 return revertLookup();
671
672 Heap::QQmlValueTypeWrapper *valueTypeWrapper =
673 const_cast<Heap::QQmlValueTypeWrapper*>(static_cast<const Heap::QQmlValueTypeWrapper *>(o));
674 if (valueTypeWrapper->metaObject() != reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1))
675 return revertLookup();
676
677 if (valueTypeWrapper->isReference() && !valueTypeWrapper->readReference())
678 return Encode::undefined();
679
680 return getGadgetProperty(
681 engine, valueTypeWrapper, QMetaType(lookup->qgadgetLookup.metaType),
682 lookup->qgadgetLookup.coreIndex, lookup->qgadgetLookup.isFunction,
683 lookup->qgadgetLookup.isEnum);
684}
685
686bool QQmlValueTypeWrapper::lookupSetter(
687 Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
688{
689 return QV4::Lookup::setterFallback(l, engine, object, value);
690}
691
692bool QQmlValueTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup,
693 const Value &value)
694{
695 return Object::virtualResolveLookupSetter(object, engine, lookup, value);
696}
697
698ReturnedValue QQmlValueTypeWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
699{
701
702 if (!id.isString())
703 return Object::virtualGet(m, id, receiver, hasProperty);
704
705 const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m);
706 QV4::ExecutionEngine *v4 = r->engine();
707
708 // Note: readReferenceValue() can change the reference->type.
709 if (r->d()->isReference() && !r->readReferenceValue())
710 return Value::undefinedValue().asReturnedValue();
711
712 QQmlPropertyData result = r->dataForPropertyKey(id);
713 if (!result.isValid())
714 return Object::virtualGet(m, id, receiver, hasProperty);
715
716 if (hasProperty)
717 *hasProperty = true;
718
719 return getGadgetProperty(v4, r->d(), result.propType(), result.coreIndex(), result.isFunction(), result.isEnum());
720}
721
722bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
723{
724 if (!id.isString())
725 return Object::virtualPut(m, id, value, receiver);
726
728 ExecutionEngine *v4 = static_cast<QQmlValueTypeWrapper *>(m)->engine();
729 Scope scope(v4);
730 if (scope.hasException())
731 return false;
732
733 Scoped<QQmlValueTypeWrapper> r(scope, static_cast<QQmlValueTypeWrapper *>(m));
734 Heap::Object *heapObject = nullptr;
735 if (r->d()->isReference()) {
736 heapObject = r->d()->object();
737 if (!r->readReferenceValue() || !r->d()->canWriteBack())
738 return false;
739 }
740
741 const QMetaObject *metaObject = r->d()->metaObject();
742 const QQmlPropertyData pd = r->dataForPropertyKey(id);
743 if (!pd.isValid())
744 return false;
745
746 if (heapObject) {
747 QObject *referenceObject = nullptr;
749 const int referencePropertyIndex = r->d()->property();
750 QV4::Scoped<QV4::QObjectWrapper> o(scope, heapObject);
751 if (o) {
752 referenceObject = o->object();
753 } else {
754 QV4::Scoped<QV4::QQmlTypeWrapper> t(scope, heapObject);
755 if (t)
756 referenceObject = t->object();
757 }
758
759 if (f) {
760 if (!f->isBinding()) {
761 // assigning a JS function to a non-var-property is not allowed.
762 QString error = QStringLiteral("Cannot assign JavaScript function to value-type property");
763 ScopedString e(scope, v4->newString(error));
764 v4->throwError(e);
765 return false;
766 }
767
768 if (!referenceObject) {
769 QString error = QStringLiteral("Cannot create binding on nested value type property");
770 ScopedString e(scope, v4->newString(error));
771 v4->throwError(e);
772 return false;
773 }
774
775 const QMetaProperty writebackProperty
776 = referenceObject->metaObject()->property(referencePropertyIndex);
777 const QMetaType writeBackPropertyType = writebackProperty.metaType();
778
779 QQmlRefPointer<QQmlContextData> context = v4->callingQmlContext();
780
781 QQmlPropertyData cacheData;
782 cacheData.setWritable(true);
783 cacheData.setPropType(writeBackPropertyType);
784 cacheData.setCoreIndex(referencePropertyIndex);
785
786 QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
787
788 QV4::Scoped<JavaScriptFunctionObject> f(scope, bindingFunction->bindingFunction());
789 QV4::ScopedContext ctx(scope, f->scope());
790 QQmlBinding *newBinding = QQmlBinding::create(&cacheData, f->function(), referenceObject, context, ctx);
791 newBinding->setSourceLocation(bindingFunction->currentLocation());
792 if (f->isBoundFunction())
793 newBinding->setBoundFunction(static_cast<QV4::BoundFunction *>(f.getPointer()));
794 newBinding->setSourceLocation(bindingFunction->currentLocation());
795 newBinding->setTarget(referenceObject, cacheData, &pd);
797 return true;
798 } else if (referenceObject) {
799 if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
800 if (auto binding = QQmlPropertyPrivate::binding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd.coreIndex()))) {
801 Q_ASSERT(binding->kind() == QQmlAbstractBinding::QmlBinding);
802 const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
803 const auto stackFrame = v4->currentStackFrame;
804 qCInfo(lcBindingRemoval,
805 "Overwriting binding on %s::%s which was initially bound at %s by setting \"%s\" at %s:%d",
806 referenceObject->metaObject()->className(), referenceObject->metaObject()->property(referencePropertyIndex).name(),
807 qPrintable(qmlBinding->expressionIdentifier()),
808 metaObject->property(pd.coreIndex()).name(),
809 qPrintable(stackFrame->source()), stackFrame->lineNumber());
810 }
811 }
812 QQmlPropertyPrivate::removeBinding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd.coreIndex()));
813 }
814 }
815
816 QMetaProperty property = metaObject->property(pd.coreIndex());
817 Q_ASSERT(property.isValid());
818 if (value.isUndefined() && pd.isResettable()) {
819 property.resetOnGadget(reinterpret_cast<QObject *>(r->d()->gadgetPtr()));
820 if (heapObject)
821 r->d()->writeBack(pd.coreIndex());
822 return true;
823 }
824
826
827 if (property.isEnumType() && (QMetaType::Type)v.userType() == QMetaType::Double)
828 v = v.toInt();
829
830 void *gadget = r->d()->gadgetPtr();
831 property.writeOnGadget(gadget, std::move(v));
832
833 if (heapObject)
834 r->d()->writeBack(pd.coreIndex());
835
836 return true;
837}
838
839} // namespace QV4
840
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
\inmodule QtCore\reentrant
Definition qdatetime.h:283
\inmodule QtCore \reentrant
Definition qdatetime.h:29
T fromVariant(const QVariant &value)
Returns the given value converted to the template type {T}.
Definition qjsengine.h:115
\inmodule QtCore\reentrant
Definition qjsonarray.h:18
\inmodule QtCore\reentrant
Definition qjsonobject.h:20
\inmodule QtCore\reentrant
Definition qjsonvalue.h:25
\inmodule QtCore\compares equality \compareswith equality QLine \endcompareswith
Definition qline.h:192
pointer data()
Definition qlist.h:431
\inmodule QtCore
Definition qmetaobject.h:19
bool isValid() const
\inmodule QtCore
\inmodule QtCore
Definition qmetatype.h:341
void destruct(void *data) const
constexpr TypeFlags flags() const
Definition qmetatype.h:2658
QMetaType underlyingType() const
int id(int=0) const
Definition qmetatype.h:475
@ PointerToQObject
Definition qmetatype.h:406
Type
\macro Q_DECLARE_OPAQUE_POINTER(PointerType)
Definition qmetatype.h:345
static bool convert(QMetaType fromType, const void *from, QMetaType toType, void *to)
Converts the object at from from fromType to the preallocated space at to typed toType.
friend class QVariant
Definition qmetatype.h:796
\inmodule QtCore
Definition qobject.h:103
QVariant property(const char *name) const
Returns the value of the object's name property.
Definition qobject.cpp:4323
\inmodule QtCore\reentrant
Definition qpoint.h:217
void setTarget(const QQmlProperty &)
void setBoundFunction(QV4::BoundFunction *boundFunction)
void setSourceLocation(const QQmlSourceLocation &location)
static QQmlBinding * create(const QQmlPropertyData *, const QQmlScriptString &, QObject *, QQmlContext *)
static void resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type, const QMetaObject **metaObject, int *index)
static const QMetaObject * metaObjectForValueType(QMetaType type)
static bool isValueType(QMetaType type)
bool isResettable() const
void setWritable(bool onoff)
void load(const QMetaProperty &)
static void setBinding(QQmlAbstractBinding *binding, BindingFlags flags=None, QQmlPropertyData::WriteFlags writeFlags=QQmlPropertyData::DontRemoveBinding)
static void removeBinding(const QQmlProperty &that)
static QQmlAbstractBinding * binding(QObject *, QQmlPropertyIndex index)
\inmodule QtCore\reentrant
Definition qrect.h:484
\inmodule QtCore \reentrant
\inmodule QtCore
Definition qsize.h:208
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
\inmodule QtCore \reentrant
Definition qdatetime.h:215
\inmodule QtCore
Definition qvariant.h:65
QMetaType metaType() const
const void * constData() const
Definition qvariant.h:451
EGLContext ctx
QDate date
[1]
auto mo
[7]
short next
Definition keywords.cpp:445
Combined button and popup list for selecting options.
static Heap::ReferenceObject::Flags referenceFlags(const QMetaObject *metaObject, int index)
Scoped< FunctionObject > ScopedFunctionObject
quint64 ReturnedValue
Scoped< String > ScopedString
static void doStaticReadCall(const QMetaObject *metaObject, Heap::QQmlValueTypeWrapper *valueTypeWrapper, int index, void **args)
@ Attr_Invalid
@ Attr_Data
Scoped< ExecutionContext > ScopedContext
static ReturnedValue getGadgetProperty(ExecutionEngine *engine, Heap::QQmlValueTypeWrapper *valueTypeWrapper, QMetaType metaType, quint16 coreIndex, bool isFunction, bool isEnum)
static void * context
#define Q_UNLIKELY(x)
DBusConnection const char DBusError * error
static struct AttrInfo attrs[]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qCInfo(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLboolean r
[2]
GLuint object
[3]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLenum type
GLenum target
GLbitfield flags
GLenum GLuint GLsizei propCount
GLuint name
const GLubyte * c
GLenum array
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
#define VALUE_TYPE_LOAD(metatype, cpptype, constructor)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
#define qPrintable(string)
Definition qstring.h:1531
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
unsigned short quint16
Definition qtypes.h:48
size_t quintptr
Definition qtypes.h:167
unsigned long ulong
Definition qtypes.h:35
quint64 qulonglong
Definition qtypes.h:64
unsigned int uint
Definition qtypes.h:34
qint64 qlonglong
Definition qtypes.h:63
#define Q_ALLOCA_ASSIGN(type, name, size)
Definition qv4alloca_p.h:66
#define Q_ALLOCA_DECLARE(type, name)
Definition qv4alloca_p.h:62
#define RETURN_UNDEFINED()
#define DEFINE_OBJECT_VTABLE(classname)
const char property[13]
Definition qwizard.cpp:101
mimeData setData("text/csv", csvData)
obj metaObject() -> className()
QVariant variant
[1]
QDateTime dateTime
[12]
QSharedPointer< T > other(t)
[5]
QFrame frame
[0]
QJSValueList args
QJSEngine engine
[0]
\inmodule QtCore \reentrant
Definition qchar.h:18
static Q_CORE_EXPORT QMetaMethod firstMethod(const QMetaObject *baseObject, QByteArrayView name)
\inmodule QtCore
static int metacall(QObject *, Call, int, void **)
struct QMetaObject::Data d
CppStackFrame * currentStackFrame
QQmlRefPointer< QQmlContextData > callingQmlContext() const
ReturnedValue throwError(const Value &value)
String * id_toString() const
Heap::Object * newObject()
Object * valueTypeWrapperPrototype() const
Heap::String * newString(char16_t c)
static QVariant toVariant(const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols=true)
ReturnedValue throwTypeError()
ReturnedValue(* getter)(Lookup *l, ExecutionEngine *engine, const Value &object)
Definition qv4lookup_p.h:40
struct QV4::Lookup::@583::@601 qgadgetLookup
static bool setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
ExecutionEngine * engine() const
static ReturnedValue create(ExecutionEngine *engine, Heap::Object *wrapper, int index)
~QQmlValueTypeWrapperOwnPropertyKeyIterator() override=default
bool isEqual(const QVariant &value) const
static bool writeBack(HeapObject *ref, int internalIndex=AllProperties)
static bool readReference(HeapObject *ref)
bool hasException() const
ExecutionEngine * engine
static constexpr VTable::GetOwnProperty virtualGetOwnProperty
static constexpr VTable::ResolveLookupGetter virtualResolveLookupGetter
const T * as() const
Definition qv4value_p.h:132
void wrapper()