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
qqmlobjectcreator_p.h
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#ifndef QQMLOBJECTCREATOR_P_H
4#define QQMLOBJECTCREATOR_P_H
5
6//
7// W A R N I N G
8// -------------
9//
10// This file is not part of the Qt API. It exists purely as an
11// implementation detail. This header file may change from version to
12// version without notice, or even be removed.
13//
14// We mean it.
15//
16
17#include <private/qqmlimport_p.h>
18#include <private/qqmltypenamecache_p.h>
19#include <private/qv4compileddata_p.h>
20#include <private/qrecursionwatcher_p.h>
21#include <private/qqmlprofiler_p.h>
22#include <private/qv4qmlcontext_p.h>
23#include <private/qqmlguardedcontextdata_p.h>
24#include <private/qqmlfinalizer_p.h>
25#include <private/qqmlvmemetaobject_p.h>
26
27#include <qpointer.h>
28#include <deque>
29
30QT_BEGIN_NAMESPACE
31
32class QQmlAbstractBinding;
35
40
41/*!
42\internal
43This struct contains information solely used for displaying error messages
44\variable aliasesToRequired allows us to give the user a way to know which (aliasing) properties
45can be set to set the required property
46\sa QQmlComponentPrivate::unsetRequiredPropertyToQQmlError
47*/
55
57{
59 RequiredPropertyKey(const QObject *object, const QQmlPropertyData *data)
60 : object(object)
61 , data(data)
62 {}
63
64 const QObject *object = nullptr;
65 const QQmlPropertyData *data = nullptr;
66
67private:
68 friend size_t qHash(const RequiredPropertyKey &key, size_t seed = 0)
69 {
70 return qHashMulti(seed, key.object, key.data);
71 }
72
73 friend bool operator==(const RequiredPropertyKey &a, const RequiredPropertyKey &b)
74 {
75 return a.object == b.object && a.data == b.data;
76 }
77};
78
80
91
97
98class Q_AUTOTEST_EXPORT ObjectInCreationGCAnchorList {
99public:
100 // this is a non owning view, rule of zero applies
101 ObjectInCreationGCAnchorList() = default;
102 ObjectInCreationGCAnchorList(const QV4::Scope &scope)
103 {
104 allocationScope = &scope;
105 }
106 void trackObject(QV4::ExecutionEngine *engine, QObject *instance);
107 bool canTrack() const { return allocationScope; }
108private:
109 // pointer to scope to reference JS wrappers during creation phase.
110 const QV4::Scope *allocationScope = nullptr;
111};
112
117
134
135class Q_QML_EXPORT QQmlObjectCreator
136{
137 Q_DECLARE_TR_FUNCTIONS(QQmlObjectCreator)
138public:
139 enum class InitFlag: quint8
140 {
141 None = 0x0,
142 IsDocumentRoot = 0x1,
143 IsContextObject = 0x2,
144 };
146
147 QQmlObjectCreator(const QQmlRefPointer<QQmlContextData> &parentContext,
148 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
149 const QQmlRefPointer<QQmlContextData> &creationContext,
150 const QString &inlineComponentName,
151 QQmlIncubatorPrivate *incubator = nullptr);
152 ~QQmlObjectCreator();
153
155 QObject *create(int subComponentIndex = -1, QObject *parent = nullptr,
156 QQmlInstantiationInterrupt *interrupt = nullptr, int flags = NormalObject);
157
158 bool populateDeferredProperties(QObject *instance, const QQmlData::DeferredData *deferredData);
159
160 void beginPopulateDeferred(const QQmlRefPointer<QQmlContextData> &context);
161 void populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex,
162 const QV4::CompiledData::Binding *binding);
163 void populateDeferredInstance(QObject *outerObject, int deferredIndex,
164 int index, QObject *instance, QObject *bindingTarget,
165 const QQmlPropertyData *valueTypeProperty,
166 const QV4::CompiledData::Binding *binding = nullptr);
168
169 bool finalize(QQmlInstantiationInterrupt &interrupt);
170 void clear();
171
172 QQmlRefPointer<QQmlContextData> rootContext() const { return sharedState->rootContext; }
173 QQmlComponentAttached **componentAttachment() { return &sharedState->componentAttached; }
174
176
178 {
179 return parentContext.contextData();
180 }
181 std::vector<QQmlGuard<QObject> > &allCreatedObjects() { return sharedState->allCreatedObjects; }
182
183 RequiredProperties *requiredProperties() {return &sharedState->requiredProperties;}
184 bool componentHadTopLevelRequiredProperties() const {return sharedState->hadTopLevelRequiredProperties;}
185
186 static QQmlComponent *createComponent(
187 QQmlEngine *engine, QV4::ExecutableCompilationUnit *compilationUnit, int index,
188 QObject *parent, const QQmlRefPointer<QQmlContextData> &context);
189
190 void removePendingBinding(QObject *target, int propertyIndex) const
191 {
192 QList<DeferredQPropertyBinding> &pendingBindings = sharedState.data()->allQPropertyBindings;
193 pendingBindings.removeIf([&](const DeferredQPropertyBinding &deferred) {
194 return deferred.properyIndex == propertyIndex && deferred.target == target;
195 });
196 }
197
198private:
199 QQmlObjectCreator(
200 const QQmlRefPointer<QQmlContextData> &contextData,
201 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
202 const QString inlineComponentName,
203 QQmlObjectCreatorSharedState *inheritedSharedState, bool isContextObject);
204
205 void init(const QQmlRefPointer<QQmlContextData> &parentContext);
206
207 void initializeDData(
208 const QV4::CompiledData::Object *obj, QObject *instance, QQmlData *ddata,
209 InitFlags flags);
210 void initializePropertyCache(
211 int index, QQmlData *ddata, const QV4::ResolvedTypeReference *typeRef);
212 void initializeParent(QObject *instance, QObject *parent);
213 QObject *populateInstanceAndAliasBindings(int index, QObject *instance, InitFlags flags);
214
215 QObject *createInstance(int index, QObject *parent = nullptr, bool isContextObject = false);
216
217 QObject *initializeComponent(
218 const QV4::CompiledData::Object *obj, QObject *instance, InitFlags flags);
219 QObject *initializeComposite(
220 int index, const QV4::CompiledData::Object *obj,
221 const QV4::ResolvedTypeReference *typeRef, QObject *instance, QObject *parent,
222 InitFlags flags);
223 QObject *initializeNonComposite(
224 int index, const QV4::CompiledData::Object *obj,
225 const QV4::ResolvedTypeReference *typeRef, QObject *instance, QObject *parent,
226 InitFlags flags);
227
228 bool populateInstance(int index, QObject *instance, QObject *bindingTarget,
229 const QQmlPropertyData *valueTypeProperty,
230 const QV4::CompiledData::Binding *binding = nullptr);
231
232 // If qmlProperty and binding are null, populate all properties, otherwise only the given one.
233 void populateDeferred(QObject *instance, int deferredIndex);
234 void populateDeferred(QObject *instance, int deferredIndex,
235 const QQmlPropertyPrivate *qmlProperty,
236 const QV4::CompiledData::Binding *binding);
237
238 enum BindingMode {
239 ApplyNone = 0x0,
240 ApplyImmediate = 0x1,
241 ApplyDeferred = 0x2,
242 ApplyAll = ApplyImmediate | ApplyDeferred,
243 };
244 Q_DECLARE_FLAGS(BindingSetupFlags, BindingMode);
245
246 void setupBindings(BindingSetupFlags mode = BindingMode::ApplyImmediate);
247 bool setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
248 void setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
249 void setupFunctions();
250
251 QString stringAt(int idx) const { return compilationUnit->stringAt(idx); }
252 void recordError(const QV4::CompiledData::Location &location, const QString &description);
253
254 void registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const;
255
256 inline QV4::QmlContext *currentQmlContext();
257 QV4::ResolvedTypeReference *resolvedType(int id) const
258 {
259 return compilationUnit->resolvedType(id);
260 }
261
262 enum Phase {
263 Startup,
264 CreatingObjects,
265 CreatingObjectsPhase2,
266 ObjectsCreated,
267 Finalizing,
268 Done
269 } phase;
270
271 QQmlEngine *engine;
272 QV4::ExecutionEngine *v4;
273 QString m_inlineComponentName;
274 QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
275 const QV4::CompiledData::Unit *qmlUnit;
276 QQmlGuardedContextData parentContext;
277 QQmlRefPointer<QQmlContextData> context;
278 const QQmlPropertyCacheVector *propertyCaches;
279 QQmlRefPointer<QQmlObjectCreatorSharedState> sharedState;
280 bool topLevelCreator;
281 bool isContextObject;
282 QQmlIncubatorPrivate *incubator;
283
284 QObject *_qobject;
285 QObject *_scopeObject;
286 QObject *_bindingTarget;
287
288 const QQmlPropertyData *_valueTypeProperty; // belongs to _qobjectForBindings's property cache
289 int _compiledObjectIndex;
290 const QV4::CompiledData::Object *_compiledObject;
291 QQmlData *_ddata;
292 QQmlPropertyCache::ConstPtr _propertyCache;
293 QQmlVMEMetaObject *_vmeMetaObject;
294 QQmlListProperty<QObject> _currentList;
295 QV4::QmlContext *_qmlContext;
296
298
299 typedef std::function<bool(QQmlObjectCreatorSharedState *sharedState)> PendingAliasBinding;
300 std::vector<PendingAliasBinding> pendingAliasBindings;
301
302 template<typename Functor>
303 void doPopulateDeferred(QObject *instance, int deferredIndex, Functor f)
304 {
305 QQmlData *declarativeData = QQmlData::get(instance);
306
307 // We're in the process of creating the object. We sure hope it's still alive.
308 Q_ASSERT(declarativeData && declarativeData->propertyCache);
309
310 QObject *bindingTarget = instance;
311
312 QQmlPropertyCache::ConstPtr cache = declarativeData->propertyCache;
313 QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(instance);
314
315 QObject *scopeObject = instance;
316 qt_ptr_swap(_scopeObject, scopeObject);
317
318 QV4::Scope valueScope(v4);
319 QScopedValueRollback<ObjectInCreationGCAnchorList> jsObjectGuard(
320 sharedState->allJavaScriptObjects, ObjectInCreationGCAnchorList(valueScope));
321
322 Q_ASSERT(topLevelCreator);
323 QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.constructUndefined(1));
324
325 qt_ptr_swap(_qmlContext, qmlContext);
326
327 _propertyCache.swap(cache);
328 qt_ptr_swap(_qobject, instance);
329
330 int objectIndex = deferredIndex;
331 std::swap(_compiledObjectIndex, objectIndex);
332
333 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
334 qt_ptr_swap(_compiledObject, obj);
335 qt_ptr_swap(_ddata, declarativeData);
336 qt_ptr_swap(_bindingTarget, bindingTarget);
337 qt_ptr_swap(_vmeMetaObject, vmeMetaObject);
338
339 f();
340
341 qt_ptr_swap(_vmeMetaObject, vmeMetaObject);
342 qt_ptr_swap(_bindingTarget, bindingTarget);
343 qt_ptr_swap(_ddata, declarativeData);
344 qt_ptr_swap(_compiledObject, obj);
345 std::swap(_compiledObjectIndex, objectIndex);
346 qt_ptr_swap(_qobject, instance);
347 _propertyCache.swap(cache);
348
349 qt_ptr_swap(_qmlContext, qmlContext);
350 qt_ptr_swap(_scopeObject, scopeObject);
351 }
352 void registerPostHocRequiredProperties(const QV4::CompiledData::Binding *binding);
353};
354
356{
357 QQmlObjectCreatorRecursionWatcher(QQmlObjectCreator *creator);
358
359 bool hasRecursed() const { return watcher.hasRecursed(); }
360
361private:
362 QQmlRefPointer<QQmlObjectCreatorSharedState> sharedState;
363 QRecursionWatcher<QQmlObjectCreatorSharedState, &QQmlObjectCreatorSharedState::recursionNode> watcher;
364};
365
366QV4::QmlContext *QQmlObjectCreator::currentQmlContext()
367{
368 if (!_qmlContext->isManaged())
369 _qmlContext->setM(QV4::QmlContext::create(v4->rootContext(), context, _scopeObject));
370
371 return _qmlContext;
372}
373
374Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlObjectCreator::InitFlags);
375
376QT_END_NAMESPACE
377
378#endif // QQMLOBJECTCREATOR_P_H
friend class QQmlIncubatorPrivate
QQmlComponentAttached ** componentAttachment()
Q_DECLARE_FLAGS(InitFlags, InitFlag)
bool finalize(QQmlInstantiationInterrupt &interrupt)
bool componentHadTopLevelRequiredProperties() const
void beginPopulateDeferred(const QQmlRefPointer< QQmlContextData > &context)
QQmlRefPointer< QQmlContextData > parentContextData() const
static QQmlComponent * createComponent(QQmlEngine *engine, QV4::ExecutableCompilationUnit *compilationUnit, int index, QObject *parent, const QQmlRefPointer< QQmlContextData > &context)
QObject * create(int subComponentIndex=-1, QObject *parent=nullptr, QQmlInstantiationInterrupt *interrupt=nullptr, int flags=NormalObject)
void removePendingBinding(QObject *target, int propertyIndex) const
std::vector< QQmlGuard< QObject > > & allCreatedObjects()
void populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex, const QV4::CompiledData::Binding *binding)
RequiredProperties * requiredProperties()
QList< QQmlError > errors
void populateDeferredInstance(QObject *outerObject, int deferredIndex, int index, QObject *instance, QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty, const QV4::CompiledData::Binding *binding=nullptr)
bool populateDeferredProperties(QObject *instance, const QQmlData::DeferredData *deferredData)
QQmlObjectCreator(const QQmlRefPointer< QQmlContextData > &parentContext, const QQmlRefPointer< QV4::ExecutableCompilationUnit > &compilationUnit, const QQmlRefPointer< QQmlContextData > &creationContext, const QString &inlineComponentName, QQmlIncubatorPrivate *incubator=nullptr)
QQmlRefPointer< QQmlContextData > rootContext() const
void clear()
Clears the entire result set and releases any associated resources.
RequiredPropertiesAndTarget & operator=(RequiredPropertiesAndTarget &&)=default
RequiredPropertiesAndTarget(const RequiredPropertiesAndTarget &)=default
RequiredPropertiesAndTarget(QObject *target)
RequiredPropertiesAndTarget & operator=(const RequiredPropertiesAndTarget &)=default
RequiredPropertiesAndTarget(RequiredPropertiesAndTarget &&)=default
Definition qjsvalue.h:24
QJSEngine engine
[0]
QUntypedPropertyBinding binding
QQmlObjectCreatorRecursionWatcher(QQmlObjectCreator *creator)
QList< DeferredQPropertyBinding > allQPropertyBindings
std::vector< QQmlGuard< QObject > > allCreatedObjects
QQmlRefPointer< QQmlContextData > rootContext
std::vector< ParserStatus > allParserStatusCallbacks
QQmlRefPointer< QQmlContextData > creationContext
QQmlComponentAttached * componentAttached
std::vector< QQmlAbstractBinding::Ptr > allCreatedBindings
QList< QQmlFinalizerHook * > finalizeHooks
ObjectInCreationGCAnchorList allJavaScriptObjects
QString stringAt(int index) const
QV4::CompiledData::Location location
QList< AliasToRequiredInfo > aliasesToRequired
friend bool operator==(const RequiredPropertyKey &a, const RequiredPropertyKey &b)
friend size_t qHash(const RequiredPropertyKey &key, size_t seed=0)
RequiredPropertyKey()=default
const QQmlPropertyData * data
RequiredPropertyKey(const QObject *object, const QQmlPropertyData *data)