diff options
author | Gunnar Sletta <gunnar.sletta@nokia.com> | 2011-08-11 16:03:12 +0200 |
---|---|---|
committer | Gunnar Sletta <gunnar.sletta@nokia.com> | 2011-08-11 16:03:12 +0200 |
commit | f9949f501890a7f8289fcbda85d3a4085bdbb21a (patch) | |
tree | 759e57bb3ed156e46a98c3a4223951c3edc55d43 /src | |
parent | 1ddef09c351f2899b1662ddd1de190c0d0a8b7bf (diff) | |
parent | 3e0c19d5ba0e4826c3f036c3172d8ea0e30530a6 (diff) |
Merge branch 'master' into refactor
Conflicts:
src/declarative/declarative.pro
src/imports/gestures/gestures.pro
src/imports/inputcontext/inputcontext.pro
src/qtquick1/graphicsitems/qdeclarativeitem.cpp
src/qtquick1/qtquick1.pro
Change-Id: I782be7090d8b6da9c890bc8e778722da93da8037
Diffstat (limited to 'src')
91 files changed, 6661 insertions, 541 deletions
diff --git a/src/3rdparty/v8 b/src/3rdparty/v8 -Subproject bec11b8b7f89d135e7d9a823ac4fe98c70d017c +Subproject 472c04c9e7a64e8734c76d2cf97a7cc5b773b78 diff --git a/src/declarative/debugger/qdeclarativedebughelper.cpp b/src/declarative/debugger/qdeclarativedebughelper.cpp index 6eea82c948..5f5d8754bb 100644 --- a/src/declarative/debugger/qdeclarativedebughelper.cpp +++ b/src/declarative/debugger/qdeclarativedebughelper.cpp @@ -39,12 +39,10 @@ ** ****************************************************************************/ -#include <QtScript/QScriptEngine> - #include "private/qdeclarativedebughelper_p.h" #include <QtCore/QAbstractAnimation> -#include <QtScript/QScriptEngine> +#include <QtDeclarative/QJSEngine> #include <private/qdeclarativeengine_p.h> #include <private/qabstractanimation_p.h> diff --git a/src/declarative/debugger/qjsdebuggeragent.cpp b/src/declarative/debugger/qjsdebuggeragent.cpp index 3169f91b59..f47def802a 100644 --- a/src/declarative/debugger/qjsdebuggeragent.cpp +++ b/src/declarative/debugger/qjsdebuggeragent.cpp @@ -46,9 +46,9 @@ #include <QtCore/qcoreapplication.h> #include <QtCore/qset.h> #include <QtCore/qurl.h> -#include <QtScript/qscriptcontextinfo.h> -#include <QtScript/qscriptengine.h> -#include <QtScript/qscriptvalueiterator.h> +#include <QtDeclarative/qjsengine.h> + +#include <QtCore/qstringlist.h> QT_BEGIN_NAMESPACE @@ -61,9 +61,9 @@ public: void continueExec(); void recordKnownObjects(const QList<JSAgentWatchData> &); - QList<JSAgentWatchData> getLocals(QScriptContext *); + QList<JSAgentWatchData> getLocals(void *); void positionChange(qint64 scriptId, int lineNumber, int columnNumber); - QScriptEngine *engine() { return q->engine(); } + QJSEngine *engine() { return q->engine(); } void stopped(); public: @@ -111,7 +111,7 @@ private: } // anonymous namespace static JSAgentWatchData fromScriptValue(const QString &expression, - const QScriptValue &value) + const QJSValue &value) { static const QString arrayStr = QCoreApplication::translate ("Debugger::JSAgentWatchData", "[Array of length %1]"); @@ -123,7 +123,7 @@ static JSAgentWatchData fromScriptValue(const QString &expression, data.name = data.exp; data.hasChildren = false; data.value = value.toString().toUtf8(); - data.objectId = value.objectId(); + // data.objectId = value.objectId(); if (value.isArray()) { data.type = "Array"; data.value = arrayStr.arg(value.property(QLatin1String("length")).toString()).toUtf8(); @@ -167,30 +167,30 @@ static JSAgentWatchData fromScriptValue(const QString &expression, return data; } -static QList<JSAgentWatchData> expandObject(const QScriptValue &object) +static QList<JSAgentWatchData> expandObject(const QJSValue &object) { QList<JSAgentWatchData> result; - QScriptValueIterator it(object); - while (it.hasNext()) { - it.next(); - if (it.flags() & QScriptValue::SkipInEnumeration) - continue; - if (/*object.isQObject() &&*/ it.value().isFunction()) { - // Cosmetics: skip all functions and slot, there are too many of them, - // and it is not useful information in the debugger. - continue; - } - JSAgentWatchData data = fromScriptValue(it.name(), it.value()); - result.append(data); - } - if (result.isEmpty()) { - JSAgentWatchData data; - data.name = "<no initialized data>"; - data.hasChildren = false; - data.value = " "; - data.objectId = 0; - result.append(data); - } +// QScriptValueIterator it(object); +// while (it.hasNext()) { +// it.next(); +// if (it.flags() & QScriptValue::SkipInEnumeration) +// continue; +// if (/*object.isQObject() &&*/ it.value().isFunction()) { +// // Cosmetics: skip all functions and slot, there are too many of them, +// // and it is not useful information in the debugger. +// continue; +// } +// JSAgentWatchData data = fromScriptValue(it.name(), it.value()); +// result.append(data); +// } +// if (result.isEmpty()) { +// JSAgentWatchData data; +// data.name = "<no initialized data>"; +// data.hasChildren = false; +// data.value = " "; +// data.objectId = 0; +// result.append(data); +// } return result; } @@ -206,20 +206,20 @@ void QJSDebuggerAgentPrivate::recordKnownObjects(const QList<JSAgentWatchData>& knownObjectIds << data.objectId; } -QList<JSAgentWatchData> QJSDebuggerAgentPrivate::getLocals(QScriptContext *ctx) +QList<JSAgentWatchData> QJSDebuggerAgentPrivate::getLocals(void *ctx) { QList<JSAgentWatchData> locals; - if (ctx) { - QScriptValue activationObject = ctx->activationObject(); - QScriptValue thisObject = ctx->thisObject(); - locals = expandObject(activationObject); - if (thisObject.isObject() - && thisObject.objectId() != engine()->globalObject().objectId() - && QScriptValueIterator(thisObject).hasNext()) - locals.prepend(fromScriptValue(QLatin1String("this"), thisObject)); - recordKnownObjects(locals); - knownObjectIds << activationObject.objectId(); - } +// if (ctx) { +// QScriptValue activationObject = ctx->activationObject(); +// QScriptValue thisObject = ctx->thisObject(); +// locals = expandObject(activationObject); +// if (thisObject.isObject() +// && thisObject.objectId() != engine()->globalObject().objectId() +// && QScriptValueIterator(thisObject).hasNext()) +// locals.prepend(fromScriptValue(QLatin1String("this"), thisObject)); +// recordKnownObjects(locals); +// knownObjectIds << activationObject.objectId(); +// } return locals; } @@ -228,20 +228,18 @@ QList<JSAgentWatchData> QJSDebuggerAgentPrivate::getLocals(QScriptContext *ctx) report debugging-related events (e.g. step completion) to the given \a backend. */ -QJSDebuggerAgent::QJSDebuggerAgent(QScriptEngine *engine, QObject *parent) +QJSDebuggerAgent::QJSDebuggerAgent(QJSEngine *engine, QObject *parent) : QObject(parent) - , QScriptEngineAgent(engine) , d(new QJSDebuggerAgentPrivate(this)) { - QJSDebuggerAgent::engine()->setAgent(this); + //QJSDebuggerAgent::engine()->setAgent(this); } QJSDebuggerAgent::QJSDebuggerAgent(QDeclarativeEngine *engine, QObject *parent) : QObject(parent) - , QScriptEngineAgent(0) , d(new QJSDebuggerAgentPrivate(this)) { - QJSDebuggerAgent::engine()->setAgent(this); + //QJSDebuggerAgent::engine()->setAgent(this); } /*! @@ -249,7 +247,7 @@ QJSDebuggerAgent::QJSDebuggerAgent(QDeclarativeEngine *engine, QObject *parent) */ QJSDebuggerAgent::~QJSDebuggerAgent() { - engine()->setAgent(0); + //engine()->setAgent(0); delete d; } @@ -317,9 +315,9 @@ QList<JSAgentWatchData> QJSDebuggerAgent::expandObjectById(quint64 objectId) { SetupExecEnv execEnv(d); - QScriptValue v; - if (d->knownObjectIds.contains(objectId)) - v = engine()->objectById(objectId); + QJSValue v; +// if (d->knownObjectIds.contains(objectId)) +// v = engine()->objectById(objectId); QList<JSAgentWatchData> result = expandObject(v); d->recordKnownObjects(result); @@ -329,21 +327,21 @@ QList<JSAgentWatchData> QJSDebuggerAgent::expandObjectById(quint64 objectId) QList<JSAgentWatchData> QJSDebuggerAgent::locals() { SetupExecEnv execEnv(d); - return d->getLocals(engine()->currentContext()); + return d->getLocals(0/*engine()->currentContext()*/); } QList<JSAgentWatchData> QJSDebuggerAgent::localsAtFrame(int frameId) { SetupExecEnv execEnv(d); - int deep = 0; - QScriptContext *ctx = engine()->currentContext(); - while (ctx && deep < frameId) { - ctx = ctx->parentContext(); - deep++; - } +// int deep = 0; +// QScriptContext *ctx = engine()->currentContext(); +// while (ctx && deep < frameId) { +// ctx = ctx->parentContext(); +// deep++; +// } - return d->getLocals(ctx); + return d->getLocals(0/*ctx*/); } QList<JSAgentStackData> QJSDebuggerAgent::backtrace() @@ -352,37 +350,37 @@ QList<JSAgentStackData> QJSDebuggerAgent::backtrace() QList<JSAgentStackData> backtrace; - for (QScriptContext *ctx = engine()->currentContext(); ctx; ctx = ctx->parentContext()) { - QScriptContextInfo info(ctx); - - JSAgentStackData frame; - frame.functionName = info.functionName().toUtf8(); - if (frame.functionName.isEmpty()) { - if (ctx->parentContext()) { - switch (info.functionType()) { - case QScriptContextInfo::ScriptFunction: - frame.functionName = "<anonymous>"; - break; - case QScriptContextInfo::NativeFunction: - frame.functionName = "<native>"; - break; - case QScriptContextInfo::QtFunction: - case QScriptContextInfo::QtPropertyFunction: - frame.functionName = "<native slot>"; - break; - } - } else { - frame.functionName = "<global>"; - } - } - frame.lineNumber = info.lineNumber(); - // if the line number is unknown, fallback to the function line number - if (frame.lineNumber == -1) - frame.lineNumber = info.functionStartLineNumber(); - - frame.fileUrl = info.fileName().toUtf8(); - backtrace.append(frame); - } +// for (QScriptContext *ctx = engine()->currentContext(); ctx; ctx = ctx->parentContext()) { +// QScriptContextInfo info(ctx); + +// JSAgentStackData frame; +// frame.functionName = info.functionName().toUtf8(); +// if (frame.functionName.isEmpty()) { +// if (ctx->parentContext()) { +// switch (info.functionType()) { +// case QScriptContextInfo::ScriptFunction: +// frame.functionName = "<anonymous>"; +// break; +// case QScriptContextInfo::NativeFunction: +// frame.functionName = "<native>"; +// break; +// case QScriptContextInfo::QtFunction: +// case QScriptContextInfo::QtPropertyFunction: +// frame.functionName = "<native slot>"; +// break; +// } +// } else { +// frame.functionName = "<global>"; +// } +// } +// frame.lineNumber = info.lineNumber(); +// // if the line number is unknown, fallback to the function line number +// if (frame.lineNumber == -1) +// frame.lineNumber = info.functionStartLineNumber(); + +// frame.fileUrl = info.fileName().toUtf8(); +// backtrace.append(frame); +// } return backtrace; } @@ -405,9 +403,9 @@ void QJSDebuggerAgent::setProperty(qint64 objectId, SetupExecEnv execEnv(d); if (d->knownObjectIds.contains(objectId)) { - QScriptValue object = engine()->objectById(objectId); + QJSValue object;// = engine()->objectById(objectId); if (object.isObject()) { - QScriptValue result = engine()->evaluate(value); + QJSValue result = engine()->evaluate(value); object.setProperty(property, result); } } @@ -457,7 +455,7 @@ void QJSDebuggerAgent::functionEntry(qint64 scriptId) /*! \reimp */ -void QJSDebuggerAgent::functionExit(qint64 scriptId, const QScriptValue &returnValue) +void QJSDebuggerAgent::functionExit(qint64 scriptId, const QJSValue &returnValue) { Q_UNUSED(scriptId); Q_UNUSED(returnValue); @@ -476,53 +474,53 @@ void QJSDebuggerAgentPrivate::positionChange(qint64 scriptId, int lineNumber, in { Q_UNUSED(columnNumber); - if (state == StoppedState) - return; //no re-entrency - - // check breakpoints - if (!breakpoints.isEmpty()) { - QHash<qint64, QString>::const_iterator it = filenames.constFind(scriptId); - QScriptContext *ctx = engine()->currentContext(); - QScriptContextInfo info(ctx); - if (it == filenames.constEnd()) { - // It is possible that the scripts are loaded before the agent is attached - QString filename = info.fileName(); - - JSAgentStackData frame; - frame.functionName = info.functionName().toUtf8(); - - QPair<QString, qint32> key = qMakePair(filename, lineNumber); - it = filenames.insert(scriptId, filename); - } - - const QString filePath = it.value(); - JSAgentBreakpoints bps = fileNameToBreakpoints.values(fileName(filePath)).toSet(); - - foreach (const JSAgentBreakpointData &bp, bps) { - if (bp.lineNumber == lineNumber) { - stopped(); - return; - } - } - } - - switch (state) { - case NoState: - case StoppedState: - // Do nothing - break; - case SteppingOutState: - if (stepDepth >= 0) - break; - //fallthough - case SteppingOverState: - if (stepDepth > 0) - break; - //fallthough - case SteppingIntoState: - stopped(); - break; - } +// if (state == StoppedState) +// return; //no re-entrency + +// // check breakpoints +// if (!breakpoints.isEmpty()) { +// QHash<qint64, QString>::const_iterator it = filenames.constFind(scriptId); +// QScriptContext *ctx = engine()->currentContext(); +// QScriptContextInfo info(ctx); +// if (it == filenames.constEnd()) { +// // It is possible that the scripts are loaded before the agent is attached +// QString filename = info.fileName(); + +// JSAgentStackData frame; +// frame.functionName = info.functionName().toUtf8(); + +// QPair<QString, qint32> key = qMakePair(filename, lineNumber); +// it = filenames.insert(scriptId, filename); +// } + +// const QString filePath = it.value(); +// JSAgentBreakpoints bps = fileNameToBreakpoints.values(fileName(filePath)).toSet(); + +// foreach (const JSAgentBreakpointData &bp, bps) { +// if (bp.lineNumber == lineNumber) { +// stopped(); +// return; +// } +// } +// } + +// switch (state) { +// case NoState: +// case StoppedState: +// // Do nothing +// break; +// case SteppingOutState: +// if (stepDepth >= 0) +// break; +// //fallthough +// case SteppingOverState: +// if (stepDepth > 0) +// break; +// //fallthough +// case SteppingIntoState: +// stopped(); +// break; +// } } @@ -530,7 +528,7 @@ void QJSDebuggerAgentPrivate::positionChange(qint64 scriptId, int lineNumber, in \reimp */ void QJSDebuggerAgent::exceptionThrow(qint64 scriptId, - const QScriptValue &exception, + const QJSValue &exception, bool hasHandler) { Q_UNUSED(scriptId); @@ -546,30 +544,16 @@ void QJSDebuggerAgent::exceptionThrow(qint64 scriptId, /*! \reimp */ -void QJSDebuggerAgent::exceptionCatch(qint64 scriptId, const QScriptValue &exception) +void QJSDebuggerAgent::exceptionCatch(qint64 scriptId, const QJSValue &exception) { Q_UNUSED(scriptId); Q_UNUSED(exception); } -bool QJSDebuggerAgent::supportsExtension(Extension extension) const -{ - return extension == QScriptEngineAgent::DebuggerInvocationRequest; -} - -QVariant QJSDebuggerAgent::extension(Extension extension, const QVariant &argument) -{ - if (extension == QScriptEngineAgent::DebuggerInvocationRequest) { - d->stopped(); - return QVariant(); - } - return QScriptEngineAgent::extension(extension, argument); -} - void QJSDebuggerAgentPrivate::stopped() { bool becauseOfException = false; - const QScriptValue &exception = QScriptValue(); + const QJSValue &exception = QJSValue(); knownObjectIds.clear(); state = StoppedState; diff --git a/src/declarative/debugger/qjsdebuggeragent_p.h b/src/declarative/debugger/qjsdebuggeragent_p.h index 309588eb2f..30cbfe67b4 100644 --- a/src/declarative/debugger/qjsdebuggeragent_p.h +++ b/src/declarative/debugger/qjsdebuggeragent_p.h @@ -53,11 +53,11 @@ // We mean it. // -#include <QtScript/qscriptengineagent.h> #include <QtCore/qset.h> +#include <QtDeclarative/qjsengine.h> QT_BEGIN_NAMESPACE -class QScriptValue; +class QJSValue; class QDeclarativeEngine; QT_END_NAMESPACE @@ -136,16 +136,17 @@ inline uint qHash(const JSAgentBreakpointData &b) } -class QJSDebuggerAgent : public QObject, public QScriptEngineAgent +class QJSDebuggerAgent : public QObject { Q_OBJECT public: - QJSDebuggerAgent(QScriptEngine *engine, QObject *parent = 0); + QJSDebuggerAgent(QJSEngine *engine, QObject *parent = 0); QJSDebuggerAgent(QDeclarativeEngine *engine, QObject *parent = 0); ~QJSDebuggerAgent(); bool isInitialized() const; + QJSEngine * engine() {return 0; } void setBreakpoints(const JSAgentBreakpoints &); void setWatchExpressions(const QStringList &); @@ -175,20 +176,16 @@ public: void functionEntry(qint64 scriptId); void functionExit(qint64 scriptId, - const QScriptValue &returnValue); + const QJSValue &returnValue); void positionChange(qint64 scriptId, int lineNumber, int columnNumber); void exceptionThrow(qint64 scriptId, - const QScriptValue &exception, + const QJSValue &exception, bool hasHandler); void exceptionCatch(qint64 scriptId, - const QScriptValue &exception); - - bool supportsExtension(Extension extension) const; - QVariant extension(Extension extension, - const QVariant &argument = QVariant()); + const QJSValue &exception); Q_SIGNALS: void stopped(bool becauseOfException, diff --git a/src/declarative/declarative.pro b/src/declarative/declarative.pro index c959e4caaf..7f4255f34f 100644 --- a/src/declarative/declarative.pro +++ b/src/declarative/declarative.pro @@ -6,7 +6,8 @@ QPRO_PWD = $$PWD CONFIG += module MODULE_PRI += ../../modules/qt_declarative.pri -QT = core-private gui-private script-private network script opengl opengl-private widgets-private +QT = core-private gui-private network opengl opengl-private widgets-private + contains(QT_CONFIG, svg): QT += svg DEFINES += QT_BUILD_DECLARATIVE_LIB QT_NO_URL_CAST_FROM_STRING win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000 diff --git a/src/declarative/items/context2d/qsgcontext2d.cpp b/src/declarative/items/context2d/qsgcontext2d.cpp index 6ee87cf144..4d455419ad 100644 --- a/src/declarative/items/context2d/qsgcontext2d.cpp +++ b/src/declarative/items/context2d/qsgcontext2d.cpp @@ -3361,7 +3361,7 @@ void QSGContext2D::release() } } -void QSGContext2D::processCommands(const QScriptValue& commands) +void QSGContext2D::processCommands(const QJSValue& commands) { #ifdef QSGCANVASITEM_DEBUG QElapsedTimer t; @@ -3369,7 +3369,7 @@ void QSGContext2D::processCommands(const QScriptValue& commands) #endif int ii = 0; if (commands.isArray()) { - QScriptValue cmd = commands.property(ii); + QJSValue cmd = commands.property(ii); while(cmd.isValid()) { processCommand(cmd); ii++; @@ -3460,7 +3460,7 @@ bool QSGContext2D::event(QEvent *e) return QObject::event(e); } -void QSGContext2D::processCommand(const QScriptValue& cmd) +void QSGContext2D::processCommand(const QJSValue& cmd) { int action = cmd.property(0).toInt32(); switch (action) { diff --git a/src/declarative/items/context2d/qsgcontext2d_p.h b/src/declarative/items/context2d/qsgcontext2d_p.h index 335d954fc1..f8fc9b75a2 100644 --- a/src/declarative/items/context2d/qsgcontext2d_p.h +++ b/src/declarative/items/context2d/qsgcontext2d_p.h @@ -55,7 +55,7 @@ #include <QtCore/qmetatype.h> #include <QtCore/qcoreevent.h> #include <QtCore/qvariant.h> -#include <QtScript/qscriptvalue.h> +#include <QtDeclarative/qjsvalue.h> #include <private/qv8engine_p.h> #include <QMutex> #include <QWaitCondition> @@ -323,7 +323,7 @@ public slots: void paint(QPainter* painter); void sync(); - void processCommands(const QScriptValue& commands); + void processCommands(const QJSValue& commands); signals: void changed(); void painted(); @@ -385,7 +385,7 @@ protected: virtual bool event(QEvent *); private: - void processCommand(const QScriptValue& command); + void processCommand(const QJSValue& command); Q_DECLARE_PRIVATE(QSGContext2D) }; diff --git a/src/declarative/items/qsgitem.cpp b/src/declarative/items/qsgitem.cpp index 6769489711..a0ccf74336 100644 --- a/src/declarative/items/qsgitem.cpp +++ b/src/declarative/items/qsgitem.cpp @@ -42,7 +42,7 @@ #include "qsgitem.h" #include "qsgcanvas.h" -#include <QtScript/qscriptengine.h> +#include <QtDeclarative/qjsengine.h> #include "qsgcanvas_p.h" #include "qsgevent.h" diff --git a/src/declarative/items/qsgloader.cpp b/src/declarative/items/qsgloader.cpp index 0d1febacb4..ccf16896fb 100644 --- a/src/declarative/items/qsgloader.cpp +++ b/src/declarative/items/qsgloader.cpp @@ -165,7 +165,7 @@ void QSGLoader::setSourceComponent(QDeclarativeComponent *comp) d->component = comp; d->ownComponent = false; if (!d->component) { - emit sourceChanged(); + emit sourceComponentChanged(); emit statusChanged(); emit progressChanged(); emit itemChanged(); @@ -197,7 +197,10 @@ void QSGLoaderPrivate::load() q, SIGNAL(progressChanged())); emit q->statusChanged(); emit q->progressChanged(); - emit q->sourceChanged(); + if (ownComponent) + emit q->sourceChanged(); + else + emit q->sourceComponentChanged(); emit q->itemChanged(); } } @@ -209,7 +212,10 @@ void QSGLoaderPrivate::_q_sourceLoaded() if (component) { if (!component->errors().isEmpty()) { QDeclarativeEnginePrivate::warning(qmlEngine(q), component->errors()); - emit q->sourceChanged(); + if (ownComponent) + emit q->sourceChanged(); + else + emit q->sourceComponentChanged(); emit q->statusChanged(); emit q->progressChanged(); return; @@ -253,7 +259,10 @@ void QSGLoaderPrivate::_q_sourceLoaded() source = QUrl(); } component->completeCreate(); - emit q->sourceChanged(); + if (ownComponent) + emit q->sourceChanged(); + else + emit q->sourceComponentChanged(); emit q->statusChanged(); emit q->progressChanged(); emit q->itemChanged(); diff --git a/src/declarative/items/qsgloader_p.h b/src/declarative/items/qsgloader_p.h index b8605db567..832d3a6138 100644 --- a/src/declarative/items/qsgloader_p.h +++ b/src/declarative/items/qsgloader_p.h @@ -58,13 +58,13 @@ class Q_AUTOTEST_EXPORT QSGLoader : public QSGImplicitSizeItem Q_ENUMS(Status) Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) - Q_PROPERTY(QDeclarativeComponent *sourceComponent READ sourceComponent WRITE setSourceComponent RESET resetSourceComponent NOTIFY sourceChanged) + Q_PROPERTY(QDeclarativeComponent *sourceComponent READ sourceComponent WRITE setSourceComponent RESET resetSourceComponent NOTIFY sourceComponentChanged) Q_PROPERTY(QSGItem *item READ item NOTIFY itemChanged) Q_PROPERTY(Status status READ status NOTIFY statusChanged) Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged) public: - QSGLoader(QSGItem *parent=0); + QSGLoader(QSGItem *parent = 0); virtual ~QSGLoader(); QUrl source() const; @@ -83,6 +83,7 @@ public: Q_SIGNALS: void itemChanged(); void sourceChanged(); + void sourceComponentChanged(); void statusChanged(); void progressChanged(); void loaded(); diff --git a/src/declarative/qml/qdeclarative.h b/src/declarative/qml/qdeclarative.h index 38b2a841ba..4c962f890e 100644 --- a/src/declarative/qml/qdeclarative.h +++ b/src/declarative/qml/qdeclarative.h @@ -395,8 +395,8 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor, class QDeclarativeContext; class QDeclarativeEngine; -class QScriptValue; -class QScriptEngine; +class QJSValue; +class QJSEngine; Q_DECLARATIVE_EXPORT void qmlExecuteDeferred(QObject *); Q_DECLARATIVE_EXPORT QDeclarativeContext *qmlContext(const QObject *); Q_DECLARATIVE_EXPORT QDeclarativeEngine *qmlEngine(const QObject *); @@ -454,7 +454,7 @@ Q_DECLARATIVE_EXPORT void qmlRegisterBaseTypes(const char *uri, int versionMajor \endqml */ inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor, - QScriptValue (*callback)(QDeclarativeEngine *, QScriptEngine *)) + QJSValue (*callback)(QDeclarativeEngine *, QJSEngine *)) { QDeclarativePrivate::RegisterModuleApi api = { 0, @@ -537,7 +537,7 @@ inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMi \endqml */ inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor, - QObject *(*callback)(QDeclarativeEngine *, QScriptEngine *)) + QObject *(*callback)(QDeclarativeEngine *, QJSEngine *)) { QDeclarativePrivate::RegisterModuleApi api = { 0, diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp index 684726d346..069744153a 100644 --- a/src/declarative/qml/qdeclarativebinding.cpp +++ b/src/declarative/qml/qdeclarativebinding.cpp @@ -367,7 +367,7 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags) bool isUndefined = false; v8::HandleScope handle_scope; - v8::Context::Scope scope(ep->v8engine.context()); + v8::Context::Scope scope(ep->v8engine()->context()); v8::Local<v8::Value> result = d->v8value(0, &isUndefined); bool needsErrorData = false; diff --git a/src/declarative/qml/qdeclarativecompileddata.cpp b/src/declarative/qml/qdeclarativecompileddata.cpp index d08a808d77..da7c3fea7b 100644 --- a/src/declarative/qml/qdeclarativecompileddata.cpp +++ b/src/declarative/qml/qdeclarativecompileddata.cpp @@ -126,7 +126,6 @@ QDeclarativeCompiledData::~QDeclarativeCompiledData() if (rootPropertyCache) rootPropertyCache->release(); - qDeleteAll(cachedPrograms); qDeleteAll(cachedClosures); for (int ii = 0; ii < v8bindings.count(); ++ii) @@ -135,12 +134,9 @@ QDeclarativeCompiledData::~QDeclarativeCompiledData() void QDeclarativeCompiledData::clear() { - qDeleteAll(cachedPrograms); qDeleteAll(cachedClosures); for (int ii = 0; ii < cachedClosures.count(); ++ii) cachedClosures[ii] = 0; - for (int ii = 0; ii < cachedPrograms.count(); ++ii) - cachedPrograms[ii] = 0; } const QMetaObject *QDeclarativeCompiledData::TypeReference::metaObject() const diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index a0b1d8f176..5e1d3f60a9 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -455,7 +455,8 @@ void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop, QTime time = QDeclarativeStringConverters::timeFromString(string); instr.setType(QDeclarativeInstruction::StoreTime); instr.storeTime.propertyIndex = prop.propertyIndex(); - instr.storeTime.time = *(QDeclarativeInstruction::instr_storeTime::QTime *)&time; + Q_ASSERT(sizeof(instr.storeTime.time) == sizeof(QTime)); + ::memcpy(&instr.storeTime.time, &time, sizeof(QTime)); } break; case QVariant::DateTime: @@ -465,7 +466,8 @@ void QDeclarativeCompiler::genLiteralAssignment(const QMetaProperty &prop, instr.setType(QDeclarativeInstruction::StoreDateTime); instr.storeDateTime.propertyIndex = prop.propertyIndex(); instr.storeDateTime.date = dateTime.date().toJulianDay(); - instr.storeDateTime.time = *(QDeclarativeInstruction::instr_storeTime::QTime *)&time; + Q_ASSERT(sizeof(instr.storeDateTime.time) == sizeof(QTime)); + ::memcmp(&instr.storeDateTime.time, &time, sizeof(QTime)); } break; #endif // QT_NO_DATESTRING @@ -2369,7 +2371,7 @@ bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj) if (propName.at(0).isUpper()) COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter")); - if (enginePrivate->v8engine.illegalNames().contains(propName)) + if (enginePrivate->v8engine()->illegalNames().contains(propName)) COMPILE_EXCEPTION(&prop, tr("Illegal property name")); propNames.insert(prop.name); @@ -2382,7 +2384,7 @@ bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj) QString nameStr = QString::fromUtf8(name); if (nameStr.at(0).isUpper()) COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter")); - if (enginePrivate->v8engine.illegalNames().contains(nameStr)) + if (enginePrivate->v8engine()->illegalNames().contains(nameStr)) COMPILE_EXCEPTION(obj, tr("Illegal signal name")); methodNames.insert(name); } @@ -2393,7 +2395,7 @@ bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj) QString nameStr = QString::fromUtf8(name); if (nameStr.at(0).isUpper()) COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter")); - if (enginePrivate->v8engine.illegalNames().contains(nameStr)) + if (enginePrivate->v8engine()->illegalNames().contains(nameStr)) COMPILE_EXCEPTION(obj, tr("Illegal method name")); methodNames.insert(name); } @@ -2687,7 +2689,7 @@ bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QStr } - if (enginePrivate->v8engine.illegalNames().contains(val)) + if (enginePrivate->v8engine()->illegalNames().contains(val)) COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property")); return true; diff --git a/src/declarative/qml/qdeclarativecompiler_p.h b/src/declarative/qml/qdeclarativecompiler_p.h index a1dfabbd46..a2b959a568 100644 --- a/src/declarative/qml/qdeclarativecompiler_p.h +++ b/src/declarative/qml/qdeclarativecompiler_p.h @@ -76,7 +76,6 @@ class QDeclarativeComponent; class QDeclarativeContext; class QDeclarativeContextData; -class QScriptProgram; class Q_AUTOTEST_EXPORT QDeclarativeCompiledData : public QDeclarativeRefCount, public QDeclarativeCleanup { public: @@ -112,8 +111,7 @@ public: QList<QString> primitives; QList<QByteArray> datas; QByteArray bytecode; - QList<QScriptProgram *> cachedPrograms; - QList<QScriptValue *> cachedClosures; + QList<QJSValue *> cachedClosures; QList<QDeclarativePropertyCache *> propertyCaches; QList<QDeclarativeIntegerCache *> contextCaches; QList<QDeclarativeScriptData *> scripts; diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp index e99928d862..ca7f3e0f74 100644 --- a/src/declarative/qml/qdeclarativecomponent.cpp +++ b/src/declarative/qml/qdeclarativecomponent.cpp @@ -54,7 +54,6 @@ #include "private/qdeclarativescriptparser_p.h" #include "private/qdeclarativedebugtrace_p.h" #include "private/qdeclarativeenginedebug_p.h" -#include <QtScript/qscriptvalueiterator.h> #include <QStack> #include <QStringList> @@ -672,7 +671,7 @@ void QDeclarativeComponent::createObject(QDeclarativeV8Function *args) QDeclarativeEngine *engine = d->engine; QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); - QV8Engine *v8engine = &ep->v8engine; + QV8Engine *v8engine = ep->v8engine(); QDeclarativeContext *ctxt = creationContext(); if (!ctxt) ctxt = engine->rootContext(); @@ -748,6 +747,10 @@ void QDeclarativeComponent::createObject(QDeclarativeV8Function *args) completeCreate(); + QDeclarativeData *ddata = QDeclarativeData::get(ret); + Q_ASSERT(ddata); + ddata->setImplicitDestructible(); + RETURN(object); #undef RETURN diff --git a/src/declarative/qml/qdeclarativecomponent.h b/src/declarative/qml/qdeclarativecomponent.h index bb4d886914..a3457d1446 100644 --- a/src/declarative/qml/qdeclarativecomponent.h +++ b/src/declarative/qml/qdeclarativecomponent.h @@ -47,7 +47,7 @@ #include <QtCore/qobject.h> #include <QtCore/qstring.h> -#include <QtScript/qscriptvalue.h> +#include <QtDeclarative/qjsvalue.h> QT_BEGIN_HEADER diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp index d625a1fd98..ff6e628c66 100644 --- a/src/declarative/qml/qdeclarativecontext.cpp +++ b/src/declarative/qml/qdeclarativecontext.cpp @@ -50,12 +50,10 @@ #include "private/qdeclarativev4bindings_p.h" #include "private/qv8bindings_p.h" -#include <qscriptengine.h> +#include <qjsengine.h> #include <QtCore/qvarlengtharray.h> #include <QtCore/qdebug.h> -#include <private/qscriptdeclarativeclass_p.h> - QT_BEGIN_NAMESPACE QDeclarativeContextPrivate::QDeclarativeContextPrivate() diff --git a/src/declarative/qml/qdeclarativecontext.h b/src/declarative/qml/qdeclarativecontext.h index d8e8506dad..9c2fd01645 100644 --- a/src/declarative/qml/qdeclarativecontext.h +++ b/src/declarative/qml/qdeclarativecontext.h @@ -44,7 +44,7 @@ #include <QtCore/qurl.h> #include <QtCore/qobject.h> -#include <QtScript/qscriptvalue.h> +#include <QtDeclarative/qjsvalue.h> #include <QtCore/qmetatype.h> #include <QtCore/qvariant.h> diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h index bb9c2ada02..5f4072130a 100644 --- a/src/declarative/qml/qdeclarativecontext_p.h +++ b/src/declarative/qml/qdeclarativecontext_p.h @@ -63,7 +63,7 @@ #include "private/qdeclarativeparser_p.h" #include <QtCore/qhash.h> -#include <QtScript/qscriptvalue.h> +#include <QtDeclarative/qjsvalue.h> #include <QtCore/qset.h> #include <private/qobject_p.h> diff --git a/src/declarative/qml/qdeclarativedata_p.h b/src/declarative/qml/qdeclarativedata_p.h index 9fe5e732b7..aebea738bd 100644 --- a/src/declarative/qml/qdeclarativedata_p.h +++ b/src/declarative/qml/qdeclarativedata_p.h @@ -53,7 +53,7 @@ // We mean it. // -#include <QtScript/qscriptvalue.h> +#include <QtDeclarative/qjsvalue.h> #include <private/qobject_p.h> #include <private/qv8_p.h> diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 8fdc7b1c22..4781264bde 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -441,7 +441,7 @@ void QDeclarativeEnginePrivate::init() Q_Q(QDeclarativeEngine); qRegisterMetaType<QVariant>("QVariant"); qRegisterMetaType<QDeclarativeScriptString>("QDeclarativeScriptString"); - qRegisterMetaType<QScriptValue>("QScriptValue"); + qRegisterMetaType<QJSValue>("QJSValue"); qRegisterMetaType<QDeclarativeComponent::Status>("QDeclarativeComponent::Status"); qRegisterMetaType<QList<QObject*> >("QList<QObject*>"); qRegisterMetaType<QList<int> >("QList<int>"); @@ -449,8 +449,7 @@ void QDeclarativeEnginePrivate::init() QDeclarativeData::init(); - // Init V8 data - v8engine.init(q); + v8engine()->setEngine(q); rootContext = new QDeclarativeContext(q,true); @@ -505,7 +504,7 @@ QDeclarativeWorkerScriptEngine *QDeclarativeEnginePrivate::getWorkerScriptEngine Create a new QDeclarativeEngine with the given \a parent. */ QDeclarativeEngine::QDeclarativeEngine(QObject *parent) -: QObject(*new QDeclarativeEnginePrivate(this), parent) +: QJSEngine(*new QDeclarativeEnginePrivate(this), parent) { Q_D(QDeclarativeEngine); d->init(); @@ -1386,13 +1385,13 @@ bool QDeclarativeEngine::importPlugin(const QString &filePath, const QString &ur void QDeclarativeEngine::setOfflineStoragePath(const QString& dir) { Q_D(QDeclarativeEngine); - qt_qmlsqldatabase_setOfflineStoragePath(&d->v8engine, dir); + qt_qmlsqldatabase_setOfflineStoragePath(d->v8engine(), dir); } QString QDeclarativeEngine::offlineStoragePath() const { Q_D(const QDeclarativeEngine); - return qt_qmlsqldatabase_getOfflineStoragePath(&d->v8engine); + return qt_qmlsqldatabase_getOfflineStoragePath(d->v8engine()); } static void voidptr_destructor(void *v) diff --git a/src/declarative/qml/qdeclarativeengine.h b/src/declarative/qml/qdeclarativeengine.h index e97c2d96b0..3f90296681 100644 --- a/src/declarative/qml/qdeclarativeengine.h +++ b/src/declarative/qml/qdeclarativeengine.h @@ -45,7 +45,8 @@ #include <QtCore/qurl.h> #include <QtCore/qobject.h> #include <QtCore/qmap.h> -#include <QtScript/qscriptvalue.h> +#include <QtDeclarative/qjsengine.h> +#include <QtDeclarative/qjsvalue.h> #include <QtDeclarative/qdeclarativeerror.h> QT_BEGIN_HEADER @@ -61,12 +62,12 @@ class QDeclarativeExpression; class QDeclarativeContext; class QDeclarativeType; class QUrl; -class QScriptEngine; +class QJSEngine; class QScriptContext; class QDeclarativeImageProvider; class QNetworkAccessManager; class QDeclarativeNetworkAccessManagerFactory; -class Q_DECLARATIVE_EXPORT QDeclarativeEngine : public QObject +class Q_DECLARATIVE_EXPORT QDeclarativeEngine : public QJSEngine { Q_PROPERTY(QString offlineStoragePath READ offlineStoragePath WRITE setOfflineStoragePath) Q_OBJECT diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h index 538e8a05a0..6ff12189da 100644 --- a/src/declarative/qml/qdeclarativeengine_p.h +++ b/src/declarative/qml/qdeclarativeengine_p.h @@ -139,8 +139,7 @@ public: QDeclarativeDelayedError *erroredBindings; int inProgressCreations; - // V8 Engine - QV8Engine v8engine; + QV8Engine *v8engine() const { return q_func()->handle(); } QDeclarativeWorkerScriptEngine *getWorkerScriptEngine(); QDeclarativeWorkerScriptEngine *workerScriptEngine; @@ -256,7 +255,7 @@ public: static void warning(QDeclarativeEnginePrivate *, const QDeclarativeError &); static void warning(QDeclarativeEnginePrivate *, const QList<QDeclarativeError> &); - static QV8Engine *getV8Engine(QDeclarativeEngine *e) { return &e->d_func()->v8engine; } + static QV8Engine *getV8Engine(QDeclarativeEngine *e) { return e->d_func()->v8engine(); } static QDeclarativeEnginePrivate *get(QDeclarativeEngine *e) { return e->d_func(); } static QDeclarativeEnginePrivate *get(QDeclarativeContext *c) { return (c && c->engine()) ? QDeclarativeEnginePrivate::get(c->engine()) : 0; } static QDeclarativeEnginePrivate *get(QDeclarativeContextData *c) { return (c && c->engine) ? QDeclarativeEnginePrivate::get(c->engine) : 0; } diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp index ff19a07313..8806996bd4 100644 --- a/src/declarative/qml/qdeclarativeexpression.cpp +++ b/src/declarative/qml/qdeclarativeexpression.cpp @@ -144,11 +144,11 @@ QDeclarativeExpressionPrivate::evalFunction(QDeclarativeContextData *ctxt, QObje // XXX TODO: Implement script caching, like we used to do with QScriptProgram in the // QtScript days v8::HandleScope handle_scope; - v8::Context::Scope ctxtscope(ep->v8engine.context()); + v8::Context::Scope ctxtscope(ep->v8engine()->context()); v8::TryCatch tc; - v8::Local<v8::Object> scopeobject = ep->v8engine.qmlScope(ctxt, scope); - v8::Local<v8::Script> script = ep->v8engine.qmlModeCompile(code, filename, line); + v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope); + v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, filename, line); v8::Local<v8::Value> result = script->Run(scopeobject); if (tc.HasCaught()) return v8::Persistent<v8::Function>(); if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject); @@ -485,9 +485,9 @@ v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::F v8::Local<v8::Value> result; { v8::TryCatch try_catch; - v8::Handle<v8::Object> This = ep->v8engine.global(); + v8::Handle<v8::Object> This = ep->v8engine()->global(); if (scopeObject() && requiresThisObject()) { - v8::Handle<v8::Value> value = ep->v8engine.newQObject(scopeObject()); + v8::Handle<v8::Value> value = ep->v8engine()->newQObject(scopeObject()); if (value->IsObject()) This = v8::Handle<v8::Object>::Cast(value); } @@ -498,7 +498,7 @@ v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::F if (watcher.wasDeleted()) { } else if (try_catch.HasCaught()) { - v8::Context::Scope scope(ep->v8engine.context()); + v8::Context::Scope scope(ep->v8engine()->context()); v8::Local<v8::Message> message = try_catch.Message(); if (!message.IsEmpty()) { QDeclarativeExpressionPrivate::exceptionToError(message, error); @@ -638,9 +638,9 @@ v8::Local<v8::Value> QDeclarativeExpressionPrivate::v8value(QObject *secondarySc v8::Local<v8::Value> result; QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine); QObject *restoreSecondaryScope = 0; - restoreSecondaryScope = ep->v8engine.contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope); + restoreSecondaryScope = ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope); result = evaluate(v8function, isUndefined); - ep->v8engine.contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope); + ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope); return result; } else { return evaluate(v8function, isUndefined); @@ -663,9 +663,9 @@ QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isU { v8::HandleScope handle_scope; - v8::Context::Scope context_scope(ep->v8engine.context()); + v8::Context::Scope context_scope(ep->v8engine()->context()); v8::Local<v8::Value> result = v8value(secondaryScope, isUndefined); - rv = ep->v8engine.toVariant(result, qMetaTypeId<QList<QObject*> >()); + rv = ep->v8engine()->toVariant(result, qMetaTypeId<QList<QObject*> >()); } ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. diff --git a/src/declarative/qml/qdeclarativemetatype.cpp b/src/declarative/qml/qdeclarativemetatype.cpp index c5cc23de7c..a989ae847b 100644 --- a/src/declarative/qml/qdeclarativemetatype.cpp +++ b/src/declarative/qml/qdeclarativemetatype.cpp @@ -61,7 +61,7 @@ #include <qvector.h> #include <qlocale.h> #include <QtCore/qcryptographichash.h> -#include <QtScript/qscriptvalue.h> +#include <QtDeclarative/qjsvalue.h> #include <ctype.h> @@ -1114,7 +1114,7 @@ QT_END_NAMESPACE #include <QtGui/qquaternion.h> #include <private/qv8engine_p.h> -Q_DECLARE_METATYPE(QScriptValue); +Q_DECLARE_METATYPE(QJSValue); Q_DECLARE_METATYPE(QDeclarativeV8Handle); QT_BEGIN_NAMESPACE @@ -1195,7 +1195,7 @@ bool QDeclarativeMetaType::canCopy(int type) default: if (type == qMetaTypeId<QVariant>() || - type == qMetaTypeId<QScriptValue>() || + type == qMetaTypeId<QJSValue>() || type == qMetaTypeId<QDeclarativeV8Handle>() || typeCategory(type) != Unknown) { return true; @@ -1416,8 +1416,8 @@ bool QDeclarativeMetaType::copy(int type, void *data, const void *copy) if (type == qMetaTypeId<QVariant>()) { *static_cast<NS(QVariant) *>(data) = *static_cast<const NS(QVariant)*>(copy); return true; - } else if (type == qMetaTypeId<QScriptValue>()) { - *static_cast<NS(QScriptValue) *>(data) = *static_cast<const NS(QScriptValue)*>(copy); + } else if (type == qMetaTypeId<QJSValue>()) { + *static_cast<NS(QJSValue) *>(data) = *static_cast<const NS(QJSValue)*>(copy); return true; } else if (type == qMetaTypeId<QDeclarativeV8Handle>()) { *static_cast<NS(QDeclarativeV8Handle) *>(data) = *static_cast<const NS(QDeclarativeV8Handle)*>(copy); @@ -1626,8 +1626,8 @@ bool QDeclarativeMetaType::copy(int type, void *data, const void *copy) if (type == qMetaTypeId<QVariant>()) { *static_cast<NS(QVariant) *>(data) = NS(QVariant)(); return true; - } else if (type == qMetaTypeId<QScriptValue>()) { - *static_cast<NS(QScriptValue) *>(data) = NS(QScriptValue)(); + } else if (type == qMetaTypeId<QJSValue>()) { + *static_cast<NS(QJSValue) *>(data) = NS(QJSValue)(); return true; } else if (type == qMetaTypeId<QDeclarativeV8Handle>()) { *static_cast<NS(QDeclarativeV8Handle) *>(data) = NS(QDeclarativeV8Handle)(); diff --git a/src/declarative/qml/qdeclarativemetatype_p.h b/src/declarative/qml/qdeclarativemetatype_p.h index cfc4f077f8..429aa7a98f 100644 --- a/src/declarative/qml/qdeclarativemetatype_p.h +++ b/src/declarative/qml/qdeclarativemetatype_p.h @@ -59,7 +59,7 @@ #include <QtCore/qvariant.h> #include <QtCore/qbitarray.h> #include <private/qdeclarativeglobal_p.h> -#include <QtScript/qscriptvalue.h> +#include <QtDeclarative/qjsvalue.h> QT_BEGIN_NAMESPACE @@ -113,9 +113,9 @@ public: ModuleApiInstance() : scriptCallback(0), qobjectCallback(0), qobjectApi(0) {} - QScriptValue (*scriptCallback)(QDeclarativeEngine *, QScriptEngine *); - QObject *(*qobjectCallback)(QDeclarativeEngine *, QScriptEngine *); - QScriptValue scriptApi; + QJSValue (*scriptCallback)(QDeclarativeEngine *, QJSEngine *); + QObject *(*qobjectCallback)(QDeclarativeEngine *, QJSEngine *); + QJSValue scriptApi; QObject *qobjectApi; }; struct ModuleApi { @@ -123,8 +123,8 @@ public: inline bool operator==(const ModuleApi &) const; int major; int minor; - QScriptValue (*script)(QDeclarativeEngine *, QScriptEngine *); - QObject *(*qobject)(QDeclarativeEngine *, QScriptEngine *); + QJSValue (*script)(QDeclarativeEngine *, QJSEngine *); + QObject *(*qobject)(QDeclarativeEngine *, QJSEngine *); }; static ModuleApi moduleApi(const QByteArray &, int, int); }; diff --git a/src/declarative/qml/qdeclarativeprivate.h b/src/declarative/qml/qdeclarativeprivate.h index 9eacc1d1cb..e8e8f229cf 100644 --- a/src/declarative/qml/qdeclarativeprivate.h +++ b/src/declarative/qml/qdeclarativeprivate.h @@ -74,8 +74,8 @@ public: }; -class QScriptValue; -class QScriptEngine; +class QJSValue; +class QJSEngine; class QDeclarativeEngine; class QDeclarativeCustomParser; namespace QDeclarativePrivate @@ -243,8 +243,8 @@ namespace QDeclarativePrivate int versionMajor; int versionMinor; - QScriptValue (*scriptApi)(QDeclarativeEngine *, QScriptEngine *); - QObject *(*qobjectApi)(QDeclarativeEngine *, QScriptEngine *); + QJSValue (*scriptApi)(QDeclarativeEngine *, QJSEngine *); + QObject *(*qobjectApi)(QDeclarativeEngine *, QJSEngine *); }; enum RegistrationType { diff --git a/src/declarative/qml/qdeclarativepropertycache.cpp b/src/declarative/qml/qdeclarativepropertycache.cpp index 6ff47d7b57..d2148ad874 100644 --- a/src/declarative/qml/qdeclarativepropertycache.cpp +++ b/src/declarative/qml/qdeclarativepropertycache.cpp @@ -49,7 +49,7 @@ #include <QtCore/qdebug.h> -Q_DECLARE_METATYPE(QScriptValue) +Q_DECLARE_METATYPE(QJSValue) Q_DECLARE_METATYPE(QDeclarativeV8Handle); QT_BEGIN_NAMESPACE @@ -83,8 +83,8 @@ static QDeclarativePropertyCache::Data::Flags flagsForPropertyType(int propType, if (propType < QMetaType::User && propType != QMetaType::QObjectStar && propType != QMetaType::QWidgetStar) { } else if (propType == qMetaTypeId<QDeclarativeBinding *>()) { flags |= QDeclarativePropertyCache::Data::IsQmlBinding; - } else if (propType == qMetaTypeId<QScriptValue>()) { - flags |= QDeclarativePropertyCache::Data::IsQScriptValue; + } else if (propType == qMetaTypeId<QJSValue>()) { + flags |= QDeclarativePropertyCache::Data::IsQJSValue; } else if (propType == qMetaTypeId<QDeclarativeV8Handle>()) { flags |= QDeclarativePropertyCache::Data::IsV8Handle; } else { @@ -518,7 +518,7 @@ QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj, rv = cache->property(name); } else { QString strname = QV8Engine::toStringStatic(name.string()); - // QString strname = ep->v8engine.toString(name); + // QString strname = ep->v8engine()->toString(name); local = QDeclarativePropertyCache::create(obj->metaObject(), strname); if (local.isValid()) rv = &local; diff --git a/src/declarative/qml/qdeclarativepropertycache_p.h b/src/declarative/qml/qdeclarativepropertycache_p.h index 621463dad9..cdbd49388f 100644 --- a/src/declarative/qml/qdeclarativepropertycache_p.h +++ b/src/declarative/qml/qdeclarativepropertycache_p.h @@ -60,7 +60,6 @@ #include "private/qhashedstring_p.h" #include <QtCore/qvector.h> -#include <QtScript/private/qscriptdeclarativeclass_p.h> QT_BEGIN_NAMESPACE class QDeclarativeEngine; @@ -96,7 +95,7 @@ public: IsEnumType = 0x00000100, // Property type is an enum IsQList = 0x00000200, // Property type is a QML list IsQmlBinding = 0x00000400, // Property type is a QDeclarativeBinding* - IsQScriptValue = 0x00000800, // Property type is a QScriptValue + IsQJSValue = 0x00000800, // Property type is a QScriptValue IsV8Handle = 0x00001000, // Property type is a QDeclarativeV8Handle // Apply only to IsFunctions @@ -127,7 +126,7 @@ public: bool isEnum() const { return flags & IsEnumType; } bool isQList() const { return flags & IsQList; } bool isQmlBinding() const { return flags & IsQmlBinding; } - bool isQScriptValue() const { return flags & IsQScriptValue; } + bool isQJSValue() const { return flags & IsQJSValue; } bool isV8Handle() const { return flags & IsV8Handle; } bool isVMEFunction() const { return flags & IsVMEFunction; } bool hasArguments() const { return flags & HasArguments; } diff --git a/src/declarative/qml/qdeclarativesqldatabase_p.h b/src/declarative/qml/qdeclarativesqldatabase_p.h index 337f717b1e..ef88b2e4f5 100644 --- a/src/declarative/qml/qdeclarativesqldatabase_p.h +++ b/src/declarative/qml/qdeclarativesqldatabase_p.h @@ -42,7 +42,7 @@ #ifndef QDECLARATIVESQLDATABASE_P_H #define QDECLARATIVESQLDATABASE_P_H -#include <QtScript/qscriptengine.h> +#include <QtDeclarative/qjsengine.h> // // W A R N I N G // ------------- diff --git a/src/declarative/qml/qdeclarativetypeloader.cpp b/src/declarative/qml/qdeclarativetypeloader.cpp index cb3e8aef3e..97c5b38c20 100644 --- a/src/declarative/qml/qdeclarativetypeloader.cpp +++ b/src/declarative/qml/qdeclarativetypeloader.cpp @@ -1230,7 +1230,7 @@ void QDeclarativeScriptBlob::done() m_scriptData->pragmas = m_pragmas; // XXX TODO: Handle errors that occur duing the script compile - QV8Engine *v8engine = &QDeclarativeEnginePrivate::get(engine)->v8engine; + QV8Engine *v8engine = QDeclarativeEnginePrivate::get(engine)->v8engine(); v8::HandleScope handle_scope; v8::Context::Scope scope(v8engine->context()); v8::Local<v8::Script> program = v8engine->qmlModeCompile(m_source, finalUrl().toString(), 1); diff --git a/src/declarative/qml/qdeclarativetypeloader_p.h b/src/declarative/qml/qdeclarativetypeloader_p.h index 20e16750cf..1ca6f8c9c2 100644 --- a/src/declarative/qml/qdeclarativetypeloader_p.h +++ b/src/declarative/qml/qdeclarativetypeloader_p.h @@ -55,8 +55,7 @@ #include <QtCore/qobject.h> #include <QtNetwork/qnetworkreply.h> -#include <QtScript/qscriptvalue.h> -#include <QtScript/qscriptprogram.h> +#include <QtDeclarative/qjsvalue.h> #include <QtDeclarative/qdeclarativeerror.h> #include <QtDeclarative/qdeclarativeengine.h> #include <private/qdeclarativecleanup_p.h> diff --git a/src/declarative/qml/qdeclarativetypenamecache_p.h b/src/declarative/qml/qdeclarativetypenamecache_p.h index abf18ce384..e89747b15a 100644 --- a/src/declarative/qml/qdeclarativetypenamecache_p.h +++ b/src/declarative/qml/qdeclarativetypenamecache_p.h @@ -57,8 +57,6 @@ #include "private/qdeclarativecleanup_p.h" #include "private/qdeclarativemetatype_p.h" -#include <private/qscriptdeclarativeclass_p.h> - #include <private/qhashedstring_p.h> QT_BEGIN_NAMESPACE diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp index 96b71acf76..45e4745c1a 100644 --- a/src/declarative/qml/qdeclarativevme.cpp +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -73,10 +73,32 @@ #include <QtCore/qvarlengtharray.h> #include <QtCore/qcoreapplication.h> #include <QtCore/qdatetime.h> -#include <QtScript/qscriptvalue.h> +#include <QtCore/qvarlengtharray.h> +#include <QtDeclarative/qjsvalue.h> QT_BEGIN_NAMESPACE +// A simple stack wrapper around QVarLengthArray +template<typename T> +class QDeclarativeVMEStack : private QVarLengthArray<T, 128> +{ +private: + typedef QVarLengthArray<T, 128> VLA; + int _index; + +public: + inline QDeclarativeVMEStack(); + inline bool isEmpty() const; + inline const T &top() const; + inline void push(const T &o); + inline T pop(); + inline int count() const; + inline const T &at(int index) const; +}; + +// We do this so we can forward declare the type in the qdeclarativevme_p.h header +class QDeclarativeVMEObjectStack : public QDeclarativeVMEStack<QObject *> {}; + QDeclarativeVME::QDeclarativeVME() { } @@ -102,10 +124,12 @@ struct ListInstance QDeclarativeListProperty<void> qListProperty; }; +Q_DECLARE_TYPEINFO(ListInstance, Q_PRIMITIVE_TYPE | Q_MOVABLE_TYPE); + QObject *QDeclarativeVME::run(QDeclarativeContextData *ctxt, QDeclarativeCompiledData *comp, int start, const QBitField &bindingSkipList) { - QDeclarativeVMEStack<QObject *> stack; + QDeclarativeVMEObjectStack stack; if (start == -1) start = 0; @@ -122,7 +146,7 @@ void QDeclarativeVME::runDeferred(QObject *object) QDeclarativeContextData *ctxt = data->context; QDeclarativeCompiledData *comp = data->deferredComponent; int start = data->deferredIdx; - QDeclarativeVMEStack<QObject *> stack; + QDeclarativeVMEObjectStack stack; stack.push(object); run(stack, ctxt, comp, start, QBitField()); @@ -152,7 +176,7 @@ static void removeBindingOnProperty(QObject *o, int index) #define CLEAN_PROPERTY(o, index) if (fastHasBinding(o, index)) removeBindingOnProperty(o, index) -QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, +QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack, QDeclarativeContextData *ctxt, QDeclarativeCompiledData *comp, int start, const QBitField &bindingSkipList) @@ -1001,7 +1025,7 @@ v8::Persistent<v8::Object> QDeclarativeVME::run(QDeclarativeContextData *parentC return qPersistentNew<v8::Object>(script->m_value); QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(parentCtxt->engine); - QV8Engine *v8engine = &ep->v8engine; + QV8Engine *v8engine = ep->v8engine(); bool shared = script->pragmas & QDeclarativeParser::Object::ScriptBlock::Shared; @@ -1069,4 +1093,48 @@ v8::Persistent<v8::Object> QDeclarativeVME::run(QDeclarativeContextData *parentC return rv; } +template<typename T> +QDeclarativeVMEStack<T>::QDeclarativeVMEStack() +: _index(-1) +{ +} + +template<typename T> +bool QDeclarativeVMEStack<T>::isEmpty() const { + return _index == -1; +} + +template<typename T> +const T &QDeclarativeVMEStack<T>::top() const { + return at(_index); +} + +template<typename T> +void QDeclarativeVMEStack<T>::push(const T &o) { + _index++; + + Q_ASSERT(_index <= VLA::size()); + if (_index == VLA::size()) + append(o); + else + VLA::data()[_index] = o; +} + +template<typename T> +T QDeclarativeVMEStack<T>::pop() { + Q_ASSERT(_index >= 0); + --_index; + return VLA::data()[_index + 1]; +} + +template<typename T> +int QDeclarativeVMEStack<T>::count() const { + return _index + 1; +} + +template<typename T> +const T &QDeclarativeVMEStack<T>::at(int index) const { + return VLA::data()[index]; +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativevme_p.h b/src/declarative/qml/qdeclarativevme_p.h index dd23f1c62f..d0c98d448e 100644 --- a/src/declarative/qml/qdeclarativevme_p.h +++ b/src/declarative/qml/qdeclarativevme_p.h @@ -64,39 +64,12 @@ QT_BEGIN_NAMESPACE class QObject; -class QScriptValue; +class QJSValue; class QDeclarativeScriptData; class QDeclarativeCompiledData; class QDeclarativeCompiledData; class QDeclarativeContextData; - -template<typename T, int N = 128> -class QDeclarativeVMEStack { -public: - QDeclarativeVMEStack() : index(-1), maxSize(N), data((T *)fixedData) {} - ~QDeclarativeVMEStack() { if (data != (T *)fixedData) qFree(data); } - - bool isEmpty() const { return index == -1; } - const T &top() const { return data[index]; } - void push(const T &i) { ++index; if (index == maxSize) realloc(); data[index] = i; } - const T &pop() { --index; return data[index + 1]; } - int count() const { return index + 1; } - const T &at(int idx) { return data[idx]; } - -private: - void realloc() { - maxSize += N; - if (data != (T *)fixedData) { - data = (T*)qRealloc(data, maxSize * sizeof(T)); - } else { - data = (T*)qMalloc(maxSize * sizeof(T)); - } - } - int index; - int maxSize; - T *data; - char fixedData[N * sizeof(T)]; -}; +class QDeclarativeVMEObjectStack; class QDeclarativeVME { @@ -114,7 +87,7 @@ public: private: v8::Persistent<v8::Object> run(QDeclarativeContextData *, QDeclarativeScriptData *); - QObject *run(QDeclarativeVMEStack<QObject *> &, + QObject *run(QDeclarativeVMEObjectStack &, QDeclarativeContextData *, QDeclarativeCompiledData *, int start, const QBitField &); QList<QDeclarativeError> vmeErrors; diff --git a/src/declarative/qml/qdeclarativevmemetaobject.cpp b/src/declarative/qml/qdeclarativevmemetaobject.cpp index 247c1aa533..746c9f650b 100644 --- a/src/declarative/qml/qdeclarativevmemetaobject.cpp +++ b/src/declarative/qml/qdeclarativevmemetaobject.cpp @@ -48,7 +48,7 @@ #include "private/qdeclarativecontext_p.h" #include "private/qdeclarativebinding_p.h" -Q_DECLARE_METATYPE(QScriptValue); +Q_DECLARE_METATYPE(QJSValue); QT_BEGIN_NAMESPACE @@ -73,7 +73,7 @@ public: inline const QTime &asQTime(); inline const QDate &asQDate(); inline const QDateTime &asQDateTime(); - inline const QScriptValue &asQScriptValue(); + inline const QJSValue &asQJSValue(); inline void setValue(QObject *); inline void setValue(const QVariant &); @@ -86,7 +86,7 @@ public: inline void setValue(const QTime &); inline void setValue(const QDate &); inline void setValue(const QDateTime &); - inline void setValue(const QScriptValue &); + inline void setValue(const QJSValue &); private: int type; void *data[4]; // Large enough to hold all types @@ -135,8 +135,8 @@ void QDeclarativeVMEVariant::cleanup() } else if (type == qMetaTypeId<QVariant>()) { ((QVariant *)dataPtr())->~QVariant(); type = QVariant::Invalid; - } else if (type == qMetaTypeId<QScriptValue>()) { - ((QScriptValue *)dataPtr())->~QScriptValue(); + } else if (type == qMetaTypeId<QJSValue>()) { + ((QJSValue *)dataPtr())->~QJSValue(); type = QVariant::Invalid; } @@ -245,12 +245,12 @@ const QDateTime &QDeclarativeVMEVariant::asQDateTime() return *(QDateTime *)(dataPtr()); } -const QScriptValue &QDeclarativeVMEVariant::asQScriptValue() +const QJSValue &QDeclarativeVMEVariant::asQJSValue() { - if (type != qMetaTypeId<QScriptValue>()) - setValue(QScriptValue()); + if (type != qMetaTypeId<QJSValue>()) + setValue(QJSValue()); - return *(QScriptValue *)(dataPtr()); + return *(QJSValue *)(dataPtr()); } void QDeclarativeVMEVariant::setValue(QObject *v) @@ -367,14 +367,14 @@ void QDeclarativeVMEVariant::setValue(const QDateTime &v) } } -void QDeclarativeVMEVariant::setValue(const QScriptValue &v) +void QDeclarativeVMEVariant::setValue(const QJSValue &v) { - if (type != qMetaTypeId<QScriptValue>()) { + if (type != qMetaTypeId<QJSValue>()) { cleanup(); - type = qMetaTypeId<QScriptValue>(); - new (dataPtr()) QScriptValue(v); + type = qMetaTypeId<QJSValue>(); + new (dataPtr()) QJSValue(v); } else { - *(QScriptValue *)(dataPtr()) = v; + *(QJSValue *)(dataPtr()) = v; } } @@ -656,18 +656,18 @@ int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + id; v8::HandleScope handle_scope; - v8::Context::Scope scope(ep->v8engine.context()); + v8::Context::Scope scope(ep->v8engine()->context()); v8::Handle<v8::Value> *args = 0; if (data->parameterCount) { args = new v8::Handle<v8::Value>[data->parameterCount]; for (int ii = 0; ii < data->parameterCount; ++ii) - args[ii] = ep->v8engine.fromVariant(*(QVariant *)a[ii + 1]); + args[ii] = ep->v8engine()->fromVariant(*(QVariant *)a[ii + 1]); } v8::TryCatch try_catch; - v8::Local<v8::Value> result = function->Call(ep->v8engine.global(), data->parameterCount, args); + v8::Local<v8::Value> result = function->Call(ep->v8engine()->global(), data->parameterCount, args); QVariant rv; if (try_catch.HasCaught()) { @@ -677,7 +677,7 @@ int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) ep->warning(error); if (a[0]) *(QVariant *)a[0] = QVariant(); } else { - if (a[0]) *(QVariant *)a[0] = ep->v8engine.toVariant(result, 0); + if (a[0]) *(QVariant *)a[0] = ep->v8engine()->toVariant(result, 0); } ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. @@ -720,7 +720,7 @@ v8::Handle<v8::Function> QDeclarativeVMEMetaObject::method(int index) QScriptValue QDeclarativeVMEMetaObject::readVarProperty(int id) { if (data[id].dataType() == qMetaTypeId<QScriptValue>()) - return data[id].asQScriptValue(); + return data[id].asQJSValue(); else if (data[id].dataType() == QMetaType::QObjectStar) return QDeclarativeEnginePrivate::get(ctxt->engine)->objectClass->newQObject(data[id].asQObject()); else @@ -732,7 +732,7 @@ QVariant QDeclarativeVMEMetaObject::readVarPropertyAsVariant(int id) { #if 0 if (data[id].dataType() == qMetaTypeId<QScriptValue>()) - return QDeclarativeEnginePrivate::get(ctxt->engine)->scriptValueToVariant(data[id].asQScriptValue()); + return QDeclarativeEnginePrivate::get(ctxt->engine)->scriptValueToVariant(data[id].asQJSValue()); else #endif if (data[id].dataType() == QMetaType::QObjectStar) diff --git a/src/declarative/qml/qdeclarativeworkerscript.cpp b/src/declarative/qml/qdeclarativeworkerscript.cpp index b519573ccf..fc9bb887e8 100644 --- a/src/declarative/qml/qdeclarativeworkerscript.cpp +++ b/src/declarative/qml/qdeclarativeworkerscript.cpp @@ -48,10 +48,9 @@ #include <QtCore/qcoreevent.h> #include <QtCore/qcoreapplication.h> #include <QtCore/qdebug.h> -#include <QtScript/qscriptengine.h> +#include <QtDeclarative/qjsengine.h> #include <QtCore/qmutex.h> #include <QtCore/qwaitcondition.h> -#include <QtScript/qscriptvalueiterator.h> #include <QtCore/qfile.h> #include <QtCore/qdatetime.h> #include <QtNetwork/qnetworkaccessmanager.h> @@ -190,7 +189,7 @@ private: }; QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QDeclarativeWorkerScriptEnginePrivate *parent) -: p(parent), accessManager(0) +: QV8Engine(0), p(parent), accessManager(0) { } @@ -203,8 +202,7 @@ QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::~WorkerEngine() void QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::init() { - QV8Engine::init(0); - + initDeclarativeGlobalObject(); #define CALL_ONMESSAGE_SCRIPT \ "(function(object, message) { "\ "var isfunction = false; "\ @@ -705,7 +703,7 @@ bool QDeclarativeWorkerScript::event(QEvent *event) QDeclarativeEngine *engine = qmlEngine(this); if (engine) { WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event); - QV8Engine *v8engine = &QDeclarativeEnginePrivate::get(engine)->v8engine; + QV8Engine *v8engine = QDeclarativeEnginePrivate::get(engine)->v8engine(); v8::HandleScope handle_scope; v8::Context::Scope scope(v8engine->context()); v8::Handle<v8::Value> value = QV8Worker::deserialize(workerEvent->data(), v8engine); diff --git a/src/declarative/qml/qdeclarativeworkerscript_p.h b/src/declarative/qml/qdeclarativeworkerscript_p.h index 85910b16e9..d953b0ff18 100644 --- a/src/declarative/qml/qdeclarativeworkerscript_p.h +++ b/src/declarative/qml/qdeclarativeworkerscript_p.h @@ -57,7 +57,7 @@ #include "qdeclarativeparserstatus.h" #include <QtCore/qthread.h> -#include <QtScript/qscriptvalue.h> +#include <QtDeclarative/qjsvalue.h> #include <QtCore/qurl.h> QT_BEGIN_HEADER diff --git a/src/declarative/qml/qdeclarativexmlhttprequest.cpp b/src/declarative/qml/qdeclarativexmlhttprequest.cpp index 194a60f2d3..abcc283610 100644 --- a/src/declarative/qml/qdeclarativexmlhttprequest.cpp +++ b/src/declarative/qml/qdeclarativexmlhttprequest.cpp @@ -51,9 +51,8 @@ #include "qdeclarativeglobal_p.h" #include <QtCore/qobject.h> -#include <QtScript/qscriptvalue.h> -#include <QtScript/qscriptcontext.h> -#include <QtScript/qscriptengine.h> +#include <QtDeclarative/qjsvalue.h> +#include <QtDeclarative/qjsengine.h> #include <QtNetwork/qnetworkreply.h> #include <QtCore/qtextcodec.h> #include <QtCore/qxmlstream.h> diff --git a/src/declarative/qml/qdeclarativexmlhttprequest_p.h b/src/declarative/qml/qdeclarativexmlhttprequest_p.h index a2082db59f..c5c53a6ce1 100644 --- a/src/declarative/qml/qdeclarativexmlhttprequest_p.h +++ b/src/declarative/qml/qdeclarativexmlhttprequest_p.h @@ -42,7 +42,7 @@ #ifndef QDECLARATIVEXMLHTTPREQUEST_P_H #define QDECLARATIVEXMLHTTPREQUEST_P_H -#include <QtScript/qscriptengine.h> +#include <QtDeclarative/qjsengine.h> // // W A R N I N G // ------------- diff --git a/src/declarative/qml/v4/qdeclarativev4bindings.cpp b/src/declarative/qml/v4/qdeclarativev4bindings.cpp index 9209e93e4f..d93d930034 100644 --- a/src/declarative/qml/v4/qdeclarativev4bindings.cpp +++ b/src/declarative/qml/v4/qdeclarativev4bindings.cpp @@ -67,20 +67,20 @@ struct Register { void setNaN() { setqreal(qSNaN()); } bool isUndefined() const { return dataType == UndefinedType; } - void setQObject(QObject *o) { *((QObject **)data) = o; dataType = QObjectStarType; } - QObject *getQObject() const { return *((QObject **)data); } + void setQObject(QObject *o) { qobjectValue = o; dataType = QObjectStarType; } + QObject *getQObject() const { return qobjectValue; } - void setqreal(qreal v) { *((qreal *)data) = v; dataType = QRealType; } - qreal getqreal() const { return *((qreal *)data); } - qreal &getqrealref() const { return *((qreal *)data); } + void setqreal(qreal v) { qrealValue = v; dataType = QRealType; } + qreal getqreal() const { return qrealValue; } + qreal &getqrealref() { return qrealValue; } - void setint(int v) { *((int *)data) = v; dataType = IntType; } - int getint() const { return *((int *)data); } - int &getintref() const { return *((int *)data); } + void setint(int v) { intValue = v; dataType = IntType; } + int getint() const { return intValue; } + int &getintref() { return intValue; } - void setbool(bool v) { *((bool *)data) = v; dataType = BoolType; } - bool getbool() const { return *((bool *)data); } - bool &getboolref() const { return *((bool *)data); } + void setbool(bool v) { boolValue = v; dataType = BoolType; } + bool getbool() const { return boolValue; } + bool &getboolref() { return boolValue; } QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); } QString *getstringptr() { return (QString *)typeDataPtr(); } @@ -97,10 +97,16 @@ struct Register { Type gettype() const { return dataType; } void settype(Type t) { dataType = t; } - // int type; // Optional type - Type dataType; // Type of data - void *data[2]; // Object stored here + union { + QObject *qobjectValue; + qreal qrealValue; + int intValue; + bool boolValue; + void *data[sizeof(QVariant)]; + qint64 q_for_alignment_1; + double q_for_alignment_2; + }; inline void cleanup(); inline void cleanupString(); @@ -211,7 +217,6 @@ public: typedef QDeclarativeNotifierEndpoint Subscription; Subscription *subscriptions; - QScriptDeclarativeClass::PersistentIdentifier *identifiers; void run(Binding *, QDeclarativePropertyPrivate::WriteFlags flags); @@ -234,20 +239,19 @@ public: inline void subscribeId(QDeclarativeContextData *p, int idIndex, int subIndex); inline void subscribe(QObject *o, int notifyIndex, int subIndex); - inline static qint32 toInt32(qsreal n); - static const qsreal D32; - static quint32 toUint32(qsreal n); + inline static qint32 toInt32(qreal n); + static const qreal D32; + static quint32 toUint32(qreal n); }; QDeclarativeV4BindingsPrivate::QDeclarativeV4BindingsPrivate() -: subscriptions(0), identifiers(0), program(0), bindings(0) +: subscriptions(0), program(0), bindings(0) { } QDeclarativeV4BindingsPrivate::~QDeclarativeV4BindingsPrivate() { delete [] subscriptions; subscriptions = 0; - delete [] identifiers; identifiers = 0; } int QDeclarativeV4BindingsPrivate::methodCount = -1; @@ -498,24 +502,10 @@ inline static QUrl toUrl(Register *reg, int type, QDeclarativeContextData *conte return base; } -static QObject *variantToQObject(const QVariant &value, bool *ok) -{ - if (ok) *ok = true; - - if (value.userType() == QMetaType::QObjectStar) { - return qvariant_cast<QObject*>(value); - } else { - if (ok) *ok = false; - return 0; - } -} - void QDeclarativeV4BindingsPrivate::init() { if (program->subscriptions) subscriptions = new QDeclarativeV4BindingsPrivate::Subscription[program->subscriptions]; - if (program->identifiers) - identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers]; bindings = new QDeclarativeV4BindingsPrivate::Binding[program->bindings]; } @@ -685,15 +675,15 @@ static void throwException(int id, QDeclarativeDelayedError *error, QDeclarativeEnginePrivate::warning(context->engine, error->error); } -const qsreal QDeclarativeV4BindingsPrivate::D32 = 4294967296.0; +const qreal QDeclarativeV4BindingsPrivate::D32 = 4294967296.0; -qint32 QDeclarativeV4BindingsPrivate::toInt32(qsreal n) +qint32 QDeclarativeV4BindingsPrivate::toInt32(qreal n) { if (qIsNaN(n) || qIsInf(n) || (n == 0)) return 0; double sign = (n < 0) ? -1.0 : 1.0; - qsreal abs_n = fabs(n); + qreal abs_n = fabs(n); n = ::fmod(sign * ::floor(abs_n), D32); const double D31 = D32 / 2.0; @@ -707,13 +697,13 @@ qint32 QDeclarativeV4BindingsPrivate::toInt32(qsreal n) return qint32 (n); } -inline quint32 QDeclarativeV4BindingsPrivate::toUint32(qsreal n) +inline quint32 QDeclarativeV4BindingsPrivate::toUint32(qreal n) { if (qIsNaN(n) || qIsInf(n) || (n == 0)) return 0; double sign = (n < 0) ? -1.0 : 1.0; - qsreal abs_n = fabs(n); + qreal abs_n = fabs(n); n = ::fmod(sign * ::floor(abs_n), D32); @@ -1021,7 +1011,7 @@ void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks, } else { // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine. // Ideally we should just call the methods in the QScript namespace directly. - QScriptValue tmp(*src.getstringptr()); + QJSValue tmp(*src.getstringptr()); if (instr->unaryop.src == instr->unaryop.output) { output.cleanupString(); MARK_CLEAN_REGISTER(instr->unaryop.output); @@ -1041,7 +1031,7 @@ void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks, } else { // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine. // Ideally we should just call the methods in the QScript namespace directly. - QScriptValue tmp(*src.getstringptr()); + QJSValue tmp(*src.getstringptr()); if (instr->unaryop.src == instr->unaryop.output) { output.cleanupString(); MARK_CLEAN_REGISTER(instr->unaryop.output); @@ -1061,7 +1051,7 @@ void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks, } else { // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine. // Ideally we should just call the methods in the QScript namespace directly. - QScriptValue tmp(*src.getstringptr()); + QJSValue tmp(*src.getstringptr()); if (instr->unaryop.src == instr->unaryop.output) { output.cleanupString(); MARK_CLEAN_REGISTER(instr->unaryop.output); @@ -1109,7 +1099,7 @@ void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks, QML_V4_BEGIN_INSTR(MathPIReal, unaryop) { - static const qsreal qmlPI = 2.0 * qAsin(1.0); + static const qreal qmlPI = 2.0 * qAsin(1.0); Register &output = registers[instr->unaryop.output]; output.setqreal(qmlPI); } @@ -1486,16 +1476,16 @@ void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks, executedBlocks |= instr->blockop.block; QML_V4_END_INSTR(Block, blockop) + // XXX not applicable in v8 QML_V4_BEGIN_INSTR(InitString, initstring) - if (!identifiers[instr->initstring.offset].identifier) { - quint32 len = *(quint32 *)(data + instr->initstring.dataIdx); - QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32)); +// if (!identifiers[instr->initstring.offset].identifier) { +// quint32 len = *(quint32 *)(data + instr->initstring.dataIdx); +// QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32)); - QString str = QString::fromRawData(strdata, len); +// QString str = QString::fromRawData(strdata, len); - // XXX not applicable in v8 - // identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str); - } +// // identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str); +// } QML_V4_END_INSTR(InitString, initstring) QML_V4_BEGIN_INSTR(CleanupRegister, cleanup) diff --git a/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp b/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp index 34a59caf1a..bddfca18b4 100644 --- a/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp +++ b/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp @@ -436,7 +436,7 @@ bool QDeclarativeV4IRBuilder::visit(AST::IdentifierExpression *ast) if (name.at(0) == QLatin1Char('u') && name.length() == 9 && name == QLatin1String("undefined")) { _expr.code = _block->CONST(IR::UndefinedType, 0); // ### undefined value - } else if(m_engine->v8engine.illegalNames().contains(name) ) { + } else if (m_engine->v8engine()->illegalNames().contains(name) ) { if (qmlVerboseCompiler()) qWarning() << "*** illegal symbol:" << name; return false; } else if (const QDeclarativeParser::Object *obj = m_expression->ids.value(name)) { diff --git a/src/declarative/qml/v8/qjsconverter_p.h b/src/declarative/qml/v8/qjsconverter_p.h new file mode 100644 index 0000000000..4aec472c7a --- /dev/null +++ b/src/declarative/qml/v8/qjsconverter_p.h @@ -0,0 +1,272 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-ONLY$ +** GNU Lesser General Public License Usage +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QJSCONVERTER_P_H +#define QJSCONVERTER_P_H + +#include "qjsvalue.h" +#include <QtCore/qglobal.h> +#include <QtCore/qnumeric.h> +#include <QtCore/qstring.h> +#include <QtCore/qvarlengtharray.h> +#include <QtCore/qregexp.h> +#include <QtCore/qdatetime.h> + +#include <private/qv8_p.h> + +QT_BEGIN_NAMESPACE + +extern char *qdtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **digits_str); +Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax); + +/* + \internal + \class QJSConverter + QJSValue and QJSEngine helper class. This class's responsibility is to convert values + between JS values and Qt/C++ values. + + This is a nice way to inline these functions in both QJSValue and QJSEngine. +*/ +class QJSConverter { +public: + static quint32 toArrayIndex(const QString& string) + { + // FIXME this function should be exported by JSC C API. + bool ok; + quint32 idx = string.toUInt(&ok); + if (!ok || toString(idx) != string) + idx = 0xffffffff; + + return idx; + } + + static QString toString(v8::Handle<v8::String> jsString) + { + if (jsString.IsEmpty()) + return QString(); + QString qstr; + qstr.resize(jsString->Length()); + jsString->Write(reinterpret_cast<uint16_t*>(qstr.data())); + return qstr; + } + + static v8::Handle<v8::String> toString(const QString& string) + { + return v8::String::New(reinterpret_cast<const uint16_t*>(string.data()), string.size()); + } + + static QString toString(double value) + { + // FIXME this should be easier. The ideal fix is to create + // a new function in V8 API which could cover the functionality. + + if (qIsNaN(value)) + return QString::fromLatin1("NaN"); + if (qIsInf(value)) + return QString::fromLatin1(value < 0 ? "-Infinity" : "Infinity"); + if (!value) + return QString::fromLatin1("0"); + + QVarLengthArray<char, 25> buf; + int decpt; + int sign; + char* result = 0; + char* endresult; + (void)qdtoa(value, 0, 0, &decpt, &sign, &endresult, &result); + + if (!result) + return QString(); + + int resultLen = endresult - result; + if (decpt <= 0 && decpt > -6) { + buf.resize(-decpt + 2 + sign); + qMemSet(buf.data(), '0', -decpt + 2 + sign); + if (sign) // fix the sign. + buf[0] = '-'; + buf[sign + 1] = '.'; + buf.append(result, resultLen); + } else { + if (sign) + buf.append('-'); + int length = buf.size() - sign + resultLen; + if (decpt <= 21 && decpt > 0) { + if (length <= decpt) { + const char* zeros = "0000000000000000000000000"; + buf.append(result, resultLen); + buf.append(zeros, decpt - length); + } else { + buf.append(result, decpt); + buf.append('.'); + buf.append(result + decpt, resultLen - decpt); + } + } else if (result[0] >= '0' && result[0] <= '9') { + if (length > 1) { + buf.append(result, 1); + buf.append('.'); + buf.append(result + 1, resultLen - 1); + } else + buf.append(result, resultLen); + buf.append('e'); + buf.append(decpt >= 0 ? '+' : '-'); + int e = qAbs(decpt - 1); + if (e >= 100) + buf.append('0' + e / 100); + if (e >= 10) + buf.append('0' + (e % 100) / 10); + buf.append('0' + e % 10); + } + } + free(result); + buf.append(0); + return QString::fromLatin1(buf.constData()); + } + + enum { + PropertyAttributeMask = v8::ReadOnly | v8::DontDelete | v8::DontEnum, + }; + + // return a mask of v8::PropertyAttribute that may also contains QScriptValue::PropertyGetter or QScriptValue::PropertySetter + static uint toPropertyAttributes(const QFlags<QJSValue::PropertyFlag>& flags) + { + uint attr = 0; + if (flags.testFlag(QJSValue::ReadOnly)) + attr |= v8::ReadOnly; + if (flags.testFlag(QJSValue::Undeletable)) + attr |= v8::DontDelete; + if (flags.testFlag(QJSValue::SkipInEnumeration)) + attr |= v8::DontEnum; +// if (flags.testFlag(QScriptValue::PropertyGetter)) +// attr |= QScriptValue::PropertyGetter; +// if (flags.testFlag(QScriptValue::PropertySetter)) +// attr |= QScriptValue::PropertySetter; + return attr; + } + + // Converts a JS RegExp to a QRegExp. + // The conversion is not 100% exact since ECMA regexp and QRegExp + // have different semantics/flags, but we try to do our best. + static QRegExp toRegExp(v8::Handle<v8::RegExp> jsRegExp) + { + QString pattern = QJSConverter::toString(jsRegExp->GetSource()); + Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive; + if (jsRegExp->GetFlags() & v8::RegExp::kIgnoreCase) + caseSensitivity = Qt::CaseInsensitive; + return QRegExp(pattern, caseSensitivity, QRegExp::RegExp2); + } + + // Converts a QRegExp to a JS RegExp. + // The conversion is not 100% exact since ECMA regexp and QRegExp + // have different semantics/flags, but we try to do our best. + static v8::Handle<v8::RegExp> toRegExp(const QRegExp &re) + { + // Convert the pattern to a ECMAScript pattern. + QString pattern = qt_regexp_toCanonical(re.pattern(), re.patternSyntax()); + if (re.isMinimal()) { + QString ecmaPattern; + int len = pattern.length(); + ecmaPattern.reserve(len); + int i = 0; + const QChar *wc = pattern.unicode(); + bool inBracket = false; + while (i < len) { + QChar c = wc[i++]; + ecmaPattern += c; + switch (c.unicode()) { + case '?': + case '+': + case '*': + case '}': + if (!inBracket) + ecmaPattern += QLatin1Char('?'); + break; + case '\\': + if (i < len) + ecmaPattern += wc[i++]; + break; + case '[': + inBracket = true; + break; + case ']': + inBracket = false; + break; + default: + break; + } + } + pattern = ecmaPattern; + } + + int flags = v8::RegExp::kNone; + if (re.caseSensitivity() == Qt::CaseInsensitive) + flags |= v8::RegExp::kIgnoreCase; + + return v8::RegExp::New(QJSConverter::toString(pattern), static_cast<v8::RegExp::Flags>(flags)); + } + + // Converts a QStringList to JS. + // The result is a new Array object with length equal to the length + // of the QStringList, and the elements being the QStringList's + // elements converted to JS Strings. + static v8::Handle<v8::Array> toStringList(const QStringList &lst) + { + v8::Handle<v8::Array> result = v8::Array::New(lst.size()); + for (int i = 0; i < lst.size(); ++i) + result->Set(i, toString(lst.at(i))); + return result; + } + + // Converts a JS Array object to a QStringList. + // The result is a QStringList with length equal to the length + // of the JS Array, and elements being the JS Array's elements + // converted to QStrings. + static QStringList toStringList(v8::Handle<v8::Array> jsArray) + { + QStringList result; + uint32_t length = jsArray->Length(); + for (uint32_t i = 0; i < length; ++i) + result.append(toString(jsArray->Get(i)->ToString())); + return result; + } + + + // Converts a JS Date to a QDateTime. + static QDateTime toDateTime(v8::Handle<v8::Date> jsDate) + { + return QDateTime::fromMSecsSinceEpoch(jsDate->NumberValue()); + } + + // Converts a QDateTime to a JS Date. + static v8::Handle<v8::Value> toDateTime(const QDateTime &dt) + { + double date; + if (!dt.isValid()) + date = qSNaN(); + else + date = dt.toMSecsSinceEpoch(); + return v8::Date::New(date); + } +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/v8/qjsengine.cpp b/src/declarative/qml/v8/qjsengine.cpp new file mode 100644 index 0000000000..e80fcb4e7e --- /dev/null +++ b/src/declarative/qml/v8/qjsengine.cpp @@ -0,0 +1,431 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-ONLY$ +** GNU Lesser General Public License Usage +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qjsengine.h" +#include "qjsvalue.h" +#include "qjsvalue_p.h" +#include "qscriptisolate_p.h" +#include "qscript_impl_p.h" +#include "qv8engine_p.h" + +#include <QtCore/qdatetime.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qvariant.h> +#include <QtCore/qdatetime.h> + +#include <QtCore/qcoreapplication.h> +#include <QtCore/qdir.h> +#include <QtCore/qfile.h> +#include <QtCore/qfileinfo.h> +#include <QtCore/qpluginloader.h> +#include <qthread.h> +#include <qmutex.h> +#include <qwaitcondition.h> + +#undef Q_D +#undef Q_Q +#define Q_D(blah) +#define Q_Q(blah) + +Q_DECLARE_METATYPE(QJSValue) +Q_DECLARE_METATYPE(QObjectList) +Q_DECLARE_METATYPE(QList<int>) + +QT_BEGIN_NAMESPACE + + +/*! + Constructs a QJSEngine object. + + The globalObject() is initialized to have properties as described in + \l{ECMA-262}, Section 15.1. +*/ +QJSEngine::QJSEngine() + : d(new QV8Engine(this)) +{ +} + +/*! + \internal +*/ +QJSEngine::QJSEngine(QJSEngine::ContextOwnership ownership) + : d(new QV8Engine(this, ownership)) +{ +} + +/*! + Constructs a QJSEngine object with the given \a parent. + + The globalObject() is initialized to have properties as described in + \l{ECMA-262}, Section 15.1. +*/ + +QJSEngine::QJSEngine(QObject *parent) + : QObject(parent) + , d(new QV8Engine(this)) +{ +} + +QJSEngine::QJSEngine(QObjectPrivate &dd, QObject *parent) + : QObject(dd, parent) + , d(new QV8Engine(this)) +{ +} + +/*! + Destroys this QJSEngine. +*/ +QJSEngine::~QJSEngine() +{ + delete d; +} + +/*! + Returns true if the last script evaluation resulted in an uncaught + exception; otherwise returns false. + + The exception state is cleared when evaluate() is called. + + \sa uncaughtException(), uncaughtExceptionLineNumber(), + uncaughtExceptionBacktrace() +*/ +bool QJSEngine::hasUncaughtException() const +{ + Q_D(const QJSEngine); + QScriptIsolate api(d); + return d->hasUncaughtException(); +} + +/*! + Returns the current uncaught exception, or an invalid QJSValue + if there is no uncaught exception. + + The exception value is typically an \c{Error} object; in that case, + you can call toString() on the return value to obtain an error + message. + + \sa hasUncaughtException(), uncaughtExceptionLineNumber(), + uncaughtExceptionBacktrace() +*/ +QJSValue QJSEngine::uncaughtException() const +{ + Q_D(const QJSEngine); + QScriptIsolate api(d); + return d->scriptValueFromInternal(d->uncaughtException()); +} + +/*! + Clears any uncaught exceptions in this engine. + + \sa hasUncaughtException() +*/ +void QJSEngine::clearExceptions() +{ + Q_D(QJSEngine); + QScriptIsolate api(d); + d->clearExceptions(); +} + + +/*! + Runs the garbage collector. + + The garbage collector will attempt to reclaim memory by locating and disposing of objects that are + no longer reachable in the script environment. + + Normally you don't need to call this function; the garbage collector will automatically be invoked + when the QJSEngine decides that it's wise to do so (i.e. when a certain number of new objects + have been created). However, you can call this function to explicitly request that garbage + collection should be performed as soon as possible. + + \sa reportAdditionalMemoryCost() +*/ +void QJSEngine::collectGarbage() +{ + Q_D(QJSEngine); + QScriptIsolate api(d); + d->collectGarbage(); +} + +/*! + Evaluates \a program, using \a lineNumber as the base line number, + and returns the result of the evaluation. + + The script code will be evaluated in the current context. + + The evaluation of \a program can cause an exception in the + engine; in this case the return value will be the exception + that was thrown (typically an \c{Error} object). You can call + hasUncaughtException() to determine if an exception occurred in + the last call to evaluate(). + + \a lineNumber is used to specify a starting line number for \a + program; line number information reported by the engine that pertain + to this evaluation (e.g. uncaughtExceptionLineNumber()) will be + based on this argument. For example, if \a program consists of two + lines of code, and the statement on the second line causes a script + exception, uncaughtExceptionLineNumber() would return the given \a + lineNumber plus one. When no starting line number is specified, line + numbers will be 1-based. + + \a fileName is used for error reporting. For example in error objects + the file name is accessible through the "fileName" property if it's + provided with this function. +*/ +QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, int lineNumber) +{ + Q_D(QJSEngine); + QScriptIsolate api(d, QScriptIsolate::NotNullEngine); + v8::HandleScope handleScope; + return QJSValuePrivate::get(d->evaluate(program, fileName, lineNumber)); +} + +QJSValue QJSEngine::nullValue() +{ + Q_D(QJSEngine); + QScriptIsolate api(d, QScriptIsolate::NotNullEngine); + v8::HandleScope handleScope; + return QJSValuePrivate::get(new QJSValuePrivate(d, v8::Null())); +} + +QJSValue QJSEngine::undefinedValue() +{ + Q_D(QJSEngine); + QScriptIsolate api(d, QScriptIsolate::NotNullEngine); + v8::HandleScope handleScope; + return QJSValuePrivate::get(new QJSValuePrivate(d, v8::Undefined())); +} + +QJSValue QJSEngine::newObject() +{ + Q_D(QJSEngine); + QScriptIsolate api(d, QScriptIsolate::NotNullEngine); + v8::HandleScope handleScope; + return QJSValuePrivate::get(new QJSValuePrivate(d, v8::Object::New())); +} + +QJSValue QJSEngine::newArray(uint length) +{ + Q_D(QJSEngine); + QScriptIsolate api(d, QScriptIsolate::NotNullEngine); + v8::HandleScope handleScope; + return QJSValuePrivate::get(d->newArray(length)); +} + +/*! + Creates a QtScript object that wraps the given QObject \a + object, using the given \a ownership. The given \a options control + various aspects of the interaction with the resulting script object. + + Signals and slots, properties and children of \a object are + available as properties of the created QJSValue. For more + information, see the \l{QtScript} documentation. + + If \a object is a null pointer, this function returns nullValue(). + + If a default prototype has been registered for the \a object's class + (or its superclass, recursively), the prototype of the new script + object will be set to be that default prototype. + + If the given \a object is deleted outside of QtScript's control, any + attempt to access the deleted QObject's members through the QtScript + wrapper object (either by script code or C++) will result in a + script exception. + + \sa QJSValue::toQObject(), reportAdditionalMemoryCost() +*/ +QJSValue QJSEngine::newQObject(QObject *object) +{ + Q_D(QJSEngine); + QScriptIsolate api(d, QScriptIsolate::NotNullEngine); + v8::HandleScope handleScope; + return d->scriptValueFromInternal(d->newQObject(object)); +} + +/*! + Creates a QtScript object holding the given variant \a value. + + If a default prototype has been registered with the meta type id of + \a value, then the prototype of the created object will be that + prototype; otherwise, the prototype will be the Object prototype + object. + + \sa setDefaultPrototype(), QJSValue::toVariant(), reportAdditionalMemoryCost() +*/ +QJSValue QJSEngine::newVariant(const QVariant &value) +{ + Q_D(QJSEngine); + QScriptIsolate api(d, QScriptIsolate::NotNullEngine); + v8::HandleScope handleScope; + return d->scriptValueFromInternal(d->newVariant(value)); +} + + +QJSValue QJSEngine::globalObject() const +{ + Q_D(const QJSEngine); + QScriptIsolate api(d, QScriptIsolate::NotNullEngine); + v8::HandleScope handleScope; + return d->scriptValueFromInternal(d->global()); +} + +QJSValue QJSEngine::toObject(const QJSValue& value) +{ + Q_D(QJSEngine); + QScriptIsolate api(d, QScriptIsolate::NotNullEngine); + v8::HandleScope handleScope; + return QJSValuePrivate::get(QJSValuePrivate::get(value)->toObject(d)); +} + +/*! + Creates a QtScript object of class Date from the given \a value. + + \sa QJSValue::toDateTime() +*/ +QJSValue QJSEngine::newDate(const QDateTime &dt) +{ + Q_D(QJSEngine); + QScriptIsolate api(d, QScriptIsolate::NotNullEngine); + v8::HandleScope handleScope; + return d->scriptValueFromInternal(v8::Handle<v8::Value>(QJSConverter::toDateTime(dt))); +} + +/*! + Creates a QtScript object of class Date with the given + \a value (the number of milliseconds since 01 January 1970, + UTC). +*/ +QJSValue QJSEngine::newDate(double date) +{ + Q_D(QJSEngine); + QScriptIsolate api(d, QScriptIsolate::NotNullEngine); + v8::HandleScope handleScope; + return d->scriptValueFromInternal(v8::Handle<v8::Value>(v8::Date::New(date))); +} + +/*! + Creates a QtScript object of class RegExp with the given + \a regexp. + + \sa QJSValue::toRegExp() +*/ +QJSValue QJSEngine::newRegExp(const QRegExp ®exp) +{ + Q_D(QJSEngine); + QScriptIsolate api(d, QScriptIsolate::NotNullEngine); + v8::HandleScope handleScope; + return QJSValuePrivate::get(d->newRegExp(regexp)); +} + +/*! + Creates a QtScript object of class RegExp with the given + \a pattern and \a flags. + + The legal flags are 'g' (global), 'i' (ignore case), and 'm' + (multiline). +*/ +QJSValue QJSEngine::newRegExp(const QString &pattern, const QString &flags) +{ + Q_D(QJSEngine); + QScriptIsolate api(d, QScriptIsolate::NotNullEngine); + v8::HandleScope handleScope; + return QJSValuePrivate::get(d->newRegExp(pattern, flags)); +} + +/*! + * \internal + * used by QJSEngine::toScriptValue + */ +QJSValue QJSEngine::create(int type, const void *ptr) +{ + Q_D(QJSEngine); + QScriptIsolate api(d, QScriptIsolate::NotNullEngine); + v8::HandleScope handleScope; + return d->scriptValueFromInternal(d->metaTypeToJS(type, ptr)); +} + +/*! + \internal + \since 4.5 + convert \a value to \a type, store the result in \a ptr +*/ +bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr) +{ + QJSValuePrivate *vp = QJSValuePrivate::get(value); + QV8Engine *engine = vp->engine(); + if (engine) { + QScriptIsolate api(engine, QScriptIsolate::NotNullEngine); + v8::HandleScope handleScope; + return engine->metaTypeFromJS(*vp, type, ptr); + } else { + switch (type) { + case QMetaType::Bool: + *reinterpret_cast<bool*>(ptr) = vp->toBool(); + return true; + case QMetaType::Int: + *reinterpret_cast<int*>(ptr) = vp->toInt32(); + return true; + case QMetaType::UInt: + *reinterpret_cast<uint*>(ptr) = vp->toUInt32(); + return true; + case QMetaType::LongLong: + *reinterpret_cast<qlonglong*>(ptr) = vp->toInteger(); + return true; + case QMetaType::ULongLong: + *reinterpret_cast<qulonglong*>(ptr) = vp->toInteger(); + return true; + case QMetaType::Double: + *reinterpret_cast<double*>(ptr) = vp->toNumber(); + return true; + case QMetaType::QString: + *reinterpret_cast<QString*>(ptr) = vp->toString(); + return true; + case QMetaType::Float: + *reinterpret_cast<float*>(ptr) = vp->toNumber(); + return true; + case QMetaType::Short: + *reinterpret_cast<short*>(ptr) = vp->toInt32(); + return true; + case QMetaType::UShort: + *reinterpret_cast<unsigned short*>(ptr) = vp->toUInt16(); + return true; + case QMetaType::Char: + *reinterpret_cast<char*>(ptr) = vp->toInt32(); + return true; + case QMetaType::UChar: + *reinterpret_cast<unsigned char*>(ptr) = vp->toUInt16(); + return true; + case QMetaType::QChar: + *reinterpret_cast<QChar*>(ptr) = vp->toUInt16(); + return true; + default: + return false; + } + } +} + + +QT_END_NAMESPACE + +#include "moc_qjsengine.cpp" diff --git a/src/declarative/qml/v8/qjsengine.h b/src/declarative/qml/v8/qjsengine.h new file mode 100644 index 0000000000..5109cefcf4 --- /dev/null +++ b/src/declarative/qml/v8/qjsengine.h @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-ONLY$ +** GNU Lesser General Public License Usage +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QJSENGINE_H +#define QJSENGINE_H + +#include <QtCore/qmetatype.h> + +#include <QtCore/qvariant.h> +#include <QtCore/qsharedpointer.h> +#include <QtCore/qobject.h> +#include <QtDeclarative/qjsvalue.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Script) + +class QDateTime; +class QV8Engine; + +class QRegExp; + +template <typename T> +inline T qjsvalue_cast(const QJSValue &); + +class Q_SCRIPT_EXPORT QJSEngine + : public QObject +{ + Q_OBJECT +public: + enum ContextOwnership { + AdoptCurrentContext, + CreateNewContext + }; + + QJSEngine(); + explicit QJSEngine(ContextOwnership ownership); + explicit QJSEngine(QObject *parent); + virtual ~QJSEngine(); + + QJSValue globalObject() const; + + QJSValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1); + + bool hasUncaughtException() const; + QJSValue uncaughtException() const; + void clearExceptions(); + + QJSValue nullValue(); + QJSValue undefinedValue(); + + QJSValue newVariant(const QVariant &value); + + QJSValue newRegExp(const QRegExp ®exp); + + QJSValue newObject(); + QJSValue newArray(uint length = 0); + QJSValue newRegExp(const QString &pattern, const QString &flags); + QJSValue newDate(double value); + QJSValue newDate(const QDateTime &value); + + QJSValue newQObject(QObject *object); + + template <typename T> + inline QJSValue toScriptValue(const T &value) + { + return create(qMetaTypeId<T>(), &value); + } + template <typename T> + inline T fromScriptValue(const QJSValue &value) + { + return qjsvalue_cast<T>(value); + } + + void collectGarbage(); + + QJSValue toObject(const QJSValue &value); + + QV8Engine *handle() const { return d; } + +Q_SIGNALS: + void signalHandlerException(const QJSValue &exception); + +private: + QJSValue create(int type, const void *ptr); + + static bool convertV2(const QJSValue &value, int type, void *ptr); + + friend inline bool qjsvalue_cast_helper(const QJSValue &, int, void *); + +protected: + QJSEngine(QObjectPrivate &dd, QObject *parent = 0); + +private: + QV8Engine *d; + Q_DISABLE_COPY(QJSEngine) + friend class QV8Engine; +}; + +inline bool qjsvalue_cast_helper(const QJSValue &value, int type, void *ptr) +{ + return QJSEngine::convertV2(value, type, ptr); +} + +template<typename T> +T qjsvalue_cast(const QJSValue &value) +{ + T t; + const int id = qMetaTypeId<T>(); + + if (qjsvalue_cast_helper(value, id, &t)) + return t; + else if (value.isVariant()) + return qvariant_cast<T>(value.toVariant()); + + return T(); +} + +template <> +inline QVariant qjsvalue_cast<QVariant>(const QJSValue &value) +{ + return value.toVariant(); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QJSENGINE_H diff --git a/src/declarative/qml/v8/qjsvalue.cpp b/src/declarative/qml/v8/qjsvalue.cpp new file mode 100644 index 0000000000..eff7b4321a --- /dev/null +++ b/src/declarative/qml/v8/qjsvalue.cpp @@ -0,0 +1,1024 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-ONLY$ +** GNU Lesser General Public License Usage +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qscriptisolate_p.h" +#include "qjsengine.h" +#include "qv8engine_p.h" +#include "qjsvalue.h" +#include "qjsvalue_p.h" +#include "qscript_impl_p.h" +#include "qscriptshareddata_p.h" +#include <QtCore/qregexp.h> +#include <QtCore/qstring.h> + +QT_BEGIN_NAMESPACE + +/*! + Constructs an invalid value. +*/ +QJSValue::QJSValue() + : d_ptr(InvalidValue()) +{ +} + +/*! + Constructs a new QJSValue with a boolean \a value. +*/ +QJSValue::QJSValue(bool value) + : d_ptr(new QJSValuePrivate(value)) +{ +} + +/*! + \enum QJSValue::PropertyFlag + + This enum describes the attributes of a property. + + \value ReadOnly The property is read-only. Attempts by Qt Script code to write to the property will be ignored. + + \value Undeletable Attempts by Qt Script code to \c{delete} the property will be ignored. + + \value SkipInEnumeration The property is not to be enumerated by a \c{for-in} enumeration. + + \value PropertyGetter The property is defined by a function which will be called to get the property value. + + \value PropertySetter The property is defined by a function which will be called to set the property value. + + \omitvalue QObjectMember This flag is used to indicate that an existing property is a QObject member (a property or method). + + \value KeepExistingFlags This value is used to indicate to setProperty() that the property's flags should be left unchanged. If the property doesn't exist, the default flags (0) will be used. + + \omitvalue UserRange Flags in this range are not used by Qt Script, and can be used for custom purposes. +*/ + +/*! + Constructs a new QJSValue with a number \a value. +*/ +QJSValue::QJSValue(int value) + : d_ptr(new QJSValuePrivate(value)) +{ +} + +/*! + Constructs a new QJSValue with a number \a value. +*/ +QJSValue::QJSValue(uint value) + : d_ptr(new QJSValuePrivate(value)) +{ +} + +/*! + Constructs a new QJSValue with a number \a value. +*/ +QJSValue::QJSValue(double value) + : d_ptr(new QJSValuePrivate(value)) +{ +} + +/*! + Constructs a new QJSValue with a string \a value. +*/ +QJSValue::QJSValue(const QString& value) + : d_ptr(new QJSValuePrivate(value)) +{ +} + +/*! + Constructs a new QJSValue with a special \a value. +*/ +QJSValue::QJSValue(SpecialValue value) + : d_ptr(new QJSValuePrivate(value)) +{ +} + +/*! + Constructs a new QJSValue with a string \a value. +*/ +QJSValue::QJSValue(const QLatin1String &value) + : d_ptr(new QJSValuePrivate(value)) +{ +} + +/*! + \fn QJSValue::QJSValue(const QLatin1String &value) + + Constructs a new QJSValue with a string \a value. +*/ +#ifndef QT_NO_CAST_FROM_ASCII +QJSValue::QJSValue(const char *value) + : d_ptr(new QJSValuePrivate(QString::fromAscii(value))) +{ +} +#endif + +/*! + Block automatic convertion to bool + \internal +*/ +QJSValue::QJSValue(void* d) +{ + Q_UNUSED(d); + Q_ASSERT(false); +} + +/*! + Constructs a new QJSValue from private + \internal +*/ +QJSValue::QJSValue(QJSValuePrivate* d) + : d_ptr(d) +{ +} + +/*! + Constructs a new QJSValue from private + \internal +*/ +QJSValue::QJSValue(QScriptPassPointer<QJSValuePrivate> d) + : d_ptr(d.give()) +{ +} + +/*! + \obsolete + + Constructs a new QJSValue with the boolean \a value and + registers it with the script \a engine. +*/ +QJSValue::QJSValue(QJSEngine* engine, bool value) +{ + if (engine) { + QScriptIsolate api(QV8Engine::get(engine), QScriptIsolate::NotNullEngine); + d_ptr = new QJSValuePrivate(QV8Engine::get(engine), value); + } else { + d_ptr = new QJSValuePrivate(value); + } +} + +/*! + \obsolete + + Constructs a new QJSValue with the integer \a value and + registers it with the script \a engine. +*/ +QJSValue::QJSValue(QJSEngine* engine, int value) +{ + if (engine) { + QScriptIsolate api(QV8Engine::get(engine), QScriptIsolate::NotNullEngine); + d_ptr = new QJSValuePrivate(QV8Engine::get(engine), value); + } else { + d_ptr = new QJSValuePrivate(value); + } +} + +/*! + \obsolete + + Constructs a new QJSValue with the unsigned integer \a value and + registers it with the script \a engine. + */ +QJSValue::QJSValue(QJSEngine* engine, uint value) +{ + if (engine) { + QScriptIsolate api(QV8Engine::get(engine), QScriptIsolate::NotNullEngine); + d_ptr = new QJSValuePrivate(QV8Engine::get(engine), value); + } else { + d_ptr = new QJSValuePrivate(value); + } +} + +/*! + \obsolete + + Constructs a new QJSValue with the double \a value and + registers it with the script \a engine. +*/ +QJSValue::QJSValue(QJSEngine* engine, double value) +{ + if (engine) { + QScriptIsolate api(QV8Engine::get(engine), QScriptIsolate::NotNullEngine); + d_ptr = new QJSValuePrivate(QV8Engine::get(engine), value); + } else { + d_ptr = new QJSValuePrivate(value); + } +} + +/*! + \obsolete + + Constructs a new QJSValue with the string \a value and + registers it with the script \a engine. +*/ +QJSValue::QJSValue(QJSEngine* engine, const QString& value) +{ + if (engine) { + QScriptIsolate api(QV8Engine::get(engine), QScriptIsolate::NotNullEngine); + d_ptr = new QJSValuePrivate(QV8Engine::get(engine), value); + } else { + d_ptr = new QJSValuePrivate(value); + } +} + +/*! + \obsolete + + Constructs a new QJSValue with the string \a value and + registers it with the script \a engine. +*/ +QJSValue::QJSValue(QJSEngine* engine, const char* value) +{ + if (engine) { + QScriptIsolate api(QV8Engine::get(engine), QScriptIsolate::NotNullEngine); + d_ptr = new QJSValuePrivate(QV8Engine::get(engine), QString::fromUtf8(value)); + } else { + d_ptr = new QJSValuePrivate(QString::fromUtf8(value)); + } +} + +/*! + \obsolete + + Constructs a new QJSValue with the special \a value and + registers it with the script \a engine. +*/ +QJSValue::QJSValue(QJSEngine* engine, SpecialValue value) +{ + if (engine) { + QScriptIsolate api(QV8Engine::get(engine), QScriptIsolate::NotNullEngine); + d_ptr = new QJSValuePrivate(QV8Engine::get(engine), value); + } else { + d_ptr = new QJSValuePrivate(value); + } +} + +/*! + Constructs a new QJSValue that is a copy of \a other. + + Note that if \a other is an object (i.e., isObject() would return + true), then only a reference to the underlying object is copied into + the new script value (i.e., the object itself is not copied). +*/ +QJSValue::QJSValue(const QJSValue& other) + : d_ptr(other.d_ptr) +{ +} + +/*! + Destroys this QJSValue. +*/ +QJSValue::~QJSValue() +{ +} + +/*! + Returns true if this QJSValue is valid; otherwise returns + false. +*/ +bool QJSValue::isValid() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->isValid(); +} + +/*! + Returns true if this QJSValue is of the primitive type Boolean; + otherwise returns false. + + \sa toBool() +*/ +bool QJSValue::isBool() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->isBool(); +} + +/*! + \obsolete + + Use isBool() instead. + Returns true if this QJSValue is of the primitive type Boolean; + otherwise returns false. +*/ +bool QJSValue::isBoolean() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->isBool(); +} + +/*! + Returns true if this QJSValue is of the primitive type Number; + otherwise returns false. + + \sa toNumber() +*/ +bool QJSValue::isNumber() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->isNumber(); +} + +/*! + Returns true if this QJSValue is of the primitive type Null; + otherwise returns false. + + \sa QJSEngine::nullValue() +*/ +bool QJSValue::isNull() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->isNull(); +} + +/*! + Returns true if this QJSValue is of the primitive type String; + otherwise returns false. + + \sa toString() +*/ +bool QJSValue::isString() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->isString(); +} + +/*! + Returns true if this QJSValue is of the primitive type Undefined; + otherwise returns false. + + \sa QJSEngine::undefinedValue() +*/ +bool QJSValue::isUndefined() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->isUndefined(); +} + +/*! + Returns true if this QJSValue is an object of the Error class; + otherwise returns false. + + \sa QScriptContext::throwError() +*/ +bool QJSValue::isError() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->isError(); +} + +/*! + Returns true if this QJSValue is an object of the Array class; + otherwise returns false. + + \sa QJSEngine::newArray() +*/ +bool QJSValue::isArray() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->isArray(); + } + +/*! + Returns true if this QJSValue is of the Object type; otherwise + returns false. + + Note that function values, variant values, and QObject values are + objects, so this function returns true for such values. + + \sa toObject(), QJSEngine::newObject() +*/ +bool QJSValue::isObject() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->isObject(); +} + +/*! + Returns true if this QJSValue is a function; otherwise returns + false. + + \sa call() +*/ +bool QJSValue::isFunction() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->isCallable(); +} + +/*! + Returns true if this QJSValue is a variant value; + otherwise returns false. + + \sa toVariant(), QJSEngine::newVariant() +*/ +bool QJSValue::isVariant() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->isVariant(); +} + +/*! + Returns the string value of this QJSValue, as defined in + \l{ECMA-262} section 9.8, "ToString". + + Note that if this QJSValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's toString() function (and possibly valueOf()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa isString() +*/ +QString QJSValue::toString() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->toString(); +} + +/*! + Returns the number value of this QJSValue, as defined in + \l{ECMA-262} section 9.3, "ToNumber". + + Note that if this QJSValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's valueOf() function (and possibly toString()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa isNumber(), toInteger(), toInt32(), toUInt32(), toUInt16() +*/ +double QJSValue::toNumber() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->toNumber(); +} + +/*! + Returns the boolean value of this QJSValue, using the conversion + rules described in \l{ECMA-262} section 9.2, "ToBoolean". + + Note that if this QJSValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's valueOf() function (and possibly toString()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa isBool() +*/ +bool QJSValue::toBool() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->toBool(); +} + +/*! + \obsolete + + Use toBool() instead. +*/ +bool QJSValue::toBoolean() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->toBool(); +} + +/*! + Returns the integer value of this QJSValue, using the conversion + rules described in \l{ECMA-262} section 9.4, "ToInteger". + + Note that if this QJSValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's valueOf() function (and possibly toString()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa toNumber() +*/ +double QJSValue::toInteger() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->toInteger(); +} + +/*! + Returns the signed 32-bit integer value of this QJSValue, using + the conversion rules described in \l{ECMA-262} section 9.5, "ToInt32". + + Note that if this QJSValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's valueOf() function (and possibly toString()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa toNumber(), toUInt32() +*/ +qint32 QJSValue::toInt32() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->toInt32(); +} + +/*! + Returns the unsigned 32-bit integer value of this QJSValue, using + the conversion rules described in \l{ECMA-262} section 9.6, "ToUint32". + + Note that if this QJSValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's valueOf() function (and possibly toString()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa toNumber(), toInt32() +*/ +quint32 QJSValue::toUInt32() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->toUInt32(); +} + +/*! + Returns the unsigned 16-bit integer value of this QJSValue, using + the conversion rules described in \l{ECMA-262} section 9.7, "ToUint16". + + Note that if this QJSValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's valueOf() function (and possibly toString()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa toNumber() +*/ +quint16 QJSValue::toUInt16() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->toUInt16(); +} + +/*! + \obsolete + + This function is obsolete; use QJSEngine::toObject() instead. +*/ +QJSValue QJSValue::toObject() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return QJSValuePrivate::get(d->toObject()); +} + +/*! + Returns the QVariant value of this QJSValue, if it can be + converted to a QVariant; otherwise returns an invalid QVariant. + The conversion is performed according to the following table: + + \table + \header \o Input Type \o Result + \row \o Undefined \o An invalid QVariant. + \row \o Null \o An invalid QVariant. + \row \o Boolean \o A QVariant containing the value of the boolean. + \row \o Number \o A QVariant containing the value of the number. + \row \o String \o A QVariant containing the value of the string. + \row \o QVariant Object \o The result is the QVariant value of the object (no conversion). + \row \o QObject Object \o A QVariant containing a pointer to the QObject. + \row \o Date Object \o A QVariant containing the date value (toDateTime()). + \row \o RegExp Object \o A QVariant containing the regular expression value (toRegExp()). + \row \o Array Object \o The array is converted to a QVariantList. Each element is converted to a QVariant, recursively; cyclic references are not followed. + \row \o Object \o The object is converted to a QVariantMap. Each property is converted to a QVariant, recursively; cyclic references are not followed. + \endtable + + \sa isVariant() +*/ +QVariant QJSValue::toVariant() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->toVariant(); +} + + +/*! + Calls this QJSValue as a function, using \a thisObject as + the `this' object in the function call, and passing \a args + as arguments to the function. Returns the value returned from + the function. + + If this QJSValue is not a function, call() does nothing + and returns an invalid QJSValue. + + Note that if \a thisObject is not an object, the global object + (see \l{QJSEngine::globalObject()}) will be used as the + `this' object. + + Calling call() can cause an exception to occur in the script engine; + in that case, call() returns the value that was thrown (typically an + \c{Error} object). You can call + QJSEngine::hasUncaughtException() to determine if an exception + occurred. + + \snippet doc/src/snippets/code/src_script_qscriptvalue.cpp 2 + + \sa construct() +*/ +QJSValue QJSValue::call(const QJSValue& thisObject, const QJSValueList& args) +{ + Q_D(QJSValue); + QScriptIsolate api(d->engine()); + return d->call(QJSValuePrivate::get(thisObject), args); +} + +/*! + Creates a new \c{Object} and calls this QJSValue as a + constructor, using the created object as the `this' object and + passing \a args as arguments. If the return value from the + constructor call is an object, then that object is returned; + otherwise the default constructed object is returned. + + If this QJSValue is not a function, construct() does nothing + and returns an invalid QJSValue. + + Calling construct() can cause an exception to occur in the script + engine; in that case, construct() returns the value that was thrown + (typically an \c{Error} object). You can call + QJSEngine::hasUncaughtException() to determine if an exception + occurred. + + \sa call(), QJSEngine::newObject() +*/ +QJSValue QJSValue::construct(const QJSValueList &args) +{ + Q_D(QJSValue); + QScriptIsolate api(d->engine()); + return QJSValuePrivate::get(d->construct(args)); +} + +/*! + Returns the QJSEngine that created this QJSValue, + or 0 if this QJSValue is invalid or the value is not + associated with a particular engine. +*/ +QJSEngine* QJSValue::engine() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + QV8Engine* engine = d->engine(); + if (engine) + return QV8Engine::get(engine); + return 0; +} + + +/*! + If this QJSValue is an object, returns the internal prototype + (\c{__proto__} property) of this object; otherwise returns an + invalid QJSValue. + + \sa setPrototype(), isObject() +*/ +QJSValue QJSValue::prototype() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return QJSValuePrivate::get(d->prototype()); +} + +/*! + If this QJSValue is an object, sets the internal prototype + (\c{__proto__} property) of this object to be \a prototype; + otherwise does nothing. + + The internal prototype should not be confused with the public + property with name "prototype"; the public prototype is usually + only set on functions that act as constructors. + + \sa prototype(), isObject() +*/ +void QJSValue::setPrototype(const QJSValue& prototype) +{ + Q_D(QJSValue); + QScriptIsolate api(d->engine()); + d->setPrototype(QJSValuePrivate::get(prototype)); +} + +/*! + Assigns the \a other value to this QJSValue. + + Note that if \a other is an object (isObject() returns true), + only a reference to the underlying object will be assigned; + the object itself will not be copied. +*/ +QJSValue& QJSValue::operator=(const QJSValue& other) +{ + d_ptr = other.d_ptr; + return *this; +} + +/*! + Returns true if this QJSValue is equal to \a other, otherwise + returns false. The comparison follows the behavior described in + \l{ECMA-262} section 11.9.3, "The Abstract Equality Comparison + Algorithm". + + This function can return true even if the type of this QJSValue + is different from the type of the \a other value; i.e. the + comparison is not strict. For example, comparing the number 9 to + the string "9" returns true; comparing an undefined value to a null + value returns true; comparing a \c{Number} object whose primitive + value is 6 to a \c{String} object whose primitive value is "6" + returns true; and comparing the number 1 to the boolean value + \c{true} returns true. If you want to perform a comparison + without such implicit value conversion, use strictlyEquals(). + + Note that if this QJSValue or the \a other value are objects, + calling this function has side effects on the script engine, since + the engine will call the object's valueOf() function (and possibly + toString()) in an attempt to convert the object to a primitive value + (possibly resulting in an uncaught script exception). + + \sa strictlyEquals(), lessThan() +*/ +bool QJSValue::equals(const QJSValue& other) const +{ + Q_D(const QJSValue); + QJSValuePrivate* otherValue = QJSValuePrivate::get(other); + QScriptIsolate api(d->engine() ? d->engine() : otherValue->engine()); + return d_ptr->equals(otherValue); +} + +/*! + Returns true if this QJSValue is equal to \a other using strict + comparison (no conversion), otherwise returns false. The comparison + follows the behavior described in \l{ECMA-262} section 11.9.6, "The + Strict Equality Comparison Algorithm". + + If the type of this QJSValue is different from the type of the + \a other value, this function returns false. If the types are equal, + the result depends on the type, as shown in the following table: + + \table + \header \o Type \o Result + \row \o Undefined \o true + \row \o Null \o true + \row \o Boolean \o true if both values are true, false otherwise + \row \o Number \o false if either value is NaN (Not-a-Number); true if values are equal, false otherwise + \row \o String \o true if both values are exactly the same sequence of characters, false otherwise + \row \o Object \o true if both values refer to the same object, false otherwise + \endtable + + \sa equals() +*/ +bool QJSValue::strictlyEquals(const QJSValue& other) const +{ + Q_D(const QJSValue); + QJSValuePrivate* o = QJSValuePrivate::get(other); + QScriptIsolate api(d->engine() ? d->engine() : o->engine()); + return d_ptr->strictlyEquals(o); +} + +/*! + Returns true if this QJSValue is an instance of + \a other; otherwise returns false. + + This QJSValue is considered to be an instance of \a other if + \a other is a function and the value of the \c{prototype} + property of \a other is in the prototype chain of this + QJSValue. +*/ +bool QJSValue::instanceOf(const QJSValue &other) const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->instanceOf(QJSValuePrivate::get(other)); +} + +/*! + Returns the value of this QJSValue's property with the given \a name, + using the given \a mode to resolve the property. + + If no such property exists, an invalid QJSValue is returned. + + If the property is implemented using a getter function (i.e. has the + PropertyGetter flag set), calling property() has side-effects on the + script engine, since the getter function will be called (possibly + resulting in an uncaught script exception). If an exception + occurred, property() returns the value that was thrown (typically + an \c{Error} object). + + \sa setProperty(), propertyFlags(), QJSValueIterator +*/ +QJSValue QJSValue::property(const QString& name) const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return QJSValuePrivate::get(d->property(name)); +} + +/*! + \overload + + Returns the property at the given \a arrayIndex, using the given \a + mode to resolve the property. + + This function is provided for convenience and performance when + working with array objects. + + If this QJSValue is not an Array object, this function behaves + as if property() was called with the string representation of \a + arrayIndex. +*/ +QJSValue QJSValue::property(quint32 arrayIndex) const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return QJSValuePrivate::get(d->property(arrayIndex)); +} + +/*! + Sets the value of this QJSValue's property with the given \a name to + the given \a value. + + If this QJSValue is not an object, this function does nothing. + + If this QJSValue does not already have a property with name \a name, + a new property is created; the given \a flags then specify how this + property may be accessed by script code. + + If \a value is invalid, the property is removed. + + If the property is implemented using a setter function (i.e. has the + PropertySetter flag set), calling setProperty() has side-effects on + the script engine, since the setter function will be called with the + given \a value as argument (possibly resulting in an uncaught script + exception). + + Note that you cannot specify custom getter or setter functions for + built-in properties, such as the \c{length} property of Array objects + or meta properties of QObject objects. + + \sa property() +*/ +void QJSValue::setProperty(const QString& name, const QJSValue& value) +{ + Q_D(QJSValue); + QScriptIsolate api(d->engine()); + d->setProperty(name, QJSValuePrivate::get(value)); +} + +/*! + \overload + + Sets the property at the given \a arrayIndex to the given \a value. + + This function is provided for convenience and performance when + working with array objects. + + If this QJSValue is not an Array object, this function behaves + as if setProperty() was called with the string representation of \a + arrayIndex. +*/ +void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value) +{ + Q_D(QJSValue); + QScriptIsolate api(d->engine()); + d->setProperty(arrayIndex, QJSValuePrivate::get(value)); +} + +/*! + Returns the flags of the property with the given \a name, using the + given \a mode to resolve the property. + + \sa property() +*/ +QJSValue::PropertyFlags QJSValue::propertyFlags(const QString& name) const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->propertyFlags(name); +} + +/*! + * If this QJSValue is a QObject, returns the QObject pointer + * that the QJSValue represents; otherwise, returns 0. + * + * If the QObject that this QJSValue wraps has been deleted, + * this function returns 0 (i.e. it is possible for toQObject() + * to return 0 even when isQObject() returns true). + * + * \sa isQObject() + */ +QObject *QJSValue::toQObject() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->toQObject(); +} + +/*! + Returns a QDateTime representation of this value, in local time. + If this QJSValue is not a date, or the value of the date is NaN + (Not-a-Number), an invalid QDateTime is returned. + + \sa isDate() +*/ +QDateTime QJSValue::toDateTime() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->toDataTime(); +} + +/*! + Returns the QRegExp representation of this value. + If this QJSValue is not a regular expression, an empty + QRegExp is returned. + + \sa isRegExp() +*/ +QRegExp QJSValue::toRegExp() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->toRegExp(); +} + +/*! + Returns true if this QJSValue is an object of the Date class; + otherwise returns false. + + \sa QJSEngine::newDate() +*/ +bool QJSValue::isDate() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->isDate(); +} + +/*! + Returns true if this QJSValue is an object of the RegExp class; + otherwise returns false. + + \sa QJSEngine::newRegExp() +*/ +bool QJSValue::isRegExp() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->isRegExp(); +} + +/*! + Returns true if this QJSValue is a QObject; otherwise returns + false. + + Note: This function returns true even if the QObject that this + QJSValue wraps has been deleted. + + \sa toQObject(), QJSEngine::newQObject() +*/ +bool QJSValue::isQObject() const +{ + Q_D(const QJSValue); + QScriptIsolate api(d->engine()); + return d->isQObject(); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/v8/qjsvalue.h b/src/declarative/qml/v8/qjsvalue.h new file mode 100644 index 0000000000..07276bc694 --- /dev/null +++ b/src/declarative/qml/v8/qjsvalue.h @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-ONLY$ +** GNU Lesser General Public License Usage +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QJSVALUE_H +#define QJSVALUE_H + +#include <QtCore/qstring.h> + +#include <QtCore/qlist.h> +#include <QtCore/qsharedpointer.h> +#include <QtCore/qshareddata.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Script) + +class QJSValue; +class QJSEngine; +class QVariant; +class QObject; +struct QMetaObject; +class QDateTime; +class QRegExp; + +typedef QList<QJSValue> QJSValueList; + +class QJSValuePrivate; +struct QScriptValuePrivatePointerDeleter; +template <class T> class QScriptPassPointer; + +class Q_SCRIPT_EXPORT QJSValue +{ +public: + enum PropertyFlag { + ReadOnly = 0x00000001, + Undeletable = 0x00000002, + SkipInEnumeration = 0x00000004 + }; + Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag) + + enum SpecialValue { + NullValue, + UndefinedValue + }; + +public: + QJSValue(); + ~QJSValue(); + QJSValue(const QJSValue &other); + QJSValue(QJSEngine *engine, SpecialValue val); + QJSValue(QJSEngine *engine, bool val); + QJSValue(QJSEngine *engine, int val); + QJSValue(QJSEngine *engine, uint val); + QJSValue(QJSEngine *engine, double val); + QJSValue(QJSEngine *engine, const QString &val); + + QJSValue(SpecialValue value); + QJSValue(bool value); + QJSValue(int value); + QJSValue(uint value); + QJSValue(double value); + QJSValue(const QString &value); + QJSValue(const QLatin1String &value); +#ifndef QT_NO_CAST_FROM_ASCII + QT_ASCII_CAST_WARN_CONSTRUCTOR QJSValue(const char *str); +#endif + + QJSValue &operator=(const QJSValue &other); + + QJSEngine *engine() const; + bool isValid() const; + bool isBool() const; + bool isBoolean() const; + bool isNumber() const; + bool isFunction() const; + bool isNull() const; + bool isString() const; + bool isUndefined() const; + bool isVariant() const; + bool isQObject() const; + bool isObject() const; + bool isDate() const; + bool isRegExp() const; + bool isArray() const; + bool isError() const; + + QString toString() const; + double toNumber() const; + bool toBool() const; + bool toBoolean() const; + double toInteger() const; + qint32 toInt32() const; + quint32 toUInt32() const; + quint16 toUInt16() const; + QVariant toVariant() const; + QObject *toQObject() const; + QJSValue toObject() const; + QDateTime toDateTime() const; + QRegExp toRegExp() const; + + bool instanceOf(const QJSValue &other) const; + + bool equals(const QJSValue &other) const; + bool strictlyEquals(const QJSValue &other) const; + + QJSValue prototype() const; + void setPrototype(const QJSValue &prototype); + + QJSValue property(const QString &name) const; + void setProperty(const QString &name, const QJSValue &value); + + QJSValue property(quint32 arrayIndex) const; + void setProperty(quint32 arrayIndex, const QJSValue &value); + + QJSValue::PropertyFlags propertyFlags(const QString &name) const; + + QJSValue call(const QJSValue &thisObject = QJSValue(), + const QJSValueList &args = QJSValueList()); + QJSValue construct(const QJSValueList &args = QJSValueList()); + +private: + // force compile error, prevent QJSValue(bool) to be called + QJSValue(void *); + // force compile error, prevent QJSValue(QScriptEngine*, bool) to be called + QJSValue(QJSEngine *, void *); + QJSValue(QJSEngine *, const char *); + + QJSValue(QJSValuePrivate*); + QJSValue(QScriptPassPointer<QJSValuePrivate>); + +private: + QExplicitlySharedDataPointer<QJSValuePrivate> d_ptr; + + Q_DECLARE_PRIVATE(QJSValue) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QJSValue::PropertyFlags) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/declarative/qml/v8/qjsvalue_impl_p.h b/src/declarative/qml/v8/qjsvalue_impl_p.h new file mode 100644 index 0000000000..adff6ce945 --- /dev/null +++ b/src/declarative/qml/v8/qjsvalue_impl_p.h @@ -0,0 +1,1133 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-ONLY$ +** GNU Lesser General Public License Usage +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QJSVALUE_IMPL_P_H +#define QJSVALUE_IMPL_P_H + +#include "qjsconverter_p.h" +#include "qjsvalue_p.h" +#include "qv8engine_p.h" +#include "qscriptisolate_p.h" + +QT_BEGIN_NAMESPACE + + +QJSValuePrivate* QJSValuePrivate::get(const QJSValue& q) { Q_ASSERT(q.d_ptr.data()); return q.d_ptr.data(); } + +QJSValue QJSValuePrivate::get(const QJSValuePrivate* d) +{ + Q_ASSERT(d); + return QJSValue(const_cast<QJSValuePrivate*>(d)); +} + +QJSValue QJSValuePrivate::get(QScriptPassPointer<QJSValuePrivate> d) +{ + Q_ASSERT(d); + return QJSValue(d); +} + +QJSValue QJSValuePrivate::get(QJSValuePrivate* d) +{ + Q_ASSERT(d); + return QJSValue(d); +} + +QJSValuePrivate::QJSValuePrivate() + : m_engine(0), m_state(Invalid) +{ +} + +QJSValuePrivate::QJSValuePrivate(bool value) + : m_engine(0), m_state(CBool), u(value) +{ +} + +QJSValuePrivate::QJSValuePrivate(int value) + : m_engine(0), m_state(CNumber), u(value) +{ +} + +QJSValuePrivate::QJSValuePrivate(uint value) + : m_engine(0), m_state(CNumber), u(value) +{ +} + +QJSValuePrivate::QJSValuePrivate(double value) + : m_engine(0), m_state(CNumber), u(value) +{ +} + +QJSValuePrivate::QJSValuePrivate(const QString& value) + : m_engine(0), m_state(CString), u(new QString(value)) +{ +} + +QJSValuePrivate::QJSValuePrivate(QJSValue::SpecialValue value) + : m_engine(0), m_state(value == QJSValue::NullValue ? CNull : CUndefined) +{ +} + +QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, bool value) + : m_engine(engine), m_state(JSValue) +{ + Q_ASSERT(engine); + v8::HandleScope handleScope; + m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value)); + m_engine->registerValue(this); +} + +QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, int value) + : m_engine(engine), m_state(JSValue) +{ + Q_ASSERT(engine); + v8::HandleScope handleScope; + m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value)); + m_engine->registerValue(this); +} + +QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, uint value) + : m_engine(engine), m_state(JSValue) +{ + Q_ASSERT(engine); + v8::HandleScope handleScope; + m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value)); + m_engine->registerValue(this); +} + +QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, double value) + : m_engine(engine), m_state(JSValue) +{ + Q_ASSERT(engine); + v8::HandleScope handleScope; + m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value)); + m_engine->registerValue(this); +} + +QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, const QString& value) + : m_engine(engine), m_state(JSValue) +{ + Q_ASSERT(engine); + v8::HandleScope handleScope; + m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value)); + m_engine->registerValue(this); +} + +QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, QJSValue::SpecialValue value) + : m_engine(engine), m_state(JSValue) +{ + Q_ASSERT(engine); + v8::HandleScope handleScope; + m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value)); + m_engine->registerValue(this); +} + +QJSValuePrivate::QJSValuePrivate(QV8Engine *engine, v8::Handle<v8::Value> value) + : m_engine(engine), m_state(JSValue), m_value(v8::Persistent<v8::Value>::New(value)) +{ + Q_ASSERT(engine); + // It shouldn't happen, v8 shows errors by returning an empty handler. This is important debug + // information and it can't be simply ignored. + Q_ASSERT(!value.IsEmpty()); + m_engine->registerValue(this); +} + +QJSValuePrivate::~QJSValuePrivate() +{ + if (isJSBased()) { + m_engine->unregisterValue(this); + QScriptIsolate api(m_engine); + m_value.Dispose(); + } else if (isStringBased()) { + delete u.m_string; + } +} + +bool QJSValuePrivate::toBool() const +{ + switch (m_state) { + case JSValue: + { + v8::HandleScope scope; + return m_value->ToBoolean()->Value(); + } + case CNumber: + return !(qIsNaN(u.m_number) || !u.m_number); + case CBool: + return u.m_bool; + case Invalid: + case CNull: + case CUndefined: + return false; + case CString: + return u.m_string->length(); + } + + Q_ASSERT_X(false, "toBool()", "Not all states are included in the previous switch statement."); + return false; // Avoid compiler warning. +} + +double QJSValuePrivate::toNumber() const +{ + switch (m_state) { + case JSValue: + { + v8::HandleScope scope; + return m_value->ToNumber()->Value(); + } + case CNumber: + return u.m_number; + case CBool: + return u.m_bool ? 1 : 0; + case CNull: + case Invalid: + return 0; + case CUndefined: + return qQNaN(); + case CString: + bool ok; + double result = u.m_string->toDouble(&ok); + if (ok) + return result; + result = u.m_string->toInt(&ok, 0); // Try other bases. + if (ok) + return result; + if (*u.m_string == QLatin1String("Infinity")) + return qInf(); + if (*u.m_string == QLatin1String("-Infinity")) + return -qInf(); + return u.m_string->length() ? qQNaN() : 0; + } + + Q_ASSERT_X(false, "toNumber()", "Not all states are included in the previous switch statement."); + return 0; // Avoid compiler warning. +} + +QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::toObject(QV8Engine* engine) const +{ + Q_ASSERT(engine); + if (this->engine() && engine != this->engine()) { + qWarning("QJSEngine::toObject: cannot convert value created in a different engine"); + return InvalidValue(); + } + + v8::HandleScope scope; + switch (m_state) { + case Invalid: + case CNull: + case CUndefined: + return new QJSValuePrivate; + case CString: + return new QJSValuePrivate(engine, engine->makeJSValue(*u.m_string)->ToObject()); + case CNumber: + return new QJSValuePrivate(engine, engine->makeJSValue(u.m_number)->ToObject()); + case CBool: + return new QJSValuePrivate(engine, engine->makeJSValue(u.m_bool)->ToObject()); + case JSValue: + if (m_value->IsObject()) + return const_cast<QJSValuePrivate*>(this); + if (m_value->IsNull() || m_value->IsUndefined()) // avoid "Uncaught TypeError: Cannot convert null to object" + return InvalidValue(); + return new QJSValuePrivate(engine, m_value->ToObject()); + default: + Q_ASSERT_X(false, Q_FUNC_INFO, "Not all states are included in this switch"); + return InvalidValue(); + } +} + +/*! + This method is created only for QJSValue::toObject() purpose which is obsolete. + \internal + */ +QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::toObject() const +{ + if (isJSBased()) + return toObject(engine()); + + // Without an engine there is not much we can do. + return new QJSValuePrivate; +} + +QString QJSValuePrivate::toString() const +{ + switch (m_state) { + case Invalid: + return QString(); + case CBool: + return u.m_bool ? QString::fromLatin1("true") : QString::fromLatin1("false"); + case CString: + return *u.m_string; + case CNumber: + return QJSConverter::toString(u.m_number); + case CNull: + return QString::fromLatin1("null"); + case CUndefined: + return QString::fromLatin1("undefined"); + case JSValue: + Q_ASSERT(!m_value.IsEmpty()); + v8::HandleScope handleScope; + v8::TryCatch tryCatch; + v8::Local<v8::String> result = m_value->ToString(); + if (result.IsEmpty()) { + result = tryCatch.Exception()->ToString(); + m_engine->setException(tryCatch.Exception(), tryCatch.Message()); + } + return QJSConverter::toString(result); + } + + Q_ASSERT_X(false, "toString()", "Not all states are included in the previous switch statement."); + return QString(); // Avoid compiler warning. +} + +QVariant QJSValuePrivate::toVariant() const +{ + switch (m_state) { + case Invalid: + return QVariant(); + case CBool: + return QVariant(u.m_bool); + case CString: + return QVariant(*u.m_string); + case CNumber: + return QVariant(u.m_number); + case CNull: + return QVariant(); + case CUndefined: + return QVariant(); + case JSValue: + break; + } + + Q_ASSERT(m_state == JSValue); + Q_ASSERT(!m_value.IsEmpty()); + Q_ASSERT(m_engine); + + v8::HandleScope handleScope; + return m_engine->variantFromJS(m_value); +} + +inline QDateTime QJSValuePrivate::toDataTime() const +{ + if (!isDate()) + return QDateTime(); + + v8::HandleScope handleScope; + return QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(m_value)); + +} + +inline QRegExp QJSValuePrivate::toRegExp() const +{ + if (!isRegExp()) + return QRegExp(); + + v8::HandleScope handleScope; + return QJSConverter::toRegExp(v8::Handle<v8::RegExp>::Cast(m_value)); +} + +QObject* QJSValuePrivate::toQObject() const +{ + if (!isJSBased()) + return 0; + + v8::HandleScope handleScope; + return engine()->qtObjectFromJS(m_value); +} + +double QJSValuePrivate::toInteger() const +{ + double result = toNumber(); + if (qIsNaN(result)) + return 0; + if (qIsInf(result)) + return result; + return (result > 0) ? qFloor(result) : -1 * qFloor(-result); +} + +qint32 QJSValuePrivate::toInt32() const +{ + double result = toInteger(); + // Orginaly it should look like that (result == 0 || qIsInf(result) || qIsNaN(result)), but + // some of these operation are invoked in toInteger subcall. + if (qIsInf(result)) + return 0; + return result; +} + +quint32 QJSValuePrivate::toUInt32() const +{ + double result = toInteger(); + // Orginaly it should look like that (result == 0 || qIsInf(result) || qIsNaN(result)), but + // some of these operation are invoked in toInteger subcall. + if (qIsInf(result)) + return 0; + return result; +} + +quint16 QJSValuePrivate::toUInt16() const +{ + return toInt32(); +} + +inline bool QJSValuePrivate::isArray() const +{ + return isJSBased() && m_value->IsArray(); +} + +inline bool QJSValuePrivate::isBool() const +{ + return m_state == CBool || (isJSBased() && m_value->IsBoolean()); +} + +inline bool QJSValuePrivate::isCallable() const +{ + if (isFunction()) + return true; + if (isObject()) { + // Our C++ wrappers register function handlers but not always act as callables. + return v8::Object::Cast(*m_value)->IsCallable(); + } + return false; +} + +inline bool QJSValuePrivate::isError() const +{ + if (!isJSBased()) + return false; + v8::HandleScope handleScope; + return m_value->IsError(); +} + +inline bool QJSValuePrivate::isFunction() const +{ + return isJSBased() && m_value->IsFunction(); +} + +inline bool QJSValuePrivate::isNull() const +{ + return m_state == CNull || (isJSBased() && m_value->IsNull()); +} + +inline bool QJSValuePrivate::isNumber() const +{ + return m_state == CNumber || (isJSBased() && m_value->IsNumber()); +} + +inline bool QJSValuePrivate::isObject() const +{ + return isJSBased() && m_value->IsObject(); +} + +inline bool QJSValuePrivate::isString() const +{ + return m_state == CString || (isJSBased() && m_value->IsString()); +} + +inline bool QJSValuePrivate::isUndefined() const +{ + return m_state == CUndefined || (isJSBased() && m_value->IsUndefined()); +} + +inline bool QJSValuePrivate::isValid() const +{ + return m_state != Invalid; +} + +inline bool QJSValuePrivate::isVariant() const +{ + return isJSBased() && m_engine->isVariant(m_value); +} + +bool QJSValuePrivate::isDate() const +{ + return (isJSBased() && m_value->IsDate()); +} + +bool QJSValuePrivate::isRegExp() const +{ + return (isJSBased() && m_value->IsRegExp()); +} + +bool QJSValuePrivate::isQObject() const +{ + return isJSBased() && engine()->isQObject(m_value); +} + +inline bool QJSValuePrivate::equals(QJSValuePrivate* other) +{ + if (!isValid()) + return !other->isValid(); + + if (!other->isValid()) + return false; + + if (!isJSBased() && !other->isJSBased()) { + switch (m_state) { + case CNull: + case CUndefined: + return other->isUndefined() || other->isNull(); + case CNumber: + switch (other->m_state) { + case CBool: + case CString: + return u.m_number == other->toNumber(); + case CNumber: + return u.m_number == other->u.m_number; + default: + return false; + } + case CBool: + switch (other->m_state) { + case CBool: + return u.m_bool == other->u.m_bool; + case CNumber: + return toNumber() == other->u.m_number; + case CString: + return toNumber() == other->toNumber(); + default: + return false; + } + case CString: + switch (other->m_state) { + case CBool: + return toNumber() == other->toNumber(); + case CNumber: + return toNumber() == other->u.m_number; + case CString: + return *u.m_string == *other->u.m_string; + default: + return false; + } + default: + Q_ASSERT_X(false, "QJSValue::equals", "Not all states are included in the previous switch statement."); + } + } + + v8::HandleScope handleScope; + if (isJSBased() && !other->isJSBased()) { + if (!other->assignEngine(engine())) { + qWarning("QJSValue::equals: cannot compare to a value created in a different engine"); + return false; + } + } else if (!isJSBased() && other->isJSBased()) { + if (!assignEngine(other->engine())) { + qWarning("QJSValue::equals: cannot compare to a value created in a different engine"); + return false; + } + } + + Q_ASSERT(this->engine() && other->engine()); + if (this->engine() != other->engine()) { + qWarning("QJSValue::equals: cannot compare to a value created in a different engine"); + return false; + } + return m_value->Equals(other->m_value); +} + +inline bool QJSValuePrivate::strictlyEquals(QJSValuePrivate* other) +{ + if (isJSBased()) { + // We can't compare these two values without binding to the same engine. + if (!other->isJSBased()) { + if (other->assignEngine(engine())) + return m_value->StrictEquals(other->m_value); + return false; + } + if (other->engine() != engine()) { + qWarning("QJSValue::strictlyEquals: cannot compare to a value created in a different engine"); + return false; + } + return m_value->StrictEquals(other->m_value); + } + if (isStringBased()) { + if (other->isStringBased()) + return *u.m_string == *(other->u.m_string); + if (other->isJSBased()) { + assignEngine(other->engine()); + return m_value->StrictEquals(other->m_value); + } + } + if (isNumberBased()) { + if (other->isJSBased()) { + assignEngine(other->engine()); + return m_value->StrictEquals(other->m_value); + } + if (m_state != other->m_state) + return false; + if (m_state == CNumber) + return u.m_number == other->u.m_number; + Q_ASSERT(m_state == CBool); + return u.m_bool == other->u.m_bool; + } + + if (!isValid() && !other->isValid()) + return true; + + return false; +} + +inline bool QJSValuePrivate::lessThan(QJSValuePrivate *other) const +{ + if (engine() != other->engine() && engine() && other->engine()) { + qWarning("QJSValue::lessThan: cannot compare to a value created in a different engine"); + return false; + } + + if (!isValid() || !other->isValid()) + return false; + + if (isString() && other->isString()) + return toString() < other->toString(); + + if (isObject() || other->isObject()) { + v8::HandleScope handleScope; + QV8Engine *eng = m_engine ? engine() : other->engine(); + // FIXME: lessThan can throw an exception which will be dropped by this code: + Q_ASSERT(eng); + eng->saveException(); + QScriptSharedDataPointer<QJSValuePrivate> cmp(eng->evaluate(QString::fromLatin1("(function(a,b){return a<b})"))); + Q_ASSERT(cmp->isFunction()); + v8::Handle<v8::Value> args[2]; + cmp->prepareArgumentsForCall(args, QJSValueList() << QJSValuePrivate::get(this) << QJSValuePrivate::get(other)); + QScriptSharedDataPointer<QJSValuePrivate> resultValue(cmp->call(0, 2, args)); + bool result = resultValue->toBool(); + eng->restoreException(); + return result; + } + + double nthis = toNumber(); + double nother = other->toNumber(); + if (qIsNaN(nthis) || qIsNaN(nother)) { + // Should return undefined in ECMA standard. + return false; + } + return nthis < nother; +} + +inline bool QJSValuePrivate::instanceOf(QJSValuePrivate* other) const +{ + if (!isObject() || !other->isFunction()) + return false; + if (engine() != other->engine()) { + qWarning("QJSValue::instanceof: cannot perform operation on a value created in a different engine"); + return false; + } + v8::HandleScope handleScope; + return instanceOf(v8::Handle<v8::Object>::Cast(other->m_value)); +} + +inline bool QJSValuePrivate::instanceOf(v8::Handle<v8::Object> other) const +{ + Q_ASSERT(isObject()); + Q_ASSERT(other->IsFunction()); + + v8::Handle<v8::Object> self = v8::Handle<v8::Object>::Cast(m_value); + v8::Handle<v8::Value> selfPrototype = self->GetPrototype(); + v8::Handle<v8::Value> otherPrototype = other->Get(v8::String::New("prototype")); + + while (!selfPrototype->IsNull()) { + if (selfPrototype->StrictEquals(otherPrototype)) + return true; + // In general a prototype can be an object or null, but in the loop it can't be null, so + // we can cast it safely. + selfPrototype = v8::Handle<v8::Object>::Cast(selfPrototype)->GetPrototype(); + } + return false; +} + +inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::prototype() const +{ + if (isObject()) { + v8::HandleScope handleScope; + return new QJSValuePrivate(engine(), v8::Handle<v8::Object>::Cast(m_value)->GetPrototype()); + } + return InvalidValue(); +} + +inline void QJSValuePrivate::setPrototype(QJSValuePrivate* prototype) +{ + if (isObject() && (prototype->isObject() || prototype->isNull())) { + if (engine() != prototype->engine()) { + if (prototype->engine()) { + qWarning("QJSValue::setPrototype() failed: cannot set a prototype created in a different engine"); + return; + } + prototype->assignEngine(engine()); + } + v8::HandleScope handleScope; + if (!v8::Handle<v8::Object>::Cast(m_value)->SetPrototype(*prototype)) + qWarning("QJSValue::setPrototype() failed: cyclic prototype value"); + } +} + +inline void QJSValuePrivate::setProperty(const QString& name, QJSValuePrivate* value, uint attribs) +{ + if (!isObject()) + return; + v8::HandleScope handleScope; + setProperty(QJSConverter::toString(name), value, attribs); +} + +inline void QJSValuePrivate::setProperty(v8::Handle<v8::String> name, QJSValuePrivate* value, uint attribs) +{ + if (!isObject()) + return; + + if (!value->isJSBased()) + value->assignEngine(engine()); + + if (!value->isValid()) { + // Remove the property. + v8::HandleScope handleScope; + v8::TryCatch tryCatch; + v8::Handle<v8::Object> recv(v8::Object::Cast(*m_value)); +// if (attribs & QJSValue::PropertyGetter && !(attribs & QJSValue::PropertySetter)) { +// v8::Local<v8::Object> descriptor = engine()->originalGlobalObject()->getOwnPropertyDescriptor(recv, name); +// if (!descriptor.IsEmpty()) { +// v8::Local<v8::Value> setter = descriptor->Get(v8::String::New("set")); +// if (!setter.IsEmpty() && !setter->IsUndefined()) { +// recv->Delete(name); +// engine()->originalGlobalObject()->defineGetterOrSetter(recv, name, setter, QJSValue::PropertySetter); +// if (tryCatch.HasCaught()) +// engine()->setException(tryCatch.Exception(), tryCatch.Message()); +// return; +// } +// } +// } else if (attribs & QJSValue::PropertySetter && !(attribs & QJSValue::PropertyGetter)) { +// v8::Local<v8::Object> descriptor = engine()->originalGlobalObject()->getOwnPropertyDescriptor(recv, name); +// if (!descriptor.IsEmpty()) { +// v8::Local<v8::Value> getter = descriptor->Get(v8::String::New("get")); +// if (!getter.IsEmpty() && !getter->IsUndefined()) { +// recv->Delete(name); +// engine()->originalGlobalObject()->defineGetterOrSetter(recv, name, getter, QJSValue::PropertyGetter); +// if (tryCatch.HasCaught()) +// engine()->setException(tryCatch.Exception(), tryCatch.Message()); +// return; +// } +// } +// } + recv->Delete(name); + if (tryCatch.HasCaught()) + engine()->setException(tryCatch.Exception(), tryCatch.Message()); + return; + } + + if (engine() != value->engine()) { + qWarning("QJSValue::setProperty(%s) failed: " + "cannot set value created in a different engine", + qPrintable(QJSConverter::toString(name))); + return; + } + + v8::TryCatch tryCatch; +// if (attribs & (QJSValue::PropertyGetter | QJSValue::PropertySetter)) { +// engine()->originalGlobalObject()->defineGetterOrSetter(*this, name, value->m_value, attribs); +// } else { + v8::Object::Cast(*m_value)->Set(name, value->m_value, v8::PropertyAttribute(attribs & QJSConverter::PropertyAttributeMask)); +// } + if (tryCatch.HasCaught()) + engine()->setException(tryCatch.Exception(), tryCatch.Message()); +} + +inline void QJSValuePrivate::setProperty(quint32 index, QJSValuePrivate* value, uint attribs) +{ + // FIXME this method should by integrated with other overloads to use the same code patch. + // for now it is not possible as v8 doesn't allow to set property attributes using index based api. + + if (!isObject()) + return; + + if (attribs) { + // FIXME we dont need to convert index to a string. + //Object::Set(int,value) do not take attributes. + setProperty(QString::number(index), value, attribs); + return; + } + + if (!value->isJSBased()) + value->assignEngine(engine()); + + if (!value->isValid()) { + // Remove the property. + v8::HandleScope handleScope; + v8::TryCatch tryCatch; + v8::Object::Cast(*m_value)->Delete(index); + if (tryCatch.HasCaught()) + engine()->setException(tryCatch.Exception(), tryCatch.Message()); + return; + } + + if (engine() != value->engine()) { + qWarning("QJSValue::setProperty() failed: cannot set value created in a different engine"); + return; + } + + v8::HandleScope handleScope; + v8::TryCatch tryCatch; + v8::Object::Cast(*m_value)->Set(index, value->m_value); + if (tryCatch.HasCaught()) + engine()->setException(tryCatch.Exception(), tryCatch.Message()); +} + +inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(const QString& name) const +{ + if (!name.length()) + return InvalidValue(); + + v8::HandleScope handleScope; + return property(QJSConverter::toString(name)); +} + +inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(v8::Handle<v8::String> name) const +{ + Q_ASSERT(!name.IsEmpty()); + if (!isObject()) + return InvalidValue(); + return property<>(name); +} + +inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(quint32 index) const +{ + if (!isObject()) + return InvalidValue(); + return property<>(index); +} + +template<typename T> +inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(T name) const +{ + Q_ASSERT(isObject()); + v8::HandleScope handleScope; + v8::Handle<v8::Object> self(v8::Object::Cast(*m_value)); + + v8::TryCatch tryCatch; + v8::Handle<v8::Value> result = self->Get(name); + if (tryCatch.HasCaught()) { + result = tryCatch.Exception(); + engine()->setException(result, tryCatch.Message()); + return new QJSValuePrivate(engine(), result); + } + if (result.IsEmpty() || (result->IsUndefined() && !self->Has(name))) { + // In QtScript we make a distinction between a property that exists and has value undefined, + // and a property that doesn't exist; in the latter case, we should return an invalid value. + return InvalidValue(); + } + return new QJSValuePrivate(engine(), result); +} + +inline bool QJSValuePrivate::deleteProperty(const QString& name) +{ + if (!isObject()) + return false; + + v8::HandleScope handleScope; + v8::Handle<v8::Object> self(v8::Handle<v8::Object>::Cast(m_value)); + return self->Delete(QJSConverter::toString(name)); +} + +inline QJSValue::PropertyFlags QJSValuePrivate::propertyFlags(const QString& name) const +{ + if (!isObject()) + return QJSValue::PropertyFlags(0); + + v8::HandleScope handleScope; + return engine()->getPropertyFlags(v8::Handle<v8::Object>::Cast(m_value), QJSConverter::toString(name)); +} + +inline QJSValue::PropertyFlags QJSValuePrivate::propertyFlags(v8::Handle<v8::String> name) const +{ + if (!isObject()) + return QJSValue::PropertyFlags(0); + + v8::HandleScope handleScope; + return engine()->getPropertyFlags(v8::Handle<v8::Object>::Cast(m_value), name); +} + +inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::call(QJSValuePrivate* thisObject, const QJSValueList& args) +{ + if (!isCallable()) + return InvalidValue(); + + v8::HandleScope handleScope; + + // Convert all arguments and bind to the engine. + int argc = args.size(); + QVarLengthArray<v8::Handle<v8::Value>, 8> argv(argc); + if (!prepareArgumentsForCall(argv.data(), args)) { + qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine"); + return InvalidValue(); + } + + return call(thisObject, argc, argv.data()); +} + +QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::call(QJSValuePrivate* thisObject, int argc, v8::Handle<v8::Value> *argv) +{ + QV8Engine *e = engine(); + + v8::Handle<v8::Object> recv; + + if (!thisObject || !thisObject->isObject()) { + recv = v8::Handle<v8::Object>(v8::Object::Cast(*e->global())); + } else { + if (!thisObject->assignEngine(e)) { + qWarning("QJSValue::call() failed: cannot call function with thisObject created in a different engine"); + return InvalidValue(); + } + + recv = v8::Handle<v8::Object>(v8::Object::Cast(*thisObject->m_value)); + } + + if (argc < 0) { + v8::Local<v8::Value> exeption = v8::Exception::TypeError(v8::String::New("Arguments must be an array")); + e->setException(exeption); + return new QJSValuePrivate(e, exeption); + } + + v8::TryCatch tryCatch; + v8::Handle<v8::Value> result = v8::Object::Cast(*m_value)->CallAsFunction(recv, argc, argv); + + if (result.IsEmpty()) { + result = tryCatch.Exception(); + // TODO: figure out why v8 doesn't always produce an exception value. + //Q_ASSERT(!result.IsEmpty()); + if (result.IsEmpty()) + result = v8::Exception::Error(v8::String::New("missing exception value")); + e->setException(result, tryCatch.Message()); + } + + return new QJSValuePrivate(e, result); +} + +inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::construct(int argc, v8::Handle<v8::Value> *argv) +{ + QV8Engine *e = engine(); + + if (argc < 0) { + v8::Local<v8::Value> exeption = v8::Exception::TypeError(v8::String::New("Arguments must be an array")); + e->setException(exeption); + return new QJSValuePrivate(e, exeption); + } + + v8::TryCatch tryCatch; + v8::Handle<v8::Value> result = v8::Object::Cast(*m_value)->CallAsConstructor(argc, argv); + + if (result.IsEmpty()) { + result = tryCatch.Exception(); + e->setException(result, tryCatch.Message()); + } + + return new QJSValuePrivate(e, result); +} + +inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::construct(const QJSValueList& args) +{ + if (!isCallable()) + return InvalidValue(); + + v8::HandleScope handleScope; + + // Convert all arguments and bind to the engine. + int argc = args.size(); + QVarLengthArray<v8::Handle<v8::Value>, 8> argv(argc); + if (!prepareArgumentsForCall(argv.data(), args)) { + qWarning("QJSValue::construct() failed: cannot construct function with argument created in a different engine"); + return InvalidValue(); + } + + return construct(argc, argv.data()); +} + +/*! \internal + * Make sure this value is associated with a v8 value belogning to this engine. + * If the value was invalid, or belogning to another engine, return false. + */ +bool QJSValuePrivate::assignEngine(QV8Engine* engine) +{ + Q_ASSERT(engine); + v8::HandleScope handleScope; + switch (m_state) { + case Invalid: + return false; + case CBool: + m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(u.m_bool)); + break; + case CString: + m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(*u.m_string)); + delete u.m_string; + break; + case CNumber: + m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(u.m_number)); + break; + case CNull: + m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(QJSValue::NullValue)); + break; + case CUndefined: + m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(QJSValue::UndefinedValue)); + break; + default: + if (this->engine() == engine) + return true; + else if (!isJSBased()) + Q_ASSERT_X(!isJSBased(), "assignEngine()", "Not all states are included in the previous switch statement."); + else + qWarning("JSValue can't be rassigned to an another engine."); + return false; + } + m_engine = engine; + m_state = JSValue; + + m_engine->registerValue(this); + return true; +} + +/*! + \internal + reinitialize this value to an invalid value. +*/ +void QJSValuePrivate::reinitialize() +{ + if (isJSBased()) { + m_engine->unregisterValue(this); + m_value.Dispose(); + m_value.Clear(); + } else if (isStringBased()) { + delete u.m_string; + } + m_engine = 0; + m_state = Invalid; +} + +/*! + \internal + reinitialize this value to an JSValue. +*/ +void QJSValuePrivate::reinitialize(QV8Engine* engine, v8::Handle<v8::Value> value) +{ + Q_ASSERT_X(this != InvalidValue(), Q_FUNC_INFO, "static invalid can't be reinitialized to a different value"); + if (isJSBased()) { + m_value.Dispose(); + // avoid double registration + m_engine->unregisterValue(this); + } else if (isStringBased()) { + delete u.m_string; + } + m_engine = engine; + m_state = JSValue; + m_value = v8::Persistent<v8::Value>::New(value); + m_engine->registerValue(this); +} + +QV8Engine* QJSValuePrivate::engine() const +{ + return m_engine; +} + +inline QJSValuePrivate::operator v8::Handle<v8::Value>() const +{ + Q_ASSERT(isJSBased()); + return m_value; +} + +inline QJSValuePrivate::operator v8::Handle<v8::Object>() const +{ + Q_ASSERT(isObject()); + return v8::Handle<v8::Object>::Cast(m_value); +} + +/*! + * Return a v8::Handle, assign to the engine if needed. + */ +v8::Handle<v8::Value> QJSValuePrivate::asV8Value(QV8Engine* engine) +{ + if (!m_engine) { + if (!assignEngine(engine)) + return v8::Handle<v8::Value>(); + } + Q_ASSERT(isJSBased()); + return m_value; +} + +/*! + \internal + Returns true if QSV have an engine associated. +*/ +bool QJSValuePrivate::isJSBased() const +{ +#ifndef QT_NO_DEBUG + // internals check. + if (m_state >= JSValue) + Q_ASSERT(!m_value.IsEmpty()); + else + Q_ASSERT(m_value.IsEmpty()); +#endif + return m_state >= JSValue; +} + +/*! + \internal + Returns true if current value of QSV is placed in m_number. +*/ +bool QJSValuePrivate::isNumberBased() const { return m_state == CNumber || m_state == CBool; } + +/*! + \internal + Returns true if current value of QSV is placed in m_string. +*/ +bool QJSValuePrivate::isStringBased() const { return m_state == CString; } + +/*! + \internal + Converts arguments and bind them to the engine. + \attention argv should be big enough +*/ +inline bool QJSValuePrivate::prepareArgumentsForCall(v8::Handle<v8::Value> argv[], const QJSValueList& args) const +{ + QJSValueList::const_iterator i = args.constBegin(); + for (int j = 0; i != args.constEnd(); j++, i++) { + QJSValuePrivate* value = QJSValuePrivate::get(*i); + if ((value->isJSBased() && engine() != value->engine()) + || (!value->isJSBased() && value->isValid() && !value->assignEngine(engine()))) + // Different engines are not allowed! + return false; + if (value->isValid()) + argv[j] = *value; + else + argv[j] = engine()->makeJSValue(QJSValue::UndefinedValue); + } + return true; +} + +QT_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/v8/qjsvalue_p.h b/src/declarative/qml/v8/qjsvalue_p.h new file mode 100644 index 0000000000..7b2a001f97 --- /dev/null +++ b/src/declarative/qml/v8/qjsvalue_p.h @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-ONLY$ +** GNU Lesser General Public License Usage +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QJSVALUE_P_H +#define QJSVALUE_P_H + +#include <private/qv8_p.h> + +#include <QtCore/qbytearray.h> +#include <QtCore/qdatetime.h> +#include <QtCore/qmath.h> +#include <QtCore/qvarlengtharray.h> +#include <qdebug.h> + +#include "qscripttools_p.h" +#include "qscriptshareddata_p.h" +#include "qjsvalue.h" + +QT_BEGIN_NAMESPACE + +/*! + \internal + \class QJSValuePrivate +*/ +class QJSValuePrivate + : public QSharedData + , public QScriptLinkedNode +{ +public: + inline QJSValuePrivate(); + inline static QJSValuePrivate* get(const QJSValue& q); + inline static QJSValue get(const QJSValuePrivate* d); + inline static QJSValue get(QJSValuePrivate* d); + inline static QJSValue get(QScriptPassPointer<QJSValuePrivate> d); + inline ~QJSValuePrivate(); + + inline QJSValuePrivate(bool value); + inline QJSValuePrivate(int value); + inline QJSValuePrivate(uint value); + inline QJSValuePrivate(double value); + inline QJSValuePrivate(const QString& value); + inline QJSValuePrivate(QJSValue::SpecialValue value); + + inline QJSValuePrivate(QV8Engine *engine, bool value); + inline QJSValuePrivate(QV8Engine *engine, int value); + inline QJSValuePrivate(QV8Engine *engine, uint value); + inline QJSValuePrivate(QV8Engine *engine, double value); + inline QJSValuePrivate(QV8Engine *engine, const QString& value); + inline QJSValuePrivate(QV8Engine *engine, QJSValue::SpecialValue value); + inline QJSValuePrivate(QV8Engine *engine, v8::Handle<v8::Value>); + inline void reinitialize(); + inline void reinitialize(QV8Engine *engine, v8::Handle<v8::Value> value); + + inline bool toBool() const; + inline double toNumber() const; + inline QScriptPassPointer<QJSValuePrivate> toObject() const; + inline QScriptPassPointer<QJSValuePrivate> toObject(QV8Engine *engine) const; + inline QString toString() const; + inline double toInteger() const; + inline qint32 toInt32() const; + inline quint32 toUInt32() const; + inline quint16 toUInt16() const; + inline QDateTime toDataTime() const; + inline QRegExp toRegExp() const; + inline QObject *toQObject() const; + inline QVariant toVariant() const; + + inline bool isArray() const; + inline bool isBool() const; + inline bool isCallable() const; + inline bool isError() const; + inline bool isFunction() const; + inline bool isNull() const; + inline bool isNumber() const; + inline bool isObject() const; + inline bool isString() const; + inline bool isUndefined() const; + inline bool isValid() const; + inline bool isVariant() const; + inline bool isDate() const; + inline bool isRegExp() const; + inline bool isQObject() const; + + inline bool equals(QJSValuePrivate* other); + inline bool strictlyEquals(QJSValuePrivate* other); + inline bool lessThan(QJSValuePrivate *other) const; + inline bool instanceOf(QJSValuePrivate*) const; + inline bool instanceOf(v8::Handle<v8::Object> other) const; + + inline QScriptPassPointer<QJSValuePrivate> prototype() const; + inline void setPrototype(QJSValuePrivate* prototype); + + inline void setProperty(const QString &name, QJSValuePrivate *value, uint attribs = 0); + inline void setProperty(v8::Handle<v8::String> name, QJSValuePrivate *value, uint attribs = 0); + inline void setProperty(quint32 index, QJSValuePrivate* value, uint attribs = 0); + inline QScriptPassPointer<QJSValuePrivate> property(const QString& name) const; + inline QScriptPassPointer<QJSValuePrivate> property(v8::Handle<v8::String> name) const; + inline QScriptPassPointer<QJSValuePrivate> property(quint32 index) const; + template<typename T> + inline QScriptPassPointer<QJSValuePrivate> property(T name) const; + inline bool deleteProperty(const QString& name); + inline QJSValue::PropertyFlags propertyFlags(const QString& name) const; + inline QJSValue::PropertyFlags propertyFlags(v8::Handle<v8::String> name) const; + + inline QScriptPassPointer<QJSValuePrivate> call(QJSValuePrivate* thisObject, const QJSValueList& args); + inline QScriptPassPointer<QJSValuePrivate> call(QJSValuePrivate* thisObject, const QJSValue& arguments); + inline QScriptPassPointer<QJSValuePrivate> call(QJSValuePrivate* thisObject, int argc, v8::Handle< v8::Value >* argv); + inline QScriptPassPointer<QJSValuePrivate> construct(int argc, v8::Handle<v8::Value> *argv); + inline QScriptPassPointer<QJSValuePrivate> construct(const QJSValueList& args); + inline QScriptPassPointer<QJSValuePrivate> construct(const QJSValue& arguments); + + inline bool assignEngine(QV8Engine *engine); + inline QV8Engine *engine() const; + + inline operator v8::Handle<v8::Value>() const; + inline operator v8::Handle<v8::Object>() const; + inline v8::Handle<v8::Value> asV8Value(QV8Engine *engine); +private: + QV8Engine *m_engine; + + // Please, update class documentation when you change the enum. + enum State { + Invalid = 0, + CString = 0x1000, + CNumber, + CBool, + CNull, + CUndefined, + JSValue = 0x2000, // V8 values are equal or higher then this value. + // JSPrimitive, + // JSObject + } m_state; + + union CValue { + bool m_bool; + double m_number; + QString* m_string; + + CValue() : m_number(0) {} + CValue(bool value) : m_bool(value) {} + CValue(int number) : m_number(number) {} + CValue(uint number) : m_number(number) {} + CValue(double number) : m_number(number) {} + CValue(QString* string) : m_string(string) {} + } u; + // v8::Persistent is not a POD, so can't be part of the union. + v8::Persistent<v8::Value> m_value; + + Q_DISABLE_COPY(QJSValuePrivate) + inline bool isJSBased() const; + inline bool isNumberBased() const; + inline bool isStringBased() const; + inline bool prepareArgumentsForCall(v8::Handle<v8::Value> argv[], const QJSValueList& arguments) const; +}; + +// This template is used indirectly by the Q_GLOBAL_STATIC macro below +template<> +class QGlobalStaticDeleter<QJSValuePrivate> +{ +public: + QGlobalStatic<QJSValuePrivate> &globalStatic; + QGlobalStaticDeleter(QGlobalStatic<QJSValuePrivate> &_globalStatic) + : globalStatic(_globalStatic) + { + globalStatic.pointer->ref.ref(); + } + + inline ~QGlobalStaticDeleter() + { + if (!globalStatic.pointer->ref.deref()) { // Logic copy & paste from SharedDataPointer + delete globalStatic.pointer; + } + globalStatic.pointer = 0; + globalStatic.destroyed = true; + } +}; + +Q_GLOBAL_STATIC(QJSValuePrivate, InvalidValue) + +QT_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/v8/qjsvalueiterator.cpp b/src/declarative/qml/v8/qjsvalueiterator.cpp new file mode 100644 index 0000000000..ca9123f0c0 --- /dev/null +++ b/src/declarative/qml/v8/qjsvalueiterator.cpp @@ -0,0 +1,294 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-ONLY$ +** GNU Lesser General Public License Usage +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qjsvalueiterator.h" + +#include "qscriptisolate_p.h" +#include "qjsvalue_p.h" +#include "qv8engine_p.h" +#include "qscript_impl_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QJSValueIterator + + \brief The QJSValueIterator class provides a Java-style iterator for QJSValue. + + \ingroup script + + + The QJSValueIterator constructor takes a QJSValue as + argument. After construction, the iterator is located at the very + beginning of the sequence of properties. Here's how to iterate over + all the properties of a QJSValue: + + \snippet doc/src/snippets/code/src_script_QJSValueIterator.cpp 0 + + The next() advances the iterator. The name(), value() and flags() + functions return the name, value and flags of the last item that was + jumped over. + + If you want to remove properties as you iterate over the + QJSValue, use remove(). If you want to modify the value of a + property, use setValue(). + + Note that QJSValueIterator only iterates over the QJSValue's + own properties; i.e. it does not follow the prototype chain. You can + use a loop like this to follow the prototype chain: + + \snippet doc/src/snippets/code/src_script_QJSValueIterator.cpp 1 + + Note that QJSValueIterator will not automatically skip over + properties that have the QJSValue::SkipInEnumeration flag set; + that flag only affects iteration in script code. If you want, you + can skip over such properties with code like the following: + + \snippet doc/src/snippets/code/src_script_QJSValueIterator.cpp 2 + + \sa QJSValue::property() +*/ + +using v8::Persistent; +using v8::Local; +using v8::Array; +using v8::String; +using v8::Handle; +using v8::Object; +using v8::Value; + +// FIXME (Qt5) This class should be refactored. It should use the common Iterator interface. +// FIXME it could be faster! +class QJSValueIteratorPrivate { +public: + inline QJSValueIteratorPrivate(const QJSValuePrivate* value); + inline ~QJSValueIteratorPrivate(); + + inline bool hasNext() const; + inline bool next(); + + inline QString name() const; + + inline QScriptPassPointer<QJSValuePrivate> value() const; + + inline bool isValid() const; + inline QV8Engine* engine() const; +private: + Q_DISABLE_COPY(QJSValueIteratorPrivate) + //void dump(QString) const; + + QScriptSharedDataPointer<QJSValuePrivate> m_object; + QList<v8::Persistent<v8::String> > m_names; + QMutableListIterator<v8::Persistent<v8::String> > m_iterator; +}; + +inline QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValuePrivate* value) + : m_object(const_cast<QJSValuePrivate*>(value)) + , m_iterator(m_names) +{ + Q_ASSERT(value); + QV8Engine *engine = m_object->engine(); + QScriptIsolate api(engine); + if (!m_object->isObject()) + m_object = 0; + else { + v8::HandleScope scope; + Handle<Value> tmp = *value; + Handle<Object> obj = Handle<Object>::Cast(tmp); + Local<Array> names; + + // FIXME we need newer V8! + //names = obj->GetOwnPropertyNames(); + names = engine->getOwnPropertyNames(obj); + + // it is suboptimal, it would be better to write iterator instead + uint32_t count = names->Length(); + Local<String> name; + m_names.reserve(count); // The count is the maximal count of values. + for (uint32_t i = count - 1; i < count; --i) { + name = names->Get(i)->ToString(); + m_names.append(v8::Persistent<v8::String>::New(name)); + } + + // Reinitialize the iterator. + m_iterator = m_names; + } +} + +inline QJSValueIteratorPrivate::~QJSValueIteratorPrivate() +{ + QMutableListIterator<v8::Persistent<v8::String> > it = m_names; + //FIXME: we need register this QJSVAlueIterator + if (engine()) { + while (it.hasNext()) { + it.next().Dispose(); + } + } else { + // FIXME leak ? + } +} + +inline bool QJSValueIteratorPrivate::hasNext() const +{ + //dump("hasNext()"); + return isValid() + ? m_iterator.hasNext() : false; +} + +inline bool QJSValueIteratorPrivate::next() +{ + //dump("next();"); + if (m_iterator.hasNext()) { + m_iterator.next(); + return true; + } + return false; +} + +inline QString QJSValueIteratorPrivate::name() const +{ + //dump("name"); + if (!isValid()) + return QString(); + + return QJSConverter::toString(m_iterator.value()); +} + +inline QScriptPassPointer<QJSValuePrivate> QJSValueIteratorPrivate::value() const +{ + //dump("value()"); + if (!isValid()) + return InvalidValue(); + + return m_object->property(m_iterator.value()); +} + +inline bool QJSValueIteratorPrivate::isValid() const +{ + bool result = m_object ? m_object->isValid() : false; + // We know that if this object is still valid then it is an object + // if this assumption is not correct then some other logic in this class + // have to be changed too. + Q_ASSERT(!result || m_object->isObject()); + return result; +} + +inline QV8Engine* QJSValueIteratorPrivate::engine() const +{ + return m_object ? m_object->engine() : 0; +} + +//void QJSValueIteratorPrivate::dump(QString fname) const +//{ +// qDebug() << " *** " << fname << " ***"; +// foreach (Persistent<String> name, m_names) { +// qDebug() << " - " << QJSConverter::toString(name); +// } +//} + +/*! + Constructs an iterator for traversing \a object. The iterator is + set to be at the front of the sequence of properties (before the + first property). +*/ +QJSValueIterator::QJSValueIterator(const QJSValue& object) + : d_ptr(new QJSValueIteratorPrivate(QJSValuePrivate::get(object))) +{} + +/*! + Destroys the iterator. +*/ +QJSValueIterator::~QJSValueIterator() +{} + +/*! + Returns true if there is at least one item ahead of the iterator + (i.e. the iterator is \e not at the back of the property sequence); + otherwise returns false. + + \sa next(), hasPrevious() +*/ +bool QJSValueIterator::hasNext() const +{ + Q_D(const QJSValueIterator); + QScriptIsolate api(d->engine()); + return d->hasNext(); +} + +/*! + Advances the iterator by one position. + + Calling this function on an iterator located at the back of the + container leads to undefined results. + + \sa hasNext(), previous(), name() +*/ +bool QJSValueIterator::next() +{ + Q_D(QJSValueIterator); + QScriptIsolate api(d->engine()); + return d->next(); +} + +/*! + Returns the name of the last property that was jumped over using + next() or previous(). + + \sa value(), flags() +*/ +QString QJSValueIterator::name() const +{ + Q_D(const QJSValueIterator); + QScriptIsolate api(d->engine()); + return d_ptr->name(); +} + + +/*! + Returns the value of the last property that was jumped over using + next() or previous(). + + \sa setValue(), name() +*/ +QJSValue QJSValueIterator::value() const +{ + Q_D(const QJSValueIterator); + QScriptIsolate api(d->engine()); + return QJSValuePrivate::get(d->value()); +} + + +/*! + Makes the iterator operate on \a object. The iterator is set to be + at the front of the sequence of properties (before the first + property). +*/ +QJSValueIterator& QJSValueIterator::operator=(QJSValue& object) +{ + Q_D(QJSValueIterator); + QScriptIsolate api(d->engine()); + d_ptr.reset(new QJSValueIteratorPrivate(QJSValuePrivate::get(object))); + return *this; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/v8/qjsvalueiterator.h b/src/declarative/qml/v8/qjsvalueiterator.h new file mode 100644 index 0000000000..1ec4d4b63b --- /dev/null +++ b/src/declarative/qml/v8/qjsvalueiterator.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-ONLY$ +** GNU Lesser General Public License Usage +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSCRIPTVALUEITERATOR_H +#define QSCRIPTVALUEITERATOR_H + +#include <QtDeclarative/qjsvalue.h> +#include <QtCore/qscopedpointer.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Script) + +class QString; + +class QJSValueIteratorPrivate; +class Q_SCRIPT_EXPORT QJSValueIterator +{ +public: + QJSValueIterator(const QJSValue &value); + ~QJSValueIterator(); + + bool hasNext() const; + bool next(); + + QString name() const; + + QJSValue value() const; + QJSValueIterator& operator=(QJSValue &value); + +private: + QScopedPointer<QJSValueIteratorPrivate> d_ptr; + + Q_DECLARE_PRIVATE(QJSValueIterator) + Q_DISABLE_COPY(QJSValueIterator) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSCRIPTVALUEITERATOR_H diff --git a/src/declarative/qml/v8/qscript_impl_p.h b/src/declarative/qml/v8/qscript_impl_p.h new file mode 100644 index 0000000000..e66b561efe --- /dev/null +++ b/src/declarative/qml/v8/qscript_impl_p.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-ONLY$ +** GNU Lesser General Public License Usage +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QSCRIPT_IMPL_P_H +#define QSCRIPT_IMPL_P_H + +#include "qv8engine_impl_p.h" +#include "qjsvalue_impl_p.h" + +#endif //QSCRIPT_IMPL_P_H diff --git a/src/declarative/qml/v8/qscriptisolate_p.h b/src/declarative/qml/v8/qscriptisolate_p.h new file mode 100644 index 0000000000..fa200c00b6 --- /dev/null +++ b/src/declarative/qml/v8/qscriptisolate_p.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-ONLY$ +** GNU Lesser General Public License Usage +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef APIPREAMBLE_P_H +#define APIPREAMBLE_P_H + +#include <private/qv8_p.h> +#include "qv8engine_p.h" + +QT_BEGIN_NAMESPACE + +/** + \internal + Class used to switch to the right isolate. It does the same thing as v8::Isolate::Scope but + it checks for a null engine. + \attention We decided to put context switching "up" which means that it should be as high + as possible on call stack. And it should be switched at most once per public API function call. +*/ +class QScriptIsolate { +public: + // OperationMode was introduced to reduce number of checking for a null engine pointer. If we + // know that given pointer is not null than we should pass NotNullEngine as constructor argument + // that would nicely remove checking on compilation time. + enum OperationMode {Default, NotNullEngine}; + inline QScriptIsolate(const QV8Engine *engine, const OperationMode mode = Default) + : m_engine(engine) + , m_mode(mode) + { + if (m_mode == NotNullEngine || m_engine) { + Q_ASSERT(m_engine); + m_engine->context()->Enter(); + } + } + + inline ~QScriptIsolate() + { + if (m_mode == NotNullEngine || m_engine) { + m_engine->context()->Exit(); + } + } + +private: + Q_DISABLE_COPY(QScriptIsolate); + const QV8Engine *m_engine; + const OperationMode m_mode; +}; + + +QT_END_NAMESPACE + +#endif // APIPREAMBLE_P_H diff --git a/src/declarative/qml/v8/qscriptoriginalglobalobject_p.h b/src/declarative/qml/v8/qscriptoriginalglobalobject_p.h new file mode 100644 index 0000000000..c46d0e37a0 --- /dev/null +++ b/src/declarative/qml/v8/qscriptoriginalglobalobject_p.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-ONLY$ +** GNU Lesser General Public License Usage +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSCRIPTORIGINALGLOBALOBJECT_P_H +#define QSCRIPTORIGINALGLOBALOBJECT_P_H + +#include "QtCore/qglobal.h" +#include "qjsvalue.h" + +#include <private/qv8_p.h> + +QT_BEGIN_NAMESPACE + +class QV8Engine; + +/*! + \internal + This class is a workaround for missing V8 API functionality. This class keeps all important + properties of an original (default) global object, so we can use it even if the global object was + changed. + + FIXME this class is a container for workarounds :-) it should be replaced by proper API calls. + + The class have to be created on the QV8Engine creation time (before any change got applied to + global object). + + \attention All methods (apart from constructor) assumes that a context and a scope are prepared correctly. +*/ +class QScriptOriginalGlobalObject +{ +public: + inline QScriptOriginalGlobalObject(const QV8Engine *engine, v8::Handle<v8::Context> context); + inline void destroy(); + + inline QJSValue::PropertyFlags getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property); + inline v8::Local<v8::Object> getOwnPropertyDescriptor(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property) const; + inline bool strictlyEquals(v8::Handle<v8::Object> object); +private: + Q_DISABLE_COPY(QScriptOriginalGlobalObject) + + // Copy of constructors and prototypes used in isType functions. + v8::Persistent<v8::Function> m_ownPropertyDescriptor; + v8::Persistent<v8::Object> m_globalObject; +}; + +QScriptOriginalGlobalObject::QScriptOriginalGlobalObject(const QV8Engine *engine, v8::Handle<v8::Context> context) +{ + // Please notice that engine is not fully initialized at this point. + + v8::Context::Scope contextScope(context); + + v8::HandleScope scope; + + m_globalObject = v8::Persistent<v8::Object>::New(context->Global()); + + v8::Local<v8::Object> objectConstructor = m_globalObject->Get(v8::String::New("Object"))->ToObject(); + Q_ASSERT(objectConstructor->IsObject()); + { // Initialize m_ownPropertyDescriptor. + v8::Local<v8::Value> ownPropertyDescriptor = objectConstructor->Get(v8::String::New("getOwnPropertyDescriptor")); + Q_ASSERT(!ownPropertyDescriptor.IsEmpty()); + m_ownPropertyDescriptor = v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(ownPropertyDescriptor)); + } +} + +/*! + \internal + QScriptOriginalGlobalObject lives as long as QV8Engine that keeps it. In ~QSEP + the v8 context is removed, so we need to remove our handlers before. to break this dependency + destroy method should be called before or insight QSEP destructor. +*/ +inline void QScriptOriginalGlobalObject::destroy() +{ + m_ownPropertyDescriptor.Dispose(); + m_globalObject.Dispose(); + // After this line this instance is unusable. +} + +inline QJSValue::PropertyFlags QScriptOriginalGlobalObject::getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property) +{ + Q_ASSERT(object->IsObject()); + Q_ASSERT(!property.IsEmpty()); + v8::Local<v8::Object> descriptor = getOwnPropertyDescriptor(object, property); + if (descriptor.IsEmpty()) { +// // Property isn't owned by this object. +// if (!(mode & QScriptValue::ResolvePrototype)) +// return 0; + v8::Local<v8::Value> prototype = object->GetPrototype(); + if (prototype->IsNull()) + return 0; + return getPropertyFlags(v8::Local<v8::Object>::Cast(prototype), property); + } + v8::Local<v8::String> writableName = v8::String::New("writable"); + v8::Local<v8::String> configurableName = v8::String::New("configurable"); + v8::Local<v8::String> enumerableName = v8::String::New("enumerable"); +// v8::Local<v8::String> getName = v8::String::New("get"); +// v8::Local<v8::String> setName = v8::String::New("set"); + + unsigned flags = 0; + + if (!descriptor->Get(configurableName)->BooleanValue()) + flags |= QJSValue::Undeletable; + if (!descriptor->Get(enumerableName)->BooleanValue()) + flags |= QJSValue::SkipInEnumeration; + + //"writable" is only a property of the descriptor if it is not an accessor + if (descriptor->Has(writableName)) { + if (!descriptor->Get(writableName)->BooleanValue()) + flags |= QJSValue::ReadOnly; + } else { +// if (descriptor->Get(getName)->IsObject()) +// flags |= QScriptValue::PropertyGetter; +// if (descriptor->Get(setName)->IsObject()) +// flags |= QScriptValue::PropertySetter; + } + + return QJSValue::PropertyFlag(flags); +} + +inline v8::Local<v8::Object> QScriptOriginalGlobalObject::getOwnPropertyDescriptor(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property) const +{ + Q_ASSERT(object->IsObject()); + Q_ASSERT(!property.IsEmpty()); + // FIXME do we need try catch here? + v8::Handle<v8::Value> argv[] = {object, property}; + v8::Local<v8::Value> descriptor = m_ownPropertyDescriptor->Call(m_globalObject, /* argc */ 2, argv); + if (descriptor.IsEmpty() || !descriptor->IsObject()) + return v8::Local<v8::Object>(); + return v8::Local<v8::Object>::Cast(descriptor); +} + +inline bool QScriptOriginalGlobalObject::strictlyEquals(v8::Handle<v8::Object> object) +{ + return m_globalObject->GetPrototype()->StrictEquals(object); +} + +QT_END_NAMESPACE + +#endif diff --git a/src/declarative/qml/v8/qscriptshareddata_p.h b/src/declarative/qml/v8/qscriptshareddata_p.h new file mode 100644 index 0000000000..6604b10e32 --- /dev/null +++ b/src/declarative/qml/v8/qscriptshareddata_p.h @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-ONLY$ +** GNU Lesser General Public License Usage +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QSCRIPTSHAREDDATA_P_H +#define QSCRIPTSHAREDDATA_P_H + +#include "qglobal.h" +#include "qshareddata.h" + +QT_BEGIN_NAMESPACE + +/*! + \internal + This class should have the same interface as the QSharedData, but implementation doesn't + need to be thread safe, so atomic ref count was replaced by normal integer value. +*/ +class QScriptSharedData +{ +public: + class ReferenceCounter { + // FIXME shouldn't it be uint or something longer? + mutable int m_ref; + ReferenceCounter(int ref) : m_ref(ref) {} + ~ReferenceCounter() { Q_ASSERT_X(!m_ref, Q_FUNC_INFO, "Memory problem found"); } + public: + bool ref() { return ++m_ref; } + bool deref() { return --m_ref; } + friend class QScriptSharedData; + }; + + ReferenceCounter ref; + inline QScriptSharedData() : ref(0) { } + +private: + Q_DISABLE_COPY(QScriptSharedData) +}; + + +template <class T> class QScriptPassPointer; + +// FIXME: that could be reimplemented to not check for a null value. +template<class T> +class QScriptSharedDataPointer : public QExplicitlySharedDataPointer<T> +{ +public: + inline QScriptSharedDataPointer() {} + explicit QScriptSharedDataPointer(QScriptPassPointer<T> data) : QExplicitlySharedDataPointer<T>(data.give()) {} + explicit QScriptSharedDataPointer(T *data) : QExplicitlySharedDataPointer<T>(data) {} + + inline QScriptSharedDataPointer<T> &operator=(const QScriptPassPointer<T> &other) + { + this->QExplicitlySharedDataPointer<T>::operator =(other.give()); + return *this; + } + inline QScriptSharedDataPointer<T> &operator=(T *other) + { + this->QExplicitlySharedDataPointer<T>::operator =(other); + return *this; + } +}; + +// FIXME: that could be reimplemented to not check for a null value. +template <class T> +class QScriptPassPointer { +public: + QScriptPassPointer(T *data) : m_ptr(data) {} + inline QScriptPassPointer() { m_ptr = 0; } + inline QScriptPassPointer(const QScriptPassPointer<T> &other) : m_ptr(other.give()) {} + inline ~QScriptPassPointer() { Q_ASSERT_X(!m_ptr, Q_FUNC_INFO, "Ownership of the QScriptPassPointer hasn't been taken"); } + + inline T &operator*() const { return *m_ptr; } + inline T *operator->() { return m_ptr; } + inline T *operator->() const { return m_ptr; } + inline T *data() const { return m_ptr; } + inline const T *constData() const { return m_ptr; } + + inline bool operator==(const QScriptPassPointer<T> &other) const { return m_ptr == other.m_ptr; } + inline bool operator!=(const QScriptPassPointer<T> &other) const { return m_ptr != other.m_ptr; } + inline bool operator==(const QScriptSharedDataPointer<T> &other) const { return m_ptr == other.m_ptr; } + inline bool operator!=(const QScriptSharedDataPointer<T> &other) const { return m_ptr != other.m_ptr; } + inline bool operator==(const T *ptr) const { return m_ptr == ptr; } + inline bool operator!=(const T *ptr) const { return m_ptr != ptr; } + + inline operator bool () const { return m_ptr != 0; } + inline bool operator!() const { return !m_ptr; } + + inline QScriptPassPointer<T> & operator=(const QScriptPassPointer<T> &other) + { + if (other.m_ptr != m_ptr) { + if (m_ptr) + delete m_ptr; + m_ptr = other.give(); + } + return *this; + } + + inline QScriptPassPointer &operator=(T *other) + { + if (other != m_ptr) { + if (m_ptr) + delete m_ptr; + m_ptr = other; + } + return *this; + } + + inline T* give() const + { + T* result = m_ptr; + m_ptr = 0; + return result; + } + +private: + mutable T* m_ptr; +}; + +QT_END_NAMESPACE + +#endif // QSCRIPTSHAREDDATA_P_H diff --git a/src/declarative/qml/v8/qscripttools_p.h b/src/declarative/qml/v8/qscripttools_p.h new file mode 100644 index 0000000000..f74fbab83f --- /dev/null +++ b/src/declarative/qml/v8/qscripttools_p.h @@ -0,0 +1,216 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-ONLY$ +** GNU Lesser General Public License Usage +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QSCRIPTTOOLS_P_H +#define QSCRIPTTOOLS_P_H + +#include <qdebug.h> + +QT_BEGIN_NAMESPACE + +template<class T> +class QScriptBagContainer; + +/*! + \internal + \interface + Helper class for a container. The purpuse of it is to add two pointer properties to a class + inheriting this class without bloating an interface. + + This class exist only as a memory storage implementation. The only way to use it is to inherit it. +*/ +class QScriptLinkedNode +{ +protected: + QScriptLinkedNode() + : m_next(0) + , m_prev(0) + {} + + ~QScriptLinkedNode() + { + Q_ASSERT_X(!isUsed(), Q_FUNC_INFO, "Destorying QScriptLinkedNode instance that still is in a container"); + } + +private: + bool isUsed() const + { + return m_next || m_prev; + } + +#if defined(Q_NO_TEMPLATE_FRIENDS) +public: +#else + template<class T> + friend class QScriptBagContainer; +#endif + QScriptLinkedNode *m_next; + QScriptLinkedNode *m_prev; +}; + +/*! + \internal + The QScriptBagContainer is a simple, low level, set like container for a pointer type castable to + QScriptLinkedNode*. + Algorithms complexity: + put: O(1) + get: O(1) + forEach: O(n) + \note This container doesn't take ownership of pointed values. + \attention All values have to be unique. +*/ +template<class T> +class QScriptBagContainer +{ +public: + QScriptBagContainer() + : m_first(0) + {} + + /*! + \internal + Add a this \a value to this container + */ + void insert(T* value) + { + //dump(Q_FUNC_INFO, value); + Q_ASSERT_X(!contains(value), Q_FUNC_INFO, "Can't insert a value which is in the bag already"); + QScriptLinkedNode* v = static_cast<QScriptLinkedNode*>(value); + Q_ASSERT(v); + Q_ASSERT_X(!v->m_next && !v->m_prev, Q_FUNC_INFO, "Can't insert a value which is in an another bag"); + + if (m_first) + m_first->m_prev = v; + + v->m_next = m_first; + v->m_prev = 0; + m_first = v; + } + + /*! + \internal + Remove this \a value from this container + */ + void remove(T* value) + { + //dump(Q_FUNC_INFO, value); + QScriptLinkedNode* v = static_cast<QScriptLinkedNode*>(value); + Q_ASSERT(v); + + if (!v->m_next && !v->m_prev && m_first != v) { + // ignore that value as it is not registered at all + // FIXME: That may be optimized out if unregister call is removed from ~QtDataBase + return; + } + + Q_ASSERT_X(contains(value), Q_FUNC_INFO, "Can't remove a value which is not in the bag"); + Q_ASSERT(v->m_prev || (m_first == v && !v->m_prev)); + + if (v->m_next) + v->m_next->m_prev= v->m_prev; + + if (v->m_prev) + v->m_prev->m_next = v->m_next; + else + m_first = v->m_next; + // reset removed value + v->m_next = v->m_prev = 0; + } + + /*! + \internal + Call \a fun for each element in this container. Fun should accept T* as a parameter. + \note In general it is not allowed to change this container by calling put() or get() unless + given value is the same as currently procceded by forEach. + */ + template<class Functor> + void forEach(Functor fun) + { + //dump(Q_FUNC_INFO); + QScriptLinkedNode *i = m_first; + QScriptLinkedNode *tmp; + while (i) { + tmp = i; + i = i->m_next; + fun(static_cast<T*>(tmp)); + } + } + + /*! + \internal + Clear this container. + */ + void clear() + { + m_first = 0; + } + + /*! + \internal + Returns true if this container is empty; false otherwise. + */ + bool isEmpty() const + { + return !m_first; + } + +// void dump(const char* msg, T* obj = 0) const +// { +// qDebug() << msg << obj; +// qDebug() << m_first; +// QScriptLinkedNode *i = m_first; +// while (i) { +// qDebug() <<" - " << i << "(" << i->m_prev << ", " << i->m_next <<")"; +// i = i->m_next; +// } +// } + +private: + bool contains(T *value) const + { + QScriptLinkedNode *i = m_first; + while (i) { + if (static_cast<T*>(i) == value) + return true; + i = i->m_next; + } + return false; + } + QScriptLinkedNode *m_first; +}; + +QT_END_NAMESPACE + +#endif //QSCRIPTTOOLS_P_H diff --git a/src/declarative/qml/v8/qv8bindings.cpp b/src/declarative/qml/v8/qv8bindings.cpp index 4f5543e690..c45274a97f 100644 --- a/src/declarative/qml/v8/qv8bindings.cpp +++ b/src/declarative/qml/v8/qv8bindings.cpp @@ -129,7 +129,7 @@ void QV8BindingsPrivate::Binding::update(QDeclarativePropertyPrivate::WriteFlags ep->referenceScarceResources(); v8::HandleScope handle_scope; - v8::Context::Scope scope(ep->v8engine.context()); + v8::Context::Scope scope(ep->v8engine()->context()); v8::Local<v8::Value> result = evaluate(v8::Handle<v8::Function>::Cast(parent->functions->Get(index)), &isUndefined); diff --git a/src/declarative/qml/v8/qv8engine.cpp b/src/declarative/qml/v8/qv8engine.cpp index 0294a60871..acbfb92b15 100644 --- a/src/declarative/qml/v8/qv8engine.cpp +++ b/src/declarative/qml/v8/qv8engine.cpp @@ -49,6 +49,7 @@ #include <private/qdeclarativeengine_p.h> #include <private/qdeclarativecomponent_p.h> #include <private/qdeclarativestringconverters_p.h> +#include <private/qdeclarativeapplication_p.h> #include <QtDeclarative/qdeclarativecomponent.h> @@ -58,10 +59,15 @@ #include <QtCore/qnumeric.h> #include <QtGui/qdesktopservices.h> #include <QtGui/qfontdatabase.h> -#include <private/qdeclarativeapplication_p.h> #include <private/qdeclarativexmlhttprequest_p.h> #include <private/qdeclarativesqldatabase_p.h> +#include "qscript_impl_p.h" + +Q_DECLARE_METATYPE(QJSValue) +Q_DECLARE_METATYPE(QList<int>) + + // XXX TODO: Need to check all the global functions will also work in a worker script where the // QDeclarativeEngine is not available QT_BEGIN_NAMESPACE @@ -94,9 +100,41 @@ static bool ObjectComparisonCallback(v8::Local<v8::Object> lhs, v8::Local<v8::Ob return false; } -QV8Engine::QV8Engine() -: m_xmlHttpRequestData(0), m_sqlDatabaseData(0), m_listModelData(0) +QV8Engine::QV8Engine(QJSEngine* qq, QJSEngine::ContextOwnership ownership) + : q(qq) + , m_engine(0) + , m_ownsV8Context(ownership == QJSEngine::CreateNewContext) + , m_context((ownership == QJSEngine::CreateNewContext) ? v8::Context::New() : v8::Persistent<v8::Context>::New(v8::Context::GetCurrent())) + , m_originalGlobalObject(this, m_context) + , m_xmlHttpRequestData(0) + , m_sqlDatabaseData(0) + , m_listModelData(0) { + qMetaTypeId<QJSValue>(); + qMetaTypeId<QList<int> >(); + + QByteArray v8args = qgetenv("V8ARGS"); + if (!v8args.isEmpty()) + v8::V8::SetFlagsFromString(v8args.constData(), v8args.length()); + + v8::HandleScope handle_scope; + qPersistentRegister(m_context); + v8::Context::Scope context_scope(m_context); + + v8::V8::SetUserObjectComparisonCallbackFunction(ObjectComparisonCallback); + + m_stringWrapper.init(); + m_contextWrapper.init(this); + m_qobjectWrapper.init(this); + m_typeWrapper.init(this); + m_listWrapper.init(this); + m_variantWrapper.init(this); + m_valueTypeWrapper.init(this); + + { + v8::Handle<v8::Value> v = global()->Get(v8::String::New("Object"))->ToObject()->Get(v8::String::New("getOwnPropertyNames")); + m_getOwnPropertyNames = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(v)); + } } QV8Engine::~QV8Engine() @@ -114,6 +152,10 @@ QV8Engine::~QV8Engine() qPersistentDispose(m_freezeObject); qPersistentDispose(m_getOwnPropertyNames); + + invalidateAllValues(); + clearExceptions(); + m_valueTypeWrapper.destroy(); m_variantWrapper.destroy(); m_listWrapper.destroy(); @@ -121,39 +163,11 @@ QV8Engine::~QV8Engine() m_qobjectWrapper.destroy(); m_contextWrapper.destroy(); m_stringWrapper.destroy(); - qPersistentDispose(m_context); -} - -void QV8Engine::init(QDeclarativeEngine *engine) -{ - m_engine = engine; - - QByteArray v8args = qgetenv("V8ARGS"); - if (!v8args.isEmpty()) - v8::V8::SetFlagsFromString(v8args.constData(), v8args.length()); - - v8::HandleScope handle_scope; - m_context = v8::Context::New(); - qPersistentRegister(m_context); - v8::Context::Scope context_scope(m_context); - - v8::V8::SetUserObjectComparisonCallbackFunction(ObjectComparisonCallback); - m_stringWrapper.init(); - m_contextWrapper.init(this); - m_qobjectWrapper.init(this); - m_typeWrapper.init(this); - m_listWrapper.init(this); - m_variantWrapper.init(this); - m_valueTypeWrapper.init(this); + m_originalGlobalObject.destroy(); - { - v8::Handle<v8::Value> v = global()->Get(v8::String::New("Object"))->ToObject()->Get(v8::String::New("getOwnPropertyNames")); - m_getOwnPropertyNames = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(v)); - } - - initializeGlobal(m_context->Global()); - freezeObject(m_context->Global()); + if (m_ownsV8Context) + qPersistentDispose(m_context); } QString QV8Engine::toStringStatic(v8::Handle<v8::Value> jsstr) @@ -357,8 +371,10 @@ v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant) break; } - if (QDeclarativeValueType *vt = QDeclarativeEnginePrivate::get(m_engine)->valueTypes[type]) - return m_valueTypeWrapper.newValueType(variant, vt); + if (m_engine) { + if (QDeclarativeValueType *vt = QDeclarativeEnginePrivate::get(m_engine)->valueTypes[type]) + return m_valueTypeWrapper.newValueType(variant, vt); + } } else { if (type == qMetaTypeId<QDeclarativeListReference>()) { @@ -386,7 +402,7 @@ v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant) } // XXX TODO: To be compatible, we still need to handle: - // + QScriptValue + // + QJSValue // + QObjectList // + QList<int> @@ -420,6 +436,7 @@ const QSet<QString> &QV8Engine::illegalNames() const // Requires a handle scope v8::Local<v8::Array> QV8Engine::getOwnPropertyNames(v8::Handle<v8::Object> o) { + // FIXME Newer v8 have API for this function v8::TryCatch tc; v8::Handle<v8::Value> args[] = { o }; v8::Local<v8::Value> r = m_getOwnPropertyNames->Call(global(), 1, args); @@ -531,9 +548,6 @@ void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global) } } - if (m_engine) - qt->Set(v8::String::New("application"), newQObject(new QDeclarativeApplication(m_engine))); - qt->Set(v8::String::New("include"), V8FUNCTION(QV8Include::include, this)); qt->Set(v8::String::New("isQtObject"), V8FUNCTION(isQtObject, this)); qt->Set(v8::String::New("rgba"), V8FUNCTION(rgba, this)); @@ -543,12 +557,6 @@ void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global) qt->Set(v8::String::New("size"), V8FUNCTION(size, this)); qt->Set(v8::String::New("vector3d"), V8FUNCTION(vector3d, this)); - if (m_engine) { - qt->Set(v8::String::New("lighter"), V8FUNCTION(lighter, this)); - qt->Set(v8::String::New("darker"), V8FUNCTION(darker, this)); - qt->Set(v8::String::New("tint"), V8FUNCTION(tint, this)); - } - qt->Set(v8::String::New("formatDate"), V8FUNCTION(formatDate, this)); qt->Set(v8::String::New("formatTime"), V8FUNCTION(formatTime, this)); qt->Set(v8::String::New("formatDateTime"), V8FUNCTION(formatDateTime, this)); @@ -561,6 +569,10 @@ void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global) qt->Set(v8::String::New("resolvedUrl"), V8FUNCTION(resolvedUrl, this)); if (m_engine) { + qt->Set(v8::String::New("application"), newQObject(new QDeclarativeApplication(m_engine))); + qt->Set(v8::String::New("lighter"), V8FUNCTION(lighter, this)); + qt->Set(v8::String::New("darker"), V8FUNCTION(darker, this)); + qt->Set(v8::String::New("tint"), V8FUNCTION(tint, this)); qt->Set(v8::String::New("quit"), V8FUNCTION(quit, this)); qt->Set(v8::String::New("createQmlObject"), V8FUNCTION(createQmlObject, this)); qt->Set(v8::String::New("createComponent"), V8FUNCTION(createComponent, this)); @@ -1658,5 +1670,652 @@ v8::Handle<v8::Value> QV8Engine::qsTrIdNoOp(const v8::Arguments &args) return args[0]; } +void QV8Engine::initDeclarativeGlobalObject() +{ + v8::HandleScope handels; + v8::Context::Scope contextScope(m_context); + initializeGlobal(m_context->Global()); + freezeObject(m_context->Global()); +} + +void QV8Engine::setEngine(QDeclarativeEngine *engine) +{ + m_engine = engine; + initDeclarativeGlobalObject(); +} + +void QV8Engine::setException(v8::Handle<v8::Value> value, v8::Handle<v8::Message> msg) +{ + m_exception.set(value, msg); +} + +v8::Handle<v8::Value> QV8Engine::throwException(v8::Handle<v8::Value> value) +{ + setException(value); + v8::ThrowException(value); + return value; +} + +void QV8Engine::clearExceptions() +{ + m_exception.clear(); +} + +v8::Handle<v8::Value> QV8Engine::uncaughtException() const +{ + if (!hasUncaughtException()) + return v8::Handle<v8::Value>(); + return m_exception; +} + +bool QV8Engine::hasUncaughtException() const +{ + return m_exception; +} + +int QV8Engine::uncaughtExceptionLineNumber() const +{ + return m_exception.lineNumber(); +} + +QStringList QV8Engine::uncaughtExceptionBacktrace() const +{ + return m_exception.backtrace(); +} + +/*! + \internal + Save the current exception on stack so it can be set again later. + \sa QV8Engine::restoreException +*/ +void QV8Engine::saveException() +{ + m_exception.push(); +} + +/*! + \internal + Load a saved exception from stack. Current exception, if exists will be dropped + \sa QV8Engine::saveException +*/ +void QV8Engine::restoreException() +{ + m_exception.pop(); +} + +QV8Engine::Exception::Exception() {} + +QV8Engine::Exception::~Exception() +{ + Q_ASSERT_X(m_stack.isEmpty(), Q_FUNC_INFO, "Some saved exceptions left. Asymetric pop/push found."); + clear(); +} + +void QV8Engine::Exception::set(v8::Handle<v8::Value> value, v8::Handle<v8::Message> message) +{ + Q_ASSERT_X(!value.IsEmpty(), Q_FUNC_INFO, "Throwing an empty value handle is highly suspected"); + clear(); + m_value = v8::Persistent<v8::Value>::New(value); + m_message = v8::Persistent<v8::Message>::New(message); +} + +void QV8Engine::Exception::clear() +{ + m_value.Dispose(); + m_value.Clear(); + m_message.Dispose(); + m_message.Clear(); +} + +QV8Engine::Exception::operator bool() const +{ + return !m_value.IsEmpty(); +} + +QV8Engine::Exception::operator v8::Handle<v8::Value>() const +{ + Q_ASSERT(*this); + return m_value; +} + +int QV8Engine::Exception::lineNumber() const +{ + if (m_message.IsEmpty()) + return -1; + return m_message->GetLineNumber(); +} + +QStringList QV8Engine::Exception::backtrace() const +{ + if (m_message.IsEmpty()) + return QStringList(); + + QStringList backtrace; + v8::Handle<v8::StackTrace> trace = m_message->GetStackTrace(); + if (trace.IsEmpty()) + // FIXME it should not happen (SetCaptureStackTraceForUncaughtExceptions is called). + return QStringList(); + + for (int i = 0; i < trace->GetFrameCount(); ++i) { + v8::Local<v8::StackFrame> frame = trace->GetFrame(i); + backtrace.append(QJSConverter::toString(frame->GetFunctionName())); + backtrace.append(QJSConverter::toString(frame->GetFunctionName())); + backtrace.append(QString::fromAscii("()@")); + backtrace.append(QJSConverter::toString(frame->GetScriptName())); + backtrace.append(QString::fromAscii(":")); + backtrace.append(QString::number(frame->GetLineNumber())); + } + return backtrace; +} + +void QV8Engine::Exception::push() +{ + m_stack.push(qMakePair(m_value, m_message)); + m_value.Clear(); + m_message.Clear(); +} + +void QV8Engine::Exception::pop() +{ + Q_ASSERT_X(!m_stack.empty(), Q_FUNC_INFO, "Attempt to load unsaved exception found"); + ValueMessagePair pair = m_stack.pop(); + clear(); + m_value = pair.first; + m_message = pair.second; +} + +QScriptPassPointer<QJSValuePrivate> QV8Engine::newRegExp(const QString &pattern, const QString &flags) +{ + int f = v8::RegExp::kNone; + + QString::const_iterator i = flags.constBegin(); + for (; i != flags.constEnd(); ++i) { + switch (i->unicode()) { + case 'i': + f |= v8::RegExp::kIgnoreCase; + break; + case 'm': + f |= v8::RegExp::kMultiline; + break; + case 'g': + f |= v8::RegExp::kGlobal; + break; + default: + { + // ignore a Syntax Error. + } + } + } + + v8::Handle<v8::RegExp> regexp = v8::RegExp::New(QJSConverter::toString(pattern), static_cast<v8::RegExp::Flags>(f)); + return new QJSValuePrivate(this, regexp); +} + +QScriptPassPointer<QJSValuePrivate> QV8Engine::newRegExp(const QRegExp ®exp) +{ + return new QJSValuePrivate(this, QJSConverter::toRegExp(regexp)); +} + + +// Converts a QVariantList to JS. +// The result is a new Array object with length equal to the length +// of the QVariantList, and the elements being the QVariantList's +// elements converted to JS, recursively. +v8::Handle<v8::Array> QV8Engine::variantListToJS(const QVariantList &lst) +{ + v8::Handle<v8::Array> result = v8::Array::New(lst.size()); + for (int i = 0; i < lst.size(); ++i) + result->Set(i, variantToJS(lst.at(i))); + return result; +} + +// Converts a JS Array object to a QVariantList. +// The result is a QVariantList with length equal to the length +// of the JS Array, and elements being the JS Array's elements +// converted to QVariants, recursively. +QVariantList QV8Engine::variantListFromJS(v8::Handle<v8::Array> jsArray) +{ + QVariantList result; + int hash = jsArray->GetIdentityHash(); + if (visitedConversionObjects.contains(hash)) + return result; // Avoid recursion. + v8::HandleScope handleScope; + visitedConversionObjects.insert(hash); + uint32_t length = jsArray->Length(); + for (uint32_t i = 0; i < length; ++i) + result.append(variantFromJS(jsArray->Get(i))); + visitedConversionObjects.remove(hash); + return result; +} + +// Converts a QVariantMap to JS. +// The result is a new Object object with property names being +// the keys of the QVariantMap, and values being the values of +// the QVariantMap converted to JS, recursively. +v8::Handle<v8::Object> QV8Engine::variantMapToJS(const QVariantMap &vmap) +{ + v8::Handle<v8::Object> result = v8::Object::New(); + QVariantMap::const_iterator it; + for (it = vmap.constBegin(); it != vmap.constEnd(); ++it) + result->Set(QJSConverter::toString(it.key()), variantToJS(it.value())); + return result; +} + +// Converts a JS Object to a QVariantMap. +// The result is a QVariantMap with keys being the property names +// of the object, and values being the values of the JS object's +// properties converted to QVariants, recursively. +QVariantMap QV8Engine::variantMapFromJS(v8::Handle<v8::Object> jsObject) +{ + QVariantMap result; + int hash = jsObject->GetIdentityHash(); + if (visitedConversionObjects.contains(hash)) + return result; // Avoid recursion. + visitedConversionObjects.insert(hash); + v8::HandleScope handleScope; + // TODO: Only object's own property names. Include non-enumerable properties. + v8::Handle<v8::Array> propertyNames = jsObject->GetPropertyNames(); + uint32_t length = propertyNames->Length(); + for (uint32_t i = 0; i < length; ++i) { + v8::Handle<v8::Value> name = propertyNames->Get(i); + result.insert(QJSConverter::toString(name->ToString()), variantFromJS(jsObject->Get(name))); + } + visitedConversionObjects.remove(hash); + return result; +} + +// Converts the meta-type defined by the given type and data to JS. +// Returns the value if conversion succeeded, an empty handle otherwise. +v8::Handle<v8::Value> QV8Engine::metaTypeToJS(int type, const void *data) +{ + Q_ASSERT(data != 0); + v8::Handle<v8::Value> result; + + // check if it's one of the types we know + switch (QMetaType::Type(type)) { + case QMetaType::Void: + return v8::Undefined(); + case QMetaType::Bool: + return v8::Boolean::New(*reinterpret_cast<const bool*>(data)); + case QMetaType::Int: + return v8::Int32::New(*reinterpret_cast<const int*>(data)); + case QMetaType::UInt: + return v8::Uint32::New(*reinterpret_cast<const uint*>(data)); + case QMetaType::LongLong: + return v8::Number::New(double(*reinterpret_cast<const qlonglong*>(data))); + case QMetaType::ULongLong: +#if defined(Q_OS_WIN) && defined(_MSC_FULL_VER) && _MSC_FULL_VER <= 12008804 +#pragma message("** NOTE: You need the Visual Studio Processor Pack to compile support for 64bit unsigned integers.") + return v8::Number::New(double((qlonglong)*reinterpret_cast<const qulonglong*>(data))); +#elif defined(Q_CC_MSVC) && !defined(Q_CC_MSVC_NET) + return v8::Number::New(double((qlonglong)*reinterpret_cast<const qulonglong*>(data))); +#else + return v8::Number::New(double(*reinterpret_cast<const qulonglong*>(data))); +#endif + case QMetaType::Double: + return v8::Number::New(double(*reinterpret_cast<const double*>(data))); + case QMetaType::QString: + return QJSConverter::toString(*reinterpret_cast<const QString*>(data)); + case QMetaType::Float: + return v8::Number::New(*reinterpret_cast<const float*>(data)); + case QMetaType::Short: + return v8::Int32::New(*reinterpret_cast<const short*>(data)); + case QMetaType::UShort: + return v8::Uint32::New(*reinterpret_cast<const unsigned short*>(data)); + case QMetaType::Char: + return v8::Int32::New(*reinterpret_cast<const char*>(data)); + case QMetaType::UChar: + return v8::Uint32::New(*reinterpret_cast<const unsigned char*>(data)); + case QMetaType::QChar: + return v8::Uint32::New((*reinterpret_cast<const QChar*>(data)).unicode()); + case QMetaType::QStringList: + result = QJSConverter::toStringList(*reinterpret_cast<const QStringList *>(data)); + break; + case QMetaType::QVariantList: + result = variantListToJS(*reinterpret_cast<const QVariantList *>(data)); + break; + case QMetaType::QVariantMap: + result = variantMapToJS(*reinterpret_cast<const QVariantMap *>(data)); + break; + case QMetaType::QDateTime: + result = QJSConverter::toDateTime(*reinterpret_cast<const QDateTime *>(data)); + break; + case QMetaType::QDate: + result = QJSConverter::toDateTime(QDateTime(*reinterpret_cast<const QDate *>(data))); + break; + case QMetaType::QRegExp: + result = QJSConverter::toRegExp(*reinterpret_cast<const QRegExp *>(data)); + break; + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + result = newQObject(*reinterpret_cast<QObject* const *>(data)); + break; + case QMetaType::QVariant: + result = variantToJS(*reinterpret_cast<const QVariant*>(data)); + break; + default: + if (type == qMetaTypeId<QJSValue>()) { + return QJSValuePrivate::get(*reinterpret_cast<const QJSValue*>(data))->asV8Value(this); + } else { + QByteArray typeName = QMetaType::typeName(type); + if (typeName.endsWith('*') && !*reinterpret_cast<void* const *>(data)) { + return v8::Null(); + } else { + // Fall back to wrapping in a QVariant. + result = newVariant(QVariant(type, data)); + } + } + } + return result; +} + +// Converts a JS value to a meta-type. +// data must point to a place that can store a value of the given type. +// Returns true if conversion succeeded, false otherwise. +bool QV8Engine::metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data) { + // check if it's one of the types we know + switch (QMetaType::Type(type)) { + case QMetaType::Bool: + *reinterpret_cast<bool*>(data) = value->ToBoolean()->Value(); + return true; + case QMetaType::Int: + *reinterpret_cast<int*>(data) = value->ToInt32()->Value(); + return true; + case QMetaType::UInt: + *reinterpret_cast<uint*>(data) = value->ToUint32()->Value(); + return true; + case QMetaType::LongLong: + *reinterpret_cast<qlonglong*>(data) = qlonglong(value->ToInteger()->Value()); + return true; + case QMetaType::ULongLong: + *reinterpret_cast<qulonglong*>(data) = qulonglong(value->ToInteger()->Value()); + return true; + case QMetaType::Double: + *reinterpret_cast<double*>(data) = value->ToNumber()->Value(); + return true; + case QMetaType::QString: + if (value->IsUndefined() || value->IsNull()) + *reinterpret_cast<QString*>(data) = QString(); + else + *reinterpret_cast<QString*>(data) = QJSConverter::toString(value->ToString()); + return true; + case QMetaType::Float: + *reinterpret_cast<float*>(data) = value->ToNumber()->Value(); + return true; + case QMetaType::Short: + *reinterpret_cast<short*>(data) = short(value->ToInt32()->Value()); + return true; + case QMetaType::UShort: + *reinterpret_cast<unsigned short*>(data) = ushort(value->ToInt32()->Value()); // ### QScript::ToUInt16() + return true; + case QMetaType::Char: + *reinterpret_cast<char*>(data) = char(value->ToInt32()->Value()); + return true; + case QMetaType::UChar: + *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value->ToInt32()->Value()); + return true; + case QMetaType::QChar: + if (value->IsString()) { + QString str = QJSConverter::toString(v8::Handle<v8::String>::Cast(value)); + *reinterpret_cast<QChar*>(data) = str.isEmpty() ? QChar() : str.at(0); + } else { + *reinterpret_cast<QChar*>(data) = QChar(ushort(value->ToInt32()->Value())); // ### QScript::ToUInt16() + } + return true; + case QMetaType::QDateTime: + if (value->IsDate()) { + *reinterpret_cast<QDateTime *>(data) = QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(value)); + return true; + } break; + case QMetaType::QDate: + if (value->IsDate()) { + *reinterpret_cast<QDate *>(data) = QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(value)).date(); + return true; + } break; + case QMetaType::QRegExp: + if (value->IsRegExp()) { + *reinterpret_cast<QRegExp *>(data) = QJSConverter::toRegExp(v8::Handle<v8::RegExp>::Cast(value)); + return true; + } break; + case QMetaType::QObjectStar: + if (isQObject(value) || value->IsNull()) { + *reinterpret_cast<QObject* *>(data) = qtObjectFromJS(value); + return true; + } break; + case QMetaType::QWidgetStar: + if (isQObject(value) || value->IsNull()) { + QObject *qo = qtObjectFromJS(value); + if (!qo || qo->isWidgetType()) { + *reinterpret_cast<QWidget* *>(data) = reinterpret_cast<QWidget*>(qo); + return true; + } + } break; + case QMetaType::QStringList: + if (value->IsArray()) { + *reinterpret_cast<QStringList *>(data) = QJSConverter::toStringList(v8::Handle<v8::Array>::Cast(value)); + return true; + } break; + case QMetaType::QVariantList: + if (value->IsArray()) { + *reinterpret_cast<QVariantList *>(data) = variantListFromJS(v8::Handle<v8::Array>::Cast(value)); + return true; + } break; + case QMetaType::QVariantMap: + if (value->IsObject()) { + *reinterpret_cast<QVariantMap *>(data) = variantMapFromJS(v8::Handle<v8::Object>::Cast(value)); + return true; + } break; + case QMetaType::QVariant: + *reinterpret_cast<QVariant*>(data) = variantFromJS(value); + return true; + default: + ; + } + +#if 0 + if (isQtVariant(value)) { + const QVariant &var = variantValue(value); + // ### Enable once constructInPlace() is in qt master. + if (var.userType() == type) { + QMetaType::constructInPlace(type, data, var.constData()); + return true; + } + if (var.canConvert(QVariant::Type(type))) { + QVariant vv = var; + vv.convert(QVariant::Type(type)); + Q_ASSERT(vv.userType() == type); + QMetaType::constructInPlace(type, data, vv.constData()); + return true; + } + + } +#endif + + // Try to use magic. + + QByteArray name = QMetaType::typeName(type); + if (convertToNativeQObject(value, name, reinterpret_cast<void* *>(data))) + return true; + if (isVariant(value) && name.endsWith('*')) { + int valueType = QMetaType::type(name.left(name.size()-1)); + QVariant var = variantValue(value); + if (valueType == var.userType()) { + // We have T t, T* is requested, so return &t. + *reinterpret_cast<void* *>(data) = var.data(); + return true; + } else { + // Look in the prototype chain. + v8::Handle<v8::Value> proto = value->ToObject()->GetPrototype(); + while (proto->IsObject()) { + bool canCast = false; + if (isVariant(proto)) { + canCast = (type == variantValue(proto).userType()) + || (valueType && (valueType == variantValue(proto).userType())); + } + else if (isQObject(proto)) { + QByteArray className = name.left(name.size()-1); + if (QObject *qobject = qtObjectFromJS(proto)) + canCast = qobject->qt_metacast(className) != 0; + } + if (canCast) { + QByteArray varTypeName = QMetaType::typeName(var.userType()); + if (varTypeName.endsWith('*')) + *reinterpret_cast<void* *>(data) = *reinterpret_cast<void* *>(var.data()); + else + *reinterpret_cast<void* *>(data) = var.data(); + return true; + } + proto = proto->ToObject()->GetPrototype(); + } + } + } else if (value->IsNull() && name.endsWith('*')) { + *reinterpret_cast<void* *>(data) = 0; + return true; + } else if (type == qMetaTypeId<QJSValue>()) { + *reinterpret_cast<QJSValue*>(data) = QJSValuePrivate::get(new QJSValuePrivate(this, value)); + return true; + } + + return false; +} + +// Converts a QVariant to JS. +v8::Handle<v8::Value> QV8Engine::variantToJS(const QVariant &value) +{ + return metaTypeToJS(value.userType(), value.constData()); +} + +// Converts a JS value to a QVariant. +// Null, Undefined -> QVariant() (invalid) +// Boolean -> QVariant(bool) +// Number -> QVariant(double) +// String -> QVariant(QString) +// Array -> QVariantList(...) +// Date -> QVariant(QDateTime) +// RegExp -> QVariant(QRegExp) +// [Any other object] -> QVariantMap(...) +QVariant QV8Engine::variantFromJS(v8::Handle<v8::Value> value) +{ + Q_ASSERT(!value.IsEmpty()); + if (value->IsNull() || value->IsUndefined()) + return QVariant(); + if (value->IsBoolean()) + return value->ToBoolean()->Value(); + else if (value->IsInt32()) + return value->ToInt32()->Value(); + else if (value->IsNumber()) + return value->ToNumber()->Value(); + if (value->IsString()) + return QJSConverter::toString(value->ToString()); + Q_ASSERT(value->IsObject()); + if (value->IsArray()) + return variantListFromJS(v8::Handle<v8::Array>::Cast(value)); + if (value->IsDate()) + return QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(value)); + if (value->IsRegExp()) + return QJSConverter::toRegExp(v8::Handle<v8::RegExp>::Cast(value)); + if (isVariant(value)) + return variantValue(value); + if (isQObject(value)) + return qVariantFromValue(qtObjectFromJS(value)); + return variantMapFromJS(value->ToObject()); +} + +bool QV8Engine::convertToNativeQObject(v8::Handle<v8::Value> value, + const QByteArray &targetType, + void **result) +{ + if (!targetType.endsWith('*')) + return false; + if (QObject *qobject = qtObjectFromJS(value)) { + int start = targetType.startsWith("const ") ? 6 : 0; + QByteArray className = targetType.mid(start, targetType.size()-start-1); + if (void *instance = qobject->qt_metacast(className)) { + *result = instance; + return true; + } + } + return false; +} + +QObject *QV8Engine::qtObjectFromJS(v8::Handle<v8::Value> value) +{ + if (!value->IsObject()) + return 0; + + QV8ObjectResource *r = (QV8ObjectResource *)value->ToObject()->GetExternalResource(); + if (!r) + return 0; + QV8ObjectResource::ResourceType type = r->resourceType(); + if (type == QV8ObjectResource::QObjectType) + return qobjectWrapper()->toQObject(r); + else if (type == QV8ObjectResource::VariantType) { + QVariant variant = variantWrapper()->toVariant(r); + int type = variant.userType(); + if ((type == QMetaType::QObjectStar) || (type == QMetaType::QWidgetStar)) + return *reinterpret_cast<QObject* const *>(variant.constData()); + } + return 0; +} + + +QVariant QV8Engine::variantValue(v8::Handle<v8::Value> value) +{ + Q_ASSERT(isVariant(value)); + return QV8Engine::toVariant(value, -1 /*whateever magic hint is*/); +} + +// Creates a QVariant wrapper object. +v8::Handle<v8::Object> QV8Engine::newVariant(const QVariant &value) +{ + v8::Handle<v8::Object> instance = variantWrapper()->newVariant(value); + return instance; +} + +QScriptPassPointer<QJSValuePrivate> QV8Engine::evaluate(v8::Handle<v8::Script> script, v8::TryCatch& tryCatch) +{ + v8::HandleScope handleScope; + + clearExceptions(); + if (script.IsEmpty()) { + v8::Handle<v8::Value> exception = tryCatch.Exception(); + if (exception.IsEmpty()) { + // This is possible on syntax errors like { a:12, b:21 } <- missing "(", ")" around expression. + return InvalidValue(); + } + setException(exception, tryCatch.Message()); + return new QJSValuePrivate(this, exception); + } + v8::Handle<v8::Value> result; + result = script->Run(); + if (result.IsEmpty()) { + v8::Handle<v8::Value> exception = tryCatch.Exception(); + // TODO: figure out why v8 doesn't always produce an exception value + //Q_ASSERT(!exception.IsEmpty()); + if (exception.IsEmpty()) + exception = v8::Exception::Error(v8::String::New("missing exception value")); + setException(exception, tryCatch.Message()); + return new QJSValuePrivate(this, exception); + } + return new QJSValuePrivate(this, result); +} + +QJSValue QV8Engine::scriptValueFromInternal(v8::Handle<v8::Value> value) const +{ + if (value.IsEmpty()) + return QJSValuePrivate::get(InvalidValue()); + return QJSValuePrivate::get(new QJSValuePrivate(const_cast<QV8Engine*>(this), value)); +} + +QScriptPassPointer<QJSValuePrivate> QV8Engine::newArray(uint length) +{ + return new QJSValuePrivate(this, v8::Array::New(length)); +} + +void QV8Engine::emitSignalHandlerException() +{ + emit q->signalHandlerException(scriptValueFromInternal(uncaughtException())); +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/v8/qv8engine_impl_p.h b/src/declarative/qml/v8/qv8engine_impl_p.h new file mode 100644 index 0000000000..5c56efdf39 --- /dev/null +++ b/src/declarative/qml/v8/qv8engine_impl_p.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL-ONLY$ +** GNU Lesser General Public License Usage +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QV8ENGINE_IMPL_P_H +#define QV8ENGINE_IMPL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qv8engine_p.h" +#include "qjsvalue_p.h" +#include "qjsconverter_p.h" + +QT_BEGIN_NAMESPACE + +inline v8::Handle<v8::Value> QV8Engine::makeJSValue(bool value) +{ + return value ? v8::True() : v8::False(); +} + +inline v8::Handle<v8::Value> QV8Engine::makeJSValue(int value) +{ + return v8::Integer::New(value); +} + +inline v8::Handle<v8::Value> QV8Engine::makeJSValue(uint value) +{ + return v8::Integer::NewFromUnsigned(value); +} + +inline v8::Handle<v8::Value> QV8Engine::makeJSValue(double value) +{ + return v8::Number::New(value); +} + +inline v8::Handle<v8::Value> QV8Engine::makeJSValue(QJSValue::SpecialValue value) { + if (value == QJSValue::NullValue) + return v8::Null(); + return v8::Undefined(); +} + +inline v8::Handle<v8::Value> QV8Engine::makeJSValue(const QString& value) +{ + return QJSConverter::toString(value); +} + +class QtScriptBagCleaner +{ +public: + template<class T> + void operator () (T* value) const + { + value->reinitialize(); + } +}; + +inline void QV8Engine::registerValue(QJSValuePrivate *data) +{ + m_values.insert(data); +} + +inline void QV8Engine::unregisterValue(QJSValuePrivate *data) +{ + m_values.remove(data); +} + +inline void QV8Engine::invalidateAllValues() +{ + QtScriptBagCleaner invalidator; + m_values.forEach(invalidator); + m_values.clear(); +} + +/*! + \internal + \note property can be index (v8::Integer) or a property (v8::String) name, according to ECMA script + property would be converted to a string. +*/ +inline QJSValue::PropertyFlags QV8Engine::getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property) +{ + QJSValue::PropertyFlags flags = m_originalGlobalObject.getPropertyFlags(object, property); + return flags; +} + +QScriptPassPointer<QJSValuePrivate> QV8Engine::evaluate(const QString& program, const QString& fileName, int lineNumber) +{ + v8::TryCatch tryCatch; + v8::ScriptOrigin scriptOrigin(QJSConverter::toString(fileName), v8::Integer::New(lineNumber - 1)); + v8::Handle<v8::Script> script; + script = v8::Script::Compile(QJSConverter::toString(program), &scriptOrigin); + if (script.IsEmpty()) { + // TODO: Why don't we get the exception, as with Script::Compile()? + // Q_ASSERT(tryCatch.HasCaught()); + v8::Handle<v8::Value> error = v8::Exception::SyntaxError(v8::String::New("")); + setException(error); + return new QJSValuePrivate(this, error); + } + return evaluate(script, tryCatch); +} + +QT_END_NAMESPACE + +#endif // QV8ENGINE_IMPL_P_H diff --git a/src/declarative/qml/v8/qv8engine_p.h b/src/declarative/qml/v8/qv8engine_p.h index 82d696909f..b95e55002b 100644 --- a/src/declarative/qml/v8/qv8engine_p.h +++ b/src/declarative/qml/v8/qv8engine_p.h @@ -57,7 +57,14 @@ #include <QtCore/qvariant.h> #include <QtCore/qset.h> #include <QtCore/qmutex.h> +#include <QtCore/qstack.h> +#include <QtCore/qstringlist.h> + #include <private/qv8_p.h> +#include <qjsengine.h> +#include <qjsvalue.h> +#include "qscriptoriginalglobalobject_p.h" +#include "qscripttools_p.h" #include <private/qdeclarativepropertycache_p.h> @@ -195,7 +202,7 @@ public: 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) {} @@ -210,18 +217,49 @@ class QDeclarativeContextData; 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(); struct 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(); + QV8ContextWrapper *contextWrapper() { return &m_contextWrapper; } QV8QObjectWrapper *qobjectWrapper() { return &m_qobjectWrapper; } QV8TypeWrapper *typeWrapper() { return &m_typeWrapper; } @@ -237,6 +275,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); @@ -257,6 +296,9 @@ 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 ®exp); + 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 bool isQObject(v8::Handle<v8::Value>); @@ -281,8 +323,19 @@ public: // Return the list of illegal id names (the names of the properties on the global object) const QSet<QString> &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 *); @@ -295,9 +348,50 @@ public: inline Deletable *extensionData(int) const; void setExtensionData(int, Deletable *); -private: + inline v8::Handle<v8::Value> makeJSValue(bool value); + inline v8::Handle<v8::Value> makeJSValue(int value); + inline v8::Handle<v8::Value> makeJSValue(uint value); + inline v8::Handle<v8::Value> makeJSValue(double value); + inline v8::Handle<v8::Value> makeJSValue(QJSValue::SpecialValue value); + inline v8::Handle<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::Handle<v8::Object> newVariant(const QVariant &variant); + QScriptPassPointer<QJSValuePrivate> newVariant(QJSValuePrivate* value, const QVariant &variant); + + v8::Handle<v8::Array> variantListToJS(const QVariantList &lst); + QVariantList variantListFromJS(v8::Handle<v8::Array> jsArray); + + v8::Handle<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(); + + QObject *qtObjectFromJS(v8::Handle<v8::Value> value); + QSet<int> visitedConversionObjects; +protected: + QJSEngine* q; QDeclarativeEngine *m_engine; + bool m_ownsV8Context; v8::Persistent<v8::Context> m_context; + QScriptOriginalGlobalObject m_originalGlobalObject; QV8StringWrapper m_stringWrapper; QV8ContextWrapper m_contextWrapper; @@ -318,6 +412,8 @@ private: QSet<QString> m_illegalNames; + Exception m_exception; + QVariant toBasicVariant(v8::Handle<v8::Value>); void initializeGlobal(v8::Handle<v8::Object>); @@ -356,6 +452,10 @@ private: double qtDateTimeToJsDate(const QDateTime &dt); QDateTime qtDateTimeFromJsDate(double jsDate); +private: + QScriptBagContainer<QJSValuePrivate> m_values; + + Q_DISABLE_COPY(QV8Engine) }; // Allocate a new Persistent handle. *ALL* persistent handles in QML must be allocated diff --git a/src/declarative/qml/v8/qv8include.cpp b/src/declarative/qml/v8/qv8include.cpp index e2161a9001..71937d0aad 100644 --- a/src/declarative/qml/v8/qv8include.cpp +++ b/src/declarative/qml/v8/qv8include.cpp @@ -41,7 +41,7 @@ #include "qv8include_p.h" -#include <QtScript/qscriptengine.h> +#include <QtDeclarative/qjsengine.h> #include <QtNetwork/qnetworkrequest.h> #include <QtNetwork/qnetworkreply.h> #include <QtCore/qfile.h> diff --git a/src/declarative/qml/v8/qv8qobjectwrapper.cpp b/src/declarative/qml/v8/qv8qobjectwrapper.cpp index 393f8376f1..f97f427ede 100644 --- a/src/declarative/qml/v8/qv8qobjectwrapper.cpp +++ b/src/declarative/qml/v8/qv8qobjectwrapper.cpp @@ -48,15 +48,17 @@ #include <private/qdeclarativeengine_p.h> #include <private/qdeclarativevmemetaobject_p.h> #include <private/qdeclarativebinding_p.h> +#include <private/qjsvalue_p.h> +#include <private/qscript_impl_p.h> -#include <QtScript/qscriptvalue.h> +#include <QtDeclarative/qjsvalue.h> #include <QtCore/qvarlengtharray.h> #include <QtCore/qtimer.h> #include <QtCore/qatomic.h> QT_BEGIN_NAMESPACE -Q_DECLARE_METATYPE(QScriptValue); +Q_DECLARE_METATYPE(QJSValue); Q_DECLARE_METATYPE(QDeclarativeV8Handle); #if defined(__GNUC__) @@ -122,9 +124,26 @@ private: inline void cleanup(); - char data[4 * sizeof(void *)]; + union { + float floatValue; + double doubleValue; + quint32 intValue; + bool boolValue; + QObject *qobjectPtr; + + char allocData[sizeof(QVariant)]; + }; + + // Pointers to allocData + union { + QString *qstringPtr; + QVariant *qvariantPtr; + QList<QObject *> *qlistPtr; + QJSValue *qjsValuePtr; + QDeclarativeV8Handle *handlePtr; + }; + int type; - bool isObjectType; }; } @@ -316,7 +335,7 @@ static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object, QDeclarativeV8Handle handle; void *args[] = { &handle, 0 }; QMetaObject::metacall(object, QMetaObject::ReadProperty, property.coreIndex, args); - return reinterpret_cast<v8::Handle<v8::Value> &>(handle); + return handle.toHandle(); } else if (QDeclarativeValueTypeFactory::isValueType((uint)property.propType)) { QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine()); QDeclarativeValueType *valueType = ep->valueTypes[property.propType]; @@ -361,7 +380,7 @@ static v8::Handle<v8::Value> LoadPropertyDirect(QV8Engine *engine, QObject *obje QDeclarativeV8Handle handle; void *args[] = { &handle, 0 }; object->qt_metacall(QMetaObject::ReadProperty, property.coreIndex, args); - return reinterpret_cast<v8::Handle<v8::Value> &>(handle); + return handle.toHandle(); } else if (QDeclarativeValueTypeFactory::isValueType((uint)property.propType)) { QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine()); QDeclarativeValueType *valueType = ep->valueTypes[property.propType]; @@ -674,7 +693,9 @@ v8::Handle<v8::Array> QV8QObjectWrapper::Enumerator(const v8::AccessorInfo &info QStringList result; - QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(resource->engine->engine()); + QDeclarativeEnginePrivate *ep = resource->engine->engine() + ? QDeclarativeEnginePrivate::get(resource->engine->engine()) + : 0; QDeclarativePropertyCache *cache = 0; QDeclarativeData *ddata = QDeclarativeData::get(object); @@ -682,7 +703,7 @@ v8::Handle<v8::Array> QV8QObjectWrapper::Enumerator(const v8::AccessorInfo &info cache = ddata->propertyCache; if (!cache) { - cache = ep->cache(object); + cache = ep ? ep->cache(object) : 0; if (cache) { if (ddata) { cache->addref(); ddata->propertyCache = cache; } } else { @@ -1805,7 +1826,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Invoke(const v8::Arguments &args) } MetaCallArgument::MetaCallArgument() -: type(QVariant::Invalid), isObjectType(false) +: type(QVariant::Invalid) { } @@ -1817,22 +1838,22 @@ MetaCallArgument::~MetaCallArgument() void MetaCallArgument::cleanup() { if (type == QMetaType::QString) { - ((QString *)&data)->~QString(); - } else if (type == -1 || type == qMetaTypeId<QVariant>()) { - ((QVariant *)&data)->~QVariant(); - } else if (type == qMetaTypeId<QScriptValue>()) { - ((QScriptValue *)&data)->~QScriptValue(); + qstringPtr->~QString(); + } else if (type == -1 || type == QMetaType::QVariant) { + qvariantPtr->~QVariant(); + } else if (type == qMetaTypeId<QJSValue>()) { + qjsValuePtr->~QJSValue(); } else if (type == qMetaTypeId<QList<QObject *> >()) { - ((QList<QObject *> *)&data)->~QList<QObject *>(); - } + qlistPtr->~QList<QObject *>(); + } } void *MetaCallArgument::dataPtr() { if (type == -1) - return ((QVariant *)data)->data(); + return qvariantPtr->data(); else - return (void *)&data; + return (void *)&allocData; } void MetaCallArgument::initAsType(int callType) @@ -1840,8 +1861,8 @@ void MetaCallArgument::initAsType(int callType) if (type != 0) { cleanup(); type = 0; } if (callType == 0) return; - if (callType == qMetaTypeId<QScriptValue>()) { - new (&data) QScriptValue(); + if (callType == qMetaTypeId<QJSValue>()) { + qjsValuePtr = new (&allocData) QJSValue(); type = callType; } else if (callType == QMetaType::Int || callType == QMetaType::UInt || @@ -1850,23 +1871,23 @@ void MetaCallArgument::initAsType(int callType) callType == QMetaType::Float) { type = callType; } else if (callType == QMetaType::QObjectStar) { - *((QObject **)&data) = 0; + qobjectPtr = 0; type = callType; } else if (callType == QMetaType::QString) { - new (&data) QString(); + qstringPtr = new (&allocData) QString(); type = callType; - } else if (callType == qMetaTypeId<QVariant>()) { + } else if (callType == QMetaType::QVariant) { type = callType; - new (&data) QVariant(); + qvariantPtr = new (&allocData) QVariant(); } else if (callType == qMetaTypeId<QList<QObject *> >()) { type = callType; - new (&data) QList<QObject *>(); + qlistPtr = new (&allocData) QList<QObject *>(); } else if (callType == qMetaTypeId<QDeclarativeV8Handle>()) { type = callType; - new (&data) v8::Handle<v8::Value>(); + handlePtr = new (&allocData) QDeclarativeV8Handle; } else { type = -1; - new (&data) QVariant(callType, (void *)0); + qvariantPtr = new (&allocData) QVariant(callType, (void *)0); } } @@ -1874,63 +1895,63 @@ void MetaCallArgument::fromValue(int callType, QV8Engine *engine, v8::Handle<v8: { if (type != 0) { cleanup(); type = 0; } - if (callType == qMetaTypeId<QScriptValue>()) { - new (&data) QScriptValue(); - type = qMetaTypeId<QScriptValue>(); + if (callType == qMetaTypeId<QJSValue>()) { + qjsValuePtr = new (&allocData) QJSValue(QJSValuePrivate::get(new QJSValuePrivate(engine, value))); + type = qMetaTypeId<QJSValue>(); } else if (callType == QMetaType::Int) { - *((int *)&data) = int(value->Int32Value()); + intValue = quint32(value->Int32Value()); type = callType; } else if (callType == QMetaType::UInt) { - *((uint *)&data) = uint(value->Uint32Value()); + intValue = quint32(value->Uint32Value()); type = callType; } else if (callType == QMetaType::Bool) { - *((bool *)&data) = value->BooleanValue(); + boolValue = value->BooleanValue(); type = callType; } else if (callType == QMetaType::Double) { - *((double *)&data) = double(value->NumberValue()); + doubleValue = double(value->NumberValue()); type = callType; } else if (callType == QMetaType::Float) { - *((float *)&data) = float(value->NumberValue()); + floatValue = float(value->NumberValue()); type = callType; } else if (callType == QMetaType::QString) { if (value->IsNull() || value->IsUndefined()) - new (&data) QString(); + qstringPtr = new (&allocData) QString(); else - new (&data) QString(engine->toString(value->ToString())); + qstringPtr = new (&allocData) QString(engine->toString(value->ToString())); type = callType; } else if (callType == QMetaType::QObjectStar) { - *((QObject **)&data) = engine->toQObject(value); + qobjectPtr = engine->toQObject(value); type = callType; } else if (callType == qMetaTypeId<QVariant>()) { - new (&data) QVariant(engine->toVariant(value, -1)); + qvariantPtr = new (&allocData) QVariant(engine->toVariant(value, -1)); type = callType; } else if (callType == qMetaTypeId<QList<QObject*> >()) { - QList<QObject *> *list = new (&data) QList<QObject *>(); + qlistPtr = new (&allocData) QList<QObject *>(); if (value->IsArray()) { v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value); uint32_t length = array->Length(); for (uint32_t ii = 0; ii < length; ++ii) - list->append(engine->toQObject(array->Get(ii))); + qlistPtr->append(engine->toQObject(array->Get(ii))); } else { - list->append(engine->toQObject(value)); + qlistPtr->append(engine->toQObject(value)); } type = callType; } else if (callType == qMetaTypeId<QDeclarativeV8Handle>()) { - new (&data) v8::Handle<v8::Value>(value); + handlePtr = new (&allocData) QDeclarativeV8Handle(QDeclarativeV8Handle::fromHandle(value)); type = callType; } else { - new (&data) QVariant(); + qvariantPtr = new (&allocData) QVariant(); type = -1; - QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine()); + QDeclarativeEnginePrivate *ep = engine->engine() ? QDeclarativeEnginePrivate::get(engine->engine()) : 0; QVariant v = engine->toVariant(value, -1); if (v.userType() == callType) { - *((QVariant *)&data) = v; + *qvariantPtr = v; } else if (v.canConvert((QVariant::Type)callType)) { - *((QVariant *)&data) = v; - ((QVariant *)&data)->convert((QVariant::Type)callType); - } else if (const QMetaObject *mo = ep->rawMetaObjectForType(callType)) { + *qvariantPtr = v; + qvariantPtr->convert((QVariant::Type)callType); + } else if (const QMetaObject *mo = ep ? ep->rawMetaObjectForType(callType) : 0) { QObject *obj = ep->toQObject(v); if (obj) { @@ -1939,46 +1960,46 @@ void MetaCallArgument::fromValue(int callType, QV8Engine *engine, v8::Handle<v8: if (!objMo) obj = 0; } - *((QVariant *)&data) = QVariant(callType, &obj); + *qvariantPtr = QVariant(callType, &obj); } else { - *((QVariant *)&data) = QVariant(callType, (void *)0); + *qvariantPtr = QVariant(callType, (void *)0); } } } v8::Handle<v8::Value> MetaCallArgument::toValue(QV8Engine *engine) { - if (type == qMetaTypeId<QScriptValue>()) { - return v8::Undefined(); + if (type == qMetaTypeId<QJSValue>()) { + return QJSValuePrivate::get(*qjsValuePtr)->asV8Value(engine); } else if (type == QMetaType::Int) { - return v8::Integer::New(*((int *)&data)); + return v8::Integer::New(int(intValue)); } else if (type == QMetaType::UInt) { - return v8::Integer::NewFromUnsigned(*((uint *)&data)); + return v8::Integer::NewFromUnsigned(intValue); } else if (type == QMetaType::Bool) { - return v8::Boolean::New(*((bool *)&data)); + return v8::Boolean::New(boolValue); } else if (type == QMetaType::Double) { - return v8::Number::New(*((double *)&data)); + return v8::Number::New(doubleValue); } else if (type == QMetaType::Float) { - return v8::Number::New(*((float *)&data)); + return v8::Number::New(floatValue); } else if (type == QMetaType::QString) { - return engine->toString(*((QString *)&data)); + return engine->toString(*qstringPtr); } else if (type == QMetaType::QObjectStar) { - QObject *object = *((QObject **)&data); + QObject *object = qobjectPtr; if (object) QDeclarativeData::get(object, true)->setImplicitDestructible(); return engine->newQObject(object); } else if (type == qMetaTypeId<QList<QObject *> >()) { // XXX Can this be made more by using Array as a prototype and implementing // directly against QList<QObject*>? - QList<QObject *> &list = *(QList<QObject *>*)&data; + QList<QObject *> &list = *qlistPtr; v8::Local<v8::Array> array = v8::Array::New(list.count()); for (int ii = 0; ii < list.count(); ++ii) array->Set(ii, engine->newQObject(list.at(ii))); return array; } else if (type == qMetaTypeId<QDeclarativeV8Handle>()) { - return *(v8::Handle<v8::Value>*)&data; + return handlePtr->toHandle(); } else if (type == -1 || type == qMetaTypeId<QVariant>()) { - QVariant value = *((QVariant *)&data); + QVariant value = *qvariantPtr; v8::Handle<v8::Value> rv = engine->fromVariant(value); if (QObject *object = engine->toQObject(rv)) QDeclarativeData::get(object, true)->setImplicitDestructible(); diff --git a/src/declarative/qml/v8/qv8typewrapper.cpp b/src/declarative/qml/v8/qv8typewrapper.cpp index 39d03dbeea..fe30670fc2 100644 --- a/src/declarative/qml/v8/qv8typewrapper.cpp +++ b/src/declarative/qml/v8/qv8typewrapper.cpp @@ -173,10 +173,12 @@ v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property, return v8engine->typeWrapper()->newObject(object, d->type, resource->mode); } else if (QDeclarativeMetaType::ModuleApiInstance *moduleApi = typeNamespace->moduleApi()) { - // XXX TODO: Currently module APIs are implemented against QScriptValues. Consequently we - // can't do anything for script module apis here until the QtScript/V8 binding is complete. - if (moduleApi->qobjectCallback) { - moduleApi->qobjectApi = moduleApi->qobjectCallback(v8engine->engine(), 0); + if (moduleApi->scriptCallback) { + moduleApi->scriptApi = moduleApi->scriptCallback(v8engine->engine(), v8engine->engine()); + moduleApi->scriptCallback = 0; + moduleApi->qobjectCallback = 0; + } else if (moduleApi->qobjectCallback) { + moduleApi->qobjectApi = moduleApi->qobjectCallback(v8engine->engine(), v8engine->engine()); moduleApi->scriptCallback = 0; moduleApi->qobjectCallback = 0; } @@ -225,10 +227,12 @@ v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property, QV8QObjectWrapper::IgnoreRevision); } else if (resource->typeNamespace) { if (QDeclarativeMetaType::ModuleApiInstance *moduleApi = resource->typeNamespace->moduleApi()) { - // XXX TODO: Currently module APIs are implemented against QScriptValues. Consequently we - // can't do anything for script module apis here until the QtScript/V8 binding is complete. - if (moduleApi->qobjectCallback) { - moduleApi->qobjectApi = moduleApi->qobjectCallback(v8engine->engine(), 0); + if (moduleApi->scriptCallback) { + moduleApi->scriptApi = moduleApi->scriptCallback(v8engine->engine(), v8engine->engine()); + moduleApi->scriptCallback = 0; + moduleApi->qobjectCallback = 0; + } else if (moduleApi->qobjectCallback) { + moduleApi->qobjectApi = moduleApi->qobjectCallback(v8engine->engine(), v8engine->engine()); moduleApi->scriptCallback = 0; moduleApi->qobjectCallback = 0; } diff --git a/src/declarative/qml/v8/qv8variantwrapper.cpp b/src/declarative/qml/v8/qv8variantwrapper.cpp index a5602fbbad..d4097d7f74 100644 --- a/src/declarative/qml/v8/qv8variantwrapper.cpp +++ b/src/declarative/qml/v8/qv8variantwrapper.cpp @@ -71,6 +71,7 @@ void QV8VariantWrapper::init(QV8Engine *engine) { m_engine = engine; m_toString = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ToString)->GetFunction()); + m_valueOf = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ValueOf)->GetFunction()); { v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(); @@ -80,6 +81,9 @@ void QV8VariantWrapper::init(QV8Engine *engine) ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0, m_toString, v8::DEFAULT, v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("valueOf"), ValueOfGetter, 0, + m_valueOf, v8::DEFAULT, + v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete)); m_constructor = qPersistentNew<v8::Function>(ft->GetFunction()); } { @@ -98,6 +102,9 @@ void QV8VariantWrapper::init(QV8Engine *engine) ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0, m_toString, v8::DEFAULT, v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("valueOf"), ValueOfGetter, 0, + m_valueOf, v8::DEFAULT, + v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete)); m_scarceConstructor = qPersistentNew<v8::Function>(ft->GetFunction()); } @@ -105,6 +112,7 @@ void QV8VariantWrapper::init(QV8Engine *engine) void QV8VariantWrapper::destroy() { + qPersistentDispose(m_valueOf); qPersistentDispose(m_toString); qPersistentDispose(m_destroy); qPersistentDispose(m_preserve); @@ -185,6 +193,13 @@ v8::Handle<v8::Value> QV8VariantWrapper::ToStringGetter(v8::Local<v8::String> pr return info.Data(); } +v8::Handle<v8::Value> QV8VariantWrapper::ValueOfGetter(v8::Local<v8::String> property, + const v8::AccessorInfo &info) +{ + Q_UNUSED(property); + return info.Data(); +} + v8::Handle<v8::Value> QV8VariantWrapper::Preserve(const v8::Arguments &args) { QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This()); @@ -217,4 +232,27 @@ v8::Handle<v8::Value> QV8VariantWrapper::ToString(const v8::Arguments &args) } } +v8::Handle<v8::Value> QV8VariantWrapper::ValueOf(const v8::Arguments &args) +{ + QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This()); + if (resource) { + QVariant v = resource->data; + switch (v.type()) { + case QVariant::Invalid: + return v8::Undefined(); + case QVariant::String: + return resource->engine->toString(v.toString()); + case QVariant::Int: + case QVariant::Double: + case QVariant::UInt: + return v8::Number::New(v.toDouble()); + case QVariant::Bool: + return v8::Boolean::New(v.toBool()); + default: + break; + } + } + return args.This(); +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/v8/qv8variantwrapper_p.h b/src/declarative/qml/v8/qv8variantwrapper_p.h index 9e165f37f4..de74bc9e12 100644 --- a/src/declarative/qml/v8/qv8variantwrapper_p.h +++ b/src/declarative/qml/v8/qv8variantwrapper_p.h @@ -87,9 +87,12 @@ private: const v8::AccessorInfo &info); static v8::Handle<v8::Value> ToStringGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info); + static v8::Handle<v8::Value> ValueOfGetter(v8::Local<v8::String> property, + const v8::AccessorInfo &info); static v8::Handle<v8::Value> Preserve(const v8::Arguments &args); static v8::Handle<v8::Value> Destroy(const v8::Arguments &args); static v8::Handle<v8::Value> ToString(const v8::Arguments &args); + static v8::Handle<v8::Value> ValueOf(const v8::Arguments &args); QV8Engine *m_engine; v8::Persistent<v8::Function> m_constructor; @@ -97,6 +100,7 @@ private: v8::Persistent<v8::Function> m_preserve; v8::Persistent<v8::Function> m_destroy; v8::Persistent<v8::Function> m_toString; + v8::Persistent<v8::Function> m_valueOf; }; QT_END_NAMESPACE diff --git a/src/declarative/qml/v8/script.pri b/src/declarative/qml/v8/script.pri new file mode 100644 index 0000000000..04a23d1f2b --- /dev/null +++ b/src/declarative/qml/v8/script.pri @@ -0,0 +1,20 @@ + +INCLUDEPATH += $$PWD + +SOURCES += \ + $$PWD/qjsengine.cpp \ + $$PWD/qjsvalue.cpp \ + $$PWD/qjsvalueiterator.cpp \ + +HEADERS += \ + $$PWD/qjsengine.h \ + $$PWD/qjsvalue.h \ + $$PWD/qjsvalue_p.h \ + $$PWD/qjsvalueiterator.h \ + $$PWD/qjsvalue_impl_p.h \ + $$PWD/qjsconverter_p.h \ + $$PWD/qscriptisolate_p.h \ + $$PWD/qscriptshareddata_p.h \ + $$PWD/qscripttools_p.h \ + $$PWD/qscript_impl_p.h \ + $$PWD/qscriptoriginalglobalobject_p.h diff --git a/src/declarative/qml/v8/v8.pri b/src/declarative/qml/v8/v8.pri index 61e0184884..97b3d679df 100644 --- a/src/declarative/qml/v8/v8.pri +++ b/src/declarative/qml/v8/v8.pri @@ -1,6 +1,8 @@ INCLUDEPATH += $$PWD/../../../3rdparty/javascriptcore INCLUDEPATH += $$PWD +include(script.pri) + HEADERS += \ $$PWD/qv8_p.h \ $$PWD/qv8stringwrapper_p.h \ @@ -16,6 +18,7 @@ HEADERS += \ $$PWD/qv8worker_p.h \ $$PWD/qv8bindings_p.h \ $$PWD/../../../3rdparty/javascriptcore/DateMath.h \ + $$PWD/qv8engine_impl_p.h SOURCES += \ $$PWD/qv8stringwrapper.cpp \ @@ -31,4 +34,3 @@ SOURCES += \ $$PWD/qv8worker.cpp \ $$PWD/qv8bindings.cpp \ $$PWD/../../../3rdparty/javascriptcore/DateMath.cpp \ - diff --git a/src/declarative/util/qdeclarativeanimation.cpp b/src/declarative/util/qdeclarativeanimation.cpp index 213ebe564a..977f7fa0d9 100644 --- a/src/declarative/util/qdeclarativeanimation.cpp +++ b/src/declarative/util/qdeclarativeanimation.cpp @@ -159,7 +159,7 @@ void QDeclarativeAbstractAnimationPrivate::commence() q->transition(actions, properties, QDeclarativeAbstractAnimation::Forward); q->qtAnimation()->start(); - if (q->qtAnimation()->state() != QAbstractAnimation::Running) { + if (q->qtAnimation()->state() == QAbstractAnimation::Stopped) { running = false; emit q->completed(); } @@ -265,6 +265,10 @@ void QDeclarativeAbstractAnimation::setPaused(bool p) } d->paused = p; + + if (!d->componentComplete) + return; + if (d->paused) qtAnimation()->pause(); else @@ -292,6 +296,10 @@ void QDeclarativeAbstractAnimation::componentFinalized() d->running = false; setRunning(true); } + if (d->paused) { + d->paused = false; + setPaused(true); + } } /*! diff --git a/src/declarative/util/qdeclarativebind.cpp b/src/declarative/util/qdeclarativebind.cpp index 6038aca8d5..fa463ebef8 100644 --- a/src/declarative/util/qdeclarativebind.cpp +++ b/src/declarative/util/qdeclarativebind.cpp @@ -52,9 +52,8 @@ #include <QtCore/qfile.h> #include <QtCore/qdebug.h> -#include <QtScript/qscriptvalue.h> -#include <QtScript/qscriptcontext.h> -#include <QtScript/qscriptengine.h> +#include <QtDeclarative/qjsvalue.h> +#include <QtDeclarative/qjsengine.h> #include <private/qobject_p.h> @@ -281,11 +280,11 @@ void QDeclarativeBind::eval() if (!d->when) { //restore any previous binding if (d->prevBind) { - QDeclarativeAbstractBinding *tmp; - tmp = QDeclarativePropertyPrivate::setBinding(d->prop, d->prevBind); + QDeclarativeAbstractBinding *tmp = d->prevBind; + d->prevBind = 0; + tmp = QDeclarativePropertyPrivate::setBinding(d->prop, tmp); if (tmp) //should this ever be true? tmp->destroy(); - d->prevBind = 0; } return; } diff --git a/src/declarative/util/qdeclarativelistmodel.cpp b/src/declarative/util/qdeclarativelistmodel.cpp index d1496fc886..035502140b 100644 --- a/src/declarative/util/qdeclarativelistmodel.cpp +++ b/src/declarative/util/qdeclarativelistmodel.cpp @@ -485,7 +485,7 @@ ModelObject *ModelNode::object(const NestedListModel *model) { if (!objectCache) { QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(qmlEngine(model->m_listModel)); - objectCache = new ModelObject(this, const_cast<NestedListModel*>(model), &ep->v8engine); + objectCache = new ModelObject(this, const_cast<NestedListModel*>(model), ep->v8engine()); QHash<QString, ModelNode *>::iterator it; for (it = properties.begin(); it != properties.end(); ++it) { @@ -1451,7 +1451,7 @@ v8::Handle<v8::Value> NestedListModel::get(int index) const if (!node) return v8::Undefined();; - return QDeclarativeEnginePrivate::get(eng)->v8engine.newQObject(node->object(this)); + return QDeclarativeEnginePrivate::get(eng)->v8engine()->newQObject(node->object(this)); } void NestedListModel::set(int index, v8::Handle<v8::Value> valuemap, QList<int> *roles) diff --git a/src/imports/folderlistmodel/folderlistmodel.pro b/src/imports/folderlistmodel/folderlistmodel.pro index e55a5b2a29..31192fd764 100644 --- a/src/imports/folderlistmodel/folderlistmodel.pro +++ b/src/imports/folderlistmodel/folderlistmodel.pro @@ -2,7 +2,7 @@ TARGET = qmlfolderlistmodelplugin TARGETPATH = Qt/labs/folderlistmodel include(../qimportbase.pri) -QT += declarative script +QT += declarative SOURCES += qdeclarativefolderlistmodel.cpp plugin.cpp HEADERS += qdeclarativefolderlistmodel.h diff --git a/src/imports/gestures/gestures.pro b/src/imports/gestures/gestures.pro index 76b31ded6a..3b735efac5 100644 --- a/src/imports/gestures/gestures.pro +++ b/src/imports/gestures/gestures.pro @@ -2,7 +2,7 @@ TARGET = qmlgesturesplugin TARGETPATH = Qt/labs/gestures include(../qimportbase.pri) -QT += core-private gui-private declarative-private script-private qtquick1 qtquick1-private widgets-private +QT += core-private gui-private declarative-private qtquick1 qtquick1-private widgets-private SOURCES += qdeclarativegesturearea.cpp plugin.cpp HEADERS += qdeclarativegesturearea_p.h diff --git a/src/imports/inputcontext/inputcontext.pro b/src/imports/inputcontext/inputcontext.pro index af0d840192..c8641d20e3 100755 --- a/src/imports/inputcontext/inputcontext.pro +++ b/src/imports/inputcontext/inputcontext.pro @@ -2,7 +2,7 @@ TARGET = qmlinputcontextplugin TARGETPATH = Qt/labs/inputcontext include(../qimportbase.pri) -QT += declarative script widgets +QT += declarative widgets SOURCES += \ declarativeinputcontext.cpp \ diff --git a/src/imports/inputcontext/plugin.cpp b/src/imports/inputcontext/plugin.cpp index a33aa479ae..70fed2e241 100644 --- a/src/imports/inputcontext/plugin.cpp +++ b/src/imports/inputcontext/plugin.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE -static QObject *createContext(QDeclarativeEngine *, QScriptEngine *) +static QObject *createContext(QDeclarativeEngine *, QJSEngine *) { return new InputContextModule; } diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp index 5781b3ddf1..db0a029a9a 100644 --- a/src/imports/testlib/main.cpp +++ b/src/imports/testlib/main.cpp @@ -41,10 +41,8 @@ #include <QtDeclarative/qdeclarativeextensionplugin.h> #include <QtDeclarative/qdeclarative.h> -#include <QtScript/qscriptvalue.h> -#include <QtScript/qscriptcontext.h> -#include <QtScript/qscriptcontextinfo.h> -#include <QtScript/qscriptengine.h> +#include <QtDeclarative/qjsvalue.h> +#include <QtDeclarative/qjsengine.h> #include "QtQuickTest/private/quicktestresult_p.h" #include "QtQuickTest/private/quicktestevent_p.h" #include "private/qtestoptions_p.h" diff --git a/src/imports/testlib/testlib.pro b/src/imports/testlib/testlib.pro index 9980a7551f..5adde2ae85 100644 --- a/src/imports/testlib/testlib.pro +++ b/src/imports/testlib/testlib.pro @@ -21,7 +21,7 @@ symbian { } -QT += declarative script qmltest qmltest-private declarative-private script-private core-private testlib +QT += declarative qmltest qmltest-private declarative-private core-private testlib SOURCES += main.cpp HEADERS += diff --git a/src/qmltest/qmltest.pro b/src/qmltest/qmltest.pro index 6e79be0b09..418136aa0a 100644 --- a/src/qmltest/qmltest.pro +++ b/src/qmltest/qmltest.pro @@ -7,7 +7,7 @@ CONFIG += module CONFIG += dll warn_on MODULE_PRI += ../../modules/qt_qmltest.pri -QT += testlib-private declarative script testlib qtquick1 +QT += testlib-private declarative testlib qtquick1 DEFINES += QT_BUILD_QUICK_TEST_LIB QT_NO_URL_CAST_FROM_STRING diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp index a2c494513b..3f0c5325ed 100644 --- a/src/qmltest/quicktest.cpp +++ b/src/qmltest/quicktest.cpp @@ -52,9 +52,8 @@ #include <QtDeclarative/qsgview.h> #define QUICK_TEST_SCENEGRAPH 1 #endif -#include <QtScript/qscriptvalue.h> -#include <QtScript/qscriptcontext.h> -#include <QtScript/qscriptengine.h> +#include <QtDeclarative/qjsvalue.h> +#include <QtDeclarative/qjsengine.h> #include <QtOpenGL/qgl.h> #include <QtCore/qurl.h> #include <QtCore/qfileinfo.h> @@ -73,7 +72,7 @@ QT_BEGIN_NAMESPACE class Q_DECLARATIVE_EXPORT QDeclarativeDebugHelper { public: - static QScriptEngine *getScriptEngine(QDeclarativeEngine *engine); + static QJSEngine *getScriptEngine(QDeclarativeEngine *engine); static void setAnimationSlowDownFactor(qreal factor); static void enableDebugging(); }; diff --git a/src/qtquick1/graphicsitems/qdeclarativeitem.cpp b/src/qtquick1/graphicsitems/qdeclarativeitem.cpp index a4654e4fe8..20b4c11f5b 100644 --- a/src/qtquick1/graphicsitems/qdeclarativeitem.cpp +++ b/src/qtquick1/graphicsitems/qdeclarativeitem.cpp @@ -59,7 +59,7 @@ #include <QEvent> #include <QGraphicsSceneMouseEvent> #include <QtCore/qnumeric.h> -#include <QtScript/qscriptengine.h> +#include <QtDeclarative/qjsengine.h> #include <private/qv8engine_p.h> #include <QtWidgets/qgraphicstransform.h> @@ -2897,7 +2897,7 @@ QDeclarativeListProperty<QDeclarative1Transition> QDeclarativeItemPrivate::trans If clipping is enabled, an item will clip its own painting, as well as the painting of its children, to its bounding rectangle. If you set - clipping during an item's paint operation, remember to re-set it to + clipping during an item's paint operation, remember to re-set it to prevent clipping the rest of your scene. Non-rectangular clipping regions are not supported for performance reasons. diff --git a/src/qtquick1/qtquick1.pro b/src/qtquick1/qtquick1.pro index e7db6062fb..2e3113e214 100644 --- a/src/qtquick1/qtquick1.pro +++ b/src/qtquick1/qtquick1.pro @@ -7,8 +7,7 @@ CONFIG += module CONFIG += dll warn_on MODULE_PRI += ../../modules/qt_qtquick1.pri -QT += testlib-private declarative script testlib declarative-private core-private gui-private script-private network widgets-private -DEFINES += QT_NO_URL_CAST_FROM_STRING +QT += testlib-private declarative testlib declarative-private core-private gui-private network widgets-private load(qt_module_config) diff --git a/src/qtquick1/util/qdeclarativeanimation.cpp b/src/qtquick1/util/qdeclarativeanimation.cpp index 46c3f15a29..89b768b827 100644 --- a/src/qtquick1/util/qdeclarativeanimation.cpp +++ b/src/qtquick1/util/qdeclarativeanimation.cpp @@ -162,7 +162,7 @@ void QDeclarative1AbstractAnimationPrivate::commence() q->transition(actions, properties, QDeclarative1AbstractAnimation::Forward); q->qtAnimation()->start(); - if (q->qtAnimation()->state() != QAbstractAnimation::Running) { + if (q->qtAnimation()->state() == QAbstractAnimation::Stopped) { running = false; emit q->completed(); } diff --git a/src/qtquick1/util/qdeclarativebind.cpp b/src/qtquick1/util/qdeclarativebind.cpp index f6463be05d..50514234a3 100644 --- a/src/qtquick1/util/qdeclarativebind.cpp +++ b/src/qtquick1/util/qdeclarativebind.cpp @@ -49,9 +49,8 @@ #include <QtCore/qfile.h> #include <QtCore/qdebug.h> -#include <QtScript/qscriptvalue.h> -#include <QtScript/qscriptcontext.h> -#include <QtScript/qscriptengine.h> +#include <QtDeclarative/qjsvalue.h> +#include <QtDeclarative/qjsengine.h> #include <private/qobject_p.h> diff --git a/src/qtquick1/util/qdeclarativelistmodel.cpp b/src/qtquick1/util/qdeclarativelistmodel.cpp index 5d60ed9658..520d9ac388 100644 --- a/src/qtquick1/util/qdeclarativelistmodel.cpp +++ b/src/qtquick1/util/qdeclarativelistmodel.cpp @@ -52,7 +52,7 @@ #include <QtCore/qdebug.h> #include <QtCore/qstack.h> #include <QXmlStreamReader> -#include <QtScript/qscriptvalueiterator.h> +#include <QtDeclarative/qscriptvalueiterator.h> Q_DECLARE_METATYPE(QListModelInterface *) diff --git a/src/qtquick1/util/qdeclarativelistmodel_p.h b/src/qtquick1/util/qdeclarativelistmodel_p.h index 21398f7213..1be5e6001a 100644 --- a/src/qtquick1/util/qdeclarativelistmodel_p.h +++ b/src/qtquick1/util/qdeclarativelistmodel_p.h @@ -51,7 +51,7 @@ #include <QtCore/QList> #include <QtCore/QVariant> #include <QtQuick1/private/qlistmodelinterface_p.h> -#include <QtScript/qscriptvalue.h> +#include <QtDeclarative/qjsvalue.h> QT_BEGIN_HEADER diff --git a/src/qtquick1/util/qdeclarativelistmodel_p_p.h b/src/qtquick1/util/qdeclarativelistmodel_p_p.h index e34f6d850d..ee39ba45b1 100644 --- a/src/qtquick1/util/qdeclarativelistmodel_p_p.h +++ b/src/qtquick1/util/qdeclarativelistmodel_p_p.h @@ -58,7 +58,7 @@ #include "QtQuick1/private/qdeclarativeopenmetaobject_p.h" #include <QtDeclarative/qdeclarative.h> -#include <QtScript/private/qscriptdeclarativeclass_p.h> +#include <QtDeclarative/private/qscriptdeclarativeclass_p.h> QT_BEGIN_HEADER diff --git a/src/qtquick1/util/qdeclarativelistmodelworkeragent_p.h b/src/qtquick1/util/qdeclarativelistmodelworkeragent_p.h index f0979c4b31..a769185607 100644 --- a/src/qtquick1/util/qdeclarativelistmodelworkeragent_p.h +++ b/src/qtquick1/util/qdeclarativelistmodelworkeragent_p.h @@ -55,7 +55,7 @@ #include <QtDeclarative/qdeclarative.h> -#include <QtScript/qscriptvalue.h> +#include <QtDeclarative/qjsvalue.h> #include <QtGui/qevent.h> #include <QMutex> #include <QWaitCondition> diff --git a/src/qtquick1/util/qdeclarativeview.cpp b/src/qtquick1/util/qdeclarativeview.cpp index 5f0e53a482..fd5f9debf7 100644 --- a/src/qtquick1/util/qdeclarativeview.cpp +++ b/src/qtquick1/util/qdeclarativeview.cpp @@ -51,7 +51,6 @@ #include <QtDeclarative/private/qdeclarativedebugtrace_p.h> #include <QtDeclarative/private/qdeclarativeinspectorservice_p.h> -#include <qscriptvalueiterator.h> #include <qdebug.h> #include <qtimer.h> #include <qevent.h> diff --git a/src/v8/0009-Add-CallAsFunction-method-to-the-Object-class-in-the.patch b/src/v8/0009-Add-CallAsFunction-method-to-the-Object-class-in-the.patch new file mode 100644 index 0000000000..6cd9294d31 --- /dev/null +++ b/src/v8/0009-Add-CallAsFunction-method-to-the-Object-class-in-the.patch @@ -0,0 +1,286 @@ +From 5719ba59309e85f3ca47da6b64df66e710f3016f Mon Sep 17 00:00:00 2001 +From: "ager@chromium.org" <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00> +Date: Wed, 4 May 2011 13:03:08 +0000 +Subject: [PATCH] Add CallAsFunction method to the Object class in the API + +Patch by Peter Varga. + +BUG=v8:1336 +TEST=cctest/test-api/CallAsFunction + +Review URL: http://codereview.chromium.org/6883045 + +git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@7781 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 +--- + include/v8.h | 8 +++ + src/api.cc | 31 +++++++++++ + src/execution.cc | 24 ++++++++ + src/execution.h | 2 + + test/cctest/test-api.cc | 135 ++++++++++++++++++++++++++++++++++------------- + 5 files changed, 163 insertions(+), 37 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index 4dcbf28..78ee7e6 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -1606,6 +1606,14 @@ class Object : public Value { + V8EXPORT ExternalArrayType GetIndexedPropertiesExternalArrayDataType(); + V8EXPORT int GetIndexedPropertiesExternalArrayDataLength(); + ++ /** ++ * Call an Object as a function if a callback is set by the ++ * ObjectTemplate::SetCallAsFunctionHandler method. ++ */ ++ V8EXPORT Local<Value> CallAsFunction(Handle<Object> recv, ++ int argc, ++ Handle<Value> argv[]); ++ + V8EXPORT static Local<Object> New(); + static inline Object* Cast(Value* obj); + private: +diff --git a/src/api.cc b/src/api.cc +index 792e488..c72857d 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -3255,6 +3255,37 @@ int v8::Object::GetIndexedPropertiesExternalArrayDataLength() { + } + + ++Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int argc, ++ v8::Handle<v8::Value> argv[]) { ++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ++ ON_BAILOUT(isolate, "v8::Object::CallAsFunction()", ++ return Local<v8::Value>()); ++ LOG_API(isolate, "Object::CallAsFunction"); ++ ENTER_V8(isolate); ++ HandleScope scope; ++ i::Handle<i::JSObject> obj = Utils::OpenHandle(this); ++ i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv); ++ STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**)); ++ i::Object*** args = reinterpret_cast<i::Object***>(argv); ++ i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>(); ++ if (obj->IsJSFunction()) { ++ fun = i::Handle<i::JSFunction>::cast(obj); ++ } else { ++ EXCEPTION_PREAMBLE(isolate); ++ i::Handle<i::Object> delegate = ++ i::Execution::TryGetFunctionDelegate(obj, &has_pending_exception); ++ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>()); ++ fun = i::Handle<i::JSFunction>::cast(delegate); ++ recv_obj = obj; ++ } ++ EXCEPTION_PREAMBLE(isolate); ++ i::Handle<i::Object> returned = ++ i::Execution::Call(fun, recv_obj, argc, args, &has_pending_exception); ++ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>()); ++ return scope.Close(Utils::ToLocal(returned)); ++} ++ ++ + Local<v8::Object> Function::NewInstance() const { + return NewInstance(0, NULL); + } +diff --git a/src/execution.cc b/src/execution.cc +index eb26438..850dec5 100644 +--- a/src/execution.cc ++++ b/src/execution.cc +@@ -234,6 +234,30 @@ Handle<Object> Execution::GetFunctionDelegate(Handle<Object> object) { + } + + ++Handle<Object> Execution::TryGetFunctionDelegate(Handle<Object> object, ++ bool* has_pending_exception) { ++ ASSERT(!object->IsJSFunction()); ++ Isolate* isolate = Isolate::Current(); ++ ++ // Objects created through the API can have an instance-call handler ++ // that should be used when calling the object as a function. ++ if (object->IsHeapObject() && ++ HeapObject::cast(*object)->map()->has_instance_call_handler()) { ++ return Handle<JSFunction>( ++ isolate->global_context()->call_as_function_delegate()); ++ } ++ ++ // If the Object doesn't have an instance-call handler we should ++ // throw a non-callable exception. ++ i::Handle<i::Object> error_obj = isolate->factory()->NewTypeError( ++ "called_non_callable", i::HandleVector<i::Object>(&object, 1)); ++ isolate->Throw(*error_obj); ++ *has_pending_exception = true; ++ ++ return isolate->factory()->undefined_value(); ++} ++ ++ + Handle<Object> Execution::GetConstructorDelegate(Handle<Object> object) { + ASSERT(!object->IsJSFunction()); + Isolate* isolate = Isolate::Current(); +diff --git a/src/execution.h b/src/execution.h +index d4b80d2..e89d6ba 100644 +--- a/src/execution.h ++++ b/src/execution.h +@@ -138,6 +138,8 @@ class Execution : public AllStatic { + // Get a function delegate (or undefined) for the given non-function + // object. Used for support calling objects as functions. + static Handle<Object> GetFunctionDelegate(Handle<Object> object); ++ static Handle<Object> TryGetFunctionDelegate(Handle<Object> object, ++ bool* has_pending_exception); + + // Get a function delegate (or undefined) for the given non-function + // object. Used for support calling objects as constructors. +diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc +index e2a7fb1..c6affe5 100644 +--- a/test/cctest/test-api.cc ++++ b/test/cctest/test-api.cc +@@ -6962,50 +6962,111 @@ THREADED_TEST(CallAsFunction) { + v8::HandleScope scope; + LocalContext context; + +- Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); +- Local<ObjectTemplate> instance_template = t->InstanceTemplate(); +- instance_template->SetCallAsFunctionHandler(call_as_function); +- Local<v8::Object> instance = t->GetFunction()->NewInstance(); +- context->Global()->Set(v8_str("obj"), instance); +- v8::TryCatch try_catch; +- Local<Value> value; +- CHECK(!try_catch.HasCaught()); ++ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); ++ Local<ObjectTemplate> instance_template = t->InstanceTemplate(); ++ instance_template->SetCallAsFunctionHandler(call_as_function); ++ Local<v8::Object> instance = t->GetFunction()->NewInstance(); ++ context->Global()->Set(v8_str("obj"), instance); ++ v8::TryCatch try_catch; ++ Local<Value> value; ++ CHECK(!try_catch.HasCaught()); + +- value = CompileRun("obj(42)"); +- CHECK(!try_catch.HasCaught()); +- CHECK_EQ(42, value->Int32Value()); ++ value = CompileRun("obj(42)"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(42, value->Int32Value()); + +- value = CompileRun("(function(o){return o(49)})(obj)"); +- CHECK(!try_catch.HasCaught()); +- CHECK_EQ(49, value->Int32Value()); ++ value = CompileRun("(function(o){return o(49)})(obj)"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(49, value->Int32Value()); + +- // test special case of call as function +- value = CompileRun("[obj]['0'](45)"); +- CHECK(!try_catch.HasCaught()); +- CHECK_EQ(45, value->Int32Value()); ++ // test special case of call as function ++ value = CompileRun("[obj]['0'](45)"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(45, value->Int32Value()); + +- value = CompileRun("obj.call = Function.prototype.call;" +- "obj.call(null, 87)"); +- CHECK(!try_catch.HasCaught()); +- CHECK_EQ(87, value->Int32Value()); ++ value = CompileRun("obj.call = Function.prototype.call;" ++ "obj.call(null, 87)"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(87, value->Int32Value()); + +- // Regression tests for bug #1116356: Calling call through call/apply +- // must work for non-function receivers. +- const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])"; +- value = CompileRun(apply_99); +- CHECK(!try_catch.HasCaught()); +- CHECK_EQ(99, value->Int32Value()); ++ // Regression tests for bug #1116356: Calling call through call/apply ++ // must work for non-function receivers. ++ const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])"; ++ value = CompileRun(apply_99); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(99, value->Int32Value()); + +- const char* call_17 = "Function.prototype.call.call(obj, this, 17)"; +- value = CompileRun(call_17); +- CHECK(!try_catch.HasCaught()); +- CHECK_EQ(17, value->Int32Value()); ++ const char* call_17 = "Function.prototype.call.call(obj, this, 17)"; ++ value = CompileRun(call_17); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(17, value->Int32Value()); + +- // Check that the call-as-function handler can be called through +- // new. +- value = CompileRun("new obj(43)"); +- CHECK(!try_catch.HasCaught()); +- CHECK_EQ(-43, value->Int32Value()); ++ // Check that the call-as-function handler can be called through ++ // new. ++ value = CompileRun("new obj(43)"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(-43, value->Int32Value()); ++ ++ // Check that the call-as-function handler can be called through ++ // the API. ++ v8::Handle<Value> args[] = { v8_num(28) }; ++ value = instance->CallAsFunction(instance, 1, args); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(28, value->Int32Value()); ++ } ++ ++ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); ++ Local<ObjectTemplate> instance_template = t->InstanceTemplate(); ++ Local<v8::Object> instance = t->GetFunction()->NewInstance(); ++ context->Global()->Set(v8_str("obj2"), instance); ++ v8::TryCatch try_catch; ++ Local<Value> value; ++ CHECK(!try_catch.HasCaught()); ++ ++ // Call an object without call-as-function handler through the JS ++ value = CompileRun("obj2(28)"); ++ CHECK(value.IsEmpty()); ++ CHECK(try_catch.HasCaught()); ++ String::AsciiValue exception_value1(try_catch.Exception()); ++ CHECK_EQ(*exception_value1, ++ "TypeError: Property 'obj2' of object " ++ "#<Object> is not a function"); ++ try_catch.Reset(); ++ ++ // Call an object without call-as-function handler through the API ++ value = CompileRun("obj2(28)"); ++ v8::Handle<Value> args[] = { v8_num(28) }; ++ value = instance->CallAsFunction(instance, 1, args); ++ CHECK(value.IsEmpty()); ++ CHECK(try_catch.HasCaught()); ++ String::AsciiValue exception_value2(try_catch.Exception()); ++ CHECK_EQ(*exception_value2, "TypeError: [object Object] is not a function"); ++ try_catch.Reset(); ++ } ++ ++ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); ++ Local<ObjectTemplate> instance_template = t->InstanceTemplate(); ++ instance_template->SetCallAsFunctionHandler(ThrowValue); ++ Local<v8::Object> instance = t->GetFunction()->NewInstance(); ++ context->Global()->Set(v8_str("obj3"), instance); ++ v8::TryCatch try_catch; ++ Local<Value> value; ++ CHECK(!try_catch.HasCaught()); ++ ++ // Catch the exception which is thrown by call-as-function handler ++ value = CompileRun("obj3(22)"); ++ CHECK(try_catch.HasCaught()); ++ String::AsciiValue exception_value1(try_catch.Exception()); ++ CHECK_EQ(*exception_value1, "22"); ++ try_catch.Reset(); ++ ++ v8::Handle<Value> args[] = { v8_num(23) }; ++ value = instance->CallAsFunction(instance, 1, args); ++ CHECK(try_catch.HasCaught()); ++ String::AsciiValue exception_value2(try_catch.Exception()); ++ CHECK_EQ(*exception_value2, "23"); ++ try_catch.Reset(); ++ } + } + + +-- +1.7.5.4 + diff --git a/src/v8/0010-Implement-CallAsConstructor-method-for-Object-in-the.patch b/src/v8/0010-Implement-CallAsConstructor-method-for-Object-in-the.patch new file mode 100644 index 0000000000..7d90f0dfbd --- /dev/null +++ b/src/v8/0010-Implement-CallAsConstructor-method-for-Object-in-the.patch @@ -0,0 +1,397 @@ +From fd2cc52576e8c89f3dffc2b4b5a9cc9c48a96f32 Mon Sep 17 00:00:00 2001 +From: "ager@chromium.org" <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00> +Date: Fri, 6 May 2011 11:07:52 +0000 +Subject: [PATCH] Implement CallAsConstructor method for Object in the API + +Patch by Peter Varga. + +BUG=v8:1348 +TEST=cctest/test-api/ConstructorForObject + +Review URL: http://codereview.chromium.org/6902108 + +git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@7803 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 +--- + include/v8.h | 8 ++ + src/api.cc | 41 +++++++++- + src/execution.cc | 28 +++++++ + src/execution.h | 2 + + test/cctest/test-api.cc | 205 +++++++++++++++++++++++++++++++++++++++++++++-- + 5 files changed, 276 insertions(+), 8 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index 4921823..5fc8059 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -1614,6 +1614,14 @@ class Object : public Value { + int argc, + Handle<Value> argv[]); + ++ /** ++ * Call an Object as a consturctor if a callback is set by the ++ * ObjectTemplate::SetCallAsFunctionHandler method. ++ * Note: This method behaves like the Function::NewInstance method. ++ */ ++ V8EXPORT Local<Value> CallAsConstructor(int argc, ++ Handle<Value> argv[]); ++ + V8EXPORT static Local<Object> New(); + static inline Object* Cast(Value* obj); + private: +diff --git a/src/api.cc b/src/api.cc +index c5c66a7..9194641 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -3262,7 +3262,7 @@ Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int argc, + return Local<v8::Value>()); + LOG_API(isolate, "Object::CallAsFunction"); + ENTER_V8(isolate); +- HandleScope scope; ++ i::HandleScope scope(isolate); + i::Handle<i::JSObject> obj = Utils::OpenHandle(this); + i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv); + STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**)); +@@ -3282,7 +3282,44 @@ Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int argc, + i::Handle<i::Object> returned = + i::Execution::Call(fun, recv_obj, argc, args, &has_pending_exception); + EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>()); +- return scope.Close(Utils::ToLocal(returned)); ++ return Utils::ToLocal(scope.CloseAndEscape(returned)); ++} ++ ++ ++Local<v8::Value> Object::CallAsConstructor(int argc, ++ v8::Handle<v8::Value> argv[]) { ++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ++ ON_BAILOUT(isolate, "v8::Object::CallAsConstructor()", ++ return Local<v8::Object>()); ++ LOG_API(isolate, "Object::CallAsConstructor"); ++ ENTER_V8(isolate); ++ i::HandleScope scope(isolate); ++ i::Handle<i::JSObject> obj = Utils::OpenHandle(this); ++ STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**)); ++ i::Object*** args = reinterpret_cast<i::Object***>(argv); ++ if (obj->IsJSFunction()) { ++ i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(obj); ++ EXCEPTION_PREAMBLE(isolate); ++ i::Handle<i::Object> returned = ++ i::Execution::New(fun, argc, args, &has_pending_exception); ++ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>()); ++ return Utils::ToLocal(scope.CloseAndEscape( ++ i::Handle<i::JSObject>::cast(returned))); ++ } ++ EXCEPTION_PREAMBLE(isolate); ++ i::Handle<i::Object> delegate = ++ i::Execution::TryGetConstructorDelegate(obj, &has_pending_exception); ++ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>()); ++ if (!delegate->IsUndefined()) { ++ i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(delegate); ++ EXCEPTION_PREAMBLE(isolate); ++ i::Handle<i::Object> returned = ++ i::Execution::Call(fun, obj, argc, args, &has_pending_exception); ++ EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>()); ++ ASSERT(!delegate->IsUndefined()); ++ return Utils::ToLocal(scope.CloseAndEscape(returned)); ++ } ++ return Local<v8::Object>(); + } + + +diff --git a/src/execution.cc b/src/execution.cc +index 4ab3e78..db74492 100644 +--- a/src/execution.cc ++++ b/src/execution.cc +@@ -277,6 +277,34 @@ Handle<Object> Execution::GetConstructorDelegate(Handle<Object> object) { + } + + ++Handle<Object> Execution::TryGetConstructorDelegate( ++ Handle<Object> object, ++ bool* has_pending_exception) { ++ ASSERT(!object->IsJSFunction()); ++ Isolate* isolate = Isolate::Current(); ++ ++ // If you return a function from here, it will be called when an ++ // attempt is made to call the given object as a constructor. ++ ++ // Objects created through the API can have an instance-call handler ++ // that should be used when calling the object as a function. ++ if (object->IsHeapObject() && ++ HeapObject::cast(*object)->map()->has_instance_call_handler()) { ++ return Handle<JSFunction>( ++ isolate->global_context()->call_as_constructor_delegate()); ++ } ++ ++ // If the Object doesn't have an instance-call handler we should ++ // throw a non-callable exception. ++ i::Handle<i::Object> error_obj = isolate->factory()->NewTypeError( ++ "called_non_callable", i::HandleVector<i::Object>(&object, 1)); ++ isolate->Throw(*error_obj); ++ *has_pending_exception = true; ++ ++ return isolate->factory()->undefined_value(); ++} ++ ++ + bool StackGuard::IsStackOverflow() { + ExecutionAccess access(isolate_); + return (thread_local_.jslimit_ != kInterruptLimit && +diff --git a/src/execution.h b/src/execution.h +index 74189a2..7b6a48c 100644 +--- a/src/execution.h ++++ b/src/execution.h +@@ -146,6 +146,8 @@ class Execution : public AllStatic { + // Get a function delegate (or undefined) for the given non-function + // object. Used for support calling objects as constructors. + static Handle<Object> GetConstructorDelegate(Handle<Object> object); ++ static Handle<Object> TryGetConstructorDelegate(Handle<Object> object, ++ bool* has_pending_exception); + }; + + +diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc +index 1bcc232..f48d5b4 100644 +--- a/test/cctest/test-api.cc ++++ b/test/cctest/test-api.cc +@@ -6747,6 +6747,200 @@ THREADED_TEST(Constructor) { + CHECK(value->BooleanValue()); + } + ++ ++static Handle<Value> ConstructorCallback(const Arguments& args) { ++ ApiTestFuzzer::Fuzz(); ++ Local<Object> This; ++ ++ if (args.IsConstructCall()) { ++ Local<Object> Holder = args.Holder(); ++ This = Object::New(); ++ Local<Value> proto = Holder->GetPrototype(); ++ if (proto->IsObject()) { ++ This->SetPrototype(proto); ++ } ++ } else { ++ This = args.This(); ++ } ++ ++ This->Set(v8_str("a"), args[0]); ++ return This; ++} ++ ++ ++static Handle<Value> FakeConstructorCallback(const Arguments& args) { ++ ApiTestFuzzer::Fuzz(); ++ return args[0]; ++} ++ ++ ++THREADED_TEST(ConstructorForObject) { ++ v8::HandleScope handle_scope; ++ LocalContext context; ++ ++ { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); ++ instance_template->SetCallAsFunctionHandler(ConstructorCallback); ++ Local<Object> instance = instance_template->NewInstance(); ++ context->Global()->Set(v8_str("obj"), instance); ++ v8::TryCatch try_catch; ++ Local<Value> value; ++ CHECK(!try_catch.HasCaught()); ++ ++ // Call the Object's constructor with a 32-bit signed integer. ++ value = CompileRun("(function() { var o = new obj(28); return o.a; })()"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsInt32()); ++ CHECK_EQ(28, value->Int32Value()); ++ ++ Local<Value> args1[] = { v8_num(28) }; ++ Local<Value> value_obj1 = instance->CallAsConstructor(1, args1); ++ CHECK(value_obj1->IsObject()); ++ Local<Object> object1 = Local<Object>::Cast(value_obj1); ++ value = object1->Get(v8_str("a")); ++ CHECK(value->IsInt32()); ++ CHECK(!try_catch.HasCaught()); ++ CHECK_EQ(28, value->Int32Value()); ++ ++ // Call the Object's constructor with a String. ++ value = CompileRun( ++ "(function() { var o = new obj('tipli'); return o.a; })()"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsString()); ++ String::AsciiValue string_value1(value->ToString()); ++ CHECK_EQ("tipli", *string_value1); ++ ++ Local<Value> args2[] = { v8_str("tipli") }; ++ Local<Value> value_obj2 = instance->CallAsConstructor(1, args2); ++ CHECK(value_obj2->IsObject()); ++ Local<Object> object2 = Local<Object>::Cast(value_obj2); ++ value = object2->Get(v8_str("a")); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsString()); ++ String::AsciiValue string_value2(value->ToString()); ++ CHECK_EQ("tipli", *string_value2); ++ ++ // Call the Object's constructor with a Boolean. ++ value = CompileRun("(function() { var o = new obj(true); return o.a; })()"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsBoolean()); ++ CHECK_EQ(true, value->BooleanValue()); ++ ++ Handle<Value> args3[] = { v8::Boolean::New(true) }; ++ Local<Value> value_obj3 = instance->CallAsConstructor(1, args3); ++ CHECK(value_obj3->IsObject()); ++ Local<Object> object3 = Local<Object>::Cast(value_obj3); ++ value = object3->Get(v8_str("a")); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsBoolean()); ++ CHECK_EQ(true, value->BooleanValue()); ++ ++ // Call the Object's constructor with undefined. ++ Handle<Value> args4[] = { v8::Undefined() }; ++ Local<Value> value_obj4 = instance->CallAsConstructor(1, args4); ++ CHECK(value_obj4->IsObject()); ++ Local<Object> object4 = Local<Object>::Cast(value_obj4); ++ value = object4->Get(v8_str("a")); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsUndefined()); ++ ++ // Call the Object's constructor with null. ++ Handle<Value> args5[] = { v8::Null() }; ++ Local<Value> value_obj5 = instance->CallAsConstructor(1, args5); ++ CHECK(value_obj5->IsObject()); ++ Local<Object> object5 = Local<Object>::Cast(value_obj5); ++ value = object5->Get(v8_str("a")); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsNull()); ++ } ++ ++ // Check exception handling when there is no constructor set for the Object. ++ { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); ++ Local<Object> instance = instance_template->NewInstance(); ++ context->Global()->Set(v8_str("obj2"), instance); ++ v8::TryCatch try_catch; ++ Local<Value> value; ++ CHECK(!try_catch.HasCaught()); ++ ++ value = CompileRun("new obj2(28)"); ++ CHECK(try_catch.HasCaught()); ++ String::AsciiValue exception_value1(try_catch.Exception()); ++ CHECK_EQ("TypeError: object is not a function", *exception_value1); ++ try_catch.Reset(); ++ ++ Local<Value> args[] = { v8_num(29) }; ++ value = instance->CallAsConstructor(1, args); ++ CHECK(try_catch.HasCaught()); ++ String::AsciiValue exception_value2(try_catch.Exception()); ++ CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2); ++ try_catch.Reset(); ++ } ++ ++ // Check the case when constructor throws exception. ++ { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); ++ instance_template->SetCallAsFunctionHandler(ThrowValue); ++ Local<Object> instance = instance_template->NewInstance(); ++ context->Global()->Set(v8_str("obj3"), instance); ++ v8::TryCatch try_catch; ++ Local<Value> value; ++ CHECK(!try_catch.HasCaught()); ++ ++ value = CompileRun("new obj3(22)"); ++ CHECK(try_catch.HasCaught()); ++ String::AsciiValue exception_value1(try_catch.Exception()); ++ CHECK_EQ("22", *exception_value1); ++ try_catch.Reset(); ++ ++ Local<Value> args[] = { v8_num(23) }; ++ value = instance->CallAsConstructor(1, args); ++ CHECK(try_catch.HasCaught()); ++ String::AsciiValue exception_value2(try_catch.Exception()); ++ CHECK_EQ("23", *exception_value2); ++ try_catch.Reset(); ++ } ++ ++ // Check whether constructor returns with an object or non-object. ++ { Local<FunctionTemplate> function_template = ++ FunctionTemplate::New(FakeConstructorCallback); ++ Local<Function> function = function_template->GetFunction(); ++ Local<Object> instance1 = function; ++ context->Global()->Set(v8_str("obj4"), instance1); ++ v8::TryCatch try_catch; ++ Local<Value> value; ++ CHECK(!try_catch.HasCaught()); ++ ++ CHECK(instance1->IsObject()); ++ CHECK(instance1->IsFunction()); ++ ++ value = CompileRun("new obj4(28)"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsObject()); ++ ++ Local<Value> args1[] = { v8_num(28) }; ++ value = instance1->CallAsConstructor(1, args1); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(value->IsObject()); ++ ++ Local<ObjectTemplate> instance_template = ObjectTemplate::New(); ++ instance_template->SetCallAsFunctionHandler(FakeConstructorCallback); ++ Local<Object> instance2 = instance_template->NewInstance(); ++ context->Global()->Set(v8_str("obj5"), instance2); ++ CHECK(!try_catch.HasCaught()); ++ ++ CHECK(instance2->IsObject()); ++ CHECK(!instance2->IsFunction()); ++ ++ value = CompileRun("new obj5(28)"); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(!value->IsObject()); ++ ++ Local<Value> args2[] = { v8_num(28) }; ++ value = instance2->CallAsConstructor(1, args2); ++ CHECK(!try_catch.HasCaught()); ++ CHECK(!value->IsObject()); ++ } ++} ++ ++ + THREADED_TEST(FunctionDescriptorException) { + v8::HandleScope handle_scope; + LocalContext context; +@@ -7029,9 +7223,8 @@ THREADED_TEST(CallAsFunction) { + CHECK(value.IsEmpty()); + CHECK(try_catch.HasCaught()); + String::AsciiValue exception_value1(try_catch.Exception()); +- CHECK_EQ(*exception_value1, +- "TypeError: Property 'obj2' of object " +- "#<Object> is not a function"); ++ CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function", ++ *exception_value1); + try_catch.Reset(); + + // Call an object without call-as-function handler through the API +@@ -7041,7 +7234,7 @@ THREADED_TEST(CallAsFunction) { + CHECK(value.IsEmpty()); + CHECK(try_catch.HasCaught()); + String::AsciiValue exception_value2(try_catch.Exception()); +- CHECK_EQ(*exception_value2, "TypeError: [object Object] is not a function"); ++ CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2); + try_catch.Reset(); + } + +@@ -7058,14 +7251,14 @@ THREADED_TEST(CallAsFunction) { + value = CompileRun("obj3(22)"); + CHECK(try_catch.HasCaught()); + String::AsciiValue exception_value1(try_catch.Exception()); +- CHECK_EQ(*exception_value1, "22"); ++ CHECK_EQ("22", *exception_value1); + try_catch.Reset(); + + v8::Handle<Value> args[] = { v8_num(23) }; + value = instance->CallAsFunction(instance, 1, args); + CHECK(try_catch.HasCaught()); + String::AsciiValue exception_value2(try_catch.Exception()); +- CHECK_EQ(*exception_value2, "23"); ++ CHECK_EQ("23", *exception_value2); + try_catch.Reset(); + } + } +-- +1.7.5.4 + diff --git a/src/v8/0011-QtScript-V8-Add-new-v8-api-to-check-if-a-value-is-an.patch b/src/v8/0011-QtScript-V8-Add-new-v8-api-to-check-if-a-value-is-an.patch new file mode 100644 index 0000000000..0558ce19f6 --- /dev/null +++ b/src/v8/0011-QtScript-V8-Add-new-v8-api-to-check-if-a-value-is-an.patch @@ -0,0 +1,63 @@ +From 859c452847317efe1131e337fcd51514de616ea2 Mon Sep 17 00:00:00 2001 +From: Jedrzej Nowacki <jedrzej.nowacki@nokia.com> +Date: Tue, 7 Dec 2010 11:56:42 +0100 +Subject: [PATCH] QtScript/V8: Add new v8 api to check if a value is an error. + +New function v8::Value::IsError was created. + +This API is experimental and added only for the purposes of our +research. +--- + include/v8.h | 5 +++++ + src/api.cc | 6 ++++++ + src/heap.h | 1 + + 3 files changed, 12 insertions(+), 0 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index 303cb7a..f992cb2 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -937,6 +937,11 @@ class Value : public Data { + */ + V8EXPORT bool IsRegExp() const; + ++ /** ++ * Returns true if this value is an Error. ++ */ ++ V8EXPORT bool IsError() const; ++ + V8EXPORT Local<Boolean> ToBoolean() const; + V8EXPORT Local<Number> ToNumber() const; + V8EXPORT Local<String> ToString() const; +diff --git a/src/api.cc b/src/api.cc +index fd4a76b..5ada246 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -2108,6 +2108,12 @@ bool Value::IsRegExp() const { + return obj->IsJSRegExp(); + } + ++bool Value::IsError() const { ++ if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsError()")) return false; ++ i::Handle<i::Object> obj = Utils::OpenHandle(this); ++ return obj->HasSpecificClassOf(HEAP->Error_symbol()); ++} ++ + + Local<String> Value::ToString() const { + i::Handle<i::Object> obj = Utils::OpenHandle(this); +diff --git a/src/heap.h b/src/heap.h +index 8cbf378..db90bb9 100644 +--- a/src/heap.h ++++ b/src/heap.h +@@ -169,6 +169,7 @@ inline Heap* _inline_get_heap_(); + V(string_symbol, "string") \ + V(String_symbol, "String") \ + V(Date_symbol, "Date") \ ++ V(Error_symbol, "Error") \ + V(this_symbol, "this") \ + V(to_string_symbol, "toString") \ + V(char_at_symbol, "CharAt") \ +-- +1.7.4.15.g7811d + |