1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QQMLPRIVATE_H
41#define QQMLPRIVATE_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API. It exists purely as an
48// implementation detail. This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53
54#include <functional>
55#include <type_traits>
56
57#include <QtQml/qtqmlglobal.h>
58#include <QtQml/qqmlparserstatus.h>
59#include <QtQml/qqmllist.h>
60#include <QtQml/qqmlpropertyvaluesource.h>
61
62#include <QtCore/qglobal.h>
63#include <QtCore/qvariant.h>
64#include <QtCore/qurl.h>
65#include <QtCore/qpointer.h>
66
67#include <QtCore/qmetaobject.h>
68#include <QtCore/qdebug.h>
69
70#define QML_GETTYPENAMES \
71 const char *className = T::staticMetaObject.className(); \
72 const int nameLen = int(strlen(className)); \
73 QVarLengthArray<char,48> pointerName(nameLen+2); \
74 memcpy(pointerName.data(), className, size_t(nameLen)); \
75 pointerName[nameLen] = '*'; \
76 pointerName[nameLen+1] = '\0'; \
77 const int listLen = int(strlen("QQmlListProperty<")); \
78 QVarLengthArray<char,64> listName(listLen + nameLen + 2); \
79 memcpy(listName.data(), "QQmlListProperty<", size_t(listLen)); \
80 memcpy(listName.data()+listLen, className, size_t(nameLen)); \
81 listName[listLen+nameLen] = '>'; \
82 listName[listLen+nameLen+1] = '\0';
83
84QT_BEGIN_NAMESPACE
85
86class QQmlPropertyValueInterceptor;
87
88namespace QQmlPrivate {
89struct CachedQmlUnit;
90template<typename A>
91using QQmlAttachedPropertiesFunc = A *(*)(QObject *);
92}
93
94namespace QV4 {
95struct ExecutionEngine;
96namespace CompiledData {
97struct Unit;
98struct CompilationUnit;
99}
100}
101namespace QmlIR {
102struct Document;
103typedef void (*IRLoaderFunction)(Document *, const QQmlPrivate::CachedQmlUnit *);
104}
105
106using QQmlAttachedPropertiesFunc = QQmlPrivate::QQmlAttachedPropertiesFunc<QObject>;
107
108inline uint qHash(QQmlAttachedPropertiesFunc func, uint seed = 0)
109{
110 return qHash(key: quintptr(func), seed);
111}
112
113template <typename TYPE>
114class QQmlTypeInfo
115{
116public:
117 enum {
118 hasAttachedProperties = 0
119 };
120};
121
122
123class QJSValue;
124class QJSEngine;
125class QQmlEngine;
126class QQmlCustomParser;
127class QQmlTypeNotAvailable;
128
129template<class T>
130QQmlCustomParser *qmlCreateCustomParser()
131{
132 return nullptr;
133}
134
135namespace QQmlPrivate
136{
137 void Q_QML_EXPORT qdeclarativeelement_destructor(QObject *);
138 template<typename T>
139 class QQmlElement final : public T
140 {
141 public:
142 ~QQmlElement() override {
143 QQmlPrivate::qdeclarativeelement_destructor(this);
144 }
145 static void operator delete(void *ptr) {
146 // We allocate memory from this class in QQmlType::create
147 // along with some additional memory.
148 // So we override the operator delete in order to avoid the
149 // sized operator delete to be called with a different size than
150 // the size that was allocated.
151 ::operator delete (ptr);
152 }
153 static void operator delete(void *, void *) {
154 // Deliberately empty placement delete operator.
155 // Silences MSVC warning C4291: no matching operator delete found
156 }
157 };
158
159 template<typename T>
160 constexpr bool isConstructible()
161 {
162 return std::is_default_constructible<T>::value && std::is_base_of<QObject, T>::value;
163 }
164
165 template<typename T>
166 void createInto(void *memory) { new (memory) QQmlElement<T>; }
167
168 template<typename T>
169 QObject *createSingletonInstance(QQmlEngine *, QJSEngine *) { return new T; }
170
171 template<typename T>
172 QObject *createParent(QObject *p) { return new T(p); }
173
174 using CreateIntoFunction = void (*)(void *);
175 using CreateSingletonFunction = QObject *(*)(QQmlEngine *, QJSEngine *);
176 using CreateParentFunction = QObject *(*)(QObject *);
177
178 template<typename T, bool Constructible = isConstructible<T>()>
179 struct Constructors;
180
181 template<typename T>
182 struct Constructors<T, true>
183 {
184 static constexpr CreateIntoFunction createInto
185 = QQmlPrivate::createInto<T>;
186 static constexpr CreateSingletonFunction createSingletonInstance
187 = QQmlPrivate::createSingletonInstance<T>;
188 };
189
190 template<typename T>
191 struct Constructors<T, false>
192 {
193 static constexpr CreateIntoFunction createInto = nullptr;
194 static constexpr CreateSingletonFunction createSingletonInstance = nullptr;
195 };
196
197 template<typename T, bool IsVoid = std::is_void<T>::value>
198 struct ExtendedType;
199
200 // void means "not an extended type"
201 template<typename T>
202 struct ExtendedType<T, true>
203 {
204 static constexpr const CreateParentFunction createParent = nullptr;
205 static constexpr const QMetaObject *staticMetaObject = nullptr;
206 };
207
208 // If it's not void, we actually want an error if the ctor or the metaobject is missing.
209 template<typename T>
210 struct ExtendedType<T, false>
211 {
212 static constexpr const CreateParentFunction createParent = QQmlPrivate::createParent<T>;
213 static constexpr const QMetaObject *staticMetaObject = &T::staticMetaObject;
214 };
215
216 template<class From, class To, int N>
217 struct StaticCastSelectorClass
218 {
219 static inline int cast() { return -1; }
220 };
221
222 template<class From, class To>
223 struct StaticCastSelectorClass<From, To, sizeof(int)>
224 {
225 static inline int cast() { return int(reinterpret_cast<quintptr>(static_cast<To *>(reinterpret_cast<From *>(0x10000000)))) - 0x10000000; }
226 };
227
228 template<class From, class To>
229 struct StaticCastSelector
230 {
231 typedef int yes_type;
232 typedef char no_type;
233
234 static yes_type checkType(To *);
235 static no_type checkType(...);
236
237 static inline int cast()
238 {
239 return StaticCastSelectorClass<From, To, sizeof(checkType(reinterpret_cast<From *>(0)))>::cast();
240 }
241 };
242
243 template<typename...>
244 using QmlVoidT = void;
245
246 // You can prevent subclasses from using the same attached type by specialzing this.
247 // This is reserved for internal types, though.
248 template<class T, class A>
249 struct OverridableAttachedType
250 {
251 using Type = A;
252 };
253
254 template<class T, class = QmlVoidT<>, bool OldStyle = QQmlTypeInfo<T>::hasAttachedProperties>
255 struct QmlAttached
256 {
257 using Type = void;
258 using Func = QQmlAttachedPropertiesFunc<QObject>;
259 static const QMetaObject *staticMetaObject() { return nullptr; }
260 static Func attachedPropertiesFunc() { return nullptr; }
261 };
262
263 // Defined inline via QML_ATTACHED
264 template<class T>
265 struct QmlAttached<T, QmlVoidT<typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type>, false>
266 {
267 // Normal attached properties
268 template <typename Parent, typename Attached>
269 struct Properties
270 {
271 using Func = QQmlAttachedPropertiesFunc<Attached>;
272 static const QMetaObject *staticMetaObject() { return &Attached::staticMetaObject; }
273 static Func attachedPropertiesFunc() { return Parent::qmlAttachedProperties; }
274 };
275
276 // Disabled via OverridableAttachedType
277 template<typename Parent>
278 struct Properties<Parent, void>
279 {
280 using Func = QQmlAttachedPropertiesFunc<QObject>;
281 static const QMetaObject *staticMetaObject() { return nullptr; };
282 static Func attachedPropertiesFunc() { return nullptr; };
283 };
284
285 using Type = typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type;
286 using Func = typename Properties<T, Type>::Func;
287
288 static const QMetaObject *staticMetaObject()
289 {
290 return Properties<T, Type>::staticMetaObject();
291 }
292
293 static Func attachedPropertiesFunc()
294 {
295 return Properties<T, Type>::attachedPropertiesFunc();
296 }
297 };
298
299 // Separately defined via QQmlTypeInfo
300 template<class T>
301 struct QmlAttached<T, QmlVoidT<decltype(T::qmlAttachedProperties)>, true>
302 {
303 using Type = typename std::remove_pointer<decltype(T::qmlAttachedProperties(nullptr))>::type;
304 using Func = QQmlAttachedPropertiesFunc<Type>;
305
306 static const QMetaObject *staticMetaObject() { return &Type::staticMetaObject; }
307 static Func attachedPropertiesFunc() { return T::qmlAttachedProperties; }
308 };
309
310 // This is necessary because both the type containing a default template parameter and the type
311 // instantiating the template need to have access to the default template parameter type. In
312 // this case that's T::QmlAttachedType. The QML_FOREIGN macro needs to befriend specific other
313 // types. Therefore we need some kind of "accessor". Because of compiler bugs in gcc and clang,
314 // we cannot befriend attachedPropertiesFunc() directly. Wrapping the actual access into another
315 // struct "fixes" that. For convenience we still want the free standing functions in addition.
316 template<class T>
317 struct QmlAttachedAccessor
318 {
319 static QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunc()
320 {
321 return QQmlAttachedPropertiesFunc<QObject>(QmlAttached<T>::attachedPropertiesFunc());
322 }
323
324 static const QMetaObject *staticMetaObject()
325 {
326 return QmlAttached<T>::staticMetaObject();
327 }
328 };
329
330 template<typename T>
331 inline QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunc()
332 {
333 return QmlAttachedAccessor<T>::attachedPropertiesFunc();
334 }
335
336 template<typename T>
337 inline const QMetaObject *attachedPropertiesMetaObject()
338 {
339 return QmlAttachedAccessor<T>::staticMetaObject();
340 }
341
342 enum AutoParentResult { Parented, IncompatibleObject, IncompatibleParent };
343 typedef AutoParentResult (*AutoParentFunction)(QObject *object, QObject *parent);
344
345 struct RegisterType {
346 int version;
347
348 int typeId;
349 int listId;
350 int objectSize;
351 void (*create)(void *);
352 QString noCreationReason;
353
354 const char *uri;
355 int versionMajor;
356 int versionMinor;
357 const char *elementName;
358 const QMetaObject *metaObject;
359
360 QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunction;
361 const QMetaObject *attachedPropertiesMetaObject;
362
363 int parserStatusCast;
364 int valueSourceCast;
365 int valueInterceptorCast;
366
367 QObject *(*extensionObjectCreate)(QObject *);
368 const QMetaObject *extensionMetaObject;
369
370 QQmlCustomParser *customParser;
371
372 int revision;
373 // If this is extended ensure "version" is bumped!!!
374 };
375
376 struct RegisterTypeAndRevisions {
377 int version;
378
379 int typeId;
380 int listId;
381 int objectSize;
382 void (*create)(void *);
383
384 const char *uri;
385 int versionMajor;
386
387 const QMetaObject *metaObject;
388 const QMetaObject *classInfoMetaObject;
389
390 QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunction;
391 const QMetaObject *attachedPropertiesMetaObject;
392
393 int parserStatusCast;
394 int valueSourceCast;
395 int valueInterceptorCast;
396
397 QObject *(*extensionObjectCreate)(QObject *);
398 const QMetaObject *extensionMetaObject;
399
400 QQmlCustomParser *(*customParserFactory)();
401 };
402
403 struct RegisterInterface {
404 int version;
405
406 int typeId;
407 int listId;
408
409 const char *iid;
410
411 const char *uri;
412 int versionMajor;
413 };
414
415 struct RegisterAutoParent {
416 int version;
417
418 AutoParentFunction function;
419 };
420
421 struct RegisterSingletonType {
422 int version;
423
424 const char *uri;
425 int versionMajor;
426 int versionMinor;
427 const char *typeName;
428
429 QJSValue (*scriptApi)(QQmlEngine *, QJSEngine *);
430 QObject *(*qobjectApi)(QQmlEngine *, QJSEngine *);
431 const QMetaObject *instanceMetaObject; // new in version 1
432 int typeId; // new in version 2
433 int revision; // new in version 2
434 std::function<QObject*(QQmlEngine *, QJSEngine *)> generalizedQobjectApi; // new in version 3
435 // If this is extended ensure "version" is bumped!!!
436 };
437
438 struct RegisterSingletonTypeAndRevisions {
439 int version;
440 const char *uri;
441 int versionMajor;
442
443 QJSValue (*scriptApi)(QQmlEngine *, QJSEngine *);
444 const QMetaObject *instanceMetaObject;
445 const QMetaObject *classInfoMetaObject;
446
447 int typeId;
448 std::function<QObject*(QQmlEngine *, QJSEngine *)> generalizedQobjectApi; // new in version 3
449 };
450
451 struct RegisterCompositeType {
452 QUrl url;
453 const char *uri;
454 int versionMajor;
455 int versionMinor;
456 const char *typeName;
457 };
458
459 struct RegisterCompositeSingletonType {
460 QUrl url;
461 const char *uri;
462 int versionMajor;
463 int versionMinor;
464 const char *typeName;
465 };
466
467 struct CachedQmlUnit {
468 const QV4::CompiledData::Unit *qmlData;
469 void *unused1;
470 void *unused2;
471 };
472
473 typedef const CachedQmlUnit *(*QmlUnitCacheLookupFunction)(const QUrl &url);
474 struct RegisterQmlUnitCacheHook {
475 int version;
476 QmlUnitCacheLookupFunction lookupCachedQmlUnit;
477 };
478
479 enum RegistrationType {
480 TypeRegistration = 0,
481 InterfaceRegistration = 1,
482 AutoParentRegistration = 2,
483 SingletonRegistration = 3,
484 CompositeRegistration = 4,
485 CompositeSingletonRegistration = 5,
486 QmlUnitCacheHookRegistration = 6,
487 TypeAndRevisionsRegistration = 7,
488 SingletonAndRevisionsRegistration = 8
489 };
490
491 int Q_QML_EXPORT qmlregister(RegistrationType, void *);
492 void Q_QML_EXPORT qmlunregister(RegistrationType, quintptr);
493 struct Q_QML_EXPORT RegisterSingletonFunctor
494 {
495 QObject *operator()(QQmlEngine *, QJSEngine *);
496
497 QPointer<QObject> m_object;
498 bool alreadyCalled = false;
499 };
500
501 static int indexOfOwnClassInfo(const QMetaObject *metaObject, const char *key)
502 {
503 if (!metaObject || !key)
504 return -1;
505
506 const int offset = metaObject->classInfoOffset();
507 for (int i = metaObject->classInfoCount() + offset - 1; i >= offset; --i)
508 if (qstrcmp(str1: key, str2: metaObject->classInfo(index: i).name()) == 0) {
509 return i;
510 }
511 return -1;
512 }
513
514 inline const char *classInfo(const QMetaObject *metaObject, const char *key)
515 {
516 return metaObject->classInfo(index: indexOfOwnClassInfo(metaObject, key)).value();
517 }
518
519 inline int intClassInfo(const QMetaObject *metaObject, const char *key, int defaultValue = 0)
520 {
521 const int index = indexOfOwnClassInfo(metaObject, key);
522 return (index == -1) ? defaultValue
523 : QByteArray(metaObject->classInfo(index).value()).toInt();
524 }
525
526 inline bool boolClassInfo(const QMetaObject *metaObject, const char *key,
527 bool defaultValue = false)
528 {
529 const int index = indexOfOwnClassInfo(metaObject, key);
530 return (index == -1) ? defaultValue
531 : (QByteArray(metaObject->classInfo(index).value()) == "true");
532 }
533
534 inline const char *classElementName(const QMetaObject *metaObject)
535 {
536 const char *elementName = classInfo(metaObject, key: "QML.Element");
537 if (qstrcmp(str1: elementName, str2: "auto") == 0)
538 return metaObject->className();
539 if (qstrcmp(str1: elementName, str2: "anonymous") == 0)
540 return nullptr;
541
542 if (!elementName || elementName[0] < 'A' || elementName[0] > 'Z') {
543 qWarning() << "Missing or unusable QML.Element class info \"" << elementName << "\""
544 << "for" << metaObject->className();
545 }
546
547 return elementName;
548 }
549
550 template<class T, class = QmlVoidT<>>
551 struct QmlExtended
552 {
553 using Type = void;
554 };
555
556 template<class T>
557 struct QmlExtended<T, QmlVoidT<typename T::QmlExtendedType>>
558 {
559 using Type = typename T::QmlExtendedType;
560 };
561
562 template<class T, class = QmlVoidT<>>
563 struct QmlResolved
564 {
565 using Type = T;
566 };
567
568 template<class T>
569 struct QmlResolved<T, QmlVoidT<typename T::QmlForeignType>>
570 {
571 using Type = typename T::QmlForeignType;
572 };
573
574 template<class T, class = QmlVoidT<>>
575 struct QmlSingleton
576 {
577 static constexpr bool Value = false;
578 };
579
580 template<class T>
581 struct QmlSingleton<T, QmlVoidT<typename T::QmlIsSingleton>>
582 {
583 static constexpr bool Value = bool(T::QmlIsSingleton::yes);
584 };
585
586 template<class T, class = QmlVoidT<>>
587 struct QmlInterface
588 {
589 static constexpr bool Value = false;
590 };
591
592 template<class T>
593 struct QmlInterface<T, QmlVoidT<typename T::QmlIsInterface>>
594 {
595 static constexpr bool Value = bool(T::QmlIsInterface::yes);
596 };
597
598 template<typename T>
599 void qmlRegisterSingletonAndRevisions(const char *uri, int versionMajor,
600 const QMetaObject *classInfoMetaObject)
601 {
602 QML_GETTYPENAMES
603
604 RegisterSingletonTypeAndRevisions api = {
605 0,
606
607 uri,
608 versionMajor,
609
610 nullptr,
611
612 &T::staticMetaObject,
613 classInfoMetaObject,
614
615 qRegisterNormalizedMetaType<T *>(pointerName.constData()),
616 Constructors<T>::createSingletonInstance
617 };
618
619 qmlregister(SingletonAndRevisionsRegistration, &api);
620 }
621
622 template<typename T, typename E>
623 void qmlRegisterTypeAndRevisions(const char *uri, int versionMajor,
624 const QMetaObject *classInfoMetaObject)
625 {
626 QML_GETTYPENAMES
627
628 RegisterTypeAndRevisions type = {
629 0,
630 qRegisterNormalizedMetaType<T *>(pointerName.constData()),
631 qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
632 int(sizeof(T)),
633 Constructors<T>::createInto,
634
635 uri,
636 versionMajor,
637
638 &T::staticMetaObject,
639 classInfoMetaObject,
640
641 attachedPropertiesFunc<T>(),
642 attachedPropertiesMetaObject<T>(),
643
644 StaticCastSelector<T, QQmlParserStatus>::cast(),
645 StaticCastSelector<T, QQmlPropertyValueSource>::cast(),
646 StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(),
647
648 ExtendedType<E>::createParent,
649 ExtendedType<E>::staticMetaObject,
650
651 &qmlCreateCustomParser<T>
652 };
653
654 qmlregister(TypeAndRevisionsRegistration, &type);
655 }
656
657 template<>
658 void Q_QML_EXPORT qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>(
659 const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject);
660
661} // namespace QQmlPrivate
662
663QT_END_NAMESPACE
664
665#endif // QQMLPRIVATE_H
666

source code of qtdeclarative/src/qml/qml/qqmlprivate.h