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 QV4QOBJECTWRAPPER_P_H
41#define QV4QOBJECTWRAPPER_P_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 <QtCore/qglobal.h>
55#include <QtCore/qmetatype.h>
56#include <QtCore/qpair.h>
57#include <QtCore/qhash.h>
58#include <private/qqmldata_p.h>
59#include <private/qintrusivelist_p.h>
60
61#include <private/qv4value_p.h>
62#include <private/qv4functionobject_p.h>
63#include <private/qv4lookup_p.h>
64
65QT_BEGIN_NAMESPACE
66
67class QObject;
68class QQmlData;
69class QQmlPropertyCache;
70class QQmlPropertyData;
71
72namespace QV4 {
73struct QObjectSlotDispatcher;
74
75namespace Heap {
76
77struct QQmlValueTypeWrapper;
78
79struct Q_QML_EXPORT QObjectWrapper : Object {
80 void init(QObject *object)
81 {
82 Object::init();
83 qObj.init(object);
84 }
85
86 void destroy() {
87 qObj.destroy();
88 Object::destroy();
89 }
90
91 QObject *object() const { return qObj.data(); }
92 static void markObjects(Heap::Base *that, MarkStack *markStack);
93
94private:
95 QQmlQPointer<QObject> qObj;
96};
97
98#define QObjectMethodMembers(class, Member) \
99 Member(class, Pointer, QQmlValueTypeWrapper *, valueTypeWrapper) \
100 Member(class, NoMark, QQmlQPointer<QObject>, qObj) \
101 Member(class, NoMark, QQmlPropertyCache *, _propertyCache) \
102 Member(class, NoMark, int, index)
103
104DECLARE_HEAP_OBJECT(QObjectMethod, FunctionObject) {
105 DECLARE_MARKOBJECTS(QObjectMethod);
106
107 void init(QV4::ExecutionContext *scope);
108 void destroy()
109 {
110 setPropertyCache(nullptr);
111 qObj.destroy();
112 FunctionObject::destroy();
113 }
114
115 QQmlPropertyCache *propertyCache() const { return _propertyCache; }
116 void setPropertyCache(QQmlPropertyCache *c) {
117 if (c)
118 c->addref();
119 if (_propertyCache)
120 _propertyCache->release();
121 _propertyCache = c;
122 }
123
124 const QMetaObject *metaObject();
125 QObject *object() const { return qObj.data(); }
126 void setObject(QObject *o) { qObj = o; }
127
128};
129
130struct QMetaObjectWrapper : FunctionObject {
131 const QMetaObject* metaObject;
132 QQmlPropertyData *constructors;
133 int constructorCount;
134
135 void init(const QMetaObject* metaObject);
136 void destroy();
137 void ensureConstructorsCache();
138};
139
140struct QmlSignalHandler : Object {
141 void init(QObject *object, int signalIndex);
142 void destroy() {
143 qObj.destroy();
144 Object::destroy();
145 }
146 int signalIndex;
147
148 QObject *object() const { return qObj.data(); }
149 void setObject(QObject *o) { qObj = o; }
150
151private:
152 QQmlQPointer<QObject> qObj;
153};
154
155}
156
157struct Q_QML_EXPORT QObjectWrapper : public Object
158{
159 V4_OBJECT2(QObjectWrapper, Object)
160 V4_NEEDS_DESTROY
161
162 enum RevisionMode { IgnoreRevision, CheckRevision };
163
164 static void initializeBindings(ExecutionEngine *engine);
165
166 QObject *object() const { return d()->object(); }
167
168 ReturnedValue getQmlProperty(QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = nullptr, bool includeImports = false) const;
169 static ReturnedValue getQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, bool *hasProperty = nullptr, QQmlPropertyData **property = nullptr);
170
171 static bool setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, const Value &value);
172
173 static ReturnedValue wrap(ExecutionEngine *engine, QObject *object);
174 static void markWrapper(QObject *object, MarkStack *markStack);
175
176 using Object::get;
177
178 static void setProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, const Value &value);
179 void setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value);
180
181 void destroyObject(bool lastCall);
182
183 static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property);
184
185 static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
186 static ReturnedValue lookupGetter(Lookup *l, ExecutionEngine *engine, const Value &object);
187 template <typename ReversalFunctor> static ReturnedValue lookupGetterImpl(Lookup *l, ExecutionEngine *engine, const Value &object, bool useOriginalProperty, ReversalFunctor revert);
188 static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
189
190protected:
191 static void setProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, const Value &value);
192
193 static bool virtualIsEqualTo(Managed *that, Managed *o);
194 static ReturnedValue create(ExecutionEngine *engine, QObject *object);
195
196 static QQmlPropertyData *findProperty(ExecutionEngine *engine, QObject *o, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local);
197 QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const;
198
199 static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
200 static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver);
201 static PropertyAttributes virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p);
202 static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
203
204 static ReturnedValue method_connect(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
205 static ReturnedValue method_disconnect(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
206
207private:
208 Q_NEVER_INLINE static ReturnedValue wrap_slowPath(ExecutionEngine *engine, QObject *object);
209};
210
211inline ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object)
212{
213 if (Q_UNLIKELY(QQmlData::wasDeleted(object)))
214 return QV4::Encode::null();
215
216 auto ddata = QQmlData::get(object);
217 if (Q_LIKELY(ddata && ddata->jsEngineId == engine->m_engineId && !ddata->jsWrapper.isUndefined())) {
218 // We own the JS object
219 return ddata->jsWrapper.value();
220 }
221
222 return wrap_slowPath(engine, object);
223}
224
225template <typename ReversalFunctor>
226inline ReturnedValue QObjectWrapper::lookupGetterImpl(Lookup *lookup, ExecutionEngine *engine, const Value &object, bool useOriginalProperty, ReversalFunctor revertLookup)
227{
228 // we can safely cast to a QV4::Object here. If object is something else,
229 // the internal class won't match
230 Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
231 if (!o || o->internalClass != lookup->qobjectLookup.ic)
232 return revertLookup();
233
234 const Heap::QObjectWrapper *This = static_cast<const Heap::QObjectWrapper *>(o);
235 QObject *qobj = This->object();
236 if (QQmlData::wasDeleted(qobj))
237 return QV4::Encode::undefined();
238
239 QQmlData *ddata = QQmlData::get(qobj, /*create*/false);
240 if (!ddata)
241 return revertLookup();
242
243 QQmlPropertyData *property = lookup->qobjectLookup.propertyData;
244 if (ddata->propertyCache != lookup->qobjectLookup.propertyCache) {
245 if (property->isOverridden() && (!useOriginalProperty || property->isFunction() || property->isSignalHandler()))
246 return revertLookup();
247
248 QQmlPropertyCache *fromMo = ddata->propertyCache;
249 QQmlPropertyCache *toMo = lookup->qobjectLookup.propertyCache;
250 bool canConvert = false;
251 while (fromMo) {
252 if (fromMo == toMo) {
253 canConvert = true;
254 break;
255 }
256 fromMo = fromMo->parent();
257 }
258 if (!canConvert)
259 return revertLookup();
260 }
261
262 return getProperty(engine, qobj, property);
263}
264
265struct QQmlValueTypeWrapper;
266
267struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
268{
269 V4_OBJECT2(QObjectMethod, QV4::FunctionObject)
270 V4_NEEDS_DESTROY
271
272 enum { DestroyMethod = -1, ToStringMethod = -2 };
273
274 static ReturnedValue create(QV4::ExecutionContext *scope, QObject *object, int index);
275 static ReturnedValue create(QV4::ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index);
276
277 int methodIndex() const { return d()->index; }
278 QObject *object() const { return d()->object(); }
279
280 QV4::ReturnedValue method_toString(QV4::ExecutionEngine *engine) const;
281 QV4::ReturnedValue method_destroy(QV4::ExecutionEngine *ctx, const Value *args, int argc) const;
282
283 static ReturnedValue virtualCall(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
284
285 ReturnedValue callInternal(const Value *thisObject, const Value *argv, int argc) const;
286
287 static QPair<QObject *, int> extractQtMethod(const QV4::FunctionObject *function);
288};
289
290
291struct Q_QML_EXPORT QMetaObjectWrapper : public QV4::FunctionObject
292{
293 V4_OBJECT2(QMetaObjectWrapper, QV4::FunctionObject)
294 V4_NEEDS_DESTROY
295
296 static ReturnedValue create(ExecutionEngine *engine, const QMetaObject* metaObject);
297 const QMetaObject *metaObject() const { return d()->metaObject; }
298
299protected:
300 static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *);
301 static bool virtualIsEqualTo(Managed *a, Managed *b);
302
303private:
304 void init(ExecutionEngine *engine);
305 ReturnedValue constructInternal(const Value *argv, int argc) const;
306 ReturnedValue callConstructor(const QQmlPropertyData &data, QV4::ExecutionEngine *engine, QV4::CallData *callArgs) const;
307 ReturnedValue callOverloadedConstructor(QV4::ExecutionEngine *engine, QV4::CallData *callArgs) const;
308
309};
310
311struct Q_QML_EXPORT QmlSignalHandler : public QV4::Object
312{
313 V4_OBJECT2(QmlSignalHandler, QV4::Object)
314 V4_PROTOTYPE(signalHandlerPrototype)
315 V4_NEEDS_DESTROY
316
317 int signalIndex() const { return d()->signalIndex; }
318 QObject *object() const { return d()->object(); }
319
320 static void initProto(ExecutionEngine *v4);
321};
322
323class MultiplyWrappedQObjectMap : public QObject,
324 private QHash<QObject*, QV4::WeakValue>
325{
326 Q_OBJECT
327public:
328 typedef QHash<QObject*, QV4::WeakValue>::ConstIterator ConstIterator;
329 typedef QHash<QObject*, QV4::WeakValue>::Iterator Iterator;
330
331 ConstIterator begin() const { return QHash<QObject*, QV4::WeakValue>::constBegin(); }
332 Iterator begin() { return QHash<QObject*, QV4::WeakValue>::begin(); }
333 ConstIterator end() const { return QHash<QObject*, QV4::WeakValue>::constEnd(); }
334 Iterator end() { return QHash<QObject*, QV4::WeakValue>::end(); }
335
336 void insert(QObject *key, Heap::Object *value);
337 ReturnedValue value(QObject *key) const
338 {
339 ConstIterator it = find(key);
340 return it == end()
341 ? QV4::WeakValue().value()
342 : it->value();
343 }
344
345 Iterator erase(Iterator it);
346 void remove(QObject *key);
347 void mark(QObject *key, MarkStack *markStack);
348
349private Q_SLOTS:
350 void removeDestroyedObject(QObject*);
351};
352
353}
354
355QT_END_NAMESPACE
356
357#endif // QV4QOBJECTWRAPPER_P_H
358
359
360