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 
65 QT_BEGIN_NAMESPACE
66 
67 class QObject;
68 class QQmlData;
69 class QQmlPropertyCache;
70 class QQmlPropertyData;
71 
72 namespace QV4 {
73 struct QObjectSlotDispatcher;
74 
75 namespace Heap {
76 
77 struct QQmlValueTypeWrapper;
78 
79 struct Q_QML_EXPORT QObjectWrapper : Object {
initQObjectWrapper80     void init(QObject *object)
81     {
82         Object::init();
83         qObj.init(object);
84     }
85 
destroyQObjectWrapper86     void destroy() {
87         qObj.destroy();
88         Object::destroy();
89     }
90 
objectQObjectWrapper91     QObject *object() const { return qObj.data(); }
92     static void markObjects(Heap::Base *that, MarkStack *markStack);
93 
94 private:
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 
DECLARE_HEAP_OBJECT(QObjectMethod,FunctionObject)104 DECLARE_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 
130 struct 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 
140 struct QmlSignalHandler : Object {
141     void init(QObject *object, int signalIndex);
destroyQmlSignalHandler142     void destroy() {
143         qObj.destroy();
144         Object::destroy();
145     }
146     int signalIndex;
147 
objectQmlSignalHandler148     QObject *object() const { return qObj.data(); }
setObjectQmlSignalHandler149     void setObject(QObject *o) { qObj = o; }
150 
151 private:
152     QQmlQPointer<QObject> qObj;
153 };
154 
155 }
156 
157 struct 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 
objectQObjectWrapper166     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 
190 protected:
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 
207 private:
208     Q_NEVER_INLINE static ReturnedValue wrap_slowPath(ExecutionEngine *engine, QObject *object);
209 };
210 
wrap(ExecutionEngine * engine,QObject * object)211 inline 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 
225 template <typename ReversalFunctor>
lookupGetterImpl(Lookup * lookup,ExecutionEngine * engine,const Value & object,bool useOriginalProperty,ReversalFunctor revertLookup)226 inline 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 
265 struct QQmlValueTypeWrapper;
266 
267 struct 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 
methodIndexQObjectMethod277     int methodIndex() const { return d()->index; }
objectQObjectMethod278     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 
291 struct 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);
metaObjectQMetaObjectWrapper297     const QMetaObject *metaObject() const { return d()->metaObject; }
298 
299 protected:
300     static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *);
301     static bool virtualIsEqualTo(Managed *a, Managed *b);
302 
303 private:
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 
311 struct Q_QML_EXPORT QmlSignalHandler : public QV4::Object
312 {
V4_OBJECT2QmlSignalHandler313     V4_OBJECT2(QmlSignalHandler, QV4::Object)
314     V4_PROTOTYPE(signalHandlerPrototype)
315     V4_NEEDS_DESTROY
316 
317     int signalIndex() const { return d()->signalIndex; }
objectQmlSignalHandler318     QObject *object() const { return d()->object(); }
319 
320     static void initProto(ExecutionEngine *v4);
321 };
322 
323 class MultiplyWrappedQObjectMap : public QObject,
324                                   private QHash<QObject*, QV4::WeakValue>
325 {
326     Q_OBJECT
327 public:
328     typedef QHash<QObject*, QV4::WeakValue>::ConstIterator ConstIterator;
329     typedef QHash<QObject*, QV4::WeakValue>::Iterator Iterator;
330 
begin()331     ConstIterator begin() const { return QHash<QObject*, QV4::WeakValue>::constBegin(); }
begin()332     Iterator begin() { return QHash<QObject*, QV4::WeakValue>::begin(); }
end()333     ConstIterator end() const { return QHash<QObject*, QV4::WeakValue>::constEnd(); }
end()334     Iterator end() { return QHash<QObject*, QV4::WeakValue>::end(); }
335 
336     void insert(QObject *key, Heap::Object *value);
value(QObject * key)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 
349 private Q_SLOTS:
350     void removeDestroyedObject(QObject*);
351 };
352 
353 }
354 
355 QT_END_NAMESPACE
356 
357 #endif // QV4QOBJECTWRAPPER_P_H
358 
359 
360