Performance improvements
[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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
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 <private/qv8_p.h>
61
62 #include <private/qdeclarativepropertycache_p.h>
63
64 #include "qv8contextwrapper_p.h"
65 #include "qv8qobjectwrapper_p.h"
66 #include "qv8stringwrapper_p.h"
67 #include "qv8typewrapper_p.h"
68 #include "qv8listwrapper_p.h"
69 #include "qv8variantwrapper_p.h"
70 #include "qv8valuetypewrapper_p.h"
71
72 QT_BEGIN_NAMESPACE
73
74
75 // Uncomment the following line to enable global handle debugging.  When enabled, all the persistent
76 // handles allocated using qPersistentNew() (or registered with qPersistentRegsiter()) and disposed
77 // with qPersistentDispose() are tracked.  If you try and do something illegal, like double disposing
78 // a handle, qFatal() is called.
79 // #define QML_GLOBAL_HANDLE_DEBUGGING
80
81 #define V8_RESOURCE_TYPE(resourcetype) \
82 public: \
83     enum { V8ResourceType = QV8ObjectResource:: resourcetype }; \
84     virtual QV8ObjectResource::ResourceType resourceType() const { return QV8ObjectResource:: resourcetype; } \
85 private: 
86
87 #define V8ENGINE() ((QV8Engine *)v8::External::Unwrap(args.Data()))
88 #define V8FUNCTION(function, engine) v8::FunctionTemplate::New(function, v8::External::Wrap((QV8Engine*)engine))->GetFunction()
89 #define V8THROW_ERROR(string) { \
90     v8::ThrowException(v8::Exception::Error(v8::String::New(string))); \
91     return v8::Handle<v8::Value>(); \
92 }
93 #define V8ENGINE_ACCESSOR() ((QV8Engine *)v8::External::Unwrap(info.Data()));
94 #define V8THROW_ERROR_SETTER(string) { \
95     v8::ThrowException(v8::Exception::Error(v8::String::New(string))); \
96     return; \
97 }
98
99 #define V8_DEFINE_EXTENSION(dataclass, datafunction) \
100     inline dataclass *datafunction(QV8Engine *engine) \
101     { \
102         static int extensionId = -1; \
103         if (extensionId == -1) { \
104             QV8Engine::registrationMutex()->lock(); \
105             if (extensionId == -1) \
106                 extensionId = QV8Engine::registerExtension(); \
107             QV8Engine::registrationMutex()->unlock(); \
108         } \
109         dataclass *rv = (dataclass *)engine->extensionData(extensionId); \
110         if (!rv) { \
111             rv = new dataclass(engine); \
112             engine->setExtensionData(extensionId, rv); \
113         } \
114         return rv; \
115     } \
116
117 class QV8Engine;
118 class QV8ObjectResource : public v8::Object::ExternalResource
119 {
120 public:
121     QV8ObjectResource(QV8Engine *engine) : engine(engine) { Q_ASSERT(engine); }
122     enum ResourceType { ContextType, QObjectType, TypeType, ListType, VariantType, 
123                         ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType,
124                         ListModelType, Context2DType };
125     virtual ResourceType resourceType() const = 0;
126
127     QV8Engine *engine;
128 };
129
130 template<class T>
131 inline T *v8_resource_cast(v8::Handle<v8::Object> object) {
132     QV8ObjectResource *resource = static_cast<QV8ObjectResource *>(object->GetExternalResource());
133     return (resource && (quint32)resource->resourceType() == (quint32)T::V8ResourceType)?static_cast<T *>(resource):0;
134 }
135
136 template<class T>
137 inline T *v8_resource_check(v8::Handle<v8::Object> object) {
138     T *resource = static_cast<T *>(object->GetExternalResource());
139     Q_ASSERT(resource && resource->resourceType() == (quint32)T::V8ResourceType);
140     return resource;
141 }
142
143 // Used to allow a QObject method take and return raw V8 handles without having to expose
144 // v8 in the public API.
145 // Use like this:
146 //     class MyClass : public QObject {
147 //         Q_OBJECT
148 //         ...
149 //         Q_INVOKABLE void myMethod(QDeclarativeV8Function*);
150 //     };
151 // The QDeclarativeV8Function - and consequently the arguments and return value - only remains 
152 // valid during the call.  If the return value isn't set within myMethod(), the will return
153 // undefined.
154 class QV8Engine;
155 class QDeclarativeV8Function
156 {
157 public:
158     int Length() const { return _ac; }
159     v8::Local<v8::Value> operator[](int idx) { return (*_a)->Get(idx); }
160     QDeclarativeContextData *context() { return _c; }
161     v8::Handle<v8::Object> qmlGlobal() { return *_g; }
162     void returnValue(v8::Handle<v8::Value> rv) { *_r = rv; }
163     QV8Engine *engine() const { return _e; }
164 private:
165     friend class QV8QObjectWrapper;
166     QDeclarativeV8Function();
167     QDeclarativeV8Function(const QDeclarativeV8Function &);
168     QDeclarativeV8Function &operator=(const QDeclarativeV8Function &);
169
170     QDeclarativeV8Function(int length, v8::Handle<v8::Object> &args, 
171                            v8::Handle<v8::Value> &rv, v8::Handle<v8::Object> &global,
172                            QDeclarativeContextData *c, QV8Engine *e)
173     : _ac(length), _a(&args), _r(&rv), _g(&global), _c(c), _e(e) {}
174
175     int _ac;
176     v8::Handle<v8::Object> *_a;
177     v8::Handle<v8::Value> *_r;
178     v8::Handle<v8::Object> *_g;
179     QDeclarativeContextData *_c;
180     QV8Engine *_e;
181 };
182
183 class QDeclarativeV8Handle
184 {
185 public:
186     QDeclarativeV8Handle() : d(0) {}
187     QDeclarativeV8Handle(const QDeclarativeV8Handle &other) : d(other.d) {}
188     QDeclarativeV8Handle &operator=(const QDeclarativeV8Handle &other) { d = other.d; return *this; }
189
190     static QDeclarativeV8Handle fromHandle(v8::Handle<v8::Value> h) {
191         return reinterpret_cast<QDeclarativeV8Handle &>(h);
192     }
193     v8::Handle<v8::Value> toHandle() const {
194         return reinterpret_cast<const v8::Handle<v8::Value> &>(*this);
195     }
196 private:
197     void *d;
198 };
199
200 class QObject;
201 class QDeclarativeEngine;
202 class QDeclarativeValueType;
203 class QNetworkAccessManager;
204 class QDeclarativeContextData;
205 class Q_AUTOTEST_EXPORT QV8Engine 
206 {
207 public:
208     QV8Engine();
209     ~QV8Engine();
210
211     struct Deletable {
212         ~Deletable() {}
213     };
214
215     void init(QDeclarativeEngine *);
216
217     QDeclarativeEngine *engine() { return m_engine; }
218     v8::Local<v8::Object> global() { return m_context->Global(); }
219     v8::Handle<v8::Context> context() { return m_context; }
220     QV8ContextWrapper *contextWrapper() { return &m_contextWrapper; }
221     QV8QObjectWrapper *qobjectWrapper() { return &m_qobjectWrapper; }
222     QV8TypeWrapper *typeWrapper() { return &m_typeWrapper; }
223     QV8ListWrapper *listWrapper() { return &m_listWrapper; }
224     QV8VariantWrapper *variantWrapper() { return &m_variantWrapper; }
225
226     void *xmlHttpRequestData() { return m_xmlHttpRequestData; }
227     void *sqlDatabaseData() { return m_sqlDatabaseData; }
228
229     Deletable *listModelData() { return m_listModelData; }
230     void setListModelData(Deletable *d) { if (m_listModelData) delete m_listModelData; m_listModelData = d; }
231
232     QDeclarativeContextData *callingContext();
233
234     v8::Local<v8::Array> getOwnPropertyNames(v8::Handle<v8::Object>);
235     void freezeObject(v8::Handle<v8::Value>);
236
237     inline QString toString(v8::Handle<v8::Value> string);
238     inline QString toString(v8::Handle<v8::String> string);
239     static QString toStringStatic(v8::Handle<v8::Value>);
240     static QString toStringStatic(v8::Handle<v8::String>);
241     static inline bool startsWithUpper(v8::Handle<v8::String>);
242
243     QVariant toVariant(v8::Handle<v8::Value>, int typeHint);
244     v8::Handle<v8::Value> fromVariant(const QVariant &);
245     inline bool isVariant(v8::Handle<v8::Value>);
246
247     // Compile \a source (from \a fileName at \a lineNumber) in QML mode
248     v8::Local<v8::Script> qmlModeCompile(const QString &source, 
249                                          const QString &fileName = QString(), 
250                                          int lineNumber = 1);
251
252     // Return the QML global "scope" object for the \a ctxt context and \a scope object.
253     inline v8::Local<v8::Object> qmlScope(QDeclarativeContextData *ctxt, QObject *scope);
254
255     // Return a JS wrapper for the given QObject \a object
256     inline v8::Handle<v8::Value> newQObject(QObject *object);
257     inline bool isQObject(v8::Handle<v8::Value>);
258     inline QObject *toQObject(v8::Handle<v8::Value>);
259
260     // Return a JS string for the given QString \a string
261     inline v8::Local<v8::String> toString(const QString &string);
262
263     // Create a new value type object
264     inline v8::Handle<v8::Value> newValueType(QObject *, int coreIndex, QDeclarativeValueType *);
265     inline v8::Handle<v8::Value> newValueType(const QVariant &, QDeclarativeValueType *);
266
267     // Create a new QVariant object.  This doesn't examine the type of the variant, but always returns
268     // a QVariant wrapper
269     inline v8::Handle<v8::Value> newQVariant(const QVariant &);
270
271     // Return the network access manager for this engine.  By default this returns the network
272     // access manager of the QDeclarativeEngine.  It is overridden in the case of a threaded v8
273     // instance (like in WorkerScript).
274     virtual QNetworkAccessManager *networkAccessManager();
275
276     // Return the list of illegal id names (the names of the properties on the global object)
277     const QSet<QString> &illegalNames() const;
278
279     static void gc();
280
281 #ifdef QML_GLOBAL_HANDLE_DEBUGGING
282     // Used for handle debugging
283     static void registerHandle(void *);
284     static void releaseHandle(void *);
285 #endif
286
287     static QMutex *registrationMutex();
288     static int registerExtension();
289
290     inline Deletable *extensionData(int) const;
291     void setExtensionData(int, Deletable *);
292
293 private:
294     QDeclarativeEngine *m_engine;
295     v8::Persistent<v8::Context> m_context;
296
297     QV8StringWrapper m_stringWrapper;
298     QV8ContextWrapper m_contextWrapper;
299     QV8QObjectWrapper m_qobjectWrapper;
300     QV8TypeWrapper m_typeWrapper;
301     QV8ListWrapper m_listWrapper;
302     QV8VariantWrapper m_variantWrapper;
303     QV8ValueTypeWrapper m_valueTypeWrapper;
304
305     v8::Persistent<v8::Function> m_getOwnPropertyNames;
306     v8::Persistent<v8::Function> m_freezeObject;
307
308     void *m_xmlHttpRequestData;
309     void *m_sqlDatabaseData;
310
311     QVector<Deletable *> m_extensionData;
312     Deletable *m_listModelData;
313
314     QSet<QString> m_illegalNames;
315
316     QVariant toBasicVariant(v8::Handle<v8::Value>);
317
318     void initializeGlobal(v8::Handle<v8::Object>);
319
320     static v8::Handle<v8::Value> gc(const v8::Arguments &args);
321     static v8::Handle<v8::Value> print(const v8::Arguments &args);
322     static v8::Handle<v8::Value> isQtObject(const v8::Arguments &args);
323     static v8::Handle<v8::Value> rgba(const v8::Arguments &args);
324     static v8::Handle<v8::Value> hsla(const v8::Arguments &args);
325     static v8::Handle<v8::Value> rect(const v8::Arguments &args);
326     static v8::Handle<v8::Value> point(const v8::Arguments &args);
327     static v8::Handle<v8::Value> size(const v8::Arguments &args);
328     static v8::Handle<v8::Value> vector3d(const v8::Arguments &args);
329     static v8::Handle<v8::Value> lighter(const v8::Arguments &args);
330     static v8::Handle<v8::Value> darker(const v8::Arguments &args);
331     static v8::Handle<v8::Value> tint(const v8::Arguments &args);
332     static v8::Handle<v8::Value> formatDate(const v8::Arguments &args);
333     static v8::Handle<v8::Value> formatTime(const v8::Arguments &args);
334     static v8::Handle<v8::Value> formatDateTime(const v8::Arguments &args);
335     static v8::Handle<v8::Value> openUrlExternally(const v8::Arguments &args);
336     static v8::Handle<v8::Value> fontFamilies(const v8::Arguments &args);
337     static v8::Handle<v8::Value> md5(const v8::Arguments &args);
338     static v8::Handle<v8::Value> btoa(const v8::Arguments &args);
339     static v8::Handle<v8::Value> atob(const v8::Arguments &args);
340     static v8::Handle<v8::Value> quit(const v8::Arguments &args);
341     static v8::Handle<v8::Value> resolvedUrl(const v8::Arguments &args);
342     static v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args);
343     static v8::Handle<v8::Value> createComponent(const v8::Arguments &args);
344
345     double qtDateTimeToJsDate(const QDateTime &dt);
346     QDateTime qtDateTimeFromJsDate(double jsDate);
347 };
348
349 // Allocate a new Persistent handle.  *ALL* persistent handles in QML must be allocated
350 // using this method.
351 template<class T>
352 v8::Persistent<T> qPersistentNew(v8::Handle<T> that)
353 {
354     v8::Persistent<T> rv = v8::Persistent<T>::New(that);
355 #ifdef QML_GLOBAL_HANDLE_DEBUGGING
356     QV8Engine::registerHandle(*rv);
357 #endif
358     return rv;
359 }
360
361 // Register a Persistent handle that was returned to you by V8 (such as by
362 // v8::Context::New). This allows us to do handle tracking on these handles too.
363 template<class T>
364 void qPersistentRegister(v8::Persistent<T> handle)
365 {
366 #ifdef QML_GLOBAL_HANDLE_DEBUGGING
367     QV8Engine::registerHandle(*handle);
368 #else
369     Q_UNUSED(handle);
370 #endif
371 }
372
373 // Dispose and clear a persistent handle.  *ALL* persistent handles in QML must be
374 // disposed using this method.
375 template<class T>
376 void qPersistentDispose(v8::Persistent<T> &that)
377 {
378 #ifdef QML_GLOBAL_HANDLE_DEBUGGING
379     QV8Engine::releaseHandle(*that);
380 #endif
381     that.Dispose();
382     that.Clear();
383 }
384
385 QString QV8Engine::toString(v8::Handle<v8::Value> string)
386 {
387     return m_stringWrapper.toString(string->ToString());
388 }
389
390 QString QV8Engine::toString(v8::Handle<v8::String> string)
391 {
392     return m_stringWrapper.toString(string);
393 }
394
395 bool QV8Engine::isVariant(v8::Handle<v8::Value> value)
396 {
397     return m_variantWrapper.isVariant(value);
398 }
399
400 v8::Local<v8::Object> QV8Engine::qmlScope(QDeclarativeContextData *ctxt, QObject *scope)
401 {
402     return m_contextWrapper.qmlScope(ctxt, scope);
403 }
404
405 bool QV8Engine::isQObject(v8::Handle<v8::Value> obj)
406 {
407     return obj->IsObject()?m_qobjectWrapper.isQObject(v8::Handle<v8::Object>::Cast(obj)):false;
408 }
409
410 QObject *QV8Engine::toQObject(v8::Handle<v8::Value> obj)
411 {
412     return obj->IsObject()?m_qobjectWrapper.toQObject(v8::Handle<v8::Object>::Cast(obj)):0;
413 }
414
415 v8::Handle<v8::Value> QV8Engine::newQObject(QObject *object)
416 {
417     return m_qobjectWrapper.newQObject(object);
418 }
419
420 v8::Local<v8::String> QV8Engine::toString(const QString &string)
421 {
422     return m_stringWrapper.toString(string);
423 }
424
425 v8::Handle<v8::Value> QV8Engine::newValueType(QObject *object, int property, QDeclarativeValueType *type)
426 {
427     return m_valueTypeWrapper.newValueType(object, property, type);
428 }
429
430 v8::Handle<v8::Value> QV8Engine::newValueType(const QVariant &value, QDeclarativeValueType *type)
431 {
432     return m_valueTypeWrapper.newValueType(value, type);
433 }
434
435 // XXX Can this be made more optimal?  It is called prior to resolving each and every 
436 // unqualified name in QV8ContextWrapper.
437 bool QV8Engine::startsWithUpper(v8::Handle<v8::String> string)
438 {
439     uint16_t c = string->GetCharacter(0);
440     return (c >= 'A' && c <= 'Z') || 
441            (c > 127 && QChar::category(c) == QChar::Letter_Uppercase);
442 }
443
444 QV8Engine::Deletable *QV8Engine::extensionData(int index) const
445 {
446     if (index < m_extensionData.count())
447         return m_extensionData[index];
448     else
449         return 0;
450 }
451
452 QT_END_NAMESPACE
453
454 #endif // QDECLARATIVEV8ENGINE_P_H