1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #ifndef QDECLARATIVEV8ENGINE_P_H
43 #define QDECLARATIVEV8ENGINE_P_H
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.
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>
63 #include <private/qv8_p.h>
64 #include <qjsengine.h>
66 #include "qjsvalue_p.h"
67 #include "qjsvalueiterator_p.h"
68 #include "qscriptoriginalglobalobject_p.h"
69 #include "qscripttools_p.h"
71 #include <private/qdeclarativepropertycache_p.h>
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"
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
90 #define V8_RESOURCE_TYPE(resourcetype) \
92 enum { V8ResourceType = QV8ObjectResource:: resourcetype }; \
93 virtual QV8ObjectResource::ResourceType resourceType() const { return QV8ObjectResource:: resourcetype; } \
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>(); \
102 #define V8THROW_TYPE(string) { \
103 v8::ThrowException(v8::Exception::TypeError(v8::String::New(string))); \
104 return v8::Handle<v8::Value>(); \
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))); \
112 #define V8_DEFINE_EXTENSION(dataclass, datafunction) \
113 inline dataclass *datafunction(QV8Engine *engine) \
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(); \
122 dataclass *rv = (dataclass *)engine->extensionData(extensionId); \
124 rv = new dataclass(engine); \
125 engine->setExtensionData(extensionId, rv); \
132 class QV8ObjectResource : public v8::Object::ExternalResource
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, ParticleDataType };
139 virtual ResourceType resourceType() const = 0;
145 inline T *v8_resource_cast(v8::Handle<v8::Object> object) {
146 QV8ObjectResource *resource = static_cast<QV8ObjectResource *>(object->GetExternalResource());
147 return (resource && (quint32)resource->resourceType() == (quint32)T::V8ResourceType)?static_cast<T *>(resource):0;
151 inline T *v8_resource_check(v8::Handle<v8::Object> object) {
152 T *resource = static_cast<T *>(object->GetExternalResource());
153 Q_ASSERT(resource && resource->resourceType() == (quint32)T::V8ResourceType);
157 // Used to allow a QObject method take and return raw V8 handles without having to expose
158 // v8 in the public API.
160 // class MyClass : public QObject {
163 // Q_INVOKABLE void myMethod(QDeclarativeV8Function*);
165 // The QDeclarativeV8Function - and consequently the arguments and return value - only remains
166 // valid during the call. If the return value isn't set within myMethod(), the will return
169 class QDeclarativeV8Function
172 int Length() const { return _ac; }
173 v8::Local<v8::Value> operator[](int idx) { return (*_a)->Get(idx); }
174 QDeclarativeContextData *context() { return _c; }
175 v8::Handle<v8::Object> qmlGlobal() { return *_g; }
176 void returnValue(v8::Handle<v8::Value> rv) { *_r = rv; }
177 QV8Engine *engine() const { return _e; }
179 friend class QV8QObjectWrapper;
180 QDeclarativeV8Function();
181 QDeclarativeV8Function(const QDeclarativeV8Function &);
182 QDeclarativeV8Function &operator=(const QDeclarativeV8Function &);
184 QDeclarativeV8Function(int length, v8::Handle<v8::Object> &args,
185 v8::Handle<v8::Value> &rv, v8::Handle<v8::Object> &global,
186 QDeclarativeContextData *c, QV8Engine *e)
187 : _ac(length), _a(&args), _r(&rv), _g(&global), _c(c), _e(e) {}
190 v8::Handle<v8::Object> *_a;
191 v8::Handle<v8::Value> *_r;
192 v8::Handle<v8::Object> *_g;
193 QDeclarativeContextData *_c;
197 class QDeclarativeV8Handle
200 QDeclarativeV8Handle() : d(0) {}
201 QDeclarativeV8Handle(const QDeclarativeV8Handle &other) : d(other.d) {}
202 QDeclarativeV8Handle &operator=(const QDeclarativeV8Handle &other) { d = other.d; return *this; }
204 static QDeclarativeV8Handle fromHandle(v8::Handle<v8::Value> h) {
205 return QDeclarativeV8Handle(*h);
207 v8::Handle<v8::Value> toHandle() const {
208 return v8::Handle<v8::Value>((v8::Value *)d);
211 QDeclarativeV8Handle(void *d) : d(d) {}
216 class QDeclarativeEngine;
217 class QDeclarativeValueType;
218 class QNetworkAccessManager;
219 class QDeclarativeContextData;
221 class Q_DECLARATIVE_EXPORT QV8Engine
224 static QV8Engine* get(QJSEngine* q) { Q_ASSERT(q); return q->handle(); }
225 static QJSEngine* get(QV8Engine* d) { Q_ASSERT(d); return d->q; }
227 QV8Engine(QJSEngine* qq,QJSEngine::ContextOwnership ownership = QJSEngine::CreateNewContext);
231 virtual ~Deletable() {}
236 typedef QPair<v8::Persistent<v8::Value>, v8::Persistent<v8::Message> > ValueMessagePair;
238 v8::Persistent<v8::Value> m_value;
239 v8::Persistent<v8::Message> m_message;
240 QStack<ValueMessagePair> m_stack;
242 Q_DISABLE_COPY(Exception)
246 inline void set(v8::Handle<v8::Value> value, v8::Handle<v8::Message> message);
248 inline operator bool() const;
249 inline operator v8::Handle<v8::Value>() const;
250 inline int lineNumber() const;
251 inline QStringList backtrace() const;
257 void initDeclarativeGlobalObject();
258 void setEngine(QDeclarativeEngine *engine);
259 QDeclarativeEngine *engine() { return m_engine; }
260 v8::Local<v8::Object> global() { return m_context->Global(); }
261 v8::Handle<v8::Context> context() const { return m_context; }
263 inline void registerValue(QJSValuePrivate *data);
264 inline void unregisterValue(QJSValuePrivate *data);
265 inline void invalidateAllValues();
267 inline void registerValueIterator(QJSValueIteratorPrivate *data);
268 inline void unregisterValueIterator(QJSValueIteratorPrivate *data);
269 inline void invalidateAllIterators();
271 QV8ContextWrapper *contextWrapper() { return &m_contextWrapper; }
272 QV8QObjectWrapper *qobjectWrapper() { return &m_qobjectWrapper; }
273 QV8TypeWrapper *typeWrapper() { return &m_typeWrapper; }
274 QV8ListWrapper *listWrapper() { return &m_listWrapper; }
275 QV8VariantWrapper *variantWrapper() { return &m_variantWrapper; }
276 QV8ValueTypeWrapper *valueTypeWrapper() { return &m_valueTypeWrapper; }
278 void *xmlHttpRequestData() { return m_xmlHttpRequestData; }
279 void *sqlDatabaseData() { return m_sqlDatabaseData; }
281 Deletable *listModelData() { return m_listModelData; }
282 void setListModelData(Deletable *d) { if (m_listModelData) delete m_listModelData; m_listModelData = d; }
284 QDeclarativeContextData *callingContext();
286 v8::Local<v8::Array> getOwnPropertyNames(v8::Handle<v8::Object>);
287 inline QJSValue::PropertyFlags getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property);
288 void freezeObject(v8::Handle<v8::Value>);
290 inline QString toString(v8::Handle<v8::Value> string);
291 inline QString toString(v8::Handle<v8::String> string);
292 static QString toStringStatic(v8::Handle<v8::Value>);
293 static QString toStringStatic(v8::Handle<v8::String>);
294 static inline bool startsWithUpper(v8::Handle<v8::String>);
296 QVariant toVariant(v8::Handle<v8::Value>, int typeHint);
297 v8::Handle<v8::Value> fromVariant(const QVariant &);
298 inline bool isVariant(v8::Handle<v8::Value>);
300 // Compile \a source (from \a fileName at \a lineNumber) in QML mode
301 v8::Local<v8::Script> qmlModeCompile(const QString &source,
302 const QString &fileName = QString(),
305 // Return the QML global "scope" object for the \a ctxt context and \a scope object.
306 inline v8::Local<v8::Object> qmlScope(QDeclarativeContextData *ctxt, QObject *scope);
308 QScriptPassPointer<QJSValuePrivate> newRegExp(const QRegExp ®exp);
309 QScriptPassPointer<QJSValuePrivate> newRegExp(const QString &pattern, const QString &flags);
311 // Return a JS wrapper for the given QObject \a object
312 inline v8::Handle<v8::Value> newQObject(QObject *object);
313 inline bool isQObject(v8::Handle<v8::Value>);
314 inline QObject *toQObject(v8::Handle<v8::Value>);
316 // Return a JS string for the given QString \a string
317 inline v8::Local<v8::String> toString(const QString &string);
319 // Create a new value type object
320 inline v8::Handle<v8::Value> newValueType(QObject *, int coreIndex, QDeclarativeValueType *);
321 inline v8::Handle<v8::Value> newValueType(const QVariant &, QDeclarativeValueType *);
323 // Create a new QVariant object. This doesn't examine the type of the variant, but always returns
324 // a QVariant wrapper
325 inline v8::Handle<v8::Value> newQVariant(const QVariant &);
327 // Return the network access manager for this engine. By default this returns the network
328 // access manager of the QDeclarativeEngine. It is overridden in the case of a threaded v8
329 // instance (like in WorkerScript).
330 virtual QNetworkAccessManager *networkAccessManager();
332 // Return the list of illegal id names (the names of the properties on the global object)
333 const QSet<QString> &illegalNames() const;
335 inline void collectGarbage() { gc(); }
338 void clearExceptions();
339 void setException(v8::Handle<v8::Value> value, v8::Handle<v8::Message> message = v8::Handle<v8::Message>());
340 v8::Handle<v8::Value> throwException(v8::Handle<v8::Value> value);
341 bool hasUncaughtException() const;
342 int uncaughtExceptionLineNumber() const;
343 QStringList uncaughtExceptionBacktrace() const;
344 v8::Handle<v8::Value> uncaughtException() const;
345 void saveException();
346 void restoreException();
348 #ifdef QML_GLOBAL_HANDLE_DEBUGGING
349 // Used for handle debugging
350 static void registerHandle(void *);
351 static void releaseHandle(void *);
354 static QMutex *registrationMutex();
355 static int registerExtension();
357 inline Deletable *extensionData(int) const;
358 void setExtensionData(int, Deletable *);
360 inline v8::Handle<v8::Value> makeJSValue(bool value);
361 inline v8::Handle<v8::Value> makeJSValue(int value);
362 inline v8::Handle<v8::Value> makeJSValue(uint value);
363 inline v8::Handle<v8::Value> makeJSValue(double value);
364 inline v8::Handle<v8::Value> makeJSValue(QJSValue::SpecialValue value);
365 inline v8::Handle<v8::Value> makeJSValue(const QString& value);
367 inline QScriptPassPointer<QJSValuePrivate> evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1);
368 QScriptPassPointer<QJSValuePrivate> evaluate(v8::Handle<v8::Script> script, v8::TryCatch& tryCatch);
370 QScriptPassPointer<QJSValuePrivate> newArray(uint length);
371 v8::Handle<v8::Object> newVariant(const QVariant &variant);
372 QScriptPassPointer<QJSValuePrivate> newVariant(QJSValuePrivate* value, const QVariant &variant);
374 v8::Handle<v8::Array> variantListToJS(const QVariantList &lst);
375 QVariantList variantListFromJS(v8::Handle<v8::Array> jsArray);
377 v8::Handle<v8::Object> variantMapToJS(const QVariantMap &vmap);
378 QVariantMap variantMapFromJS(v8::Handle<v8::Object> jsObject);
380 v8::Handle<v8::Value> variantToJS(const QVariant &value);
381 QVariant variantFromJS(v8::Handle<v8::Value> value);
383 v8::Handle<v8::Value> metaTypeToJS(int type, const void *data);
384 bool metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data);
386 bool convertToNativeQObject(v8::Handle<v8::Value> value,
387 const QByteArray &targetType,
390 QVariant &variantValue(v8::Handle<v8::Value> value);
392 QJSValue scriptValueFromInternal(v8::Handle<v8::Value>) const;
394 void emitSignalHandlerException();
396 QObject *qtObjectFromJS(v8::Handle<v8::Value> value);
397 QSet<int> visitedConversionObjects;
400 QDeclarativeEngine *m_engine;
401 bool m_ownsV8Context;
402 v8::Persistent<v8::Context> m_context;
403 QScriptOriginalGlobalObject m_originalGlobalObject;
405 QV8StringWrapper m_stringWrapper;
406 QV8ContextWrapper m_contextWrapper;
407 QV8QObjectWrapper m_qobjectWrapper;
408 QV8TypeWrapper m_typeWrapper;
409 QV8ListWrapper m_listWrapper;
410 QV8VariantWrapper m_variantWrapper;
411 QV8ValueTypeWrapper m_valueTypeWrapper;
413 v8::Persistent<v8::Function> m_getOwnPropertyNames;
414 v8::Persistent<v8::Function> m_freezeObject;
416 void *m_xmlHttpRequestData;
417 void *m_sqlDatabaseData;
419 QVector<Deletable *> m_extensionData;
420 Deletable *m_listModelData;
422 QSet<QString> m_illegalNames;
424 Exception m_exception;
426 QVariant toBasicVariant(v8::Handle<v8::Value>);
428 void initializeGlobal(v8::Handle<v8::Object>);
430 static v8::Handle<v8::Value> gc(const v8::Arguments &args);
431 static v8::Handle<v8::Value> print(const v8::Arguments &args);
432 static v8::Handle<v8::Value> isQtObject(const v8::Arguments &args);
433 static v8::Handle<v8::Value> rgba(const v8::Arguments &args);
434 static v8::Handle<v8::Value> hsla(const v8::Arguments &args);
435 static v8::Handle<v8::Value> rect(const v8::Arguments &args);
436 static v8::Handle<v8::Value> point(const v8::Arguments &args);
437 static v8::Handle<v8::Value> size(const v8::Arguments &args);
438 static v8::Handle<v8::Value> vector3d(const v8::Arguments &args);
439 static v8::Handle<v8::Value> vector4d(const v8::Arguments &args);
440 static v8::Handle<v8::Value> lighter(const v8::Arguments &args);
441 static v8::Handle<v8::Value> darker(const v8::Arguments &args);
442 static v8::Handle<v8::Value> tint(const v8::Arguments &args);
443 static v8::Handle<v8::Value> formatDate(const v8::Arguments &args);
444 static v8::Handle<v8::Value> formatTime(const v8::Arguments &args);
445 static v8::Handle<v8::Value> formatDateTime(const v8::Arguments &args);
446 static v8::Handle<v8::Value> openUrlExternally(const v8::Arguments &args);
447 static v8::Handle<v8::Value> fontFamilies(const v8::Arguments &args);
448 static v8::Handle<v8::Value> md5(const v8::Arguments &args);
449 static v8::Handle<v8::Value> btoa(const v8::Arguments &args);
450 static v8::Handle<v8::Value> atob(const v8::Arguments &args);
451 static v8::Handle<v8::Value> quit(const v8::Arguments &args);
452 static v8::Handle<v8::Value> resolvedUrl(const v8::Arguments &args);
453 static v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args);
454 static v8::Handle<v8::Value> createComponent(const v8::Arguments &args);
455 static v8::Handle<v8::Value> qsTranslate(const v8::Arguments &args);
456 static v8::Handle<v8::Value> qsTranslateNoOp(const v8::Arguments &args);
457 static v8::Handle<v8::Value> qsTr(const v8::Arguments &args);
458 static v8::Handle<v8::Value> qsTrNoOp(const v8::Arguments &args);
459 static v8::Handle<v8::Value> qsTrId(const v8::Arguments &args);
460 static v8::Handle<v8::Value> qsTrIdNoOp(const v8::Arguments &args);
461 static v8::Handle<v8::Value> stringArg(const v8::Arguments &args);
463 double qtDateTimeToJsDate(const QDateTime &dt);
464 QDateTime qtDateTimeFromJsDate(double jsDate);
467 typedef QScriptIntrusiveList<QJSValuePrivate, &QJSValuePrivate::m_node> ValueList;
469 typedef QScriptIntrusiveList<QJSValueIteratorPrivate, &QJSValueIteratorPrivate::m_node> ValueIteratorList;
470 ValueIteratorList m_valueIterators;
472 Q_DISABLE_COPY(QV8Engine)
473 friend class QV8DebugService;
476 // Allocate a new Persistent handle. *ALL* persistent handles in QML must be allocated
477 // using this method.
479 v8::Persistent<T> qPersistentNew(v8::Handle<T> that)
481 v8::Persistent<T> rv = v8::Persistent<T>::New(that);
482 #ifdef QML_GLOBAL_HANDLE_DEBUGGING
483 QV8Engine::registerHandle(*rv);
488 // Register a Persistent handle that was returned to you by V8 (such as by
489 // v8::Context::New). This allows us to do handle tracking on these handles too.
491 void qPersistentRegister(v8::Persistent<T> handle)
493 #ifdef QML_GLOBAL_HANDLE_DEBUGGING
494 QV8Engine::registerHandle(*handle);
500 // Dispose and clear a persistent handle. *ALL* persistent handles in QML must be
501 // disposed using this method.
503 void qPersistentDispose(v8::Persistent<T> &that)
505 #ifdef QML_GLOBAL_HANDLE_DEBUGGING
506 QV8Engine::releaseHandle(*that);
512 QString QV8Engine::toString(v8::Handle<v8::Value> string)
514 return m_stringWrapper.toString(string->ToString());
517 QString QV8Engine::toString(v8::Handle<v8::String> string)
519 return m_stringWrapper.toString(string);
522 bool QV8Engine::isVariant(v8::Handle<v8::Value> value)
524 return m_variantWrapper.isVariant(value);
527 v8::Local<v8::Object> QV8Engine::qmlScope(QDeclarativeContextData *ctxt, QObject *scope)
529 return m_contextWrapper.qmlScope(ctxt, scope);
532 bool QV8Engine::isQObject(v8::Handle<v8::Value> obj)
534 return obj->IsObject()?m_qobjectWrapper.isQObject(v8::Handle<v8::Object>::Cast(obj)):false;
537 QObject *QV8Engine::toQObject(v8::Handle<v8::Value> obj)
539 return obj->IsObject()?m_qobjectWrapper.toQObject(v8::Handle<v8::Object>::Cast(obj)):0;
542 v8::Handle<v8::Value> QV8Engine::newQObject(QObject *object)
544 return m_qobjectWrapper.newQObject(object);
547 v8::Local<v8::String> QV8Engine::toString(const QString &string)
549 return m_stringWrapper.toString(string);
552 v8::Handle<v8::Value> QV8Engine::newValueType(QObject *object, int property, QDeclarativeValueType *type)
554 return m_valueTypeWrapper.newValueType(object, property, type);
557 v8::Handle<v8::Value> QV8Engine::newValueType(const QVariant &value, QDeclarativeValueType *type)
559 return m_valueTypeWrapper.newValueType(value, type);
562 // XXX Can this be made more optimal? It is called prior to resolving each and every
563 // unqualified name in QV8ContextWrapper.
564 bool QV8Engine::startsWithUpper(v8::Handle<v8::String> string)
566 uint16_t c = string->GetCharacter(0);
567 return (c >= 'A' && c <= 'Z') ||
568 (c > 127 && QChar::category(c) == QChar::Letter_Uppercase);
571 QV8Engine::Deletable *QV8Engine::extensionData(int index) const
573 if (index < m_extensionData.count())
574 return m_extensionData[index];
581 #endif // QDECLARATIVEV8ENGINE_P_H