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_INIT();
199 Q_ALLOCA_VAR(void *, p, (argc + 1) * sizeof(void *));
200 p[0] = target;
201 memcpy(p + 1, args, argc * sizeof(void *));
202 targetMetaObject->static_metacall(QMetaObject::ConstructInPlace, i, p);
203}
204
205static void callConstructor(
206 const QMetaObject *targetMetaObject, int i, void *source, void *target)
207{
208 void *p[] = { target, source };
209 targetMetaObject->static_metacall(QMetaObject::ConstructInPlace, i, p);
210}
211
212
213template<typename Allocate>
215 const QMetaObject *targetMetaObject, int ctorIndex, void **args,
216 Allocate &&allocate)
217{
218 const QMetaMethod ctor = targetMetaObject->constructor(ctorIndex);
219 callConstructor(targetMetaObject, ctorIndex, args, ctor.parameterCount(), allocate());
220}
221
222
223template<typename Allocate, typename Retrieve>
225 const QMetaObject *targetMetaObject, Allocate &&allocate, Retrieve &&retrieve,
226 QV4::ExecutionEngine *engine)
227{
228 const int end = targetMetaObject->constructorCount();
229 for (int i = 0; i < end; ++i) {
230 // Try construction from exact matches. (Score 0)
231 const QMetaMethod ctor = targetMetaObject->constructor(i);
232 if (ctor.parameterCount() != 1)
233 continue;
234
235 if (retrieve([&](QMetaType sourceMetaType, void *sourceData) {
236 if (sourceMetaType != ctor.parameterMetaType(0))
237 return false;
238 callConstructor(targetMetaObject, i, sourceData, allocate());
239 return true;
240 })) {
241 return true;
242 }
243 }
244
245 for (int i = 0; i < end; ++i) {
246 // Try construction from derived types. (Score 1)
247 const QMetaMethod ctor = targetMetaObject->constructor(i);
248 if (ctor.parameterCount() != 1)
249 continue;
250
251 const QMetaType parameterType = ctor.parameterMetaType(0);
252 const QMetaObject *parameterMetaObject = parameterType.metaObject();
253 if (!parameterMetaObject)
254 continue;
255
256 if (retrieve([&](QMetaType sourceMetaType, void *sourceData) {
257 Q_ASSERT(sourceMetaType != parameterType);
258 if (const QMetaObject *sourceMetaObject = sourceMetaType.metaObject();
259 sourceMetaObject && sourceMetaObject->inherits(parameterMetaObject)) {
260 callConstructor(targetMetaObject, i, sourceData, allocate());
261 return true;
262 }
263 return false;
264 })) {
265 return true;
266 }
267 }
268
269 for (int i = 0; i < end; ++i) {
270 // Try construction from converted types.
271 // Do not recursively try to create parameters here. This may end up in infinite recursion.
272
273 const QMetaMethod ctor = targetMetaObject->constructor(i);
274 if (ctor.parameterCount() != 1)
275 continue;
276
277 const QMetaType parameterType = ctor.parameterMetaType(0);
278
279 if (retrieve([&](QMetaType sourceMetaType, void *sourceData) {
280 QVariant converted(parameterType);
281 if (coerceValue(sourceMetaType, sourceData, parameterType, converted.data(), engine)) {
282 callConstructor(targetMetaObject, i, converted.data(), allocate());
283 return true;
284 }
285
286 return false;
287 })) {
288 return true;
289 }
290 }
291
292 return false;
293}
294
295template<typename Allocate>
297 const QMetaObject *targetMetaObject, const QV4::Value &source, Allocate &&allocate,
298 QV4::ExecutionEngine *engine)
299{
300 QVariant variant;
301 return fromMatchingType(targetMetaObject, std::forward<Allocate>(allocate), [&](auto callback) {
302 if (!variant.isValid())
303 variant = QV4::ExecutionEngine::toVariant(source, QMetaType());
304 return callback(variant.metaType(), variant.data());
305 }, engine);
306}
307
308template<typename Allocate>
310 const QMetaObject *targetMetaObject, QVariant source, Allocate &&allocate,
311 QV4::ExecutionEngine *engine)
312{
313 return fromMatchingType(targetMetaObject, std::forward<Allocate>(allocate), [&](auto callback) {
314 return callback(source.metaType(), source.data());
315 }, engine);
316}
317
318template<typename Allocate>
319static bool fromString(const QMetaObject *mo, QString s, Allocate &&allocate)
320{
321 for (int i = 0, end = mo->constructorCount(); i < end; ++i) {
322 const QMetaMethod ctor = mo->constructor(i);
323 if (ctor.parameterCount() != 1)
324 continue;
325
326 if (ctor.parameterMetaType(0) == QMetaType::fromType<QString>()) {
327 callConstructor(mo, i, &s, allocate());
328 return true;
329 }
330 }
331
332 return false;
333}
334
335template<typename Get, typename Convert>
336static bool doWriteProperty(
337 const QMetaProperty &metaProperty, void *target, Get &&get, Convert &&convert,
338 QV4::ExecutionEngine *engine)
339{
340 const QMetaType propertyType = metaProperty.metaType();
341 QVariant property = get(propertyType);
342 if (property.metaType() == propertyType) {
343 metaProperty.writeOnGadget(target, std::move(property));
344 return true;
345 }
346
347 QVariant converted = convert(propertyType);
348 if (converted.isValid()) {
349 metaProperty.writeOnGadget(target, std::move(converted));
350 return true;
351 }
352
353 converted = QVariant(propertyType);
354 if (coerceValue(
355 property.metaType(), property.constData(), propertyType, converted.data(),
356 engine)) {
357 metaProperty.writeOnGadget(target, std::move(converted));
358 return true;
359 }
360
361 return false;
362}
363
365 const QMetaObject *targetMetaObject, void *target, const QV4::Value &source,
366 QV4::ExecutionEngine *engine)
367{
368 const QV4::Object *o = static_cast<const QV4::Object *>(&source);
369 QV4::Scope scope(o->engine());
370 QV4::ScopedObject object(scope, o);
371
372 for (int i = 0; i < targetMetaObject->propertyCount(); ++i) {
373 const QMetaProperty metaProperty = targetMetaObject->property(i);
374 const QString propertyName = QString::fromUtf8(metaProperty.name());
375
376 QV4::ScopedString v4PropName(scope, scope.engine->newString(propertyName));
377 QV4::ScopedValue v4PropValue(scope, object->get(v4PropName));
378
379 // We assume that data is freshly constructed.
380 // There is no point in reset()'ing properties of a freshly created object.
381 if (v4PropValue->isUndefined())
382 continue;
383
384 if (doWriteProperty(metaProperty, target, [&](const QMetaType &propertyType) {
385 return QV4::ExecutionEngine::toVariant(v4PropValue, propertyType);
386 }, [&](const QMetaType &propertyType) {
387 return QQmlValueTypeProvider::createValueType(v4PropValue, propertyType, engine);
388 }, engine)) {
389 continue;
390 }
391
392 const QMetaType propertyType = metaProperty.metaType();
393 QVariant property = QV4::ExecutionEngine::toVariant(v4PropValue, propertyType);
394 if (property.metaType() == propertyType) {
395 metaProperty.writeOnGadget(target, std::move(property));
396 continue;
397 }
398
399 QVariant converted = QQmlValueTypeProvider::createValueType(
400 v4PropValue, propertyType, engine);
401 if (converted.isValid()) {
402 metaProperty.writeOnGadget(target, std::move(converted));
403 continue;
404 }
405
406 converted = QVariant(propertyType);
407 if (coerceValue(
408 property.metaType(), property.constData(), propertyType, converted.data(),
409 engine)) {
410 metaProperty.writeOnGadget(target, std::move(converted));
411 continue;
412 }
413
414 printConversionWarning(engine, v4PropValue->toQStringNoThrow(),
415 QString::fromUtf8(propertyType.name()), propertyName);
416 }
417}
418
420 const QMetaObject *targetMetaObject, QMetaType metaType, const QV4::Value &source,
421 QV4::ExecutionEngine *engine)
422{
423 if (!source.isObject() || !targetMetaObject)
424 return QVariant();
425
426 QVariant result(metaType);
427 doWriteProperties(targetMetaObject, result.data(), source, engine);
428 return result;
429}
430
431template<typename Read>
433 const QMetaObject *targetMetaObject, void *target,
434 const QMetaObject *sourceMetaObject, Read &&read, QV4::ExecutionEngine *engine)
435{
436 for (int i = 0; i < targetMetaObject->propertyCount(); ++i) {
437 const QMetaProperty metaProperty = targetMetaObject->property(i);
438
439 const int sourceProperty = sourceMetaObject->indexOfProperty(metaProperty.name());
440
441 // We assume that data is freshly constructed.
442 // There is no point in reset()'ing properties of a freshly created object.
443 if (sourceProperty == -1)
444 continue;
445
446 const QMetaType propertyType = metaProperty.metaType();
447 QVariant property = read(sourceMetaObject, sourceProperty);
448 if (property.metaType() == propertyType) {
449 metaProperty.writeOnGadget(target, std::move(property));
450 continue;
451 }
452
453 QVariant converted = QQmlValueTypeProvider::createValueType(property, propertyType, engine);
454 if (converted.isValid()) {
455 metaProperty.writeOnGadget(target, std::move(converted));
456 continue;
457 }
458
459 converted = QVariant(propertyType);
460 if (coerceValue(
461 property.metaType(), property.constData(), propertyType, converted.data(),
462 engine)) {
463 metaProperty.writeOnGadget(target, std::move(converted));
464 continue;
465 }
466
467 printConversionWarning(engine, QDebug::toString(property),
468 QString::fromUtf8(propertyType.name()),
469 QString::fromUtf8(metaProperty.name()));
470 }
471}
472
473
475 const QMetaObject *targetMeta, void *target, QObject *source, QV4::ExecutionEngine *engine)
476{
477 doWriteProperties(
478 targetMeta, target, source->metaObject(),
479 [source](const QMetaObject *sourceMetaObject, int sourceProperty) {
480 return sourceMetaObject->property(sourceProperty).read(source);
481 }, engine);
482}
483
485 const QMetaObject *targetMetaObject, QMetaType targetMetaType, QObject *source,
486 QV4::ExecutionEngine *engine)
487{
488 if (!source || !targetMetaObject)
489 return QVariant();
490
491 QVariant result(targetMetaType);
492 doWriteProperties(targetMetaObject, result.data(), source, engine);
493 return result;
494}
495
497 const QMetaObject *targetMetaObject, QMetaType targetMetaType,
498 const QMetaObject *sourceMetaObject, const void *source, QV4::ExecutionEngine *engine)
499{
500 if (!source || !sourceMetaObject || !targetMetaObject)
501 return QVariant();
502
503 QVariant result(targetMetaType);
504 doWriteProperties(
505 targetMetaObject, result.data(), sourceMetaObject,
506 [source](const QMetaObject *sourceMetaObject, int sourceProperty) {
507 return sourceMetaObject->property(sourceProperty).readOnGadget(source);
508 }, engine);
509 return result;
510}
511
512template<typename Map>
514 const QMetaObject *targetMetaObject, void *target, const Map &source,
515 QV4::ExecutionEngine *engine)
516{
517 for (int i = 0; i < targetMetaObject->propertyCount(); ++i) {
518 const QMetaProperty metaProperty = targetMetaObject->property(i);
519
520 // We assume that data is freshly constructed.
521 // There is no point in reset()'ing properties of a freshly created object.
522 const auto it = source.constFind(QString::fromUtf8(metaProperty.name()));
523 if (it == source.constEnd())
524 continue;
525
526 const QMetaType propertyType = metaProperty.metaType();
527 QVariant property = *it;
528 if (property.metaType() == propertyType) {
529 metaProperty.writeOnGadget(target, std::move(property));
530 continue;
531 }
532
533 QVariant converted = QQmlValueTypeProvider::createValueType(property, propertyType, engine);
534 if (converted.isValid()) {
535 metaProperty.writeOnGadget(target, std::move(converted));
536 continue;
537 }
538
539 converted = QVariant(propertyType);
540 if (coerceValue(
541 property.metaType(), property.constData(), propertyType, converted.data(),
542 engine)) {
543 metaProperty.writeOnGadget(target, std::move(converted));
544 continue;
545 }
546
547 printConversionWarning(engine, QDebug::toString(property),
548 QString::fromUtf8(propertyType.name()),
549 QString::fromUtf8(metaProperty.name()));
550 }
551}
552
553template<typename Map>
555 const QMetaObject *targetMetaObject, QMetaType targetMetaType, const Map &source,
556 QV4::ExecutionEngine *engine)
557{
558 QVariant result(targetMetaType);
559 doWriteProperties(targetMetaObject, result.data(), source, engine);
560 return result;
561}
562
564 const QMetaObject *targetMetaObject, QMetaType targetMetaType, const QVariant &source,
565 QV4::ExecutionEngine *engine)
566{
567 if (!targetMetaObject)
568 return QVariant();
569
570 if (source.metaType() == QMetaType::fromType<QJSValue>()) {
571 QJSValue val = source.value<QJSValue>();
572 // Generally, the GC might collect a Value at any point so that
573 // a `ScopedValue` should be used.
574 // In this case, the Value is tied to a `QJSValue` which is
575 // persistent to the GC and thus fromReturnedValue is safe.
576 return byProperties(
577 targetMetaObject, targetMetaType,
578 QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(&val)),
579 engine);
580 }
581
582 if (source.metaType() == QMetaType::fromType<QVariantMap>()) {
583 return byProperties(
584 targetMetaObject, targetMetaType,
585 *static_cast<const QVariantMap *>(source.constData()), engine);
586 }
587
588 if (source.metaType() == QMetaType::fromType<QVariantHash>()) {
589 return byProperties(
590 targetMetaObject, targetMetaType,
591 *static_cast<const QVariantHash *>(source.constData()), engine);
592 }
593
594 if (source.metaType().flags() & QMetaType::PointerToQObject)
595 return byProperties(targetMetaObject, targetMetaType, source.value<QObject *>(), engine);
596
597 if (const QMetaObject *sourceMeta = QQmlMetaType::metaObjectForValueType(source.metaType())) {
598 return byProperties(
599 targetMetaObject, targetMetaType, sourceMeta, source.constData(), engine);
600 }
601
602 return QVariant();
603}
604
605template<typename Allocate, typename DefaultConstruct>
607 const QQmlType &targetType, const QV4::Value &source,
608 Allocate &&allocate, DefaultConstruct &&defaultConstruct, QV4::ExecutionEngine *engine)
609{
610 const auto warn = [&](const QMetaObject *targetMetaObject) {
611 qWarning().noquote()
612 << "Could not find any constructor for value type"
613 << targetMetaObject->className() << "to call with value"
614 << source.toQStringNoThrow();
615 };
616
617 if (targetType.canPopulateValueType()) {
618 if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
619 if (source.isObject()) {
620 doWriteProperties(targetMetaObject, defaultConstruct(), source, engine);
621 return true;
622 }
623 if (targetType.canConstructValueType()) {
624 if (fromMatchingType(targetMetaObject, source, allocate, engine))
625 return true;
626 warn(targetMetaObject);
627 }
628 }
629 } else if (targetType.canConstructValueType()) {
630 if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
631 if (fromMatchingType(targetMetaObject, source, allocate, engine))
632 return true;
633 warn(targetMetaObject);
634 }
635 }
636
637 if (const auto valueTypeFunction = targetType.createValueTypeFunction()) {
638 const QVariant result
639 = valueTypeFunction(QJSValuePrivate::fromReturnedValue(source.asReturnedValue()));
640 const QMetaType resultType = result.metaType();
641 if (resultType == targetType.typeId()) {
642 resultType.construct(allocate(), result.constData());
643 return true;
644 }
645 }
646
647 return false;
648}
649
650template<typename Allocate, typename DefaultConstruct>
652 const QQmlType &targetType, QMetaType sourceMetaType, void *source,
653 Allocate &&allocate, DefaultConstruct &&defaultConstruct, QV4::ExecutionEngine *engine)
654{
655
656 const auto warn = [&](const QMetaObject *targetMetaObject) {
657 qWarning().noquote()
658 << "Could not find any constructor for value type"
659 << targetMetaObject->className() << "to call with value" << source;
660 };
661
662 if (targetType.canPopulateValueType()) {
663 if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
664 if (const QMetaObject *sourceMetaObject
665 = QQmlMetaType::metaObjectForValueType(sourceMetaType)) {
666 doWriteProperties(
667 targetMetaObject, defaultConstruct(), sourceMetaObject,
668 [&source](const QMetaObject *sourceMetaObject, int sourceProperty) {
669 return sourceMetaObject->property(sourceProperty).readOnGadget(source);
670 }, engine);
671 return true;
672 }
673
674 if (sourceMetaType == QMetaType::fromType<QVariantMap>()) {
675 doWriteProperties(
676 targetMetaObject, defaultConstruct(),
677 *static_cast<const QVariantMap *>(source), engine);
678 return true;
679 }
680
681 if (sourceMetaType == QMetaType::fromType<QVariantHash>()) {
682 doWriteProperties(
683 targetMetaObject, defaultConstruct(),
684 *static_cast<const QVariantHash *>(source), engine);
685 return true;
686 }
687
688 if (sourceMetaType.flags() & QMetaType::PointerToQObject) {
689 doWriteProperties(
690 targetMetaObject, defaultConstruct(),
691 *static_cast<QObject *const *>(source), engine);
692 return true;
693 }
694 }
695 }
696
697 if (targetType.canConstructValueType()) {
698 if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
699 if (fromMatchingType(
700 targetMetaObject, std::forward<Allocate>(allocate), [&](auto callback) {
701 return callback(sourceMetaType, source);
702 }, engine)) {
703 return true;
704 }
705 warn(targetMetaObject);
706 }
707 }
708
709 return false;
710}
711
712/*!
713 * \internal
714 * Populate the value type in place at \a target, which is expected to be
715 * allocated and default-constructed, for example the result of a QVariant(QMetaType).
716 * This is efficient if we can do byProperties() since it can use the pre-constructed object.
717 * It also avoids the creation of a QVariant in most cases. It is not
718 * efficient if you're going to create a QVariant anyway.
719 */
720bool QQmlValueTypeProvider::populateValueType(
721 QMetaType targetMetaType, void *target, QMetaType sourceMetaType, void *source,
722 QV4::ExecutionEngine *engine)
723{
724 if (sourceMetaType == QMetaType::fromType<QJSValue>()) {
725 const QJSValue *val = static_cast<const QJSValue *>(source);
726 // Generally, the GC might collect a Value at any point so that
727 // a `ScopedValue` should be used.
728 // In this case, the Value is tied to a `QJSValue` which is
729 // persistent to the GC and thus fromReturnedValue is safe.
730 return populateValueType(
731 targetMetaType, target,
732 QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(val)),
733 engine);
734 }
735
736 if (!isConstructibleMetaType(targetMetaType))
737 return false;
738
739 return createOrConstructValueType(
740 QQmlMetaType::qmlType(targetMetaType), sourceMetaType, source,
741 [targetMetaType, target]() {
742 targetMetaType.destruct(target);
743 return target;
744 }, [target]() {
745 return target;
746 }, engine);
747}
748
749/*!
750 * \internal
751 * Populate the value type in place at \a target, which is expected to be
752 * allocated and default-constructed, for example the result of a QVariant(QMetaType).
753 * This is efficient if we can do byProperties() since it can use the pre-constructed object.
754 * It also avoids the creation of a QVariant in most cases. It is not
755 * efficient if you're going to create a QVariant anyway.
756 */
757bool QQmlValueTypeProvider::populateValueType(
758 QMetaType targetMetaType, void *target, const QV4::Value &source,
759 QV4::ExecutionEngine *engine)
760{
761 if (!isConstructibleMetaType(targetMetaType))
762 return false;
763
764 return createOrConstructValueType(
765 QQmlMetaType::qmlType(targetMetaType), source, [targetMetaType, target]() {
766 targetMetaType.destruct(target);
767 return target;
768 }, [target]() {
769 return target;
770 }, engine);
771}
772
773/*!
774 * \internal
775 * Specialization that constructs the value type on the heap using new and returns a pointer to it.
776 */
777void *QQmlValueTypeProvider::heapCreateValueType(
778 const QQmlType &targetType, const QV4::Value &source, QV4::ExecutionEngine *engine)
779{
780 void *target = nullptr;
781 if (createOrConstructValueType(
782 targetType, source, [&]() {
783 const QMetaType metaType = targetType.typeId();
784 const ushort align = metaType.alignOf();
785 target = align > __STDCPP_DEFAULT_NEW_ALIGNMENT__
786 ? operator new(metaType.sizeOf(), std::align_val_t(align))
787 : operator new(metaType.sizeOf());
788 return target;
789 }, [&]() {
790 target = targetType.typeId().create();
791 return target;
792 }, engine)) {
793 Q_ASSERT(target != nullptr);
794 }
795
796 return target;
797}
798
799QVariant QQmlValueTypeProvider::constructValueType(
800 QMetaType targetMetaType, const QMetaObject *targetMetaObject,
801 int ctorIndex, void **args)
802{
803 QVariant result;
804 fromVerifiedType(targetMetaObject, ctorIndex, args,
805 [&]() { return createVariantData(targetMetaType, &result); });
806 return result;
807}
808
809static QVariant fromJSValue(const QQmlType &type, const QJSValue &s, QMetaType metaType)
810{
811 if (const auto valueTypeFunction = type.createValueTypeFunction()) {
812 const QVariant result = valueTypeFunction(s);
813 if (result.metaType() == metaType)
814 return result;
815 }
816
817 return QVariant();
818}
819
820QVariant QQmlValueTypeProvider::createValueType(const QJSValue &s, QMetaType metaType)
821{
822 if (!isConstructibleMetaType(metaType))
823 return QVariant();
824 return fromJSValue(QQmlMetaType::qmlType(metaType), s, metaType);
825}
826
827QVariant QQmlValueTypeProvider::createValueType(const QString &s, QMetaType metaType)
828{
829 if (!isConstructibleMetaType(metaType))
830 return QVariant();
831 const QQmlType type = QQmlMetaType::qmlType(metaType);
832 if (type.canConstructValueType()) {
833 if (const QMetaObject *mo = type.metaObjectForValueType()) {
834 QVariant result;
835 if (fromString(mo, s, [&]() { return createVariantData(metaType, &result); }))
836 return result;
837 }
838 }
839
840 return fromJSValue(type, s, metaType);
841}
842
843QVariant QQmlValueTypeProvider::createValueType(
844 const QV4::Value &s, QMetaType metaType, QV4::ExecutionEngine *engine)
845{
846 if (!isConstructibleMetaType(metaType))
847 return QVariant();
848 const QQmlType type = QQmlMetaType::qmlType(metaType);
849 const auto warn = [&](const QMetaObject *mo) {
850 qWarning().noquote()
851 << "Could not find any constructor for value type"
852 << mo->className() << "to call with value" << s.toQStringNoThrow();
853 };
854
855 if (type.canPopulateValueType()) {
856 if (const QMetaObject *mo = type.metaObject()) {
857 QVariant result = byProperties(mo, metaType, s, engine);
858 if (result.isValid())
859 return result;
860 if (type.canConstructValueType()) {
861 if (fromMatchingType(
862 mo, s, [&]() { return createVariantData(metaType, &result); },
863 engine)) {
864 return result;
865 }
866 warn(mo);
867 }
868 }
869 } else if (type.canConstructValueType()) {
870 if (const QMetaObject *mo = type.metaObject()) {
871 QVariant result;
872 if (fromMatchingType(
873 mo, s, [&]() { return createVariantData(metaType, &result); },
874 engine)) {
875 return result;
876 }
877 warn(mo);
878 }
879 }
880
881 return fromJSValue(type, QJSValuePrivate::fromReturnedValue(s.asReturnedValue()), metaType);
882
883}
884
885/*!
886 * \internal
887 * This should only be called with either builtin types or wrapped QJSValues as source.
888 */
889QVariant QQmlValueTypeProvider::createValueType(
890 const QVariant &s, QMetaType metaType, QV4::ExecutionEngine *engine)
891{
892 if (!isConstructibleMetaType(metaType))
893 return QVariant();
894 const QQmlType type = QQmlMetaType::qmlType(metaType);
895 const auto warn = [&](const QMetaObject *mo) {
896 qWarning().noquote()
897 << "Could not find any constructor for value type"
898 << mo->className() << "to call with value" << s;
899 };
900
901 if (type.canPopulateValueType()) {
902 if (const QMetaObject *mo = type.metaObjectForValueType()) {
903 QVariant result = byProperties(mo, metaType, s, engine);
904 if (result.isValid())
905 return result;
906 if (type.canConstructValueType()) {
907 if (fromMatchingType(
908 mo, s, [&]() { return createVariantData(metaType, &result); },
909 engine)) {
910 return result;
911 }
912 warn(mo);
913 }
914 }
915 } else if (type.canConstructValueType()) {
916 if (const QMetaObject *mo = type.metaObjectForValueType()) {
917 QVariant result;
918 if (fromMatchingType(
919 mo, s, [&]() { return createVariantData(metaType, &result); },
920 engine)) {
921 return result;
922 }
923 warn(mo);
924 }
925 }
926
927 return QVariant();
928}
929
930QQmlColorProvider::~QQmlColorProvider() {}
931QVariant QQmlColorProvider::colorFromString(const QString &, bool *ok) { if (ok) *ok = false; return QVariant(); }
932unsigned QQmlColorProvider::rgbaFromString(const QString &, bool *ok) { if (ok) *ok = false; return 0; }
933QVariant QQmlColorProvider::fromRgbF(double, double, double, double) { return QVariant(); }
934QVariant QQmlColorProvider::fromHslF(double, double, double, double) { return QVariant(); }
935QVariant QQmlColorProvider::fromHsvF(double, double, double, double) { return QVariant(); }
936QVariant QQmlColorProvider::lighter(const QVariant &, qreal) { return QVariant(); }
937QVariant QQmlColorProvider::darker(const QVariant &, qreal) { return QVariant(); }
938QVariant QQmlColorProvider::alpha(const QVariant &, qreal)
939{
940 return QVariant();
941}
942QVariant QQmlColorProvider::tint(const QVariant &, const QVariant &) { return QVariant(); }
943
945
946Q_QML_EXPORT QQmlColorProvider *QQml_setColorProvider(QQmlColorProvider *newProvider)
947{
948 QQmlColorProvider *old = colorProvider;
949 colorProvider = newProvider;
950 return old;
951}
952
954{
955 if (colorProvider == nullptr) {
956 qWarning() << "Warning: QQml_colorProvider: no color provider has been set!";
957 static QQmlColorProvider nullColorProvider;
958 colorProvider = &nullColorProvider;
959 }
960
961 return &colorProvider;
962}
963
964Q_AUTOTEST_EXPORT QQmlColorProvider *QQml_colorProvider(void)
965{
966 static QQmlColorProvider **providerPtr = getColorProvider();
967 return *providerPtr;
968}
969
970
971QQmlGuiProvider::~QQmlGuiProvider() {}
972QQmlApplication *QQmlGuiProvider::application(QObject *parent)
973{
974 return new QQmlApplication(parent);
975}
976QStringList QQmlGuiProvider::fontFamilies() { return QStringList(); }
977bool QQmlGuiProvider::openUrlExternally(const QUrl &) { return false; }
978
979QObject *QQmlGuiProvider::inputMethod()
980{
981 // We don't have any input method code by default
982 QObject *o = new QObject();
983 o->setObjectName(QStringLiteral("No inputMethod available"));
984 QQmlEngine::setObjectOwnership(o, QQmlEngine::JavaScriptOwnership);
985 return o;
986}
987
988QObject *QQmlGuiProvider::styleHints()
989{
990 QObject *o = new QObject();
991 o->setObjectName(QStringLiteral("No styleHints available"));
992 QQmlEngine::setObjectOwnership(o, QQmlEngine::JavaScriptOwnership);
993 return o;
994}
995
996QString QQmlGuiProvider::pluginName() const { return QString(); }
997
998static QQmlGuiProvider *guiProvider = nullptr;
999
1000Q_QML_EXPORT QQmlGuiProvider *QQml_setGuiProvider(QQmlGuiProvider *newProvider)
1001{
1002 QQmlGuiProvider *old = guiProvider;
1003 guiProvider = newProvider;
1004 return old;
1005}
1006
1008{
1009 if (guiProvider == nullptr) {
1010 static QQmlGuiProvider nullGuiProvider; //Still provides an application with no GUI support
1011 guiProvider = &nullGuiProvider;
1012 }
1013
1014 return &guiProvider;
1015}
1016
1017Q_AUTOTEST_EXPORT QQmlGuiProvider *QQml_guiProvider(void)
1018{
1019 static QQmlGuiProvider **providerPtr = getGuiProvider();
1020 return *providerPtr;
1021}
1022
1023//Docs in qqmlengine.cpp
1024QQmlApplication::QQmlApplication(QObject *parent)
1025 : QQmlApplication(*(new QQmlApplicationPrivate), parent)
1026{
1027}
1028
1029QQmlApplication::QQmlApplication(QQmlApplicationPrivate &dd, QObject *parent)
1030 : QObject(dd, parent)
1031{
1032 connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()),
1033 this, SIGNAL(aboutToQuit()));
1034 connect(QCoreApplication::instance(), SIGNAL(applicationNameChanged()),
1035 this, SIGNAL(nameChanged()));
1036 connect(QCoreApplication::instance(), SIGNAL(applicationVersionChanged()),
1037 this, SIGNAL(versionChanged()));
1038 connect(QCoreApplication::instance(), SIGNAL(organizationNameChanged()),
1039 this, SIGNAL(organizationChanged()));
1040 connect(QCoreApplication::instance(), SIGNAL(organizationDomainChanged()),
1041 this, SIGNAL(domainChanged()));
1042}
1043
1044QStringList QQmlApplication::args()
1045{
1046 Q_D(QQmlApplication);
1047 if (!d->argsInit) {
1048 d->argsInit = true;
1049 d->args = QCoreApplication::arguments();
1050 }
1051 return d->args;
1052}
1053
1054QString QQmlApplication::name() const
1055{
1056 return QCoreApplication::instance()->applicationName();
1057}
1058
1059QString QQmlApplication::version() const
1060{
1061 return QCoreApplication::instance()->applicationVersion();
1062}
1063
1064QString QQmlApplication::organization() const
1065{
1066 return QCoreApplication::instance()->organizationName();
1067}
1068
1069QString QQmlApplication::domain() const
1070{
1071 return QCoreApplication::instance()->organizationDomain();
1072}
1073
1074void QQmlApplication::setName(const QString &arg)
1075{
1076 QCoreApplication::instance()->setApplicationName(arg);
1077}
1078
1079void QQmlApplication::setVersion(const QString &arg)
1080{
1081 QCoreApplication::instance()->setApplicationVersion(arg);
1082}
1083
1084void QQmlApplication::setOrganization(const QString &arg)
1085{
1086 QCoreApplication::instance()->setOrganizationName(arg);
1087}
1088
1089void QQmlApplication::setDomain(const QString &arg)
1090{
1091 QCoreApplication::instance()->setOrganizationDomain(arg);
1092}
1093
1094static const QQmlData *ddata_for_cast(QObject *object)
1095{
1096 Q_ASSERT(object);
1097 auto ddata = QQmlData::get(object, false);
1098 return (ddata && ddata->propertyCache) ? ddata : nullptr;
1099}
1100
1101bool qmlobject_can_cpp_cast(QObject *object, const QMetaObject *mo)
1102{
1103 Q_ASSERT(mo);
1104 if (const QQmlData *ddata = ddata_for_cast(object))
1105 return ddata->propertyCache->firstCppMetaObject()->inherits(mo);
1106 return object->metaObject()->inherits(mo);
1107}
1108
1109bool qmlobject_can_qml_cast(QObject *object, const QQmlType &type)
1110{
1111 Q_ASSERT(type.isValid());
1112
1113 // A non-composite type will always have a metaobject.
1114 const QMetaObject *typeMetaObject = type.metaObject();
1115 const QQmlPropertyCache::ConstPtr typePropertyCache = typeMetaObject
1116 ? QQmlPropertyCache::ConstPtr()
1117 : QQmlMetaType::findPropertyCacheInCompositeTypes(type.typeId());
1118
1119 if (const QQmlData *ddata = ddata_for_cast(object)) {
1120 for (const QQmlPropertyCache *propertyCache = ddata->propertyCache.data(); propertyCache;
1121 propertyCache = propertyCache->parent().data()) {
1122
1123 if (typeMetaObject) {
1124 // Prefer the metaobject inheritance mechanism, since it is more accurate.
1125 //
1126 // Assume the object can be casted to the type. Then, if we have a type metaobject,
1127 // the object's property cache inheritance has to contain it. Otherwise we would
1128 // end up with diverging metaobject hierarchies if we created the object's
1129 // metaobject. This would be a disaster.
1130 if (const QMetaObject *objectMetaObject = propertyCache->metaObject())
1131 return objectMetaObject->inherits(typeMetaObject);
1132 } else {
1133 // This is a best effort attempt. There are a number of ways for the
1134 // property caches to be unrelated but the types still convertible.
1135 // Multiple property caches can hold the same metaobject, for example for
1136 // versions of non-composite types.
1137 if (propertyCache == typePropertyCache.data())
1138 return true;
1139 }
1140 }
1141 }
1142
1143 // If nothing else works, we have to create the metaobjects.
1144
1145 return object->metaObject()->inherits(typeMetaObject
1146 ? typeMetaObject
1147 : (typePropertyCache ? typePropertyCache->createMetaObject() : nullptr));
1148}
1149
1150QT_END_NAMESPACE
1151
1152#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)