Fix QJSEngine::newQObject ownership behaviour
[profile/ivi/qtdeclarative.git] / src / declarative / qml / v8 / qv8engine_p.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #ifndef QDECLARATIVEV8ENGINE_P_H
43 #define QDECLARATIVEV8ENGINE_P_H
44
45 //
46 //  W A R N I N G
47 //  -------------
48 //
49 // This file is not part of the Qt API.  It exists purely as an
50 // implementation detail.  This header file may change from version to
51 // version without notice, or even be removed.
52 //
53 // We mean it.
54 //
55
56 #include <QtCore/qglobal.h>
57 #include <QtCore/qvariant.h>
58 #include <QtCore/qset.h>
59 #include <QtCore/qmutex.h>
60 #include <QtCore/qstack.h>
61 #include <QtCore/qstringlist.h>
62
63 #include <private/qv8_p.h>
64 #include <qjsengine.h>
65 #include <qjsvalue.h>
66 #include "qjsvalue_p.h"
67 #include "qjsvalueiterator_p.h"
68 #include "qscriptoriginalglobalobject_p.h"
69 #include "qscripttools_p.h"
70
71 #include <private/qdeclarativepropertycache_p.h>
72
73 #include "qv8contextwrapper_p.h"
74 #include "qv8qobjectwrapper_p.h"
75 #include "qv8stringwrapper_p.h"
76 #include "qv8typewrapper_p.h"
77 #include "qv8listwrapper_p.h"
78 #include "qv8variantwrapper_p.h"
79 #include "qv8valuetypewrapper_p.h"
80
81 QT_BEGIN_NAMESPACE
82
83
84 // Uncomment the following line to enable global handle debugging.  When enabled, all the persistent
85 // handles allocated using qPersistentNew() (or registered with qPersistentRegsiter()) and disposed
86 // with qPersistentDispose() are tracked.  If you try and do something illegal, like double disposing
87 // a handle, qFatal() is called.
88 // #define QML_GLOBAL_HANDLE_DEBUGGING
89
90 #define V8_RESOURCE_TYPE(resourcetype) \
91 public: \
92     enum { V8ResourceType = QV8ObjectResource:: resourcetype }; \
93     virtual QV8ObjectResource::ResourceType resourceType() const { return QV8ObjectResource:: resourcetype; } \
94 private: 
95
96 #define V8ENGINE() ((QV8Engine *)v8::External::Unwrap(args.Data()))
97 #define V8FUNCTION(function, engine) v8::FunctionTemplate::New(function, v8::External::Wrap((QV8Engine*)engine))->GetFunction()
98 #define V8THROW_ERROR(string) { \
99     v8::ThrowException(v8::Exception::Error(v8::String::New(string))); \
100     return v8::Handle<v8::Value>(); \
101 }
102 #define V8THROW_TYPE(string) { \
103     v8::ThrowException(v8::Exception::TypeError(v8::String::New(string))); \
104     return v8::Handle<v8::Value>(); \
105 }
106 #define V8ENGINE_ACCESSOR() ((QV8Engine *)v8::External::Unwrap(info.Data()));
107 #define V8THROW_ERROR_SETTER(string) { \
108     v8::ThrowException(v8::Exception::Error(v8::String::New(string))); \
109     return; \
110 }
111
112 #define V8_DEFINE_EXTENSION(dataclass, datafunction) \
113     inline dataclass *datafunction(QV8Engine *engine) \
114     { \
115         static int extensionId = -1; \
116         if (extensionId == -1) { \
117             QV8Engine::registrationMutex()->lock(); \
118             if (extensionId == -1) \
119                 extensionId = QV8Engine::registerExtension(); \
120             QV8Engine::registrationMutex()->unlock(); \
121         } \
122         dataclass *rv = (dataclass *)engine->extensionData(extensionId); \
123         if (!rv) { \
124             rv = new dataclass(engine); \
125             engine->setExtensionData(extensionId, rv); \
126         } \
127         return rv; \
128     } \
129
130
131 class QV8Engine;
132 class QV8ObjectResource : public v8::Object::ExternalResource
133 {
134 public:
135     QV8ObjectResource(QV8Engine *engine) : engine(engine) { Q_ASSERT(engine); }
136     enum ResourceType { ContextType, QObjectType, TypeType, ListType, VariantType, 
137                         ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType,
138                         ListModelType, Context2DType, Context2DStyleType, Context2DPixelArrayType, 
139                         ParticleDataType, SignalHandlerType, IncubatorType, VisualDataItemType };
140     virtual ResourceType resourceType() const = 0;
141
142     QV8Engine *engine;
143 };
144
145 template<class T>
146 inline T *v8_resource_cast(v8::Handle<v8::Object> object) {
147     QV8ObjectResource *resource = static_cast<QV8ObjectResource *>(object->GetExternalResource());
148     return (resource && (quint32)resource->resourceType() == (quint32)T::V8ResourceType)?static_cast<T *>(resource):0;
149 }
150
151 template<class T>
152 inline T *v8_resource_check(v8::Handle<v8::Object> object) {
153     T *resource = static_cast<T *>(object->GetExternalResource());
154     Q_ASSERT(resource && resource->resourceType() == (quint32)T::V8ResourceType);
155     return resource;
156 }
157
158 // Used to allow a QObject method take and return raw V8 handles without having to expose
159 // v8 in the public API.
160 // Use like this:
161 //     class MyClass : public QObject {
162 //         Q_OBJECT
163 //         ...
164 //         Q_INVOKABLE void myMethod(QDeclarativeV8Function*);
165 //     };
166 // The QDeclarativeV8Function - and consequently the arguments and return value - only remains 
167 // valid during the call.  If the return value isn't set within myMethod(), the will return
168 // undefined.
169 class QV8Engine;
170 class QDeclarativeV8Function
171 {
172 public:
173     int Length() const { return _ac; }
174     v8::Local<v8::Value> operator[](int idx) { return (*_a)->Get(idx); }
175     QDeclarativeContextData *context() { return _c; }
176     v8::Handle<v8::Object> qmlGlobal() { return *_g; }
177     void returnValue(v8::Handle<v8::Value> rv) { *_r = rv; }
178     QV8Engine *engine() const { return _e; }
179 private:
180     friend class QV8QObjectWrapper;
181     QDeclarativeV8Function();
182     QDeclarativeV8Function(const QDeclarativeV8Function &);
183     QDeclarativeV8Function &operator=(const QDeclarativeV8Function &);
184
185     QDeclarativeV8Function(int length, v8::Handle<v8::Object> &args, 
186                            v8::Handle<v8::Value> &rv, v8::Handle<v8::Object> &global,
187                            QDeclarativeContextData *c, QV8Engine *e)
188     : _ac(length), _a(&args), _r(&rv), _g(&global), _c(c), _e(e) {}
189
190     int _ac;
191     v8::Handle<v8::Object> *_a;
192     v8::Handle<v8::Value> *_r;
193     v8::Handle<v8::Object> *_g;
194     QDeclarativeContextData *_c;
195     QV8Engine *_e;
196 };
197
198 class QDeclarativeV8Handle
199 {
200 public:
201     QDeclarativeV8Handle() : d(0) {}
202     QDeclarativeV8Handle(const QDeclarativeV8Handle &other) : d(other.d) {}
203     QDeclarativeV8Handle &operator=(const QDeclarativeV8Handle &other) { d = other.d; return *this; }
204
205     static QDeclarativeV8Handle fromHandle(v8::Handle<v8::Value> h) {
206         return QDeclarativeV8Handle(*h);
207     }
208     v8::Handle<v8::Value> toHandle() const {
209         return v8::Handle<v8::Value>((v8::Value *)d);
210     }
211 private:
212     QDeclarativeV8Handle(void *d) : d(d) {}
213     void *d;
214 };
215
216 class QObject;
217 class QDeclarativeEngine;
218 class QDeclarativeValueType;
219 class QNetworkAccessManager;
220 class QDeclarativeContextData;
221
222 class Q_DECLARATIVE_EXPORT QV8Engine
223 {
224 public:
225     static QV8Engine* get(QJSEngine* q) { Q_ASSERT(q); return q->handle(); }
226     static QJSEngine* get(QV8Engine* d) { Q_ASSERT(d); return d->q; }
227
228     QV8Engine(QJSEngine* qq,QJSEngine::ContextOwnership ownership = QJSEngine::CreateNewContext);
229     ~QV8Engine();
230
231     // ### TODO get rid of it, do we really need CppOwnership?
232     // This enum should be in sync with QDeclarativeEngine::ObjectOwnership
233     enum ObjectOwnership { CppOwnership, JavaScriptOwnership };
234
235     struct Deletable {
236         virtual ~Deletable() {}
237     };
238
239     class Exception
240     {
241         typedef QPair<v8::Persistent<v8::Value>, v8::Persistent<v8::Message> > ValueMessagePair;
242
243         v8::Persistent<v8::Value> m_value;
244         v8::Persistent<v8::Message> m_message;
245         QStack<ValueMessagePair> m_stack;
246
247         Q_DISABLE_COPY(Exception)
248     public:
249         inline Exception();
250         inline ~Exception();
251         inline void set(v8::Handle<v8::Value> value, v8::Handle<v8::Message> message);
252         inline void clear();
253         inline operator bool() const;
254         inline operator v8::Handle<v8::Value>() const;
255         inline int lineNumber() const;
256         inline QStringList backtrace() const;
257
258         inline void push();
259         inline void pop();
260     };
261
262     void initDeclarativeGlobalObject();
263     void setEngine(QDeclarativeEngine *engine);
264     QDeclarativeEngine *engine() { return m_engine; }
265     v8::Local<v8::Object> global() { return m_context->Global(); }
266     v8::Handle<v8::Context> context() const { return m_context; }
267
268     inline void registerValue(QJSValuePrivate *data);
269     inline void unregisterValue(QJSValuePrivate *data);
270     inline void invalidateAllValues();
271
272     inline void registerValueIterator(QJSValueIteratorPrivate *data);
273     inline void unregisterValueIterator(QJSValueIteratorPrivate *data);
274     inline void invalidateAllIterators();
275
276     QV8ContextWrapper *contextWrapper() { return &m_contextWrapper; }
277     QV8QObjectWrapper *qobjectWrapper() { return &m_qobjectWrapper; }
278     QV8TypeWrapper *typeWrapper() { return &m_typeWrapper; }
279     QV8ListWrapper *listWrapper() { return &m_listWrapper; }
280     QV8VariantWrapper *variantWrapper() { return &m_variantWrapper; }
281     QV8ValueTypeWrapper *valueTypeWrapper() { return &m_valueTypeWrapper; }
282
283     void *xmlHttpRequestData() { return m_xmlHttpRequestData; }
284     void *sqlDatabaseData() { return m_sqlDatabaseData; }
285
286     Deletable *listModelData() { return m_listModelData; }
287     void setListModelData(Deletable *d) { if (m_listModelData) delete m_listModelData; m_listModelData = d; }
288
289     QDeclarativeContextData *callingContext();
290
291     v8::Local<v8::Array> getOwnPropertyNames(v8::Handle<v8::Object>);
292     inline QJSValue::PropertyFlags getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property);
293     void freezeObject(v8::Handle<v8::Value>);
294
295     inline QString toString(v8::Handle<v8::Value> string);
296     inline QString toString(v8::Handle<v8::String> string);
297     static QString toStringStatic(v8::Handle<v8::Value>);
298     static QString toStringStatic(v8::Handle<v8::String>);
299     static inline bool startsWithUpper(v8::Handle<v8::String>);
300
301     QVariant toVariant(v8::Handle<v8::Value>, int typeHint);
302     v8::Handle<v8::Value> fromVariant(const QVariant &);
303     inline bool isVariant(v8::Handle<v8::Value>);
304
305     // Compile \a source (from \a fileName at \a lineNumber) in QML mode
306     v8::Local<v8::Script> qmlModeCompile(const QString &source, 
307                                          const QString &fileName = QString(), 
308                                          int lineNumber = 1);
309
310     // Return the QML global "scope" object for the \a ctxt context and \a scope object.
311     inline v8::Local<v8::Object> qmlScope(QDeclarativeContextData *ctxt, QObject *scope);
312
313     QScriptPassPointer<QJSValuePrivate> newRegExp(const QRegExp &regexp);
314     QScriptPassPointer<QJSValuePrivate> newRegExp(const QString &pattern, const QString &flags);
315
316     // Return a JS wrapper for the given QObject \a object
317     inline v8::Handle<v8::Value> newQObject(QObject *object);
318     inline v8::Handle<v8::Value> newQObject(QObject *object, const ObjectOwnership ownership);
319     inline bool isQObject(v8::Handle<v8::Value>);
320     inline QObject *toQObject(v8::Handle<v8::Value>);
321
322     // Return a JS string for the given QString \a string
323     inline v8::Local<v8::String> toString(const QString &string);
324
325     // Create a new value type object
326     inline v8::Handle<v8::Value> newValueType(QObject *, int coreIndex, QDeclarativeValueType *);
327     inline v8::Handle<v8::Value> newValueType(const QVariant &, QDeclarativeValueType *);
328
329     // Create a new QVariant object.  This doesn't examine the type of the variant, but always returns
330     // a QVariant wrapper
331     inline v8::Handle<v8::Value> newQVariant(const QVariant &);
332
333     // Return the network access manager for this engine.  By default this returns the network
334     // access manager of the QDeclarativeEngine.  It is overridden in the case of a threaded v8
335     // instance (like in WorkerScript).
336     virtual QNetworkAccessManager *networkAccessManager();
337
338     // Return the list of illegal id names (the names of the properties on the global object)
339     const QStringHash<bool> &illegalNames() const;
340
341     inline void collectGarbage() { gc(); }
342     static void gc();
343
344     void clearExceptions();
345     void setException(v8::Handle<v8::Value> value, v8::Handle<v8::Message> message = v8::Handle<v8::Message>());
346     v8::Handle<v8::Value> throwException(v8::Handle<v8::Value> value);
347     bool hasUncaughtException() const;
348     int uncaughtExceptionLineNumber() const;
349     QStringList uncaughtExceptionBacktrace() const;
350     v8::Handle<v8::Value> uncaughtException() const;
351     void saveException();
352     void restoreException();
353
354 #ifdef QML_GLOBAL_HANDLE_DEBUGGING
355     // Used for handle debugging
356     static void registerHandle(void *);
357     static void releaseHandle(void *);
358 #endif
359
360     static QMutex *registrationMutex();
361     static int registerExtension();
362
363     inline Deletable *extensionData(int) const;
364     void setExtensionData(int, Deletable *);
365
366     inline v8::Handle<v8::Value> makeJSValue(bool value);
367     inline v8::Handle<v8::Value> makeJSValue(int value);
368     inline v8::Handle<v8::Value> makeJSValue(uint value);
369     inline v8::Handle<v8::Value> makeJSValue(double value);
370     inline v8::Handle<v8::Value> makeJSValue(QJSValue::SpecialValue value);
371     inline v8::Handle<v8::Value> makeJSValue(const QString& value);
372
373     inline QScriptPassPointer<QJSValuePrivate> evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1);
374     QScriptPassPointer<QJSValuePrivate> evaluate(v8::Handle<v8::Script> script, v8::TryCatch& tryCatch);
375
376     QScriptPassPointer<QJSValuePrivate> newArray(uint length);
377     v8::Handle<v8::Object> newVariant(const QVariant &variant);
378     QScriptPassPointer<QJSValuePrivate> newVariant(QJSValuePrivate* value, const QVariant &variant);
379
380     v8::Handle<v8::Array> variantListToJS(const QVariantList &lst);
381     QVariantList variantListFromJS(v8::Handle<v8::Array> jsArray);
382
383     v8::Handle<v8::Object> variantMapToJS(const QVariantMap &vmap);
384     QVariantMap variantMapFromJS(v8::Handle<v8::Object> jsObject);
385
386     v8::Handle<v8::Value> variantToJS(const QVariant &value);
387     QVariant variantFromJS(v8::Handle<v8::Value> value);
388
389     v8::Handle<v8::Value> metaTypeToJS(int type, const void *data);
390     bool metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data);
391
392     bool convertToNativeQObject(v8::Handle<v8::Value> value,
393                                 const QByteArray &targetType,
394                                 void **result);
395
396     QVariant &variantValue(v8::Handle<v8::Value> value);
397
398     QJSValue scriptValueFromInternal(v8::Handle<v8::Value>) const;
399
400     void emitSignalHandlerException();
401
402     QObject *qtObjectFromJS(v8::Handle<v8::Value> value);
403     QSet<int> visitedConversionObjects;
404 protected:
405     QJSEngine* q;
406     QDeclarativeEngine *m_engine;
407     bool m_ownsV8Context;
408     v8::Persistent<v8::Context> m_context;
409     QScriptOriginalGlobalObject m_originalGlobalObject;
410
411     QV8StringWrapper m_stringWrapper;
412     QV8ContextWrapper m_contextWrapper;
413     QV8QObjectWrapper m_qobjectWrapper;
414     QV8TypeWrapper m_typeWrapper;
415     QV8ListWrapper m_listWrapper;
416     QV8VariantWrapper m_variantWrapper;
417     QV8ValueTypeWrapper m_valueTypeWrapper;
418
419     v8::Persistent<v8::Function> m_getOwnPropertyNames;
420     v8::Persistent<v8::Function> m_freezeObject;
421
422     void *m_xmlHttpRequestData;
423     void *m_sqlDatabaseData;
424
425     QVector<Deletable *> m_extensionData;
426     Deletable *m_listModelData;
427
428     QStringHash<bool> m_illegalNames;
429
430     Exception m_exception;
431
432     QVariant toBasicVariant(v8::Handle<v8::Value>);
433
434     void initializeGlobal(v8::Handle<v8::Object>);
435
436     double qtDateTimeToJsDate(const QDateTime &dt);
437     QDateTime qtDateTimeFromJsDate(double jsDate);
438
439 private:
440     typedef QScriptIntrusiveList<QJSValuePrivate, &QJSValuePrivate::m_node> ValueList;
441     ValueList m_values;
442     typedef QScriptIntrusiveList<QJSValueIteratorPrivate, &QJSValueIteratorPrivate::m_node> ValueIteratorList;
443     ValueIteratorList m_valueIterators;
444
445     Q_DISABLE_COPY(QV8Engine)
446 };
447
448 // Allocate a new Persistent handle.  *ALL* persistent handles in QML must be allocated
449 // using this method.
450 template<class T>
451 v8::Persistent<T> qPersistentNew(v8::Handle<T> that)
452 {
453     v8::Persistent<T> rv = v8::Persistent<T>::New(that);
454 #ifdef QML_GLOBAL_HANDLE_DEBUGGING
455     QV8Engine::registerHandle(*rv);
456 #endif
457     return rv;
458 }
459
460 // Register a Persistent handle that was returned to you by V8 (such as by
461 // v8::Context::New). This allows us to do handle tracking on these handles too.
462 template<class T>
463 void qPersistentRegister(v8::Persistent<T> handle)
464 {
465 #ifdef QML_GLOBAL_HANDLE_DEBUGGING
466     QV8Engine::registerHandle(*handle);
467 #else
468     Q_UNUSED(handle);
469 #endif
470 }
471
472 // Dispose and clear a persistent handle.  *ALL* persistent handles in QML must be
473 // disposed using this method.
474 template<class T>
475 void qPersistentDispose(v8::Persistent<T> &that)
476 {
477 #ifdef QML_GLOBAL_HANDLE_DEBUGGING
478     QV8Engine::releaseHandle(*that);
479 #endif
480     that.Dispose();
481     that.Clear();
482 }
483
484 QString QV8Engine::toString(v8::Handle<v8::Value> string)
485 {
486     return m_stringWrapper.toString(string->ToString());
487 }
488
489 QString QV8Engine::toString(v8::Handle<v8::String> string)
490 {
491     return m_stringWrapper.toString(string);
492 }
493
494 bool QV8Engine::isVariant(v8::Handle<v8::Value> value)
495 {
496     return m_variantWrapper.isVariant(value);
497 }
498
499 v8::Local<v8::Object> QV8Engine::qmlScope(QDeclarativeContextData *ctxt, QObject *scope)
500 {
501     return m_contextWrapper.qmlScope(ctxt, scope);
502 }
503
504 bool QV8Engine::isQObject(v8::Handle<v8::Value> obj)
505 {
506     return obj->IsObject()?m_qobjectWrapper.isQObject(v8::Handle<v8::Object>::Cast(obj)):false;
507 }
508
509 QObject *QV8Engine::toQObject(v8::Handle<v8::Value> obj)
510 {
511     return obj->IsObject()?m_qobjectWrapper.toQObject(v8::Handle<v8::Object>::Cast(obj)):0;
512 }
513
514 v8::Handle<v8::Value> QV8Engine::newQObject(QObject *object)
515 {
516     return m_qobjectWrapper.newQObject(object);
517 }
518
519 v8::Handle<v8::Value> QV8Engine::newQObject(QObject *object, const ObjectOwnership ownership)
520 {
521     if (!object)
522         return v8::Null();
523
524     v8::Handle<v8::Value> result = newQObject(object);
525     QDeclarativeData *ddata = QDeclarativeData::get(object, true);
526     if (ownership == JavaScriptOwnership && ddata) {
527         ddata->indestructible = false;
528         ddata->explicitIndestructibleSet = true;
529     }
530     return result;
531 }
532
533 v8::Local<v8::String> QV8Engine::toString(const QString &string)
534 {
535     return m_stringWrapper.toString(string);
536 }
537
538 v8::Handle<v8::Value> QV8Engine::newValueType(QObject *object, int property, QDeclarativeValueType *type)
539 {
540     return m_valueTypeWrapper.newValueType(object, property, type);
541 }
542
543 v8::Handle<v8::Value> QV8Engine::newValueType(const QVariant &value, QDeclarativeValueType *type)
544 {
545     return m_valueTypeWrapper.newValueType(value, type);
546 }
547
548 // XXX Can this be made more optimal?  It is called prior to resolving each and every 
549 // unqualified name in QV8ContextWrapper.
550 bool QV8Engine::startsWithUpper(v8::Handle<v8::String> string)
551 {
552     uint16_t c = string->GetCharacter(0);
553     return (c >= 'A' && c <= 'Z') || 
554            (c > 127 && QChar::category(c) == QChar::Letter_Uppercase);
555 }
556
557 QV8Engine::Deletable *QV8Engine::extensionData(int index) const
558 {
559     if (index < m_extensionData.count())
560         return m_extensionData[index];
561     else
562         return 0;
563 }
564
565 QT_END_NAMESPACE
566
567 #endif // QDECLARATIVEV8ENGINE_P_H