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