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 | #ifndef QQMLPRIVATE_H |
5 | #define QQMLPRIVATE_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists purely as an |
12 | // implementation detail. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include <QtQml/qtqmlglobal.h> |
19 | #include <QtQml/qqmlparserstatus.h> |
20 | #include <QtQml/qqmllist.h> |
21 | #include <QtQml/qqmlpropertyvaluesource.h> |
22 | #include <QtQml/qjsvalue.h> |
23 | |
24 | #include <QtCore/qglobal.h> |
25 | #include <QtCore/qvariant.h> |
26 | #include <QtCore/qurl.h> |
27 | #include <QtCore/qpointer.h> |
28 | #include <QtCore/qversionnumber.h> |
29 | |
30 | #include <QtCore/qmetaobject.h> |
31 | #include <QtCore/qmetacontainer.h> |
32 | #include <QtCore/qdebug.h> |
33 | |
34 | #include <functional> |
35 | #include <type_traits> |
36 | #include <limits> |
37 | |
38 | QT_BEGIN_NAMESPACE |
39 | |
40 | class QQmlPropertyValueInterceptor; |
41 | class QQmlContextData; |
42 | class QQmlFinalizerHook; |
43 | |
44 | namespace QQmlPrivate { |
45 | struct CachedQmlUnit; |
46 | template<typename A> |
47 | using QQmlAttachedPropertiesFunc = A *(*)(QObject *); |
48 | } |
49 | |
50 | namespace QV4 { |
51 | struct ExecutionEngine; |
52 | class ExecutableCompilationUnit; |
53 | namespace CompiledData { |
54 | struct Unit; |
55 | } |
56 | } |
57 | namespace QmlIR { |
58 | struct Document; |
59 | typedef void (*IRLoaderFunction)(Document *, const QQmlPrivate::CachedQmlUnit *); |
60 | } |
61 | |
62 | using QQmlAttachedPropertiesFunc = QQmlPrivate::QQmlAttachedPropertiesFunc<QObject>; |
63 | |
64 | inline size_t qHash(QQmlAttachedPropertiesFunc func, size_t seed = 0) |
65 | { |
66 | return qHash(key: quintptr(func), seed); |
67 | } |
68 | |
69 | template <typename TYPE> |
70 | class QQmlTypeInfo |
71 | { |
72 | public: |
73 | enum { |
74 | hasAttachedProperties = 0 |
75 | }; |
76 | }; |
77 | |
78 | |
79 | class QJSEngine; |
80 | class QQmlEngine; |
81 | class QQmlCustomParser; |
82 | class QQmlTypeNotAvailable; |
83 | |
84 | template<class T> |
85 | QQmlCustomParser *qmlCreateCustomParser() |
86 | { |
87 | return nullptr; |
88 | } |
89 | |
90 | namespace QQmlPrivate |
91 | { |
92 | void Q_QML_EXPORT qdeclarativeelement_destructor(QObject *); |
93 | template<typename T> |
94 | class QQmlElement final : public T |
95 | { |
96 | public: |
97 | ~QQmlElement() override { |
98 | QQmlPrivate::qdeclarativeelement_destructor(this); |
99 | } |
100 | static void operator delete(void *ptr) { |
101 | // We allocate memory from this class in QQmlType::create |
102 | // along with some additional memory. |
103 | // So we override the operator delete in order to avoid the |
104 | // sized operator delete to be called with a different size than |
105 | // the size that was allocated. |
106 | ::operator delete (ptr); |
107 | } |
108 | #ifdef Q_CC_MSVC |
109 | static void operator delete(void *, void *) { |
110 | // Deliberately empty placement delete operator. |
111 | // Silences MSVC warning C4291: no matching operator delete found |
112 | // On MinGW it causes -Wmismatched-new-delete, though. |
113 | } |
114 | #endif |
115 | }; |
116 | |
117 | enum class SingletonConstructionMode |
118 | { |
119 | None, |
120 | Constructor, |
121 | Factory, |
122 | FactoryWrapper |
123 | }; |
124 | |
125 | template<typename T, typename WrapperT = T, typename = std::void_t<>> |
126 | struct HasSingletonFactory |
127 | { |
128 | static constexpr bool value = false; |
129 | }; |
130 | |
131 | template<typename T, typename WrapperT> |
132 | struct HasSingletonFactory<T, WrapperT, std::void_t<decltype(WrapperT::create( |
133 | static_cast<QQmlEngine *>(nullptr), |
134 | static_cast<QJSEngine *>(nullptr)))>> |
135 | { |
136 | static constexpr bool value = std::is_same_v< |
137 | decltype(WrapperT::create(static_cast<QQmlEngine *>(nullptr), |
138 | static_cast<QJSEngine *>(nullptr))), T *>; |
139 | }; |
140 | |
141 | template<typename T, typename WrapperT> |
142 | constexpr SingletonConstructionMode singletonConstructionMode() |
143 | { |
144 | if constexpr (!std::is_base_of<QObject, T>::value) |
145 | return SingletonConstructionMode::None; |
146 | if constexpr (!std::is_same_v<T, WrapperT> && HasSingletonFactory<T, WrapperT>::value) |
147 | return SingletonConstructionMode::FactoryWrapper; |
148 | if constexpr (std::is_default_constructible<T>::value) |
149 | return SingletonConstructionMode::Constructor; |
150 | if constexpr (HasSingletonFactory<T>::value) |
151 | return SingletonConstructionMode::Factory; |
152 | |
153 | return SingletonConstructionMode::None; |
154 | } |
155 | |
156 | template<typename> |
157 | struct QmlMarkerFunction; |
158 | |
159 | template<typename Ret, typename Class> |
160 | struct QmlMarkerFunction<Ret (Class::*)()> |
161 | { |
162 | using ClassType = Class; |
163 | }; |
164 | |
165 | template<typename T, typename Marker> |
166 | using QmlTypeHasMarker = std::is_same<T, typename QmlMarkerFunction<Marker>::ClassType>; |
167 | |
168 | template<typename T> |
169 | void createInto(void *memory, void *) { new (memory) QQmlElement<T>; } |
170 | |
171 | template<typename T, typename WrapperT, SingletonConstructionMode Mode> |
172 | QObject *createSingletonInstance(QQmlEngine *q, QJSEngine *j) |
173 | { |
174 | Q_UNUSED(q); |
175 | Q_UNUSED(j); |
176 | if constexpr (Mode == SingletonConstructionMode::Constructor) |
177 | return new T; |
178 | else if constexpr (Mode == SingletonConstructionMode::Factory) |
179 | return T::create(q, j); |
180 | else if constexpr (Mode == SingletonConstructionMode::FactoryWrapper) |
181 | return WrapperT::create(q, j); |
182 | else |
183 | return nullptr; |
184 | } |
185 | |
186 | template<typename T> |
187 | QObject *createParent(QObject *p) { return new T(p); } |
188 | |
189 | using CreateIntoFunction = void (*)(void *, void *); |
190 | using CreateSingletonFunction = QObject *(*)(QQmlEngine *, QJSEngine *); |
191 | using CreateParentFunction = QObject *(*)(QObject *); |
192 | using CreateValueTypeFunction = QVariant (*)(const QJSValue &); |
193 | |
194 | template<typename T, typename WrapperT = T, |
195 | SingletonConstructionMode Mode = singletonConstructionMode<T, WrapperT>()> |
196 | struct Constructors; |
197 | |
198 | template<typename T, typename WrapperT> |
199 | struct Constructors<T, WrapperT, SingletonConstructionMode::Constructor> |
200 | { |
201 | static constexpr CreateIntoFunction createInto |
202 | = QQmlPrivate::createInto<T>; |
203 | static constexpr CreateSingletonFunction createSingletonInstance |
204 | = QQmlPrivate::createSingletonInstance< |
205 | T, WrapperT, SingletonConstructionMode::Constructor>; |
206 | }; |
207 | |
208 | template<typename T, typename WrapperT> |
209 | struct Constructors<T, WrapperT, SingletonConstructionMode::None> |
210 | { |
211 | static constexpr CreateIntoFunction createInto = nullptr; |
212 | static constexpr CreateSingletonFunction createSingletonInstance = nullptr; |
213 | }; |
214 | |
215 | template<typename T, typename WrapperT> |
216 | struct Constructors<T, WrapperT, SingletonConstructionMode::Factory> |
217 | { |
218 | static constexpr CreateIntoFunction createInto = nullptr; |
219 | static constexpr CreateSingletonFunction createSingletonInstance |
220 | = QQmlPrivate::createSingletonInstance< |
221 | T, WrapperT, SingletonConstructionMode::Factory>; |
222 | }; |
223 | |
224 | template<typename T, typename WrapperT> |
225 | struct Constructors<T, WrapperT, SingletonConstructionMode::FactoryWrapper> |
226 | { |
227 | static constexpr CreateIntoFunction createInto = nullptr; |
228 | static constexpr CreateSingletonFunction createSingletonInstance |
229 | = QQmlPrivate::createSingletonInstance< |
230 | T, WrapperT, SingletonConstructionMode::FactoryWrapper>; |
231 | }; |
232 | |
233 | template<typename T, |
234 | bool IsObject = std::is_base_of<QObject, T>::value, |
235 | bool IsGadget = QtPrivate::IsGadgetHelper<T>::IsRealGadget> |
236 | struct ExtendedType; |
237 | |
238 | template<typename T> |
239 | struct ExtendedType<T, false, false> |
240 | { |
241 | static constexpr const CreateParentFunction createParent = nullptr; |
242 | static const QMetaObject *staticMetaObject() { return nullptr; } |
243 | }; |
244 | |
245 | // If it's a QObject, we actually want an error if the ctor or the metaobject is missing. |
246 | template<typename T> |
247 | struct ExtendedType<T, true, false> |
248 | { |
249 | static constexpr const CreateParentFunction createParent = QQmlPrivate::createParent<T>; |
250 | static const QMetaObject *staticMetaObject() { return &T::staticMetaObject; } |
251 | }; |
252 | |
253 | // If it's a Q_GADGET, we don't want the ctor. |
254 | template<typename T> |
255 | struct ExtendedType<T, false, true> |
256 | { |
257 | static constexpr const CreateParentFunction createParent = nullptr; |
258 | static const QMetaObject *staticMetaObject() { return &T::staticMetaObject; } |
259 | }; |
260 | |
261 | template<typename F, typename Result = void> |
262 | struct ValueTypeFactory |
263 | { |
264 | static constexpr const Result (*create)(const QJSValue &) = nullptr; |
265 | }; |
266 | |
267 | template<typename F> |
268 | struct ValueTypeFactory<F, std::void_t<decltype(F::create(QJSValue()))>> |
269 | { |
270 | static decltype(F::create(QJSValue())) create(const QJSValue ¶ms) |
271 | { |
272 | return F::create(params); |
273 | } |
274 | }; |
275 | |
276 | template<typename T, typename F, |
277 | bool HasCtor = std::is_constructible_v<T, QJSValue>, |
278 | bool HasFactory = std::is_constructible_v< |
279 | QVariant, decltype(ValueTypeFactory<F>::create(QJSValue()))>> |
280 | struct ValueType; |
281 | |
282 | template<typename T, typename F> |
283 | struct ValueType<T, F, false, false> |
284 | { |
285 | static constexpr const CreateValueTypeFunction create = nullptr; |
286 | }; |
287 | |
288 | template<typename T, typename F, bool HasCtor> |
289 | struct ValueType<T, F, HasCtor, true> |
290 | { |
291 | static QVariant create(const QJSValue ¶ms) |
292 | { |
293 | return F::create(params); |
294 | } |
295 | }; |
296 | |
297 | template<typename T, typename F> |
298 | struct ValueType<T, F, true, false> |
299 | { |
300 | static QVariant create(const QJSValue ¶ms) |
301 | { |
302 | return QVariant::fromValue(T(params)); |
303 | } |
304 | }; |
305 | |
306 | template<class From, class To, int N> |
307 | struct StaticCastSelectorClass |
308 | { |
309 | static inline int cast() { return -1; } |
310 | }; |
311 | |
312 | template<class From, class To> |
313 | struct StaticCastSelectorClass<From, To, sizeof(int)> |
314 | { |
315 | static inline int cast() { return int(reinterpret_cast<quintptr>(static_cast<To *>(reinterpret_cast<From *>(0x10000000)))) - 0x10000000; } |
316 | }; |
317 | |
318 | template<class From, class To> |
319 | struct StaticCastSelector |
320 | { |
321 | typedef int yes_type; |
322 | typedef char no_type; |
323 | |
324 | static yes_type checkType(To *); |
325 | static no_type checkType(...); |
326 | |
327 | static inline int cast() |
328 | { |
329 | return StaticCastSelectorClass<From, To, sizeof(checkType(reinterpret_cast<From *>(0)))>::cast(); |
330 | } |
331 | }; |
332 | |
333 | // You can prevent subclasses from using the same attached type by specialzing this. |
334 | // This is reserved for internal types, though. |
335 | template<class T, class A> |
336 | struct OverridableAttachedType |
337 | { |
338 | using Type = A; |
339 | }; |
340 | |
341 | template<class T, class = std::void_t<>, bool OldStyle = QQmlTypeInfo<T>::hasAttachedProperties> |
342 | struct QmlAttached |
343 | { |
344 | using Type = void; |
345 | using Func = QQmlAttachedPropertiesFunc<QObject>; |
346 | static const QMetaObject *staticMetaObject() { return nullptr; } |
347 | static Func attachedPropertiesFunc() { return nullptr; } |
348 | }; |
349 | |
350 | // Defined inline via QML_ATTACHED |
351 | template<class T> |
352 | struct QmlAttached<T, std::void_t<typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type>, false> |
353 | { |
354 | // Normal attached properties |
355 | template <typename Parent, typename Attached> |
356 | struct Properties |
357 | { |
358 | using Func = QQmlAttachedPropertiesFunc<Attached>; |
359 | static const QMetaObject *staticMetaObject() { return &Attached::staticMetaObject; } |
360 | static Func attachedPropertiesFunc() { return Parent::qmlAttachedProperties; } |
361 | }; |
362 | |
363 | // Disabled via OverridableAttachedType |
364 | template<typename Parent> |
365 | struct Properties<Parent, void> |
366 | { |
367 | using Func = QQmlAttachedPropertiesFunc<QObject>; |
368 | static const QMetaObject *staticMetaObject() { return nullptr; }; |
369 | static Func attachedPropertiesFunc() { return nullptr; }; |
370 | }; |
371 | |
372 | using Type = typename std::conditional< |
373 | QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_attached)>::value, |
374 | typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type, void>::type; |
375 | using Func = typename Properties<T, Type>::Func; |
376 | |
377 | static const QMetaObject *staticMetaObject() |
378 | { |
379 | return Properties<T, Type>::staticMetaObject(); |
380 | } |
381 | |
382 | static Func attachedPropertiesFunc() |
383 | { |
384 | return Properties<T, Type>::attachedPropertiesFunc(); |
385 | } |
386 | }; |
387 | |
388 | // Separately defined via QQmlTypeInfo |
389 | template<class T> |
390 | struct QmlAttached<T, std::void_t<decltype(T::qmlAttachedProperties)>, true> |
391 | { |
392 | using Type = typename std::remove_pointer<decltype(T::qmlAttachedProperties(nullptr))>::type; |
393 | using Func = QQmlAttachedPropertiesFunc<Type>; |
394 | |
395 | static const QMetaObject *staticMetaObject() { return &Type::staticMetaObject; } |
396 | static Func attachedPropertiesFunc() { return T::qmlAttachedProperties; } |
397 | }; |
398 | |
399 | // This is necessary because both the type containing a default template parameter and the type |
400 | // instantiating the template need to have access to the default template parameter type. In |
401 | // this case that's T::QmlAttachedType. The QML_FOREIGN macro needs to befriend specific other |
402 | // types. Therefore we need some kind of "accessor". Because of compiler bugs in gcc and clang, |
403 | // we cannot befriend attachedPropertiesFunc() directly. Wrapping the actual access into another |
404 | // struct "fixes" that. For convenience we still want the free standing functions in addition. |
405 | template<class T> |
406 | struct QmlAttachedAccessor |
407 | { |
408 | static QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunc() |
409 | { |
410 | return QQmlAttachedPropertiesFunc<QObject>(QmlAttached<T>::attachedPropertiesFunc()); |
411 | } |
412 | |
413 | static const QMetaObject *staticMetaObject() |
414 | { |
415 | return QmlAttached<T>::staticMetaObject(); |
416 | } |
417 | }; |
418 | |
419 | template<typename T> |
420 | inline QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunc() |
421 | { |
422 | return QmlAttachedAccessor<T>::attachedPropertiesFunc(); |
423 | } |
424 | |
425 | template<typename T> |
426 | inline const QMetaObject *attachedPropertiesMetaObject() |
427 | { |
428 | return QmlAttachedAccessor<T>::staticMetaObject(); |
429 | } |
430 | |
431 | enum AutoParentResult { Parented, IncompatibleObject, IncompatibleParent }; |
432 | typedef AutoParentResult (*AutoParentFunction)(QObject *object, QObject *parent); |
433 | |
434 | enum class ValueTypeCreationMethod { None, Construct, Structured }; |
435 | |
436 | struct RegisterType { |
437 | enum StructVersion: int { |
438 | Base = 0, |
439 | FinalizerCast = 1, |
440 | CreationMethod = 2, |
441 | CurrentVersion = CreationMethod, |
442 | }; |
443 | |
444 | bool has(StructVersion v) const { return structVersion >= int(v); } |
445 | |
446 | int structVersion; |
447 | |
448 | QMetaType typeId; |
449 | QMetaType listId; |
450 | int objectSize; |
451 | // The second parameter of create is for userdata |
452 | void (*create)(void *, void *); |
453 | void *userdata; |
454 | QString noCreationReason; |
455 | |
456 | // ### Qt7: Get rid of this. It can be covered by creationMethod below. |
457 | QVariant (*createValueType)(const QJSValue &); |
458 | |
459 | const char *uri; |
460 | QTypeRevision version; |
461 | const char *elementName; |
462 | const QMetaObject *metaObject; |
463 | |
464 | QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunction; |
465 | const QMetaObject *attachedPropertiesMetaObject; |
466 | |
467 | int parserStatusCast; |
468 | int valueSourceCast; |
469 | int valueInterceptorCast; |
470 | |
471 | QObject *(*extensionObjectCreate)(QObject *); |
472 | const QMetaObject *extensionMetaObject; |
473 | |
474 | QQmlCustomParser *customParser; |
475 | |
476 | QTypeRevision revision; |
477 | int finalizerCast; |
478 | |
479 | ValueTypeCreationMethod creationMethod; |
480 | // If this is extended ensure "version" is bumped!!! |
481 | }; |
482 | |
483 | struct RegisterTypeAndRevisions { |
484 | int structVersion; |
485 | |
486 | QMetaType typeId; |
487 | QMetaType listId; |
488 | int objectSize; |
489 | void (*create)(void *, void *); |
490 | void *userdata; |
491 | |
492 | QVariant (*createValueType)(const QJSValue &); |
493 | |
494 | const char *uri; |
495 | QTypeRevision version; |
496 | |
497 | const QMetaObject *metaObject; |
498 | const QMetaObject *classInfoMetaObject; |
499 | |
500 | QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunction; |
501 | const QMetaObject *attachedPropertiesMetaObject; |
502 | |
503 | int parserStatusCast; |
504 | int valueSourceCast; |
505 | int valueInterceptorCast; |
506 | |
507 | QObject *(*extensionObjectCreate)(QObject *); |
508 | const QMetaObject *extensionMetaObject; |
509 | |
510 | QQmlCustomParser *(*customParserFactory)(); |
511 | QVector<int> *qmlTypeIds; |
512 | int finalizerCast; |
513 | |
514 | bool forceAnonymous; |
515 | QMetaSequence listMetaSequence; |
516 | }; |
517 | |
518 | struct RegisterInterface { |
519 | int structVersion; |
520 | |
521 | QMetaType typeId; |
522 | QMetaType listId; |
523 | |
524 | const char *iid; |
525 | |
526 | const char *uri; |
527 | QTypeRevision version; |
528 | }; |
529 | |
530 | struct RegisterAutoParent { |
531 | int structVersion; |
532 | |
533 | AutoParentFunction function; |
534 | }; |
535 | |
536 | struct RegisterSingletonType { |
537 | int structVersion; |
538 | |
539 | const char *uri; |
540 | QTypeRevision version; |
541 | const char *typeName; |
542 | |
543 | std::function<QJSValue(QQmlEngine *, QJSEngine *)> scriptApi; |
544 | std::function<QObject*(QQmlEngine *, QJSEngine *)> qObjectApi; |
545 | |
546 | const QMetaObject *instanceMetaObject; |
547 | QMetaType typeId; |
548 | |
549 | QObject *(*extensionObjectCreate)(QObject *); |
550 | const QMetaObject *extensionMetaObject; |
551 | |
552 | QTypeRevision revision; |
553 | }; |
554 | |
555 | struct RegisterSingletonTypeAndRevisions { |
556 | int structVersion; |
557 | const char *uri; |
558 | QTypeRevision version; |
559 | |
560 | std::function<QObject*(QQmlEngine *, QJSEngine *)> qObjectApi; |
561 | |
562 | const QMetaObject *instanceMetaObject; |
563 | const QMetaObject *classInfoMetaObject; |
564 | |
565 | QMetaType typeId; |
566 | |
567 | QObject *(*extensionObjectCreate)(QObject *); |
568 | const QMetaObject *extensionMetaObject; |
569 | |
570 | QVector<int> *qmlTypeIds; |
571 | }; |
572 | |
573 | struct RegisterCompositeType { |
574 | int structVersion; |
575 | QUrl url; |
576 | const char *uri; |
577 | QTypeRevision version; |
578 | const char *typeName; |
579 | }; |
580 | |
581 | struct RegisterCompositeSingletonType { |
582 | int structVersion; |
583 | QUrl url; |
584 | const char *uri; |
585 | QTypeRevision version; |
586 | const char *typeName; |
587 | }; |
588 | |
589 | struct RegisterSequentialContainer { |
590 | int structVersion; |
591 | const char *uri; |
592 | QTypeRevision version; |
593 | |
594 | // ### Qt7: Remove typeName. It's ignored because the only valid name is "list", |
595 | // and that's automatic. |
596 | const char *typeName; |
597 | |
598 | QMetaType typeId; |
599 | QMetaSequence metaSequence; |
600 | QTypeRevision revision; |
601 | }; |
602 | |
603 | struct RegisterSequentialContainerAndRevisions { |
604 | int structVersion; |
605 | const char *uri; |
606 | QTypeRevision version; |
607 | |
608 | const QMetaObject *classInfoMetaObject; |
609 | QMetaType typeId; |
610 | QMetaSequence metaSequence; |
611 | |
612 | QVector<int> *qmlTypeIds; |
613 | }; |
614 | |
615 | struct Q_QML_EXPORT AOTCompiledContext { |
616 | enum: uint { InvalidStringId = (std::numeric_limits<uint>::max)() }; |
617 | |
618 | QQmlContextData *qmlContext; |
619 | QObject *qmlScopeObject; |
620 | QJSEngine *engine; |
621 | union { |
622 | QV4::ExecutableCompilationUnit *compilationUnit; |
623 | qintptr ; |
624 | }; |
625 | |
626 | QObject *thisObject() const; |
627 | QQmlEngine *qmlEngine() const; |
628 | |
629 | QJSValue jsMetaType(int index) const; |
630 | void setInstructionPointer(int offset) const; |
631 | void setReturnValueUndefined() const; |
632 | |
633 | // Run QQmlPropertyCapture::captureProperty() without retrieving the value. |
634 | bool captureLookup(uint index, QObject *object) const; |
635 | bool captureQmlContextPropertyLookup(uint index) const; |
636 | void captureTranslation() const; |
637 | QString translationContext() const; |
638 | QMetaType lookupResultMetaType(uint index) const; |
639 | void storeNameSloppy(uint nameIndex, void *value, QMetaType type) const; |
640 | QJSValue javaScriptGlobalProperty(uint nameIndex) const; |
641 | |
642 | const QLoggingCategory *resolveLoggingCategory(QObject *wrapper, bool *ok) const; |
643 | |
644 | void writeToConsole( |
645 | QtMsgType type, const QString &message, |
646 | const QLoggingCategory *loggingCategory) const; |
647 | |
648 | QVariant constructValueType( |
649 | QMetaType resultMetaType, const QMetaObject *resultMetaObject, |
650 | int ctorIndex, void *ctorArg) const; |
651 | |
652 | // All of these lookup functions should be used as follows: |
653 | // |
654 | // while (!fooBarLookup(...)) { |
655 | // setInstructionPointer(...); |
656 | // initFooBarLookup(...); |
657 | // if (engine->hasException()) { |
658 | // ... |
659 | // break; |
660 | // } |
661 | // } |
662 | // |
663 | // The bool-returning *Lookup functions exclusively run the happy path and return false if |
664 | // that fails in any way. The failure may either be in the lookup structs not being |
665 | // initialized or an exception being thrown. |
666 | // The init*Lookup functions initialize the lookup structs and amend any exceptions |
667 | // previously thrown with line numbers. They might also throw their own exceptions. If an |
668 | // exception is present after the initialization there is no way to carry out the lookup and |
669 | // the exception should be propagated. If not, the original lookup can be tried again. |
670 | |
671 | bool callQmlContextPropertyLookup( |
672 | uint index, void **args, const QMetaType *types, int argc) const; |
673 | void initCallQmlContextPropertyLookup(uint index) const; |
674 | |
675 | bool loadContextIdLookup(uint index, void *target) const; |
676 | void initLoadContextIdLookup(uint index) const; |
677 | |
678 | bool callObjectPropertyLookup(uint index, QObject *object, |
679 | void **args, const QMetaType *types, int argc) const; |
680 | void initCallObjectPropertyLookup(uint index) const; |
681 | |
682 | bool callGlobalLookup(uint index, void **args, const QMetaType *types, int argc) const; |
683 | void initCallGlobalLookup(uint index) const; |
684 | |
685 | bool loadGlobalLookup(uint index, void *target, QMetaType type) const; |
686 | void initLoadGlobalLookup(uint index) const; |
687 | |
688 | bool loadScopeObjectPropertyLookup(uint index, void *target) const; |
689 | void initLoadScopeObjectPropertyLookup(uint index, QMetaType type) const; |
690 | |
691 | bool loadSingletonLookup(uint index, void *target) const; |
692 | void initLoadSingletonLookup(uint index, uint importNamespace) const; |
693 | |
694 | bool loadAttachedLookup(uint index, QObject *object, void *target) const; |
695 | void initLoadAttachedLookup(uint index, uint importNamespace, QObject *object) const; |
696 | |
697 | bool loadTypeLookup(uint index, void *target) const; |
698 | void initLoadTypeLookup(uint index, uint importNamespace) const; |
699 | |
700 | bool getObjectLookup(uint index, QObject *object, void *target) const; |
701 | void initGetObjectLookup(uint index, QObject *object, QMetaType type) const; |
702 | |
703 | bool getValueLookup(uint index, void *value, void *target) const; |
704 | void initGetValueLookup(uint index, const QMetaObject *metaObject, QMetaType type) const; |
705 | |
706 | bool getEnumLookup(uint index, void *target) const; |
707 | void initGetEnumLookup(uint index, const QMetaObject *metaObject, |
708 | const char *enumerator, const char *enumValue) const; |
709 | |
710 | bool setObjectLookup(uint index, QObject *object, void *value) const; |
711 | void initSetObjectLookup(uint index, QObject *object, QMetaType type) const; |
712 | |
713 | bool setValueLookup(uint index, void *target, void *value) const; |
714 | void initSetValueLookup(uint index, const QMetaObject *metaObject, QMetaType type) const; |
715 | }; |
716 | |
717 | struct AOTCompiledFunction { |
718 | qintptr ; |
719 | QMetaType returnType; |
720 | QList<QMetaType> argumentTypes; |
721 | void (*functionPtr)(const AOTCompiledContext *context, void *resultPtr, void **arguments); |
722 | }; |
723 | |
724 | #if QT_DEPRECATED_SINCE(6, 6) |
725 | QT_DEPRECATED_VERSION_X(6, 6, "Use AOTCompiledFunction instead" ) |
726 | typedef AOTCompiledFunction TypedFunction; |
727 | #endif |
728 | |
729 | struct CachedQmlUnit { |
730 | const QV4::CompiledData::Unit *qmlData; |
731 | const AOTCompiledFunction *aotCompiledFunctions; |
732 | void *unused2; |
733 | }; |
734 | |
735 | typedef const CachedQmlUnit *(*QmlUnitCacheLookupFunction)(const QUrl &url); |
736 | struct RegisterQmlUnitCacheHook { |
737 | int structVersion; |
738 | QmlUnitCacheLookupFunction lookupCachedQmlUnit; |
739 | }; |
740 | |
741 | enum RegistrationType { |
742 | TypeRegistration = 0, |
743 | InterfaceRegistration = 1, |
744 | AutoParentRegistration = 2, |
745 | SingletonRegistration = 3, |
746 | CompositeRegistration = 4, |
747 | CompositeSingletonRegistration = 5, |
748 | QmlUnitCacheHookRegistration = 6, |
749 | TypeAndRevisionsRegistration = 7, |
750 | SingletonAndRevisionsRegistration = 8, |
751 | SequentialContainerRegistration = 9, |
752 | SequentialContainerAndRevisionsRegistration = 10, |
753 | }; |
754 | |
755 | int Q_QML_EXPORT qmlregister(RegistrationType, void *); |
756 | void Q_QML_EXPORT qmlunregister(RegistrationType, quintptr); |
757 | |
758 | #if QT_DEPRECATED_SINCE(6, 3) |
759 | struct Q_QML_EXPORT SingletonFunctor |
760 | { |
761 | QT_DEPRECATED QObject *operator()(QQmlEngine *, QJSEngine *); |
762 | QPointer<QObject> m_object; |
763 | bool alreadyCalled = false; |
764 | }; |
765 | #endif |
766 | |
767 | struct Q_QML_EXPORT SingletonInstanceFunctor |
768 | { |
769 | QObject *operator()(QQmlEngine *, QJSEngine *); |
770 | |
771 | QPointer<QObject> m_object; |
772 | |
773 | // Not a QPointer, so that you cannot assign it to a different |
774 | // engine when the first one is deleted. |
775 | // That would mess up the QML contexts. |
776 | QQmlEngine *m_engine = nullptr; |
777 | }; |
778 | |
779 | static int indexOfOwnClassInfo(const QMetaObject *metaObject, const char *key, int startOffset = -1) |
780 | { |
781 | if (!metaObject || !key) |
782 | return -1; |
783 | |
784 | const int offset = metaObject->classInfoOffset(); |
785 | const int start = (startOffset == -1) |
786 | ? (metaObject->classInfoCount() + offset - 1) |
787 | : startOffset; |
788 | for (int i = start; i >= offset; --i) |
789 | if (qstrcmp(str1: key, str2: metaObject->classInfo(index: i).name()) == 0) { |
790 | return i; |
791 | } |
792 | return -1; |
793 | } |
794 | |
795 | inline const char *classInfo(const QMetaObject *metaObject, const char *key) |
796 | { |
797 | return metaObject->classInfo(index: indexOfOwnClassInfo(metaObject, key)).value(); |
798 | } |
799 | |
800 | inline QTypeRevision revisionClassInfo(const QMetaObject *metaObject, const char *key, |
801 | QTypeRevision defaultValue = QTypeRevision()) |
802 | { |
803 | const int index = indexOfOwnClassInfo(metaObject, key); |
804 | return (index == -1) ? defaultValue |
805 | : QTypeRevision::fromEncodedVersion( |
806 | value: QLatin1StringView(metaObject->classInfo(index).value()).toInt()); |
807 | } |
808 | |
809 | Q_QML_EXPORT QList<QTypeRevision> revisionClassInfos(const QMetaObject *metaObject, const char *key); |
810 | |
811 | inline bool boolClassInfo(const QMetaObject *metaObject, const char *key, |
812 | bool defaultValue = false) |
813 | { |
814 | const int index = indexOfOwnClassInfo(metaObject, key); |
815 | if (index == -1) |
816 | return defaultValue; |
817 | return qstrcmp(str1: metaObject->classInfo(index).value(), str2: "true" ) == 0; |
818 | } |
819 | |
820 | inline const char *classElementName(const QMetaObject *metaObject) |
821 | { |
822 | const char *elementName = classInfo(metaObject, key: "QML.Element" ); |
823 | if (qstrcmp(str1: elementName, str2: "auto" ) == 0) { |
824 | const char *strippedClassName = metaObject->className(); |
825 | for (const char *c = strippedClassName; *c != '\0'; c++) { |
826 | if (*c == ':') |
827 | strippedClassName = c + 1; |
828 | } |
829 | |
830 | return strippedClassName; |
831 | } |
832 | if (qstrcmp(str1: elementName, str2: "anonymous" ) == 0) |
833 | return nullptr; |
834 | |
835 | if (!elementName) { |
836 | qWarning().nospace() << "Missing QML.Element class info \"" << elementName << "\"" |
837 | << " for " << metaObject->className(); |
838 | } |
839 | |
840 | return elementName; |
841 | } |
842 | |
843 | template<class T, class = std::void_t<>> |
844 | struct QmlExtended |
845 | { |
846 | using Type = void; |
847 | }; |
848 | |
849 | template<class T> |
850 | struct QmlExtended<T, std::void_t<typename T::QmlExtendedType>> |
851 | { |
852 | using Type = typename std::conditional< |
853 | QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_extended)>::value, |
854 | typename T::QmlExtendedType, void>::type; |
855 | }; |
856 | |
857 | template<class T, class = std::void_t<>> |
858 | struct QmlExtendedNamespace |
859 | { |
860 | static constexpr const QMetaObject *metaObject() { return nullptr; } |
861 | }; |
862 | |
863 | template<class T> |
864 | struct QmlExtendedNamespace<T, std::void_t<decltype(T::qmlExtendedNamespace())>> |
865 | { |
866 | static constexpr const QMetaObject *metaObject() |
867 | { |
868 | if constexpr (QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_extendedNamespace)>::value) |
869 | return T::qmlExtendedNamespace(); |
870 | else |
871 | return nullptr; |
872 | } |
873 | }; |
874 | |
875 | template<class T, class = std::void_t<>> |
876 | struct QmlResolved |
877 | { |
878 | using Type = T; |
879 | }; |
880 | |
881 | template<class T> |
882 | struct QmlResolved<T, std::void_t<typename T::QmlForeignType>> |
883 | { |
884 | using Type = typename std::conditional< |
885 | QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_foreign)>::value, |
886 | typename T::QmlForeignType, T>::type; |
887 | }; |
888 | |
889 | template<class T, class = std::void_t<>> |
890 | struct QmlUncreatable |
891 | { |
892 | static constexpr bool Value = false; |
893 | }; |
894 | |
895 | template<class T> |
896 | struct QmlUncreatable<T, std::void_t<typename T::QmlIsUncreatable>> |
897 | { |
898 | static constexpr bool Value = |
899 | QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_uncreatable)>::value |
900 | && bool(T::QmlIsUncreatable::yes); |
901 | }; |
902 | |
903 | template<class T, class = std::void_t<>> |
904 | struct QmlAnonymous |
905 | { |
906 | static constexpr bool Value = false; |
907 | }; |
908 | |
909 | template<class T> |
910 | struct QmlAnonymous<T, std::void_t<typename T::QmlIsAnonymous>> |
911 | { |
912 | static constexpr bool Value = |
913 | QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_anonymous)>::value |
914 | && bool(T::QmlIsAnonymous::yes); |
915 | }; |
916 | |
917 | |
918 | template<class T, class = std::void_t<>> |
919 | struct QmlSingleton |
920 | { |
921 | static constexpr bool Value = false; |
922 | }; |
923 | |
924 | template<class T> |
925 | struct QmlSingleton<T, std::void_t<typename T::QmlIsSingleton>> |
926 | { |
927 | static constexpr bool Value = |
928 | QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_singleton)>::value |
929 | && bool(T::QmlIsSingleton::yes); |
930 | }; |
931 | |
932 | template<class T, class = std::void_t<>> |
933 | struct QmlSequence |
934 | { |
935 | static constexpr bool Value = false; |
936 | }; |
937 | |
938 | template<class T> |
939 | struct QmlSequence<T, std::void_t<typename T::QmlIsSequence>> |
940 | { |
941 | Q_STATIC_ASSERT((std::is_same_v<typename T::QmlSequenceValueType, |
942 | typename QmlResolved<T>::Type::value_type>)); |
943 | static constexpr bool Value = bool(T::QmlIsSequence::yes); |
944 | }; |
945 | |
946 | template<class T, class = std::void_t<>> |
947 | struct QmlInterface |
948 | { |
949 | static constexpr bool Value = false; |
950 | }; |
951 | |
952 | template<class T> |
953 | struct QmlInterface<T, std::void_t<typename T::QmlIsInterface>> |
954 | { |
955 | static constexpr bool Value = bool(T::QmlIsInterface::yes); |
956 | }; |
957 | |
958 | template<class T, typename = std::void_t<>> |
959 | struct StaticMetaObject |
960 | { |
961 | static const QMetaObject *staticMetaObject() { return nullptr; } |
962 | }; |
963 | |
964 | template<class T> |
965 | struct StaticMetaObject<T, std::void_t<decltype(T::staticMetaObject)>> |
966 | { |
967 | static const QMetaObject *staticMetaObject() { return &T::staticMetaObject; } |
968 | }; |
969 | |
970 | template<class T> |
971 | struct QmlMetaType |
972 | { |
973 | static constexpr bool hasAcceptableCtors() |
974 | { |
975 | if constexpr (!std::is_default_constructible_v<T>) |
976 | return false; |
977 | else if constexpr (std::is_base_of_v<QObject, T>) |
978 | return true; |
979 | else |
980 | return std::is_copy_constructible_v<T>; |
981 | } |
982 | |
983 | static QMetaType self() |
984 | { |
985 | if constexpr (std::is_base_of_v<QObject, T>) |
986 | return QMetaType::fromType<T*>(); |
987 | else |
988 | return QMetaType::fromType<T>(); |
989 | } |
990 | |
991 | static QMetaType list() |
992 | { |
993 | if constexpr (std::is_base_of_v<QObject, T>) |
994 | return QMetaType::fromType<QQmlListProperty<T>>(); |
995 | else |
996 | return QMetaType::fromType<QList<T>>(); |
997 | } |
998 | |
999 | static QMetaSequence sequence() |
1000 | { |
1001 | if constexpr (std::is_base_of_v<QObject, T>) |
1002 | return QMetaSequence(); |
1003 | else |
1004 | return QMetaSequence::fromContainer<QList<T>>(); |
1005 | } |
1006 | }; |
1007 | |
1008 | template<typename T, typename E, typename WrapperT = T> |
1009 | void qmlRegisterSingletonAndRevisions(const char *uri, int versionMajor, |
1010 | const QMetaObject *classInfoMetaObject, |
1011 | QVector<int> *qmlTypeIds, const QMetaObject *extension) |
1012 | { |
1013 | static_assert(std::is_base_of_v<QObject, T>); |
1014 | RegisterSingletonTypeAndRevisions api = { |
1015 | 0, |
1016 | |
1017 | uri, |
1018 | QTypeRevision::fromMajorVersion(majorVersion: versionMajor), |
1019 | |
1020 | Constructors<T, WrapperT>::createSingletonInstance, |
1021 | |
1022 | StaticMetaObject<T>::staticMetaObject(), |
1023 | classInfoMetaObject, |
1024 | |
1025 | QmlMetaType<T>::self(), |
1026 | |
1027 | ExtendedType<E>::createParent, |
1028 | extension ? extension : ExtendedType<E>::staticMetaObject(), |
1029 | |
1030 | qmlTypeIds |
1031 | }; |
1032 | |
1033 | qmlregister(SingletonAndRevisionsRegistration, &api); |
1034 | } |
1035 | |
1036 | template<typename T, typename E> |
1037 | void qmlRegisterTypeAndRevisions(const char *uri, int versionMajor, |
1038 | const QMetaObject *classInfoMetaObject, |
1039 | QVector<int> *qmlTypeIds, const QMetaObject *extension, |
1040 | bool forceAnonymous = false) |
1041 | { |
1042 | RegisterTypeAndRevisions type = { |
1043 | 3, |
1044 | QmlMetaType<T>::self(), |
1045 | QmlMetaType<T>::list(), |
1046 | int(sizeof(T)), |
1047 | Constructors<T>::createInto, |
1048 | nullptr, |
1049 | ValueType<T, E>::create, |
1050 | |
1051 | uri, |
1052 | QTypeRevision::fromMajorVersion(majorVersion: versionMajor), |
1053 | |
1054 | StaticMetaObject<T>::staticMetaObject(), |
1055 | classInfoMetaObject, |
1056 | |
1057 | attachedPropertiesFunc<T>(), |
1058 | attachedPropertiesMetaObject<T>(), |
1059 | |
1060 | StaticCastSelector<T, QQmlParserStatus>::cast(), |
1061 | StaticCastSelector<T, QQmlPropertyValueSource>::cast(), |
1062 | StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(), |
1063 | |
1064 | ExtendedType<E>::createParent, |
1065 | extension ? extension : ExtendedType<E>::staticMetaObject(), |
1066 | |
1067 | &qmlCreateCustomParser<T>, |
1068 | qmlTypeIds, |
1069 | StaticCastSelector<T, QQmlFinalizerHook>::cast(), |
1070 | |
1071 | forceAnonymous, |
1072 | QmlMetaType<T>::sequence(), |
1073 | }; |
1074 | |
1075 | // Initialize the extension so that we can find it by name or ID. |
1076 | qMetaTypeId<E>(); |
1077 | |
1078 | qmlregister(TypeAndRevisionsRegistration, &type); |
1079 | } |
1080 | |
1081 | template<typename T> |
1082 | void qmlRegisterSequenceAndRevisions(const char *uri, int versionMajor, |
1083 | const QMetaObject *classInfoMetaObject, |
1084 | QVector<int> *qmlTypeIds) |
1085 | { |
1086 | RegisterSequentialContainerAndRevisions type = { |
1087 | 0, |
1088 | uri, |
1089 | QTypeRevision::fromMajorVersion(majorVersion: versionMajor), |
1090 | classInfoMetaObject, |
1091 | QMetaType::fromType<T>(), |
1092 | QMetaSequence::fromContainer<T>(), |
1093 | qmlTypeIds |
1094 | }; |
1095 | |
1096 | qmlregister(SequentialContainerAndRevisionsRegistration, &type); |
1097 | } |
1098 | |
1099 | template<> |
1100 | void Q_QML_EXPORT qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>( |
1101 | const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject, |
1102 | QVector<int> *qmlTypeIds, const QMetaObject *, bool); |
1103 | |
1104 | constexpr QtPrivate::QMetaTypeInterface metaTypeForNamespace( |
1105 | const QtPrivate::QMetaTypeInterface::MetaObjectFn &metaObjectFunction, const char *name) |
1106 | { |
1107 | return { |
1108 | /*.revision=*/ .revision: 0, |
1109 | /*.alignment=*/ .alignment: 0, |
1110 | /*.size=*/ .size: 0, |
1111 | /*.flags=*/ .flags: 0, |
1112 | /*.typeId=*/ .typeId: {}, |
1113 | /*.metaObject=*/ .metaObjectFn: metaObjectFunction, |
1114 | /*.name=*/ .name: name, |
1115 | /*.defaultCtr=*/ .defaultCtr: nullptr, |
1116 | /*.copyCtr=*/ .copyCtr: nullptr, |
1117 | /*.moveCtr=*/ .moveCtr: nullptr, |
1118 | /*.dtor=*/ .dtor: nullptr, |
1119 | /*.equals*/ .equals: nullptr, |
1120 | /*.lessThan*/ .lessThan: nullptr, |
1121 | /*.debugStream=*/ .debugStream: nullptr, |
1122 | /*.dataStreamOut=*/ .dataStreamOut: nullptr, |
1123 | /*.dataStreamIn=*/ .dataStreamIn: nullptr, |
1124 | /*.legacyRegisterOp=*/ .legacyRegisterOp: nullptr |
1125 | }; |
1126 | } |
1127 | |
1128 | Q_QML_EXPORT QObject *qmlExtendedObject(QObject *, int); |
1129 | |
1130 | enum QmlRegistrationWarning { |
1131 | UnconstructibleType, |
1132 | UnconstructibleSingleton, |
1133 | NonQObjectWithAtached, |
1134 | }; |
1135 | |
1136 | Q_QML_EXPORT void qmlRegistrationWarning(QmlRegistrationWarning warning, QMetaType type); |
1137 | |
1138 | } // namespace QQmlPrivate |
1139 | |
1140 | QT_END_NAMESPACE |
1141 | |
1142 | #endif // QQMLPRIVATE_H |
1143 | |