Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmlglobal.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// Qt-Security score:significant
4
5#include <QtQml/private/qjsvalue_p.h>
6#include <QtQml/private/qqmlglobal_p.h>
7#include <QtQml/private/qqmlmetatype_p.h>
8#include <QtQml/private/qv4qobjectwrapper_p.h>
9#include <QtQml/private/qv4alloca_p.h>
10#include <QtQml/qqmlengine.h>
11
12#include <QtCore/private/qvariant_p.h>
13#include <QtCore/qcoreapplication.h>
14#include <QtCore/qdebug.h>
15#include <QtCore/qstringlist.h>
16
18
19static void printConversionWarning(QV4::ExecutionEngine *engine, const QString &propertyValue,
20 const QString &propertyType, const QString &propertyName) {
21 auto stackTrace = engine->stackTrace(1);
22 QString errorLocation;
23 if (!stackTrace.isEmpty()) {
24 const auto& stackTop = stackTrace[0];
25 errorLocation = QString::fromLatin1("%1:%2: ").arg(stackTop.source, QString::number(stackTop.line));
26 }
27 qWarning().noquote()
28 << QLatin1String("%4Could not convert %1 to %2 for property %3")
29 .arg(propertyValue, propertyType, propertyName, errorLocation);
30}
31
32// Pre-filter the metatype before poking QQmlMetaType::qmlType() and locking its mutex.
33static bool isConstructibleMetaType(const QMetaType metaType)
34{
35 switch (metaType.id()) {
36 // The builtins are not constructible this way.
37 case QMetaType::Void:
38 case QMetaType::Nullptr:
39 case QMetaType::QVariant:
40 case QMetaType::Int:
41 case QMetaType::UInt:
42 case QMetaType::LongLong:
43 case QMetaType::ULongLong:
44 case QMetaType::Float:
45 case QMetaType::Double:
46 case QMetaType::Long:
47 case QMetaType::ULong:
48 case QMetaType::Short:
49 case QMetaType::UShort:
50 case QMetaType::Char:
51 case QMetaType::SChar:
52 case QMetaType::UChar:
53 case QMetaType::QChar:
54 case QMetaType::QString:
55 case QMetaType::Bool:
56 case QMetaType::QDateTime:
57 case QMetaType::QDate:
58 case QMetaType::QTime:
59 case QMetaType::QUrl:
60 case QMetaType::QRegularExpression:
61 case QMetaType::QByteArray:
62 case QMetaType::QLocale:
63 return false;
64 default:
65 break;
66 }
67
68 // QJSValue is also builtin
69 if (metaType == QMetaType::fromType<QJSValue>())
70 return false;
71
72 // We also don't want to construct pointers of any kind, or lists, or enums.
73 if (metaType.flags() &
74 (QMetaType::PointerToQObject
75 | QMetaType::IsEnumeration
76 | QMetaType::SharedPointerToQObject
77 | QMetaType::WeakPointerToQObject
78 | QMetaType::TrackingPointerToQObject
79 | QMetaType::IsUnsignedEnumeration
80 | QMetaType::PointerToGadget
81 | QMetaType::IsPointer
82 | QMetaType::IsQmlList)) {
83 return false;
84 }
85
86 return true;
87}
88
89template<typename JSValue>
90JSValue nullValue()
91{
92 if constexpr (std::is_same_v<JSValue, QJSValue>)
93 return QJSValue::NullValue;
94 if constexpr (std::is_same_v<JSValue, QJSPrimitiveValue>)
95 return QJSPrimitiveNull();
96}
97
98template<typename JSValue>
99bool coerceToJSValue(QMetaType fromType, const void *from, JSValue *to)
100{
101 if (!fromType.isValid()) {
102 *to = JSValue();
103 return true;
104 }
105
106 if ((fromType.flags() & QMetaType::PointerToQObject)
107 && *static_cast<QObject *const *>(from) == nullptr) {
108 *to = nullValue<JSValue>();
109 return true;
110 }
111
112 switch (fromType.id()) {
113 case QMetaType::Void:
114 *to = JSValue();
115 return true;
116 case QMetaType::Bool:
117 *to = JSValue(*static_cast<const bool *>(from));
118 return true;
119 case QMetaType::Int:
120 *to = JSValue(*static_cast<const int *>(from));
121 return true;
122 case QMetaType::Double:
123 *to = JSValue(*static_cast<const double *>(from));
124 return true;
125 case QMetaType::QString:
126 *to = JSValue(*static_cast<const QString *>(from));
127 return true;
128 case QMetaType::Nullptr:
129 *to = nullValue<JSValue>();
130 return true;
131 }
132
133 return false;
134}
135
136static bool coerceValue(
137 QMetaType fromType, const void *from, QMetaType toType, void *to,
138 QV4::ExecutionEngine *engine)
139{
140 // We would like to convert via metaTypeFromJS here, but that would allow conversion of
141 // anything to numbers and strings. That would mean a value type with a ctor that takes
142 // a number or a string would be constructible from any other value. While this would be
143 // quite JavaScript-y, it's probably too permissive here.
144
145 if (QMetaType::convert(fromType, from, toType, to))
146 return true;
147
148 if (toType == QMetaType::fromType<QJSPrimitiveValue>())
149 return coerceToJSValue(fromType, from, static_cast<QJSPrimitiveValue *>(to));
150
151 if (toType == QMetaType::fromType<QJSValue>()) {
152 if (coerceToJSValue(fromType, from, static_cast<QJSValue *>(to)))
153 return true;
154
155 if (!engine)
156 return false;
157
158 QV4::Scope scope(engine);
159 QV4::ScopedValue v(scope, scope.engine->metaTypeToJS(fromType, from));
160 *static_cast<QJSValue *>(to) = QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
161 return true;
162 }
163
164 if (toType == QMetaType::fromType<QJSManagedValue>()) {
165 if (!engine)
166 return false;
167
168 QV4::Scope scope(engine);
169 QV4::ScopedValue v(scope, scope.engine->metaTypeToJS(fromType, from));
170 *static_cast<QJSManagedValue *>(to) = QJSManagedValue(
171 QJSValuePrivate::fromReturnedValue(v->asReturnedValue()), engine->jsEngine());
172 return true;
173 }
174
175
176 return false;
177}
178
179static void *createVariantData(QMetaType type, QVariant *variant)
180{
181 const QtPrivate::QMetaTypeInterface *iface = type.iface();
182 QVariant::Private *d = &variant->data_ptr();
183 Q_ASSERT(d->is_null && !d->is_shared);
184 *d = QVariant::Private(iface);
185 if (QVariant::Private::canUseInternalSpace(iface))
186 return d->data.data;
187
188 // This is not exception safe.
189 // If your value type throws an exception from its ctor bad things will happen anyway.
190 d->data.shared = QVariant::PrivateShared::create(iface->size, iface->alignment);
191 d->is_shared = true;
192 return d->data.shared->data();
193}
194
195static void callConstructor(
196 const QMetaObject *targetMetaObject, int i, void **args, int argc, void *target)
197{
198 Q_ALLOCA_VAR(void *, p, (argc + 1) * sizeof(void *));
199 p[0] = target;
200 memcpy(p + 1, args, argc * sizeof(void *));
201 targetMetaObject->static_metacall(QMetaObject::ConstructInPlace, i, p);
202}
203
204static void callConstructor(
205 const QMetaObject *targetMetaObject, int i, void *source, void *target)
206{
207 void *p[] = { target, source };
208 targetMetaObject->static_metacall(QMetaObject::ConstructInPlace, i, p);
209}
210
211
212template<typename Allocate>
214 const QMetaObject *targetMetaObject, int ctorIndex, void **args,
215 Allocate &&allocate)
216{
217 const QMetaMethod ctor = targetMetaObject->constructor(ctorIndex);
218 callConstructor(targetMetaObject, ctorIndex, args, ctor.parameterCount(), allocate());
219}
220
221
222template<typename Allocate, typename Retrieve>
224 const QMetaObject *targetMetaObject, Allocate &&allocate, Retrieve &&retrieve,
225 QV4::ExecutionEngine *engine)
226{
227 const int end = targetMetaObject->constructorCount();
228 for (int i = 0; i < end; ++i) {
229 // Try construction from exact matches. (Score 0)
230 const QMetaMethod ctor = targetMetaObject->constructor(i);
231 if (ctor.parameterCount() != 1)
232 continue;
233
234 if (retrieve([&](QMetaType sourceMetaType, void *sourceData) {
235 if (sourceMetaType != ctor.parameterMetaType(0))
236 return false;
237 callConstructor(targetMetaObject, i, sourceData, allocate());
238 return true;
239 })) {
240 return true;
241 }
242 }
243
244 for (int i = 0; i < end; ++i) {
245 // Try construction from derived types. (Score 1)
246 const QMetaMethod ctor = targetMetaObject->constructor(i);
247 if (ctor.parameterCount() != 1)
248 continue;
249
250 const QMetaType parameterType = ctor.parameterMetaType(0);
251 const QMetaObject *parameterMetaObject = parameterType.metaObject();
252 if (!parameterMetaObject)
253 continue;
254
255 if (retrieve([&](QMetaType sourceMetaType, void *sourceData) {
256 Q_ASSERT(sourceMetaType != parameterType);
257 if (const QMetaObject *sourceMetaObject = sourceMetaType.metaObject();
258 sourceMetaObject && sourceMetaObject->inherits(parameterMetaObject)) {
259 callConstructor(targetMetaObject, i, sourceData, allocate());
260 return true;
261 }
262 return false;
263 })) {
264 return true;
265 }
266 }
267
268 for (int i = 0; i < end; ++i) {
269 // Try construction from converted types.
270 // Do not recursively try to create parameters here. This may end up in infinite recursion.
271
272 const QMetaMethod ctor = targetMetaObject->constructor(i);
273 if (ctor.parameterCount() != 1)
274 continue;
275
276 const QMetaType parameterType = ctor.parameterMetaType(0);
277
278 if (retrieve([&](QMetaType sourceMetaType, void *sourceData) {
279 QVariant converted(parameterType);
280 if (coerceValue(sourceMetaType, sourceData, parameterType, converted.data(), engine)) {
281 callConstructor(targetMetaObject, i, converted.data(), allocate());
282 return true;
283 }
284
285 return false;
286 })) {
287 return true;
288 }
289 }
290
291 return false;
292}
293
294template<typename Allocate>
296 const QMetaObject *targetMetaObject, const QV4::Value &source, Allocate &&allocate,
297 QV4::ExecutionEngine *engine)
298{
299 QVariant variant;
300 return fromMatchingType(targetMetaObject, std::forward<Allocate>(allocate), [&](auto callback) {
301 if (!variant.isValid())
302 variant = QV4::ExecutionEngine::toVariant(source, QMetaType());
303 return callback(variant.metaType(), variant.data());
304 }, engine);
305}
306
307template<typename Allocate>
309 const QMetaObject *targetMetaObject, QVariant source, Allocate &&allocate,
310 QV4::ExecutionEngine *engine)
311{
312 return fromMatchingType(targetMetaObject, std::forward<Allocate>(allocate), [&](auto callback) {
313 return callback(source.metaType(), source.data());
314 }, engine);
315}
316
317template<typename Allocate>
318static bool fromString(const QMetaObject *mo, QString s, Allocate &&allocate)
319{
320 for (int i = 0, end = mo->constructorCount(); i < end; ++i) {
321 const QMetaMethod ctor = mo->constructor(i);
322 if (ctor.parameterCount() != 1)
323 continue;
324
325 if (ctor.parameterMetaType(0) == QMetaType::fromType<QString>()) {
326 callConstructor(mo, i, &s, allocate());
327 return true;
328 }
329 }
330
331 return false;
332}
333
334template<typename Get, typename Convert>
335static bool doWriteProperty(
336 const QMetaProperty &metaProperty, void *target, Get &&get, Convert &&convert,
337 QV4::ExecutionEngine *engine)
338{
339 const QMetaType propertyType = metaProperty.metaType();
340 QVariant property = get(propertyType);
341 if (property.metaType() == propertyType) {
342 metaProperty.writeOnGadget(target, std::move(property));
343 return true;
344 }
345
346 QVariant converted = convert(propertyType);
347 if (converted.isValid()) {
348 metaProperty.writeOnGadget(target, std::move(converted));
349 return true;
350 }
351
352 converted = QVariant(propertyType);
353 if (coerceValue(
354 property.metaType(), property.constData(), propertyType, converted.data(),
355 engine)) {
356 metaProperty.writeOnGadget(target, std::move(converted));
357 return true;
358 }
359
360 return false;
361}
362
364 const QMetaObject *targetMetaObject, void *target, const QV4::Value &source,
365 QV4::ExecutionEngine *engine)
366{
367 const QV4::Object *o = static_cast<const QV4::Object *>(&source);
368 QV4::Scope scope(o->engine());
369 QV4::ScopedObject object(scope, o);
370
371 for (int i = 0; i < targetMetaObject->propertyCount(); ++i) {
372 const QMetaProperty metaProperty = targetMetaObject->property(i);
373 const QString propertyName = QString::fromUtf8(metaProperty.name());
374
375 QV4::ScopedString v4PropName(scope, scope.engine->newString(propertyName));
376 QV4::ScopedValue v4PropValue(scope, object->get(v4PropName));
377
378 // We assume that data is freshly constructed.
379 // There is no point in reset()'ing properties of a freshly created object.
380 if (v4PropValue->isUndefined())
381 continue;
382
383 if (doWriteProperty(metaProperty, target, [&](const QMetaType &propertyType) {
384 return QV4::ExecutionEngine::toVariant(v4PropValue, propertyType);
385 }, [&](const QMetaType &propertyType) {
386 return QQmlValueTypeProvider::createValueType(v4PropValue, propertyType, engine);
387 }, engine)) {
388 continue;
389 }
390
391 const QMetaType propertyType = metaProperty.metaType();
392 QVariant property = QV4::ExecutionEngine::toVariant(v4PropValue, propertyType);
393 if (property.metaType() == propertyType) {
394 metaProperty.writeOnGadget(target, std::move(property));
395 continue;
396 }
397
398 QVariant converted = QQmlValueTypeProvider::createValueType(
399 v4PropValue, propertyType, engine);
400 if (converted.isValid()) {
401 metaProperty.writeOnGadget(target, std::move(converted));
402 continue;
403 }
404
405 converted = QVariant(propertyType);
406 if (coerceValue(
407 property.metaType(), property.constData(), propertyType, converted.data(),
408 engine)) {
409 metaProperty.writeOnGadget(target, std::move(converted));
410 continue;
411 }
412
413 printConversionWarning(engine, v4PropValue->toQStringNoThrow(),
414 QString::fromUtf8(propertyType.name()), propertyName);
415 }
416}
417
419 const QMetaObject *targetMetaObject, QMetaType metaType, const QV4::Value &source,
420 QV4::ExecutionEngine *engine)
421{
422 if (!source.isObject() || !targetMetaObject)
423 return QVariant();
424
425 QVariant result(metaType);
426 doWriteProperties(targetMetaObject, result.data(), source, engine);
427 return result;
428}
429
430template<typename Read>
432 const QMetaObject *targetMetaObject, void *target,
433 const QMetaObject *sourceMetaObject, Read &&read, QV4::ExecutionEngine *engine)
434{
435 for (int i = 0; i < targetMetaObject->propertyCount(); ++i) {
436 const QMetaProperty metaProperty = targetMetaObject->property(i);
437
438 const int sourceProperty = sourceMetaObject->indexOfProperty(metaProperty.name());
439
440 // We assume that data is freshly constructed.
441 // There is no point in reset()'ing properties of a freshly created object.
442 if (sourceProperty == -1)
443 continue;
444
445 const QMetaType propertyType = metaProperty.metaType();
446 QVariant property = read(sourceMetaObject, sourceProperty);
447 if (property.metaType() == propertyType) {
448 metaProperty.writeOnGadget(target, std::move(property));
449 continue;
450 }
451
452 QVariant converted = QQmlValueTypeProvider::createValueType(property, propertyType, engine);
453 if (converted.isValid()) {
454 metaProperty.writeOnGadget(target, std::move(converted));
455 continue;
456 }
457
458 converted = QVariant(propertyType);
459 if (coerceValue(
460 property.metaType(), property.constData(), propertyType, converted.data(),
461 engine)) {
462 metaProperty.writeOnGadget(target, std::move(converted));
463 continue;
464 }
465
466 printConversionWarning(engine, QDebug::toString(property),
467 QString::fromUtf8(propertyType.name()),
468 QString::fromUtf8(metaProperty.name()));
469 }
470}
471
472
474 const QMetaObject *targetMeta, void *target, QObject *source, QV4::ExecutionEngine *engine)
475{
476 doWriteProperties(
477 targetMeta, target, source->metaObject(),
478 [source](const QMetaObject *sourceMetaObject, int sourceProperty) {
479 return sourceMetaObject->property(sourceProperty).read(source);
480 }, engine);
481}
482
484 const QMetaObject *targetMetaObject, QMetaType targetMetaType, QObject *source,
485 QV4::ExecutionEngine *engine)
486{
487 if (!source || !targetMetaObject)
488 return QVariant();
489
490 QVariant result(targetMetaType);
491 doWriteProperties(targetMetaObject, result.data(), source, engine);
492 return result;
493}
494
496 const QMetaObject *targetMetaObject, QMetaType targetMetaType,
497 const QMetaObject *sourceMetaObject, const void *source, QV4::ExecutionEngine *engine)
498{
499 if (!source || !sourceMetaObject || !targetMetaObject)
500 return QVariant();
501
502 QVariant result(targetMetaType);
503 doWriteProperties(
504 targetMetaObject, result.data(), sourceMetaObject,
505 [source](const QMetaObject *sourceMetaObject, int sourceProperty) {
506 return sourceMetaObject->property(sourceProperty).readOnGadget(source);
507 }, engine);
508 return result;
509}
510
511template<typename Map>
513 const QMetaObject *targetMetaObject, void *target, const Map &source,
514 QV4::ExecutionEngine *engine)
515{
516 for (int i = 0; i < targetMetaObject->propertyCount(); ++i) {
517 const QMetaProperty metaProperty = targetMetaObject->property(i);
518
519 // We assume that data is freshly constructed.
520 // There is no point in reset()'ing properties of a freshly created object.
521 const auto it = source.constFind(QString::fromUtf8(metaProperty.name()));
522 if (it == source.constEnd())
523 continue;
524
525 const QMetaType propertyType = metaProperty.metaType();
526 QVariant property = *it;
527 if (property.metaType() == propertyType) {
528 metaProperty.writeOnGadget(target, std::move(property));
529 continue;
530 }
531
532 QVariant converted = QQmlValueTypeProvider::createValueType(property, propertyType, engine);
533 if (converted.isValid()) {
534 metaProperty.writeOnGadget(target, std::move(converted));
535 continue;
536 }
537
538 converted = QVariant(propertyType);
539 if (coerceValue(
540 property.metaType(), property.constData(), propertyType, converted.data(),
541 engine)) {
542 metaProperty.writeOnGadget(target, std::move(converted));
543 continue;
544 }
545
546 printConversionWarning(engine, QDebug::toString(property),
547 QString::fromUtf8(propertyType.name()),
548 QString::fromUtf8(metaProperty.name()));
549 }
550}
551
552template<typename Map>
554 const QMetaObject *targetMetaObject, QMetaType targetMetaType, const Map &source,
555 QV4::ExecutionEngine *engine)
556{
557 QVariant result(targetMetaType);
558 doWriteProperties(targetMetaObject, result.data(), source, engine);
559 return result;
560}
561
563 const QMetaObject *targetMetaObject, QMetaType targetMetaType, const QVariant &source,
564 QV4::ExecutionEngine *engine)
565{
566 if (!targetMetaObject)
567 return QVariant();
568
569 if (source.metaType() == QMetaType::fromType<QJSValue>()) {
570 QJSValue val = source.value<QJSValue>();
571 // Generally, the GC might collect a Value at any point so that
572 // a `ScopedValue` should be used.
573 // In this case, the Value is tied to a `QJSValue` which is
574 // persistent to the GC and thus fromReturnedValue is safe.
575 return byProperties(
576 targetMetaObject, targetMetaType,
577 QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(&val)),
578 engine);
579 }
580
581 if (source.metaType() == QMetaType::fromType<QVariantMap>()) {
582 return byProperties(
583 targetMetaObject, targetMetaType,
584 *static_cast<const QVariantMap *>(source.constData()), engine);
585 }
586
587 if (source.metaType() == QMetaType::fromType<QVariantHash>()) {
588 return byProperties(
589 targetMetaObject, targetMetaType,
590 *static_cast<const QVariantHash *>(source.constData()), engine);
591 }
592
593 if (source.metaType().flags() & QMetaType::PointerToQObject)
594 return byProperties(targetMetaObject, targetMetaType, source.value<QObject *>(), engine);
595
596 if (const QMetaObject *sourceMeta = QQmlMetaType::metaObjectForValueType(source.metaType())) {
597 return byProperties(
598 targetMetaObject, targetMetaType, sourceMeta, source.constData(), engine);
599 }
600
601 return QVariant();
602}
603
604template<typename Allocate, typename DefaultConstruct>
606 const QQmlType &targetType, const QV4::Value &source,
607 Allocate &&allocate, DefaultConstruct &&defaultConstruct, QV4::ExecutionEngine *engine)
608{
609 const auto warn = [&](const QMetaObject *targetMetaObject) {
610 qWarning().noquote()
611 << "Could not find any constructor for value type"
612 << targetMetaObject->className() << "to call with value"
613 << source.toQStringNoThrow();
614 };
615
616 if (targetType.canPopulateValueType()) {
617 if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
618 if (source.isObject()) {
619 doWriteProperties(targetMetaObject, defaultConstruct(), source, engine);
620 return true;
621 }
622 if (targetType.canConstructValueType()) {
623 if (fromMatchingType(targetMetaObject, source, allocate, engine))
624 return true;
625 warn(targetMetaObject);
626 }
627 }
628 } else if (targetType.canConstructValueType()) {
629 if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
630 if (fromMatchingType(targetMetaObject, source, allocate, engine))
631 return true;
632 warn(targetMetaObject);
633 }
634 }
635
636 if (const auto valueTypeFunction = targetType.createValueTypeFunction()) {
637 const QVariant result
638 = valueTypeFunction(QJSValuePrivate::fromReturnedValue(source.asReturnedValue()));
639 const QMetaType resultType = result.metaType();
640 if (resultType == targetType.typeId()) {
641 resultType.construct(allocate(), result.constData());
642 return true;
643 }
644 }
645
646 return false;
647}
648
649template<typename Allocate, typename DefaultConstruct>
651 const QQmlType &targetType, QMetaType sourceMetaType, void *source,
652 Allocate &&allocate, DefaultConstruct &&defaultConstruct, QV4::ExecutionEngine *engine)
653{
654
655 const auto warn = [&](const QMetaObject *targetMetaObject) {
656 qWarning().noquote()
657 << "Could not find any constructor for value type"
658 << targetMetaObject->className() << "to call with value" << source;
659 };
660
661 if (targetType.canPopulateValueType()) {
662 if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
663 if (const QMetaObject *sourceMetaObject
664 = QQmlMetaType::metaObjectForValueType(sourceMetaType)) {
665 doWriteProperties(
666 targetMetaObject, defaultConstruct(), sourceMetaObject,
667 [&source](const QMetaObject *sourceMetaObject, int sourceProperty) {
668 return sourceMetaObject->property(sourceProperty).readOnGadget(source);
669 }, engine);
670 return true;
671 }
672
673 if (sourceMetaType == QMetaType::fromType<QVariantMap>()) {
674 doWriteProperties(
675 targetMetaObject, defaultConstruct(),
676 *static_cast<const QVariantMap *>(source), engine);
677 return true;
678 }
679
680 if (sourceMetaType == QMetaType::fromType<QVariantHash>()) {
681 doWriteProperties(
682 targetMetaObject, defaultConstruct(),
683 *static_cast<const QVariantHash *>(source), engine);
684 return true;
685 }
686
687 if (sourceMetaType.flags() & QMetaType::PointerToQObject) {
688 doWriteProperties(
689 targetMetaObject, defaultConstruct(),
690 *static_cast<QObject *const *>(source), engine);
691 return true;
692 }
693 }
694 }
695
696 if (targetType.canConstructValueType()) {
697 if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
698 if (fromMatchingType(
699 targetMetaObject, std::forward<Allocate>(allocate), [&](auto callback) {
700 return callback(sourceMetaType, source);
701 }, engine)) {
702 return true;
703 }
704 warn(targetMetaObject);
705 }
706 }
707
708 return false;
709}
710
711/*!
712 * \internal
713 * Populate the value type in place at \a target, which is expected to be
714 * allocated and default-constructed, for example the result of a QVariant(QMetaType).
715 * This is efficient if we can do byProperties() since it can use the pre-constructed object.
716 * It also avoids the creation of a QVariant in most cases. It is not
717 * efficient if you're going to create a QVariant anyway.
718 */
719bool QQmlValueTypeProvider::populateValueType(
720 QMetaType targetMetaType, void *target, QMetaType sourceMetaType, void *source,
721 QV4::ExecutionEngine *engine)
722{
723 if (sourceMetaType == QMetaType::fromType<QJSValue>()) {
724 const QJSValue *val = static_cast<const QJSValue *>(source);
725 // Generally, the GC might collect a Value at any point so that
726 // a `ScopedValue` should be used.
727 // In this case, the Value is tied to a `QJSValue` which is
728 // persistent to the GC and thus fromReturnedValue is safe.
729 return populateValueType(
730 targetMetaType, target,
731 QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(val)),
732 engine);
733 }
734
735 if (!isConstructibleMetaType(targetMetaType))
736 return false;
737
738 return createOrConstructValueType(
739 QQmlMetaType::qmlType(targetMetaType), sourceMetaType, source,
740 [targetMetaType, target]() {
741 targetMetaType.destruct(target);
742 return target;
743 }, [target]() {
744 return target;
745 }, engine);
746}
747
748/*!
749 * \internal
750 * Populate the value type in place at \a target, which is expected to be
751 * allocated and default-constructed, for example the result of a QVariant(QMetaType).
752 * This is efficient if we can do byProperties() since it can use the pre-constructed object.
753 * It also avoids the creation of a QVariant in most cases. It is not
754 * efficient if you're going to create a QVariant anyway.
755 */
756bool QQmlValueTypeProvider::populateValueType(
757 QMetaType targetMetaType, void *target, const QV4::Value &source,
758 QV4::ExecutionEngine *engine)
759{
760 if (!isConstructibleMetaType(targetMetaType))
761 return false;
762
763 return createOrConstructValueType(
764 QQmlMetaType::qmlType(targetMetaType), source, [targetMetaType, target]() {
765 targetMetaType.destruct(target);
766 return target;
767 }, [target]() {
768 return target;
769 }, engine);
770}
771
772/*!
773 * \internal
774 * Specialization that constructs the value type on the heap using new and returns a pointer to it.
775 */
776void *QQmlValueTypeProvider::heapCreateValueType(
777 const QQmlType &targetType, const QV4::Value &source, QV4::ExecutionEngine *engine)
778{
779 void *target = nullptr;
780 if (createOrConstructValueType(
781 targetType, source, [&]() {
782 const QMetaType metaType = targetType.typeId();
783 const ushort align = metaType.alignOf();
784 target = align > __STDCPP_DEFAULT_NEW_ALIGNMENT__
785 ? operator new(metaType.sizeOf(), std::align_val_t(align))
786 : operator new(metaType.sizeOf());
787 return target;
788 }, [&]() {
789 target = targetType.typeId().create();
790 return target;
791 }, engine)) {
792 Q_ASSERT(target != nullptr);
793 }
794
795 return target;
796}
797
798QVariant QQmlValueTypeProvider::constructValueType(
799 QMetaType targetMetaType, const QMetaObject *targetMetaObject,
800 int ctorIndex, void **args)
801{
802 QVariant result;
803 fromVerifiedType(targetMetaObject, ctorIndex, args,
804 [&]() { return createVariantData(targetMetaType, &result); });
805 return result;
806}
807
808static QVariant fromJSValue(const QQmlType &type, const QJSValue &s, QMetaType metaType)
809{
810 if (const auto valueTypeFunction = type.createValueTypeFunction()) {
811 const QVariant result = valueTypeFunction(s);
812 if (result.metaType() == metaType)
813 return result;
814 }
815
816 return QVariant();
817}
818
819QVariant QQmlValueTypeProvider::createValueType(const QJSValue &s, QMetaType metaType)
820{
821 if (!isConstructibleMetaType(metaType))
822 return QVariant();
823 return fromJSValue(QQmlMetaType::qmlType(metaType), s, metaType);
824}
825
826QVariant QQmlValueTypeProvider::createValueType(const QString &s, QMetaType metaType)
827{
828 if (!isConstructibleMetaType(metaType))
829 return QVariant();
830 const QQmlType type = QQmlMetaType::qmlType(metaType);
831 if (type.canConstructValueType()) {
832 if (const QMetaObject *mo = type.metaObjectForValueType()) {
833 QVariant result;
834 if (fromString(mo, s, [&]() { return createVariantData(metaType, &result); }))
835 return result;
836 }
837 }
838
839 return fromJSValue(type, s, metaType);
840}
841
842QVariant QQmlValueTypeProvider::createValueType(
843 const QV4::Value &s, QMetaType metaType, QV4::ExecutionEngine *engine)
844{
845 if (!isConstructibleMetaType(metaType))
846 return QVariant();
847 const QQmlType type = QQmlMetaType::qmlType(metaType);
848 const auto warn = [&](const QMetaObject *mo) {
849 qWarning().noquote()
850 << "Could not find any constructor for value type"
851 << mo->className() << "to call with value" << s.toQStringNoThrow();
852 };
853
854 if (type.canPopulateValueType()) {
855 if (const QMetaObject *mo = type.metaObject()) {
856 QVariant result = byProperties(mo, metaType, s, engine);
857 if (result.isValid())
858 return result;
859 if (type.canConstructValueType()) {
860 if (fromMatchingType(
861 mo, s, [&]() { return createVariantData(metaType, &result); },
862 engine)) {
863 return result;
864 }
865 warn(mo);
866 }
867 }
868 } else if (type.canConstructValueType()) {
869 if (const QMetaObject *mo = type.metaObject()) {
870 QVariant result;
871 if (fromMatchingType(
872 mo, s, [&]() { return createVariantData(metaType, &result); },
873 engine)) {
874 return result;
875 }
876 warn(mo);
877 }
878 }
879
880 return fromJSValue(type, QJSValuePrivate::fromReturnedValue(s.asReturnedValue()), metaType);
881
882}
883
884/*!
885 * \internal
886 * This should only be called with either builtin types or wrapped QJSValues as source.
887 */
888QVariant QQmlValueTypeProvider::createValueType(
889 const QVariant &s, QMetaType metaType, QV4::ExecutionEngine *engine)
890{
891 if (!isConstructibleMetaType(metaType))
892 return QVariant();
893 const QQmlType type = QQmlMetaType::qmlType(metaType);
894 const auto warn = [&](const QMetaObject *mo) {
895 qWarning().noquote()
896 << "Could not find any constructor for value type"
897 << mo->className() << "to call with value" << s;
898 };
899
900 if (type.canPopulateValueType()) {
901 if (const QMetaObject *mo = type.metaObjectForValueType()) {
902 QVariant result = byProperties(mo, metaType, s, engine);
903 if (result.isValid())
904 return result;
905 if (type.canConstructValueType()) {
906 if (fromMatchingType(
907 mo, s, [&]() { return createVariantData(metaType, &result); },
908 engine)) {
909 return result;
910 }
911 warn(mo);
912 }
913 }
914 } else if (type.canConstructValueType()) {
915 if (const QMetaObject *mo = type.metaObjectForValueType()) {
916 QVariant result;
917 if (fromMatchingType(
918 mo, s, [&]() { return createVariantData(metaType, &result); },
919 engine)) {
920 return result;
921 }
922 warn(mo);
923 }
924 }
925
926 return QVariant();
927}
928
929QQmlColorProvider::~QQmlColorProvider() {}
930QVariant QQmlColorProvider::colorFromString(const QString &, bool *ok) { if (ok) *ok = false; return QVariant(); }
931unsigned QQmlColorProvider::rgbaFromString(const QString &, bool *ok) { if (ok) *ok = false; return 0; }
932QVariant QQmlColorProvider::fromRgbF(double, double, double, double) { return QVariant(); }
933QVariant QQmlColorProvider::fromHslF(double, double, double, double) { return QVariant(); }
934QVariant QQmlColorProvider::fromHsvF(double, double, double, double) { return QVariant(); }
935QVariant QQmlColorProvider::lighter(const QVariant &, qreal) { return QVariant(); }
936QVariant QQmlColorProvider::darker(const QVariant &, qreal) { return QVariant(); }
937QVariant QQmlColorProvider::alpha(const QVariant &, qreal)
938{
939 return QVariant();
940}
941QVariant QQmlColorProvider::tint(const QVariant &, const QVariant &) { return QVariant(); }
942
944
945Q_QML_EXPORT QQmlColorProvider *QQml_setColorProvider(QQmlColorProvider *newProvider)
946{
947 QQmlColorProvider *old = colorProvider;
948 colorProvider = newProvider;
949 return old;
950}
951
953{
954 if (colorProvider == nullptr) {
955 qWarning() << "Warning: QQml_colorProvider: no color provider has been set!";
956 static QQmlColorProvider nullColorProvider;
957 colorProvider = &nullColorProvider;
958 }
959
960 return &colorProvider;
961}
962
963Q_AUTOTEST_EXPORT QQmlColorProvider *QQml_colorProvider(void)
964{
965 static QQmlColorProvider **providerPtr = getColorProvider();
966 return *providerPtr;
967}
968
969
970QQmlGuiProvider::~QQmlGuiProvider() {}
971QQmlApplication *QQmlGuiProvider::application(QObject *parent)
972{
973 return new QQmlApplication(parent);
974}
975QStringList QQmlGuiProvider::fontFamilies() { return QStringList(); }
976bool QQmlGuiProvider::openUrlExternally(const QUrl &) { return false; }
977
978QObject *QQmlGuiProvider::inputMethod()
979{
980 // We don't have any input method code by default
981 QObject *o = new QObject();
982 o->setObjectName(QStringLiteral("No inputMethod available"));
983 QQmlEngine::setObjectOwnership(o, QQmlEngine::JavaScriptOwnership);
984 return o;
985}
986
987QObject *QQmlGuiProvider::styleHints()
988{
989 QObject *o = new QObject();
990 o->setObjectName(QStringLiteral("No styleHints available"));
991 QQmlEngine::setObjectOwnership(o, QQmlEngine::JavaScriptOwnership);
992 return o;
993}
994
995QString QQmlGuiProvider::pluginName() const { return QString(); }
996
997static QQmlGuiProvider *guiProvider = nullptr;
998
999Q_QML_EXPORT QQmlGuiProvider *QQml_setGuiProvider(QQmlGuiProvider *newProvider)
1000{
1001 QQmlGuiProvider *old = guiProvider;
1002 guiProvider = newProvider;
1003 return old;
1004}
1005
1007{
1008 if (guiProvider == nullptr) {
1009 static QQmlGuiProvider nullGuiProvider; //Still provides an application with no GUI support
1010 guiProvider = &nullGuiProvider;
1011 }
1012
1013 return &guiProvider;
1014}
1015
1016Q_AUTOTEST_EXPORT QQmlGuiProvider *QQml_guiProvider(void)
1017{
1018 static QQmlGuiProvider **providerPtr = getGuiProvider();
1019 return *providerPtr;
1020}
1021
1022//Docs in qqmlengine.cpp
1023QQmlApplication::QQmlApplication(QObject *parent)
1024 : QQmlApplication(*(new QQmlApplicationPrivate), parent)
1025{
1026}
1027
1028QQmlApplication::QQmlApplication(QQmlApplicationPrivate &dd, QObject *parent)
1029 : QObject(dd, parent)
1030{
1031 connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()),
1032 this, SIGNAL(aboutToQuit()));
1033 connect(QCoreApplication::instance(), SIGNAL(applicationNameChanged()),
1034 this, SIGNAL(nameChanged()));
1035 connect(QCoreApplication::instance(), SIGNAL(applicationVersionChanged()),
1036 this, SIGNAL(versionChanged()));
1037 connect(QCoreApplication::instance(), SIGNAL(organizationNameChanged()),
1038 this, SIGNAL(organizationChanged()));
1039 connect(QCoreApplication::instance(), SIGNAL(organizationDomainChanged()),
1040 this, SIGNAL(domainChanged()));
1041}
1042
1043QStringList QQmlApplication::args()
1044{
1045 Q_D(QQmlApplication);
1046 if (!d->argsInit) {
1047 d->argsInit = true;
1048 d->args = QCoreApplication::arguments();
1049 }
1050 return d->args;
1051}
1052
1053QString QQmlApplication::name() const
1054{
1055 return QCoreApplication::instance()->applicationName();
1056}
1057
1058QString QQmlApplication::version() const
1059{
1060 return QCoreApplication::instance()->applicationVersion();
1061}
1062
1063QString QQmlApplication::organization() const
1064{
1065 return QCoreApplication::instance()->organizationName();
1066}
1067
1068QString QQmlApplication::domain() const
1069{
1070 return QCoreApplication::instance()->organizationDomain();
1071}
1072
1073void QQmlApplication::setName(const QString &arg)
1074{
1075 QCoreApplication::instance()->setApplicationName(arg);
1076}
1077
1078void QQmlApplication::setVersion(const QString &arg)
1079{
1080 QCoreApplication::instance()->setApplicationVersion(arg);
1081}
1082
1083void QQmlApplication::setOrganization(const QString &arg)
1084{
1085 QCoreApplication::instance()->setOrganizationName(arg);
1086}
1087
1088void QQmlApplication::setDomain(const QString &arg)
1089{
1090 QCoreApplication::instance()->setOrganizationDomain(arg);
1091}
1092
1093static const QQmlData *ddata_for_cast(QObject *object)
1094{
1095 Q_ASSERT(object);
1096 auto ddata = QQmlData::get(object, false);
1097 return (ddata && ddata->propertyCache) ? ddata : nullptr;
1098}
1099
1100bool qmlobject_can_cpp_cast(QObject *object, const QMetaObject *mo)
1101{
1102 Q_ASSERT(mo);
1103 if (const QQmlData *ddata = ddata_for_cast(object))
1104 return ddata->propertyCache->firstCppMetaObject()->inherits(mo);
1105 return object->metaObject()->inherits(mo);
1106}
1107
1108bool qmlobject_can_qml_cast(QObject *object, const QQmlType &type)
1109{
1110 Q_ASSERT(type.isValid());
1111
1112 // A non-composite type will always have a metaobject.
1113 const QMetaObject *typeMetaObject = type.metaObject();
1114 const QQmlPropertyCache::ConstPtr typePropertyCache = typeMetaObject
1115 ? QQmlPropertyCache::ConstPtr()
1116 : QQmlMetaType::findPropertyCacheInCompositeTypes(type.typeId());
1117
1118 if (const QQmlData *ddata = ddata_for_cast(object)) {
1119 for (const QQmlPropertyCache *propertyCache = ddata->propertyCache.data(); propertyCache;
1120 propertyCache = propertyCache->parent().data()) {
1121
1122 if (typeMetaObject) {
1123 // Prefer the metaobject inheritance mechanism, since it is more accurate.
1124 //
1125 // Assume the object can be casted to the type. Then, if we have a type metaobject,
1126 // the object's property cache inheritance has to contain it. Otherwise we would
1127 // end up with diverging metaobject hierarchies if we created the object's
1128 // metaobject. This would be a disaster.
1129 if (const QMetaObject *objectMetaObject = propertyCache->metaObject())
1130 return objectMetaObject->inherits(typeMetaObject);
1131 } else {
1132 // This is a best effort attempt. There are a number of ways for the
1133 // property caches to be unrelated but the types still convertible.
1134 // Multiple property caches can hold the same metaobject, for example for
1135 // versions of non-composite types.
1136 if (propertyCache == typePropertyCache.data())
1137 return true;
1138 }
1139 }
1140 }
1141
1142 // If nothing else works, we have to create the metaobjects.
1143
1144 return object->metaObject()->inherits(typeMetaObject
1145 ? typeMetaObject
1146 : (typePropertyCache ? typePropertyCache->createMetaObject() : nullptr));
1147}
1148
1149QT_END_NAMESPACE
1150
1151#include "moc_qqmlglobal_p.cpp"
static void doWriteProperties(const QMetaObject *targetMetaObject, void *target, const QV4::Value &source, QV4::ExecutionEngine *engine)
static QQmlGuiProvider ** getGuiProvider(void)
static bool fromMatchingType(const QMetaObject *targetMetaObject, QVariant source, Allocate &&allocate, QV4::ExecutionEngine *engine)
static bool fromMatchingType(const QMetaObject *targetMetaObject, const QV4::Value &source, Allocate &&allocate, QV4::ExecutionEngine *engine)
JSValue nullValue()
static bool fromMatchingType(const QMetaObject *targetMetaObject, Allocate &&allocate, Retrieve &&retrieve, QV4::ExecutionEngine *engine)
bool coerceToJSValue(QMetaType fromType, const void *from, JSValue *to)
static void callConstructor(const QMetaObject *targetMetaObject, int i, void *source, void *target)
static void callConstructor(const QMetaObject *targetMetaObject, int i, void **args, int argc, void *target)
static void doWriteProperties(const QMetaObject *targetMetaObject, void *target, const QMetaObject *sourceMetaObject, Read &&read, QV4::ExecutionEngine *engine)
bool createOrConstructValueType(const QQmlType &targetType, const QV4::Value &source, Allocate &&allocate, DefaultConstruct &&defaultConstruct, QV4::ExecutionEngine *engine)
static QVariant fromJSValue(const QQmlType &type, const QJSValue &s, QMetaType metaType)
static bool fromString(const QMetaObject *mo, QString s, Allocate &&allocate)
static QVariant byProperties(const QMetaObject *targetMetaObject, QMetaType targetMetaType, const QMetaObject *sourceMetaObject, const void *source, QV4::ExecutionEngine *engine)
static void fromVerifiedType(const QMetaObject *targetMetaObject, int ctorIndex, void **args, Allocate &&allocate)
bool createOrConstructValueType(const QQmlType &targetType, QMetaType sourceMetaType, void *source, Allocate &&allocate, DefaultConstruct &&defaultConstruct, QV4::ExecutionEngine *engine)
static QVariant byProperties(const QMetaObject *targetMetaObject, QMetaType metaType, const QV4::Value &source, QV4::ExecutionEngine *engine)
void doWriteProperties(const QMetaObject *targetMetaObject, void *target, const Map &source, QV4::ExecutionEngine *engine)
static QQmlColorProvider ** getColorProvider(void)
static bool coerceValue(QMetaType fromType, const void *from, QMetaType toType, void *to, QV4::ExecutionEngine *engine)
static void doWriteProperties(const QMetaObject *targetMeta, void *target, QObject *source, QV4::ExecutionEngine *engine)
QVariant byProperties(const QMetaObject *targetMetaObject, QMetaType targetMetaType, const Map &source, QV4::ExecutionEngine *engine)
static QQmlGuiProvider * guiProvider
static bool doWriteProperty(const QMetaProperty &metaProperty, void *target, Get &&get, Convert &&convert, QV4::ExecutionEngine *engine)
static QVariant byProperties(const QMetaObject *targetMetaObject, QMetaType targetMetaType, QObject *source, QV4::ExecutionEngine *engine)
static const QQmlData * ddata_for_cast(QObject *object)
bool qmlobject_can_qml_cast(QObject *object, const QQmlType &type)
static bool isConstructibleMetaType(const QMetaType metaType)
static QT_BEGIN_NAMESPACE void printConversionWarning(QV4::ExecutionEngine *engine, const QString &propertyValue, const QString &propertyType, const QString &propertyName)
static QQmlColorProvider * colorProvider
static void * createVariantData(QMetaType type, QVariant *variant)
Q_QML_EXPORT bool qmlobject_can_cpp_cast(QObject *object, const QMetaObject *mo)