Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / v8 / qv8engine_p.h
index 46ba0a4..f46a660 100644 (file)
@@ -1,34 +1,34 @@
 /****************************************************************************
 **
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
 **
 ** This file is part of the QtDeclarative module of the Qt Toolkit.
 **
 ** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
 ** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 **
 ** In addition, as a special exception, Nokia gives you certain additional
-** rights.  These rights are described in the Nokia Qt LGPL Exception
+** rights. These rights are described in the Nokia Qt LGPL Exception
 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 **
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
 **
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
 **
 **
 **
 #include <QtCore/qvariant.h>
 #include <QtCore/qset.h>
 #include <QtCore/qmutex.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QThreadStorage>
+
 #include <private/qv8_p.h>
+#include <qjsengine.h>
+#include <qjsvalue.h>
+#include "qjsvalue_p.h"
+#include "qjsvalueiterator_p.h"
+#include "qscriptoriginalglobalobject_p.h"
+#include "qscripttools_p.h"
 
 #include <private/qdeclarativepropertycache_p.h>
 
@@ -68,6 +79,7 @@
 #include "qv8listwrapper_p.h"
 #include "qv8variantwrapper_p.h"
 #include "qv8valuetypewrapper_p.h"
+#include "qv8sequencewrapper_p.h"
 
 QT_BEGIN_NAMESPACE
 
@@ -90,6 +102,10 @@ private:
     v8::ThrowException(v8::Exception::Error(v8::String::New(string))); \
     return v8::Handle<v8::Value>(); \
 }
+#define V8THROW_TYPE(string) { \
+    v8::ThrowException(v8::Exception::TypeError(v8::String::New(string))); \
+    return v8::Handle<v8::Value>(); \
+}
 #define V8ENGINE_ACCESSOR() ((QV8Engine *)v8::External::Unwrap(info.Data()));
 #define V8THROW_ERROR_SETTER(string) { \
     v8::ThrowException(v8::Exception::Error(v8::String::New(string))); \
@@ -114,6 +130,7 @@ private:
         return rv; \
     } \
 
+
 class QV8Engine;
 class QV8ObjectResource : public v8::Object::ExternalResource
 {
@@ -121,7 +138,9 @@ public:
     QV8ObjectResource(QV8Engine *engine) : engine(engine) { Q_ASSERT(engine); }
     enum ResourceType { ContextType, QObjectType, TypeType, ListType, VariantType, 
                         ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType,
-                        ListModelType, Context2DType };
+                        ListModelType, Context2DType, Context2DStyleType, Context2DPixelArrayType, 
+                        ParticleDataType, SignalHandlerType, IncubatorType, VisualDataItemType,
+                        SequenceType, LocaleDataType };
     virtual ResourceType resourceType() const = 0;
 
     QV8Engine *engine;
@@ -188,12 +207,13 @@ public:
     QDeclarativeV8Handle &operator=(const QDeclarativeV8Handle &other) { d = other.d; return *this; }
 
     static QDeclarativeV8Handle fromHandle(v8::Handle<v8::Value> h) {
-        return reinterpret_cast<QDeclarativeV8Handle &>(h);
+        return QDeclarativeV8Handle(*h);
     }
     v8::Handle<v8::Value> toHandle() const {
-        return reinterpret_cast<const v8::Handle<v8::Value> &>(*this);
+        return v8::Handle<v8::Value>((v8::Value *)d);
     }
 private:
+    QDeclarativeV8Handle(void *d) : d(d) {}
     void *d;
 };
 
@@ -202,26 +222,89 @@ class QDeclarativeEngine;
 class QDeclarativeValueType;
 class QNetworkAccessManager;
 class QDeclarativeContextData;
-class Q_AUTOTEST_EXPORT QV8Engine 
+
+class Q_AUTOTEST_EXPORT QV8GCCallback
+{
+private:
+    class ThreadData;
+public:
+    static void garbageCollectorPrologueCallback(v8::GCType, v8::GCCallbackFlags);
+    static void registerGcPrologueCallback();
+
+    class Q_AUTOTEST_EXPORT Node {
+    public:
+        typedef void (*PrologueCallback)(Node *node);
+        Node(PrologueCallback callback);
+        ~Node();
+
+        QIntrusiveListNode node;
+        PrologueCallback prologueCallback;
+    };
+
+    static void addGcCallbackNode(Node *node);
+};
+
+class Q_DECLARATIVE_EXPORT QV8Engine
 {
 public:
-    QV8Engine();
+    static QV8Engine* get(QJSEngine* q) { Q_ASSERT(q); return q->handle(); }
+    static QJSEngine* get(QV8Engine* d) { Q_ASSERT(d); return d->q; }
+
+    QV8Engine(QJSEngine* qq,QJSEngine::ContextOwnership ownership = QJSEngine::CreateNewContext);
     ~QV8Engine();
 
+    // ### TODO get rid of it, do we really need CppOwnership?
+    // This enum should be in sync with QDeclarativeEngine::ObjectOwnership
+    enum ObjectOwnership { CppOwnership, JavaScriptOwnership };
+
     struct Deletable {
-        ~Deletable() {}
+        virtual ~Deletable() {}
     };
 
-    void init(QDeclarativeEngine *);
+    class Exception
+    {
+        typedef QPair<v8::Persistent<v8::Value>, v8::Persistent<v8::Message> > ValueMessagePair;
+
+        v8::Persistent<v8::Value> m_value;
+        v8::Persistent<v8::Message> m_message;
+        QStack<ValueMessagePair> m_stack;
+
+        Q_DISABLE_COPY(Exception)
+    public:
+        inline Exception();
+        inline ~Exception();
+        inline void set(v8::Handle<v8::Value> value, v8::Handle<v8::Message> message);
+        inline void clear();
+        inline operator bool() const;
+        inline operator v8::Handle<v8::Value>() const;
+        inline int lineNumber() const;
+        inline QStringList backtrace() const;
+
+        inline void push();
+        inline void pop();
+    };
 
+    void initDeclarativeGlobalObject();
+    void setEngine(QDeclarativeEngine *engine);
     QDeclarativeEngine *engine() { return m_engine; }
     v8::Local<v8::Object> global() { return m_context->Global(); }
-    v8::Handle<v8::Context> context() { return m_context; }
+    v8::Handle<v8::Context> context() const { return m_context; }
+
+    inline void registerValue(QJSValuePrivate *data);
+    inline void unregisterValue(QJSValuePrivate *data);
+    inline void invalidateAllValues();
+
+    inline void registerValueIterator(QJSValueIteratorPrivate *data);
+    inline void unregisterValueIterator(QJSValueIteratorPrivate *data);
+    inline void invalidateAllIterators();
+
     QV8ContextWrapper *contextWrapper() { return &m_contextWrapper; }
     QV8QObjectWrapper *qobjectWrapper() { return &m_qobjectWrapper; }
     QV8TypeWrapper *typeWrapper() { return &m_typeWrapper; }
     QV8ListWrapper *listWrapper() { return &m_listWrapper; }
     QV8VariantWrapper *variantWrapper() { return &m_variantWrapper; }
+    QV8ValueTypeWrapper *valueTypeWrapper() { return &m_valueTypeWrapper; }
+    QV8SequenceWrapper *sequenceWrapper() { return &m_sequenceWrapper; }
 
     void *xmlHttpRequestData() { return m_xmlHttpRequestData; }
     void *sqlDatabaseData() { return m_sqlDatabaseData; }
@@ -232,6 +315,7 @@ public:
     QDeclarativeContextData *callingContext();
 
     v8::Local<v8::Array> getOwnPropertyNames(v8::Handle<v8::Object>);
+    inline QJSValue::PropertyFlags getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property);
     void freezeObject(v8::Handle<v8::Value>);
 
     inline QString toString(v8::Handle<v8::Value> string);
@@ -252,8 +336,12 @@ public:
     // Return the QML global "scope" object for the \a ctxt context and \a scope object.
     inline v8::Local<v8::Object> qmlScope(QDeclarativeContextData *ctxt, QObject *scope);
 
+    QScriptPassPointer<QJSValuePrivate> newRegExp(const QRegExp &regexp);
+    QScriptPassPointer<QJSValuePrivate> newRegExp(const QString &pattern, const QString &flags);
+
     // Return a JS wrapper for the given QObject \a object
     inline v8::Handle<v8::Value> newQObject(QObject *object);
+    inline v8::Handle<v8::Value> newQObject(QObject *object, const ObjectOwnership ownership);
     inline bool isQObject(v8::Handle<v8::Value>);
     inline QObject *toQObject(v8::Handle<v8::Value>);
 
@@ -264,6 +352,9 @@ public:
     inline v8::Handle<v8::Value> newValueType(QObject *, int coreIndex, QDeclarativeValueType *);
     inline v8::Handle<v8::Value> newValueType(const QVariant &, QDeclarativeValueType *);
 
+    // Create a new sequence type object
+    inline v8::Handle<v8::Value> newSequence(int sequenceType, QObject *, int coreIndex, bool *succeeded);
+
     // Create a new QVariant object.  This doesn't examine the type of the variant, but always returns
     // a QVariant wrapper
     inline v8::Handle<v8::Value> newQVariant(const QVariant &);
@@ -274,10 +365,21 @@ public:
     virtual QNetworkAccessManager *networkAccessManager();
 
     // Return the list of illegal id names (the names of the properties on the global object)
-    const QSet<QString> &illegalNames() const;
+    const QStringHash<bool> &illegalNames() const;
 
+    inline void collectGarbage() { gc(); }
     static void gc();
 
+    void clearExceptions();
+    void setException(v8::Handle<v8::Value> value, v8::Handle<v8::Message> message = v8::Handle<v8::Message>());
+    v8::Handle<v8::Value> throwException(v8::Handle<v8::Value> value);
+    bool hasUncaughtException() const;
+    int uncaughtExceptionLineNumber() const;
+    QStringList uncaughtExceptionBacktrace() const;
+    v8::Handle<v8::Value> uncaughtException() const;
+    void saveException();
+    void restoreException();
+
 #ifdef QML_GLOBAL_HANDLE_DEBUGGING
     // Used for handle debugging
     static void registerHandle(void *);
@@ -290,9 +392,77 @@ public:
     inline Deletable *extensionData(int) const;
     void setExtensionData(int, Deletable *);
 
-private:
+    inline v8::Handle<v8::Value> makeJSValue(bool value);
+    inline v8::Local<v8::Value> makeJSValue(int value);
+    inline v8::Local<v8::Value> makeJSValue(uint value);
+    inline v8::Local<v8::Value> makeJSValue(double value);
+    inline v8::Handle<v8::Value> makeJSValue(QJSValue::SpecialValue value);
+    inline v8::Local<v8::Value> makeJSValue(const QString &value);
+
+    inline QScriptPassPointer<QJSValuePrivate> evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1);
+    QScriptPassPointer<QJSValuePrivate> evaluate(v8::Handle<v8::Script> script, v8::TryCatch& tryCatch);
+
+    QScriptPassPointer<QJSValuePrivate> newArray(uint length);
+    v8::Local<v8::Object> newVariant(const QVariant &variant);
+    QScriptPassPointer<QJSValuePrivate> newVariant(QJSValuePrivate* value, const QVariant &variant);
+
+    v8::Local<v8::Array> variantListToJS(const QVariantList &lst);
+    QVariantList variantListFromJS(v8::Handle<v8::Array> jsArray);
+
+    v8::Local<v8::Object> variantMapToJS(const QVariantMap &vmap);
+    QVariantMap variantMapFromJS(v8::Handle<v8::Object> jsObject);
+
+    v8::Handle<v8::Value> variantToJS(const QVariant &value);
+    QVariant variantFromJS(v8::Handle<v8::Value> value);
+
+    v8::Handle<v8::Value> metaTypeToJS(int type, const void *data);
+    bool metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data);
+
+    bool convertToNativeQObject(v8::Handle<v8::Value> value,
+                                const QByteArray &targetType,
+                                void **result);
+
+    QVariant &variantValue(v8::Handle<v8::Value> value);
+
+    QJSValue scriptValueFromInternal(v8::Handle<v8::Value>) const;
+
+    void emitSignalHandlerException();
+
+    // used for console.time(), console.timeEnd()
+    void startTimer(const QString &timerName);
+    qint64 stopTimer(const QString &timerName, bool *wasRunning);
+
+    // used for console.count()
+    int consoleCountHelper(const QString &file, int line, int column);
+
+    QObject *qtObjectFromJS(v8::Handle<v8::Value> value);
+    QSet<int> visitedConversionObjects;
+
+    static QDateTime qtDateTimeFromJsDate(double jsDate);
+
+    void addRelationshipForGC(QObject *object, v8::Persistent<v8::Value> handle);
+    void addRelationshipForGC(QObject *object, QObject *other);
+
+    struct ThreadData {
+        ThreadData();
+        ~ThreadData();
+        v8::Isolate* isolate;
+        bool gcPrologueCallbackRegistered;
+        QIntrusiveList<QV8GCCallback::Node, &QV8GCCallback::Node::node> gcCallbackNodes;
+    };
+
+    static bool hasThreadData();
+    static ThreadData* threadData();
+    static void ensurePerThreadIsolate();
+
+    v8::Persistent<v8::Object> m_strongReferencer;
+
+protected:
+    QJSEngine* q;
     QDeclarativeEngine *m_engine;
+    bool m_ownsV8Context;
     v8::Persistent<v8::Context> m_context;
+    QScriptOriginalGlobalObject m_originalGlobalObject;
 
     QV8StringWrapper m_stringWrapper;
     QV8ContextWrapper m_contextWrapper;
@@ -301,6 +471,7 @@ private:
     QV8ListWrapper m_listWrapper;
     QV8VariantWrapper m_variantWrapper;
     QV8ValueTypeWrapper m_valueTypeWrapper;
+    QV8SequenceWrapper m_sequenceWrapper;
 
     v8::Persistent<v8::Function> m_getOwnPropertyNames;
     v8::Persistent<v8::Function> m_freezeObject;
@@ -311,39 +482,30 @@ private:
     QVector<Deletable *> m_extensionData;
     Deletable *m_listModelData;
 
-    QSet<QString> m_illegalNames;
+    QStringHash<bool> m_illegalNames;
+
+    Exception m_exception;
+
+    QElapsedTimer m_time;
+    QHash<QString, qint64> m_startedTimers;
+
+    QHash<QString, quint32> m_consoleCount;
 
     QVariant toBasicVariant(v8::Handle<v8::Value>);
 
     void initializeGlobal(v8::Handle<v8::Object>);
 
-    static v8::Handle<v8::Value> gc(const v8::Arguments &args);
-    static v8::Handle<v8::Value> print(const v8::Arguments &args);
-    static v8::Handle<v8::Value> isQtObject(const v8::Arguments &args);
-    static v8::Handle<v8::Value> rgba(const v8::Arguments &args);
-    static v8::Handle<v8::Value> hsla(const v8::Arguments &args);
-    static v8::Handle<v8::Value> rect(const v8::Arguments &args);
-    static v8::Handle<v8::Value> point(const v8::Arguments &args);
-    static v8::Handle<v8::Value> size(const v8::Arguments &args);
-    static v8::Handle<v8::Value> vector3d(const v8::Arguments &args);
-    static v8::Handle<v8::Value> lighter(const v8::Arguments &args);
-    static v8::Handle<v8::Value> darker(const v8::Arguments &args);
-    static v8::Handle<v8::Value> tint(const v8::Arguments &args);
-    static v8::Handle<v8::Value> formatDate(const v8::Arguments &args);
-    static v8::Handle<v8::Value> formatTime(const v8::Arguments &args);
-    static v8::Handle<v8::Value> formatDateTime(const v8::Arguments &args);
-    static v8::Handle<v8::Value> openUrlExternally(const v8::Arguments &args);
-    static v8::Handle<v8::Value> fontFamilies(const v8::Arguments &args);
-    static v8::Handle<v8::Value> md5(const v8::Arguments &args);
-    static v8::Handle<v8::Value> btoa(const v8::Arguments &args);
-    static v8::Handle<v8::Value> atob(const v8::Arguments &args);
-    static v8::Handle<v8::Value> quit(const v8::Arguments &args);
-    static v8::Handle<v8::Value> resolvedUrl(const v8::Arguments &args);
-    static v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args);
-    static v8::Handle<v8::Value> createComponent(const v8::Arguments &args);
-
     double qtDateTimeToJsDate(const QDateTime &dt);
-    QDateTime qtDateTimeFromJsDate(double jsDate);
+
+private:
+    static v8::Persistent<v8::Object> *findOwnerAndStrength(QObject *object, bool *shouldBeStrong);
+
+    typedef QScriptIntrusiveList<QJSValuePrivate, &QJSValuePrivate::m_node> ValueList;
+    ValueList m_values;
+    typedef QScriptIntrusiveList<QJSValueIteratorPrivate, &QJSValueIteratorPrivate::m_node> ValueIteratorList;
+    ValueIteratorList m_valueIterators;
+
+    Q_DISABLE_COPY(QV8Engine)
 };
 
 // Allocate a new Persistent handle.  *ALL* persistent handles in QML must be allocated
@@ -417,6 +579,20 @@ v8::Handle<v8::Value> QV8Engine::newQObject(QObject *object)
     return m_qobjectWrapper.newQObject(object);
 }
 
+v8::Handle<v8::Value> QV8Engine::newQObject(QObject *object, const ObjectOwnership ownership)
+{
+    if (!object)
+        return v8::Null();
+
+    v8::Handle<v8::Value> result = newQObject(object);
+    QDeclarativeData *ddata = QDeclarativeData::get(object, true);
+    if (ownership == JavaScriptOwnership && ddata) {
+        ddata->indestructible = false;
+        ddata->explicitIndestructibleSet = true;
+    }
+    return result;
+}
+
 v8::Local<v8::String> QV8Engine::toString(const QString &string)
 {
     return m_stringWrapper.toString(string);
@@ -432,6 +608,11 @@ v8::Handle<v8::Value> QV8Engine::newValueType(const QVariant &value, QDeclarativ
     return m_valueTypeWrapper.newValueType(value, type);
 }
 
+v8::Handle<v8::Value> QV8Engine::newSequence(int sequenceType, QObject *object, int property, bool *succeeded)
+{
+    return m_sequenceWrapper.newSequence(sequenceType, object, property, succeeded);
+}
+
 // XXX Can this be made more optimal?  It is called prior to resolving each and every 
 // unqualified name in QV8ContextWrapper.
 bool QV8Engine::startsWithUpper(v8::Handle<v8::String> string)