aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/qml')
-rw-r--r--src/declarative/qml/qdeclarativebinding.cpp37
-rw-r--r--src/declarative/qml/qdeclarativebinding_p.h2
-rw-r--r--src/declarative/qml/qdeclarativeboundsignal.cpp1
-rw-r--r--src/declarative/qml/qdeclarativecompiler.cpp13
-rw-r--r--src/declarative/qml/qdeclarativecomponent.cpp125
-rw-r--r--src/declarative/qml/qdeclarativecomponent.h4
-rw-r--r--src/declarative/qml/qdeclarativecomponent_p.h2
-rw-r--r--src/declarative/qml/qdeclarativecontext.cpp25
-rw-r--r--src/declarative/qml/qdeclarativecontext.h2
-rw-r--r--src/declarative/qml/qdeclarativecontext_p.h10
-rw-r--r--src/declarative/qml/qdeclarativecontextscriptclass.cpp335
-rw-r--r--src/declarative/qml/qdeclarativedata_p.h19
-rw-r--r--src/declarative/qml/qdeclarativeengine.cpp1046
-rw-r--r--src/declarative/qml/qdeclarativeengine.h2
-rw-r--r--src/declarative/qml/qdeclarativeengine_p.h116
-rw-r--r--src/declarative/qml/qdeclarativeenginedebug.cpp2
-rw-r--r--src/declarative/qml/qdeclarativeexpression.cpp275
-rw-r--r--src/declarative/qml/qdeclarativeexpression.h3
-rw-r--r--src/declarative/qml/qdeclarativeexpression_p.h25
-rw-r--r--src/declarative/qml/qdeclarativeglobalscriptclass.cpp147
-rw-r--r--src/declarative/qml/qdeclarativeglobalscriptclass_p.h86
-rw-r--r--src/declarative/qml/qdeclarativeinclude.cpp310
-rw-r--r--src/declarative/qml/qdeclarativeintegercache.cpp29
-rw-r--r--src/declarative/qml/qdeclarativeintegercache_p.h36
-rw-r--r--src/declarative/qml/qdeclarativelistscriptclass.cpp149
-rw-r--r--src/declarative/qml/qdeclarativemetatype.cpp9
-rw-r--r--src/declarative/qml/qdeclarativeobjectscriptclass.cpp1226
-rw-r--r--src/declarative/qml/qdeclarativeobjectscriptclass_p.h166
-rw-r--r--src/declarative/qml/qdeclarativeproperty.cpp2
-rw-r--r--src/declarative/qml/qdeclarativepropertycache.cpp79
-rw-r--r--src/declarative/qml/qdeclarativepropertycache_p.h52
-rw-r--r--src/declarative/qml/qdeclarativescarceresourcescriptclass.cpp219
-rw-r--r--src/declarative/qml/qdeclarativescarceresourcescriptclass_p.h163
-rw-r--r--src/declarative/qml/qdeclarativesqldatabase.cpp585
-rw-r--r--src/declarative/qml/qdeclarativesqldatabase_p.h8
-rw-r--r--src/declarative/qml/qdeclarativetypeloader.cpp11
-rw-r--r--src/declarative/qml/qdeclarativetypeloader_p.h8
-rw-r--r--src/declarative/qml/qdeclarativetypenamecache.cpp29
-rw-r--r--src/declarative/qml/qdeclarativetypenamecache_p.h38
-rw-r--r--src/declarative/qml/qdeclarativetypenamescriptclass.cpp195
-rw-r--r--src/declarative/qml/qdeclarativevaluetypescriptclass.cpp242
-rw-r--r--src/declarative/qml/qdeclarativevme.cpp83
-rw-r--r--src/declarative/qml/qdeclarativevme_p.h5
-rw-r--r--src/declarative/qml/qdeclarativevmemetaobject.cpp81
-rw-r--r--src/declarative/qml/qdeclarativevmemetaobject_p.h16
-rw-r--r--src/declarative/qml/qdeclarativeworkerscript.cpp414
-rw-r--r--src/declarative/qml/qdeclarativeworkerscript_p.h8
-rw-r--r--src/declarative/qml/qdeclarativexmlhttprequest.cpp1390
-rw-r--r--src/declarative/qml/qdeclarativexmlhttprequest_p.h6
-rw-r--r--src/declarative/qml/qintrusivelist_p.h7
-rw-r--r--src/declarative/qml/qml.pri17
-rw-r--r--src/declarative/qml/v4/qdeclarativev4bindings.cpp3
-rw-r--r--src/declarative/qml/v4/qdeclarativev4irbuilder.cpp3
-rw-r--r--src/declarative/qml/v8/notes.txt4
-rw-r--r--src/declarative/qml/v8/qhashedstring.cpp103
-rw-r--r--src/declarative/qml/v8/qhashedstring_p.h572
-rw-r--r--src/declarative/qml/v8/qv8_p.h1
-rw-r--r--src/declarative/qml/v8/qv8contextwrapper.cpp432
-rw-r--r--src/declarative/qml/v8/qv8contextwrapper_p.h (renamed from src/declarative/qml/qdeclarativecontextscriptclass_p.h)77
-rw-r--r--src/declarative/qml/v8/qv8engine.cpp1479
-rw-r--r--src/declarative/qml/v8/qv8engine_p.h450
-rw-r--r--src/declarative/qml/v8/qv8include.cpp243
-rw-r--r--src/declarative/qml/v8/qv8include_p.h (renamed from src/declarative/qml/qdeclarativeinclude_p.h)48
-rw-r--r--src/declarative/qml/v8/qv8listwrapper.cpp178
-rw-r--r--src/declarative/qml/v8/qv8listwrapper_p.h96
-rw-r--r--src/declarative/qml/v8/qv8qobjectwrapper.cpp1868
-rw-r--r--src/declarative/qml/v8/qv8qobjectwrapper_p.h128
-rw-r--r--src/declarative/qml/v8/qv8stringwrapper.cpp94
-rw-r--r--src/declarative/qml/v8/qv8stringwrapper_p.h76
-rw-r--r--src/declarative/qml/v8/qv8typewrapper.cpp211
-rw-r--r--src/declarative/qml/v8/qv8typewrapper_p.h (renamed from src/declarative/qml/qdeclarativetypenamescriptclass_p.h)47
-rw-r--r--src/declarative/qml/v8/qv8valuetypewrapper.cpp289
-rw-r--r--src/declarative/qml/v8/qv8valuetypewrapper_p.h (renamed from src/declarative/qml/qdeclarativevaluetypescriptclass_p.h)46
-rw-r--r--src/declarative/qml/v8/qv8variantwrapper.cpp189
-rw-r--r--src/declarative/qml/v8/qv8variantwrapper_p.h (renamed from src/declarative/qml/qdeclarativelistscriptclass_p.h)52
-rw-r--r--src/declarative/qml/v8/qv8worker.cpp352
-rw-r--r--src/declarative/qml/v8/qv8worker_p.h75
-rw-r--r--src/declarative/qml/v8/v8.pri32
78 files changed, 8911 insertions, 6097 deletions
diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp
index 6c46de69e4..6cca32782f 100644
--- a/src/declarative/qml/qdeclarativebinding.cpp
+++ b/src/declarative/qml/qdeclarativebinding.cpp
@@ -274,8 +274,17 @@ QDeclarativeBinding::QDeclarativeBinding(const QString &str, QObject *obj, QDecl
setNotifyOnValueChanged(true);
}
-QDeclarativeBinding::QDeclarativeBinding(const QScriptValue &func, QObject *obj, QDeclarativeContextData *ctxt, QObject *parent)
-: QDeclarativeExpression(ctxt, obj, func, *new QDeclarativeBindingPrivate)
+/*!
+ \internal
+
+ To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.
+ For example:
+ v8::Handle<v8::Function> function;
+ new QDeclarativeBInding(&function, scope, ctxt);
+ */
+QDeclarativeBinding::QDeclarativeBinding(void *functionPtr, QObject *obj, QDeclarativeContextData *ctxt,
+ QObject *parent)
+: QDeclarativeExpression(ctxt, obj, functionPtr, *new QDeclarativeBindingPrivate)
{
setParent(parent);
setNotifyOnValueChanged(true);
@@ -362,28 +371,22 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
bool isUndefined = false;
QVariant value;
- QScriptValue scriptValue = d->scriptValue(0, &isUndefined);
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(ep->v8engine.context());
+ v8::Local<v8::Value> result = d->v8value(0, &isUndefined);
if (wasDeleted) {
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
return;
}
- if (d->property.propertyTypeCategory() == QDeclarativeProperty::List) {
- value = ep->scriptValueToVariant(scriptValue, qMetaTypeId<QList<QObject *> >());
- } else if (scriptValue.isNull() &&
- d->property.propertyTypeCategory() == QDeclarativeProperty::Object) {
+ if (isUndefined) {
+ } else if (d->property.propertyTypeCategory() == QDeclarativeProperty::List) {
+ value = ep->v8engine.toVariant(result, qMetaTypeId<QList<QObject *> >());
+ } else if (result->IsNull() && d->property.propertyTypeCategory() == QDeclarativeProperty::Object) {
value = QVariant::fromValue((QObject *)0);
} else {
- value = ep->scriptValueToVariant(scriptValue, d->property.propertyType());
- if (value.userType() == QMetaType::QObjectStar && !qvariant_cast<QObject*>(value)) {
- // If the object is null, we extract the predicted type. While this isn't
- // 100% reliable, in many cases it gives us better error messages if we
- // assign this null-object to an incompatible property
- int type = ep->objectClass->objectType(scriptValue);
- QObject *o = 0;
- value = QVariant(type, (void *)&o);
- }
+ value = ep->v8engine.toVariant(result, d->property.propertyType());
}
@@ -410,7 +413,7 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
QLatin1String(QMetaType::typeName(d->property.propertyType())) +
QLatin1String(" ") + d->property.name());
- } else if (!scriptValue.isRegExp() && scriptValue.isFunction()) {
+ } else if (result->IsFunction()) {
QUrl url = QUrl(d->url);
int line = d->line;
diff --git a/src/declarative/qml/qdeclarativebinding_p.h b/src/declarative/qml/qdeclarativebinding_p.h
index 62aeca2a6c..f0b33359a7 100644
--- a/src/declarative/qml/qdeclarativebinding_p.h
+++ b/src/declarative/qml/qdeclarativebinding_p.h
@@ -154,7 +154,7 @@ public:
QDeclarativeBinding(const QString &, QObject *, QDeclarativeContextData *, QObject *parent=0);
QDeclarativeBinding(void *, QDeclarativeRefCount *, QObject *, QDeclarativeContextData *,
const QString &, int, QObject *parent);
- QDeclarativeBinding(const QScriptValue &, QObject *, QDeclarativeContextData *, QObject *parent=0);
+ QDeclarativeBinding(void *, QObject *, QDeclarativeContextData *, QObject *parent=0);
void setTarget(const QDeclarativeProperty &);
QDeclarativeProperty property() const;
diff --git a/src/declarative/qml/qdeclarativeboundsignal.cpp b/src/declarative/qml/qdeclarativeboundsignal.cpp
index 3e036176a5..5accc003f5 100644
--- a/src/declarative/qml/qdeclarativeboundsignal.cpp
+++ b/src/declarative/qml/qdeclarativeboundsignal.cpp
@@ -227,7 +227,6 @@ QDeclarativeBoundSignalParameters::QDeclarativeBoundSignalParameters(const QMeta
} else {
QByteArray propType = type;
if (t >= QVariant::UserType || t == QVariant::Invalid) {
- //copy of QDeclarativeObjectScriptClass::enumType()
QByteArray scope;
QByteArray name;
int scopeIdx = propType.lastIndexOf("::");
diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp
index 72010c0ef2..712f787549 100644
--- a/src/declarative/qml/qdeclarativecompiler.cpp
+++ b/src/declarative/qml/qdeclarativecompiler.cpp
@@ -64,7 +64,6 @@
#include "private/qdeclarativescriptparser_p.h"
#include "private/qdeclarativebinding_p.h"
#include "private/qdeclarativev4compiler_p.h"
-#include "private/qdeclarativeglobalscriptclass_p.h"
#include <QColor>
#include <QDebug>
@@ -2255,7 +2254,7 @@ bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop
}
} else {
// Otherwise we have to search the whole type
- // This matches the logic in QDeclarativeTypeNameScriptClass
+ // This matches the logic in QV8TypeWrapper
QByteArray enumName = enumValue.toUtf8();
const QMetaObject *metaObject = type->baseMetaObject();
for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
@@ -2360,7 +2359,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->globalClass->illegalNames().contains(propName))
+ if (enginePrivate->v8engine.illegalNames().contains(propName))
COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
propNames.insert(prop.name);
@@ -2373,7 +2372,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->globalClass->illegalNames().contains(nameStr))
+ if (enginePrivate->v8engine.illegalNames().contains(nameStr))
COMPILE_EXCEPTION(obj, tr("Illegal signal name"));
methodNames.insert(name);
}
@@ -2384,7 +2383,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->globalClass->illegalNames().contains(nameStr))
+ if (enginePrivate->v8engine.illegalNames().contains(nameStr))
COMPILE_EXCEPTION(obj, tr("Illegal method name"));
methodNames.insert(name);
}
@@ -2678,7 +2677,7 @@ bool QDeclarativeCompiler::checkValidId(QDeclarativeParser::Value *v, const QStr
}
- if (enginePrivate->globalClass->illegalNames().contains(val))
+ if (enginePrivate->v8engine.illegalNames().contains(val))
COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
return true;
@@ -2879,7 +2878,7 @@ int QDeclarativeCompiler::genContextCache()
if (compileState.ids.count() == 0)
return -1;
- QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache(engine);
+ QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
for (QHash<QString, QDeclarativeParser::Object *>::ConstIterator iter = compileState.ids.begin();
iter != compileState.ids.end();
diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp
index 01e2434f76..e99928d862 100644
--- a/src/declarative/qml/qdeclarativecomponent.cpp
+++ b/src/declarative/qml/qdeclarativecomponent.cpp
@@ -660,49 +660,50 @@ QDeclarativeComponent::QDeclarativeComponent(QDeclarativeComponentPrivate &dd, Q
Sets graphics object parent because forgetting to do this is a frequent
and serious problem.
*/
-QScriptValue QDeclarativeComponent::createObject(QObject* parent)
+void QDeclarativeComponent::createObject(QDeclarativeV8Function *args)
{
- Q_D(QDeclarativeComponent);
- return d->createObject(parent, QScriptValue(QScriptValue::NullValue));
-}
+ Q_ASSERT(args);
+
+#define RETURN(result) { args->returnValue((result)); return; }
-/*!
- \internal
- Overloadable method allows properties to be set during creation
-*/
-QScriptValue QDeclarativeComponent::createObject(QObject* parent, const QScriptValue& valuemap)
-{
Q_D(QDeclarativeComponent);
- if (!valuemap.isObject() || valuemap.isArray()) {
- qmlInfo(this) << tr("createObject: value is not an object");
- return QScriptValue(QScriptValue::NullValue);
+ Q_ASSERT(d->engine);
+
+ QDeclarativeEngine *engine = d->engine;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ QV8Engine *v8engine = &ep->v8engine;
+
+ QDeclarativeContext *ctxt = creationContext();
+ if (!ctxt) ctxt = engine->rootContext();
+
+ v8::Local<v8::Object> valuemap;
+ if (args->Length() >= 2) {
+ v8::Local<v8::Value> v = (*args)[1];
+ if (!v->IsObject() || v->IsArray()) {
+ qmlInfo(this) << tr("createObject: value is not an object");
+ RETURN(v8::Null());
+ }
+ valuemap = v8::Local<v8::Object>::Cast(v);
}
- return d->createObject(parent, valuemap);
-}
-QScriptValue QDeclarativeComponentPrivate::createObject(QObject *publicParent, const QScriptValue valuemap)
-{
- Q_Q(QDeclarativeComponent);
- QDeclarativeContext* ctxt = q->creationContext();
- if(!ctxt && engine)
- ctxt = engine->rootContext();
- if (!ctxt)
- return QScriptValue(QScriptValue::NullValue);
- QObject* ret = q->beginCreate(ctxt);
+ QObject *parent = args->Length()?v8engine->toQObject((*args)[0]):0;
+
+ QObject *ret = beginCreate(ctxt);
if (!ret) {
- q->completeCreate();
- return QScriptValue(QScriptValue::NullValue);
+ completeCreate();
+ RETURN(v8::Null());
}
- if (publicParent) {
- ret->setParent(publicParent);
+ if (parent) {
+ ret->setParent(parent);
+
QList<QDeclarativePrivate::AutoParentFunction> functions = QDeclarativeMetaType::parentFunctions();
bool needParent = false;
for (int ii = 0; ii < functions.count(); ++ii) {
- QDeclarativePrivate::AutoParentResult res = functions.at(ii)(ret, publicParent);
+ QDeclarativePrivate::AutoParentResult res = functions.at(ii)(ret, parent);
if (res == QDeclarativePrivate::Parented) {
needParent = false;
break;
@@ -715,37 +716,41 @@ QScriptValue QDeclarativeComponentPrivate::createObject(QObject *publicParent, c
qWarning("QDeclarativeComponent: Created graphical object was not placed in the graphics scene.");
}
- QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(engine);
- QDeclarativeData::get(ret, true)->setImplicitDestructible();
- QScriptValue newObject = priv->objectClass->newQObject(ret, QMetaType::QObjectStar);
-
- if (valuemap.isObject() && !valuemap.isArray()) {
- //Iterate through and assign properties
- QScriptValueIterator it(valuemap);
- while (it.hasNext()) {
- it.next();
- QScriptValue prop = newObject;
- QString propName = it.name();
- int index = propName.indexOf(QLatin1Char('.'));
- if (index > 0) {
- QString subProp = propName;
- int lastIndex = 0;
- while (index > 0) {
- subProp = propName.mid(lastIndex, index - lastIndex);
- prop = prop.property(subProp);
- lastIndex = index + 1;
- index = propName.indexOf(QLatin1Char('.'), index + 1);
- }
- prop.setProperty(propName.mid(propName.lastIndexOf(QLatin1Char('.')) + 1), it.value());
- } else {
- newObject.setProperty(propName, it.value());
- }
- }
+ v8::Handle<v8::Value> ov = v8engine->newQObject(ret);
+ Q_ASSERT(ov->IsObject());
+ v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);
+
+ if (!valuemap.IsEmpty()) {
+
+#define SET_ARGS_SOURCE \
+ "(function(object, values) {"\
+ "try {"\
+ "for(var property in values) {"\
+ "try {"\
+ "var properties = property.split(\".\");"\
+ "var o = object;"\
+ "for (var ii = 0; ii < properties.length - 1; ++ii) {"\
+ "o = o[properties[ii]];"\
+ "}"\
+ "o[properties[properties.length - 1]] = values[property];"\
+ "} catch(e) {}"\
+ "}"\
+ "} catch(e) {}"\
+ "})"
+
+ v8::Local<v8::Script> script = v8engine->qmlModeCompile(SET_ARGS_SOURCE);
+ v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(script->Run(args->qmlGlobal()));
+
+ // Try catch isn't needed as the function itself is loaded with try/catch
+ v8::Handle<v8::Value> args[] = { object, valuemap };
+ function->Call(v8engine->global(), 2, args);
}
- q->completeCreate();
+ completeCreate();
+
+ RETURN(object);
- return newObject;
+#undef RETURN
}
/*!
@@ -884,8 +889,11 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon
ctxt->imports = component->importCache;
// Nested global imports
- if (componentCreationContext && start != -1)
+ if (componentCreationContext && start != -1) {
ctxt->importedScripts = componentCreationContext->importedScripts;
+ for (int ii = 0; ii < ctxt->importedScripts.count(); ++ii)
+ ctxt->importedScripts[ii] = qPersistentNew<v8::Object>(ctxt->importedScripts[ii]);
+ }
component->importCache->addref();
ctxt->setParent(parentContext);
@@ -974,7 +982,6 @@ void QDeclarativeComponentPrivate::complete(QDeclarativeEnginePrivate *enginePri
state->bindValues.at(ii);
for (int jj = 0; jj < bv.count; ++jj) {
if(bv.at(jj)) {
- // XXX akennedy
bv.at(jj)->m_mePtr = 0;
bv.at(jj)->setEnabled(true, QDeclarativePropertyPrivate::BypassInterceptor |
QDeclarativePropertyPrivate::DontRemoveBinding);
diff --git a/src/declarative/qml/qdeclarativecomponent.h b/src/declarative/qml/qdeclarativecomponent.h
index 15004a6cb1..bb4d886914 100644
--- a/src/declarative/qml/qdeclarativecomponent.h
+++ b/src/declarative/qml/qdeclarativecomponent.h
@@ -60,6 +60,7 @@ class QByteArray;
class QDeclarativeComponentPrivate;
class QDeclarativeEngine;
class QDeclarativeComponentAttached;
+class QDeclarativeV8Function;
class Q_DECLARATIVE_EXPORT QDeclarativeComponent : public QObject
{
Q_OBJECT
@@ -110,8 +111,7 @@ Q_SIGNALS:
protected:
QDeclarativeComponent(QDeclarativeComponentPrivate &dd, QObject* parent);
- Q_INVOKABLE QScriptValue createObject(QObject* parent);
- Q_INVOKABLE Q_REVISION(1) QScriptValue createObject(QObject* parent, const QScriptValue& valuemap); //XXX Versioning
+ Q_INVOKABLE void createObject(QDeclarativeV8Function *);
private:
QDeclarativeComponent(QDeclarativeEngine *, QDeclarativeCompiledData *, int, QObject *parent);
diff --git a/src/declarative/qml/qdeclarativecomponent_p.h b/src/declarative/qml/qdeclarativecomponent_p.h
index ef04a5e137..7677f305e2 100644
--- a/src/declarative/qml/qdeclarativecomponent_p.h
+++ b/src/declarative/qml/qdeclarativecomponent_p.h
@@ -115,8 +115,6 @@ public:
ConstructionState *state);
static void complete(QDeclarativeEnginePrivate *enginePriv, ConstructionState *state);
- QScriptValue createObject(QObject *publicParent, const QScriptValue valuemap);
-
QDeclarativeEngine *engine;
QDeclarativeGuardedContextData creationContext;
diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp
index c48f2ed3d4..2b96d8fbc0 100644
--- a/src/declarative/qml/qdeclarativecontext.cpp
+++ b/src/declarative/qml/qdeclarativecontext.cpp
@@ -47,7 +47,6 @@
#include "private/qdeclarativeengine_p.h"
#include "qdeclarativeengine.h"
#include "qdeclarativeinfo.h"
-#include "private/qdeclarativeglobalscriptclass_p.h"
#include "private/qdeclarativev4bindings_p.h"
#include <qscriptengine.h>
@@ -313,7 +312,7 @@ void QDeclarativeContext::setContextProperty(const QString &name, const QVariant
}
}
- if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache(data->engine);
+ if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache();
int idx = data->propertyNames->value(name);
if (idx == -1) {
@@ -350,7 +349,7 @@ void QDeclarativeContext::setContextProperty(const QString &name, QObject *value
return;
}
- if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache(data->engine);
+ if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache();
int idx = data->propertyNames->value(name);
if (idx == -1) {
@@ -498,18 +497,18 @@ QObject *QDeclarativeContextPrivate::context_at(QDeclarativeListProperty<QObject
QDeclarativeContextData::QDeclarativeContextData()
-: parent(0), engine(0), isInternal(false), ownedByParent(false), publicContext(0), propertyNames(0), contextObject(0),
- imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0),
- contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0), linkedContext(0),
- componentAttached(0)
+: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), publicContext(0),
+ propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
+ expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0),
+ linkedContext(0), componentAttached(0)
{
}
QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt)
-: parent(0), engine(0), isInternal(false), ownedByParent(false), publicContext(ctxt), propertyNames(0), contextObject(0),
- imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0),
- contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0), linkedContext(0),
- componentAttached(0)
+: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), publicContext(ctxt),
+ propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
+ expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0),
+ linkedContext(0), componentAttached(0)
{
}
@@ -611,6 +610,10 @@ void QDeclarativeContextData::destroy()
if (optimizedBindings)
optimizedBindings->release();
+ for (int ii = 0; ii < importedScripts.count(); ++ii) {
+ qPersistentDispose(importedScripts[ii]);
+ }
+
delete [] idValues;
if (isInternal)
diff --git a/src/declarative/qml/qdeclarativecontext.h b/src/declarative/qml/qdeclarativecontext.h
index d1d6d9193c..fd33ccdabe 100644
--- a/src/declarative/qml/qdeclarativecontext.h
+++ b/src/declarative/qml/qdeclarativecontext.h
@@ -94,8 +94,6 @@ private:
friend class QDeclarativeEnginePrivate;
friend class QDeclarativeExpression;
friend class QDeclarativeExpressionPrivate;
- friend class QDeclarativeContextScriptClass;
- friend class QDeclarativeObjectScriptClass;
friend class QDeclarativeComponent;
friend class QDeclarativeComponentPrivate;
friend class QDeclarativeScriptPrivate;
diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h
index d7486b9653..93b9d3b41e 100644
--- a/src/declarative/qml/qdeclarativecontext_p.h
+++ b/src/declarative/qml/qdeclarativecontext_p.h
@@ -69,6 +69,8 @@
#include <private/qobject_p.h>
#include "private/qdeclarativeguard_p.h"
+#include <private/qv8_p.h>
+
QT_BEGIN_NAMESPACE
class QDeclarativeContext;
@@ -137,7 +139,8 @@ public:
QDeclarativeContextPrivate *asQDeclarativeContextPrivate();
quint32 isInternal:1;
quint32 ownedByParent:1; // unrelated to isInternal; parent context deletes children if true.
- quint32 dummy:30;
+ quint32 isJSContext:1;
+ quint32 dummy:29;
QDeclarativeContext *publicContext;
// Property name cache
@@ -147,7 +150,7 @@ public:
QObject *contextObject;
// Any script blocks that exist on this context
- QList<QScriptValue> importedScripts;
+ QList<v8::Persistent<v8::Object> > importedScripts;
// Context base url
QUrl url;
@@ -216,9 +219,10 @@ public:
inline QDeclarativeGuardedContextData(QDeclarativeContextData *);
inline ~QDeclarativeGuardedContextData();
+ inline QDeclarativeContextData *contextData();
inline void setContextData(QDeclarativeContextData *);
- inline QDeclarativeContextData *contextData();
+ inline bool isNull() const { return !m_contextData; }
inline operator QDeclarativeContextData*() const { return m_contextData; }
inline QDeclarativeContextData* operator->() const { return m_contextData; }
diff --git a/src/declarative/qml/qdeclarativecontextscriptclass.cpp b/src/declarative/qml/qdeclarativecontextscriptclass.cpp
deleted file mode 100644
index 7f2e3406e6..0000000000
--- a/src/declarative/qml/qdeclarativecontextscriptclass.cpp
+++ /dev/null
@@ -1,335 +0,0 @@
-/****************************************************************************
-**
-** 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$
-** 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.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qdeclarativecontextscriptclass_p.h"
-
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativecontext_p.h"
-#include "private/qdeclarativetypenamescriptclass_p.h"
-#include "private/qdeclarativelistscriptclass_p.h"
-#include "private/qdeclarativeguard_p.h"
-
-QT_BEGIN_NAMESPACE
-
-struct ContextData : public QScriptDeclarativeClass::Object {
- ContextData() : overrideObject(0), isSharedContext(true) {}
- ContextData(QDeclarativeContextData *c, QObject *o)
- : context(c), scopeObject(o), overrideObject(0), isSharedContext(false), isUrlContext(false) {}
- QDeclarativeGuardedContextData context;
- QDeclarativeGuard<QObject> scopeObject;
- QObject *overrideObject;
- bool isSharedContext:1;
- bool isUrlContext:1;
-
- QDeclarativeContextData *getContext(QDeclarativeEngine *engine) {
- if (isSharedContext) {
- return QDeclarativeEnginePrivate::get(engine)->sharedContext;
- } else {
- return context.contextData();
- }
- }
-
- QObject *getScope(QDeclarativeEngine *engine) {
- if (isSharedContext) {
- return QDeclarativeEnginePrivate::get(engine)->sharedScope;
- } else {
- return scopeObject.data();
- }
- }
-};
-
-struct UrlContextData : public ContextData {
- UrlContextData(QDeclarativeContextData *c, QObject *o, const QString &u)
- : ContextData(c, o), url(u) {
- isUrlContext = true;
- }
- UrlContextData(const QString &u)
- : ContextData(0, 0), url(u) {
- isUrlContext = true;
- }
- QString url;
-};
-
-/*
- The QDeclarativeContextScriptClass handles property access for a QDeclarativeContext
- via QtScript.
- */
-QDeclarativeContextScriptClass::QDeclarativeContextScriptClass(QDeclarativeEngine *bindEngine)
-: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine),
- lastScopeObject(0), lastContext(0), lastData(0), lastPropertyIndex(-1)
-{
-}
-
-QDeclarativeContextScriptClass::~QDeclarativeContextScriptClass()
-{
-}
-
-QScriptValue QDeclarativeContextScriptClass::newContext(QDeclarativeContextData *context, QObject *scopeObject)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- return newObject(scriptEngine, this, new ContextData(context, scopeObject));
-}
-
-QScriptValue QDeclarativeContextScriptClass::newUrlContext(QDeclarativeContextData *context, QObject *scopeObject,
- const QString &url)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- return newObject(scriptEngine, this, new UrlContextData(context, scopeObject, url));
-}
-
-QScriptValue QDeclarativeContextScriptClass::newUrlContext(const QString &url)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- return newObject(scriptEngine, this, new UrlContextData(url));
-}
-
-QScriptValue QDeclarativeContextScriptClass::newSharedContext()
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- return newObject(scriptEngine, this, new ContextData());
-}
-
-QDeclarativeContextData *QDeclarativeContextScriptClass::contextFromValue(const QScriptValue &v)
-{
- if (scriptClass(v) != this)
- return 0;
-
- ContextData *data = (ContextData *)object(v);
- return data->getContext(engine);
-}
-
-QUrl QDeclarativeContextScriptClass::urlFromValue(const QScriptValue &v)
-{
- if (scriptClass(v) != this)
- return QUrl();
-
- ContextData *data = (ContextData *)object(v);
- if (data->isUrlContext) {
- return QUrl(static_cast<UrlContextData *>(data)->url);
- } else {
- return QUrl();
- }
-}
-
-QObject *QDeclarativeContextScriptClass::setOverrideObject(QScriptValue &v, QObject *override)
-{
- if (scriptClass(v) != this)
- return 0;
-
- ContextData *data = (ContextData *)object(v);
- QObject *rv = data->overrideObject;
- data->overrideObject = override;
- return rv;
-}
-
-QScriptClass::QueryFlags
-QDeclarativeContextScriptClass::queryProperty(Object *object, const Identifier &name,
- QScriptClass::QueryFlags flags)
-{
- Q_UNUSED(flags);
-
- lastScopeObject = 0;
- lastContext = 0;
- lastData = 0;
- lastPropertyIndex = -1;
-
- QDeclarativeContextData *bindContext = ((ContextData *)object)->getContext(engine);
- QObject *scopeObject = ((ContextData *)object)->getScope(engine);
- if (!bindContext)
- return 0;
-
- QObject *overrideObject = ((ContextData *)object)->overrideObject;
- if (overrideObject) {
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QScriptClass::QueryFlags rv =
- ep->objectClass->queryProperty(overrideObject, name, flags, bindContext,
- QDeclarativeObjectScriptClass::ImplicitObject |
- QDeclarativeObjectScriptClass::SkipAttachedProperties);
- if (rv) {
- lastScopeObject = overrideObject;
- lastContext = bindContext;
- return rv;
- }
- }
-
- bool includeTypes = true;
- while (bindContext) {
- QScriptClass::QueryFlags rv =
- queryProperty(bindContext, scopeObject, name, flags, includeTypes);
- scopeObject = 0; // Only applies to the first context
- includeTypes = false; // Only applies to the first context
- if (rv) return rv;
- bindContext = bindContext->parent;
- }
-
- return 0;
-}
-
-QScriptClass::QueryFlags
-QDeclarativeContextScriptClass::queryProperty(QDeclarativeContextData *bindContext, QObject *scopeObject,
- const Identifier &name,
- QScriptClass::QueryFlags flags,
- bool includeTypes)
-{
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-
- lastPropertyIndex = bindContext->propertyNames?bindContext->propertyNames->value(name):-1;
- if (lastPropertyIndex != -1) {
- lastContext = bindContext;
- return QScriptClass::HandlesReadAccess;
- }
-
- if (includeTypes && bindContext->imports) {
- QDeclarativeTypeNameCache::Data *data = bindContext->imports->data(name);
-
- if (data) {
- lastData = data;
- lastContext = bindContext;
- lastScopeObject = scopeObject;
- return QScriptClass::HandlesReadAccess;
- }
- }
-
- if (scopeObject) {
- QScriptClass::QueryFlags rv =
- ep->objectClass->queryProperty(scopeObject, name, flags, bindContext,
- QDeclarativeObjectScriptClass::ImplicitObject | QDeclarativeObjectScriptClass::SkipAttachedProperties);
- if (rv) {
- lastScopeObject = scopeObject;
- lastContext = bindContext;
- return rv;
- }
- }
-
- if (bindContext->contextObject) {
- QScriptClass::QueryFlags rv =
- ep->objectClass->queryProperty(bindContext->contextObject, name, flags, bindContext,
- QDeclarativeObjectScriptClass::ImplicitObject | QDeclarativeObjectScriptClass::SkipAttachedProperties);
-
- if (rv) {
- lastScopeObject = bindContext->contextObject;
- lastContext = bindContext;
- return rv;
- }
- }
-
- return 0;
-}
-
-QDeclarativeContextScriptClass::Value
-QDeclarativeContextScriptClass::property(Object *object, const Identifier &name)
-{
- Q_UNUSED(object);
-
- QDeclarativeContextData *bindContext = lastContext;
- Q_ASSERT(bindContext);
-
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- if (lastData) {
-
- if (lastData->type) {
- return Value(scriptEngine, ep->typeNameClass->newObject(lastScopeObject, lastData->type));
- } else if (lastData->typeNamespace) {
- return Value(scriptEngine, ep->typeNameClass->newObject(lastScopeObject, lastData->typeNamespace));
- } else {
- int index = lastData->importedScriptIndex;
- if (index < bindContext->importedScripts.count()) {
- return Value(scriptEngine, bindContext->importedScripts.at(index));
- } else {
- return Value();
- }
- }
-
- } else if (lastScopeObject) {
-
- return ep->objectClass->property(lastScopeObject, name);
-
- } else if (lastPropertyIndex != -1) {
-
- QScriptValue rv;
- if (lastPropertyIndex < bindContext->idValueCount) {
- rv = ep->objectClass->newQObject(bindContext->idValues[lastPropertyIndex].data());
-
- if (ep->captureProperties)
- ep->capturedProperties << QDeclarativeEnginePrivate::CapturedProperty(&bindContext->idValues[lastPropertyIndex].bindings);
- } else {
- QDeclarativeContextPrivate *cp = bindContext->asQDeclarativeContextPrivate();
- const QVariant &value = cp->propertyValues.at(lastPropertyIndex);
- if (value.userType() == qMetaTypeId<QList<QObject*> >()) {
- rv = ep->listClass->newList(QDeclarativeListProperty<QObject>(bindContext->asQDeclarativeContext(), (void*)lastPropertyIndex, 0, QDeclarativeContextPrivate::context_count, QDeclarativeContextPrivate::context_at), qMetaTypeId<QDeclarativeListProperty<QObject> >());
- } else {
- rv = ep->scriptValueFromVariant(value);
- }
-
- if (ep->captureProperties)
- ep->capturedProperties << QDeclarativeEnginePrivate::CapturedProperty(bindContext->asQDeclarativeContext(), -1, lastPropertyIndex + cp->notifyIndex);
- }
-
- return Value(scriptEngine, rv);
-
- } else {
-
- return Value(scriptEngine, lastFunction);
-
- }
-}
-
-void QDeclarativeContextScriptClass::setProperty(Object *object, const Identifier &name,
- const QScriptValue &value)
-{
- Q_UNUSED(object);
- Q_ASSERT(lastScopeObject);
-
- QDeclarativeContextData *bindContext = lastContext;
- Q_ASSERT(bindContext);
-
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-
- ep->objectClass->setProperty(lastScopeObject, name, value, context(), bindContext);
-}
-
-QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativedata_p.h b/src/declarative/qml/qdeclarativedata_p.h
index 2a5eace845..65f49268e9 100644
--- a/src/declarative/qml/qdeclarativedata_p.h
+++ b/src/declarative/qml/qdeclarativedata_p.h
@@ -57,6 +57,8 @@
#include <private/qobject_p.h>
#include "private/qdeclarativeguard_p.h"
+#include <private/qv8_p.h>
+
QT_BEGIN_NAMESPACE
class QDeclarativeCompiledData;
@@ -75,9 +77,10 @@ class Q_AUTOTEST_EXPORT QDeclarativeData : public QAbstractDeclarativeData
public:
QDeclarativeData()
: ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false),
- context(0), outerContext(0), bindings(0), nextContextObject(0), prevContextObject(0), bindingBitsSize(0),
- bindingBits(0), lineNumber(0), columnNumber(0), deferredComponent(0), deferredIdx(0),
- scriptValue(0), objectDataRefCount(0), propertyCache(0), guards(0), extendedData(0) {
+ hasTaintedV8Object(false), context(0), outerContext(0), bindings(0), nextContextObject(0),
+ prevContextObject(0), bindingBitsSize(0), bindingBits(0), lineNumber(0), columnNumber(0),
+ deferredComponent(0), deferredIdx(0), v8objectid(0), propertyCache(0), guards(0),
+ extendedData(0) {
init();
}
@@ -103,7 +106,8 @@ public:
quint32 ownContext:1;
quint32 indestructible:1;
quint32 explicitIndestructibleSet:1;
- quint32 dummy:28;
+ quint32 hasTaintedV8Object:1;
+ quint32 dummy:27;
// The context that created the C++ object
QDeclarativeContextData *context;
@@ -128,10 +132,9 @@ public:
QDeclarativeCompiledData *deferredComponent; // Can't this be found from the context?
unsigned int deferredIdx;
- // ### Can we make this QScriptValuePrivate so we incur no additional allocation
- // cost?
- QScriptValue *scriptValue;
- quint32 objectDataRefCount;
+ quint32 v8objectid;
+ v8::Persistent<v8::Object> v8object;
+
QDeclarativePropertyCache *propertyCache;
QDeclarativeGuard<QObject> *guards;
diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp
index 906af83778..8764ab9452 100644
--- a/src/declarative/qml/qdeclarativeengine.cpp
+++ b/src/declarative/qml/qdeclarativeengine.cpp
@@ -44,7 +44,6 @@
#include "private/qdeclarativecontext_p.h"
#include "private/qdeclarativecompiler_p.h"
-#include "private/qdeclarativeglobalscriptclass_p.h"
#include "qdeclarative.h"
#include "qdeclarativecontext.h"
#include "qdeclarativeexpression.h"
@@ -55,9 +54,6 @@
#include "private/qdeclarativestringconverters_p.h"
#include "private/qdeclarativexmlhttprequest_p.h"
#include "private/qdeclarativesqldatabase_p.h"
-#include "private/qdeclarativescarceresourcescriptclass_p.h"
-#include "private/qdeclarativetypenamescriptclass_p.h"
-#include "private/qdeclarativelistscriptclass_p.h"
#include "qdeclarativescriptstring.h"
#include "private/qdeclarativeglobal_p.h"
#include "private/qdeclarativeworkerscript_p.h"
@@ -68,14 +64,12 @@
#include "qdeclarativeextensioninterface.h"
#include "private/qdeclarativelist_p.h"
#include "private/qdeclarativetypenamecache_p.h"
-#include "private/qdeclarativeinclude_p.h"
#include "private/qdeclarativenotifier_p.h"
#include "private/qdeclarativedebugtrace_p.h"
#include "private/qdeclarativeapplication_p.h"
#include "private/qjsdebugservice_p.h"
#include <QtCore/qmetaobject.h>
-#include <QScriptClass>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QNetworkAccessManager>
@@ -101,7 +95,6 @@
#include <QtCore/qcryptographichash.h>
#include <private/qobject_p.h>
-#include <private/qscriptdeclarativeclass_p.h>
#include <private/qdeclarativeitemsmodule_p.h>
#include <private/qdeclarativeutilmodule_p.h>
@@ -345,16 +338,16 @@ The \c status property will be updated as the operation progresses.
If provided, \a callback is invoked when the operation completes. The callback is passed
the same object as is returned from the Qt.include() call.
*/
-// Qt.include() is implemented in qdeclarativeinclude.cpp
+// Qt.include() is implemented in qv8include.cpp
QDeclarativeEnginePrivate::QDeclarativeEnginePrivate(QDeclarativeEngine *e)
: captureProperties(false), rootContext(0), isDebugging(false),
- outputWarningsToStdErr(true), contextClass(0), sharedContext(0), sharedScope(0),
- objectClass(0), valueTypeClass(0), globalClass(0), cleanup(0), erroredBindings(0),
- inProgressCreations(0), scriptEngine(this), workerScriptEngine(0), componentAttached(0),
- inBeginCreate(false), networkAccessManager(0), networkAccessManagerFactory(0),
- scarceResources(0), scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
+ outputWarningsToStdErr(true), sharedContext(0), sharedScope(0),
+ cleanup(0), erroredBindings(0), inProgressCreations(0),
+ workerScriptEngine(0), componentAttached(0), inBeginCreate(false),
+ networkAccessManager(0), networkAccessManagerFactory(0),
+ scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
sgContext(0)
{
if (!qt_QmlQtModule_registered) {
@@ -366,124 +359,6 @@ QDeclarativeEnginePrivate::QDeclarativeEnginePrivate(QDeclarativeEngine *e)
QSGParticlesModule::defineModule();
QDeclarativeValueTypeFactory::registerValueTypes();
}
- globalClass = new QDeclarativeGlobalScriptClass(&scriptEngine);
-}
-
-/*!
- \qmlmethod url Qt::resolvedUrl(url url)
- Returns \a url resolved relative to the URL of the caller.
-*/
-QUrl QDeclarativeScriptEngine::resolvedUrl(QScriptContext *context, const QUrl& url)
-{
- if (p) {
- QDeclarativeContextData *ctxt = p->getContext(context);
- if (ctxt)
- return ctxt->resolvedUrl(url);
- else
- return p->getUrl(context).resolved(url);
- }
- return baseUrl.resolved(url);
-}
-
-QDeclarativeScriptEngine::QDeclarativeScriptEngine(QDeclarativeEnginePrivate *priv)
-: p(priv), sqlQueryClass(0), namedNodeMapClass(0), nodeListClass(0)
-{
- // Note that all documentation for stuff put on the global object goes in
- // doc/src/declarative/globalobject.qdoc
-
- bool mainthread = priv != 0;
-
- QScriptValue qtObject =
- newQMetaObject(StaticQtMetaObject::get());
- globalObject().setProperty(QLatin1String("Qt"), qtObject);
-
-#ifndef QT_NO_DESKTOPSERVICES
- offlineStoragePath = QDesktopServices::storageLocation(QDesktopServices::DataLocation).replace(QLatin1Char('/'), QDir::separator())
- + QDir::separator() + QLatin1String("QML")
- + QDir::separator() + QLatin1String("OfflineStorage");
-#endif
-
-#ifndef QT_NO_XMLSTREAMREADER
- qt_add_qmlxmlhttprequest(this);
-#endif
- qt_add_qmlsqldatabase(this);
- // XXX A Multimedia "Qt.Sound" class also needs to be made available,
- // XXX but we don't want a dependency in that cirection.
- // XXX When the above a done some better way, that way should also be
- // XXX used to add Qt.Sound class.
-
- //types
- if (mainthread)
- qtObject.setProperty(QLatin1String("include"), newFunction(QDeclarativeInclude::include, 2));
- else
- qtObject.setProperty(QLatin1String("include"), newFunction(QDeclarativeInclude::worker_include, 2));
-
- qtObject.setProperty(QLatin1String("isQtObject"), newFunction(QDeclarativeEnginePrivate::isQtObject, 1));
- qtObject.setProperty(QLatin1String("rgba"), newFunction(QDeclarativeEnginePrivate::rgba, 4));
- qtObject.setProperty(QLatin1String("hsla"), newFunction(QDeclarativeEnginePrivate::hsla, 4));
- qtObject.setProperty(QLatin1String("rect"), newFunction(QDeclarativeEnginePrivate::rect, 4));
- qtObject.setProperty(QLatin1String("point"), newFunction(QDeclarativeEnginePrivate::point, 2));
- qtObject.setProperty(QLatin1String("size"), newFunction(QDeclarativeEnginePrivate::size, 2));
- qtObject.setProperty(QLatin1String("vector3d"), newFunction(QDeclarativeEnginePrivate::vector3d, 3));
-
- if (mainthread) {
- //color helpers
- qtObject.setProperty(QLatin1String("lighter"), newFunction(QDeclarativeEnginePrivate::lighter, 1));
- qtObject.setProperty(QLatin1String("darker"), newFunction(QDeclarativeEnginePrivate::darker, 1));
- qtObject.setProperty(QLatin1String("tint"), newFunction(QDeclarativeEnginePrivate::tint, 2));
- }
-
-#ifndef QT_NO_DATESTRING
- //date/time formatting
- qtObject.setProperty(QLatin1String("formatDate"),newFunction(QDeclarativeEnginePrivate::formatDate, 2));
- qtObject.setProperty(QLatin1String("formatTime"),newFunction(QDeclarativeEnginePrivate::formatTime, 2));
- qtObject.setProperty(QLatin1String("formatDateTime"),newFunction(QDeclarativeEnginePrivate::formatDateTime, 2));
-#endif
-
- //misc methods
- qtObject.setProperty(QLatin1String("openUrlExternally"),newFunction(QDeclarativeEnginePrivate::desktopOpenUrl, 1));
- qtObject.setProperty(QLatin1String("fontFamilies"),newFunction(QDeclarativeEnginePrivate::fontFamilies, 0));
- qtObject.setProperty(QLatin1String("md5"),newFunction(QDeclarativeEnginePrivate::md5, 1));
- qtObject.setProperty(QLatin1String("btoa"),newFunction(QDeclarativeEnginePrivate::btoa, 1));
- qtObject.setProperty(QLatin1String("atob"),newFunction(QDeclarativeEnginePrivate::atob, 1));
- qtObject.setProperty(QLatin1String("quit"), newFunction(QDeclarativeEnginePrivate::quit, 0));
- qtObject.setProperty(QLatin1String("resolvedUrl"),newFunction(QDeclarativeScriptEngine::resolvedUrl, 1));
-
- if (mainthread) {
- qtObject.setProperty(QLatin1String("createQmlObject"),
- newFunction(QDeclarativeEnginePrivate::createQmlObject, 1));
- qtObject.setProperty(QLatin1String("createComponent"),
- newFunction(QDeclarativeEnginePrivate::createComponent, 1));
- }
-
- //firebug/webkit compat
- QScriptValue consoleObject = newObject();
- consoleObject.setProperty(QLatin1String("log"),newFunction(QDeclarativeEnginePrivate::consoleLog, 1));
- consoleObject.setProperty(QLatin1String("debug"),newFunction(QDeclarativeEnginePrivate::consoleLog, 1));
- globalObject().setProperty(QLatin1String("console"), consoleObject);
-
- // translation functions need to be installed
- // before the global script class is constructed (QTBUG-6437)
- installTranslatorFunctions();
-}
-
-QDeclarativeScriptEngine::~QDeclarativeScriptEngine()
-{
- delete sqlQueryClass;
- delete nodeListClass;
- delete namedNodeMapClass;
-}
-
-QScriptValue QDeclarativeScriptEngine::resolvedUrl(QScriptContext *ctxt, QScriptEngine *engine)
-{
- QString arg = ctxt->argument(0).toString();
- QUrl r = QDeclarativeScriptEngine::get(engine)->resolvedUrl(ctxt,QUrl(arg));
- return QScriptValue(r.toString());
-}
-
-QNetworkAccessManager *QDeclarativeScriptEngine::networkAccessManager()
-{
- return p->getNetworkAccessManager();
}
QDeclarativeEnginePrivate::~QDeclarativeEnginePrivate()
@@ -503,20 +378,6 @@ QDeclarativeEnginePrivate::~QDeclarativeEnginePrivate()
delete rootContext;
rootContext = 0;
- delete contextClass;
- contextClass = 0;
- delete objectClass;
- objectClass = 0;
- delete scarceResourceClass;
- scarceResourceClass = 0;
- delete valueTypeClass;
- valueTypeClass = 0;
- delete typeNameClass;
- typeNameClass = 0;
- delete listClass;
- listClass = 0;
- delete globalClass;
- globalClass = 0;
for(QHash<int, QDeclarativeCompiledData*>::ConstIterator iter = m_compositeTypes.constBegin(); iter != m_compositeTypes.constEnd(); ++iter)
(*iter)->release();
@@ -582,16 +443,10 @@ void QDeclarativeEnginePrivate::init()
QDeclarativeData::init();
- contextClass = new QDeclarativeContextScriptClass(q);
- objectClass = new QDeclarativeObjectScriptClass(q);
- scarceResourceClass = new QDeclarativeScarceResourceScriptClass(q);
- valueTypeClass = new QDeclarativeValueTypeScriptClass(q);
- typeNameClass = new QDeclarativeTypeNameScriptClass(q);
- listClass = new QDeclarativeListScriptClass(q);
- rootContext = new QDeclarativeContext(q,true);
+ // Init V8 data
+ v8engine.init(q);
- QScriptValue applicationObject = objectClass->newQObject(new QDeclarativeApplication(q));
- scriptEngine.globalObject().property(QLatin1String("Qt")).setProperty(QLatin1String("application"), applicationObject);
+ rootContext = new QDeclarativeContext(q,true);
if (QCoreApplication::instance()->thread() == q->thread() &&
QDeclarativeEngineDebugServer::isDebuggingEnabled()) {
@@ -939,6 +794,14 @@ void QDeclarativeEngine::setOutputWarningsToStandardError(bool enabled)
}
/*!
+ Attempt to free unused memory.
+*/
+void QDeclarativeEngine::collectGarbage()
+{
+ QV8Engine::gc();
+}
+
+/*!
Returns the QDeclarativeContext for the \a object, or 0 if no
context has been set.
@@ -1187,19 +1050,19 @@ void QDeclarativeData::destroyed(QObject *object)
guard->objectDestroyed(object);
}
- if (scriptValue)
- delete scriptValue;
-
if (extendedData)
delete extendedData;
+ v8object.Clear(); // The WeakReference handler will clean the actual handle
+
if (ownMemory)
delete this;
}
-void QDeclarativeData::parentChanged(QObject *, QObject *parent)
+void QDeclarativeData::parentChanged(QObject *object, QObject *parent)
{
- if (!parent && scriptValue) { delete scriptValue; scriptValue = 0; }
+ Q_UNUSED(object);
+ Q_UNUSED(parent);
}
void QDeclarativeData::objectNameChanged(QObject *)
@@ -1243,44 +1106,6 @@ void QDeclarativeData::setBindingBit(QObject *obj, int bit)
bindingBits[bit / 32] |= (1 << (bit % 32));
}
-/*!
- Creates a QScriptValue allowing you to use \a object in QML script.
- \a engine is the QDeclarativeEngine it is to be created in.
-
- The QScriptValue returned is a QtScript Object, not a QtScript QObject, due
- to the special needs of QML requiring more functionality than a standard
- QtScript QObject.
-*/
-QScriptValue QDeclarativeEnginePrivate::qmlScriptObject(QObject* object,
- QDeclarativeEngine* engine)
-{
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
- return enginePriv->objectClass->newQObject(object);
-}
-
-/*!
- Returns the QDeclarativeContext for the executing QScript \a ctxt.
-*/
-QDeclarativeContextData *QDeclarativeEnginePrivate::getContext(QScriptContext *ctxt)
-{
- QScriptValue scopeNode = QScriptDeclarativeClass::scopeChainValue(ctxt, -3);
- Q_ASSERT(scopeNode.isValid());
- Q_ASSERT(QScriptDeclarativeClass::scriptClass(scopeNode) == contextClass);
- return contextClass->contextFromValue(scopeNode);
-}
-
-/*!
- Returns the QUrl associated with the script \a ctxt for the case that there is
- no QDeclarativeContext.
-*/
-QUrl QDeclarativeEnginePrivate::getUrl(QScriptContext *ctxt)
-{
- QScriptValue scopeNode = QScriptDeclarativeClass::scopeChainValue(ctxt, -3);
- Q_ASSERT(scopeNode.isValid());
- Q_ASSERT(QScriptDeclarativeClass::scriptClass(scopeNode) == contextClass);
- return contextClass->urlFromValue(scopeNode);
-}
-
QString QDeclarativeEnginePrivate::urlToLocalFileOrQrc(const QUrl& url)
{
if (url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive) == 0) {
@@ -1291,651 +1116,6 @@ QString QDeclarativeEnginePrivate::urlToLocalFileOrQrc(const QUrl& url)
return url.toLocalFile();
}
-/*!
-\qmlmethod object Qt::createComponent(url)
-
-Returns a \l Component object created using the QML file at the specified \a url,
-or \c null if an empty string was given.
-
-The returned component's \l Component::status property indicates whether the
-component was successfully created. If the status is \c Component.Error,
-see \l Component::errorString() for an error description.
-
-Call \l {Component::createObject()}{Component.createObject()} on the returned
-component to create an object instance of the component.
-
-For example:
-
-\snippet doc/src/snippets/declarative/createComponent-simple.qml 0
-
-See \l {Dynamic Object Management in QML} for more information on using this function.
-
-To create a QML object from an arbitrary string of QML (instead of a file),
-use \l{QML:Qt::createQmlObject()}{Qt.createQmlObject()}.
-*/
-
-QScriptValue QDeclarativeEnginePrivate::createComponent(QScriptContext *ctxt, QScriptEngine *engine)
-{
- QDeclarativeEnginePrivate *activeEnginePriv =
- static_cast<QDeclarativeScriptEngine*>(engine)->p;
- QDeclarativeEngine* activeEngine = activeEnginePriv->q_func();
-
- if(ctxt->argumentCount() != 1) {
- return ctxt->throwError(QLatin1String("Qt.createComponent(): Invalid arguments"));
- } else {
-
- QString arg = ctxt->argument(0).toString();
- if (arg.isEmpty())
- return engine->nullValue();
- QUrl url = QDeclarativeScriptEngine::get(engine)->resolvedUrl(ctxt, QUrl(arg));
- QDeclarativeContextData* context = activeEnginePriv->getContext(ctxt);
- QDeclarativeComponent *c = new QDeclarativeComponent(activeEngine, url, activeEngine);
- QDeclarativeComponentPrivate::get(c)->creationContext = context;
- QDeclarativeData::get(c, true)->setImplicitDestructible();
- return activeEnginePriv->objectClass->newQObject(c, qMetaTypeId<QDeclarativeComponent*>());
- }
-}
-
-/*!
-\qmlmethod object Qt::createQmlObject(string qml, object parent, string filepath)
-
-Returns a new object created from the given \a string of QML which will have the specified \a parent,
-or \c null if there was an error in creating the object.
-
-If \a filepath is specified, it will be used for error reporting for the created object.
-
-Example (where \c parentItem is the id of an existing QML item):
-
-\snippet doc/src/snippets/declarative/createQmlObject.qml 0
-
-In the case of an error, a QtScript Error object is thrown. This object has an additional property,
-\c qmlErrors, which is an array of the errors encountered.
-Each object in this array has the members \c lineNumber, \c columnNumber, \c fileName and \c message.
-For example, if the above snippet had misspelled color as 'colro' then the array would contain an object like the following:
-{ "lineNumber" : 1, "columnNumber" : 32, "fileName" : "dynamicSnippet1", "message" : "Cannot assign to non-existent property \"colro\""}.
-
-Note that this function returns immediately, and therefore may not work if
-the \a qml string loads new components (that is, external QML files that have not yet been loaded).
-If this is the case, consider using \l{QML:Qt::createComponent()}{Qt.createComponent()} instead.
-
-See \l {Dynamic Object Management in QML} for more information on using this function.
-*/
-
-QScriptValue QDeclarativeEnginePrivate::createQmlObject(QScriptContext *ctxt, QScriptEngine *engine)
-{
- QDeclarativeEnginePrivate *activeEnginePriv =
- static_cast<QDeclarativeScriptEngine*>(engine)->p;
- QDeclarativeEngine* activeEngine = activeEnginePriv->q_func();
-
- if(ctxt->argumentCount() < 2 || ctxt->argumentCount() > 3)
- return ctxt->throwError(QLatin1String("Qt.createQmlObject(): Invalid arguments"));
-
- QDeclarativeContextData* context = activeEnginePriv->getContext(ctxt);
- Q_ASSERT(context);
-
- QString qml = ctxt->argument(0).toString();
- if (qml.isEmpty())
- return engine->nullValue();
-
- QUrl url;
- if(ctxt->argumentCount() > 2)
- url = QUrl(ctxt->argument(2).toString());
- else
- url = QUrl(QLatin1String("inline"));
-
- if (url.isValid() && url.isRelative())
- url = context->resolvedUrl(url);
-
- QObject *parentArg = activeEnginePriv->objectClass->toQObject(ctxt->argument(1));
- if(!parentArg)
- return ctxt->throwError(QLatin1String("Qt.createQmlObject(): Missing parent object"));
-
- QDeclarativeComponent component(activeEngine);
- component.setData(qml.toUtf8(), url);
-
- if(component.isError()) {
- QList<QDeclarativeError> errors = component.errors();
- QString errstr = QLatin1String("Qt.createQmlObject() failed to create object: ");
- QScriptValue arr = ctxt->engine()->newArray(errors.length());
- int i = 0;
- foreach (const QDeclarativeError &error, errors){
- errstr += QLatin1String("\n ") + error.toString();
- QScriptValue qmlErrObject = ctxt->engine()->newObject();
- qmlErrObject.setProperty(QLatin1String("lineNumber"), QScriptValue(error.line()));
- qmlErrObject.setProperty(QLatin1String("columnNumber"), QScriptValue(error.column()));
- qmlErrObject.setProperty(QLatin1String("fileName"), QScriptValue(error.url().toString()));
- qmlErrObject.setProperty(QLatin1String("message"), QScriptValue(error.description()));
- arr.setProperty(i++, qmlErrObject);
- }
- QScriptValue err = ctxt->throwError(errstr);
- err.setProperty(QLatin1String("qmlErrors"),arr);
- return err;
- }
-
- if (!component.isReady())
- return ctxt->throwError(QLatin1String("Qt.createQmlObject(): Component is not ready"));
-
- QObject *obj = component.beginCreate(context->asQDeclarativeContext());
- if(obj)
- QDeclarativeData::get(obj, true)->setImplicitDestructible();
- component.completeCreate();
-
- if(component.isError()) {
- QList<QDeclarativeError> errors = component.errors();
- QString errstr = QLatin1String("Qt.createQmlObject() failed to create object: ");
- QScriptValue arr = ctxt->engine()->newArray(errors.length());
- int i = 0;
- foreach (const QDeclarativeError &error, errors){
- errstr += QLatin1String("\n ") + error.toString();
- QScriptValue qmlErrObject = ctxt->engine()->newObject();
- qmlErrObject.setProperty(QLatin1String("lineNumber"), QScriptValue(error.line()));
- qmlErrObject.setProperty(QLatin1String("columnNumber"), QScriptValue(error.column()));
- qmlErrObject.setProperty(QLatin1String("fileName"), QScriptValue(error.url().toString()));
- qmlErrObject.setProperty(QLatin1String("message"), QScriptValue(error.description()));
- arr.setProperty(i++, qmlErrObject);
- }
- QScriptValue err = ctxt->throwError(errstr);
- err.setProperty(QLatin1String("qmlErrors"),arr);
- return err;
- }
-
- Q_ASSERT(obj);
-
- obj->setParent(parentArg);
-
- QList<QDeclarativePrivate::AutoParentFunction> functions = QDeclarativeMetaType::parentFunctions();
- for (int ii = 0; ii < functions.count(); ++ii) {
- if (QDeclarativePrivate::Parented == functions.at(ii)(obj, parentArg))
- break;
- }
-
- QDeclarativeData::get(obj, true)->setImplicitDestructible();
- return activeEnginePriv->objectClass->newQObject(obj, QMetaType::QObjectStar);
-}
-
-/*!
-\qmlmethod bool Qt::isQtObject(object)
-Returns true if \c object is a valid reference to a Qt or QML object, otherwise false.
-*/
-QScriptValue QDeclarativeEnginePrivate::isQtObject(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if (ctxt->argumentCount() == 0)
- return QScriptValue(engine, false);
-
- return QScriptValue(engine, 0 != ctxt->argument(0).toQObject());
-}
-
-/*!
-\qmlmethod Qt::vector3d(real x, real y, real z)
-Returns a Vector3D with the specified \c x, \c y and \c z.
-*/
-QScriptValue QDeclarativeEnginePrivate::vector3d(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if(ctxt->argumentCount() != 3)
- return ctxt->throwError(QLatin1String("Qt.vector(): Invalid arguments"));
- qsreal x = ctxt->argument(0).toNumber();
- qsreal y = ctxt->argument(1).toNumber();
- qsreal z = ctxt->argument(2).toNumber();
- return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QVector3D(x, y, z)));
-}
-
-/*!
-\qmlmethod string Qt::formatDate(datetime date, variant format)
-
-Returns a string representation of \c date, optionally formatted according
-to \c format.
-
-The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
-property, a QDate, or QDateTime value. The \a format parameter may be any of
-the possible format values as described for
-\l{QML:Qt::formatDateTime()}{Qt.formatDateTime()}.
-
-If \a format is not specified, \a date is formatted using
-\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
-*/
-#ifndef QT_NO_DATESTRING
-QScriptValue QDeclarativeEnginePrivate::formatDate(QScriptContext*ctxt, QScriptEngine*engine)
-{
- int argCount = ctxt->argumentCount();
- if(argCount == 0 || argCount > 2)
- return ctxt->throwError(QLatin1String("Qt.formatDate(): Invalid arguments"));
-
- QDate date = ctxt->argument(0).toDateTime().date();
- Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- if (argCount == 2) {
- QScriptValue formatArg = ctxt->argument(1);
- if (formatArg.isString()) {
- QString format = formatArg.toString();
- return engine->newVariant(QVariant::fromValue(date.toString(format)));
- } else if (formatArg.isNumber()) {
- enumFormat = Qt::DateFormat(formatArg.toUInt32());
- } else {
- return ctxt->throwError(QLatin1String("Qt.formatDate(): Invalid date format"));
- }
- }
- return engine->newVariant(QVariant::fromValue(date.toString(enumFormat)));
-}
-
-/*!
-\qmlmethod string Qt::formatTime(datetime time, variant format)
-
-Returns a string representation of \c time, optionally formatted according to
-\c format.
-
-The \a time parameter may be a JavaScript \c Date object, a QTime, or QDateTime
-value. The \a format parameter may be any of the possible format values as
-described for \l{QML:Qt::formatDateTime()}{Qt.formatDateTime()}.
-
-If \a format is not specified, \a time is formatted using
-\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
-*/
-QScriptValue QDeclarativeEnginePrivate::formatTime(QScriptContext*ctxt, QScriptEngine*engine)
-{
- int argCount = ctxt->argumentCount();
- if(argCount == 0 || argCount > 2)
- return ctxt->throwError(QLatin1String("Qt.formatTime(): Invalid arguments"));
-
- QTime time;
- QScriptValue sv = ctxt->argument(0);
- if (sv.isDate())
- time = sv.toDateTime().time();
- else if (sv.toVariant().type() == QVariant::Time)
- time = sv.toVariant().toTime();
-
- Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- if (argCount == 2) {
- QScriptValue formatArg = ctxt->argument(1);
- if (formatArg.isString()) {
- QString format = formatArg.toString();
- return engine->newVariant(QVariant::fromValue(time.toString(format)));
- } else if (formatArg.isNumber()) {
- enumFormat = Qt::DateFormat(formatArg.toUInt32());
- } else {
- return ctxt->throwError(QLatin1String("Qt.formatTime(): Invalid time format"));
- }
- }
- return engine->newVariant(QVariant::fromValue(time.toString(enumFormat)));
-}
-
-/*!
-\qmlmethod string Qt::formatDateTime(datetime dateTime, variant format)
-
-Returns a string representation of \c datetime, optionally formatted according to
-\c format.
-
-The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
-property, a QDate, QTime, or QDateTime value.
-
-If \a format is not provided, \a dateTime is formatted using
-\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}. Otherwise,
-\a format should be either.
-
-\list
-\o One of the Qt::DateFormat enumeration values, such as
- \c Qt.DefaultLocaleShortDate or \c Qt.ISODate
-\o A string that specifies the format of the returned string, as detailed below.
-\endlist
-
-If \a format specifies a format string, it should use the following expressions
-to specify the date:
-
- \table
- \header \i Expression \i Output
- \row \i d \i the day as number without a leading zero (1 to 31)
- \row \i dd \i the day as number with a leading zero (01 to 31)
- \row \i ddd
- \i the abbreviated localized day name (e.g. 'Mon' to 'Sun').
- Uses QDate::shortDayName().
- \row \i dddd
- \i the long localized day name (e.g. 'Monday' to 'Qt::Sunday').
- Uses QDate::longDayName().
- \row \i M \i the month as number without a leading zero (1-12)
- \row \i MM \i the month as number with a leading zero (01-12)
- \row \i MMM
- \i the abbreviated localized month name (e.g. 'Jan' to 'Dec').
- Uses QDate::shortMonthName().
- \row \i MMMM
- \i the long localized month name (e.g. 'January' to 'December').
- Uses QDate::longMonthName().
- \row \i yy \i the year as two digit number (00-99)
- \row \i yyyy \i the year as four digit number
- \endtable
-
-In addition the following expressions can be used to specify the time:
-
- \table
- \header \i Expression \i Output
- \row \i h
- \i the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
- \row \i hh
- \i the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
- \row \i m \i the minute without a leading zero (0 to 59)
- \row \i mm \i the minute with a leading zero (00 to 59)
- \row \i s \i the second without a leading zero (0 to 59)
- \row \i ss \i the second with a leading zero (00 to 59)
- \row \i z \i the milliseconds without leading zeroes (0 to 999)
- \row \i zzz \i the milliseconds with leading zeroes (000 to 999)
- \row \i AP
- \i use AM/PM display. \e AP will be replaced by either "AM" or "PM".
- \row \i ap
- \i use am/pm display. \e ap will be replaced by either "am" or "pm".
- \endtable
-
- All other input characters will be ignored. Any sequence of characters that
- are enclosed in single quotes will be treated as text and not be used as an
- expression. Two consecutive single quotes ("''") are replaced by a single quote
- in the output.
-
-For example, if the following date/time value was specified:
-
- \code
- // 21 May 2001 14:13:09
- var dateTime = new Date(2001, 5, 21, 14, 13, 09)
- \endcode
-
-This \a dateTime value could be passed to \c Qt.formatDateTime(),
-\l {QML:Qt::formatDate()}{Qt.formatDate()} or \l {QML:Qt::formatTime()}{Qt.formatTime()}
-with the \a format values below to produce the following results:
-
- \table
- \header \i Format \i Result
- \row \i "dd.MM.yyyy" \i 21.05.2001
- \row \i "ddd MMMM d yy" \i Tue May 21 01
- \row \i "hh:mm:ss.zzz" \i 14:13:09.042
- \row \i "h:m:s ap" \i 2:13:9 pm
- \endtable
-*/
-QScriptValue QDeclarativeEnginePrivate::formatDateTime(QScriptContext*ctxt, QScriptEngine*engine)
-{
- int argCount = ctxt->argumentCount();
- if(argCount == 0 || argCount > 2)
- return ctxt->throwError(QLatin1String("Qt.formatDateTime(): Invalid arguments"));
-
- QDateTime date = ctxt->argument(0).toDateTime();
- Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- if (argCount == 2) {
- QScriptValue formatArg = ctxt->argument(1);
- if (formatArg.isString()) {
- QString format = formatArg.toString();
- return engine->newVariant(QVariant::fromValue(date.toString(format)));
- } else if (formatArg.isNumber()) {
- enumFormat = Qt::DateFormat(formatArg.toUInt32());
- } else {
- return ctxt->throwError(QLatin1String("Qt.formatDateTime(): Invalid datetime format"));
- }
- }
- return engine->newVariant(QVariant::fromValue(date.toString(enumFormat)));
-}
-#endif // QT_NO_DATESTRING
-
-/*!
-\qmlmethod color Qt::rgba(real red, real green, real blue, real alpha)
-
-Returns a color with the specified \c red, \c green, \c blue and \c alpha components.
-All components should be in the range 0-1 inclusive.
-*/
-QScriptValue QDeclarativeEnginePrivate::rgba(QScriptContext *ctxt, QScriptEngine *engine)
-{
- int argCount = ctxt->argumentCount();
- if(argCount < 3 || argCount > 4)
- return ctxt->throwError(QLatin1String("Qt.rgba(): Invalid arguments"));
- qsreal r = ctxt->argument(0).toNumber();
- qsreal g = ctxt->argument(1).toNumber();
- qsreal b = ctxt->argument(2).toNumber();
- qsreal a = (argCount == 4) ? ctxt->argument(3).toNumber() : 1;
-
- if (r < 0.0) r=0.0;
- if (r > 1.0) r=1.0;
- if (g < 0.0) g=0.0;
- if (g > 1.0) g=1.0;
- if (b < 0.0) b=0.0;
- if (b > 1.0) b=1.0;
- if (a < 0.0) a=0.0;
- if (a > 1.0) a=1.0;
-
- return engine->toScriptValue(QVariant::fromValue(QColor::fromRgbF(r, g, b, a)));
-}
-
-/*!
-\qmlmethod color Qt::hsla(real hue, real saturation, real lightness, real alpha)
-
-Returns a color with the specified \c hue, \c saturation, \c lightness and \c alpha components.
-All components should be in the range 0-1 inclusive.
-*/
-QScriptValue QDeclarativeEnginePrivate::hsla(QScriptContext *ctxt, QScriptEngine *engine)
-{
- int argCount = ctxt->argumentCount();
- if(argCount < 3 || argCount > 4)
- return ctxt->throwError(QLatin1String("Qt.hsla(): Invalid arguments"));
- qsreal h = ctxt->argument(0).toNumber();
- qsreal s = ctxt->argument(1).toNumber();
- qsreal l = ctxt->argument(2).toNumber();
- qsreal a = (argCount == 4) ? ctxt->argument(3).toNumber() : 1;
-
- if (h < 0.0) h=0.0;
- if (h > 1.0) h=1.0;
- if (s < 0.0) s=0.0;
- if (s > 1.0) s=1.0;
- if (l < 0.0) l=0.0;
- if (l > 1.0) l=1.0;
- if (a < 0.0) a=0.0;
- if (a > 1.0) a=1.0;
-
- return engine->toScriptValue(QVariant::fromValue(QColor::fromHslF(h, s, l, a)));
-}
-
-/*!
-\qmlmethod rect Qt::rect(int x, int y, int width, int height)
-
-Returns a \c rect with the top-left corner at \c x, \c y and the specified \c width and \c height.
-
-The returned object has \c x, \c y, \c width and \c height attributes with the given values.
-*/
-QScriptValue QDeclarativeEnginePrivate::rect(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if(ctxt->argumentCount() != 4)
- return ctxt->throwError(QLatin1String("Qt.rect(): Invalid arguments"));
-
- qsreal x = ctxt->argument(0).toNumber();
- qsreal y = ctxt->argument(1).toNumber();
- qsreal w = ctxt->argument(2).toNumber();
- qsreal h = ctxt->argument(3).toNumber();
-
- return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
-}
-
-/*!
-\qmlmethod point Qt::point(int x, int y)
-Returns a Point with the specified \c x and \c y coordinates.
-*/
-QScriptValue QDeclarativeEnginePrivate::point(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if(ctxt->argumentCount() != 2)
- return ctxt->throwError(QLatin1String("Qt.point(): Invalid arguments"));
- qsreal x = ctxt->argument(0).toNumber();
- qsreal y = ctxt->argument(1).toNumber();
- return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QPointF(x, y)));
-}
-
-/*!
-\qmlmethod Qt::size(int width, int height)
-Returns a Size with the specified \c width and \c height.
-*/
-QScriptValue QDeclarativeEnginePrivate::size(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if(ctxt->argumentCount() != 2)
- return ctxt->throwError(QLatin1String("Qt.size(): Invalid arguments"));
- qsreal w = ctxt->argument(0).toNumber();
- qsreal h = ctxt->argument(1).toNumber();
- return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QSizeF(w, h)));
-}
-
-/*!
-\qmlmethod color Qt::lighter(color baseColor, real factor)
-Returns a color lighter than \c baseColor by the \c factor provided.
-
-If the factor is greater than 1.0, this functions returns a lighter color.
-Setting factor to 1.5 returns a color that is 50% brighter. If the factor is less than 1.0,
-the return color is darker, but we recommend using the Qt.darker() function for this purpose.
-If the factor is 0 or negative, the return value is unspecified.
-
-The function converts the current RGB color to HSV, multiplies the value (V) component
-by factor and converts the color back to RGB.
-
-If \c factor is not supplied, returns a color 50% lighter than \c baseColor (factor 1.5).
-*/
-QScriptValue QDeclarativeEnginePrivate::lighter(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if(ctxt->argumentCount() != 1 && ctxt->argumentCount() != 2)
- return ctxt->throwError(QLatin1String("Qt.lighter(): Invalid arguments"));
- QVariant v = ctxt->argument(0).toVariant();
- QColor color;
- if (v.userType() == QVariant::Color)
- color = v.value<QColor>();
- else if (v.userType() == QVariant::String) {
- bool ok;
- color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
- if (!ok)
- return engine->nullValue();
- } else
- return engine->nullValue();
- qsreal factor = 1.5;
- if (ctxt->argumentCount() == 2)
- factor = ctxt->argument(1).toNumber();
- color = color.lighter(int(qRound(factor*100.)));
- return engine->toScriptValue(QVariant::fromValue(color));
-}
-
-/*!
-\qmlmethod color Qt::darker(color baseColor, real factor)
-Returns a color darker than \c baseColor by the \c factor provided.
-
-If the factor is greater than 1.0, this function returns a darker color.
-Setting factor to 3.0 returns a color that has one-third the brightness.
-If the factor is less than 1.0, the return color is lighter, but we recommend using
-the Qt.lighter() function for this purpose. If the factor is 0 or negative, the return
-value is unspecified.
-
-The function converts the current RGB color to HSV, divides the value (V) component
-by factor and converts the color back to RGB.
-
-If \c factor is not supplied, returns a color 50% darker than \c baseColor (factor 2.0).
-*/
-QScriptValue QDeclarativeEnginePrivate::darker(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if(ctxt->argumentCount() != 1 && ctxt->argumentCount() != 2)
- return ctxt->throwError(QLatin1String("Qt.darker(): Invalid arguments"));
- QVariant v = ctxt->argument(0).toVariant();
- QColor color;
- if (v.userType() == QVariant::Color)
- color = v.value<QColor>();
- else if (v.userType() == QVariant::String) {
- bool ok;
- color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
- if (!ok)
- return engine->nullValue();
- } else
- return engine->nullValue();
- qsreal factor = 2.0;
- if (ctxt->argumentCount() == 2)
- factor = ctxt->argument(1).toNumber();
- color = color.darker(int(qRound(factor*100.)));
- return engine->toScriptValue(QVariant::fromValue(color));
-}
-
-/*!
-\qmlmethod bool Qt::openUrlExternally(url target)
-Attempts to open the specified \c target url in an external application, based on the user's desktop preferences. Returns true if it succeeds, and false otherwise.
-*/
-QScriptValue QDeclarativeEnginePrivate::desktopOpenUrl(QScriptContext *ctxt, QScriptEngine *e)
-{
- if(ctxt->argumentCount() < 1)
- return QScriptValue(e, false);
- bool ret = false;
-#ifndef QT_NO_DESKTOPSERVICES
- ret = QDesktopServices::openUrl(QDeclarativeScriptEngine::get(e)->resolvedUrl(ctxt, QUrl(ctxt->argument(0).toString())));
-#endif
- return QScriptValue(e, ret);
-}
-
-/*!
-\qmlmethod list<string> Qt::fontFamilies()
-Returns a list of the font families available to the application.
-*/
-
-QScriptValue QDeclarativeEnginePrivate::fontFamilies(QScriptContext *ctxt, QScriptEngine *e)
-{
- if(ctxt->argumentCount() != 0)
- return ctxt->throwError(QLatin1String("Qt.fontFamilies(): Invalid arguments"));
-
- QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(e);
- QFontDatabase database;
- return p->scriptValueFromVariant(database.families());
-}
-
-/*!
-\qmlmethod string Qt::md5(data)
-Returns a hex string of the md5 hash of \c data.
-*/
-QScriptValue QDeclarativeEnginePrivate::md5(QScriptContext *ctxt, QScriptEngine *)
-{
- if (ctxt->argumentCount() != 1)
- return ctxt->throwError(QLatin1String("Qt.md5(): Invalid arguments"));
-
- QByteArray data = ctxt->argument(0).toString().toUtf8();
- QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5);
-
- return QScriptValue(QLatin1String(result.toHex()));
-}
-
-/*!
-\qmlmethod string Qt::btoa(data)
-Binary to ASCII - this function returns a base64 encoding of \c data.
-*/
-QScriptValue QDeclarativeEnginePrivate::btoa(QScriptContext *ctxt, QScriptEngine *)
-{
- if (ctxt->argumentCount() != 1)
- return ctxt->throwError(QLatin1String("Qt.btoa(): Invalid arguments"));
-
- QByteArray data = ctxt->argument(0).toString().toUtf8();
-
- return QScriptValue(QLatin1String(data.toBase64()));
-}
-
-/*!
-\qmlmethod string Qt::atob(data)
-ASCII to binary - this function returns a base64 decoding of \c data.
-*/
-
-QScriptValue QDeclarativeEnginePrivate::atob(QScriptContext *ctxt, QScriptEngine *)
-{
- if (ctxt->argumentCount() != 1)
- return ctxt->throwError(QLatin1String("Qt.atob(): Invalid arguments"));
-
- QByteArray data = ctxt->argument(0).toString().toUtf8();
-
- return QScriptValue(QLatin1String(QByteArray::fromBase64(data)));
-}
-
-QScriptValue QDeclarativeEnginePrivate::consoleLog(QScriptContext *ctxt, QScriptEngine *e)
-{
- if(ctxt->argumentCount() < 1)
- return e->newVariant(QVariant(false));
-
- QByteArray msg;
-
- for (int i=0; i<ctxt->argumentCount(); ++i) {
- if (!msg.isEmpty()) msg += ' ';
- msg += ctxt->argument(i).toString().toLocal8Bit();
- // does not support firebug "%[a-z]" formatting, since firebug really
- // does just ignore the format letter, which makes it pointless.
- }
-
- qDebug("%s",msg.constData());
-
- return e->newVariant(QVariant(true));
-}
-
void QDeclarativeEnginePrivate::sendQuit()
{
Q_Q(QDeclarativeEngine);
@@ -2004,145 +1184,6 @@ void QDeclarativeEnginePrivate::warning(QDeclarativeEnginePrivate *engine, const
dumpwarning(error);
}
-/*!
-\qmlmethod Qt::quit()
-This function causes the QDeclarativeEngine::quit() signal to be emitted.
-Within the \l {QML Viewer}, this causes the launcher application to exit;
-to quit a C++ application when this method is called, connect the
-QDeclarativeEngine::quit() signal to the QCoreApplication::quit() slot.
-*/
-
-QScriptValue QDeclarativeEnginePrivate::quit(QScriptContext * /*ctxt*/, QScriptEngine *e)
-{
- QDeclarativeEnginePrivate *qe = get (e);
- qe->sendQuit();
- return QScriptValue();
-}
-
-/*!
- \qmlmethod color Qt::tint(color baseColor, color tintColor)
- This function allows tinting one color with another.
-
- The tint color should usually be mostly transparent, or you will not be
- able to see the underlying color. The below example provides a slight red
- tint by having the tint color be pure red which is only 1/16th opaque.
-
- \qml
- Item {
- Rectangle {
- x: 0; width: 80; height: 80
- color: "lightsteelblue"
- }
- Rectangle {
- x: 100; width: 80; height: 80
- color: Qt.tint("lightsteelblue", "#10FF0000")
- }
- }
- \endqml
- \image declarative-rect_tint.png
-
- Tint is most useful when a subtle change is intended to be conveyed due to some event; you can then use tinting to more effectively tune the visible color.
-*/
-QScriptValue QDeclarativeEnginePrivate::tint(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if(ctxt->argumentCount() != 2)
- return ctxt->throwError(QLatin1String("Qt.tint(): Invalid arguments"));
- //get color
- QVariant v = ctxt->argument(0).toVariant();
- QColor color;
- if (v.userType() == QVariant::Color)
- color = v.value<QColor>();
- else if (v.userType() == QVariant::String) {
- bool ok;
- color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
- if (!ok)
- return engine->nullValue();
- } else
- return engine->nullValue();
-
- //get tint color
- v = ctxt->argument(1).toVariant();
- QColor tintColor;
- if (v.userType() == QVariant::Color)
- tintColor = v.value<QColor>();
- else if (v.userType() == QVariant::String) {
- bool ok;
- tintColor = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
- if (!ok)
- return engine->nullValue();
- } else
- return engine->nullValue();
-
- //tint
- QColor finalColor;
- int a = tintColor.alpha();
- if (a == 0xFF)
- finalColor = tintColor;
- else if (a == 0x00)
- finalColor = color;
- else {
- qreal a = tintColor.alphaF();
- qreal inv_a = 1.0 - a;
-
- finalColor.setRgbF(tintColor.redF() * a + color.redF() * inv_a,
- tintColor.greenF() * a + color.greenF() * inv_a,
- tintColor.blueF() * a + color.blueF() * inv_a,
- a + inv_a * color.alphaF());
- }
-
- return engine->toScriptValue(QVariant::fromValue(finalColor));
-}
-
-QScriptValue QDeclarativeEnginePrivate::scriptValueFromVariant(const QVariant &val)
-{
- if (variantIsScarceResource(val)) {
- return scarceResourceClass->newScarceResource(val);
- } else if (val.userType() == qMetaTypeId<QDeclarativeListReference>()) {
- QDeclarativeListReferencePrivate *p =
- QDeclarativeListReferencePrivate::get((QDeclarativeListReference*)val.constData());
- if (p->object) {
- return listClass->newList(p->property, p->propertyType);
- } else {
- return scriptEngine.nullValue();
- }
- } else if (val.userType() == qMetaTypeId<QList<QObject *> >()) {
- const QList<QObject *> &list = *(QList<QObject *>*)val.constData();
- QScriptValue rv = scriptEngine.newArray(list.count());
- for (int ii = 0; ii < list.count(); ++ii) {
- QObject *object = list.at(ii);
- rv.setProperty(ii, objectClass->newQObject(object));
- }
- return rv;
- } else if (QDeclarativeValueType *vt = valueTypes[val.userType()]) {
- return valueTypeClass->newObject(val, vt);
- }
-
- bool objOk;
- QObject *obj = QDeclarativeMetaType::toQObject(val, &objOk);
- if (objOk) {
- return objectClass->newQObject(obj);
- } else {
- return scriptEngine.toScriptValue(val);
- }
-}
-
-/*
- If the variant is a scarce resource (consumes a large amount of memory, or
- only a limited number of them can be held in memory at any given time without
- exhausting supply for future use) we need to release the scarce resource
- after evaluation of the javascript binding is complete.
- */
-bool QDeclarativeEnginePrivate::variantIsScarceResource(const QVariant& val)
-{
- if (val.type() == QVariant::Pixmap) {
- return true;
- } else if (val.type() == QVariant::Image) {
- return true;
- }
-
- return false;
-}
-
/*
This function should be called prior to evaluation of any js expression,
so that scarce resources are not freed prematurely (eg, if there is a
@@ -2170,45 +1211,13 @@ void QDeclarativeEnginePrivate::dereferenceScarceResources()
// note that the actual SRD is owned by the JS engine,
// so we cannot delete the SRD; but we can free the
// memory used by the variant in the SRD.
- ScarceResourceData *srd = 0;
- while (scarceResources) {
- srd = scarceResources; // srd points to the "old" (current) head of the list
- scarceResources = srd->next; // srd->next is the "new" head of the list
- if (srd->next) srd->next->prev = &scarceResources; // newHead->prev = listptr.
- srd->next = 0;
- srd->prev = 0;
- srd->releaseResource(); // release the old head node.
+ while (ScarceResourceData *sr = scarceResources.first()) {
+ sr->data = QVariant();
+ scarceResources.remove(sr);
}
}
}
-QVariant QDeclarativeEnginePrivate::scriptValueToVariant(const QScriptValue &val, int hint)
-{
- QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(val);
- if (dc == objectClass)
- return QVariant::fromValue(objectClass->toQObject(val));
- else if (dc == scarceResourceClass)
- return scarceResourceClass->toVariant(val);
- else if (dc == valueTypeClass)
- return valueTypeClass->toVariant(val);
- else if (dc == contextClass)
- return QVariant();
-
- // Convert to a QList<QObject*> only if val is an array and we were explicitly hinted
- if (hint == qMetaTypeId<QList<QObject *> >() && val.isArray()) {
- QList<QObject *> list;
- int length = val.property(QLatin1String("length")).toInt32();
- for (int ii = 0; ii < length; ++ii) {
- QScriptValue arrayItem = val.property(ii);
- QObject *d = arrayItem.toQObject();
- list << d;
- }
- return QVariant::fromValue(list);
- }
-
- return val.toVariant();
-}
-
/*!
Adds \a path as a directory where the engine searches for
installed modules in a URL-based directory structure.
@@ -2312,7 +1321,6 @@ void QDeclarativeEngine::setPluginPathList(const QStringList &paths)
d->importDatabase.setPluginPathList(paths);
}
-
/*!
Imports the plugin named \a filePath with the \a uri provided.
Returns true if the plugin was successfully imported; otherwise returns false.
@@ -2372,13 +1380,13 @@ bool QDeclarativeEngine::importPlugin(const QString &filePath, const QString &ur
void QDeclarativeEngine::setOfflineStoragePath(const QString& dir)
{
Q_D(QDeclarativeEngine);
- d->scriptEngine.offlineStoragePath = dir;
+ qt_qmlsqldatabase_setOfflineStoragePath(&d->v8engine, dir);
}
QString QDeclarativeEngine::offlineStoragePath() const
{
Q_D(const QDeclarativeEngine);
- return d->scriptEngine.offlineStoragePath;
+ 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 476ff60ec9..e97c2d96b0 100644
--- a/src/declarative/qml/qdeclarativeengine.h
+++ b/src/declarative/qml/qdeclarativeengine.h
@@ -107,6 +107,8 @@ public:
bool outputWarningsToStandardError() const;
void setOutputWarningsToStandardError(bool);
+ void collectGarbage();
+
static QDeclarativeContext *contextForObject(const QObject *);
static void setContextForObject(QObject *, QDeclarativeContext *);
diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h
index c690ac7bff..ba22ba95c0 100644
--- a/src/declarative/qml/qdeclarativeengine_p.h
+++ b/src/declarative/qml/qdeclarativeengine_p.h
@@ -66,81 +66,41 @@
#include "qdeclarativeimageprovider.h"
#include "private/qdeclarativeproperty_p.h"
#include "private/qdeclarativepropertycache_p.h"
-#include "private/qdeclarativeobjectscriptclass_p.h"
-#include "private/qdeclarativescarceresourcescriptclass_p.h"
-#include "private/qdeclarativecontextscriptclass_p.h"
-#include "private/qdeclarativevaluetypescriptclass_p.h"
#include "private/qdeclarativemetatype_p.h"
#include "private/qdeclarativedirparser_p.h"
+#include "private/qintrusivelist_p.h"
-#include <QtScript/QScriptClass>
-#include <QtScript/QScriptValue>
-#include <QtScript/QScriptString>
#include <QtCore/qstring.h>
#include <QtCore/qlist.h>
#include <QtCore/qpair.h>
#include <QtCore/qstack.h>
#include <QtCore/qmutex.h>
-#include <QtScript/qscriptengine.h>
#include <private/qobject_p.h>
+#include <private/qv8engine_p.h>
+
QT_BEGIN_NAMESPACE
class QDeclarativeContext;
class QDeclarativeEngine;
class QDeclarativeContextPrivate;
class QDeclarativeExpression;
-class QDeclarativeContextScriptClass;
class QDeclarativeImportDatabase;
-class QDeclarativeObjectScriptClass;
-class QDeclarativeScarceResourceScriptClass;
class ScarceResourceData;
-class QDeclarativeTypeNameScriptClass;
-class QDeclarativeValueTypeScriptClass;
class QNetworkReply;
class QNetworkAccessManager;
class QDeclarativeNetworkAccessManagerFactory;
class QDeclarativeAbstractBinding;
-class QScriptDeclarativeClass;
-class QDeclarativeTypeNameScriptClass;
class QDeclarativeTypeNameCache;
class QDeclarativeComponentAttached;
-class QDeclarativeListScriptClass;
class QDeclarativeCleanup;
class QDeclarativeDelayedError;
class QDeclarativeWorkerScriptEngine;
-class QDeclarativeGlobalScriptClass;
class QDir;
class QSGTexture;
class QSGContext;
-class QDeclarativeScriptEngine : public QScriptEngine
-{
-public:
- QDeclarativeScriptEngine(QDeclarativeEnginePrivate *priv);
- virtual ~QDeclarativeScriptEngine();
-
- QUrl resolvedUrl(QScriptContext *context, const QUrl& url); // resolved against p's context, or baseUrl if no p
- static QScriptValue resolvedUrl(QScriptContext *ctxt, QScriptEngine *engine);
-
- static QDeclarativeScriptEngine *get(QScriptEngine* e) { return static_cast<QDeclarativeScriptEngine*>(e); }
-
- QDeclarativeEnginePrivate *p;
-
- // User by SQL API
- QScriptClass *sqlQueryClass;
- QString offlineStoragePath;
-
- // Used by DOM Core 3 API
- QScriptClass *namedNodeMapClass;
- QScriptClass *nodeListClass;
-
- QUrl baseUrl;
-
- virtual QNetworkAccessManager *networkAccessManager();
-};
-
class Q_AUTOTEST_EXPORT QDeclarativeEnginePrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QDeclarativeEngine)
@@ -169,16 +129,8 @@ public:
bool outputWarningsToStdErr;
- QDeclarativeContextScriptClass *contextClass;
QDeclarativeContextData *sharedContext;
QObject *sharedScope;
- QDeclarativeObjectScriptClass *objectClass;
- QDeclarativeScarceResourceScriptClass *scarceResourceClass;
- QDeclarativeValueTypeScriptClass *valueTypeClass;
- QDeclarativeTypeNameScriptClass *typeNameClass;
- QDeclarativeListScriptClass *listClass;
- // Global script class
- QDeclarativeGlobalScriptClass *globalClass;
// Registered cleanup handlers
QDeclarativeCleanup *cleanup;
@@ -187,7 +139,8 @@ public:
QDeclarativeDelayedError *erroredBindings;
int inProgressCreations;
- QDeclarativeScriptEngine scriptEngine;
+ // V8 Engine
+ QV8Engine v8engine;
QDeclarativeWorkerScriptEngine *getWorkerScriptEngine();
QDeclarativeWorkerScriptEngine *workerScriptEngine;
@@ -242,15 +195,20 @@ public:
QImage getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
QPixmap getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
- /*
- A scarce resource (like a large pixmap or texture) will be cached in a
- JavaScript wrapper object when accessed in a binding or other js expression.
- We need some way to automatically release that scarce resource prior to normal
- garbage collection (unless the user explicitly preserves the resource).
- */
- ScarceResourceData* scarceResources;
+ // Scarce resources are "exceptionally high cost" QVariant types where allowing the
+ // normal JavaScript GC to clean them up is likely to lead to out-of-memory or other
+ // out-of-resource situations. When such a resource is passed into JavaScript we
+ // add it to the scarceResources list and it is destroyed when we return from the
+ // JavaScript execution that created it. The user can prevent this behavior by
+ // calling preserve() on the object which removes it from this scarceResource list.
+ class ScarceResourceData {
+ public:
+ ScarceResourceData(const QVariant &data) : data(data) {}
+ QVariant data;
+ QIntrusiveListNode node;
+ };
+ QIntrusiveList<ScarceResourceData, &ScarceResourceData::node> scarceResources;
int scarceResourcesRefCount;
- static bool variantIsScarceResource(const QVariant& val);
void referenceScarceResources();
void dereferenceScarceResources();
@@ -290,9 +248,6 @@ public:
QHash<int, int> m_qmlLists;
QHash<int, QDeclarativeCompiledData *> m_compositeTypes;
- QScriptValue scriptValueFromVariant(const QVariant &);
- QVariant scriptValueToVariant(const QScriptValue &, int hint = QVariant::Invalid);
-
void sendQuit();
void warning(const QDeclarativeError &);
void warning(const QList<QDeclarativeError> &);
@@ -301,44 +256,11 @@ public:
static void warning(QDeclarativeEnginePrivate *, const QDeclarativeError &);
static void warning(QDeclarativeEnginePrivate *, const QList<QDeclarativeError> &);
- static QScriptValue qmlScriptObject(QObject*, QDeclarativeEngine*);
-
- static QScriptValue createComponent(QScriptContext*, QScriptEngine*);
- static QScriptValue createQmlObject(QScriptContext*, QScriptEngine*);
- static QScriptValue isQtObject(QScriptContext*, QScriptEngine*);
- static QScriptValue vector3d(QScriptContext*, QScriptEngine*);
- static QScriptValue rgba(QScriptContext*, QScriptEngine*);
- static QScriptValue hsla(QScriptContext*, QScriptEngine*);
- static QScriptValue point(QScriptContext*, QScriptEngine*);
- static QScriptValue size(QScriptContext*, QScriptEngine*);
- static QScriptValue rect(QScriptContext*, QScriptEngine*);
-
- static QScriptValue lighter(QScriptContext*, QScriptEngine*);
- static QScriptValue darker(QScriptContext*, QScriptEngine*);
- static QScriptValue tint(QScriptContext*, QScriptEngine*);
-
- static QScriptValue desktopOpenUrl(QScriptContext*, QScriptEngine*);
- static QScriptValue fontFamilies(QScriptContext*, QScriptEngine*);
- static QScriptValue md5(QScriptContext*, QScriptEngine*);
- static QScriptValue btoa(QScriptContext*, QScriptEngine*);
- static QScriptValue atob(QScriptContext*, QScriptEngine*);
- static QScriptValue consoleLog(QScriptContext*, QScriptEngine*);
- static QScriptValue quit(QScriptContext*, QScriptEngine*);
-
-#ifndef QT_NO_DATESTRING
- static QScriptValue formatDate(QScriptContext*, QScriptEngine*);
- static QScriptValue formatTime(QScriptContext*, QScriptEngine*);
- static QScriptValue formatDateTime(QScriptContext*, QScriptEngine*);
-#endif
- static QScriptEngine *getScriptEngine(QDeclarativeEngine *e) { return &e->d_func()->scriptEngine; }
- static QDeclarativeEngine *getEngine(QScriptEngine *e) { return static_cast<QDeclarativeScriptEngine*>(e)->p->q_func(); }
+ 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; }
- static QDeclarativeEnginePrivate *get(QScriptEngine *e) { return static_cast<QDeclarativeScriptEngine*>(e)->p; }
static QDeclarativeEngine *get(QDeclarativeEnginePrivate *p) { return p->q_func(); }
- QDeclarativeContextData *getContext(QScriptContext *);
- QUrl getUrl(QScriptContext *);
static QString urlToLocalFileOrQrc(const QUrl& url);
diff --git a/src/declarative/qml/qdeclarativeenginedebug.cpp b/src/declarative/qml/qdeclarativeenginedebug.cpp
index 8f22314530..7844d30e86 100644
--- a/src/declarative/qml/qdeclarativeenginedebug.cpp
+++ b/src/declarative/qml/qdeclarativeenginedebug.cpp
@@ -700,7 +700,7 @@ void QDeclarativeEngineDebugServer::setMethodBody(int objectId, const QString &m
Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this
int lineNumber = vmeMetaObject->vmeMethodLineNumber(prop->coreIndex);
- vmeMetaObject->setVmeMethod(prop->coreIndex, QDeclarativeExpressionPrivate::evalInObjectScope(contextData, object, jsfunction, contextData->url.toString(), lineNumber, 0));
+ vmeMetaObject->setVmeMethod(prop->coreIndex, QDeclarativeExpressionPrivate::evalFunction(contextData, object, jsfunction, contextData->url.toString(), lineNumber));
}
void QDeclarativeEngineDebugServer::propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value)
diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp
index 8079cf3eea..7d2803f33b 100644
--- a/src/declarative/qml/qdeclarativeexpression.cpp
+++ b/src/declarative/qml/qdeclarativeexpression.cpp
@@ -47,12 +47,8 @@
#include "private/qdeclarativerewrite_p.h"
#include "private/qdeclarativescriptstring_p.h"
#include "private/qdeclarativecompiler_p.h"
-#include "private/qdeclarativeglobalscriptclass_p.h"
#include <QtCore/qdebug.h>
-#include <QtScript/qscriptprogram.h>
-
-#include <private/qscriptdeclarativeclass_p.h>
QT_BEGIN_NAMESPACE
@@ -73,13 +69,17 @@ bool QDeclarativeDelayedError::addError(QDeclarativeEnginePrivate *e)
}
QDeclarativeQtScriptExpression::QDeclarativeQtScriptExpression()
-: dataRef(0), expressionFunctionMode(ExplicitContext), scopeObject(0), trackChange(false),
- guardList(0), guardListLength(0), guardObject(0), guardObjectNotifyIndex(-1), deleted(0)
+: dataRef(0), extractExpressionFromFunction(false), expressionFunctionMode(ExplicitContext),
+ scopeObject(0), trackChange(false), guardList(0), guardListLength(0), guardObject(0),
+ guardObjectNotifyIndex(-1), deleted(0)
{
}
QDeclarativeQtScriptExpression::~QDeclarativeQtScriptExpression()
{
+ qPersistentDispose(v8function);
+ qPersistentDispose(v8qmlscope);
+
if (guardList) { delete [] guardList; guardList = 0; }
if (dataRef) dataRef->release();
if (deleted) *deleted = true;
@@ -104,17 +104,16 @@ void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QS
expressionFunctionValid = false;
}
-void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QScriptValue &func,
+void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, v8::Handle<v8::Function> func,
QObject *me)
{
- expression = func.toString();
-
QDeclarativeAbstractExpression::setContext(ctxt);
scopeObject = me;
- expressionFunction = func;
+ v8function = qPersistentNew<v8::Function>(func);
expressionFunctionMode = ExplicitContext;
expressionFunctionValid = true;
+ extractExpressionFromFunction = true;
}
void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *expr,
@@ -124,7 +123,8 @@ void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *ex
url = srcUrl;
line = lineNumber;
- if (dataRef) dataRef->release();
+ Q_ASSERT(!dataRef);
+
dataRef = rc;
if (dataRef) dataRef->addref();
@@ -137,75 +137,36 @@ void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *ex
bool isSharedProgram = progIdx & 0x80000000;
progIdx &= 0x7FFFFFFF;
- QDeclarativeEngine *engine = ctxt->engine;
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- if (isSharedProgram) {
-
- if (!dd->cachedClosures.at(progIdx)) {
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
- scriptContext->pushScope(ep->contextClass->newSharedContext());
- scriptContext->pushScope(ep->globalClass->staticGlobalObject());
- dd->cachedClosures[progIdx] = new QScriptValue(scriptEngine->evaluate(expression, url, line));
- scriptEngine->popContext();
- }
-
- expressionFunction = *dd->cachedClosures.at(progIdx);
- expressionFunctionMode = SharedContext;
- expressionFunctionValid = true;
-
- } else {
+ v8function = evalFunction(ctxt, me, expression, url, line, &v8qmlscope);
- if (!dd->cachedPrograms.at(progIdx)) {
- dd->cachedPrograms[progIdx] = new QScriptProgram(expression, url, line);
- }
-
- expressionFunction = evalInObjectScope(ctxt, me, *dd->cachedPrograms.at(progIdx),
- &expressionContext);
-
- expressionFunctionMode = ExplicitContext;
- expressionFunctionValid = true;
- }
+ expressionFunctionMode = ExplicitContext;
+ expressionFunctionValid = true;
QDeclarativeAbstractExpression::setContext(ctxt);
scopeObject = me;
}
-QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object,
- const QString &program, const QString &fileName,
- int lineNumber, QScriptValue *contextObject)
+// Callee owns the persistent handle
+v8::Persistent<v8::Function>
+QDeclarativeExpressionPrivate::evalFunction(QDeclarativeContextData *ctxt, QObject *scope,
+ const QString &code, const QString &filename, int line,
+ v8::Persistent<v8::Object> *qmlscope)
{
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
- if (contextObject) {
- *contextObject = ep->contextClass->newContext(context, object);
- scriptContext->pushScope(*contextObject);
- } else {
- scriptContext->pushScope(ep->contextClass->newContext(context, object));
- }
- scriptContext->pushScope(ep->globalClass->staticGlobalObject());
- QScriptValue rv = ep->scriptEngine.evaluate(program, fileName, lineNumber);
- ep->scriptEngine.popContext();
- return rv;
-}
+ QDeclarativeEngine *engine = ctxt->engine;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object,
- const QScriptProgram &program,
- QScriptValue *contextObject)
-{
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
- if (contextObject) {
- *contextObject = ep->contextClass->newContext(context, object);
- scriptContext->pushScope(*contextObject);
- } else {
- scriptContext->pushScope(ep->contextClass->newContext(context, object));
- }
- scriptContext->pushScope(ep->globalClass->staticGlobalObject());
- QScriptValue rv = ep->scriptEngine.evaluate(program);
- ep->scriptEngine.popContext();
- return rv;
+ // 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::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::Value> result = script->Run(scopeobject);
+ if (tc.HasCaught()) return v8::Persistent<v8::Function>();
+ if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
+ return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
}
/*!
@@ -370,16 +331,26 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QO
d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
}
-/*! \internal */
-QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, const QScriptValue &func,
+/*!
+ \internal
+
+ To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.
+ For example:
+ v8::Handle<v8::Function> function;
+ new QDeclarativeExpression(ctxt, scope, &function, ...);
+ */
+QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, void *functionPtr,
QDeclarativeExpressionPrivate &dd)
: QObject(dd, 0)
{
+ v8::Handle<v8::Function> function = *(v8::Handle<v8::Function> *)functionPtr;
+
Q_D(QDeclarativeExpression);
- d->init(ctxt, func, scope);
+ d->init(ctxt, function, scope);
if (QDeclarativeExpression_notifyIdx == -1)
QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
+
d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
}
@@ -417,6 +388,13 @@ QDeclarativeContext *QDeclarativeExpression::context() const
QString QDeclarativeExpression::expression() const
{
Q_D(const QDeclarativeExpression);
+ if (d->extractExpressionFromFunction && context()->engine()) {
+ QV8Engine *v8engine = QDeclarativeEnginePrivate::getV8Engine(context()->engine());
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(v8engine->context());
+
+ return v8engine->toString(v8::Handle<v8::Value>(d->v8function));
+ }
return d->expression;
}
@@ -430,34 +408,35 @@ void QDeclarativeExpression::setExpression(const QString &expression)
d->resetNotifyOnChange();
d->expression = expression;
d->expressionFunctionValid = false;
- d->expressionFunction = QScriptValue();
+ qPersistentDispose(d->v8function);
+ qPersistentDispose(d->v8qmlscope);
}
-void QDeclarativeExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine,
- QDeclarativeError &error)
+void QDeclarativeExpressionPrivate::exceptionToError(v8::Handle<v8::Message> message,
+ QDeclarativeError &error)
{
- if (scriptEngine->hasUncaughtException() &&
- scriptEngine->uncaughtException().isError()) {
+ Q_ASSERT(!message.IsEmpty());
- QString fileName;
- int lineNumber = scriptEngine->uncaughtExceptionLineNumber();
+ v8::Handle<v8::Value> name = message->GetScriptResourceName();
+ v8::Handle<v8::String> description = message->Get();
+ int lineNumber = message->GetLineNumber();
- QScriptValue exception = scriptEngine->uncaughtException();
- QLatin1String fileNameProp("fileName");
+ Q_ASSERT(name->IsString());
- if (!exception.property(fileNameProp).toString().isEmpty()){
- fileName = exception.property(fileNameProp).toString();
- } else {
- fileName = QLatin1String("<Unknown File>");
- }
+ v8::Local<v8::String> file = name->ToString();
+ if (file->Length() == 0)
+ error.setUrl(QUrl(QLatin1String("<Unknown File>")));
+ else
+ error.setUrl(QUrl(QV8Engine::toStringStatic(file)));
- error.setUrl(QUrl(fileName));
- error.setLine(lineNumber);
- error.setColumn(-1);
- error.setDescription(exception.toString());
- } else {
- error = QDeclarativeError();
- }
+ error.setLine(lineNumber);
+ error.setColumn(-1);
+
+ QString qDescription = QV8Engine::toStringStatic(description);
+ if (qDescription.startsWith(QLatin1String("Uncaught ")))
+ qDescription = qDescription.mid(9 /* strlen("Uncaught ") */);
+
+ error.setDescription(qDescription);
}
bool QDeclarativeQtScriptExpression::notifyOnValueChange() const
@@ -501,14 +480,14 @@ QDeclarativeQtScriptExpression::EvaluateFlags QDeclarativeQtScriptExpression::ev
return evalFlags;
}
-QScriptValue QDeclarativeQtScriptExpression::scriptValue(QObject *secondaryScope, bool *isUndefined)
+v8::Local<v8::Value> QDeclarativeQtScriptExpression::v8value(QObject *secondaryScope, bool *isUndefined)
{
Q_ASSERT(context() && context()->engine);
Q_ASSERT(!trackChange || (guardObject && guardObjectNotifyIndex != -1));
- if (!expressionFunction.isValid()) {
+ if (v8function.IsEmpty() || v8function->IsUndefined()) {
if (isUndefined) *isUndefined = true;
- return QScriptValue();
+ return v8::Local<v8::Value>();
}
DeleteWatcher watcher(this);
@@ -520,7 +499,7 @@ QScriptValue QDeclarativeQtScriptExpression::scriptValue(QObject *secondaryScope
ep->captureProperties = trackChange;
ep->capturedProperties.copyAndClear(lastCapturedProperties);
- QScriptValue value = eval(secondaryScope, isUndefined);
+ v8::Local<v8::Value> value = eval(secondaryScope, isUndefined);
if (!watcher.wasDeleted() && trackChange) {
if (ep->capturedProperties.count() == 0) {
@@ -540,59 +519,52 @@ QScriptValue QDeclarativeQtScriptExpression::scriptValue(QObject *secondaryScope
return value;
}
-QScriptValue QDeclarativeQtScriptExpression::eval(QObject *secondaryScope, bool *isUndefined)
+v8::Local<v8::Value> QDeclarativeQtScriptExpression::eval(QObject *secondaryScope, bool *isUndefined)
{
Q_ASSERT(context() && context()->engine);
-
DeleteWatcher watcher(this);
QDeclarativeEngine *engine = context()->engine;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+ QObject *restoreSecondaryScope = 0;
+ if (secondaryScope)
+ restoreSecondaryScope = ep->v8engine.contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope);
- QDeclarativeContextData *oldSharedContext = 0;
- QObject *oldSharedScope = 0;
- QObject *oldOverride = 0;
- bool isShared = (expressionFunctionMode == SharedContext);
+ v8::TryCatch try_catch;
- if (isShared) {
- oldSharedContext = ep->sharedContext;
- oldSharedScope = ep->sharedScope;
- ep->sharedContext = context();
- ep->sharedScope = scopeObject;
- } else {
- oldOverride = ep->contextClass->setOverrideObject(expressionContext, secondaryScope);
- }
+ v8::Handle<v8::Object> This;
- QScriptValue thisObject;
- if (evalFlags & RequiresThisObject)
- thisObject = ep->objectClass->newQObject(scopeObject);
- QScriptValue svalue = expressionFunction.call(thisObject); // This could cause this c++ object to be deleted
-
- if (isShared) {
- ep->sharedContext = oldSharedContext;
- ep->sharedScope = oldSharedScope;
- } else if (!watcher.wasDeleted()) {
- ep->contextClass->setOverrideObject(expressionContext, oldOverride);
+ if (evaluateFlags() & RequiresThisObject) {
+ v8::Handle<v8::Value> value = ep->v8engine.newQObject(scopeObject);
+ if (value->IsObject()) This = v8::Handle<v8::Object>::Cast(value);
+ }
+ if (This.IsEmpty()) {
+ This = ep->v8engine.global();
}
- if (isUndefined)
- *isUndefined = svalue.isUndefined() || scriptEngine->hasUncaughtException();
+ v8::Local<v8::Value> result = v8function->Call(This, 0, 0);
- // Handle exception
- if (scriptEngine->hasUncaughtException()) {
- if (!watcher.wasDeleted())
- QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
+ if (secondaryScope)
+ ep->v8engine.contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope);
- scriptEngine->clearExceptions();
- return QScriptValue();
- } else {
- if (!watcher.wasDeleted())
+ if (isUndefined)
+ *isUndefined = try_catch.HasCaught() || result->IsUndefined();
+
+ if (watcher.wasDeleted()) {
+ } else if (try_catch.HasCaught()) {
+ v8::Context::Scope scope(ep->v8engine.context());
+ v8::Local<v8::Message> message = try_catch.Message();
+ if (!message.IsEmpty()) {
+ QDeclarativeExpressionPrivate::exceptionToError(message, error);
+ } else {
error = QDeclarativeError();
-
- return svalue;
+ }
+ } else {
+ error = QDeclarativeError();
}
+
+ return result;
}
void QDeclarativeQtScriptExpression::updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties)
@@ -678,31 +650,23 @@ void QDeclarativeQtScriptExpression::updateGuards(const QPODVector<QDeclarativeE
}
}
-QScriptValue QDeclarativeExpressionPrivate::scriptValue(QObject *secondaryScope, bool *isUndefined)
+// Must be called with a valid handle scope
+v8::Local<v8::Value> QDeclarativeExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined)
{
if (!expressionFunctionValid) {
QDeclarativeEngine *engine = context()->engine;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
- expressionContext = ep->contextClass->newContext(context(), scopeObject);
- scriptContext->pushScope(expressionContext);
- scriptContext->pushScope(ep->globalClass->staticGlobalObject());
QDeclarativeRewrite::RewriteBinding rewriteBinding;
rewriteBinding.setName(name);
bool ok = true;
const QString code = rewriteBinding(expression, &ok);
- if (ok)
- expressionFunction = scriptEngine->evaluate(code, url, line);
-
- scriptEngine->popContext();
+ if (ok) v8function = evalFunction(context(), scopeObject, code, url, line, &v8qmlscope);
expressionFunctionMode = ExplicitContext;
expressionFunctionValid = true;
}
- return QDeclarativeQtScriptExpression::scriptValue(secondaryScope, isUndefined);
+ return QDeclarativeQtScriptExpression::v8value(secondaryScope, isUndefined);
}
QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
@@ -715,10 +679,19 @@ QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isU
}
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
+ QVariant rv;
+
ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
- QVariant retn(ep->scriptValueToVariant(scriptValue(secondaryScope, isUndefined), qMetaTypeId<QList<QObject*> >()));
+
+ {
+ v8::HandleScope handle_scope;
+ v8::Local<v8::Value> result = v8value(secondaryScope, isUndefined);
+ rv = ep->v8engine.toVariant(result, qMetaTypeId<QList<QObject*> >());
+ }
+
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
- return retn;
+
+ return rv;
}
/*!
diff --git a/src/declarative/qml/qdeclarativeexpression.h b/src/declarative/qml/qdeclarativeexpression.h
index b76205c82e..217545e08e 100644
--- a/src/declarative/qml/qdeclarativeexpression.h
+++ b/src/declarative/qml/qdeclarativeexpression.h
@@ -60,7 +60,6 @@ class QDeclarativeEngine;
class QDeclarativeContext;
class QDeclarativeExpressionPrivate;
class QDeclarativeContextData;
-class QScriptValue;
class Q_DECLARATIVE_EXPORT QDeclarativeExpression : public QObject
{
Q_OBJECT
@@ -97,7 +96,7 @@ Q_SIGNALS:
protected:
QDeclarativeExpression(QDeclarativeContextData *, QObject *, const QString &,
QDeclarativeExpressionPrivate &dd);
- QDeclarativeExpression(QDeclarativeContextData *, QObject *, const QScriptValue &,
+ QDeclarativeExpression(QDeclarativeContextData *, QObject *, void *,
QDeclarativeExpressionPrivate &dd);
QDeclarativeExpression(QDeclarativeContextData *, void *, QDeclarativeRefCount *rc,
QObject *me, const QString &, int, QDeclarativeExpressionPrivate &dd);
diff --git a/src/declarative/qml/qdeclarativeexpression_p.h b/src/declarative/qml/qdeclarativeexpression_p.h
index 27d437d5b7..b03c70905c 100644
--- a/src/declarative/qml/qdeclarativeexpression_p.h
+++ b/src/declarative/qml/qdeclarativeexpression_p.h
@@ -58,7 +58,7 @@
#include "private/qdeclarativeengine_p.h"
#include "private/qdeclarativeguard_p.h"
-#include <QtScript/qscriptvalue.h>
+#include <private/qv8engine_p.h>
QT_BEGIN_NAMESPACE
@@ -122,11 +122,12 @@ public:
QDeclarativeRefCount *dataRef;
QString expression;
+ bool extractExpressionFromFunction;
Mode expressionFunctionMode;
- QScriptValue expressionFunction;
+ v8::Persistent<v8::Function> v8function;
+ v8::Persistent<v8::Object> v8qmlscope;
- QScriptValue expressionContext; // Only used in ExplicitContext
QObject *scopeObject; // Only used in SharedContext
bool notifyOnValueChange() const;
@@ -137,7 +138,7 @@ public:
void setEvaluateFlags(EvaluateFlags flags);
EvaluateFlags evaluateFlags() const;
- QScriptValue scriptValue(QObject *secondaryScope, bool *isUndefined);
+ v8::Local<v8::Value> v8value(QObject *secondaryScope, bool *isUndefined);
class DeleteWatcher {
public:
@@ -152,7 +153,7 @@ public:
private:
void clearGuards();
- QScriptValue eval(QObject *secondaryScope, bool *isUndefined);
+ v8::Local<v8::Value> eval(QObject *secondaryScope, bool *isUndefined);
void updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties);
bool trackChange;
@@ -180,11 +181,12 @@ public:
~QDeclarativeExpressionPrivate();
void init(QDeclarativeContextData *, const QString &, QObject *);
- void init(QDeclarativeContextData *, const QScriptValue &, QObject *);
+ void init(QDeclarativeContextData *, v8::Handle<v8::Function>, QObject *);
void init(QDeclarativeContextData *, void *, QDeclarativeRefCount *, QObject *, const QString &, int);
QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0);
- QScriptValue scriptValue(QObject *secondaryScope = 0, bool *isUndefined = 0);
+
+ v8::Local<v8::Value> v8value(QObject *secondaryScope = 0, bool *isUndefined = 0);
static QDeclarativeExpressionPrivate *get(QDeclarativeExpression *expr) {
return static_cast<QDeclarativeExpressionPrivate *>(QObjectPrivate::get(expr));
@@ -196,11 +198,10 @@ public:
void _q_notify();
virtual void emitValueChanged();
- static void exceptionToError(QScriptEngine *, QDeclarativeError &);
- static QScriptValue evalInObjectScope(QDeclarativeContextData *, QObject *, const QString &, const QString &,
- int, QScriptValue *);
- static QScriptValue evalInObjectScope(QDeclarativeContextData *, QObject *, const QScriptProgram &,
- QScriptValue *);
+ static void exceptionToError(v8::Handle<v8::Message>, QDeclarativeError &);
+ static v8::Persistent<v8::Function> evalFunction(QDeclarativeContextData *ctxt, QObject *scope,
+ const QString &code, const QString &filename, int line,
+ v8::Persistent<v8::Object> *qmlscope = 0);
bool expressionFunctionValid:1;
diff --git a/src/declarative/qml/qdeclarativeglobalscriptclass.cpp b/src/declarative/qml/qdeclarativeglobalscriptclass.cpp
deleted file mode 100644
index f465d9c4ac..0000000000
--- a/src/declarative/qml/qdeclarativeglobalscriptclass.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-/****************************************************************************
-**
-** 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$
-** 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.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qdeclarativeglobalscriptclass_p.h"
-
-#include <QtCore/qstringlist.h>
-#include <QtCore/qvector.h>
-#include <QtScript/qscriptstring.h>
-#include <QtScript/qscriptengine.h>
-#include <QtScript/qscriptvalueiterator.h>
-
-#include <private/qscriptdeclarativeclass_p.h>
-
-QT_BEGIN_NAMESPACE
-
-/*
- Used to prevent any writes to the global object.
-*/
-QDeclarativeGlobalScriptClass::QDeclarativeGlobalScriptClass(QScriptEngine *engine)
-: QScriptClass(engine)
-{
- QString eval = QLatin1String("eval");
- QString version = QLatin1String("version");
-
- QScriptValue originalGlobalObject = engine->globalObject();
-
- QScriptValue newGlobalObject = engine->newObject();
-
- {
- QScriptValueIterator iter(originalGlobalObject);
- QVector<QString> names;
- QVector<QScriptValue> values;
- QVector<QScriptValue::PropertyFlags> flags;
- while (iter.hasNext()) {
- iter.next();
-
- QString name = iter.name();
-
- if (name == version)
- continue;
-
- if (name != eval) {
- names.append(name);
- values.append(iter.value());
- flags.append(iter.flags() | QScriptValue::Undeletable);
- }
- newGlobalObject.setProperty(iter.scriptName(), iter.value());
-
- m_illegalNames.insert(name);
- }
- m_staticGlobalObject = QScriptDeclarativeClass::newStaticScopeObject(
- engine, names.size(), names.constData(), values.constData(), flags.constData());
- }
-
- newGlobalObject.setScriptClass(this);
- engine->setGlobalObject(newGlobalObject);
-}
-
-QScriptClass::QueryFlags
-QDeclarativeGlobalScriptClass::queryProperty(const QScriptValue &object,
- const QScriptString &name,
- QueryFlags flags, uint *id)
-{
- Q_UNUSED(object);
- Q_UNUSED(name);
- Q_UNUSED(flags);
- Q_UNUSED(id);
- return HandlesWriteAccess;
-}
-
-void QDeclarativeGlobalScriptClass::setProperty(QScriptValue &object,
- const QScriptString &name,
- uint id, const QScriptValue &value)
-{
- Q_UNUSED(object);
- Q_UNUSED(id);
- Q_UNUSED(value);
- QString error = QLatin1String("Invalid write to global property \"") +
- name.toString() + QLatin1Char('\"');
- engine()->currentContext()->throwError(error);
-}
-
-/* This method is for the use of tst_qdeclarativeecmascript::callQtInvokables() only */
-void QDeclarativeGlobalScriptClass::explicitSetProperty(const QStringList &names, const QList<QScriptValue> &values)
-{
- Q_ASSERT(names.count() == values.count());
- QScriptValue globalObject = engine()->globalObject();
-
- QScriptValue v = engine()->newObject();
-
- QScriptValueIterator iter(v);
- while (iter.hasNext()) {
- iter.next();
- v.setProperty(iter.scriptName(), iter.value());
- }
-
- for (int ii = 0; ii < names.count(); ++ii) {
- const QString &name = names.at(ii);
- const QScriptValue &value = values.at(ii);
- v.setProperty(name, value);
- }
-
- v.setScriptClass(this);
-
- engine()->setGlobalObject(v);
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/declarative/qml/qdeclarativeglobalscriptclass_p.h b/src/declarative/qml/qdeclarativeglobalscriptclass_p.h
deleted file mode 100644
index 9aee1d7e3a..0000000000
--- a/src/declarative/qml/qdeclarativeglobalscriptclass_p.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/****************************************************************************
-**
-** 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$
-** 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.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QDECLARATIVEGLOBALSCRIPTCLASS_P_H
-#define QDECLARATIVEGLOBALSCRIPTCLASS_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 <QtScript/qscriptclass.h>
-#include <QtCore/qset.h>
-
-QT_BEGIN_NAMESPACE
-
-class Q_AUTOTEST_EXPORT QDeclarativeGlobalScriptClass : public QScriptClass
-{
-public:
- QDeclarativeGlobalScriptClass(QScriptEngine *);
-
- virtual QueryFlags queryProperty(const QScriptValue &object,
- const QScriptString &name,
- QueryFlags flags, uint *id);
-
- virtual void setProperty(QScriptValue &object, const QScriptString &name,
- uint id, const QScriptValue &value);
-
- void explicitSetProperty(const QStringList &, const QList<QScriptValue> &);
-
- const QScriptValue &staticGlobalObject() const { return m_staticGlobalObject; }
-
- const QSet<QString> &illegalNames() const { return m_illegalNames; }
-
-private:
- QSet<QString> m_illegalNames;
- QScriptValue m_staticGlobalObject;
-};
-
-QT_END_NAMESPACE
-
-#endif // QDECLARATIVEGLOBALSCRIPTCLASS_P_H
diff --git a/src/declarative/qml/qdeclarativeinclude.cpp b/src/declarative/qml/qdeclarativeinclude.cpp
deleted file mode 100644
index bf2cd617e2..0000000000
--- a/src/declarative/qml/qdeclarativeinclude.cpp
+++ /dev/null
@@ -1,310 +0,0 @@
-/****************************************************************************
-**
-** 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$
-** 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.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qdeclarativeinclude_p.h"
-
-#include <QtScript/qscriptengine.h>
-#include <QtNetwork/qnetworkrequest.h>
-#include <QtNetwork/qnetworkreply.h>
-#include <QtCore/qfile.h>
-
-#include <private/qdeclarativeengine_p.h>
-#include <private/qdeclarativeglobalscriptclass_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QDeclarativeInclude::QDeclarativeInclude(const QUrl &url,
- QDeclarativeEngine *engine,
- QScriptContext *ctxt)
-: QObject(engine), m_engine(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0)
-{
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- m_context = ep->contextClass->contextFromValue(QScriptDeclarativeClass::scopeChainValue(ctxt, -3));
-
- m_scope[0] = QScriptDeclarativeClass::scopeChainValue(ctxt, -4);
- m_scope[1] = QScriptDeclarativeClass::scopeChainValue(ctxt, -5);
-
- m_scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- m_network = QDeclarativeScriptEngine::get(m_scriptEngine)->networkAccessManager();
-
- m_result = resultValue(m_scriptEngine);
-
- QNetworkRequest request;
- request.setUrl(url);
-
- m_reply = m_network->get(request);
- QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
-}
-
-QDeclarativeInclude::~QDeclarativeInclude()
-{
- delete m_reply;
-}
-
-QScriptValue QDeclarativeInclude::resultValue(QScriptEngine *engine, Status status)
-{
- QScriptValue result = engine->newObject();
- result.setProperty(QLatin1String("OK"), QScriptValue(engine, Ok));
- result.setProperty(QLatin1String("LOADING"), QScriptValue(engine, Loading));
- result.setProperty(QLatin1String("NETWORK_ERROR"), QScriptValue(engine, NetworkError));
- result.setProperty(QLatin1String("EXCEPTION"), QScriptValue(engine, Exception));
-
- result.setProperty(QLatin1String("status"), QScriptValue(engine, status));
- return result;
-}
-
-QScriptValue QDeclarativeInclude::result() const
-{
- return m_result;
-}
-
-void QDeclarativeInclude::setCallback(const QScriptValue &c)
-{
- m_callback = c;
-}
-
-QScriptValue QDeclarativeInclude::callback() const
-{
- return m_callback;
-}
-
-#define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15
-void QDeclarativeInclude::finished()
-{
- m_redirectCount++;
-
- if (m_redirectCount < INCLUDE_MAXIMUM_REDIRECT_RECURSION) {
- QVariant redirect = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
- if (redirect.isValid()) {
- m_url = m_url.resolved(redirect.toUrl());
- delete m_reply;
-
- QNetworkRequest request;
- request.setUrl(m_url);
-
- m_reply = m_network->get(request);
- QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
- return;
- }
- }
-
- if (m_reply->error() == QNetworkReply::NoError) {
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_engine);
-
- QByteArray data = m_reply->readAll();
-
- QString code = QString::fromUtf8(data);
-
- QString urlString = m_url.toString();
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(m_scriptEngine);
- scriptContext->pushScope(ep->contextClass->newUrlContext(m_context, 0, urlString));
- scriptContext->pushScope(m_scope[0]);
-
- scriptContext->pushScope(m_scope[1]);
- scriptContext->setActivationObject(m_scope[1]);
- QDeclarativeScriptParser::extractPragmas(code);
-
- m_scriptEngine->evaluate(code, urlString, 1);
-
- m_scriptEngine->popContext();
-
- if (m_scriptEngine->hasUncaughtException()) {
- m_result.setProperty(QLatin1String("status"), QScriptValue(m_scriptEngine, Exception));
- m_result.setProperty(QLatin1String("exception"), m_scriptEngine->uncaughtException());
- m_scriptEngine->clearExceptions();
- } else {
- m_result.setProperty(QLatin1String("status"), QScriptValue(m_scriptEngine, Ok));
- }
- } else {
- m_result.setProperty(QLatin1String("status"), QScriptValue(m_scriptEngine, NetworkError));
- }
-
- callback(m_scriptEngine, m_callback, m_result);
-
- disconnect();
- deleteLater();
-}
-
-void QDeclarativeInclude::callback(QScriptEngine *engine, QScriptValue &callback, QScriptValue &status)
-{
- if (callback.isValid()) {
- QScriptValue args = engine->newArray(1);
- args.setProperty(0, status);
- callback.call(QScriptValue(), args);
- }
-}
-
-/*
- Documented in qdeclarativeengine.cpp
-*/
-QScriptValue QDeclarativeInclude::include(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if (ctxt->argumentCount() == 0)
- return engine->undefinedValue();
-
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-
- QUrl contextUrl = ep->contextClass->urlFromValue(QScriptDeclarativeClass::scopeChainValue(ctxt, -3));
- if (contextUrl.isEmpty())
- return ctxt->throwError(QLatin1String("Qt.include(): Can only be called from JavaScript files"));
-
- QString urlString = ctxt->argument(0).toString();
- QUrl url(urlString);
- if (url.isRelative()) {
- url = QUrl(contextUrl).resolved(url);
- urlString = url.toString();
- }
-
- QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
-
- QScriptValue func = ctxt->argument(1);
- if (!func.isFunction())
- func = QScriptValue();
-
- QScriptValue result;
- if (localFile.isEmpty()) {
- QDeclarativeInclude *i =
- new QDeclarativeInclude(url, QDeclarativeEnginePrivate::getEngine(engine), ctxt);
-
- if (func.isValid())
- i->setCallback(func);
-
- result = i->result();
- } else {
-
- QFile f(localFile);
- if (f.open(QIODevice::ReadOnly)) {
- QByteArray data = f.readAll();
- QString code = QString::fromUtf8(data);
-
- QDeclarativeContextData *context =
- ep->contextClass->contextFromValue(QScriptDeclarativeClass::scopeChainValue(ctxt, -3));
-
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(engine);
- scriptContext->pushScope(ep->contextClass->newUrlContext(context, 0, urlString));
- scriptContext->pushScope(ep->globalClass->staticGlobalObject());
- QScriptValue scope = QScriptDeclarativeClass::scopeChainValue(ctxt, -5);
- scriptContext->pushScope(scope);
- scriptContext->setActivationObject(scope);
- QDeclarativeScriptParser::extractPragmas(code);
-
- engine->evaluate(code, urlString, 1);
-
- engine->popContext();
-
- if (engine->hasUncaughtException()) {
- result = resultValue(engine, Exception);
- result.setProperty(QLatin1String("exception"), engine->uncaughtException());
- engine->clearExceptions();
- } else {
- result = resultValue(engine, Ok);
- }
- callback(engine, func, result);
- } else {
- result = resultValue(engine, NetworkError);
- callback(engine, func, result);
- }
- }
-
- return result;
-}
-
-QScriptValue QDeclarativeInclude::worker_include(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if (ctxt->argumentCount() == 0)
- return engine->undefinedValue();
-
- QString urlString = ctxt->argument(0).toString();
- QUrl url(ctxt->argument(0).toString());
- if (url.isRelative()) {
- QString contextUrl = QScriptDeclarativeClass::scopeChainValue(ctxt, -3).data().toString();
- Q_ASSERT(!contextUrl.isEmpty());
-
- url = QUrl(contextUrl).resolved(url);
- urlString = url.toString();
- }
-
- QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
-
- QScriptValue func = ctxt->argument(1);
- if (!func.isFunction())
- func = QScriptValue();
-
- QScriptValue result;
- if (!localFile.isEmpty()) {
-
- QFile f(localFile);
- if (f.open(QIODevice::ReadOnly)) {
- QByteArray data = f.readAll();
- QString code = QString::fromUtf8(data);
-
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(engine);
- QScriptValue urlContext = engine->newObject();
- urlContext.setData(QScriptValue(engine, urlString));
- scriptContext->pushScope(urlContext);
-
- QScriptValue scope = QScriptDeclarativeClass::scopeChainValue(ctxt, -4);
- scriptContext->pushScope(scope);
- scriptContext->setActivationObject(scope);
- QDeclarativeScriptParser::extractPragmas(code);
-
- engine->evaluate(code, urlString, 1);
-
- engine->popContext();
-
- if (engine->hasUncaughtException()) {
- result = resultValue(engine, Exception);
- result.setProperty(QLatin1String("exception"), engine->uncaughtException());
- engine->clearExceptions();
- } else {
- result = resultValue(engine, Ok);
- }
- callback(engine, func, result);
- } else {
- result = resultValue(engine, NetworkError);
- callback(engine, func, result);
- }
- }
-
- return result;
-}
-
-QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeintegercache.cpp b/src/declarative/qml/qdeclarativeintegercache.cpp
index 09beb13340..ef99c63086 100644
--- a/src/declarative/qml/qdeclarativeintegercache.cpp
+++ b/src/declarative/qml/qdeclarativeintegercache.cpp
@@ -41,34 +41,21 @@
#include "private/qdeclarativeintegercache_p.h"
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativemetatype_p.h"
-
QT_BEGIN_NAMESPACE
-QDeclarativeIntegerCache::QDeclarativeIntegerCache(QDeclarativeEngine *e)
-: QDeclarativeCleanup(e), engine(e)
+QDeclarativeIntegerCache::QDeclarativeIntegerCache()
{
}
QDeclarativeIntegerCache::~QDeclarativeIntegerCache()
{
- clear();
-}
-
-void QDeclarativeIntegerCache::clear()
-{
- qDeleteAll(stringCache);
- stringCache.clear();
- identifierCache.clear();
- engine = 0;
}
QString QDeclarativeIntegerCache::findId(int value) const
{
for (StringCache::ConstIterator iter = stringCache.begin();
iter != stringCache.end(); ++iter) {
- if (iter.value() && iter.value()->value == value)
+ if (iter.value() == value)
return iter.key();
}
return QString();
@@ -78,19 +65,13 @@ void QDeclarativeIntegerCache::add(const QString &id, int value)
{
Q_ASSERT(!stringCache.contains(id));
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
-
- // ### use contextClass
- Data *d = new Data(enginePriv->objectClass->createPersistentIdentifier(id), value);
-
- stringCache.insert(id, d);
- identifierCache.insert(d->identifier, d);
+ stringCache.insert(id, value);
}
int QDeclarativeIntegerCache::value(const QString &id)
{
- Data *d = stringCache.value(id);
- return d?d->value:-1;
+ int *rv = stringCache.value(id);
+ return rv?*rv:-1;
}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeintegercache_p.h b/src/declarative/qml/qdeclarativeintegercache_p.h
index 79506cc764..b6151ce1cc 100644
--- a/src/declarative/qml/qdeclarativeintegercache_p.h
+++ b/src/declarative/qml/qdeclarativeintegercache_p.h
@@ -54,51 +54,35 @@
//
#include "private/qdeclarativerefcount_p.h"
-#include "private/qdeclarativecleanup_p.h"
-
-#include <QtCore/qhash.h>
-
-#include <private/qscriptdeclarativeclass_p.h>
+#include "private/qhashedstring_p.h"
QT_BEGIN_NAMESPACE
class QDeclarativeType;
class QDeclarativeEngine;
-class QDeclarativeIntegerCache : public QDeclarativeRefCount, public QDeclarativeCleanup
+class QDeclarativeIntegerCache : public QDeclarativeRefCount
{
public:
- QDeclarativeIntegerCache(QDeclarativeEngine *);
+ QDeclarativeIntegerCache();
virtual ~QDeclarativeIntegerCache();
inline int count() const;
void add(const QString &, int);
+
int value(const QString &);
- QString findId(int value) const;
- inline int value(const QScriptDeclarativeClass::Identifier &id) const;
+ inline int value(v8::Handle<v8::String>);
-protected:
- virtual void clear();
+ QString findId(int value) const;
private:
- struct Data : public QScriptDeclarativeClass::PersistentIdentifier {
- Data(const QScriptDeclarativeClass::PersistentIdentifier &i, int v)
- : QScriptDeclarativeClass::PersistentIdentifier(i), value(v) {}
-
- int value;
- };
-
- typedef QHash<QString, Data *> StringCache;
- typedef QHash<QScriptDeclarativeClass::Identifier, Data *> IdentifierCache;
-
+ typedef QStringHash<int> StringCache;
StringCache stringCache;
- IdentifierCache identifierCache;
- QDeclarativeEngine *engine;
};
-int QDeclarativeIntegerCache::value(const QScriptDeclarativeClass::Identifier &id) const
+int QDeclarativeIntegerCache::value(v8::Handle<v8::String> name)
{
- Data *d = identifierCache.value(id);
- return d?d->value:-1;
+ int *result = stringCache.value(name);
+ return result?*result:-1;
}
int QDeclarativeIntegerCache::count() const
diff --git a/src/declarative/qml/qdeclarativelistscriptclass.cpp b/src/declarative/qml/qdeclarativelistscriptclass.cpp
deleted file mode 100644
index 782cb4013e..0000000000
--- a/src/declarative/qml/qdeclarativelistscriptclass.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/****************************************************************************
-**
-** 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$
-** 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.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qdeclarativelistscriptclass_p.h"
-
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativeguard_p.h"
-#include "private/qdeclarativelist_p.h"
-
-QT_BEGIN_NAMESPACE
-
-struct ListData : public QScriptDeclarativeClass::Object {
- QDeclarativeGuard<QObject> object;
- QDeclarativeListProperty<QObject> property;
- int propertyType;
-};
-
-QDeclarativeListScriptClass::QDeclarativeListScriptClass(QDeclarativeEngine *e)
-: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(e)), engine(e)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- Q_UNUSED(scriptEngine);
-
- m_lengthId = createPersistentIdentifier(QLatin1String("length"));
-}
-
-QDeclarativeListScriptClass::~QDeclarativeListScriptClass()
-{
-}
-
-QScriptValue QDeclarativeListScriptClass::newList(QObject *object, int propId, int propType)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- if (!object || propId == -1)
- return scriptEngine->nullValue();
-
- ListData *data = new ListData;
- data->object = object;
- data->propertyType = propType;
- void *args[] = { &data->property, 0 };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, propId, args);
-
- return newObject(scriptEngine, this, data);
-}
-
-QScriptValue QDeclarativeListScriptClass::newList(const QDeclarativeListProperty<QObject> &prop, int propType)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- ListData *data = new ListData;
- data->object = prop.object;
- data->property = prop;
- data->propertyType = propType;
-
- return newObject(scriptEngine, this, data);
-}
-
-QScriptClass::QueryFlags
-QDeclarativeListScriptClass::queryProperty(Object *object, const Identifier &name,
- QScriptClass::QueryFlags flags)
-{
- Q_UNUSED(object);
- Q_UNUSED(flags);
- if (name == m_lengthId.identifier)
- return QScriptClass::HandlesReadAccess;
-
- bool ok = false;
- quint32 idx = toArrayIndex(name, &ok);
-
- if (ok) {
- lastIndex = idx;
- return QScriptClass::HandlesReadAccess;
- } else {
- return 0;
- }
-}
-
-QDeclarativeListScriptClass::Value QDeclarativeListScriptClass::property(Object *obj, const Identifier &name)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
-
- ListData *data = (ListData *)obj;
- if (!data->object)
- return Value();
-
- quint32 count = data->property.count?data->property.count(&data->property):0;
-
- if (name == m_lengthId.identifier)
- return Value(scriptEngine, count);
- else if (lastIndex < count && data->property.at)
- return Value(scriptEngine, enginePriv->objectClass->newQObject(data->property.at(&data->property, lastIndex)));
- else
- return Value();
-}
-
-QVariant QDeclarativeListScriptClass::toVariant(Object *obj, bool *ok)
-{
- ListData *data = (ListData *)obj;
-
- if (!data->object) {
- if (ok) *ok = false;
- return QVariant();
- }
-
- return QVariant::fromValue(QDeclarativeListReferencePrivate::init(data->property, data->propertyType, engine));
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/declarative/qml/qdeclarativemetatype.cpp b/src/declarative/qml/qdeclarativemetatype.cpp
index 73ed23ba9d..aab5f63f08 100644
--- a/src/declarative/qml/qdeclarativemetatype.cpp
+++ b/src/declarative/qml/qdeclarativemetatype.cpp
@@ -1099,8 +1099,10 @@ QT_END_NAMESPACE
#include <QtGui/qvector3d.h>
#include <QtGui/qvector4d.h>
#include <QtGui/qquaternion.h>
+#include <private/qv8engine_p.h>
Q_DECLARE_METATYPE(QScriptValue);
+Q_DECLARE_METATYPE(QDeclarativeV8Handle);
QT_BEGIN_NAMESPACE
@@ -1181,6 +1183,7 @@ bool QDeclarativeMetaType::canCopy(int type)
default:
if (type == qMetaTypeId<QVariant>() ||
type == qMetaTypeId<QScriptValue>() ||
+ type == qMetaTypeId<QDeclarativeV8Handle>() ||
typeCategory(type) != Unknown) {
return true;
}
@@ -1403,6 +1406,9 @@ bool QDeclarativeMetaType::copy(int type, void *data, const void *copy)
} else if (type == qMetaTypeId<QScriptValue>()) {
*static_cast<NS(QScriptValue) *>(data) = *static_cast<const NS(QScriptValue)*>(copy);
return true;
+ } else if (type == qMetaTypeId<QDeclarativeV8Handle>()) {
+ *static_cast<NS(QDeclarativeV8Handle) *>(data) = *static_cast<const NS(QDeclarativeV8Handle)*>(copy);
+ return true;
} else if (typeCategory(type) != Unknown) {
*static_cast<void **>(data) = *static_cast<void* const *>(copy);
return true;
@@ -1610,6 +1616,9 @@ bool QDeclarativeMetaType::copy(int type, void *data, const void *copy)
} else if (type == qMetaTypeId<QScriptValue>()) {
*static_cast<NS(QScriptValue) *>(data) = NS(QScriptValue)();
return true;
+ } else if (type == qMetaTypeId<QDeclarativeV8Handle>()) {
+ *static_cast<NS(QDeclarativeV8Handle) *>(data) = NS(QDeclarativeV8Handle)();
+ return true;
} else if (typeCategory(type) != Unknown) {
*static_cast<void **>(data) = 0;
return true;
diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp
deleted file mode 100644
index 53f702ce51..0000000000
--- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp
+++ /dev/null
@@ -1,1226 +0,0 @@
-/****************************************************************************
-**
-** 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$
-** 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.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qdeclarativeobjectscriptclass_p.h"
-
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativecontext_p.h"
-#include "private/qdeclarativedata_p.h"
-#include "private/qdeclarativetypenamescriptclass_p.h"
-#include "private/qdeclarativelistscriptclass_p.h"
-#include "private/qdeclarativebinding_p.h"
-#include "private/qdeclarativeguard_p.h"
-#include "private/qdeclarativevmemetaobject_p.h"
-
-#include <QtCore/qtimer.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtScript/qscriptcontextinfo.h>
-
-Q_DECLARE_METATYPE(QScriptValue)
-
-#if defined(__GNUC__)
-# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
-// The code in this file does not violate strict aliasing, but GCC thinks it does
-// so turn off the warnings for us to have a clean build
-# pragma GCC diagnostic ignored "-Wstrict-aliasing"
-# endif
-#endif
-
-QT_BEGIN_NAMESPACE
-
-struct ObjectData : public QScriptDeclarativeClass::Object {
- ObjectData(QObject *o, int t) : object(o), type(t) {
- if (o) {
- QDeclarativeData *ddata = QDeclarativeData::get(object, true);
- if (ddata) ddata->objectDataRefCount++;
- }
- }
-
- virtual ~ObjectData() {
- if (object && !object->parent()) {
- QDeclarativeData *ddata = QDeclarativeData::get(object, false);
- if (ddata && !ddata->indestructible && 0 == --ddata->objectDataRefCount)
- object->deleteLater();
- }
- }
-
- QDeclarativeGuard<QObject> object;
- int type;
-};
-
-/*
- The QDeclarativeObjectScriptClass handles property access for QObjects
- via QtScript. It is also used to provide a more useful API in
- QtScript for QML.
- */
-QDeclarativeObjectScriptClass::QDeclarativeObjectScriptClass(QDeclarativeEngine *bindEngine)
-: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)),
- methods(bindEngine), lastData(0), engine(bindEngine)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- m_destroy = scriptEngine->newFunction(destroy);
- m_destroyId = createPersistentIdentifier(QLatin1String("destroy"));
- m_toString = scriptEngine->newFunction(tostring);
- m_toStringId = createPersistentIdentifier(QLatin1String("toString"));
-}
-
-QDeclarativeObjectScriptClass::~QDeclarativeObjectScriptClass()
-{
-}
-
-QScriptValue QDeclarativeObjectScriptClass::newQObject(QObject *object, int type)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- if (!object)
- return scriptEngine->nullValue();
-// return newObject(scriptEngine, this, new ObjectData(object, type));
-
- if (QObjectPrivate::get(object)->wasDeleted)
- return scriptEngine->undefinedValue();
-
- QDeclarativeData *ddata = QDeclarativeData::get(object, true);
-
- if (!ddata) {
- return scriptEngine->undefinedValue();
- } else if (!ddata->indestructible && !object->parent()) {
- return newObject(scriptEngine, this, new ObjectData(object, type));
- } else if (!ddata->scriptValue) {
- ddata->scriptValue = new QScriptValue(newObject(scriptEngine, this, new ObjectData(object, type)));
- return *ddata->scriptValue;
- } else if (ddata->scriptValue->engine() == QDeclarativeEnginePrivate::getScriptEngine(engine)) {
- return *ddata->scriptValue;
- } else {
- return newObject(scriptEngine, this, new ObjectData(object, type));
- }
-}
-
-QObject *QDeclarativeObjectScriptClass::toQObject(const QScriptValue &value) const
-{
- return value.toQObject();
-}
-
-int QDeclarativeObjectScriptClass::objectType(const QScriptValue &value) const
-{
- if (scriptClass(value) != this)
- return QVariant::Invalid;
-
- Object *o = object(value);
- return ((ObjectData*)(o))->type;
-}
-
-QScriptClass::QueryFlags
-QDeclarativeObjectScriptClass::queryProperty(Object *object, const Identifier &name,
- QScriptClass::QueryFlags flags)
-{
- return queryProperty(toQObject(object), name, flags, 0);
-}
-
-QScriptClass::QueryFlags
-QDeclarativeObjectScriptClass::queryProperty(QObject *obj, const Identifier &name,
- QScriptClass::QueryFlags flags, QDeclarativeContextData *evalContext,
- QueryHints hints)
-{
- Q_UNUSED(flags);
- lastData = 0;
- lastTNData = 0;
-
- if (name == m_destroyId.identifier ||
- name == m_toStringId.identifier)
- return QScriptClass::HandlesReadAccess;
-
- if (!obj)
- return 0;
-
- QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine);
- lastData = QDeclarativePropertyCache::property(engine, obj, name, local);
- if ((hints & ImplicitObject) && lastData && lastData->revision != 0) {
-
- QDeclarativeData *ddata = QDeclarativeData::get(obj);
- if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(lastData))
- return 0;
- }
-
- if (lastData)
- return QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess;
-
- if (!(hints & SkipAttachedProperties)) {
- if (!evalContext && context()) {
- // Global object, QScriptContext activation object, QDeclarativeContext object
- QScriptValue scopeNode = scopeChainValue(context(), -3);
- if (scopeNode.isValid()) {
- Q_ASSERT(scriptClass(scopeNode) == enginePrivate->contextClass);
-
- evalContext = enginePrivate->contextClass->contextFromValue(scopeNode);
- }
- }
-
- if (evalContext && evalContext->imports) {
- QDeclarativeTypeNameCache::Data *data = evalContext->imports->data(name);
- if (data) {
- lastTNData = data;
- return QScriptClass::HandlesReadAccess;
- }
- }
- }
-
- if (!(hints & ImplicitObject)) {
- local.coreIndex = -1;
- lastData = &local;
- return QScriptClass::HandlesWriteAccess;
- }
-
- return 0;
-}
-
-QDeclarativeObjectScriptClass::Value
-QDeclarativeObjectScriptClass::property(Object *object, const Identifier &name)
-{
- return property(toQObject(object), name);
-}
-
-QDeclarativeObjectScriptClass::Value
-QDeclarativeObjectScriptClass::property(QObject *obj, const Identifier &name)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- if (name == m_destroyId.identifier)
- return Value(scriptEngine, m_destroy);
- else if (name == m_toStringId.identifier)
- return Value(scriptEngine, m_toString);
-
- if (lastData && !lastData->isValid())
- return Value();
-
- Q_ASSERT(obj);
-
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
-
- if (lastTNData) {
-
- if (lastTNData->type)
- return Value(scriptEngine, enginePriv->typeNameClass->newObject(obj, lastTNData->type));
- else
- return Value(scriptEngine, enginePriv->typeNameClass->newObject(obj, lastTNData->typeNamespace));
-
- } else if (lastData->flags & QDeclarativePropertyCache::Data::IsFunction) {
- if (lastData->flags & QDeclarativePropertyCache::Data::IsVMEFunction) {
- return Value(scriptEngine, ((QDeclarativeVMEMetaObject *)(obj->metaObject()))->vmeMethod(lastData->coreIndex));
- } else {
- // Uncomment to use QtScript method call logic
- // QScriptValue sobj = scriptEngine->newQObject(obj);
- // return Value(scriptEngine, sobj.property(toString(name)));
- return Value(scriptEngine, methods.newMethod(obj, lastData));
- }
- } else {
- if (enginePriv->captureProperties && !(lastData->flags & QDeclarativePropertyCache::Data::IsConstant)) {
- if (lastData->coreIndex == 0) {
- enginePriv->capturedProperties <<
- QDeclarativeEnginePrivate::CapturedProperty(QDeclarativeData::get(obj, true)->objectNameNotifier());
- } else {
- enginePriv->capturedProperties <<
- QDeclarativeEnginePrivate::CapturedProperty(obj, lastData->coreIndex, lastData->notifyIndex);
- }
- }
-
- if (QDeclarativeValueTypeFactory::isValueType((uint)lastData->propType)) {
- QDeclarativeValueType *valueType = enginePriv->valueTypes[lastData->propType];
- if (valueType)
- return Value(scriptEngine, enginePriv->valueTypeClass->newObject(obj, lastData->coreIndex, valueType));
- }
-
- if (lastData->flags & QDeclarativePropertyCache::Data::IsQList) {
- return Value(scriptEngine, enginePriv->listClass->newList(obj, lastData->coreIndex, lastData->propType));
- } else if (lastData->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
- QObject *rv = 0;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, newQObject(rv, lastData->propType));
- } else if (lastData->flags & QDeclarativePropertyCache::Data::IsQScriptValue) {
- QScriptValue rv = scriptEngine->nullValue();
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, rv);
- } else if (lastData->propType == QMetaType::QReal) {
- qreal rv = 0;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, rv);
- } else if (lastData->propType == QMetaType::Int || lastData->flags & QDeclarativePropertyCache::Data::IsEnumType) {
- int rv = 0;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, rv);
- } else if (lastData->propType == QMetaType::Bool) {
- bool rv = false;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, rv);
- } else if (lastData->propType == QMetaType::QString) {
- QString rv;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, rv);
- } else if (lastData->propType == QMetaType::UInt) {
- uint rv = 0;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, rv);
- } else if (lastData->propType == QMetaType::Float) {
- float rv = 0;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, rv);
- } else if (lastData->propType == QMetaType::Double) {
- double rv = 0;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, rv);
- } else {
- QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj);
- return Value(scriptEngine, enginePriv->scriptValueFromVariant(var));
- }
- }
-}
-
-void QDeclarativeObjectScriptClass::setProperty(Object *object,
- const Identifier &name,
- const QScriptValue &value)
-{
- return setProperty(toQObject(object), name, value, context());
-}
-
-void QDeclarativeObjectScriptClass::setProperty(QObject *obj,
- const Identifier &name,
- const QScriptValue &value,
- QScriptContext *context,
- QDeclarativeContextData *evalContext)
-{
- Q_UNUSED(name);
-
- Q_ASSERT(obj);
- Q_ASSERT(lastData);
- Q_ASSERT(context);
-
- if (!lastData->isValid()) {
- QString error = QLatin1String("Cannot assign to non-existent property \"") +
- toString(name) + QLatin1Char('\"');
- context->throwError(error);
- return;
- }
-
- if (!(lastData->flags & QDeclarativePropertyCache::Data::IsWritable) &&
- !(lastData->flags & QDeclarativePropertyCache::Data::IsQList)) {
- QString error = QLatin1String("Cannot assign to read-only property \"") +
- toString(name) + QLatin1Char('\"');
- context->throwError(error);
- return;
- }
-
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
-
- if (!evalContext) {
- // Global object, QScriptContext activation object, QDeclarativeContext object
- QScriptValue scopeNode = scopeChainValue(context, -3);
- if (scopeNode.isValid()) {
- Q_ASSERT(scriptClass(scopeNode) == enginePriv->contextClass);
-
- evalContext = enginePriv->contextClass->contextFromValue(scopeNode);
- }
- }
-
- QDeclarativeBinding *newBinding = 0;
- if (value.isFunction() && !value.isRegExp()) {
- QScriptContextInfo ctxtInfo(context);
- QDeclarativePropertyCache::ValueTypeData valueTypeData;
-
- newBinding = new QDeclarativeBinding(value, obj, evalContext);
- newBinding->setSourceLocation(ctxtInfo.fileName(), ctxtInfo.functionStartLineNumber());
- newBinding->setTarget(QDeclarativePropertyPrivate::restore(*lastData, valueTypeData, obj, evalContext));
- if (newBinding->expression().contains(QLatin1String("this")))
- newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject);
- }
-
- QDeclarativeAbstractBinding *delBinding =
- QDeclarativePropertyPrivate::setBinding(obj, lastData->coreIndex, -1, newBinding);
- if (delBinding)
- delBinding->destroy();
-
- if (value.isNull() && lastData->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
- QObject *o = 0;
- int status = -1;
- int flags = 0;
- void *argv[] = { &o, 0, &status, &flags };
- QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, argv);
- } else if (value.isUndefined() && lastData->flags & QDeclarativePropertyCache::Data::IsResettable) {
- void *a[] = { 0 };
- QMetaObject::metacall(obj, QMetaObject::ResetProperty, lastData->coreIndex, a);
- } else if (value.isUndefined() && lastData->propType == qMetaTypeId<QVariant>()) {
- QDeclarativePropertyPrivate::write(obj, *lastData, QVariant(), evalContext);
- } else if (value.isUndefined()) {
- QString error = QLatin1String("Cannot assign [undefined] to ") +
- QLatin1String(QMetaType::typeName(lastData->propType));
- context->throwError(error);
- } else if (value.isFunction() && !value.isRegExp()) {
- // this is handled by the binding creation above
- } else {
- //### expand optimization for other known types
- if (lastData->propType == QMetaType::Int && value.isNumber()) {
- int rawValue = qRound(value.toNumber());
- int status = -1;
- int flags = 0;
- void *a[] = { (void *)&rawValue, 0, &status, &flags };
- QMetaObject::metacall(obj, QMetaObject::WriteProperty,
- lastData->coreIndex, a);
- return;
- } else if (lastData->propType == QMetaType::QReal && value.isNumber()) {
- qreal rawValue = qreal(value.toNumber());
- int status = -1;
- int flags = 0;
- void *a[] = { (void *)&rawValue, 0, &status, &flags };
- QMetaObject::metacall(obj, QMetaObject::WriteProperty,
- lastData->coreIndex, a);
- return;
- } else if (lastData->propType == QMetaType::QString && value.isString()) {
- const QString &rawValue = value.toString();
- int status = -1;
- int flags = 0;
- void *a[] = { (void *)&rawValue, 0, &status, &flags };
- QMetaObject::metacall(obj, QMetaObject::WriteProperty,
- lastData->coreIndex, a);
- return;
- }
-
- QVariant v;
- if (lastData->flags & QDeclarativePropertyCache::Data::IsQList)
- v = enginePriv->scriptValueToVariant(value, qMetaTypeId<QList<QObject *> >());
- else
- v = enginePriv->scriptValueToVariant(value, lastData->propType);
-
- if (!QDeclarativePropertyPrivate::write(obj, *lastData, v, evalContext)) {
- const char *valueType = 0;
- if (v.userType() == QVariant::Invalid) valueType = "null";
- else valueType = QMetaType::typeName(v.userType());
-
- QString error = QLatin1String("Cannot assign ") +
- QLatin1String(valueType) +
- QLatin1String(" to ") +
- QLatin1String(QMetaType::typeName(lastData->propType));
- context->throwError(error);
- }
- }
-}
-
-bool QDeclarativeObjectScriptClass::isQObject() const
-{
- return true;
-}
-
-QObject *QDeclarativeObjectScriptClass::toQObject(Object *object, bool *ok)
-{
- if (ok) *ok = true;
-
- ObjectData *data = (ObjectData*)object;
- return data->object.data();
-}
-
-QScriptValue QDeclarativeObjectScriptClass::tostring(QScriptContext *context, QScriptEngine *)
-{
- QObject* obj = context->thisObject().toQObject();
-
- QString ret;
- if(obj){
- QString objectName = obj->objectName();
-
- ret += QString::fromUtf8(obj->metaObject()->className());
- ret += QLatin1String("(0x");
- ret += QString::number((quintptr)obj,16);
-
- if (!objectName.isEmpty()) {
- ret += QLatin1String(", \"");
- ret += objectName;
- ret += QLatin1Char('\"');
- }
-
- ret += QLatin1Char(')');
- }else{
- ret += QLatin1String("null");
- }
- return QScriptValue(ret);
-}
-
-QScriptValue QDeclarativeObjectScriptClass::destroy(QScriptContext *context, QScriptEngine *engine)
-{
- QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
- QScriptValue that = context->thisObject();
-
- if (scriptClass(that) != p->objectClass)
- return engine->undefinedValue();
-
- ObjectData *data = (ObjectData *)p->objectClass->object(that);
- if (!data->object)
- return engine->undefinedValue();
-
- QDeclarativeData *ddata = QDeclarativeData::get(data->object, false);
- if (!ddata || ddata->indestructible)
- return engine->currentContext()->throwError(QLatin1String("Invalid attempt to destroy() an indestructible object"));
-
- QObject *obj = data->object;
- int delay = 0;
- if (context->argumentCount() > 0)
- delay = context->argument(0).toInt32();
- if (delay > 0)
- QTimer::singleShot(delay, obj, SLOT(deleteLater()));
- else
- obj->deleteLater();
-
- return engine->undefinedValue();
-}
-
-QStringList QDeclarativeObjectScriptClass::propertyNames(Object *object)
-{
- QObject *obj = toQObject(object);
- if (!obj)
- return QStringList();
-
- QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine);
-
- QDeclarativePropertyCache *cache = 0;
- QDeclarativeData *ddata = QDeclarativeData::get(obj);
- if (ddata)
- cache = ddata->propertyCache;
- if (!cache) {
- cache = enginePrivate->cache(obj);
- if (cache) {
- if (ddata) { cache->addref(); ddata->propertyCache = cache; }
- } else {
- // Not cachable - fall back to QMetaObject (eg. dynamic meta object)
- // XXX QDeclarativeOpenMetaObject has a cache, so this is suboptimal.
- // XXX This is a workaround for QTBUG-9420.
- const QMetaObject *mo = obj->metaObject();
- QStringList r;
- int pc = mo->propertyCount();
- int po = mo->propertyOffset();
- for (int i=po; i<pc; ++i)
- r += QString::fromUtf8(mo->property(i).name());
- return r;
- }
- }
- return cache->propertyNames();
-}
-
-bool QDeclarativeObjectScriptClass::compare(Object *o1, Object *o2)
-{
- ObjectData *d1 = (ObjectData *)o1;
- ObjectData *d2 = (ObjectData *)o2;
-
- return d1 == d2 || d1->object == d2->object;
-}
-
-struct MethodData : public QScriptDeclarativeClass::Object {
- MethodData(QObject *o, const QDeclarativePropertyCache::Data &d) : object(o), data(d) {}
-
- QDeclarativeGuard<QObject> object;
- QDeclarativePropertyCache::Data data;
-};
-
-QDeclarativeObjectMethodScriptClass::QDeclarativeObjectMethodScriptClass(QDeclarativeEngine *bindEngine)
-: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)),
- engine(bindEngine)
-{
- qRegisterMetaType<QList<QObject *> >("QList<QObject *>");
-
- setSupportsCall(true);
-
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- m_connect = scriptEngine->newFunction(connect);
- m_connectId = createPersistentIdentifier(QLatin1String("connect"));
- m_disconnect = scriptEngine->newFunction(disconnect);
- m_disconnectId = createPersistentIdentifier(QLatin1String("disconnect"));
-}
-
-QDeclarativeObjectMethodScriptClass::~QDeclarativeObjectMethodScriptClass()
-{
-}
-
-QScriptValue QDeclarativeObjectMethodScriptClass::newMethod(QObject *object, const QDeclarativePropertyCache::Data *method)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- return newObject(scriptEngine, this, new MethodData(object, *method));
-}
-
-QScriptValue QDeclarativeObjectMethodScriptClass::connect(QScriptContext *context, QScriptEngine *engine)
-{
- QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
-
- QScriptValue that = context->thisObject();
- if (&p->objectClass->methods != scriptClass(that))
- return engine->undefinedValue();
-
- MethodData *data = (MethodData *)object(that);
-
- if (!data->object || context->argumentCount() == 0)
- return engine->undefinedValue();
-
- QByteArray signal("2");
- signal.append(data->object->metaObject()->method(data->data.coreIndex).signature());
-
- if (context->argumentCount() == 1) {
- qScriptConnect(data->object, signal.constData(), QScriptValue(), context->argument(0));
- } else {
- qScriptConnect(data->object, signal.constData(), context->argument(0), context->argument(1));
- }
-
- return engine->undefinedValue();
-}
-
-QScriptValue QDeclarativeObjectMethodScriptClass::disconnect(QScriptContext *context, QScriptEngine *engine)
-{
- QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
-
- QScriptValue that = context->thisObject();
- if (&p->objectClass->methods != scriptClass(that))
- return engine->undefinedValue();
-
- MethodData *data = (MethodData *)object(that);
-
- if (!data->object || context->argumentCount() == 0)
- return engine->undefinedValue();
-
- QByteArray signal("2");
- signal.append(data->object->metaObject()->method(data->data.coreIndex).signature());
-
- if (context->argumentCount() == 1) {
- qScriptDisconnect(data->object, signal.constData(), QScriptValue(), context->argument(0));
- } else {
- qScriptDisconnect(data->object, signal.constData(), context->argument(0), context->argument(1));
- }
-
- return engine->undefinedValue();
-}
-
-QScriptClass::QueryFlags
-QDeclarativeObjectMethodScriptClass::queryProperty(Object *, const Identifier &name,
- QScriptClass::QueryFlags flags)
-{
- Q_UNUSED(flags);
- if (name == m_connectId.identifier || name == m_disconnectId.identifier)
- return QScriptClass::HandlesReadAccess;
- else
- return 0;
-
-}
-
-QDeclarativeObjectMethodScriptClass::Value
-QDeclarativeObjectMethodScriptClass::property(Object *, const Identifier &name)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- if (name == m_connectId.identifier)
- return Value(scriptEngine, m_connect);
- else if (name == m_disconnectId.identifier)
- return Value(scriptEngine, m_disconnect);
- else
- return Value();
-}
-
-namespace {
-struct MetaCallArgument {
- inline MetaCallArgument();
- inline ~MetaCallArgument();
- inline void *dataPtr();
-
- inline void initAsType(int type, QDeclarativeEngine *);
- void fromScriptValue(int type, QDeclarativeEngine *, const QScriptValue &);
- inline QScriptDeclarativeClass::Value toValue(QDeclarativeEngine *);
-
-private:
- MetaCallArgument(const MetaCallArgument &);
-
- inline void cleanup();
-
- char data[4 * sizeof(void *)];
- int type;
- bool isObjectType;
-};
-}
-
-MetaCallArgument::MetaCallArgument()
-: type(QVariant::Invalid), isObjectType(false)
-{
-}
-
-MetaCallArgument::~MetaCallArgument()
-{
- cleanup();
-}
-
-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();
- } else if (type == qMetaTypeId<QList<QObject *> >()) {
- ((QList<QObject *> *)&data)->~QList<QObject *>();
- }
-}
-
-void *MetaCallArgument::dataPtr()
-{
- if (type == -1)
- return ((QVariant *)data)->data();
- else
- return (void *)&data;
-}
-
-void MetaCallArgument::initAsType(int callType, QDeclarativeEngine *e)
-{
- if (type != 0) { cleanup(); type = 0; }
- if (callType == 0) return;
-
- QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e);
-
- if (callType == qMetaTypeId<QScriptValue>()) {
- new (&data) QScriptValue(engine->undefinedValue());
- type = callType;
- } else if (callType == QMetaType::Int ||
- callType == QMetaType::UInt ||
- callType == QMetaType::Bool ||
- callType == QMetaType::Double ||
- callType == QMetaType::Float) {
- type = callType;
- } else if (callType == QMetaType::QObjectStar) {
- *((QObject **)&data) = 0;
- type = callType;
- } else if (callType == QMetaType::QString) {
- new (&data) QString();
- type = callType;
- } else if (callType == qMetaTypeId<QVariant>()) {
- type = callType;
- new (&data) QVariant();
- } else if (callType == qMetaTypeId<QList<QObject *> >()) {
- type = callType;
- new (&data) QList<QObject *>();
- } else {
- type = -1;
- new (&data) QVariant(callType, (void *)0);
- }
-}
-
-void MetaCallArgument::fromScriptValue(int callType, QDeclarativeEngine *engine, const QScriptValue &value)
-{
- if (type != 0) { cleanup(); type = 0; }
-
- if (callType == qMetaTypeId<QScriptValue>()) {
- new (&data) QScriptValue(value);
- type = qMetaTypeId<QScriptValue>();
- } else if (callType == QMetaType::Int) {
- *((int *)&data) = int(value.toInt32());
- type = callType;
- } else if (callType == QMetaType::UInt) {
- *((uint *)&data) = uint(value.toUInt32());
- type = callType;
- } else if (callType == QMetaType::Bool) {
- *((bool *)&data) = value.toBool();
- type = callType;
- } else if (callType == QMetaType::Double) {
- *((double *)&data) = double(value.toNumber());
- type = callType;
- } else if (callType == QMetaType::Float) {
- *((float *)&data) = float(value.toNumber());
- type = callType;
- } else if (callType == QMetaType::QString) {
- if (value.isNull() || value.isUndefined())
- new (&data) QString();
- else
- new (&data) QString(value.toString());
- type = callType;
- } else if (callType == QMetaType::QObjectStar) {
- *((QObject **)&data) = value.toQObject();
- type = callType;
- } else if (callType == qMetaTypeId<QVariant>()) {
- new (&data) QVariant(QDeclarativeEnginePrivate::get(engine)->scriptValueToVariant(value));
- type = callType;
- } else if (callType == qMetaTypeId<QList<QObject*> >()) {
- QList<QObject *> *list = new (&data) QList<QObject *>();
- if (value.isArray()) {
- int length = value.property(QLatin1String("length")).toInt32();
- for (int ii = 0; ii < length; ++ii) {
- QScriptValue arrayItem = value.property(ii);
- QObject *d = arrayItem.toQObject();
- list->append(d);
- }
- } else if (QObject *d = value.toQObject()) {
- list->append(d);
- }
- type = callType;
- } else {
- new (&data) QVariant();
- type = -1;
-
- QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(engine);
- QVariant v = priv->scriptValueToVariant(value);
- if (v.userType() == callType) {
- *((QVariant *)&data) = v;
- } else if (v.canConvert((QVariant::Type)callType)) {
- *((QVariant *)&data) = v;
- ((QVariant *)&data)->convert((QVariant::Type)callType);
- } else if (const QMetaObject *mo = priv->rawMetaObjectForType(callType)) {
- QObject *obj = priv->toQObject(v);
-
- if (obj) {
- const QMetaObject *objMo = obj->metaObject();
- while (objMo && objMo != mo) objMo = objMo->superClass();
- if (!objMo) obj = 0;
- }
-
- *((QVariant *)&data) = QVariant(callType, &obj);
- } else {
- *((QVariant *)&data) = QVariant(callType, (void *)0);
- }
- }
-}
-
-QScriptDeclarativeClass::Value MetaCallArgument::toValue(QDeclarativeEngine *e)
-{
- QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e);
-
- if (type == qMetaTypeId<QScriptValue>()) {
- return QScriptDeclarativeClass::Value(engine, *((QScriptValue *)&data));
- } else if (type == QMetaType::Int) {
- return QScriptDeclarativeClass::Value(engine, *((int *)&data));
- } else if (type == QMetaType::UInt) {
- return QScriptDeclarativeClass::Value(engine, *((uint *)&data));
- } else if (type == QMetaType::Bool) {
- return QScriptDeclarativeClass::Value(engine, *((bool *)&data));
- } else if (type == QMetaType::Double) {
- return QScriptDeclarativeClass::Value(engine, *((double *)&data));
- } else if (type == QMetaType::Float) {
- return QScriptDeclarativeClass::Value(engine, *((float *)&data));
- } else if (type == QMetaType::QString) {
- return QScriptDeclarativeClass::Value(engine, *((QString *)&data));
- } else if (type == QMetaType::QObjectStar) {
- QObject *object = *((QObject **)&data);
- if (object)
- QDeclarativeData::get(object, true)->setImplicitDestructible();
- QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e);
- return QScriptDeclarativeClass::Value(engine, priv->objectClass->newQObject(object));
- } else if (type == qMetaTypeId<QList<QObject *> >()) {
- QList<QObject *> &list = *(QList<QObject *>*)&data;
- QScriptValue rv = engine->newArray(list.count());
- QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e);
- for (int ii = 0; ii < list.count(); ++ii) {
- QObject *object = list.at(ii);
- QDeclarativeData::get(object, true)->setImplicitDestructible();
- rv.setProperty(ii, priv->objectClass->newQObject(object));
- }
- return QScriptDeclarativeClass::Value(engine, rv);
- } else if (type == -1 || type == qMetaTypeId<QVariant>()) {
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(e);
- QScriptValue rv = ep->scriptValueFromVariant(*((QVariant *)&data));
- if (rv.isQObject()) {
- QObject *object = rv.toQObject();
- if (object)
- QDeclarativeData::get(object, true)->setImplicitDestructible();
- }
- return QScriptDeclarativeClass::Value(engine, rv);
- } else {
- return QScriptDeclarativeClass::Value();
- }
-}
-
-int QDeclarativeObjectMethodScriptClass::enumType(const QMetaObject *meta, const QString &strname)
-{
- QByteArray str = strname.toUtf8();
- QByteArray scope;
- QByteArray name;
- int scopeIdx = str.lastIndexOf("::");
- if (scopeIdx != -1) {
- scope = str.left(scopeIdx);
- name = str.mid(scopeIdx + 2);
- } else {
- name = str;
- }
- for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
- QMetaEnum m = meta->enumerator(i);
- if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
- return QVariant::Int;
- }
- return QVariant::Invalid;
-}
-
-QDeclarativeObjectMethodScriptClass::Value QDeclarativeObjectMethodScriptClass::call(Object *o, QScriptContext *ctxt)
-{
- MethodData *method = static_cast<MethodData *>(o);
-
- if (method->data.relatedIndex == -1)
- return callPrecise(method->object, method->data, ctxt);
- else
- return callOverloaded(method, ctxt);
-}
-
-QDeclarativeObjectMethodScriptClass::Value
-QDeclarativeObjectMethodScriptClass::callPrecise(QObject *object, const QDeclarativePropertyCache::Data &data,
- QScriptContext *ctxt)
-{
- if (data.flags & QDeclarativePropertyCache::Data::HasArguments) {
-
- QMetaMethod m = object->metaObject()->method(data.coreIndex);
- QList<QByteArray> argTypeNames = m.parameterTypes();
- QVarLengthArray<int, 9> argTypes(argTypeNames.count());
-
- // ### Cache
- for (int ii = 0; ii < argTypeNames.count(); ++ii) {
- argTypes[ii] = QMetaType::type(argTypeNames.at(ii));
- if (argTypes[ii] == QVariant::Invalid)
- argTypes[ii] = enumType(object->metaObject(), QString::fromLatin1(argTypeNames.at(ii)));
- if (argTypes[ii] == QVariant::Invalid)
- return Value(ctxt, ctxt->throwError(QString::fromLatin1("Unknown method parameter type: %1").arg(QLatin1String(argTypeNames.at(ii)))));
- }
-
- if (argTypes.count() > ctxt->argumentCount())
- return Value(ctxt, ctxt->throwError(QLatin1String("Insufficient arguments")));
-
- return callMethod(object, data.coreIndex, data.propType, argTypes.count(), argTypes.data(), ctxt);
-
- } else {
-
- return callMethod(object, data.coreIndex, data.propType, 0, 0, ctxt);
-
- }
-}
-
-QDeclarativeObjectMethodScriptClass::Value
-QDeclarativeObjectMethodScriptClass::callMethod(QObject *object, int index,
- int returnType, int argCount, int *argTypes,
- QScriptContext *ctxt)
-{
- if (argCount > 0) {
-
- QVarLengthArray<MetaCallArgument, 9> args(argCount + 1);
- args[0].initAsType(returnType, engine);
-
- for (int ii = 0; ii < argCount; ++ii)
- args[ii + 1].fromScriptValue(argTypes[ii], engine, ctxt->argument(ii));
-
- QVarLengthArray<void *, 9> argData(args.count());
- for (int ii = 0; ii < args.count(); ++ii)
- argData[ii] = args[ii].dataPtr();
-
- QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, argData.data());
-
- return args[0].toValue(engine);
-
- } else if (returnType != 0) {
-
- MetaCallArgument arg;
- arg.initAsType(returnType, engine);
-
- void *args[] = { arg.dataPtr() };
-
- QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
-
- return arg.toValue(engine);
-
- } else {
-
- void *args[] = { 0 };
- QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
- return Value();
-
- }
-}
-
-/*!
-Resolve the overloaded method to call. The algorithm works conceptually like this:
- 1. Resolve the set of overloads it is *possible* to call.
- Impossible overloads include those that have too many parameters or have parameters
- of unknown type.
- 2. Filter the set of overloads to only contain those with the closest number of
- parameters.
- For example, if we are called with 3 parameters and there are 2 overloads that
- take 2 parameters and one that takes 3, eliminate the 2 parameter overloads.
- 3. Find the best remaining overload based on its match score.
- If two or more overloads have the same match score, call the last one. The match
- score is constructed by adding the matchScore() result for each of the parameters.
-*/
-QDeclarativeObjectMethodScriptClass::Value
-QDeclarativeObjectMethodScriptClass::callOverloaded(MethodData *method, QScriptContext *ctxt)
-{
- int argumentCount = ctxt->argumentCount();
-
- QDeclarativePropertyCache::Data *best = 0;
- int bestParameterScore = INT_MAX;
- int bestMatchScore = INT_MAX;
-
- QDeclarativePropertyCache::Data dummy;
- QDeclarativePropertyCache::Data *attempt = &method->data;
-
- do {
- QList<QByteArray> methodArgTypeNames;
-
- if (attempt->flags & QDeclarativePropertyCache::Data::HasArguments)
- methodArgTypeNames = method->object->metaObject()->method(attempt->coreIndex).parameterTypes();
-
- int methodArgumentCount = methodArgTypeNames.count();
-
- if (methodArgumentCount > argumentCount)
- continue; // We don't have sufficient arguments to call this method
-
- int methodParameterScore = argumentCount - methodArgumentCount;
- if (methodParameterScore > bestParameterScore)
- continue; // We already have a better option
-
- int methodMatchScore = 0;
- QVarLengthArray<int, 9> methodArgTypes(methodArgumentCount);
-
- bool unknownArgument = false;
- for (int ii = 0; ii < methodArgumentCount; ++ii) {
- methodArgTypes[ii] = QMetaType::type(methodArgTypeNames.at(ii));
- if (methodArgTypes[ii] == QVariant::Invalid)
- methodArgTypes[ii] = enumType(method->object->metaObject(),
- QString::fromLatin1(methodArgTypeNames.at(ii)));
- if (methodArgTypes[ii] == QVariant::Invalid) {
- unknownArgument = true;
- break;
- }
- methodMatchScore += matchScore(ctxt->argument(ii), methodArgTypes[ii], methodArgTypeNames.at(ii));
- }
- if (unknownArgument)
- continue; // We don't understand all the parameters
-
- if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
- best = attempt;
- bestParameterScore = methodParameterScore;
- bestMatchScore = methodMatchScore;
- }
-
- if (bestParameterScore == 0 && bestMatchScore == 0)
- break; // We can't get better than that
-
- } while((attempt = relatedMethod(method->object, attempt, dummy)) != 0);
-
- if (best) {
- return callPrecise(method->object, *best, ctxt);
- } else {
- QString error = QLatin1String("Unable to determine callable overload. Candidates are:");
- QDeclarativePropertyCache::Data *candidate = &method->data;
- while (candidate) {
- error += QLatin1String("\n ") + QString::fromUtf8(method->object->metaObject()->method(candidate->coreIndex).signature());
- candidate = relatedMethod(method->object, candidate, dummy);
- }
- return Value(ctxt, ctxt->throwError(error));
- }
-}
-
-/*!
- Returns the match score for converting \a actual to be of type \a conversionType. A
- zero score means "perfect match" whereas a higher score is worse.
-
- The conversion table is copied out of the QtScript callQtMethod() function.
-*/
-int QDeclarativeObjectMethodScriptClass::matchScore(const QScriptValue &actual, int conversionType,
- const QByteArray &conversionTypeName)
-{
- if (actual.isNumber()) {
- switch (conversionType) {
- case QMetaType::Double:
- return 0;
- case QMetaType::Float:
- return 1;
- case QMetaType::LongLong:
- case QMetaType::ULongLong:
- return 2;
- case QMetaType::Long:
- case QMetaType::ULong:
- return 3;
- case QMetaType::Int:
- case QMetaType::UInt:
- return 4;
- case QMetaType::Short:
- case QMetaType::UShort:
- return 5;
- break;
- case QMetaType::Char:
- case QMetaType::UChar:
- return 6;
- default:
- return 10;
- }
- } else if (actual.isString()) {
- switch (conversionType) {
- case QMetaType::QString:
- return 0;
- default:
- return 10;
- }
- } else if (actual.isBoolean()) {
- switch (conversionType) {
- case QMetaType::Bool:
- return 0;
- default:
- return 10;
- }
- } else if (actual.isDate()) {
- switch (conversionType) {
- case QMetaType::QDateTime:
- return 0;
- case QMetaType::QDate:
- return 1;
- case QMetaType::QTime:
- return 2;
- default:
- return 10;
- }
- } else if (actual.isRegExp()) {
- switch (conversionType) {
- case QMetaType::QRegExp:
- return 0;
- default:
- return 10;
- }
- } else if (actual.isVariant()) {
- if (conversionType == qMetaTypeId<QVariant>())
- return 0;
- else if (actual.toVariant().userType() == conversionType)
- return 0;
- else
- return 10;
- } else if (actual.isArray()) {
- switch (conversionType) {
- case QMetaType::QStringList:
- case QMetaType::QVariantList:
- return 5;
- default:
- return 10;
- }
- } else if (actual.isQObject()) {
- switch (conversionType) {
- case QMetaType::QObjectStar:
- return 0;
- default:
- return 10;
- }
- } else if (actual.isNull()) {
- switch (conversionType) {
- case QMetaType::VoidStar:
- case QMetaType::QObjectStar:
- return 0;
- default:
- if (!conversionTypeName.endsWith('*'))
- return 10;
- else
- return 0;
- }
- } else {
- return 10;
- }
-}
-
-static inline int QMetaObject_methods(const QMetaObject *metaObject)
-{
- struct Private
- {
- int revision;
- int className;
- int classInfoCount, classInfoData;
- int methodCount, methodData;
- };
-
- return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
-}
-
-static QByteArray QMetaMethod_name(const QMetaMethod &m)
-{
- QByteArray sig = m.signature();
- int paren = sig.indexOf('(');
- if (paren == -1)
- return sig;
- else
- return sig.left(paren);
-}
-
-/*!
-Returns the next related method, if one, or 0.
-*/
-QDeclarativePropertyCache::Data *
-QDeclarativeObjectMethodScriptClass::relatedMethod(QObject *object, QDeclarativePropertyCache::Data *current,
- QDeclarativePropertyCache::Data &dummy)
-{
- QDeclarativePropertyCache *cache = QDeclarativeData::get(object)->propertyCache;
- if (current->relatedIndex == -1)
- return 0;
-
- if (cache) {
- return cache->method(current->relatedIndex);
- } else {
- const QMetaObject *mo = object->metaObject();
- int methodOffset = mo->methodCount() - QMetaObject_methods(mo);
-
- while (methodOffset > current->relatedIndex) {
- mo = mo->superClass();
- methodOffset -= QMetaObject_methods(mo);
- }
-
- QMetaMethod method = mo->method(current->relatedIndex);
- dummy.load(method);
-
- // Look for overloaded methods
- QByteArray methodName = QMetaMethod_name(method);
- for (int ii = current->relatedIndex - 1; ii >= methodOffset; --ii) {
- if (methodName == QMetaMethod_name(mo->method(ii))) {
- dummy.relatedIndex = ii;
- return &dummy;
- }
- }
-
- return &dummy;
- }
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass_p.h b/src/declarative/qml/qdeclarativeobjectscriptclass_p.h
deleted file mode 100644
index f1f1ab25d0..0000000000
--- a/src/declarative/qml/qdeclarativeobjectscriptclass_p.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/****************************************************************************
-**
-** 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$
-** 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.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QDECLARATIVEOBJECTSCRIPTCLASS_P_H
-#define QDECLARATIVEOBJECTSCRIPTCLASS_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 "private/qdeclarativepropertycache_p.h"
-#include "private/qdeclarativetypenamecache_p.h"
-
-#include <private/qscriptdeclarativeclass_p.h>
-#include <QtScript/qscriptengine.h>
-
-QT_BEGIN_NAMESPACE
-
-class QDeclarativeEngine;
-class QScriptContext;
-class QScriptEngine;
-class QDeclarativeContextData;
-class MethodData;
-
-class Q_AUTOTEST_EXPORT QDeclarativeObjectMethodScriptClass : public QScriptDeclarativeClass
-{
-public:
- QDeclarativeObjectMethodScriptClass(QDeclarativeEngine *);
- ~QDeclarativeObjectMethodScriptClass();
-
- QScriptValue newMethod(QObject *, const QDeclarativePropertyCache::Data *);
-
-protected:
- virtual Value call(Object *, QScriptContext *);
- virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, QScriptClass::QueryFlags flags);
- virtual Value property(Object *, const Identifier &);
-
-private:
- int enumType(const QMetaObject *, const QString &);
-
- Value callPrecise(QObject *, const QDeclarativePropertyCache::Data &, QScriptContext *);
- Value callOverloaded(MethodData *, QScriptContext *);
- Value callMethod(QObject *, int index, int returnType, int argCount, int *argTypes, QScriptContext *ctxt);
-
- int matchScore(const QScriptValue &, int, const QByteArray &);
- QDeclarativePropertyCache::Data *relatedMethod(QObject *, QDeclarativePropertyCache::Data *current,
- QDeclarativePropertyCache::Data &dummy);
-
- PersistentIdentifier m_connectId;
- PersistentIdentifier m_disconnectId;
- QScriptValue m_connect;
- QScriptValue m_disconnect;
-
- static QScriptValue connect(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue disconnect(QScriptContext *context, QScriptEngine *engine);
-
- QDeclarativeEngine *engine;
-};
-
-class Q_AUTOTEST_EXPORT QDeclarativeObjectScriptClass : public QScriptDeclarativeClass
-{
-public:
- QDeclarativeObjectScriptClass(QDeclarativeEngine *);
- ~QDeclarativeObjectScriptClass();
-
- QScriptValue newQObject(QObject *, int type = QMetaType::QObjectStar);
-
- QObject *toQObject(const QScriptValue &) const;
- int objectType(const QScriptValue &) const;
-
- enum QueryHint {
- ImplicitObject = 0x01,
- SkipAttachedProperties = 0x02
- };
- Q_DECLARE_FLAGS(QueryHints, QueryHint)
-
- QScriptClass::QueryFlags queryProperty(QObject *, const Identifier &,
- QScriptClass::QueryFlags flags,
- QDeclarativeContextData *evalContext,
- QueryHints hints = 0);
-
- Value property(QObject *, const Identifier &);
-
- void setProperty(QObject *, const Identifier &name, const QScriptValue &,
- QScriptContext *context, QDeclarativeContextData *evalContext = 0);
- virtual QStringList propertyNames(Object *);
- virtual bool compare(Object *, Object *);
-
-protected:
- virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
- QScriptClass::QueryFlags flags);
-
- virtual Value property(Object *, const Identifier &);
- virtual void setProperty(Object *, const Identifier &name, const QScriptValue &);
- virtual bool isQObject() const;
- virtual QObject *toQObject(Object *, bool *ok = 0);
-
-private:
- friend class QDeclarativeObjectMethodScriptClass;
- QDeclarativeObjectMethodScriptClass methods;
-
- QDeclarativeTypeNameCache::Data *lastTNData;
- QDeclarativePropertyCache::Data *lastData;
- QDeclarativePropertyCache::Data local;
-
- PersistentIdentifier m_destroyId;
- PersistentIdentifier m_toStringId;
- QScriptValue m_destroy;
- QScriptValue m_toString;
-
- static QScriptValue tostring(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue destroy(QScriptContext *context, QScriptEngine *engine);
-
- QDeclarativeEngine *engine;
-};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeObjectScriptClass::QueryHints);
-
-QT_END_NAMESPACE
-
-#endif // QDECLARATIVEOBJECTSCRIPTCLASS_P_H
-
diff --git a/src/declarative/qml/qdeclarativeproperty.cpp b/src/declarative/qml/qdeclarativeproperty.cpp
index ae28049eed..213403d006 100644
--- a/src/declarative/qml/qdeclarativeproperty.cpp
+++ b/src/declarative/qml/qdeclarativeproperty.cpp
@@ -1503,7 +1503,7 @@ QDeclarativePropertyPrivate::restore(const QDeclarativePropertyCache::Data &data
prop.d = new QDeclarativePropertyPrivate;
prop.d->object = object;
prop.d->context = ctxt;
- prop.d->engine = ctxt->engine;
+ prop.d->engine = ctxt?ctxt->engine:0;
prop.d->core = data;
prop.d->valueType = valueType;
diff --git a/src/declarative/qml/qdeclarativepropertycache.cpp b/src/declarative/qml/qdeclarativepropertycache.cpp
index 0fa4e24725..783a66ef97 100644
--- a/src/declarative/qml/qdeclarativepropertycache.cpp
+++ b/src/declarative/qml/qdeclarativepropertycache.cpp
@@ -43,9 +43,11 @@
#include "private/qdeclarativeengine_p.h"
#include "private/qdeclarativebinding_p.h"
+#include "private/qv8engine_p.h"
#include <QtCore/qdebug.h>
Q_DECLARE_METATYPE(QScriptValue)
+Q_DECLARE_METATYPE(QDeclarativeV8Handle);
QT_BEGIN_NAMESPACE
@@ -68,6 +70,8 @@ QDeclarativePropertyCache::Data::Flags QDeclarativePropertyCache::Data::flagsFor
flags |= Data::IsQmlBinding;
} else if (propType == qMetaTypeId<QScriptValue>()) {
flags |= Data::IsQScriptValue;
+ } else if (propType == qMetaTypeId<QDeclarativeV8Handle>()) {
+ flags |= Data::IsV8Handle;
} else if (p.isEnumType()) {
flags |= Data::IsEnumType;
} else {
@@ -107,8 +111,13 @@ void QDeclarativePropertyCache::Data::load(const QMetaMethod &m)
propType = QMetaType::type(returnType);
QList<QByteArray> params = m.parameterTypes();
- if (!params.isEmpty())
+ if (!params.isEmpty()) {
flags |= Data::HasArguments;
+ if (params.at(0).length() == 23 &&
+ 0 == qstrcmp(params.at(0).constData(), "QDeclarativeV8Function*")) {
+ flags |= Data::IsV8Function;
+ }
+ }
revision = m.revision();
}
@@ -156,16 +165,10 @@ void QDeclarativePropertyCache::clear()
data->release();
}
- for (IdentifierCache::ConstIterator iter = identifierCache.begin();
- iter != identifierCache.end(); ++iter) {
- RData *data = (*iter);
- data->release();
- }
-
indexCache.clear();
methodIndexCache.clear();
stringCache.clear();
- identifierCache.clear();
+ qPersistentDispose(constructor);
}
QDeclarativePropertyCache::Data QDeclarativePropertyCache::create(const QMetaObject *metaObject,
@@ -219,7 +222,6 @@ QDeclarativePropertyCache *QDeclarativePropertyCache::copy() const
cache->indexCache = indexCache;
cache->methodIndexCache = methodIndexCache;
cache->stringCache = stringCache;
- cache->identifierCache = identifierCache;
cache->allowedRevisionCache = allowedRevisionCache;
for (int ii = 0; ii < indexCache.count(); ++ii) {
@@ -230,8 +232,8 @@ QDeclarativePropertyCache *QDeclarativePropertyCache::copy() const
}
for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
(*iter)->addref();
- for (IdentifierCache::ConstIterator iter = identifierCache.begin(); iter != identifierCache.end(); ++iter)
- (*iter)->addref();
+
+ // We specifically do *NOT* copy the constructor
return cache;
}
@@ -248,6 +250,8 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb
{
Q_UNUSED(revision);
+ qPersistentDispose(constructor); // Now invalid
+
allowedRevisionCache.append(0);
QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
@@ -267,7 +271,6 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb
methodName = methodName.left(parenIdx);
RData *data = new RData;
- data->identifier = enginePriv->objectClass->createPersistentIdentifier(methodName);
methodIndexCache[ii] = data;
data->load(m);
@@ -286,12 +289,9 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb
data->overrideIndexIsProperty = !bool(old->flags & Data::IsFunction);
data->overrideIndex = old->coreIndex;
stringCache[methodName]->release();
- identifierCache[data->identifier.identifier]->release();
}
stringCache.insert(methodName, data);
- identifierCache.insert(data->identifier.identifier, data);
- data->addref();
data->addref();
}
@@ -307,7 +307,6 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb
QString propName = QString::fromUtf8(p.name());
RData *data = new RData;
- data->identifier = enginePriv->objectClass->createPersistentIdentifier(propName);
indexCache[ii] = data;
data->load(p, engine);
@@ -320,12 +319,9 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb
data->overrideIndexIsProperty = !bool(old->flags & Data::IsFunction);
data->overrideIndex = old->coreIndex;
stringCache[propName]->release();
- identifierCache[data->identifier.identifier]->release();
}
stringCache.insert(propName, data);
- identifierCache.insert(data->identifier.identifier, data);
- data->addref();
data->addref();
}
}
@@ -375,7 +371,8 @@ QDeclarativePropertyCache::method(int index) const
QDeclarativePropertyCache::Data *
QDeclarativePropertyCache::property(const QString &str) const
{
- return stringCache.value(str);
+ QDeclarativePropertyCache::RData **rv = stringCache.value(str);
+ return rv?*rv:0;
}
QString QDeclarativePropertyCache::Data::name(QObject *object)
@@ -407,29 +404,38 @@ QString QDeclarativePropertyCache::Data::name(const QMetaObject *metaObject)
QStringList QDeclarativePropertyCache::propertyNames() const
{
- return stringCache.keys();
+ QStringList keys;
+ for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
+ keys.append(iter.key());
+ return keys;
}
-QDeclarativePropertyCache::Data *QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj,
- const QScriptDeclarativeClass::Identifier &name, Data &local)
+QDeclarativePropertyCache::Data *
+QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj,
+ v8::Handle<v8::String> name, Data &local)
{
- QDeclarativePropertyCache::Data *rv = 0;
-
- QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine);
-
+ // XXX Optimize for worker script case where engine isn't available
QDeclarativePropertyCache *cache = 0;
- QDeclarativeData *ddata = QDeclarativeData::get(obj);
- if (ddata && ddata->propertyCache && ddata->propertyCache->qmlEngine() == engine)
- cache = ddata->propertyCache;
- if (!cache) {
- cache = enginePrivate->cache(obj);
- if (cache && ddata && !ddata->propertyCache) { cache->addref(); ddata->propertyCache = cache; }
+ if (engine) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+
+ QDeclarativeData *ddata = QDeclarativeData::get(obj);
+ if (ddata && ddata->propertyCache && ddata->propertyCache->qmlEngine() == engine) // XXX aakenend
+ cache = ddata->propertyCache;
+ if (!cache) {
+ cache = ep->cache(obj);
+ if (cache && ddata && !ddata->propertyCache) { cache->addref(); ddata->propertyCache = cache; }
+ }
}
+ QDeclarativePropertyCache::Data *rv = 0;
+
if (cache) {
rv = cache->property(name);
} else {
- local = QDeclarativePropertyCache::create(obj->metaObject(), enginePrivate->objectClass->toString(name));
+ QString strname = QV8Engine::toStringStatic(name);
+ // QString strname = ep->v8engine.toString(name);
+ local = QDeclarativePropertyCache::create(obj->metaObject(), strname);
if (local.isValid())
rv = &local;
}
@@ -437,8 +443,9 @@ QDeclarativePropertyCache::Data *QDeclarativePropertyCache::property(QDeclarativ
return rv;
}
-QDeclarativePropertyCache::Data *QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj,
- const QString &name, Data &local)
+QDeclarativePropertyCache::Data *
+QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj,
+ const QString &name, Data &local)
{
QDeclarativePropertyCache::Data *rv = 0;
diff --git a/src/declarative/qml/qdeclarativepropertycache_p.h b/src/declarative/qml/qdeclarativepropertycache_p.h
index 7e34748c6c..87005eb8f4 100644
--- a/src/declarative/qml/qdeclarativepropertycache_p.h
+++ b/src/declarative/qml/qdeclarativepropertycache_p.h
@@ -57,6 +57,7 @@
#include "private/qdeclarativecleanup_p.h"
#include "private/qdeclarativenotifier_p.h"
+#include "private/qhashedstring_p.h"
#include <QtCore/qvector.h>
#include <QtScript/private/qscriptdeclarativeclass_p.h>
@@ -64,6 +65,8 @@ QT_BEGIN_NAMESPACE
class QDeclarativeEngine;
class QMetaProperty;
+class QV8Engine;
+class QV8QObjectWrapper;
class Q_AUTOTEST_EXPORT QDeclarativePropertyCache : public QDeclarativeRefCount, public QDeclarativeCleanup
{
@@ -93,16 +96,30 @@ public:
IsQList = 0x00000100,
IsQmlBinding = 0x00000200,
IsQScriptValue = 0x00000400,
+ IsV8Handle = 0x00000800,
// Apply only to IsFunctions
- IsVMEFunction = 0x00000800,
- HasArguments = 0x00001000,
- IsSignal = 0x00002000,
- IsVMESignal = 0x00004000
+ IsVMEFunction = 0x00001000,
+ HasArguments = 0x00002000,
+ IsSignal = 0x00004000,
+ IsVMESignal = 0x00008000,
+ IsV8Function = 0x00010000
};
Q_DECLARE_FLAGS(Flags, Flag)
bool isValid() const { return coreIndex != -1; }
+ bool isConstant() const { return flags & IsConstant; }
+ bool isWritable() const { return flags & IsWritable; }
+ bool isResettable() const { return flags & IsResettable; }
+ bool isAlias() const { return flags & IsAlias; }
+ bool isFinal() const { return flags & IsFinal; }
+ bool isFunction() const { return flags & IsFunction; }
+ bool isQObject() const { return flags & IsQObjectDerived; }
+ 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 isV8Handle() const { return flags & IsV8Handle; }
Flags flags;
int propType;
@@ -141,7 +158,7 @@ public:
static Data create(const QMetaObject *, const QString &);
- inline Data *property(const QScriptDeclarativeClass::Identifier &id) const;
+ inline Data *property(v8::Handle<v8::String>) const;
Data *property(const QString &) const;
Data *property(int) const;
Data *method(int) const;
@@ -151,22 +168,25 @@ public:
inline bool isAllowedInRevision(Data *) const;
inline QDeclarativeEngine *qmlEngine() const;
- static Data *property(QDeclarativeEngine *, QObject *, const QScriptDeclarativeClass::Identifier &, Data &);
static Data *property(QDeclarativeEngine *, QObject *, const QString &, Data &);
+ static Data *property(QDeclarativeEngine *, QObject *, v8::Handle<v8::String>, Data &);
protected:
virtual void clear();
private:
friend class QDeclarativeEnginePrivate;
+ friend class QV8QObjectWrapper;
+ // Implemented in v8/qv8qobjectwrapper.cpp
+ v8::Local<v8::Object> newQObject(QObject *, QV8Engine *);
+
+ // XXX is this worth it anymore?
struct RData : public Data, public QDeclarativeRefCount {
- QScriptDeclarativeClass::PersistentIdentifier identifier;
};
typedef QVector<RData *> IndexCache;
- typedef QHash<QString, RData *> StringCache;
- typedef QHash<QScriptDeclarativeClass::Identifier, RData *> IdentifierCache;
+ typedef QStringHash<RData *> StringCache;
typedef QVector<int> AllowedRevisionCache;
void updateRecur(QDeclarativeEngine *, const QMetaObject *);
@@ -175,8 +195,8 @@ private:
IndexCache indexCache;
IndexCache methodIndexCache;
StringCache stringCache;
- IdentifierCache identifierCache;
AllowedRevisionCache allowedRevisionCache;
+ v8::Persistent<v8::Function> constructor;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativePropertyCache::Data::Flags);
@@ -207,12 +227,6 @@ QDeclarativePropertyCache::overrideData(Data *data) const
return methodIndexCache.at(data->overrideIndex);
}
-QDeclarativePropertyCache::Data *
-QDeclarativePropertyCache::property(const QScriptDeclarativeClass::Identifier &id) const
-{
- return identifierCache.value(id);
-}
-
QDeclarativePropertyCache::ValueTypeData::ValueTypeData()
: flags(QDeclarativePropertyCache::Data::NoFlags), valueTypeCoreIdx(-1), valueTypePropType(0)
{
@@ -236,6 +250,12 @@ QDeclarativeEngine *QDeclarativePropertyCache::qmlEngine() const
return engine;
}
+QDeclarativePropertyCache::Data *QDeclarativePropertyCache::property(v8::Handle<v8::String> str) const
+{
+ QDeclarativePropertyCache::RData **rv = stringCache.value(str);
+ return rv?*rv:0;
+}
+
QT_END_NAMESPACE
#endif // QDECLARATIVEPROPERTYCACHE_P_H
diff --git a/src/declarative/qml/qdeclarativescarceresourcescriptclass.cpp b/src/declarative/qml/qdeclarativescarceresourcescriptclass.cpp
deleted file mode 100644
index d94e2d9332..0000000000
--- a/src/declarative/qml/qdeclarativescarceresourcescriptclass.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-/****************************************************************************
-**
-** 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$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qdeclarativescarceresourcescriptclass_p.h"
-
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativecontext_p.h"
-#include "private/qdeclarativedata_p.h"
-#include "private/qdeclarativetypenamescriptclass_p.h"
-#include "private/qdeclarativelistscriptclass_p.h"
-#include "private/qdeclarativebinding_p.h"
-#include "private/qdeclarativeguard_p.h"
-#include "private/qdeclarativevmemetaobject_p.h"
-
-#include <QtCore/qtimer.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtScript/qscriptcontextinfo.h>
-
-Q_DECLARE_METATYPE(QScriptValue);
-
-QT_BEGIN_NAMESPACE
-
-QDeclarativeScarceResourceScriptClass::QDeclarativeScarceResourceScriptClass(QDeclarativeEngine *bindEngine)
- : QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- // Properties of this type can be explicitly preserved by clients,
- // which prevents the scarce resource from being automatically
- // released after the binding has been evaluated.
- m_preserve = scriptEngine->newFunction(preserve);
- m_preserveId = createPersistentIdentifier(QLatin1String("preserve"));
-
- // Similarly, they can be explicitly destroyed by clients,
- // which releases the scarce resource.
- m_destroy = scriptEngine->newFunction(destroy);
- m_destroyId = createPersistentIdentifier(QLatin1String("destroy"));
-}
-
-QDeclarativeScarceResourceScriptClass::~QDeclarativeScarceResourceScriptClass()
-{
-}
-
-/*
- Returns a JavaScript object whose instance data is a new scarce resource data.
- The scarce resource is added to the doubly-linked-list of scarce resources in the engine
- so that the scarce resource can be released after evaluation completes.
- */
-QScriptValue QDeclarativeScarceResourceScriptClass::newScarceResource(const QVariant &v)
-{
- // create the scarce resource
- ScarceResourceData *srd = new ScarceResourceData(v);
-
- // insert into the linked list
- QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine);
- srd->insertInto(&enginePrivate->scarceResources);
- Q_ASSERT(enginePrivate->scarceResourcesRefCount > 0);
-
- // return the javascript object with the scarce resource instance data
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- return QScriptDeclarativeClass::newObject(scriptEngine, this, srd); // JSC takes ownership of srd.
-}
-
-QVariant QDeclarativeScarceResourceScriptClass::toVariant(Object *object, bool *ok)
-{
- ScarceResourceData *obj = static_cast<ScarceResourceData*>(object);
- if (ok) *ok = true;
- return obj->resource;
-}
-
-QVariant QDeclarativeScarceResourceScriptClass::toVariant(const QScriptValue &value)
-{
- Q_ASSERT(scriptClass(value) == this);
-
- return toVariant(object(value), 0);
-}
-
-// The destroy() and preserve() function properties are readable.
-QScriptClass::QueryFlags
-QDeclarativeScarceResourceScriptClass::queryProperty(Object *object, const Identifier &name,
- QScriptClass::QueryFlags flags)
-{
- Q_UNUSED(object)
- Q_UNUSED(flags)
-
- if (name == m_destroyId.identifier || name == m_preserveId.identifier)
- return (QScriptClass::HandlesReadAccess);
- return 0;
-}
-
-// Return the (function) values which may be evaluated by clients.
-QDeclarativeScarceResourceScriptClass::Value
-QDeclarativeScarceResourceScriptClass::property(Object *object, const Identifier &name)
-{
- Q_UNUSED(object)
-
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- // functions
- if (name == m_preserveId.identifier)
- return Value(scriptEngine, m_preserve);
- else if (name == m_destroyId.identifier)
- return Value(scriptEngine, m_destroy);
-
- return Value();
-}
-
-/*
- This method is called when the user explicitly calls the "preserve" method of a scarce resource in JavaScript
- within the specified evaluation context \a context of the script engine \a engine.
- Calling this function signifies that the user explicitly wants to preserve the resource rather than let it
- be automatically released once evaluation of the expression is complete.
- This function removes the internal scarce resource from the declarative engine's linked list of scarce resources
- to release after evaluation of the expression completes. This means that the resource will only be truly
- released when the JavaScript engine's garbage collector is run.
-
- Example:
- \qml
- function getIcon(model) {
- var icon = model.avatar; // a pixmap property
- icon.preserve(); // explicitly preserves the resource
- return icon; // a valid variant will be returned
- }
- \endqml
- */
-QScriptValue QDeclarativeScarceResourceScriptClass::preserve(QScriptContext *context, QScriptEngine *engine)
-{
- QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
- QScriptValue that = context->thisObject();
-
- if (scriptClass(that) != p->scarceResourceClass)
- return engine->undefinedValue();
-
- // The client wishes to preserve the resource in this SRD.
- ScarceResourceData *data = static_cast<ScarceResourceData *>(p->scarceResourceClass->object(that));
- if (!data)
- return engine->undefinedValue();
-
- // remove node from list, without releasing the resource.
- data->removeNode();
-
- return engine->undefinedValue();
-}
-
-/*
- This method is called when the user explicitly calls the "destroy" method of a scarce resource in JavaScript
- within the specified evaluation context \a context of the script engine \a engine.
- Calling this function signifies that the user explicitly wants to release the resource.
- This function sets the internal scarce resource variant to the invalid variant, in order to release the original resource,
- and then removes the resource from the declarative engine's linked-list of scarce resources to
- to release after evaluation of the expression completes, as it has already been released.
-
- Example:
- \qml
- function getIcon(model) {
- var icon = model.avatar; // a pixmap property
- icon.destroy(); // explicitly releases the resource
- return icon; // an invalid variant will be returned
- }
- \endqml
- */
-QScriptValue QDeclarativeScarceResourceScriptClass::destroy(QScriptContext *context, QScriptEngine *engine)
-{
- QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
- QScriptValue that = context->thisObject();
-
- if (scriptClass(that) != p->scarceResourceClass)
- return engine->undefinedValue();
-
- // the client wishes to release the resource in this SRD.
- ScarceResourceData *data = static_cast<ScarceResourceData *>(p->scarceResourceClass->object(that));
- if (!data)
- return engine->undefinedValue();
-
- // release the resource and remove the node from the list.
- data->releaseResource();
-
- return engine->undefinedValue();
-}
-
-QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativescarceresourcescriptclass_p.h b/src/declarative/qml/qdeclarativescarceresourcescriptclass_p.h
deleted file mode 100644
index 2a1390a230..0000000000
--- a/src/declarative/qml/qdeclarativescarceresourcescriptclass_p.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/****************************************************************************
-**
-** 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$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QDECLARATIVESCARCERESOURCESCRIPTCLASS_P_H
-#define QDECLARATIVESCARCERESOURCESCRIPTCLASS_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 "private/qdeclarativepropertycache_p.h"
-#include "private/qdeclarativetypenamecache_p.h"
-
-#include <private/qscriptdeclarativeclass_p.h>
-#include <QtScript/qscriptengine.h>
-
-QT_BEGIN_NAMESPACE
-
-class QDeclarativeEngine;
-
-/*
- Scarce resources (like pixmaps and textures) are managed manually
- in that the variant will be set to the invalid variant once the
- JavaScript engine has finished using the JavaScript object whose
- instance data is the ScarceResourceData (but before the garbage
- collector frees the JavaScript object itself).
-
- The engine stores a doubly-linked-list of scarce resources which
- will to be cleaned up after a binding is successfully evaluated
- (unless the user explicitly preserves the scarce resource).
-
- A ScarceResourceData pointer should not be deleted manually, as
- all instances of a ScarceResourceData should be owned by the
- JavaScript engine.
- */
-struct ScarceResourceData : public QScriptDeclarativeClass::Object {
- ScarceResourceData(const QVariant &v) : resource(v), prev(0), next(0)
- {
- }
-
- virtual ~ScarceResourceData()
- {
- releaseResource();
- }
-
- // Insert this resource into the given list of resources.
- void insertInto(ScarceResourceData **list)
- {
- // This node becomes the head of the list.
- next = *list; // so our next = old list head
- *list = this; // list now points to us (we're the head)
- prev = list; // as we're the head, our prev ptr becomes the list ptr.
-
- // and the next node's prev pointer must contain a ptr to our next ptr,
- // since per definition, prev always contains a pointer to the previous node's "next" ptr,
- // and the "this" node is the "this->next" node's "prev" node.
- if (next) next->prev = &next;
- }
-
- // Remove this resource from the list of resources, without releasing the resource.
- void removeNode()
- {
- // whatever previously pointed to this node (ie, as that node's "next" node)
- // should now point to our next node (since we no longer exist in the list).
- // and the next node's prev ptr should point to our prev node.
- if (prev) *prev = next;
- if (next) next->prev = prev;
- prev = 0;
- next = 0;
- }
-
- // Release this resource, and remove from the list.
- void releaseResource()
- {
- resource = QVariant();
- removeNode();
- }
-
- QVariant resource;
-
- // prev always contains a pointer to the previous node's "next" ptr.
- // :. for the head node, [*prev] will be engine->scarceResources
- // :. for every other node, [*prev] will be the previous node's "next" ptr.
- ScarceResourceData **prev;
- ScarceResourceData *next;
-};
-
-class Q_AUTOTEST_EXPORT QDeclarativeScarceResourceScriptClass : public QScriptDeclarativeClass
-{
-public:
- QDeclarativeScarceResourceScriptClass(QDeclarativeEngine *);
- ~QDeclarativeScarceResourceScriptClass();
-
- // Creates a new JavaScript object whose instance data is the scarce resource v
- QScriptValue newScarceResource(const QVariant &v);
-
- // inherited from QScriptDeclarativeClass
- virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
- QScriptClass::QueryFlags flags);
- virtual Value property(Object *, const Identifier &);
- virtual QVariant toVariant(Object *, bool *ok = 0);
- QVariant toVariant(const QScriptValue &value);
-
-private:
- PersistentIdentifier m_preserveId;
- PersistentIdentifier m_destroyId;
- QScriptValue m_preserve;
- QScriptValue m_destroy;
-
- static QScriptValue preserve(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue destroy(QScriptContext *context, QScriptEngine *engine);
-
- QDeclarativeEngine *engine;
-};
-
-QT_END_NAMESPACE
-
-#endif // QDECLARATIVESCARCERESOURCESCRIPTCLASS_P_H
diff --git a/src/declarative/qml/qdeclarativesqldatabase.cpp b/src/declarative/qml/qdeclarativesqldatabase.cpp
index 588b6bf306..df072ed02d 100644
--- a/src/declarative/qml/qdeclarativesqldatabase.cpp
+++ b/src/declarative/qml/qdeclarativesqldatabase.cpp
@@ -47,101 +47,21 @@
#include "private/qdeclarativeengine_p.h"
#include <QtCore/qobject.h>
-#include <QtScript/qscriptvalue.h>
-#include <QtScript/qscriptvalueiterator.h>
-#include <QtScript/qscriptcontext.h>
-#include <QtScript/qscriptengine.h>
-#include <QtScript/qscriptclasspropertyiterator.h>
#include <QtSql/qsqldatabase.h>
#include <QtSql/qsqlquery.h>
#include <QtSql/qsqlerror.h>
#include <QtSql/qsqlrecord.h>
+#include <QtGui/qdesktopservices.h>
#include <QtCore/qstack.h>
#include <QtCore/qcryptographichash.h>
#include <QtCore/qsettings.h>
#include <QtCore/qdir.h>
#include <QtCore/qdebug.h>
-Q_DECLARE_METATYPE(QSqlDatabase)
-Q_DECLARE_METATYPE(QSqlQuery)
+#include <private/qv8engine_p.h>
QT_BEGIN_NAMESPACE
-class QDeclarativeSqlQueryScriptClass: public QScriptClass {
-public:
- QDeclarativeSqlQueryScriptClass(QScriptEngine *engine) : QScriptClass(engine)
- {
- str_length = engine->toStringHandle(QLatin1String("length"));
- str_forwardOnly = engine->toStringHandle(QLatin1String("forwardOnly")); // not in HTML5 (an optimization)
- }
-
- QueryFlags queryProperty(const QScriptValue &,
- const QScriptString &name,
- QueryFlags flags, uint *)
- {
- if (flags & HandlesReadAccess) {
- if (name == str_length) {
- return HandlesReadAccess;
- } else if (name == str_forwardOnly) {
- return flags;
- }
- }
- if (flags & HandlesWriteAccess)
- if (name == str_forwardOnly)
- return flags;
- return 0;
- }
-
- QScriptValue property(const QScriptValue &object,
- const QScriptString &name, uint)
- {
- QSqlQuery query = qscriptvalue_cast<QSqlQuery>(object.data());
- if (name == str_length) {
- int s = query.size();
- if (s<0) {
- // Inefficient.
- if (query.last()) {
- return query.at()+1;
- } else {
- return 0;
- }
- } else {
- return s;
- }
- } else if (name == str_forwardOnly) {
- return query.isForwardOnly();
- }
- return engine()->undefinedValue();
- }
-
- void setProperty(QScriptValue &object,
- const QScriptString &name, uint, const QScriptValue & value)
- {
- if (name == str_forwardOnly) {
- QSqlQuery query = qscriptvalue_cast<QSqlQuery>(object.data());
- query.setForwardOnly(value.toBool());
- }
- }
-
- QScriptValue::PropertyFlags propertyFlags(const QScriptValue &/*object*/, const QScriptString &name, uint /*id*/)
- {
- if (name == str_length) {
- return QScriptValue::Undeletable
- | QScriptValue::SkipInEnumeration;
- }
- return QScriptValue::Undeletable;
- }
-
-private:
- QScriptString str_length;
- QScriptString str_forwardOnly;
-};
-
-// If the spec changes to allow iteration, check git history...
-// class QDeclarativeSqlQueryScriptClassPropertyIterator : public QScriptClassPropertyIterator
-
-
-
enum SqlException {
UNKNOWN_ERR,
DATABASE_ERR,
@@ -165,90 +85,227 @@ static const char* sqlerror[] = {
0
};
-#define THROW_SQL(error, desc) \
+#define THROW_SQL(error, desc)
+
+#define V8THROW_SQL(error, desc) \
{ \
- QScriptValue errorValue = context->throwError(desc); \
- errorValue.setProperty(QLatin1String("code"), error); \
- return errorValue; \
+ v8::Local<v8::Value> v = v8::Exception::Error(engine->toString(desc)); \
+ v->ToObject()->Set(v8::String::New("code"), v8::Integer::New(error)); \
+ v8::ThrowException(v); \
+ return v8::Handle<v8::Value>(); \
+}
+
+#define V8THROW_REFERENCE(string) { \
+ v8::ThrowException(v8::Exception::ReferenceError(v8::String::New(string))); \
+ return v8::Handle<v8::Value>(); \
+}
+
+#define V8THROW_REFERENCE_VOID(string) { \
+ v8::ThrowException(v8::Exception::ReferenceError(v8::String::New(string))); \
+ return; \
}
-static QString qmlsqldatabase_databasesPath(QScriptEngine *engine)
+struct QDeclarativeSqlDatabaseData {
+ QDeclarativeSqlDatabaseData(QV8Engine *engine);
+ ~QDeclarativeSqlDatabaseData();
+
+ QString offlineStoragePath;
+ v8::Persistent<v8::Function> constructor;
+ v8::Persistent<v8::Function> queryConstructor;
+ v8::Persistent<v8::Function> rowsConstructor;
+
+ static inline QDeclarativeSqlDatabaseData *data(QV8Engine *e) {
+ return (QDeclarativeSqlDatabaseData *)e->sqlDatabaseData();
+ }
+ static inline QDeclarativeSqlDatabaseData *data(void *d) {
+ return (QDeclarativeSqlDatabaseData *)d;
+ }
+};
+
+class QV8SqlDatabaseResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(SQLDatabaseType)
+
+public:
+ enum Type { Database, Query, Rows };
+
+ QV8SqlDatabaseResource(QV8Engine *e)
+ : QV8ObjectResource(e), type(Database), inTransaction(false), readonly(false), forwardOnly(false) {}
+
+ Type type;
+ QSqlDatabase database;
+
+ QString version; // type == Database
+
+ bool inTransaction; // type == Query
+ bool readonly; // type == Query
+
+ QSqlQuery query; // type == Rows
+ bool forwardOnly; // type == Rows
+};
+
+static v8::Handle<v8::Value> qmlsqldatabase_version(v8::Local<v8::String> property, const v8::AccessorInfo& info)
{
- QDeclarativeScriptEngine *qmlengine = static_cast<QDeclarativeScriptEngine*>(engine);
- return qmlengine->offlineStoragePath
- + QDir::separator() + QLatin1String("Databases");
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Database)
+ V8THROW_REFERENCE("Not a SQLDatabase object");
+
+ return r->engine->toString(r->version);
}
-static void qmlsqldatabase_initDatabasesPath(QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlsqldatabase_rows_length(v8::Local<v8::String> property, const v8::AccessorInfo& info)
{
- QDir().mkpath(qmlsqldatabase_databasesPath(engine));
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Rows)
+ V8THROW_REFERENCE("Not a SQLDatabase::Rows object");
+
+ int s = r->query.size();
+ if (s < 0) {
+ // Inefficient
+ if (r->query.last()) {
+ s = r->query.at() + 1;
+ } else {
+ s = 0;
+ }
+ }
+ return v8::Integer::New(s);
}
-static QString qmlsqldatabase_databaseFile(const QString& connectionName, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlsqldatabase_rows_forwardOnly(v8::Local<v8::String> property,
+ const v8::AccessorInfo& info)
{
- return qmlsqldatabase_databasesPath(engine) + QDir::separator()
- + connectionName;
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Rows)
+ V8THROW_REFERENCE("Not a SQLDatabase::Rows object");
+
+ return v8::Boolean::New(r->query.isForwardOnly());
}
+static void qmlsqldatabase_rows_setForwardOnly(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo& info)
+{
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Rows)
+ V8THROW_REFERENCE_VOID("Not a SQLDatabase::Rows object");
+
+ r->query.setForwardOnly(value->BooleanValue());
+}
-static QScriptValue qmlsqldatabase_item(QScriptContext *context, QScriptEngine *engine)
+QDeclarativeSqlDatabaseData::~QDeclarativeSqlDatabaseData()
{
- QSqlQuery query = qscriptvalue_cast<QSqlQuery>(context->thisObject().data());
- int i = context->argument(0).toNumber();
- if (query.at() == i || query.seek(i)) { // Qt 4.6 doesn't optimize seek(at())
- QSqlRecord r = query.record();
- QScriptValue row = engine->newObject();
- for (int j=0; j<r.count(); ++j) {
- row.setProperty(r.fieldName(j), QScriptValue(engine,r.value(j).toString()));
+ qPersistentDispose(constructor);
+ qPersistentDispose(queryConstructor);
+}
+
+static QString qmlsqldatabase_databasesPath(QV8Engine *engine)
+{
+ return QDeclarativeSqlDatabaseData::data(engine)->offlineStoragePath +
+ QDir::separator() + QLatin1String("Databases");
+}
+
+static void qmlsqldatabase_initDatabasesPath(QV8Engine *engine)
+{
+ QDir().mkpath(qmlsqldatabase_databasesPath(engine));
+}
+
+static QString qmlsqldatabase_databaseFile(const QString& connectionName, QV8Engine *engine)
+{
+ return qmlsqldatabase_databasesPath(engine) + QDir::separator() + connectionName;
+}
+
+static v8::Handle<v8::Value> qmlsqldatabase_rows_index(QV8SqlDatabaseResource *r, uint32_t index)
+{
+ if (r->query.at() == index || r->query.seek(index)) {
+
+ QSqlRecord record = r->query.record();
+ // XXX optimize
+ v8::Local<v8::Object> row = v8::Object::New();
+ for (int ii = 0; ii < record.count(); ++ii) {
+ row->Set(r->engine->toString(record.fieldName(ii)),
+ r->engine->toString(record.value(ii).toString()));
}
return row;
+ } else {
+ return v8::Undefined();
}
- return engine->undefinedValue();
}
-static QScriptValue qmlsqldatabase_executeSql_outsidetransaction(QScriptContext *context, QScriptEngine * /*engine*/)
+static v8::Handle<v8::Value> qmlsqldatabase_rows_index(uint32_t index, const v8::AccessorInfo& info)
{
- THROW_SQL(DATABASE_ERR,QDeclarativeEngine::tr("executeSql called outside transaction()"));
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Rows)
+ V8THROW_REFERENCE("Not a SQLDatabase::Rows object");
+
+ return qmlsqldatabase_rows_index(r, index);
}
-static QScriptValue qmlsqldatabase_executeSql(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlsqldatabase_rows_item(const v8::Arguments& args)
{
- QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject());
- QString sql = context->argument(0).toString();
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Rows)
+ V8THROW_REFERENCE("Not a SQLDatabase::Rows object");
+
+ return qmlsqldatabase_rows_index(r, args.Length()?args[0]->Uint32Value():0);
+}
+
+static v8::Handle<v8::Value> qmlsqldatabase_executeSql(const v8::Arguments& args)
+{
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Query)
+ V8THROW_REFERENCE("Not a SQLDatabase::Query object");
+
+ QV8Engine *engine = r->engine;
+
+ if (!r->inTransaction)
+ V8THROW_SQL(DATABASE_ERR,QDeclarativeEngine::tr("executeSql called outside transaction()"));
+
+ QSqlDatabase db = r->database;
+
+ QString sql = engine->toString(args[0]);
+
+ if (r->readonly && !sql.startsWith(QLatin1String("SELECT"),Qt::CaseInsensitive)) {
+ V8THROW_SQL(SYNTAX_ERR, QDeclarativeEngine::tr("Read-only Transaction"));
+ }
+
QSqlQuery query(db);
bool err = false;
- QScriptValue result;
+ v8::Handle<v8::Value> result = v8::Undefined();
if (query.prepare(sql)) {
- if (context->argumentCount() > 1) {
- QScriptValue values = context->argument(1);
- if (values.isObject()) {
- if (values.isArray()) {
- int size = values.property(QLatin1String("length")).toInt32();
- for (int i = 0; i < size; ++i)
- query.bindValue(i, values.property(i).toVariant());
- } else {
- for (QScriptValueIterator it(values); it.hasNext();) {
- it.next();
- query.bindValue(it.name(),it.value().toVariant());
- }
- }
+ if (args.Length() > 1) {
+ v8::Local<v8::Value> values = args[1];
+ if (values->IsArray()) {
+ v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(values);
+ uint32_t size = array->Length();
+ for (uint32_t ii = 0; ii < size; ++ii)
+ query.bindValue(ii, engine->toVariant(array->Get(ii), -1));
+ } else if (values->IsObject() && !values->ToObject()->GetExternalResource()) {
+ v8::Local<v8::Object> object = values->ToObject();
+ v8::Local<v8::Array> names = object->GetPropertyNames();
+ uint32_t size = names->Length();
+ for (uint32_t ii = 0; ii < size; ++ii)
+ query.bindValue(engine->toString(names->Get(ii)),
+ engine->toVariant(object->Get(names->Get(ii)), -1));
} else {
- query.bindValue(0,values.toVariant());
+ query.bindValue(0, engine->toVariant(values, -1));
}
}
if (query.exec()) {
- result = engine->newObject();
- QDeclarativeScriptEngine *qmlengine = static_cast<QDeclarativeScriptEngine*>(engine);
- if (!qmlengine->sqlQueryClass)
- qmlengine->sqlQueryClass = new QDeclarativeSqlQueryScriptClass(engine);
- QScriptValue rows = engine->newObject(qmlengine->sqlQueryClass);
- rows.setData(engine->newVariant(QVariant::fromValue(query)));
- rows.setProperty(QLatin1String("item"), engine->newFunction(qmlsqldatabase_item,1), QScriptValue::SkipInEnumeration);
- result.setProperty(QLatin1String("rows"),rows);
- result.setProperty(QLatin1String("rowsAffected"),query.numRowsAffected());
- result.setProperty(QLatin1String("insertId"),query.lastInsertId().toString());
+ v8::Handle<v8::Object> rows = QDeclarativeSqlDatabaseData::data(engine)->rowsConstructor->NewInstance();
+ QV8SqlDatabaseResource *r = new QV8SqlDatabaseResource(engine);
+ r->type = QV8SqlDatabaseResource::Rows;
+ r->database = db;
+ r->query = query;
+ rows->SetExternalResource(r);
+
+ v8::Local<v8::Object> resultObject = v8::Object::New();
+ result = resultObject;
+ // XXX optimize
+ resultObject->Set(v8::String::New("rowsAffected"), v8::Integer::New(query.numRowsAffected()));
+ resultObject->Set(v8::String::New("insertId"), engine->toString(query.lastInsertId().toString()));
+ resultObject->Set(v8::String::New("rows"), rows);
} else {
err = true;
}
@@ -256,117 +313,138 @@ static QScriptValue qmlsqldatabase_executeSql(QScriptContext *context, QScriptEn
err = true;
}
if (err)
- THROW_SQL(DATABASE_ERR,query.lastError().text());
+ V8THROW_SQL(DATABASE_ERR,query.lastError().text());
+
return result;
}
-static QScriptValue qmlsqldatabase_executeSql_readonly(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlsqldatabase_changeVersion(const v8::Arguments& args)
{
- QString sql = context->argument(0).toString();
- if (sql.startsWith(QLatin1String("SELECT"),Qt::CaseInsensitive)) {
- return qmlsqldatabase_executeSql(context,engine);
- } else {
- THROW_SQL(SYNTAX_ERR,QDeclarativeEngine::tr("Read-only Transaction"))
- }
-}
+ if (args.Length() < 2)
+ return v8::Undefined();
-static QScriptValue qmlsqldatabase_change_version(QScriptContext *context, QScriptEngine *engine)
-{
- if (context->argumentCount() < 2)
- return engine->undefinedValue();
-
- QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject());
- QString from_version = context->argument(0).toString();
- QString to_version = context->argument(1).toString();
- QScriptValue callback = context->argument(2);
-
- QScriptValue instance = engine->newObject();
- instance.setProperty(QLatin1String("executeSql"), engine->newFunction(qmlsqldatabase_executeSql,1));
- QScriptValue tx = engine->newVariant(instance,QVariant::fromValue(db));
-
- QString foundvers = context->thisObject().property(QLatin1String("version")).toString();
- if (from_version!=foundvers) {
- THROW_SQL(VERSION_ERR,QDeclarativeEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(foundvers));
- return engine->undefinedValue();
- }
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Database)
+ V8THROW_REFERENCE("Not a SQLDatabase object");
+
+ QV8Engine *engine = r->engine;
+
+ QSqlDatabase db = r->database;
+ QString from_version = engine->toString(args[0]);
+ QString to_version = engine->toString(args[1]);
+ v8::Handle<v8::Value> callback = args[2];
+
+ if (from_version != r->version)
+ V8THROW_SQL(VERSION_ERR, QDeclarativeEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(r->version));
+
+ v8::Local<v8::Object> instance = QDeclarativeSqlDatabaseData::data(engine)->queryConstructor->NewInstance();
+ QV8SqlDatabaseResource *r2 = new QV8SqlDatabaseResource(engine);
+ r2->type = QV8SqlDatabaseResource::Query;
+ r2->database = db;
+ r2->version = r->version;
+ r2->inTransaction = true;
+ instance->SetExternalResource(r2);
bool ok = true;
- if (callback.isFunction()) {
+ if (callback->IsFunction()) {
ok = false;
db.transaction();
- callback.call(QScriptValue(), QScriptValueList() << tx);
- if (engine->hasUncaughtException()) {
+
+ v8::TryCatch tc;
+ v8::Handle<v8::Value> callbackArgs[] = { instance };
+ v8::Handle<v8::Function>::Cast(callback)->Call(engine->global(), 1, callbackArgs);
+
+ if (tc.HasCaught()) {
+ db.rollback();
+ tc.ReThrow();
+ return v8::Handle<v8::Value>();
+ } else if (!db.commit()) {
db.rollback();
+ V8THROW_SQL(UNKNOWN_ERR,QDeclarativeEngine::tr("SQL transaction failed"));
} else {
- if (!db.commit()) {
- db.rollback();
- THROW_SQL(UNKNOWN_ERR,QDeclarativeEngine::tr("SQL transaction failed"));
- } else {
- ok = true;
- }
+ ok = true;
}
}
+ r2->inTransaction = false;
+
if (ok) {
- context->thisObject().setProperty(QLatin1String("version"), to_version, QScriptValue::ReadOnly);
+ r2->version = to_version;
#ifndef QT_NO_SETTINGS
QSettings ini(qmlsqldatabase_databaseFile(db.connectionName(),engine) + QLatin1String(".ini"), QSettings::IniFormat);
ini.setValue(QLatin1String("Version"), to_version);
#endif
}
- return engine->undefinedValue();
+ return v8::Undefined();
}
-static QScriptValue qmlsqldatabase_transaction_shared(QScriptContext *context, QScriptEngine *engine, bool readOnly)
+static v8::Handle<v8::Value> qmlsqldatabase_transaction_shared(const v8::Arguments& args, bool readOnly)
{
- QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject());
- QScriptValue callback = context->argument(0);
- if (!callback.isFunction())
- THROW_SQL(UNKNOWN_ERR,QDeclarativeEngine::tr("transaction: missing callback"));
-
- QScriptValue instance = engine->newObject();
- instance.setProperty(QLatin1String("executeSql"),
- engine->newFunction(readOnly ? qmlsqldatabase_executeSql_readonly : qmlsqldatabase_executeSql,1));
- QScriptValue tx = engine->newVariant(instance,QVariant::fromValue(db));
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Database)
+ V8THROW_REFERENCE("Not a SQLDatabase object");
+
+ QV8Engine *engine = r->engine;
+
+ if (args.Length() == 0 || !args[0]->IsFunction())
+ V8THROW_SQL(UNKNOWN_ERR,QDeclarativeEngine::tr("transaction: missing callback"));
+
+ QSqlDatabase db = r->database;
+ v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(args[0]);
+
+ v8::Local<v8::Object> instance = QDeclarativeSqlDatabaseData::data(engine)->queryConstructor->NewInstance();
+ QV8SqlDatabaseResource *q = new QV8SqlDatabaseResource(engine);
+ q->type = QV8SqlDatabaseResource::Query;
+ q->database = db;
+ q->readonly = readOnly;
+ q->inTransaction = true;
+ instance->SetExternalResource(q);
db.transaction();
- callback.call(QScriptValue(), QScriptValueList() << tx);
- instance.setProperty(QLatin1String("executeSql"),
- engine->newFunction(qmlsqldatabase_executeSql_outsidetransaction));
- if (engine->hasUncaughtException()) {
+ v8::TryCatch tc;
+ v8::Handle<v8::Value> callbackArgs[] = { instance };
+ callback->Call(engine->global(), 1, callbackArgs);
+
+ q->inTransaction = false;
+
+ if (tc.HasCaught()) {
+ db.rollback();
+ tc.ReThrow();
+ return v8::Handle<v8::Value>();
+ } else if (!db.commit()) {
db.rollback();
- } else {
- if (!db.commit())
- db.rollback();
}
- return engine->undefinedValue();
+
+ return v8::Undefined();
}
-static QScriptValue qmlsqldatabase_transaction(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlsqldatabase_transaction(const v8::Arguments& args)
{
- return qmlsqldatabase_transaction_shared(context,engine,false);
+ return qmlsqldatabase_transaction_shared(args, false);
}
-static QScriptValue qmlsqldatabase_read_transaction(QScriptContext *context, QScriptEngine *engine)
+
+static v8::Handle<v8::Value> qmlsqldatabase_read_transaction(const v8::Arguments& args)
{
- return qmlsqldatabase_transaction_shared(context,engine,true);
+ return qmlsqldatabase_transaction_shared(args, true);
}
/*
Currently documented in doc/src/declarative/globalobject.qdoc
*/
-static QScriptValue qmlsqldatabase_open_sync(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlsqldatabase_open_sync(const v8::Arguments& args)
{
#ifndef QT_NO_SETTINGS
+ QV8Engine *engine = V8ENGINE();
qmlsqldatabase_initDatabasesPath(engine);
QSqlDatabase database;
- QString dbname = context->argument(0).toString();
- QString dbversion = context->argument(1).toString();
- QString dbdescription = context->argument(2).toString();
- int dbestimatedsize = context->argument(3).toNumber();
- QScriptValue dbcreationCallback = context->argument(4);
+ QString dbname = engine->toString(args[0]);
+ QString dbversion = engine->toString(args[1]);
+ QString dbdescription = engine->toString(args[2]);
+ int dbestimatedsize = args[3]->Int32Value();
+ v8::Handle<v8::Value> dbcreationCallback = args[4];
QCryptographicHash md5(QCryptographicHash::Md5);
md5.addData(dbname.toUtf8());
@@ -383,13 +461,13 @@ static QScriptValue qmlsqldatabase_open_sync(QScriptContext *context, QScriptEng
database = QSqlDatabase::database(dbid);
version = ini.value(QLatin1String("Version")).toString();
if (version != dbversion && !dbversion.isEmpty() && !version.isEmpty())
- THROW_SQL(VERSION_ERR,QDeclarativeEngine::tr("SQL: database version mismatch"));
+ V8THROW_SQL(VERSION_ERR, QDeclarativeEngine::tr("SQL: database version mismatch"));
} else {
created = !QFile::exists(basename+QLatin1String(".sqlite"));
database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), dbid);
if (created) {
ini.setValue(QLatin1String("Name"), dbname);
- if (dbcreationCallback.isFunction())
+ if (dbcreationCallback->IsFunction())
version = QString();
ini.setValue(QLatin1String("Version"), version);
ini.setValue(QLatin1String("Description"), dbdescription);
@@ -398,7 +476,7 @@ static QScriptValue qmlsqldatabase_open_sync(QScriptContext *context, QScriptEng
} else {
if (!dbversion.isEmpty() && ini.value(QLatin1String("Version")) != dbversion) {
// Incompatible
- THROW_SQL(VERSION_ERR,QDeclarativeEngine::tr("SQL: database version mismatch"));
+ V8THROW_SQL(VERSION_ERR,QDeclarativeEngine::tr("SQL: database version mismatch"));
}
version = ini.value(QLatin1String("Version")).toString();
}
@@ -408,35 +486,96 @@ static QScriptValue qmlsqldatabase_open_sync(QScriptContext *context, QScriptEng
database.open();
}
- QScriptValue instance = engine->newObject();
- instance.setProperty(QLatin1String("transaction"), engine->newFunction(qmlsqldatabase_transaction,1));
- instance.setProperty(QLatin1String("readTransaction"), engine->newFunction(qmlsqldatabase_read_transaction,1));
- instance.setProperty(QLatin1String("version"), version, QScriptValue::ReadOnly);
- instance.setProperty(QLatin1String("changeVersion"), engine->newFunction(qmlsqldatabase_change_version,3));
-
- QScriptValue result = engine->newVariant(instance,QVariant::fromValue(database));
-
- if (created && dbcreationCallback.isFunction()) {
- dbcreationCallback.call(QScriptValue(), QScriptValueList() << result);
+ v8::Local<v8::Object> instance = QDeclarativeSqlDatabaseData::data(engine)->constructor->NewInstance();
+ QV8SqlDatabaseResource *r = new QV8SqlDatabaseResource(engine);
+ r->database = database;
+ r->version = version;
+ instance->SetExternalResource(r);
+
+ if (created && dbcreationCallback->IsFunction()) {
+ v8::TryCatch tc;
+ v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(dbcreationCallback);
+ v8::Handle<v8::Value> args[] = { instance };
+ callback->Call(engine->global(), 1, args);
+ if (tc.HasCaught()) {
+ tc.ReThrow();
+ return v8::Handle<v8::Value>();
+ }
}
- return result;
+ return instance;
#else
- return engine->undefinedValue();
+ return v8::Undefined();
#endif // QT_NO_SETTINGS
}
-void qt_add_qmlsqldatabase(QScriptEngine *engine)
+QDeclarativeSqlDatabaseData::QDeclarativeSqlDatabaseData(QV8Engine *engine)
{
- QScriptValue openDatabase = engine->newFunction(qmlsqldatabase_open_sync, 4);
- engine->globalObject().setProperty(QLatin1String("openDatabaseSync"), openDatabase);
+ QString dataLocation = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
+ offlineStoragePath = dataLocation.replace(QLatin1Char('/'), QDir::separator()) +
+ QDir::separator() + QLatin1String("QML") +
+ QDir::separator() + QLatin1String("OfflineStorage");
- QScriptValue sqlExceptionPrototype = engine->newObject();
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->PrototypeTemplate()->Set(v8::String::New("transaction"),
+ V8FUNCTION(qmlsqldatabase_transaction, engine));
+ ft->PrototypeTemplate()->Set(v8::String::New("readTransaction"),
+ V8FUNCTION(qmlsqldatabase_read_transaction, engine));
+ ft->PrototypeTemplate()->SetAccessor(v8::String::New("version"), qmlsqldatabase_version);
+ ft->PrototypeTemplate()->Set(v8::String::New("changeVersion"),
+ V8FUNCTION(qmlsqldatabase_changeVersion, engine));
+ constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->PrototypeTemplate()->Set(v8::String::New("executeSql"),
+ V8FUNCTION(qmlsqldatabase_executeSql, engine));
+ queryConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->PrototypeTemplate()->Set(v8::String::New("item"), V8FUNCTION(qmlsqldatabase_rows_item, engine));
+ ft->PrototypeTemplate()->SetAccessor(v8::String::New("length"), qmlsqldatabase_rows_length);
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("forwardOnly"), qmlsqldatabase_rows_forwardOnly,
+ qmlsqldatabase_rows_setForwardOnly);
+ ft->InstanceTemplate()->SetIndexedPropertyHandler(qmlsqldatabase_rows_index);
+ rowsConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+}
+
+void *qt_add_qmlsqldatabase(QV8Engine *engine)
+{
+ v8::Local<v8::Function> openDatabase = V8FUNCTION(qmlsqldatabase_open_sync, engine);
+ engine->global()->Set(v8::String::New("openDatabaseSync"), openDatabase);
+
+ v8::PropertyAttribute attributes = (v8::PropertyAttribute)(v8::ReadOnly | v8::DontEnum | v8::DontDelete);
+ v8::Local<v8::Object> sqlExceptionPrototype = v8::Object::New();
for (int i=0; sqlerror[i]; ++i)
- sqlExceptionPrototype.setProperty(QLatin1String(sqlerror[i]),
- i,QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ sqlExceptionPrototype->Set(v8::String::New(sqlerror[i]), v8::Integer::New(i), attributes);
+ engine->global()->Set(v8::String::New("SQLException"), sqlExceptionPrototype);
+
+ return (void *)new QDeclarativeSqlDatabaseData(engine);
+}
+
+void qt_rem_qmlsqldatabase(QV8Engine *engine, void *d)
+{
+ QDeclarativeSqlDatabaseData *data = (QDeclarativeSqlDatabaseData *)d;
+ delete data;
+}
- engine->globalObject().setProperty(QLatin1String("SQLException"), sqlExceptionPrototype);
+void qt_qmlsqldatabase_setOfflineStoragePath(QV8Engine *engine, const QString &path)
+{
+ QDeclarativeSqlDatabaseData::data(engine)->offlineStoragePath = path;
+}
+
+QString qt_qmlsqldatabase_getOfflineStoragePath(const QV8Engine *engine)
+{
+ return QDeclarativeSqlDatabaseData::data(const_cast<QV8Engine *>(engine))->offlineStoragePath;
}
/*
diff --git a/src/declarative/qml/qdeclarativesqldatabase_p.h b/src/declarative/qml/qdeclarativesqldatabase_p.h
index 04adcefcec..337f717b1e 100644
--- a/src/declarative/qml/qdeclarativesqldatabase_p.h
+++ b/src/declarative/qml/qdeclarativesqldatabase_p.h
@@ -58,8 +58,12 @@
QT_BEGIN_NAMESPACE
-class QScriptEngine;
-void qt_add_qmlsqldatabase(QScriptEngine *engine);
+class QV8Engine;
+
+void *qt_add_qmlsqldatabase(QV8Engine *engine);
+void qt_rem_qmlsqldatabase(QV8Engine *engine, void *);
+void qt_qmlsqldatabase_setOfflineStoragePath(QV8Engine *engine, const QString &);
+QString qt_qmlsqldatabase_getOfflineStoragePath(const QV8Engine *);
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativetypeloader.cpp b/src/declarative/qml/qdeclarativetypeloader.cpp
index a413305e28..a788b4b915 100644
--- a/src/declarative/qml/qdeclarativetypeloader.cpp
+++ b/src/declarative/qml/qdeclarativetypeloader.cpp
@@ -1100,6 +1100,9 @@ void QDeclarativeScriptData::clear()
for (int ii = 0; ii < scripts.count(); ++ii)
scripts.at(ii)->release();
scripts.clear();
+
+ qPersistentDispose(m_program);
+ qPersistentDispose(m_value);
}
QDeclarativeScriptBlob::QDeclarativeScriptBlob(const QUrl &url, QDeclarativeTypeLoader *loader)
@@ -1228,7 +1231,13 @@ void QDeclarativeScriptBlob::done()
m_imports.populateCache(m_scriptData->importCache, engine);
m_scriptData->pragmas = m_pragmas;
- m_scriptData->m_program = QScriptProgram(m_source, finalUrl().toString());
+
+ // XXX TODO: Handle errors that occur duing the script compile
+ 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);
+ m_scriptData->m_program = qPersistentNew<v8::Script>(program);
}
QDeclarativeQmldirData::QDeclarativeQmldirData(const QUrl &url)
diff --git a/src/declarative/qml/qdeclarativetypeloader_p.h b/src/declarative/qml/qdeclarativetypeloader_p.h
index 05873df4ca..20e16750cf 100644
--- a/src/declarative/qml/qdeclarativetypeloader_p.h
+++ b/src/declarative/qml/qdeclarativetypeloader_p.h
@@ -64,6 +64,8 @@
#include <private/qdeclarativedirparser_p.h>
#include <private/qdeclarativeimport_p.h>
+#include <private/qv8_p.h>
+
QT_BEGIN_NAMESPACE
class QDeclarativeScriptData;
@@ -307,8 +309,10 @@ private:
friend class QDeclarativeScriptBlob;
bool m_loaded;
- QScriptProgram m_program;
- QScriptValue m_value;
+ v8::Persistent<v8::Script> m_program;
+ v8::Persistent<v8::Object> m_value;
+// QScriptProgram m_program;
+// QScriptValue m_value;
};
class Q_AUTOTEST_EXPORT QDeclarativeScriptBlob : public QDeclarativeDataBlob
diff --git a/src/declarative/qml/qdeclarativetypenamecache.cpp b/src/declarative/qml/qdeclarativetypenamecache.cpp
index 8a1b4bff43..23183aa9fb 100644
--- a/src/declarative/qml/qdeclarativetypenamecache.cpp
+++ b/src/declarative/qml/qdeclarativetypenamecache.cpp
@@ -57,9 +57,7 @@ QDeclarativeTypeNameCache::~QDeclarativeTypeNameCache()
void QDeclarativeTypeNameCache::clear()
{
- qDeleteAll(stringCache);
stringCache.clear();
- identifierCache.clear();
m_moduleApi = 0;
engine = 0;
}
@@ -69,14 +67,9 @@ void QDeclarativeTypeNameCache::add(const QString &name, int importedScriptIndex
if (stringCache.contains(name))
return;
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-
- RData *data = new RData;
- // ### Use typename class
- data->identifier = ep->objectClass->createPersistentIdentifier(name);
- data->importedScriptIndex = importedScriptIndex;
+ Data data;
+ data.importedScriptIndex = importedScriptIndex;
stringCache.insert(name, data);
- identifierCache.insert(data->identifier.identifier, data);
}
void QDeclarativeTypeNameCache::add(const QString &name, QDeclarativeType *type)
@@ -84,14 +77,9 @@ void QDeclarativeTypeNameCache::add(const QString &name, QDeclarativeType *type)
if (stringCache.contains(name))
return;
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-
- RData *data = new RData;
- // ### Use typename class
- data->identifier = ep->objectClass->createPersistentIdentifier(name);
- data->type = type;
+ Data data;
+ data.type = type;
stringCache.insert(name, data);
- identifierCache.insert(data->identifier.identifier, data);
}
void QDeclarativeTypeNameCache::add(const QString &name, QDeclarativeTypeNameCache *typeNamespace)
@@ -101,13 +89,10 @@ void QDeclarativeTypeNameCache::add(const QString &name, QDeclarativeTypeNameCac
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- RData *data = new RData;
- // ### Use typename class
- data->identifier = ep->objectClass->createPersistentIdentifier(name);
- data->typeNamespace = typeNamespace;
- stringCache.insert(name, data);
- identifierCache.insert(data->identifier.identifier, data);
+ Data data;
typeNamespace->addref();
+ data.typeNamespace = typeNamespace;
+ stringCache.insert(name, data);
}
QDeclarativeTypeNameCache::Data *QDeclarativeTypeNameCache::data(const QString &id) const
diff --git a/src/declarative/qml/qdeclarativetypenamecache_p.h b/src/declarative/qml/qdeclarativetypenamecache_p.h
index 497633b993..97c69bae35 100644
--- a/src/declarative/qml/qdeclarativetypenamecache_p.h
+++ b/src/declarative/qml/qdeclarativetypenamecache_p.h
@@ -59,6 +59,8 @@
#include <private/qscriptdeclarativeclass_p.h>
+#include <private/qhashedstring_p.h>
+
QT_BEGIN_NAMESPACE
class QDeclarativeType;
@@ -71,7 +73,9 @@ public:
struct Data {
inline Data();
+ inline Data(const Data &);
inline ~Data();
+ inline Data &operator=(const Data &);
QDeclarativeType *type;
QDeclarativeTypeNameCache *typeNamespace;
int importedScriptIndex;
@@ -82,7 +86,7 @@ public:
void add(const QString &, QDeclarativeTypeNameCache *);
Data *data(const QString &) const;
- inline Data *data(const QScriptDeclarativeClass::Identifier &id) const;
+ inline Data *data(v8::Handle<v8::String>) const;
inline bool isEmpty() const;
inline QDeclarativeMetaType::ModuleApiInstance *moduleApi() const;
@@ -92,14 +96,10 @@ protected:
virtual void clear();
private:
- struct RData : public Data {
- QScriptDeclarativeClass::PersistentIdentifier identifier;
- };
- typedef QHash<QString, RData *> StringCache;
- typedef QHash<QScriptDeclarativeClass::Identifier, RData *> IdentifierCache;
+ typedef QStringHash<Data> StringCache;
StringCache stringCache;
- IdentifierCache identifierCache;
+
QDeclarativeEngine *engine;
QDeclarativeMetaType::ModuleApiInstance *m_moduleApi;
};
@@ -114,14 +114,25 @@ QDeclarativeTypeNameCache::Data::~Data()
if (typeNamespace) typeNamespace->release();
}
-QDeclarativeTypeNameCache::Data *QDeclarativeTypeNameCache::data(const QScriptDeclarativeClass::Identifier &id) const
+bool QDeclarativeTypeNameCache::isEmpty() const
{
- return identifierCache.value(id);
+ return stringCache.isEmpty();
}
-bool QDeclarativeTypeNameCache::isEmpty() const
+QDeclarativeTypeNameCache::Data::Data(const QDeclarativeTypeNameCache::Data &o)
+: type(o.type), typeNamespace(o.typeNamespace), importedScriptIndex(o.importedScriptIndex)
+{
+ if (typeNamespace) typeNamespace->addref();
+}
+
+QDeclarativeTypeNameCache::Data &QDeclarativeTypeNameCache::Data::operator=(const QDeclarativeTypeNameCache::Data &o)
{
- return identifierCache.isEmpty();
+ if (o.typeNamespace) o.typeNamespace->addref();
+ if (typeNamespace) typeNamespace->release();
+ type = o.type;
+ typeNamespace = o.typeNamespace;
+ importedScriptIndex = o.importedScriptIndex;
+ return *this;
}
QDeclarativeMetaType::ModuleApiInstance *QDeclarativeTypeNameCache::moduleApi() const
@@ -129,6 +140,11 @@ QDeclarativeMetaType::ModuleApiInstance *QDeclarativeTypeNameCache::moduleApi()
return m_moduleApi;
}
+QDeclarativeTypeNameCache::Data *QDeclarativeTypeNameCache::data(v8::Handle<v8::String> name) const
+{
+ return stringCache.value(name);
+}
+
QT_END_NAMESPACE
#endif // QDECLARATIVETYPENAMECACHE_P_H
diff --git a/src/declarative/qml/qdeclarativetypenamescriptclass.cpp b/src/declarative/qml/qdeclarativetypenamescriptclass.cpp
deleted file mode 100644
index 32fcdb4c08..0000000000
--- a/src/declarative/qml/qdeclarativetypenamescriptclass.cpp
+++ /dev/null
@@ -1,195 +0,0 @@
-/****************************************************************************
-**
-** 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$
-** 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.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qdeclarativetypenamescriptclass_p.h"
-
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativetypenamecache_p.h"
-
-QT_BEGIN_NAMESPACE
-
-struct TypeNameData : public QScriptDeclarativeClass::Object {
- TypeNameData(QObject *o, QDeclarativeType *t, QDeclarativeTypeNameScriptClass::TypeNameMode m) : object(o), type(t), typeNamespace(0), mode(m) {}
- TypeNameData(QObject *o, QDeclarativeTypeNameCache *n, QDeclarativeTypeNameScriptClass::TypeNameMode m) : object(o), type(0), typeNamespace(n), mode(m) {
- if (typeNamespace) typeNamespace->addref();
- }
- ~TypeNameData() {
- if (typeNamespace) typeNamespace->release();
- }
-
- QObject *object;
- QDeclarativeType *type;
- QDeclarativeTypeNameCache *typeNamespace;
- QDeclarativeTypeNameScriptClass::TypeNameMode mode;
-};
-
-QDeclarativeTypeNameScriptClass::QDeclarativeTypeNameScriptClass(QDeclarativeEngine *bindEngine)
-: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)),
- engine(bindEngine), object(0), type(0), api(0)
-{
-}
-
-QDeclarativeTypeNameScriptClass::~QDeclarativeTypeNameScriptClass()
-{
-}
-
-QScriptValue QDeclarativeTypeNameScriptClass::newObject(QObject *object, QDeclarativeType *type, TypeNameMode mode)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- return QScriptDeclarativeClass::newObject(scriptEngine, this, new TypeNameData(object, type, mode));
-}
-
-QScriptValue QDeclarativeTypeNameScriptClass::newObject(QObject *object, QDeclarativeTypeNameCache *ns, TypeNameMode mode)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- return QScriptDeclarativeClass::newObject(scriptEngine, this, new TypeNameData(object, ns, mode));
-}
-
-QScriptClass::QueryFlags
-QDeclarativeTypeNameScriptClass::queryProperty(Object *obj, const Identifier &name,
- QScriptClass::QueryFlags flags)
-{
- Q_UNUSED(flags);
-
- TypeNameData *data = (TypeNameData *)obj;
-
- object = 0;
- type = 0;
- api = 0;
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-
- if (data->typeNamespace) {
- QDeclarativeTypeNameCache::Data *d = data->typeNamespace->data(name);
- if (d && d->type) {
- type = d->type;
- return QScriptClass::HandlesReadAccess;
- } else if (QDeclarativeMetaType::ModuleApiInstance *moduleApi = data->typeNamespace->moduleApi()) {
- if (moduleApi->scriptCallback) {
- moduleApi->scriptApi = moduleApi->scriptCallback(engine, &ep->scriptEngine);
- moduleApi->scriptCallback = 0;
- moduleApi->qobjectCallback = 0;
- } else if (moduleApi->qobjectCallback) {
- moduleApi->qobjectApi = moduleApi->qobjectCallback(engine, &ep->scriptEngine);
- moduleApi->scriptCallback = 0;
- moduleApi->qobjectCallback = 0;
- }
-
- api = moduleApi;
- if (api->qobjectApi) {
- return ep->objectClass->queryProperty(api->qobjectApi, name, flags, 0,
- QDeclarativeObjectScriptClass::SkipAttachedProperties);
- } else {
- return QScriptClass::HandlesReadAccess;
- }
-
- return 0;
-
- } else {
- return 0;
- }
-
- } else if (data->type) {
-
- if (startsWithUpper(name)) {
- QString strName = toString(name);
- // Must be an enum
- if (data->mode == IncludeEnums) {
- // ### Optimize
- QByteArray enumName = strName.toUtf8();
- const QMetaObject *metaObject = data->type->baseMetaObject();
- for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
- QMetaEnum e = metaObject->enumerator(ii);
- int value = e.keyToValue(enumName.constData());
- if (value != -1) {
- enumValue = value;
- return QScriptClass::HandlesReadAccess;
- }
- }
- }
- return 0;
- } else if (data->object) {
- // Must be an attached property
- object = qmlAttachedPropertiesObjectById(data->type->attachedPropertiesId(), data->object);
- if (!object) return 0;
- return ep->objectClass->queryProperty(object, name, flags, 0);
- }
-
- }
-
- return 0;
-}
-
-QDeclarativeTypeNameScriptClass::Value
-QDeclarativeTypeNameScriptClass::property(Object *obj, const Identifier &name)
-{
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- if (type) {
- return Value(scriptEngine, newObject(((TypeNameData *)obj)->object, type, ((TypeNameData *)obj)->mode));
- } else if (object) {
- return ep->objectClass->property(object, name);
- } else if (api && api->qobjectApi) {
- return ep->objectClass->property(api->qobjectApi, name);
- } else if (api) {
- return propertyValue(api->scriptApi, name);
- } else {
- return Value(scriptEngine, enumValue);
- }
-}
-
-void QDeclarativeTypeNameScriptClass::setProperty(Object *, const Identifier &n, const QScriptValue &v)
-{
- Q_ASSERT(!type);
-
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- if (api) {
- Q_ASSERT(api->qobjectApi);
- ep->objectClass->setProperty(api->qobjectApi, n, v, context());
- } else {
- Q_ASSERT(object);
- ep->objectClass->setProperty(object, n, v, context());
- }
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp b/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp
deleted file mode 100644
index c5e5a3006a..0000000000
--- a/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-/****************************************************************************
-**
-** 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$
-** 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.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qdeclarativevaluetypescriptclass_p.h"
-
-#include "private/qdeclarativebinding_p.h"
-#include "private/qdeclarativeproperty_p.h"
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativeguard_p.h"
-
-#include <QtScript/qscriptcontextinfo.h>
-
-QT_BEGIN_NAMESPACE
-
-struct QDeclarativeValueTypeObject : public QScriptDeclarativeClass::Object {
- enum Type { Reference, Copy };
- QDeclarativeValueTypeObject(Type t) : objectType(t) {}
- Type objectType;
- QDeclarativeValueType *type;
-};
-
-struct QDeclarativeValueTypeReference : public QDeclarativeValueTypeObject {
- QDeclarativeValueTypeReference() : QDeclarativeValueTypeObject(Reference) {}
- QDeclarativeGuard<QObject> object;
- int property;
-};
-
-struct QDeclarativeValueTypeCopy : public QDeclarativeValueTypeObject {
- QDeclarativeValueTypeCopy() : QDeclarativeValueTypeObject(Copy) {}
- QVariant value;
-};
-
-QDeclarativeValueTypeScriptClass::QDeclarativeValueTypeScriptClass(QDeclarativeEngine *bindEngine)
-: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine)
-{
-}
-
-QDeclarativeValueTypeScriptClass::~QDeclarativeValueTypeScriptClass()
-{
-}
-
-QScriptValue QDeclarativeValueTypeScriptClass::newObject(QObject *object, int coreIndex, QDeclarativeValueType *type)
-{
- QDeclarativeValueTypeReference *ref = new QDeclarativeValueTypeReference;
- ref->type = type;
- ref->object = object;
- ref->property = coreIndex;
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- return QScriptDeclarativeClass::newObject(scriptEngine, this, ref);
-}
-
-QScriptValue QDeclarativeValueTypeScriptClass::newObject(const QVariant &v, QDeclarativeValueType *type)
-{
- QDeclarativeValueTypeCopy *copy = new QDeclarativeValueTypeCopy;
- copy->type = type;
- copy->value = v;
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- return QScriptDeclarativeClass::newObject(scriptEngine, this, copy);
-}
-
-QScriptClass::QueryFlags
-QDeclarativeValueTypeScriptClass::queryProperty(Object *obj, const Identifier &name,
- QScriptClass::QueryFlags)
-{
- QDeclarativeValueTypeObject *o = static_cast<QDeclarativeValueTypeObject *>(obj);
-
- m_lastIndex = -1;
-
- QByteArray propName = toString(name).toUtf8();
-
- m_lastIndex = o->type->metaObject()->indexOfProperty(propName.constData());
- if (m_lastIndex == -1)
- return 0;
-
- QScriptClass::QueryFlags rv = 0;
-
- if (o->objectType == QDeclarativeValueTypeObject::Reference) {
- QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(o);
-
- if (!ref->object)
- return 0;
-
- QMetaProperty prop = ref->object->metaObject()->property(m_lastIndex);
-
- rv = QScriptClass::HandlesReadAccess;
- if (prop.isWritable())
- rv |= QScriptClass::HandlesWriteAccess;
- } else {
- rv = QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess;
- }
-
- return rv;
-}
-
-QDeclarativeValueTypeScriptClass::Value QDeclarativeValueTypeScriptClass::property(Object *obj, const Identifier &)
-{
- QDeclarativeValueTypeObject *o = static_cast<QDeclarativeValueTypeObject *>(obj);
-
- QVariant rv;
- if (o->objectType == QDeclarativeValueTypeObject::Reference) {
- QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(obj);
-
- QMetaProperty p = ref->type->metaObject()->property(m_lastIndex);
- ref->type->read(ref->object, ref->property);
- rv = p.read(ref->type);
- } else {
- QDeclarativeValueTypeCopy *copy = static_cast<QDeclarativeValueTypeCopy *>(obj);
-
- QMetaProperty p = copy->type->metaObject()->property(m_lastIndex);
- copy->type->setValue(copy->value);
- rv = p.read(copy->type);
- }
-
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- return Value(scriptEngine, static_cast<QDeclarativeEnginePrivate *>(QObjectPrivate::get(engine))->scriptValueFromVariant(rv));
-}
-
-void QDeclarativeValueTypeScriptClass::setProperty(Object *obj, const Identifier &,
- const QScriptValue &value)
-{
- QDeclarativeValueTypeObject *o = static_cast<QDeclarativeValueTypeObject *>(obj);
-
- QVariant v = QDeclarativeEnginePrivate::get(engine)->scriptValueToVariant(value);
-
- if (o->objectType == QDeclarativeValueTypeObject::Reference) {
- QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(obj);
-
- ref->type->read(ref->object, ref->property);
- QMetaProperty p = ref->type->metaObject()->property(m_lastIndex);
-
- QDeclarativeBinding *newBinding = 0;
- if (value.isFunction() && !value.isRegExp()) {
- QDeclarativeContextData *ctxt = QDeclarativeEnginePrivate::get(engine)->getContext(context());
-
- QDeclarativePropertyCache::Data cacheData;
- cacheData.flags = QDeclarativePropertyCache::Data::IsWritable;
- cacheData.propType = ref->object->metaObject()->property(ref->property).userType();
- cacheData.coreIndex = ref->property;
-
- QDeclarativePropertyCache::ValueTypeData valueTypeData;
- valueTypeData.valueTypeCoreIdx = m_lastIndex;
- valueTypeData.valueTypePropType = p.userType();
-
- newBinding = new QDeclarativeBinding(value, ref->object, ctxt);
- QScriptContextInfo ctxtInfo(context());
- newBinding->setSourceLocation(ctxtInfo.fileName(), ctxtInfo.functionStartLineNumber());
- QDeclarativeProperty prop = QDeclarativePropertyPrivate::restore(cacheData, valueTypeData, ref->object, ctxt);
- newBinding->setTarget(prop);
- if (newBinding->expression().contains(QLatin1String("this")))
- newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject);
- }
-
- QDeclarativeAbstractBinding *delBinding =
- QDeclarativePropertyPrivate::setBinding(ref->object, ref->property, m_lastIndex, newBinding);
- if (delBinding)
- delBinding->destroy();
-
- if (p.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double)
- v = v.toInt();
- p.write(ref->type, v);
- ref->type->write(ref->object, ref->property, 0);
-
- } else {
- QDeclarativeValueTypeCopy *copy = static_cast<QDeclarativeValueTypeCopy *>(obj);
- copy->type->setValue(copy->value);
- QMetaProperty p = copy->type->metaObject()->property(m_lastIndex);
- p.write(copy->type, v);
- copy->value = copy->type->value();
- }
-}
-
-QVariant QDeclarativeValueTypeScriptClass::toVariant(Object *obj, bool *ok)
-{
- QDeclarativeValueTypeObject *o = static_cast<QDeclarativeValueTypeObject *>(obj);
-
- if (o->objectType == QDeclarativeValueTypeObject::Reference) {
- QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(obj);
-
- if (ok) *ok = true;
-
- if (ref->object) {
- ref->type->read(ref->object, ref->property);
- return ref->type->value();
- }
- } else {
- QDeclarativeValueTypeCopy *copy = static_cast<QDeclarativeValueTypeCopy *>(obj);
-
- if (ok) *ok = true;
-
- return copy->value;
- }
-
- return QVariant();
-}
-
-QVariant QDeclarativeValueTypeScriptClass::toVariant(const QScriptValue &value)
-{
- Q_ASSERT(scriptClass(value) == this);
-
- return toVariant(object(value), 0);
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp
index a9b303c94f..9082ef06c1 100644
--- a/src/declarative/qml/qdeclarativevme.cpp
+++ b/src/declarative/qml/qdeclarativevme.cpp
@@ -59,7 +59,6 @@
#include "private/qdeclarativecontext_p.h"
#include "private/qdeclarativev4bindings_p.h"
#include "private/qdeclarativeglobal_p.h"
-#include "private/qdeclarativeglobalscriptclass_p.h"
#include "qdeclarativescriptstring.h"
#include "qdeclarativescriptstring_p.h"
@@ -965,68 +964,66 @@ QDeclarativeCompiledData::TypeReference::createInstance(QDeclarativeContextData
}
}
-QScriptValue QDeclarativeVME::run(QDeclarativeContextData *parentCtxt, QDeclarativeScriptData *script)
+v8::Persistent<v8::Object> QDeclarativeVME::run(QDeclarativeContextData *parentCtxt, QDeclarativeScriptData *script)
{
if (script->m_loaded)
- return script->m_value;
+ return qPersistentNew<v8::Object>(script->m_value);
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(parentCtxt->engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(parentCtxt->engine);
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(parentCtxt->engine);
+ QV8Engine *v8engine = &ep->v8engine;
bool shared = script->pragmas & QDeclarativeParser::Object::ScriptBlock::Shared;
// Create the script context if required
- QDeclarativeContextData *ctxt = 0;
- if (!shared) {
- ctxt = new QDeclarativeContextData;
- ctxt->isInternal = true;
- ctxt->url = script->url;
-
- // For backward compatibility, if there are no imports, we need to use the
- // imports from the parent context. See QTBUG-17518.
- if (!script->importCache->isEmpty()) {
- ctxt->imports = script->importCache;
- } else {
- ctxt->imports = parentCtxt->imports;
- }
-
- if (ctxt->imports) {
- ctxt->imports->addref();
- }
-
- ctxt->setParent(parentCtxt, true);
+ QDeclarativeContextData *ctxt = new QDeclarativeContextData;
+ ctxt->isInternal = true;
+ ctxt->isJSContext = true;
+ ctxt->url = script->url;
+
+ // For backward compatibility, if there are no imports, we need to use the
+ // imports from the parent context. See QTBUG-17518.
+ if (!script->importCache->isEmpty()) {
+ ctxt->imports = script->importCache;
+ } else {
+ ctxt->imports = parentCtxt->imports;
+ }
- for (int ii = 0; ii < script->scripts.count(); ++ii)
- ctxt->importedScripts << run(ctxt, script->scripts.at(ii)->scriptData());
+ if (ctxt->imports) {
+ ctxt->imports->addref();
}
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
- if (shared) {
- scriptContext->pushScope(enginePriv->contextClass->newUrlContext(script->url.toString())); // XXX toString()?
- } else {
- scriptContext->pushScope(enginePriv->contextClass->newUrlContext(ctxt, 0, script->url.toString()));
+ ctxt->setParent(parentCtxt, true);
+
+ for (int ii = 0; ii < script->scripts.count(); ++ii) {
+ ctxt->importedScripts << run(ctxt, script->scripts.at(ii)->scriptData());
}
- scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject());
- QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine);
- scriptContext->pushScope(scope);
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(v8engine->context());
- scriptEngine->evaluate(script->m_program);
+ v8::Local<v8::Object> qmlglobal = v8engine->qmlScope(ctxt, 0);
- if (scriptEngine->hasUncaughtException()) {
- QDeclarativeError error;
- QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
- enginePriv->warning(error);
- }
+ v8::TryCatch try_catch;
+ script->m_program->Run(qmlglobal);
- scriptEngine->popContext();
+ v8::Persistent<v8::Object> rv;
+
+ if (try_catch.HasCaught()) {
+ v8::Local<v8::Message> message = try_catch.Message();
+ if (!message.IsEmpty()) {
+ QDeclarativeError error;
+ QDeclarativeExpressionPrivate::exceptionToError(message, error);
+ ep->warning(error);
+ }
+ }
+ rv = qPersistentNew<v8::Object>(qmlglobal);
if (shared) {
+ script->m_value = qPersistentNew<v8::Object>(qmlglobal);
script->m_loaded = true;
- script->m_value = scope;
}
- return scope;
+ return rv;
}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativevme_p.h b/src/declarative/qml/qdeclarativevme_p.h
index b255e7fa55..dd23f1c62f 100644
--- a/src/declarative/qml/qdeclarativevme_p.h
+++ b/src/declarative/qml/qdeclarativevme_p.h
@@ -59,6 +59,8 @@
#include <QtCore/QString>
#include <QtCore/QStack>
+#include <private/qv8_p.h>
+
QT_BEGIN_NAMESPACE
class QObject;
@@ -103,7 +105,6 @@ public:
QObject *run(QDeclarativeContextData *, QDeclarativeCompiledData *,
int start = -1, const QBitField & = QBitField());
- QScriptValue run(QDeclarativeContextData *, QDeclarativeScriptData *);
void runDeferred(QObject *);
@@ -111,6 +112,8 @@ public:
QList<QDeclarativeError> errors() const;
private:
+ v8::Persistent<v8::Object> run(QDeclarativeContextData *, QDeclarativeScriptData *);
+
QObject *run(QDeclarativeVMEStack<QObject *> &,
QDeclarativeContextData *, QDeclarativeCompiledData *,
int start, const QBitField &);
diff --git a/src/declarative/qml/qdeclarativevmemetaobject.cpp b/src/declarative/qml/qdeclarativevmemetaobject.cpp
index 78519b2601..247c1aa533 100644
--- a/src/declarative/qml/qdeclarativevmemetaobject.cpp
+++ b/src/declarative/qml/qdeclarativevmemetaobject.cpp
@@ -383,7 +383,7 @@ QDeclarativeVMEMetaObject::QDeclarativeVMEMetaObject(QObject *obj,
const QDeclarativeVMEMetaData *meta,
QDeclarativeCompiledData *cdata)
: object(obj), compiledData(cdata), ctxt(QDeclarativeData::get(obj, true)->outerContext),
- metaData(meta), data(0), methods(0), parent(0)
+ metaData(meta), data(0), v8methods(0), parent(0)
{
compiledData->addref();
@@ -418,7 +418,10 @@ QDeclarativeVMEMetaObject::~QDeclarativeVMEMetaObject()
compiledData->release();
delete parent;
delete [] data;
- delete [] methods;
+
+ for (int ii = 0; v8methods && ii < metaData->methodCount; ++ii) {
+ qPersistentDispose(v8methods[ii]);
+ }
}
int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
@@ -649,27 +652,34 @@ int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine);
ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
- QScriptValue function = method(id);
-
- QScriptValueList args;
+ v8::Handle<v8::Function> function = method(id);
QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + id;
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(ep->v8engine.context());
+ v8::Handle<v8::Value> *args = 0;
+
if (data->parameterCount) {
- for (int ii = 0; ii < data->parameterCount; ++ii) {
- args << ep->scriptValueFromVariant(*(QVariant *)a[ii + 1]);
- }
+ 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]);
}
- QScriptValue rv = function.call(ep->objectClass->newQObject(object), args);
- if (ep->scriptEngine.hasUncaughtException()) {
+ v8::TryCatch try_catch;
+
+ v8::Local<v8::Value> result = function->Call(ep->v8engine.global(), data->parameterCount, args);
+
+ QVariant rv;
+ if (try_catch.HasCaught()) {
QDeclarativeError error;
- QDeclarativeExpressionPrivate::exceptionToError(&ep->scriptEngine, error);
- if (error.isValid()) {
+ QDeclarativeExpressionPrivate::exceptionToError(try_catch.Message(), error);
+ if (error.isValid())
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]) *reinterpret_cast<QVariant *>(a[0]) = ep->scriptValueToVariant(rv);
-
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
return -1;
}
@@ -683,12 +693,12 @@ int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
return object->qt_metacall(c, _id, a);
}
-QScriptValue QDeclarativeVMEMetaObject::method(int index)
+v8::Handle<v8::Function> QDeclarativeVMEMetaObject::method(int index)
{
- if (!methods)
- methods = new QScriptValue[metaData->methodCount];
+ if (!v8methods)
+ v8methods = new v8::Persistent<v8::Function>[metaData->methodCount];
- if (!methods[index].isValid()) {
+ if (v8methods[index].IsEmpty()) {
QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + index;
const QChar *body =
@@ -696,17 +706,17 @@ QScriptValue QDeclarativeVMEMetaObject::method(int index)
QString code = QString::fromRawData(body, data->bodyLength);
- // XXX Use QScriptProgram
// XXX We should evaluate all methods in a single big script block to
// improve the call time between dynamic methods defined on the same
// object
- methods[index] = QDeclarativeExpressionPrivate::evalInObjectScope(ctxt, object, code, ctxt->url.toString(),
- data->lineNumber, 0);
+ v8methods[index] = QDeclarativeExpressionPrivate::evalFunction(ctxt, object, code, ctxt->url.toString(),
+ data->lineNumber);
}
- return methods[index];
+ return v8methods[index];
}
+#if 0
QScriptValue QDeclarativeVMEMetaObject::readVarProperty(int id)
{
if (data[id].dataType() == qMetaTypeId<QScriptValue>())
@@ -716,22 +726,28 @@ QScriptValue QDeclarativeVMEMetaObject::readVarProperty(int id)
else
return QDeclarativeEnginePrivate::get(ctxt->engine)->scriptValueFromVariant(data[id].asQVariant());
}
+#endif
QVariant QDeclarativeVMEMetaObject::readVarPropertyAsVariant(int id)
{
+#if 0
if (data[id].dataType() == qMetaTypeId<QScriptValue>())
return QDeclarativeEnginePrivate::get(ctxt->engine)->scriptValueToVariant(data[id].asQScriptValue());
- else if (data[id].dataType() == QMetaType::QObjectStar)
+ else
+#endif
+ if (data[id].dataType() == QMetaType::QObjectStar)
return QVariant::fromValue(data[id].asQObject());
else
return data[id].asQVariant();
}
+#if 0
void QDeclarativeVMEMetaObject::writeVarProperty(int id, const QScriptValue &value)
{
data[id].setValue(value);
activate(object, methodOffset + id, 0);
}
+#endif
void QDeclarativeVMEMetaObject::writeVarProperty(int id, const QVariant &value)
{
@@ -803,7 +819,7 @@ int QDeclarativeVMEMetaObject::vmeMethodLineNumber(int index)
return data->lineNumber;
}
-QScriptValue QDeclarativeVMEMetaObject::vmeMethod(int index)
+v8::Handle<v8::Function> QDeclarativeVMEMetaObject::vmeMethod(int index)
{
if (index < methodOffset) {
Q_ASSERT(parent);
@@ -814,7 +830,8 @@ QScriptValue QDeclarativeVMEMetaObject::vmeMethod(int index)
return method(index - methodOffset - plainSignals);
}
-void QDeclarativeVMEMetaObject::setVmeMethod(int index, const QScriptValue &value)
+// Used by debugger
+void QDeclarativeVMEMetaObject::setVmeMethod(int index, v8::Persistent<v8::Function> value)
{
if (index < methodOffset) {
Q_ASSERT(parent);
@@ -823,11 +840,16 @@ void QDeclarativeVMEMetaObject::setVmeMethod(int index, const QScriptValue &valu
int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
- if (!methods)
- methods = new QScriptValue[metaData->methodCount];
- methods[index - methodOffset - plainSignals] = value;
+ if (!v8methods)
+ v8methods = new v8::Persistent<v8::Function>[metaData->methodCount];
+
+ int methodIndex = index - methodOffset - plainSignals;
+ if (!v8methods[methodIndex].IsEmpty())
+ qPersistentDispose(v8methods[methodIndex]);
+ v8methods[methodIndex] = value;
}
+#if 0
QScriptValue QDeclarativeVMEMetaObject::vmeProperty(int index)
{
if (index < propOffset) {
@@ -845,6 +867,7 @@ void QDeclarativeVMEMetaObject::setVMEProperty(int index, const QScriptValue &v)
}
return writeVarProperty(index - propOffset, v);
}
+#endif
bool QDeclarativeVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const
{
diff --git a/src/declarative/qml/qdeclarativevmemetaobject_p.h b/src/declarative/qml/qdeclarativevmemetaobject_p.h
index 373f1a81b3..991c79a4ef 100644
--- a/src/declarative/qml/qdeclarativevmemetaobject_p.h
+++ b/src/declarative/qml/qdeclarativevmemetaobject_p.h
@@ -69,6 +69,8 @@
#include "private/qdeclarativecompiler_p.h"
#include "private/qdeclarativecontext_p.h"
+#include <private/qv8_p.h>
+
QT_BEGIN_NAMESPACE
#define QML_ALIAS_FLAG_PTR 0x00000001
@@ -140,11 +142,13 @@ public:
bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const;
void registerInterceptor(int index, int valueIndex, QDeclarativePropertyValueInterceptor *interceptor);
- QScriptValue vmeMethod(int index);
+ v8::Handle<v8::Function> vmeMethod(int index);
int vmeMethodLineNumber(int index);
- void setVmeMethod(int index, const QScriptValue &);
+ void setVmeMethod(int index, v8::Persistent<v8::Function>);
+#if 0
QScriptValue vmeProperty(int index);
void setVMEProperty(int index, const QScriptValue &);
+#endif
void connectAliasSignal(int index);
@@ -167,12 +171,14 @@ private:
QBitArray aInterceptors;
QHash<int, QPair<int, QDeclarativePropertyValueInterceptor*> > interceptors;
- QScriptValue *methods;
- QScriptValue method(int);
+ v8::Persistent<v8::Function> *v8methods;
+ v8::Handle<v8::Function> method(int);
+#if 0
QScriptValue readVarProperty(int);
- QVariant readVarPropertyAsVariant(int);
void writeVarProperty(int, const QScriptValue &);
+#endif
+ QVariant readVarPropertyAsVariant(int);
void writeVarProperty(int, const QVariant &);
QAbstractDynamicMetaObject *parent;
diff --git a/src/declarative/qml/qdeclarativeworkerscript.cpp b/src/declarative/qml/qdeclarativeworkerscript.cpp
index f887084edb..b519573ccf 100644
--- a/src/declarative/qml/qdeclarativeworkerscript.cpp
+++ b/src/declarative/qml/qdeclarativeworkerscript.cpp
@@ -58,6 +58,8 @@
#include <QtDeclarative/qdeclarativeinfo.h>
#include "qdeclarativenetworkaccessmanagerfactory.h"
+#include <private/qv8engine_p.h>
+#include <private/qv8worker_p.h>
QT_BEGIN_NAMESPACE
@@ -66,15 +68,15 @@ class WorkerDataEvent : public QEvent
public:
enum Type { WorkerData = QEvent::User };
- WorkerDataEvent(int workerId, const QVariant &data);
+ WorkerDataEvent(int workerId, const QByteArray &data);
virtual ~WorkerDataEvent();
int workerId() const;
- QVariant data() const;
+ QByteArray data() const;
private:
int m_id;
- QVariant m_data;
+ QByteArray m_data;
};
class WorkerLoadEvent : public QEvent
@@ -128,27 +130,28 @@ public:
QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *eng);
- struct ScriptEngine : public QDeclarativeScriptEngine
+ class WorkerEngine : public QV8Engine
{
- ScriptEngine(QDeclarativeWorkerScriptEnginePrivate *parent) : QDeclarativeScriptEngine(0), p(parent), accessManager(0) {}
- ~ScriptEngine() { delete accessManager; }
+ public:
+ WorkerEngine(QDeclarativeWorkerScriptEnginePrivate *parent);
+ ~WorkerEngine();
+
+ void init();
+ virtual QNetworkAccessManager *networkAccessManager();
+
QDeclarativeWorkerScriptEnginePrivate *p;
- QNetworkAccessManager *accessManager;
- virtual QNetworkAccessManager *networkAccessManager() {
- if (!accessManager) {
- if (p->qmlengine && p->qmlengine->networkAccessManagerFactory()) {
- accessManager = p->qmlengine->networkAccessManagerFactory()->create(this);
- } else {
- accessManager = new QNetworkAccessManager(this);
- }
- }
- return accessManager;
- }
+ v8::Local<v8::Function> sendFunction(int id);
+ void callOnMessage(v8::Handle<v8::Object> object, v8::Handle<v8::Value> arg);
+ private:
+ v8::Persistent<v8::Function> onmessage;
+ v8::Persistent<v8::Function> createsend;
+ QNetworkAccessManager *accessManager;
};
- ScriptEngine *workerEngine;
- static QDeclarativeWorkerScriptEnginePrivate *get(QScriptEngine *e) {
- return static_cast<ScriptEngine *>(e)->p;
+
+ WorkerEngine *workerEngine;
+ static QDeclarativeWorkerScriptEnginePrivate *get(QV8Engine *e) {
+ return static_cast<WorkerEngine *>(e)->p;
}
QDeclarativeEngine *qmlengine;
@@ -158,26 +161,21 @@ public:
struct WorkerScript {
WorkerScript();
+ ~WorkerScript();
int id;
QUrl source;
bool initialized;
QDeclarativeWorkerScript *owner;
- QScriptValue object;
-
- QScriptValue callback;
+ v8::Persistent<v8::Object> object;
};
QHash<int, WorkerScript *> workers;
- QScriptValue getWorker(int);
+ v8::Handle<v8::Object> getWorker(WorkerScript *);
int m_nextId;
- static QVariant scriptValueToVariant(const QScriptValue &);
- static QScriptValue variantToScriptValue(const QVariant &, QScriptEngine *);
-
- static QScriptValue onMessage(QScriptContext *ctxt, QScriptEngine *engine);
- static QScriptValue sendMessage(QScriptContext *ctxt, QScriptEngine *engine);
+ static v8::Handle<v8::Value> sendMessage(const v8::Arguments &args);
signals:
void stopThread();
@@ -186,75 +184,133 @@ protected:
virtual bool event(QEvent *);
private:
- void processMessage(int, const QVariant &);
+ void processMessage(int, const QByteArray &);
void processLoad(int, const QUrl &);
- void reportScriptException(WorkerScript *);
+ void reportScriptException(WorkerScript *, const QDeclarativeError &error);
};
-QDeclarativeWorkerScriptEnginePrivate::QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *engine)
-: workerEngine(0), qmlengine(engine), m_nextId(0)
+QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QDeclarativeWorkerScriptEnginePrivate *parent)
+: p(parent), accessManager(0)
{
}
-QScriptValue QDeclarativeWorkerScriptEnginePrivate::onMessage(QScriptContext *ctxt, QScriptEngine *engine)
+QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::~WorkerEngine()
+{
+ qPersistentDispose(createsend);
+ qPersistentDispose(onmessage);
+ delete accessManager;
+}
+
+void QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::init()
{
- QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(engine);
+ QV8Engine::init(0);
- int id = ctxt->thisObject().data().toVariant().toInt();
+#define CALL_ONMESSAGE_SCRIPT \
+ "(function(object, message) { "\
+ "var isfunction = false; "\
+ "try { "\
+ "isfunction = object.WorkerScript.onMessage instanceof Function; "\
+ "} catch (e) {}" \
+ "if (isfunction) "\
+ "object.WorkerScript.onMessage(message); "\
+ "})"
- WorkerScript *script = p->workers.value(id);
- if (!script)
- return engine->undefinedValue();
+#define SEND_MESSAGE_CREATE_SCRIPT \
+ "(function(method, engine) { "\
+ "return (function(id) { "\
+ "return (function(message) { "\
+ "if (arguments.length) method(engine, id, message); "\
+ "}); "\
+ "}); "\
+ "})"
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(context());
+
+ {
+ v8::Local<v8::Script> onmessagescript = v8::Script::New(v8::String::New(CALL_ONMESSAGE_SCRIPT));
+ onmessage = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(onmessagescript->Run()));
+ }
+ {
+ v8::Local<v8::Script> createsendscript = v8::Script::New(v8::String::New(SEND_MESSAGE_CREATE_SCRIPT));
+ v8::Local<v8::Function> createsendconstructor = v8::Local<v8::Function>::Cast(createsendscript->Run());
+
+ v8::Handle<v8::Value> args[] = {
+ V8FUNCTION(QDeclarativeWorkerScriptEnginePrivate::sendMessage, this)
+ };
+ v8::Local<v8::Value> createsendvalue = createsendconstructor->Call(global(), 1, args);
+
+ createsend = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(createsendvalue));
+ }
+}
- if (ctxt->argumentCount() >= 1)
- script->callback = ctxt->argument(0);
+// Requires handle and context scope
+v8::Local<v8::Function> QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::sendFunction(int id)
+{
+ v8::Handle<v8::Value> args[] = { v8::Integer::New(id) };
+ return v8::Local<v8::Function>::Cast(createsend->Call(global(), 1, args));
+}
+
+// Requires handle and context scope
+void QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::callOnMessage(v8::Handle<v8::Object> object,
+ v8::Handle<v8::Value> arg)
+{
+ v8::Handle<v8::Value> args[] = { object, arg };
+ onmessage->Call(global(), 2, args);
+}
+
+QNetworkAccessManager *QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::networkAccessManager()
+{
+ if (!accessManager) {
+ if (p->qmlengine && p->qmlengine->networkAccessManagerFactory()) {
+ accessManager = p->qmlengine->networkAccessManagerFactory()->create(p);
+ } else {
+ accessManager = new QNetworkAccessManager(p);
+ }
+ }
+ return accessManager;
+}
- return script->callback;
+QDeclarativeWorkerScriptEnginePrivate::QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *engine)
+: workerEngine(0), qmlengine(engine), m_nextId(0)
+{
}
-QScriptValue QDeclarativeWorkerScriptEnginePrivate::sendMessage(QScriptContext *ctxt, QScriptEngine *engine)
+v8::Handle<v8::Value> QDeclarativeWorkerScriptEnginePrivate::sendMessage(const v8::Arguments &args)
{
- if (!ctxt->argumentCount())
- return engine->undefinedValue();
+ WorkerEngine *engine = (WorkerEngine*)V8ENGINE();
- QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(engine);
+ int id = args[1]->Int32Value();
- int id = ctxt->thisObject().data().toVariant().toInt();
+ QByteArray data = QV8Worker::serialize(args[2], engine);
- WorkerScript *script = p->workers.value(id);
+ QMutexLocker(&engine->p->m_lock);
+ WorkerScript *script = engine->p->workers.value(id);
if (!script)
- return engine->undefinedValue();
-
- QMutexLocker(&p->m_lock);
+ return v8::Undefined();
if (script->owner)
- QCoreApplication::postEvent(script->owner,
- new WorkerDataEvent(0, scriptValueToVariant(ctxt->argument(0))));
+ QCoreApplication::postEvent(script->owner, new WorkerDataEvent(0, data));
- return engine->undefinedValue();
+ return v8::Undefined();
}
-QScriptValue QDeclarativeWorkerScriptEnginePrivate::getWorker(int id)
+// Requires handle scope and context scope
+v8::Handle<v8::Object> QDeclarativeWorkerScriptEnginePrivate::getWorker(WorkerScript *script)
{
- QHash<int, WorkerScript *>::ConstIterator iter = workers.find(id);
-
- if (iter == workers.end())
- return workerEngine->nullValue();
-
- WorkerScript *script = *iter;
if (!script->initialized) {
-
script->initialized = true;
- script->object = workerEngine->newObject();
- QScriptValue api = workerEngine->newObject();
- api.setData(script->id);
+ script->object = qPersistentNew<v8::Object>(workerEngine->contextWrapper()->urlScope(script->source));
+
+ workerEngine->contextWrapper()->setReadOnly(script->object, false);
- api.setProperty(QLatin1String("onMessage"), workerEngine->newFunction(onMessage),
- QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
- api.setProperty(QLatin1String("sendMessage"), workerEngine->newFunction(sendMessage));
+ v8::Local<v8::Object> api = v8::Object::New();
+ api->Set(v8::String::New("sendMessage"), workerEngine->sendFunction(script->id));
- script->object.setProperty(QLatin1String("WorkerScript"), api);
+ script->object->Set(v8::String::New("WorkerScript"), api);
+
+ workerEngine->contextWrapper()->setReadOnly(script->object, true);
}
return script->object;
@@ -262,6 +318,7 @@ QScriptValue QDeclarativeWorkerScriptEnginePrivate::getWorker(int id)
bool QDeclarativeWorkerScriptEnginePrivate::event(QEvent *event)
{
+ // XXX must handle remove request
if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
processMessage(workerEvent->workerId(), workerEvent->data());
@@ -278,22 +335,24 @@ bool QDeclarativeWorkerScriptEnginePrivate::event(QEvent *event)
}
}
-void QDeclarativeWorkerScriptEnginePrivate::processMessage(int id, const QVariant &data)
+void QDeclarativeWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &data)
{
WorkerScript *script = workers.value(id);
if (!script)
return;
- if (script->callback.isFunction()) {
- QScriptValue args = workerEngine->newArray(1);
- args.setProperty(0, variantToScriptValue(data, workerEngine));
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(workerEngine->context());
- script->callback.call(script->object, args);
+ v8::Handle<v8::Value> value = QV8Worker::deserialize(data, workerEngine);
- if (workerEngine->hasUncaughtException()) {
- reportScriptException(script);
- workerEngine->clearExceptions();
- }
+ v8::TryCatch tc;
+ workerEngine->callOnMessage(script->object, value);
+
+ if (tc.HasCaught()) {
+ QDeclarativeError error;
+ QDeclarativeExpressionPrivate::exceptionToError(tc.Message(), error);
+ reportScriptException(script, error);
}
}
@@ -308,44 +367,41 @@ void QDeclarativeWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
if (f.open(QIODevice::ReadOnly)) {
QByteArray data = f.readAll();
QString sourceCode = QString::fromUtf8(data);
-
- QScriptValue activation = getWorker(id);
-
- QScriptContext *ctxt = QScriptDeclarativeClass::pushCleanContext(workerEngine);
- QScriptValue urlContext = workerEngine->newObject();
- urlContext.setData(QScriptValue(workerEngine, url.toString()));
- ctxt->pushScope(urlContext);
- ctxt->pushScope(activation);
- ctxt->setActivationObject(activation);
QDeclarativeScriptParser::extractPragmas(sourceCode);
- workerEngine->baseUrl = url;
- workerEngine->evaluate(sourceCode);
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(workerEngine->context());
WorkerScript *script = workers.value(id);
- if (script) {
- script->source = url;
- if (workerEngine->hasUncaughtException()) {
- reportScriptException(script);
- workerEngine->clearExceptions();
- }
+ if (!script)
+ return;
+ script->source = url;
+ v8::Handle<v8::Object> activation = getWorker(script);
+ if (activation.IsEmpty())
+ return;
+
+ // XXX ???
+ // workerEngine->baseUrl = url;
+
+ v8::TryCatch tc;
+ v8::Local<v8::Script> program = workerEngine->qmlModeCompile(sourceCode, url.toString());
+
+ if (!tc.HasCaught())
+ program->Run(activation);
+
+ if (tc.HasCaught()) {
+ QDeclarativeError error;
+ QDeclarativeExpressionPrivate::exceptionToError(tc.Message(), error);
+ reportScriptException(script, error);
}
-
- workerEngine->popContext();
} else {
qWarning().nospace() << "WorkerScript: Cannot find source file " << url.toString();
}
}
-void QDeclarativeWorkerScriptEnginePrivate::reportScriptException(WorkerScript *script)
+void QDeclarativeWorkerScriptEnginePrivate::reportScriptException(WorkerScript *script,
+ const QDeclarativeError &error)
{
- if (!script || !workerEngine->hasUncaughtException())
- return;
-
- QDeclarativeError error;
- QDeclarativeExpressionPrivate::exceptionToError(workerEngine, error);
- error.setUrl(script->source);
-
QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(workerEngine);
QMutexLocker(&p->m_lock);
@@ -353,109 +409,7 @@ void QDeclarativeWorkerScriptEnginePrivate::reportScriptException(WorkerScript *
QCoreApplication::postEvent(script->owner, new WorkerErrorEvent(error));
}
-QVariant QDeclarativeWorkerScriptEnginePrivate::scriptValueToVariant(const QScriptValue &value)
-{
- if (value.isBool()) {
- return QVariant(value.toBool());
- } else if (value.isString()) {
- return QVariant(value.toString());
- } else if (value.isNumber()) {
- return QVariant((qreal)value.toNumber());
- } else if (value.isDate()) {
- return QVariant(value.toDateTime());
-#ifndef QT_NO_REGEXP
- } else if (value.isRegExp()) {
- return QVariant(value.toRegExp());
-#endif
- } else if (value.isArray()) {
- QVariantList list;
-
- quint32 length = (quint32)value.property(QLatin1String("length")).toNumber();
-
- for (quint32 ii = 0; ii < length; ++ii) {
- QVariant v = scriptValueToVariant(value.property(ii));
- list << v;
- }
-
- return QVariant(list);
- } else if (value.isQObject()) {
- QDeclarativeListModel *lm = qobject_cast<QDeclarativeListModel *>(value.toQObject());
- if (lm) {
- QDeclarativeListModelWorkerAgent *agent = lm->agent();
- if (agent) {
- QDeclarativeListModelWorkerAgent::VariantRef v(agent);
- return QVariant::fromValue(v);
- } else {
- return QVariant();
- }
- } else {
- // No other QObject's are allowed to be sent
- return QVariant();
- }
- } else if (value.isObject()) {
- QVariantHash hash;
-
- QScriptValueIterator iter(value);
-
- while (iter.hasNext()) {
- iter.next();
- hash.insert(iter.name(), scriptValueToVariant(iter.value()));
- }
-
- return QVariant(hash);
- }
-
- return QVariant();
-
-}
-
-QScriptValue QDeclarativeWorkerScriptEnginePrivate::variantToScriptValue(const QVariant &value, QScriptEngine *engine)
-{
- if (value.userType() == QVariant::Bool) {
- return QScriptValue(value.toBool());
- } else if (value.userType() == QVariant::String) {
- return QScriptValue(value.toString());
- } else if (value.userType() == QMetaType::QReal) {
- return QScriptValue(value.toReal());
- } else if (value.userType() == QVariant::DateTime) {
- return engine->newDate(value.toDateTime());
-#ifndef QT_NO_REGEXP
- } else if (value.userType() == QVariant::RegExp) {
- return engine->newRegExp(value.toRegExp());
-#endif
- } else if (value.userType() == qMetaTypeId<QDeclarativeListModelWorkerAgent::VariantRef>()) {
- QDeclarativeListModelWorkerAgent::VariantRef vr = qvariant_cast<QDeclarativeListModelWorkerAgent::VariantRef>(value);
- if (vr.a->scriptEngine() == 0)
- vr.a->setScriptEngine(engine);
- else if (vr.a->scriptEngine() != engine)
- return engine->nullValue();
- QScriptValue o = engine->newQObject(vr.a);
- o.setData(engine->newVariant(value)); // Keeps the agent ref so that it is cleaned up on gc
- return o;
- } else if (value.userType() == QMetaType::QVariantList) {
- QVariantList list = qvariant_cast<QVariantList>(value);
- QScriptValue rv = engine->newArray(list.count());
-
- for (quint32 ii = 0; ii < quint32(list.count()); ++ii)
- rv.setProperty(ii, variantToScriptValue(list.at(ii), engine));
-
- return rv;
- } else if (value.userType() == QMetaType::QVariantHash) {
-
- QVariantHash hash = qvariant_cast<QVariantHash>(value);
-
- QScriptValue rv = engine->newObject();
-
- for (QVariantHash::ConstIterator iter = hash.begin(); iter != hash.end(); ++iter)
- rv.setProperty(iter.key(), variantToScriptValue(iter.value(), engine));
-
- return rv;
- } else {
- return engine->nullValue();
- }
-}
-
-WorkerDataEvent::WorkerDataEvent(int workerId, const QVariant &data)
+WorkerDataEvent::WorkerDataEvent(int workerId, const QByteArray &data)
: QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data)
{
}
@@ -469,7 +423,7 @@ int WorkerDataEvent::workerId() const
return m_id;
}
-QVariant WorkerDataEvent::data() const
+QByteArray WorkerDataEvent::data() const
{
return m_data;
}
@@ -523,8 +477,6 @@ QDeclarativeWorkerScriptEngine::QDeclarativeWorkerScriptEngine(QDeclarativeEngin
QDeclarativeWorkerScriptEngine::~QDeclarativeWorkerScriptEngine()
{
d->m_lock.lock();
- qDeleteAll(d->workers);
- d->workers.clear();
QCoreApplication::postEvent(d, new QEvent((QEvent::Type)QDeclarativeWorkerScriptEnginePrivate::WorkerDestroyEvent));
d->m_lock.unlock();
@@ -537,9 +489,16 @@ QDeclarativeWorkerScriptEnginePrivate::WorkerScript::WorkerScript()
{
}
+QDeclarativeWorkerScriptEnginePrivate::WorkerScript::~WorkerScript()
+{
+ qPersistentDispose(object);
+}
+
int QDeclarativeWorkerScriptEngine::registerWorkerScript(QDeclarativeWorkerScript *owner)
{
- QDeclarativeWorkerScriptEnginePrivate::WorkerScript *script = new QDeclarativeWorkerScriptEnginePrivate::WorkerScript;
+ typedef QDeclarativeWorkerScriptEnginePrivate::WorkerScript WorkerScript;
+ WorkerScript *script = new WorkerScript;
+
script->id = d->m_nextId++;
script->owner = owner;
@@ -560,7 +519,7 @@ void QDeclarativeWorkerScriptEngine::executeUrl(int id, const QUrl &url)
QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url));
}
-void QDeclarativeWorkerScriptEngine::sendMessage(int id, const QVariant &data)
+void QDeclarativeWorkerScriptEngine::sendMessage(int id, const QByteArray &data)
{
QCoreApplication::postEvent(d, new WorkerDataEvent(id, data));
}
@@ -569,7 +528,11 @@ void QDeclarativeWorkerScriptEngine::run()
{
d->m_lock.lock();
- d->workerEngine = new QDeclarativeWorkerScriptEnginePrivate::ScriptEngine(d);
+ v8::Isolate *isolate = v8::Isolate::New();
+ isolate->Enter();
+
+ d->workerEngine = new QDeclarativeWorkerScriptEnginePrivate::WorkerEngine(d);
+ d->workerEngine->init();
d->m_wait.wakeAll();
@@ -577,7 +540,13 @@ void QDeclarativeWorkerScriptEngine::run()
exec();
+ qDeleteAll(d->workers);
+ d->workers.clear();
+
delete d->workerEngine; d->workerEngine = 0;
+
+ isolate->Exit();
+ isolate->Dispose();
}
@@ -677,14 +646,18 @@ void QDeclarativeWorkerScript::setSource(const QUrl &source)
of ListModel objects, any modifications by the other thread to an object
passed in \c message will not be reflected in the original object.
*/
-void QDeclarativeWorkerScript::sendMessage(const QScriptValue &message)
+void QDeclarativeWorkerScript::sendMessage(QDeclarativeV8Function *args)
{
if (!engine()) {
qWarning("QDeclarativeWorkerScript: Attempt to send message before WorkerScript establishment");
return;
}
- m_engine->sendMessage(m_scriptId, QDeclarativeWorkerScriptEnginePrivate::scriptValueToVariant(message));
+ v8::Handle<v8::Value> argument = v8::Undefined();
+ if (args->Length() != 0)
+ argument = (*args)[0];
+
+ m_engine->sendMessage(m_scriptId, QV8Worker::serialize(argument, args->engine()));
}
void QDeclarativeWorkerScript::classBegin()
@@ -731,11 +704,12 @@ bool QDeclarativeWorkerScript::event(QEvent *event)
if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
QDeclarativeEngine *engine = qmlEngine(this);
if (engine) {
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
- QScriptValue value =
- QDeclarativeWorkerScriptEnginePrivate::variantToScriptValue(workerEvent->data(), scriptEngine);
- emit message(value);
+ 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);
+ emit message(QDeclarativeV8Handle::fromHandle(value));
}
return true;
} else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) {
diff --git a/src/declarative/qml/qdeclarativeworkerscript_p.h b/src/declarative/qml/qdeclarativeworkerscript_p.h
index af3a0188f9..85910b16e9 100644
--- a/src/declarative/qml/qdeclarativeworkerscript_p.h
+++ b/src/declarative/qml/qdeclarativeworkerscript_p.h
@@ -78,7 +78,7 @@ public:
int registerWorkerScript(QDeclarativeWorkerScript *);
void removeWorkerScript(int);
void executeUrl(int, const QUrl &);
- void sendMessage(int, const QVariant &);
+ void sendMessage(int, const QByteArray &);
protected:
virtual void run();
@@ -87,6 +87,8 @@ private:
QDeclarativeWorkerScriptEnginePrivate *d;
};
+class QDeclarativeV8Function;
+class QDeclarativeV8Handle;
class Q_AUTOTEST_EXPORT QDeclarativeWorkerScript : public QObject, public QDeclarativeParserStatus
{
Q_OBJECT
@@ -101,11 +103,11 @@ public:
void setSource(const QUrl &);
public slots:
- void sendMessage(const QScriptValue &);
+ void sendMessage(QDeclarativeV8Function*);
signals:
void sourceChanged();
- void message(const QScriptValue &messageObject);
+ void message(const QDeclarativeV8Handle &messageObject);
protected:
virtual void classBegin();
diff --git a/src/declarative/qml/qdeclarativexmlhttprequest.cpp b/src/declarative/qml/qdeclarativexmlhttprequest.cpp
index 83b7d170a4..64719d59d6 100644
--- a/src/declarative/qml/qdeclarativexmlhttprequest.cpp
+++ b/src/declarative/qml/qdeclarativexmlhttprequest.cpp
@@ -41,6 +41,8 @@
#include "private/qdeclarativexmlhttprequest_p.h"
+#include <private/qv8engine_p.h>
+
#include "qdeclarativeengine.h"
#include "private/qdeclarativeengine_p.h"
#include "private/qdeclarativerefcount_p.h"
@@ -82,17 +84,17 @@
#define VALIDATION_ERR 16
#define TYPE_MISMATCH_ERR 17
-#define THROW_DOM(error, desc) \
-{ \
- QScriptValue errorValue = context->throwError(QLatin1String(desc)); \
- errorValue.setProperty(QLatin1String("code"), error); \
- return errorValue; \
-}
+#define V8THROW_DOM(error, string) { \
+ v8::Local<v8::Value> v = v8::Exception::Error(v8::String::New(string)); \
+ v->ToObject()->Set(v8::String::New("code"), v8::Integer::New(error)); \
+ v8::ThrowException(v); \
+ return v8::Handle<v8::Value>(); \
+}
-#define THROW_SYNTAX(desc) \
- return context->throwError(QScriptContext::SyntaxError, QLatin1String(desc));
-#define THROW_REFERENCE(desc) \
- return context->throwError(QScriptContext::ReferenceError, QLatin1String(desc));
+#define V8THROW_REFERENCE(string) { \
+ v8::ThrowException(v8::Exception::ReferenceError(v8::String::New(string))); \
+ return v8::Handle<v8::Value>(); \
+}
#define D(arg) (arg)->release()
#define A(arg) (arg)->addref()
@@ -101,6 +103,59 @@ QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(xhrDump, QML_XHR_DUMP);
+struct QDeclarativeXMLHttpRequestData {
+ QDeclarativeXMLHttpRequestData();
+ ~QDeclarativeXMLHttpRequestData();
+
+ v8::Persistent<v8::Function> nodeFunction;
+
+ v8::Persistent<v8::Object> namedNodeMapPrototype;
+ v8::Persistent<v8::Object> nodeListPrototype;
+ v8::Persistent<v8::Object> nodePrototype;
+ v8::Persistent<v8::Object> elementPrototype;
+ v8::Persistent<v8::Object> attrPrototype;
+ v8::Persistent<v8::Object> characterDataPrototype;
+ v8::Persistent<v8::Object> textPrototype;
+ v8::Persistent<v8::Object> cdataPrototype;
+ v8::Persistent<v8::Object> documentPrototype;
+
+ v8::Local<v8::Object> newNode();
+};
+
+static inline QDeclarativeXMLHttpRequestData *xhrdata(QV8Engine *engine)
+{
+ return (QDeclarativeXMLHttpRequestData *)engine->xmlHttpRequestData();
+}
+
+QDeclarativeXMLHttpRequestData::QDeclarativeXMLHttpRequestData()
+{
+}
+
+QDeclarativeXMLHttpRequestData::~QDeclarativeXMLHttpRequestData()
+{
+ qPersistentDispose(nodeFunction);
+ qPersistentDispose(namedNodeMapPrototype);
+ qPersistentDispose(nodeListPrototype);
+ qPersistentDispose(nodePrototype);
+ qPersistentDispose(elementPrototype);
+ qPersistentDispose(attrPrototype);
+ qPersistentDispose(characterDataPrototype);
+ qPersistentDispose(textPrototype);
+ qPersistentDispose(cdataPrototype);
+ qPersistentDispose(documentPrototype);
+}
+
+v8::Local<v8::Object> QDeclarativeXMLHttpRequestData::newNode()
+{
+ if (nodeFunction.IsEmpty()) {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ nodeFunction = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+
+ return nodeFunction->NewInstance();
+}
+
namespace {
class DocumentImpl;
@@ -169,86 +224,53 @@ class NamedNodeMap
{
public:
// JS API
- static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+ static v8::Handle<v8::Value> length(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> indexed(uint32_t index, const v8::AccessorInfo& info);
+ static v8::Handle<v8::Value> named(v8::Local<v8::String> property, const v8::AccessorInfo& args);
// C++ API
- static QScriptValue prototype(QScriptEngine *);
- static QScriptValue create(QScriptEngine *, NodeImpl *, QList<NodeImpl *> *);
-
- NamedNodeMap();
- NamedNodeMap(const NamedNodeMap &);
- ~NamedNodeMap();
- bool isNull();
-
- NodeImpl *d;
- QList<NodeImpl *> *list;
-private:
- NamedNodeMap &operator=(const NamedNodeMap &);
-};
-
-class NamedNodeMapClass : public QScriptClass
-{
-public:
- NamedNodeMapClass(QScriptEngine *engine) : QScriptClass(engine) {}
-
- virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id);
- virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
+ static v8::Handle<v8::Value> create(QV8Engine *, NodeImpl *, QList<NodeImpl *> *);
};
class NodeList
{
public:
// JS API
- static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+ static v8::Handle<v8::Value> length(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> indexed(uint32_t index, const v8::AccessorInfo& info);
// C++ API
- static QScriptValue prototype(QScriptEngine *);
- static QScriptValue create(QScriptEngine *, NodeImpl *);
-
- NodeList();
- NodeList(const NodeList &);
- ~NodeList();
- bool isNull();
-
- NodeImpl *d;
-private:
- NodeList &operator=(const NodeList &);
-};
-
-class NodeListClass : public QScriptClass
-{
-public:
- NodeListClass(QScriptEngine *engine) : QScriptClass(engine) {}
- virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id);
- virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
+ static v8::Handle<v8::Value> create(QV8Engine *, NodeImpl *);
};
class Node
{
public:
// JS API
- static QScriptValue nodeName(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue nodeValue(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue nodeType(QScriptContext *context, QScriptEngine *engine);
-
- static QScriptValue parentNode(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue childNodes(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue firstChild(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue lastChild(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue previousSibling(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue nextSibling(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue attributes(QScriptContext *context, QScriptEngine *engine);
-
- //static QScriptValue ownerDocument(QScriptContext *context, QScriptEngine *engine);
- //static QScriptValue namespaceURI(QScriptContext *context, QScriptEngine *engine);
- //static QScriptValue prefix(QScriptContext *context, QScriptEngine *engine);
- //static QScriptValue localName(QScriptContext *context, QScriptEngine *engine);
- //static QScriptValue baseURI(QScriptContext *context, QScriptEngine *engine);
- //static QScriptValue textContent(QScriptContext *context, QScriptEngine *engine);
+ static v8::Handle<v8::Value> nodeName(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> nodeValue(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> nodeType(v8::Local<v8::String>, const v8::AccessorInfo& args);
+
+ static v8::Handle<v8::Value> parentNode(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> childNodes(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> firstChild(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> lastChild(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> previousSibling(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> nextSibling(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> attributes(v8::Local<v8::String>, const v8::AccessorInfo& args);
+
+ //static v8::Handle<v8::Value> ownerDocument(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ //static v8::Handle<v8::Value> namespaceURI(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ //static v8::Handle<v8::Value> prefix(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ //static v8::Handle<v8::Value> localName(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ //static v8::Handle<v8::Value> baseURI(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ //static v8::Handle<v8::Value> textContent(v8::Local<v8::String>, const v8::AccessorInfo& args);
// C++ API
- static QScriptValue prototype(QScriptEngine *);
- static QScriptValue create(QScriptEngine *, NodeImpl *);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
+ static v8::Handle<v8::Value> create(QV8Engine *, NodeImpl *);
Node();
Node(const Node &o);
@@ -265,68 +287,82 @@ class Element : public Node
{
public:
// C++ API
- static QScriptValue prototype(QScriptEngine *);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
};
class Attr : public Node
{
public:
// JS API
- static QScriptValue name(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue specified(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue value(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue ownerElement(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue schemaTypeInfo(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue isId(QScriptContext *context, QScriptEngine *engine);
+ static v8::Handle<v8::Value> name(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> specified(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> value(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> ownerElement(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> schemaTypeInfo(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> isId(v8::Local<v8::String>, const v8::AccessorInfo& args);
// C++ API
- static QScriptValue prototype(QScriptEngine *);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
};
class CharacterData : public Node
{
public:
// JS API
- static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+ static v8::Handle<v8::Value> length(v8::Local<v8::String>, const v8::AccessorInfo& args);
// C++ API
- static QScriptValue prototype(QScriptEngine *);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
};
class Text : public CharacterData
{
public:
// JS API
- static QScriptValue isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue wholeText(QScriptContext *context, QScriptEngine *engine);
+ static v8::Handle<v8::Value> isElementContentWhitespace(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> wholeText(v8::Local<v8::String>, const v8::AccessorInfo& args);
// C++ API
- static QScriptValue prototype(QScriptEngine *);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
};
class CDATA : public Text
{
public:
// C++ API
- static QScriptValue prototype(QScriptEngine *);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
};
class Document : public Node
{
public:
// JS API
- static QScriptValue xmlVersion(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue xmlEncoding(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue xmlStandalone(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue documentElement(QScriptContext *context, QScriptEngine *engine);
+ static v8::Handle<v8::Value> xmlVersion(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> xmlEncoding(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> xmlStandalone(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> documentElement(v8::Local<v8::String>, const v8::AccessorInfo& args);
// C++ API
- static QScriptValue prototype(QScriptEngine *);
- static QScriptValue load(QScriptEngine *engine, const QByteArray &data);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
+ static v8::Handle<v8::Value> load(QV8Engine *engine, const QByteArray &data);
};
}
+class QDeclarativeDOMNodeResource : public QV8ObjectResource, public Node
+{
+ V8_RESOURCE_TYPE(DOMNodeType);
+public:
+ QDeclarativeDOMNodeResource(QV8Engine *e);
+
+ QList<NodeImpl *> *list; // Only used in NamedNodeMap
+};
+
+QDeclarativeDOMNodeResource::QDeclarativeDOMNodeResource(QV8Engine *e)
+: QV8ObjectResource(e), list(0)
+{
+}
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(Node)
@@ -345,152 +381,174 @@ void NodeImpl::release()
D(document);
}
-QScriptValue Node::nodeName(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::nodeName(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- switch (node.d->type) {
+ switch (r->d->type) {
case NodeImpl::Document:
- return QScriptValue(QLatin1String("#document"));
+ return v8::String::New("#document");
case NodeImpl::CDATA:
- return QScriptValue(QLatin1String("#cdata-section"));
+ return v8::String::New("#cdata-section");
case NodeImpl::Text:
- return QScriptValue(QLatin1String("#text"));
+ return v8::String::New("#text");
default:
- return QScriptValue(node.d->name);
+ return engine->toString(r->d->name);
}
}
-QScriptValue Node::nodeValue(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::nodeValue(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- if (node.d->type == NodeImpl::Document ||
- node.d->type == NodeImpl::DocumentFragment ||
- node.d->type == NodeImpl::DocumentType ||
- node.d->type == NodeImpl::Element ||
- node.d->type == NodeImpl::Entity ||
- node.d->type == NodeImpl::EntityReference ||
- node.d->type == NodeImpl::Notation)
- return engine->nullValue();
+ if (r->d->type == NodeImpl::Document ||
+ r->d->type == NodeImpl::DocumentFragment ||
+ r->d->type == NodeImpl::DocumentType ||
+ r->d->type == NodeImpl::Element ||
+ r->d->type == NodeImpl::Entity ||
+ r->d->type == NodeImpl::EntityReference ||
+ r->d->type == NodeImpl::Notation)
+ return v8::Null();
- return QScriptValue(node.d->data);
+ return engine->toString(r->d->data);
}
-QScriptValue Node::nodeType(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::nodeType(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
- return QScriptValue(node.d->type);
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ return v8::Integer::New(r->d->type);
}
-QScriptValue Node::parentNode(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::parentNode(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- if (node.d->parent) return Node::create(engine, node.d->parent);
- else return engine->nullValue();
+ if (r->d->parent) return Node::create(engine, r->d->parent);
+ else return v8::Null();
}
-QScriptValue Node::childNodes(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::childNodes(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return NodeList::create(engine, node.d);
+ return NodeList::create(engine, r->d);
}
-QScriptValue Node::firstChild(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::firstChild(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- if (node.d->children.isEmpty()) return engine->nullValue();
- else return Node::create(engine, node.d->children.first());
+ if (r->d->children.isEmpty()) return v8::Null();
+ else return Node::create(engine, r->d->children.first());
}
-QScriptValue Node::lastChild(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::lastChild(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- if (node.d->children.isEmpty()) return engine->nullValue();
- else return Node::create(engine, node.d->children.last());
+ if (r->d->children.isEmpty()) return v8::Null();
+ else return Node::create(engine, r->d->children.last());
}
-QScriptValue Node::previousSibling(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::previousSibling(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- if (!node.d->parent) return engine->nullValue();
+ if (!r->d->parent) return v8::Null();
- for (int ii = 0; ii < node.d->parent->children.count(); ++ii) {
- if (node.d->parent->children.at(ii) == node.d) {
- if (ii == 0) return engine->nullValue();
- else return Node::create(engine, node.d->parent->children.at(ii - 1));
+ for (int ii = 0; ii < r->d->parent->children.count(); ++ii) {
+ if (r->d->parent->children.at(ii) == r->d) {
+ if (ii == 0) return v8::Null();
+ else return Node::create(engine, r->d->parent->children.at(ii - 1));
}
}
- return engine->nullValue();
+ return v8::Null();
}
-QScriptValue Node::nextSibling(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::nextSibling(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- if (!node.d->parent) return engine->nullValue();
+ if (!r->d->parent) return v8::Null();
- for (int ii = 0; ii < node.d->parent->children.count(); ++ii) {
- if (node.d->parent->children.at(ii) == node.d) {
- if ((ii + 1) == node.d->parent->children.count()) return engine->nullValue();
- else return Node::create(engine, node.d->parent->children.at(ii + 1));
+ for (int ii = 0; ii < r->d->parent->children.count(); ++ii) {
+ if (r->d->parent->children.at(ii) == r->d) {
+ if ((ii + 1) == r->d->parent->children.count()) return v8::Null();
+ else return Node::create(engine, r->d->parent->children.at(ii + 1));
}
}
- return engine->nullValue();
+ return v8::Null();
}
-QScriptValue Node::attributes(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::attributes(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- if (node.d->type != NodeImpl::Element)
- return engine->nullValue();
+ if (r->d->type != NodeImpl::Element)
+ return v8::Null();
else
- return NamedNodeMap::create(engine, node.d, &node.d->attributes);
-}
-
-QScriptValue Node::prototype(QScriptEngine *engine)
-{
- QScriptValue proto = engine->newObject();
-
- proto.setProperty(QLatin1String("nodeName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("nodeValue"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
- proto.setProperty(QLatin1String("nodeType"), engine->newFunction(nodeType), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("parentNode"), engine->newFunction(parentNode), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("childNodes"), engine->newFunction(childNodes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("firstChild"), engine->newFunction(firstChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("lastChild"), engine->newFunction(lastChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("previousSibling"), engine->newFunction(previousSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("nextSibling"), engine->newFunction(nextSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("attributes"), engine->newFunction(attributes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
-
- return proto;
+ return NamedNodeMap::create(engine, r->d, &r->d->attributes);
+}
+
+v8::Handle<v8::Object> Node::prototype(QV8Engine *engine)
+{
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->nodePrototype.IsEmpty()) {
+ d->nodePrototype = qPersistentNew<v8::Object>(v8::Object::New());
+ d->nodePrototype->SetAccessor(v8::String::New("nodeName"), nodeName,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("nodeValue"), nodeValue,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("nodeType"), nodeType,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("parentNode"), parentNode,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("childNodes"), childNodes,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("firstChild"), firstChild,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("lastChild"), lastChild,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("previousSibling"), previousSibling,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("nextSibling"), nextSibling,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("attributes"), attributes,
+ 0, v8::External::Wrap(engine));
+ engine->freezeObject(d->nodePrototype);
+ }
+ return d->nodePrototype;
}
-QScriptValue Node::create(QScriptEngine *engine, NodeImpl *data)
+v8::Handle<v8::Value> Node::create(QV8Engine *engine, NodeImpl *data)
{
- QScriptValue instance = engine->newObject();
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ v8::Local<v8::Object> instance = d->newNode();
switch (data->type) {
case NodeImpl::Attr:
- instance.setPrototype(Attr::prototype(engine));
+ instance->SetPrototype(Attr::prototype(engine));
break;
case NodeImpl::Comment:
case NodeImpl::Document:
@@ -500,138 +558,171 @@ QScriptValue Node::create(QScriptEngine *engine, NodeImpl *data)
case NodeImpl::EntityReference:
case NodeImpl::Notation:
case NodeImpl::ProcessingInstruction:
- return QScriptValue();
+ return v8::Undefined();
case NodeImpl::CDATA:
- instance.setPrototype(CDATA::prototype(engine));
+ instance->SetPrototype(CDATA::prototype(engine));
break;
case NodeImpl::Text:
- instance.setPrototype(Text::prototype(engine));
+ instance->SetPrototype(Text::prototype(engine));
break;
case NodeImpl::Element:
- instance.setPrototype(Element::prototype(engine));
+ instance->SetPrototype(Element::prototype(engine));
break;
}
- Node node;
- node.d = data;
+ QDeclarativeDOMNodeResource *r = new QDeclarativeDOMNodeResource(engine);
+ r->d = data;
if (data) A(data);
+ instance->SetExternalResource(r);
- return engine->newVariant(instance, QVariant::fromValue(node));
-}
-
-QScriptValue Element::prototype(QScriptEngine *engine)
-{
- QScriptValue proto = engine->newObject();
- proto.setPrototype(Node::prototype(engine));
-
- proto.setProperty(QLatin1String("tagName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
-
- return proto;
-}
-
-QScriptValue Attr::prototype(QScriptEngine *engine)
-{
- QScriptValue proto = engine->newObject();
- proto.setPrototype(Node::prototype(engine));
-
- proto.setProperty(QLatin1String("name"), engine->newFunction(name), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("value"), engine->newFunction(value), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("ownerElement"), engine->newFunction(ownerElement), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
-
- return proto;
+ return instance;
}
-QScriptValue Attr::name(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Object> Element::prototype(QV8Engine *engine)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
-
- return QScriptValue(node.d->name);
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->elementPrototype.IsEmpty()) {
+ d->elementPrototype = qPersistentNew<v8::Object>(v8::Object::New());
+ d->elementPrototype->SetPrototype(Node::prototype(engine));
+ d->elementPrototype->SetAccessor(v8::String::New("tagName"), nodeName,
+ 0, v8::External::Wrap(engine));
+ engine->freezeObject(d->elementPrototype);
+ }
+ return d->elementPrototype;
+}
+
+v8::Handle<v8::Object> Attr::prototype(QV8Engine *engine)
+{
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->attrPrototype.IsEmpty()) {
+ d->attrPrototype = qPersistentNew<v8::Object>(v8::Object::New());
+ d->attrPrototype->SetPrototype(Node::prototype(engine));
+ d->attrPrototype->SetAccessor(v8::String::New("name"), name,
+ 0, v8::External::Wrap(engine));
+ d->attrPrototype->SetAccessor(v8::String::New("value"), value,
+ 0, v8::External::Wrap(engine));
+ d->attrPrototype->SetAccessor(v8::String::New("ownerElement"), ownerElement,
+ 0, v8::External::Wrap(engine));
+ engine->freezeObject(d->attrPrototype);
+ }
+ return d->attrPrototype;
}
-QScriptValue Attr::value(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Attr::name(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return QScriptValue(node.d->data);
+ return engine->toString(r->d->name);
}
-QScriptValue Attr::ownerElement(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Attr::value(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return Node::create(engine, node.d->parent);
+ return engine->toString(r->d->data);
}
-QScriptValue CharacterData::length(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Attr::ownerElement(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return QScriptValue(node.d->data.length());
+ return Node::create(engine, r->d->parent);
}
-QScriptValue CharacterData::prototype(QScriptEngine *engine)
+v8::Handle<v8::Value> CharacterData::length(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- QScriptValue proto = engine->newObject();
- proto.setPrototype(Node::prototype(engine));
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- proto.setProperty(QLatin1String("data"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
- proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
-
- return proto;
+ return v8::Integer::New(r->d->data.length());
}
-QScriptValue Text::isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Object> CharacterData::prototype(QV8Engine *engine)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
-
- return node.d->data.trimmed().isEmpty();
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->characterDataPrototype.IsEmpty()) {
+ d->characterDataPrototype = qPersistentNew<v8::Object>(v8::Object::New());
+ d->characterDataPrototype->SetPrototype(Node::prototype(engine));
+ d->characterDataPrototype->SetAccessor(v8::String::New("data"), nodeValue,
+ 0, v8::External::Wrap(engine));
+ d->characterDataPrototype->SetAccessor(v8::String::New("length"), length,
+ 0, v8::External::Wrap(engine));
+ engine->freezeObject(d->characterDataPrototype);
+ }
+ return d->characterDataPrototype;
}
-QScriptValue Text::wholeText(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Text::isElementContentWhitespace(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return node.d->data;
+ return v8::Boolean::New(r->d->data.trimmed().isEmpty());
}
-QScriptValue Text::prototype(QScriptEngine *engine)
+v8::Handle<v8::Value> Text::wholeText(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- QScriptValue proto = engine->newObject();
- proto.setPrototype(CharacterData::prototype(engine));
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- proto.setProperty(QLatin1String("isElementContentWhitespace"), engine->newFunction(isElementContentWhitespace), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("wholeText"), engine->newFunction(wholeText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
-
- return proto;
+ return engine->toString(r->d->data);
}
-QScriptValue CDATA::prototype(QScriptEngine *engine)
+v8::Handle<v8::Object> Text::prototype(QV8Engine *engine)
{
- QScriptValue proto = engine->newObject();
- proto.setPrototype(Text::prototype(engine));
- return proto;
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->textPrototype.IsEmpty()) {
+ d->textPrototype = qPersistentNew<v8::Object>(v8::Object::New());
+ d->textPrototype->SetPrototype(CharacterData::prototype(engine));
+ d->textPrototype->SetAccessor(v8::String::New("isElementContentWhitespace"), isElementContentWhitespace,
+ 0, v8::External::Wrap(engine));
+ d->textPrototype->SetAccessor(v8::String::New("wholeText"), wholeText,
+ 0, v8::External::Wrap(engine));
+ engine->freezeObject(d->textPrototype);
+ }
+ return d->textPrototype;
}
-QScriptValue Document::prototype(QScriptEngine *engine)
+v8::Handle<v8::Object> CDATA::prototype(QV8Engine *engine)
{
- QScriptValue proto = engine->newObject();
- proto.setPrototype(Node::prototype(engine));
-
- proto.setProperty(QLatin1String("xmlVersion"), engine->newFunction(xmlVersion), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
- proto.setProperty(QLatin1String("xmlEncoding"), engine->newFunction(xmlEncoding), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
- proto.setProperty(QLatin1String("xmlStandalone"), engine->newFunction(xmlStandalone), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
- proto.setProperty(QLatin1String("documentElement"), engine->newFunction(documentElement), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
-
- return proto;
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->cdataPrototype.IsEmpty()) {
+ d->cdataPrototype = qPersistentNew<v8::Object>(v8::Object::New());
+ d->cdataPrototype->SetPrototype(Text::prototype(engine));
+ engine->freezeObject(d->cdataPrototype);
+ }
+ return d->cdataPrototype;
+}
+
+v8::Handle<v8::Object> Document::prototype(QV8Engine *engine)
+{
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->documentPrototype.IsEmpty()) {
+ d->documentPrototype = qPersistentNew<v8::Object>(v8::Object::New());
+ d->documentPrototype->SetPrototype(Node::prototype(engine));
+ d->documentPrototype->SetAccessor(v8::String::New("xmlVersion"), xmlVersion,
+ 0, v8::External::Wrap(engine));
+ d->documentPrototype->SetAccessor(v8::String::New("xmlEncoding"), xmlEncoding,
+ 0, v8::External::Wrap(engine));
+ d->documentPrototype->SetAccessor(v8::String::New("xmlStandalone"), xmlStandalone,
+ 0, v8::External::Wrap(engine));
+ d->documentPrototype->SetAccessor(v8::String::New("documentElement"), documentElement,
+ 0, v8::External::Wrap(engine));
+ engine->freezeObject(d->documentPrototype);
+ }
+ return d->documentPrototype;
}
-QScriptValue Document::load(QScriptEngine *engine, const QByteArray &data)
+v8::Handle<v8::Value> Document::load(QV8Engine *engine, const QByteArray &data)
{
Q_ASSERT(engine);
@@ -709,14 +800,15 @@ QScriptValue Document::load(QScriptEngine *engine, const QByteArray &data)
if (!document || reader.hasError()) {
if (document) D(document);
- return engine->nullValue();
+ return v8::Null();
}
- QScriptValue instance = engine->newObject();
- instance.setPrototype(Document::prototype(engine));
- Node documentNode;
- documentNode.d = document;
- return engine->newVariant(instance, QVariant::fromValue(documentNode));
+ v8::Local<v8::Object> instance = xhrdata(engine)->newNode();
+ QDeclarativeDOMNodeResource *r = new QDeclarativeDOMNodeResource(engine);
+ r->d = document;
+ instance->SetExternalResource(r);
+ instance->SetPrototype(Document::prototype(engine));
+ return instance;
}
Node::Node()
@@ -740,221 +832,164 @@ bool Node::isNull() const
return d == 0;
}
-QScriptValue NamedNodeMap::length(QScriptContext *context, QScriptEngine *engine)
-{
- NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(context->thisObject().data());
- if (map.isNull()) return engine->undefinedValue();
-
- return QScriptValue(map.list->count());
-}
-
-QScriptValue NamedNodeMap::prototype(QScriptEngine *engine)
+v8::Handle<v8::Value> NamedNodeMap::length(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- QScriptValue proto = engine->newObject();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
-
- return proto;
+ return v8::Integer::New(r->list->count());
}
-QScriptValue NamedNodeMap::create(QScriptEngine *engine, NodeImpl *data, QList<NodeImpl *> *list)
+v8::Handle<v8::Value> NamedNodeMap::indexed(uint32_t index, const v8::AccessorInfo& args)
{
- QScriptValue instance = engine->newObject();
- instance.setPrototype(NamedNodeMap::prototype(engine));
-
- NamedNodeMap map;
- map.d = data;
- map.list = list;
- if (data) A(data);
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r || !r->list) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- instance.setData(engine->newVariant(QVariant::fromValue(map)));
-
- if (!QDeclarativeScriptEngine::get(engine)->namedNodeMapClass)
- QDeclarativeScriptEngine::get(engine)->namedNodeMapClass= new NamedNodeMapClass(engine);
-
- instance.setScriptClass(QDeclarativeScriptEngine::get(engine)->namedNodeMapClass);
-
- return instance;
-}
-
-NamedNodeMap::NamedNodeMap()
-: d(0), list(0)
-{
-}
-
-NamedNodeMap::NamedNodeMap(const NamedNodeMap &o)
-: d(o.d), list(o.list)
-{
- if (d) A(d);
-}
-
-NamedNodeMap::~NamedNodeMap()
-{
- if (d) D(d);
+ if (index < r->list->count()) {
+ return Node::create(engine, r->list->at(index));
+ } else {
+ return v8::Undefined();
+ }
}
-bool NamedNodeMap::isNull()
+v8::Handle<v8::Value> NamedNodeMap::named(v8::Local<v8::String> property, const v8::AccessorInfo& args)
{
- return d == 0;
-}
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r || !r->list) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
-QScriptValue NodeList::length(QScriptContext *context, QScriptEngine *engine)
-{
- NodeList list = qscriptvalue_cast<NodeList>(context->thisObject().data());
- if (list.isNull()) return engine->undefinedValue();
+ QString str = engine->toString(property);
+ for (int ii = 0; ii < r->list->count(); ++ii) {
+ if (r->list->at(ii)->name == str) {
+ return Node::create(engine, r->list->at(ii));
+ }
+ }
- return QScriptValue(list.d->children.count());
+ return v8::Undefined();
}
-QScriptValue NodeList::prototype(QScriptEngine *engine)
+v8::Handle<v8::Object> NamedNodeMap::prototype(QV8Engine *engine)
{
- QScriptValue proto = engine->newObject();
-
- proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
-
- return proto;
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->namedNodeMapPrototype.IsEmpty()) {
+ v8::Local<v8::ObjectTemplate> ot = v8::ObjectTemplate::New();
+ ot->SetAccessor(v8::String::New("length"), length, 0, v8::External::Wrap(engine));
+ ot->SetIndexedPropertyHandler(indexed, 0, 0, 0, 0, v8::External::Wrap(engine));
+ ot->SetFallbackPropertyHandler(named, 0, 0, 0, 0, v8::External::Wrap(engine));
+ d->namedNodeMapPrototype = qPersistentNew<v8::Object>(ot->NewInstance());
+ engine->freezeObject(d->namedNodeMapPrototype);
+ }
+ return d->namedNodeMapPrototype;
}
-QScriptValue NodeList::create(QScriptEngine *engine, NodeImpl *data)
+v8::Handle<v8::Value> NamedNodeMap::create(QV8Engine *engine, NodeImpl *data, QList<NodeImpl *> *list)
{
- QScriptValue instance = engine->newObject();
- instance.setPrototype(NodeList::prototype(engine));
-
- NodeList list;
- list.d = data;
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ v8::Local<v8::Object> instance = d->newNode();
+ instance->SetPrototype(NamedNodeMap::prototype(engine));
+ QDeclarativeDOMNodeResource *r = new QDeclarativeDOMNodeResource(engine);
+ r->d = data;
+ r->list = list;
if (data) A(data);
-
- instance.setData(engine->newVariant(QVariant::fromValue(list)));
-
- if (!QDeclarativeScriptEngine::get(engine)->nodeListClass)
- QDeclarativeScriptEngine::get(engine)->nodeListClass= new NodeListClass(engine);
-
- instance.setScriptClass(QDeclarativeScriptEngine::get(engine)->nodeListClass);
-
+ instance->SetExternalResource(r);
return instance;
}
-NodeList::NodeList()
-: d(0)
-{
-}
-
-NodeList::NodeList(const NodeList &o)
-: d(o.d)
-{
- if (d) A(d);
-}
-
-NodeList::~NodeList()
-{
- if (d) D(d);
-}
-
-bool NodeList::isNull()
+v8::Handle<v8::Value> NodeList::indexed(uint32_t index, const v8::AccessorInfo& args)
{
- return d == 0;
-}
-
-NamedNodeMapClass::QueryFlags NamedNodeMapClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id)
-{
- if (!(flags & HandlesReadAccess))
- return 0;
-
- NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data());
- Q_ASSERT(!map.isNull());
-
- bool ok = false;
- QString nameString = name.toString();
- uint index = nameString.toUInt(&ok);
- if (ok) {
- if ((uint)map.list->count() <= index)
- return 0;
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- *id = index;
- return HandlesReadAccess;
+ if (index < r->d->children.count()) {
+ return Node::create(engine, r->d->children.at(index));
} else {
- for (int ii = 0; ii < map.list->count(); ++ii) {
- if (map.list->at(ii) && map.list->at(ii)->name == nameString) {
- *id = ii;
- return HandlesReadAccess;
- }
- }
+ return v8::Undefined();
}
-
- return 0;
}
-QScriptValue NamedNodeMapClass::property(const QScriptValue &object, const QScriptString &, uint id)
+v8::Handle<v8::Value> NodeList::length(v8::Local<v8::String>, const v8::AccessorInfo& args)
{
- NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data());
- return Node::create(engine(), map.list->at(id));
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ return v8::Integer::New(r->d->children.count());
}
-NodeListClass::QueryFlags NodeListClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id)
+v8::Handle<v8::Object> NodeList::prototype(QV8Engine *engine)
{
- if (!(flags & HandlesReadAccess))
- return 0;
-
- bool ok = false;
- uint index = name.toString().toUInt(&ok);
- if (!ok)
- return 0;
-
- NodeList list = qscriptvalue_cast<NodeList>(object.data());
- if (list.isNull() || (uint)list.d->children.count() <= index)
- return 0; // ### I think we're meant to raise an exception
-
- *id = index;
- return HandlesReadAccess;
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->nodeListPrototype.IsEmpty()) {
+ v8::Local<v8::ObjectTemplate> ot = v8::ObjectTemplate::New();
+ ot->SetAccessor(v8::String::New("length"), length, 0, v8::External::Wrap(engine));
+ ot->SetIndexedPropertyHandler(indexed, 0, 0, 0, 0, v8::External::Wrap(engine));
+ d->nodeListPrototype = qPersistentNew<v8::Object>(ot->NewInstance());
+ engine->freezeObject(d->nodeListPrototype);
+ }
+ return d->nodeListPrototype;
}
-QScriptValue NodeListClass::property(const QScriptValue &object, const QScriptString &, uint id)
+v8::Handle<v8::Value> NodeList::create(QV8Engine *engine, NodeImpl *data)
{
- NodeList list = qscriptvalue_cast<NodeList>(object.data());
- return Node::create(engine(), list.d->children.at(id));
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ v8::Local<v8::Object> instance = d->newNode();
+ instance->SetPrototype(NodeList::prototype(engine));
+ QDeclarativeDOMNodeResource *r = new QDeclarativeDOMNodeResource(engine);
+ r->d = data;
+ if (data) A(data);
+ instance->SetExternalResource(r);
+ return instance;
}
-QScriptValue Document::documentElement(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Document::documentElement(v8::Local<v8::String>, const v8::AccessorInfo& args)
{
- Node document = qscriptvalue_cast<Node>(context->thisObject());
- if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r || r->d->type != NodeImpl::Document) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return Node::create(engine, static_cast<DocumentImpl *>(document.d)->root);
+ return Node::create(engine, static_cast<DocumentImpl *>(r->d)->root);
}
-QScriptValue Document::xmlStandalone(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Document::xmlStandalone(v8::Local<v8::String>, const v8::AccessorInfo& args)
{
- Node document = qscriptvalue_cast<Node>(context->thisObject());
- if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r || r->d->type != NodeImpl::Document) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return QScriptValue(static_cast<DocumentImpl *>(document.d)->isStandalone);
+ return v8::Boolean::New(static_cast<DocumentImpl *>(r->d)->isStandalone);
}
-QScriptValue Document::xmlVersion(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Document::xmlVersion(v8::Local<v8::String>, const v8::AccessorInfo& args)
{
- Node document = qscriptvalue_cast<Node>(context->thisObject());
- if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r || r->d->type != NodeImpl::Document) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return QScriptValue(static_cast<DocumentImpl *>(document.d)->version);
+ return engine->toString(static_cast<DocumentImpl *>(r->d)->version);
}
-QScriptValue Document::xmlEncoding(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Document::xmlEncoding(v8::Local<v8::String>, const v8::AccessorInfo& args)
{
- Node document = qscriptvalue_cast<Node>(context->thisObject());
- if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r || r->d->type != NodeImpl::Document) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return QScriptValue(static_cast<DocumentImpl *>(document.d)->encoding);
+ return engine->toString(static_cast<DocumentImpl *>(r->d)->encoding);
}
-class QDeclarativeXMLHttpRequest : public QObject
+class QDeclarativeXMLHttpRequest : public QObject, public QV8ObjectResource
{
Q_OBJECT
+V8_RESOURCE_TYPE(XMLHttpRequestType)
public:
enum State { Unsent = 0,
Opened = 1, HeadersReceived = 2,
Loading = 3, Done = 4 };
- QDeclarativeXMLHttpRequest(QNetworkAccessManager *manager);
+ QDeclarativeXMLHttpRequest(QV8Engine *engine, QNetworkAccessManager *manager);
virtual ~QDeclarativeXMLHttpRequest();
bool sendFlag() const;
@@ -963,13 +998,14 @@ public:
int replyStatus() const;
QString replyStatusText() const;
- QScriptValue open(QScriptValue *me, const QString &, const QUrl &);
+ v8::Handle<v8::Value> open(v8::Handle<v8::Object> me, const QString &, const QUrl &);
+ v8::Handle<v8::Value> send(v8::Handle<v8::Object> me, const QByteArray &);
+ v8::Handle<v8::Value> abort(v8::Handle<v8::Object> me);
void addHeader(const QString &, const QString &);
QString header(const QString &name);
QString headers();
- QScriptValue send(QScriptValue *me, const QByteArray &);
- QScriptValue abort(QScriptValue *me);
+
QString responseBody();
const QByteArray & rawResponseBody() const;
@@ -1005,10 +1041,12 @@ private:
#endif
void readEncoding();
- QScriptValue m_me; // Set to the data object while a send() is ongoing (to access the callback)
+ v8::Handle<v8::Object> getMe() const;
+ void setMe(v8::Handle<v8::Object> me);
+ v8::Persistent<v8::Object> m_me;
- QScriptValue dispatchCallback(QScriptValue *me);
- void printError(const QScriptValue&);
+ void dispatchCallback(v8::Handle<v8::Object> me);
+ void printError(v8::Handle<v8::Message>);
int m_status;
QString m_statusText;
@@ -1020,8 +1058,8 @@ private:
QNetworkAccessManager *networkAccessManager() { return m_nam; }
};
-QDeclarativeXMLHttpRequest::QDeclarativeXMLHttpRequest(QNetworkAccessManager *manager)
-: m_state(Unsent), m_errorFlag(false), m_sendFlag(false),
+QDeclarativeXMLHttpRequest::QDeclarativeXMLHttpRequest(QV8Engine *engine, QNetworkAccessManager *manager)
+: QV8ObjectResource(engine), m_state(Unsent), m_errorFlag(false), m_sendFlag(false),
m_redirectCount(0), m_gotXml(false), m_textCodec(0), m_network(0), m_nam(manager)
{
}
@@ -1056,7 +1094,8 @@ QString QDeclarativeXMLHttpRequest::replyStatusText() const
return m_statusText;
}
-QScriptValue QDeclarativeXMLHttpRequest::open(QScriptValue *me, const QString &method, const QUrl &url)
+v8::Handle<v8::Value> QDeclarativeXMLHttpRequest::open(v8::Handle<v8::Object> me, const QString &method,
+ const QUrl &url)
{
destroyNetwork();
m_sendFlag = false;
@@ -1065,7 +1104,8 @@ QScriptValue QDeclarativeXMLHttpRequest::open(QScriptValue *me, const QString &m
m_method = method;
m_url = url;
m_state = Opened;
- return dispatchCallback(me);
+ dispatchCallback(me);
+ return v8::Undefined();
}
void QDeclarativeXMLHttpRequest::addHeader(const QString &name, const QString &value)
@@ -1176,20 +1216,21 @@ void QDeclarativeXMLHttpRequest::requestFromUrl(const QUrl &url)
this, SLOT(finished()));
}
-QScriptValue QDeclarativeXMLHttpRequest::send(QScriptValue *me, const QByteArray &data)
+v8::Handle<v8::Value> QDeclarativeXMLHttpRequest::send(v8::Handle<v8::Object> me, const QByteArray &data)
{
m_errorFlag = false;
m_sendFlag = true;
m_redirectCount = 0;
m_data = data;
- m_me = *me;
+
+ setMe(me);
requestFromUrl(m_url);
- return QScriptValue();
+ return v8::Undefined();
}
-QScriptValue QDeclarativeXMLHttpRequest::abort(QScriptValue *me)
+v8::Handle<v8::Value> QDeclarativeXMLHttpRequest::abort(v8::Handle<v8::Object> me)
{
destroyNetwork();
m_responseEntityBody = QByteArray();
@@ -1202,16 +1243,31 @@ QScriptValue QDeclarativeXMLHttpRequest::abort(QScriptValue *me)
m_state = Done;
m_sendFlag = false;
- QScriptValue cbv = dispatchCallback(me);
- if (cbv.isError()) return cbv;
+ dispatchCallback(me);
}
m_state = Unsent;
- return QScriptValue();
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Object> QDeclarativeXMLHttpRequest::getMe() const
+{
+ return m_me;
+}
+
+void QDeclarativeXMLHttpRequest::setMe(v8::Handle<v8::Object> me)
+{
+ qPersistentDispose(m_me);
+
+ if (!me.IsEmpty())
+ m_me = qPersistentNew<v8::Object>(me);
}
void QDeclarativeXMLHttpRequest::downloadProgress(qint64 bytes)
{
+ v8::HandleScope handle_scope;
+
Q_UNUSED(bytes)
m_status =
m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
@@ -1222,16 +1278,18 @@ void QDeclarativeXMLHttpRequest::downloadProgress(qint64 bytes)
if (m_state < HeadersReceived) {
m_state = HeadersReceived;
fillHeadersList ();
- QScriptValue cbv = dispatchCallback(&m_me);
- if (cbv.isError()) printError(cbv);
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
}
bool wasEmpty = m_responseEntityBody.isEmpty();
m_responseEntityBody.append(m_network->readAll());
if (wasEmpty && !m_responseEntityBody.isEmpty()) {
m_state = Loading;
- QScriptValue cbv = dispatchCallback(&m_me);
- if (cbv.isError()) printError(cbv);
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
}
}
@@ -1249,6 +1307,8 @@ static const char *errorToString(QNetworkReply::NetworkError error)
void QDeclarativeXMLHttpRequest::error(QNetworkReply::NetworkError error)
{
+ v8::HandleScope handle_scope;
+
Q_UNUSED(error)
m_status =
m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
@@ -1272,20 +1332,25 @@ void QDeclarativeXMLHttpRequest::error(QNetworkReply::NetworkError error)
error == QNetworkReply::AuthenticationRequiredError ||
error == QNetworkReply::ContentReSendError) {
m_state = Loading;
- QScriptValue cbv = dispatchCallback(&m_me);
- if (cbv.isError()) printError(cbv);
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
} else {
m_errorFlag = true;
}
m_state = Done;
- QScriptValue cbv = dispatchCallback(&m_me);
- if (cbv.isError()) printError(cbv);
+
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
}
#define XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION 15
void QDeclarativeXMLHttpRequest::finished()
{
+ v8::HandleScope handle_scope;
+
m_redirectCount++;
if (m_redirectCount < XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION) {
QVariant redirect = m_network->attribute(QNetworkRequest::RedirectionTargetAttribute);
@@ -1305,8 +1370,9 @@ void QDeclarativeXMLHttpRequest::finished()
if (m_state < HeadersReceived) {
m_state = HeadersReceived;
fillHeadersList ();
- QScriptValue cbv = dispatchCallback(&m_me);
- if (cbv.isError()) printError(cbv);
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
}
m_responseEntityBody.append(m_network->readAll());
readEncoding();
@@ -1324,14 +1390,17 @@ void QDeclarativeXMLHttpRequest::finished()
destroyNetwork();
if (m_state < Loading) {
m_state = Loading;
- QScriptValue cbv = dispatchCallback(&m_me);
- if (cbv.isError()) printError(cbv);
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
}
m_state = Done;
- QScriptValue cbv = dispatchCallback(&m_me);
- if (cbv.isError()) printError(cbv);
- m_me = QScriptValue();
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
+
+ setMe(v8::Handle<v8::Object>());
}
@@ -1409,17 +1478,25 @@ const QByteArray &QDeclarativeXMLHttpRequest::rawResponseBody() const
return m_responseEntityBody;
}
-QScriptValue QDeclarativeXMLHttpRequest::dispatchCallback(QScriptValue *me)
+// Requires a TryCatch scope
+void QDeclarativeXMLHttpRequest::dispatchCallback(v8::Handle<v8::Object> me)
{
- QScriptValue v = me->property(QLatin1String("callback"));
- return v.call();
+ v8::Local<v8::Value> callback = me->Get(v8::String::New("onreadystatechange"));
+ if (callback->IsFunction()) {
+ v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(callback);
+
+ f->Call(me, 0, 0);
+ }
}
-void QDeclarativeXMLHttpRequest::printError(const QScriptValue& sv)
+// Must have a handle scope
+void QDeclarativeXMLHttpRequest::printError(v8::Handle<v8::Message> message)
{
+ v8::Context::Scope scope(engine->context());
+
QDeclarativeError error;
- QDeclarativeExpressionPrivate::exceptionToError(sv.engine(), error);
- QDeclarativeEnginePrivate::warning(QDeclarativeEnginePrivate::get(sv.engine()), error);
+ QDeclarativeExpressionPrivate::exceptionToError(message, error);
+ QDeclarativeEnginePrivate::warning(QDeclarativeEnginePrivate::get(engine->engine()), error);
}
void QDeclarativeXMLHttpRequest::destroyNetwork()
@@ -1432,71 +1509,68 @@ void QDeclarativeXMLHttpRequest::destroyNetwork()
}
// XMLHttpRequest methods
-static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_open(const v8::Arguments &args)
{
- QScriptValue dataObject = context->thisObject().data();
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
- if (context->argumentCount() < 2 || context->argumentCount() > 5)
- THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+ if (args.Length() < 2 || args.Length() > 5)
+ V8THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+
+ QV8Engine *engine = r->engine;
// Argument 0 - Method
- QString method = context->argument(0).toString().toUpper();
+ QString method = engine->toString(args[0]).toUpper();
if (method != QLatin1String("GET") &&
method != QLatin1String("PUT") &&
method != QLatin1String("HEAD") &&
method != QLatin1String("POST"))
- THROW_DOM(SYNTAX_ERR, "Unsupported HTTP method type");
-
+ V8THROW_DOM(SYNTAX_ERR, "Unsupported HTTP method type");
// Argument 1 - URL
- QUrl url = QUrl::fromEncoded(context->argument(1).toString().toUtf8());
+ QUrl url = QUrl::fromEncoded(engine->toString(args[1]).toUtf8());
- if (url.isRelative()) {
- url = QDeclarativeScriptEngine::get(engine)->resolvedUrl(context,url);
- }
+ if (url.isRelative())
+ url = engine->callingContext()->resolvedUrl(url);
// Argument 2 - async (optional)
- if (context->argumentCount() > 2 && !context->argument(2).toBoolean())
- THROW_DOM(NOT_SUPPORTED_ERR, "Synchronous XMLHttpRequest calls are not supported");
-
+ if (args.Length() > 2 && !args[2]->BooleanValue())
+ V8THROW_DOM(NOT_SUPPORTED_ERR, "Synchronous XMLHttpRequest calls are not supported");
// Argument 3/4 - user/pass (optional)
QString username, password;
- if (context->argumentCount() > 3)
- username = context->argument(3).toString();
- if (context->argumentCount() > 4)
- password = context->argument(4).toString();
-
+ if (args.Length() > 3)
+ username = engine->toString(args[3]);
+ if (args.Length() > 4)
+ password = engine->toString(args[4]);
// Clear the fragment (if any)
url.setFragment(QString());
+
// Set username/password
if (!username.isNull()) url.setUserName(username);
if (!password.isNull()) url.setPassword(password);
- return request->open(&dataObject, method, url);
+ return r->open(args.This(), method, url);
}
-static QScriptValue qmlxmlhttprequest_setRequestHeader(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_setRequestHeader(const v8::Arguments &args)
{
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
-
- if (context->argumentCount() != 2)
- THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
+ if (args.Length() != 2)
+ V8THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
- if (request->readyState() != QDeclarativeXMLHttpRequest::Opened ||
- request->sendFlag())
- THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+ if (r->readyState() != QDeclarativeXMLHttpRequest::Opened || r->sendFlag())
+ V8THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+ QV8Engine *engine = r->engine;
- QString name = context->argument(0).toString();
- QString value = context->argument(1).toString();
+ QString name = engine->toString(args[0]);
+ QString value = engine->toString(args[1]);
// ### Check that name and value are well formed
@@ -1521,237 +1595,243 @@ static QScriptValue qmlxmlhttprequest_setRequestHeader(QScriptContext *context,
nameUpper == QLatin1String("VIA") ||
nameUpper.startsWith(QLatin1String("PROXY-")) ||
nameUpper.startsWith(QLatin1String("SEC-")))
- return engine->undefinedValue();
+ return v8::Undefined();
- request->addHeader(nameUpper, value);
+ r->addHeader(nameUpper, value);
- return engine->undefinedValue();
+ return v8::Undefined();
}
-static QScriptValue qmlxmlhttprequest_send(QScriptContext *context, QScriptEngine *)
+static v8::Handle<v8::Value> qmlxmlhttprequest_send(const v8::Arguments &args)
{
- QScriptValue dataObject = context->thisObject().data();
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
- if (request->readyState() != QDeclarativeXMLHttpRequest::Opened)
- THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+ QV8Engine *engine = r->engine;
- if (request->sendFlag())
- THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+ if (r->readyState() != QDeclarativeXMLHttpRequest::Opened ||
+ r->sendFlag())
+ V8THROW_DOM(INVALID_STATE_ERR, "Invalid state");
QByteArray data;
- if (context->argumentCount() > 0)
- data = context->argument(0).toString().toUtf8();
+ if (args.Length() > 0)
+ data = engine->toString(args[0]).toUtf8();
- return request->send(&dataObject, data);
+ return r->send(args.This(), data);
}
-static QScriptValue qmlxmlhttprequest_abort(QScriptContext *context, QScriptEngine *)
+static v8::Handle<v8::Value> qmlxmlhttprequest_abort(const v8::Arguments &args)
{
- QScriptValue dataObject = context->thisObject().data();
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
- return request->abort(&dataObject);
+ return r->abort(args.This());
}
-static QScriptValue qmlxmlhttprequest_getResponseHeader(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_getResponseHeader(const v8::Arguments &args)
{
- Q_UNUSED(engine)
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
- if (context->argumentCount() != 1)
- THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+ QV8Engine *engine = r->engine;
- if (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
- request->readyState() != QDeclarativeXMLHttpRequest::Done &&
- request->readyState() != QDeclarativeXMLHttpRequest::HeadersReceived)
- THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+ if (args.Length() != 1)
+ V8THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
- QString headerName = context->argument(0).toString();
+ if (r->readyState() != QDeclarativeXMLHttpRequest::Loading &&
+ r->readyState() != QDeclarativeXMLHttpRequest::Done &&
+ r->readyState() != QDeclarativeXMLHttpRequest::HeadersReceived)
+ V8THROW_DOM(INVALID_STATE_ERR, "Invalid state");
- return QScriptValue(request->header(headerName));
+ return engine->toString(r->header(engine->toString(args[0])));
}
-static QScriptValue qmlxmlhttprequest_getAllResponseHeaders(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_getAllResponseHeaders(const v8::Arguments &args)
{
- Q_UNUSED(engine)
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ QV8Engine *engine = r->engine;
- if (context->argumentCount() != 0)
- THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+ if (args.Length() != 0)
+ V8THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
- if (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
- request->readyState() != QDeclarativeXMLHttpRequest::Done &&
- request->readyState() != QDeclarativeXMLHttpRequest::HeadersReceived)
- THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+ if (r->readyState() != QDeclarativeXMLHttpRequest::Loading &&
+ r->readyState() != QDeclarativeXMLHttpRequest::Done &&
+ r->readyState() != QDeclarativeXMLHttpRequest::HeadersReceived)
+ V8THROW_DOM(INVALID_STATE_ERR, "Invalid state");
- return QScriptValue(request->headers());
+ return engine->toString(r->headers());
}
// XMLHttpRequest properties
-static QScriptValue qmlxmlhttprequest_readyState(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_readyState(v8::Local<v8::String> property,
+ const v8::AccessorInfo& info)
{
- Q_UNUSED(engine)
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(info.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
- return QScriptValue(request->readyState());
+ return v8::Integer::NewFromUnsigned(r->readyState());
}
-static QScriptValue qmlxmlhttprequest_status(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_status(v8::Local<v8::String> property,
+ const v8::AccessorInfo& info)
{
- Q_UNUSED(engine)
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(info.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
- if (request->readyState() == QDeclarativeXMLHttpRequest::Unsent ||
- request->readyState() == QDeclarativeXMLHttpRequest::Opened)
- THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+ if (r->readyState() == QDeclarativeXMLHttpRequest::Unsent ||
+ r->readyState() == QDeclarativeXMLHttpRequest::Opened)
+ V8THROW_DOM(INVALID_STATE_ERR, "Invalid state");
- if (request->errorFlag())
- return QScriptValue(0);
+ if (r->errorFlag())
+ return v8::Integer::New(0);
else
- return QScriptValue(request->replyStatus());
+ return v8::Integer::New(r->replyStatus());
}
-static QScriptValue qmlxmlhttprequest_statusText(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_statusText(v8::Local<v8::String> property,
+ const v8::AccessorInfo& info)
{
- Q_UNUSED(engine)
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(info.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
- if (request->readyState() == QDeclarativeXMLHttpRequest::Unsent ||
- request->readyState() == QDeclarativeXMLHttpRequest::Opened)
- THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+ QV8Engine *engine = r->engine;
- if (request->errorFlag())
- return QScriptValue(0);
+ if (r->readyState() == QDeclarativeXMLHttpRequest::Unsent ||
+ r->readyState() == QDeclarativeXMLHttpRequest::Opened)
+ V8THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+
+ if (r->errorFlag())
+ return engine->toString(QString());
else
- return QScriptValue(request->replyStatusText());
+ return engine->toString(r->replyStatusText());
}
-static QScriptValue qmlxmlhttprequest_responseText(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_responseText(v8::Local<v8::String> property,
+ const v8::AccessorInfo& info)
{
- Q_UNUSED(engine)
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(info.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ QV8Engine *engine = r->engine;
- if (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
- request->readyState() != QDeclarativeXMLHttpRequest::Done)
- return QScriptValue(QString());
+ if (r->readyState() != QDeclarativeXMLHttpRequest::Loading &&
+ r->readyState() != QDeclarativeXMLHttpRequest::Done)
+ return engine->toString(QString());
else
- return QScriptValue(request->responseBody());
+ return engine->toString(r->responseBody());
}
-static QScriptValue qmlxmlhttprequest_responseXML(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_responseXML(v8::Local<v8::String> property,
+ const v8::AccessorInfo& info)
{
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(info.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
- if (!request->receivedXml() ||
- (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
- request->readyState() != QDeclarativeXMLHttpRequest::Done))
- return engine->nullValue();
- else
- return Document::load(engine, request->rawResponseBody());
+ if (!r->receivedXml() ||
+ (r->readyState() != QDeclarativeXMLHttpRequest::Loading &&
+ r->readyState() != QDeclarativeXMLHttpRequest::Done)) {
+ return v8::Null();
+ } else {
+ return Document::load(r->engine, r->rawResponseBody());
+ }
}
-static QScriptValue qmlxmlhttprequest_onreadystatechange(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_new(const v8::Arguments &args)
{
- Q_UNUSED(engine);
- QScriptValue dataObject = context->thisObject().data();
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ if (args.IsConstructCall()) {
+ QV8Engine *engine = V8ENGINE();
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine());
+
+ QDeclarativeXMLHttpRequest *r = new QDeclarativeXMLHttpRequest(engine, engine->networkAccessManager());
+ args.This()->SetExternalResource(r);
- if (context->argumentCount()) {
- QScriptValue v = context->argument(0);
- dataObject.setProperty(QLatin1String("callback"), v);
- return v;
+ return args.This();
} else {
- return dataObject.property(QLatin1String("callback"));
+ return v8::Undefined();
}
}
-// Constructor
-static QScriptValue qmlxmlhttprequest_new(QScriptContext *context, QScriptEngine *engine)
+#define NEWFUNCTION(function) v8::FunctionTemplate::New(function)->GetFunction()
+
+void qt_rem_qmlxmlhttprequest(QV8Engine *engine, void *d)
{
- if (context->isCalledAsConstructor()) {
- context->thisObject().setData(engine->newQObject(new QDeclarativeXMLHttpRequest(QDeclarativeScriptEngine::get(engine)->networkAccessManager()), QScriptEngine::ScriptOwnership));
- }
- return engine->undefinedValue();
+ QDeclarativeXMLHttpRequestData *data = (QDeclarativeXMLHttpRequestData *)d;
+ delete data;
}
-void qt_add_qmlxmlhttprequest(QScriptEngine *engine)
+void *qt_add_qmlxmlhttprequest(QV8Engine *engine)
{
- QScriptValue prototype = engine->newObject();
+ v8::PropertyAttribute attributes = (v8::PropertyAttribute)(v8::ReadOnly | v8::DontEnum | v8::DontDelete);
+
+ // XMLHttpRequest
+ v8::Local<v8::FunctionTemplate> xmlhttprequest = v8::FunctionTemplate::New(qmlxmlhttprequest_new,
+ v8::External::Wrap(engine));
+ xmlhttprequest->InstanceTemplate()->SetHasExternalResource(true);
// Methods
- prototype.setProperty(QLatin1String("open"), engine->newFunction(qmlxmlhttprequest_open, 2));
- prototype.setProperty(QLatin1String("setRequestHeader"), engine->newFunction(qmlxmlhttprequest_setRequestHeader, 2));
- prototype.setProperty(QLatin1String("send"), engine->newFunction(qmlxmlhttprequest_send));
- prototype.setProperty(QLatin1String("abort"), engine->newFunction(qmlxmlhttprequest_abort));
- prototype.setProperty(QLatin1String("getResponseHeader"), engine->newFunction(qmlxmlhttprequest_getResponseHeader, 1));
- prototype.setProperty(QLatin1String("getAllResponseHeaders"), engine->newFunction(qmlxmlhttprequest_getAllResponseHeaders));
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("open"), NEWFUNCTION(qmlxmlhttprequest_open), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("setRequestHeader"), NEWFUNCTION(qmlxmlhttprequest_setRequestHeader), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("send"), NEWFUNCTION(qmlxmlhttprequest_send), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("abort"), NEWFUNCTION(qmlxmlhttprequest_abort), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("getResponseHeader"), NEWFUNCTION(qmlxmlhttprequest_getResponseHeader), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("getAllResponseHeaders"), NEWFUNCTION(qmlxmlhttprequest_getAllResponseHeaders), attributes);
// Read-only properties
- prototype.setProperty(QLatin1String("readyState"), engine->newFunction(qmlxmlhttprequest_readyState), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- prototype.setProperty(QLatin1String("status"), engine->newFunction(qmlxmlhttprequest_status), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- prototype.setProperty(QLatin1String("statusText"), engine->newFunction(qmlxmlhttprequest_statusText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- prototype.setProperty(QLatin1String("responseText"), engine->newFunction(qmlxmlhttprequest_responseText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- prototype.setProperty(QLatin1String("responseXML"), engine->newFunction(qmlxmlhttprequest_responseXML), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- prototype.setProperty(QLatin1String("onreadystatechange"), engine->newFunction(qmlxmlhttprequest_onreadystatechange), QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("readyState"), qmlxmlhttprequest_readyState, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
+ xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("status"),qmlxmlhttprequest_status, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
+ xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("statusText"),qmlxmlhttprequest_statusText, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
+ xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("responseText"),qmlxmlhttprequest_responseText, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
+ xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("responseXML"),qmlxmlhttprequest_responseXML, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
// State values
- prototype.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- prototype.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- prototype.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- prototype.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- prototype.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("UNSENT"), v8::Integer::New(0), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("OPENED"), v8::Integer::New(1), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("HEADERS_RECEIVED"), v8::Integer::New(2), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("LOADING"), v8::Integer::New(3), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("DONE"), v8::Integer::New(4), attributes);
// Constructor
- QScriptValue constructor = engine->newFunction(qmlxmlhttprequest_new, prototype);
- constructor.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- constructor.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- constructor.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- constructor.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- constructor.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- engine->globalObject().setProperty(QLatin1String("XMLHttpRequest"), constructor);
+ xmlhttprequest->Set(v8::String::New("UNSENT"), v8::Integer::New(0), attributes);
+ xmlhttprequest->Set(v8::String::New("OPENED"), v8::Integer::New(1), attributes);
+ xmlhttprequest->Set(v8::String::New("HEADERS_RECEIVED"), v8::Integer::New(2), attributes);
+ xmlhttprequest->Set(v8::String::New("LOADING"), v8::Integer::New(3), attributes);
+ xmlhttprequest->Set(v8::String::New("DONE"), v8::Integer::New(4), attributes);
+ engine->global()->Set(v8::String::New("XMLHttpRequest"), xmlhttprequest->GetFunction());
// DOM Exception
- QScriptValue domExceptionPrototype = engine->newObject();
- domExceptionPrototype.setProperty(QLatin1String("INDEX_SIZE_ERR"), INDEX_SIZE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("DOMSTRING_SIZE_ERR"), DOMSTRING_SIZE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("HIERARCHY_REQUEST_ERR"), HIERARCHY_REQUEST_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("WRONG_DOCUMENT_ERR"), WRONG_DOCUMENT_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("INVALID_CHARACTER_ERR"), INVALID_CHARACTER_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("NO_DATA_ALLOWED_ERR"), NO_DATA_ALLOWED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("NO_MODIFICATION_ALLOWED_ERR"), NO_MODIFICATION_ALLOWED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("NOT_FOUND_ERR"), NOT_FOUND_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("NOT_SUPPORTED_ERR"), NOT_SUPPORTED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("INUSE_ATTRIBUTE_ERR"), INUSE_ATTRIBUTE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("INVALID_STATE_ERR"), INVALID_STATE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("SYNTAX_ERR"), SYNTAX_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("INVALID_MODIFICATION_ERR"), INVALID_MODIFICATION_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("NAMESPACE_ERR"), NAMESPACE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("INVALID_ACCESS_ERR"), INVALID_ACCESS_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("VALIDATION_ERR"), VALIDATION_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("TYPE_MISMATCH_ERR"), TYPE_MISMATCH_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
-
- engine->globalObject().setProperty(QLatin1String("DOMException"), domExceptionPrototype);
+ v8::Local<v8::Object> domexception = v8::Object::New();
+ domexception->Set(v8::String::New("INDEX_SIZE_ERR"), v8::Integer::New(INDEX_SIZE_ERR), attributes);
+ domexception->Set(v8::String::New("DOMSTRING_SIZE_ERR"), v8::Integer::New(DOMSTRING_SIZE_ERR), attributes);
+ domexception->Set(v8::String::New("HIERARCHY_REQUEST_ERR"), v8::Integer::New(HIERARCHY_REQUEST_ERR), attributes);
+ domexception->Set(v8::String::New("WRONG_DOCUMENT_ERR"), v8::Integer::New(WRONG_DOCUMENT_ERR), attributes);
+ domexception->Set(v8::String::New("INVALID_CHARACTER_ERR"), v8::Integer::New(INVALID_CHARACTER_ERR), attributes);
+ domexception->Set(v8::String::New("NO_DATA_ALLOWED_ERR"), v8::Integer::New(NO_DATA_ALLOWED_ERR), attributes);
+ domexception->Set(v8::String::New("NO_MODIFICATION_ALLOWED_ERR"), v8::Integer::New(NO_MODIFICATION_ALLOWED_ERR), attributes);
+ domexception->Set(v8::String::New("NOT_FOUND_ERR"), v8::Integer::New(NOT_FOUND_ERR), attributes);
+ domexception->Set(v8::String::New("NOT_SUPPORTED_ERR"), v8::Integer::New(NOT_SUPPORTED_ERR), attributes);
+ domexception->Set(v8::String::New("INUSE_ATTRIBUTE_ERR"), v8::Integer::New(INUSE_ATTRIBUTE_ERR), attributes);
+ domexception->Set(v8::String::New("INVALID_STATE_ERR"), v8::Integer::New(INVALID_STATE_ERR), attributes);
+ domexception->Set(v8::String::New("SYNTAX_ERR"), v8::Integer::New(SYNTAX_ERR), attributes);
+ domexception->Set(v8::String::New("INVALID_MODIFICATION_ERR"), v8::Integer::New(INVALID_MODIFICATION_ERR), attributes);
+ domexception->Set(v8::String::New("NAMESPACE_ERR"), v8::Integer::New(NAMESPACE_ERR), attributes);
+ domexception->Set(v8::String::New("INVALID_ACCESS_ERR"), v8::Integer::New(INVALID_ACCESS_ERR), attributes);
+ domexception->Set(v8::String::New("VALIDATION_ERR"), v8::Integer::New(VALIDATION_ERR), attributes);
+ domexception->Set(v8::String::New("TYPE_MISMATCH_ERR"), v8::Integer::New(TYPE_MISMATCH_ERR), attributes);
+ engine->global()->Set(v8::String::New("DOMException"), domexception);
+
+ QDeclarativeXMLHttpRequestData *data = new QDeclarativeXMLHttpRequestData;
+ return data;
}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativexmlhttprequest_p.h b/src/declarative/qml/qdeclarativexmlhttprequest_p.h
index 5c09d648dd..a2082db59f 100644
--- a/src/declarative/qml/qdeclarativexmlhttprequest_p.h
+++ b/src/declarative/qml/qdeclarativexmlhttprequest_p.h
@@ -60,8 +60,10 @@
QT_BEGIN_NAMESPACE
-class QScriptEngine;
-void qt_add_qmlxmlhttprequest(QScriptEngine *engine);
+class QV8Engine;
+
+void *qt_add_qmlxmlhttprequest(QV8Engine *engine);
+void qt_rem_qmlxmlhttprequest(QV8Engine *engine, void *);
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qintrusivelist_p.h b/src/declarative/qml/qintrusivelist_p.h
index 459d051d07..b2a15a0a52 100644
--- a/src/declarative/qml/qintrusivelist_p.h
+++ b/src/declarative/qml/qintrusivelist_p.h
@@ -65,6 +65,7 @@ public:
inline QIntrusiveList();
inline ~QIntrusiveList();
+ inline bool isEmpty() const;
inline void insert(N *n);
inline void remove(N *n);
@@ -176,6 +177,12 @@ QIntrusiveList<N, member>::~QIntrusiveList()
}
template<class N, QIntrusiveListNode N::*member>
+bool QIntrusiveList<N, member>::isEmpty() const
+{
+ return __first == 0;
+}
+
+template<class N, QIntrusiveListNode N::*member>
void QIntrusiveList<N, member>::insert(N *n)
{
QIntrusiveListNode *nnode = &(n->*member);
diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri
index a69d52c8dc..7325cd8340 100644
--- a/src/declarative/qml/qml.pri
+++ b/src/declarative/qml/qml.pri
@@ -9,7 +9,6 @@ SOURCES += \
$$PWD/qdeclarativeproperty.cpp \
$$PWD/qdeclarativecomponent.cpp \
$$PWD/qdeclarativecontext.cpp \
- $$PWD/qdeclarativeinclude.cpp \
$$PWD/qdeclarativecustomparser.cpp \
$$PWD/qdeclarativepropertyvaluesource.cpp \
$$PWD/qdeclarativepropertyvalueinterceptor.cpp \
@@ -41,13 +40,6 @@ SOURCES += \
$$PWD/qdeclarativetypenotavailable.cpp \
$$PWD/qdeclarativetypenamecache.cpp \
$$PWD/qdeclarativescriptstring.cpp \
- $$PWD/qdeclarativeobjectscriptclass.cpp \
- $$PWD/qdeclarativescarceresourcescriptclass.cpp \
- $$PWD/qdeclarativecontextscriptclass.cpp \
- $$PWD/qdeclarativeglobalscriptclass.cpp \
- $$PWD/qdeclarativevaluetypescriptclass.cpp \
- $$PWD/qdeclarativetypenamescriptclass.cpp \
- $$PWD/qdeclarativelistscriptclass.cpp \
$$PWD/qdeclarativeworkerscript.cpp \
$$PWD/qdeclarativeimageprovider.cpp \
$$PWD/qdeclarativenetworkaccessmanagerfactory.cpp \
@@ -89,7 +81,6 @@ HEADERS += \
$$PWD/qdeclarativeinfo.h \
$$PWD/qdeclarativeproperty_p.h \
$$PWD/qdeclarativecontext_p.h \
- $$PWD/qdeclarativeinclude_p.h \
$$PWD/qdeclarativetypeloader_p.h \
$$PWD/qdeclarativelist.h \
$$PWD/qdeclarativelist_p.h \
@@ -113,13 +104,6 @@ HEADERS += \
$$PWD/qdeclarativetypenotavailable_p.h \
$$PWD/qdeclarativetypenamecache_p.h \
$$PWD/qdeclarativescriptstring.h \
- $$PWD/qdeclarativeobjectscriptclass_p.h \
- $$PWD/qdeclarativescarceresourcescriptclass_p.h \
- $$PWD/qdeclarativecontextscriptclass_p.h \
- $$PWD/qdeclarativeglobalscriptclass_p.h \
- $$PWD/qdeclarativevaluetypescriptclass_p.h \
- $$PWD/qdeclarativetypenamescriptclass_p.h \
- $$PWD/qdeclarativelistscriptclass_p.h \
$$PWD/qdeclarativeworkerscript_p.h \
$$PWD/qdeclarativeguard_p.h \
$$PWD/qdeclarativeimageprovider.h \
@@ -135,3 +119,4 @@ QT += sql
include(parser/parser.pri)
include(rewriter/rewriter.pri)
include(v4/v4.pri)
+include(v8/v8.pri)
diff --git a/src/declarative/qml/v4/qdeclarativev4bindings.cpp b/src/declarative/qml/v4/qdeclarativev4bindings.cpp
index 5ef293de89..0ee7d4dc7d 100644
--- a/src/declarative/qml/v4/qdeclarativev4bindings.cpp
+++ b/src/declarative/qml/v4/qdeclarativev4bindings.cpp
@@ -1492,7 +1492,8 @@ void QDeclarativeV4BindingsPrivate::run(int instrIndex, quint32 &executedBlocks,
QString str = QString::fromRawData(strdata, len);
- identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
+ // XXX not applicable in v8
+ // identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
}
QML_V4_END_INSTR(InitString, initstring)
diff --git a/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp b/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp
index 103d5ba0df..928fea4487 100644
--- a/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp
+++ b/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp
@@ -41,7 +41,6 @@
#include "qdeclarativev4irbuilder_p.h"
-#include <private/qdeclarativeglobalscriptclass_p.h> // For illegalNames
#include <private/qdeclarativeanchors_p_p.h> // For AnchorLine
#include <private/qsganchors_p_p.h> // For AnchorLine
#include <private/qdeclarativetypenamecache_p.h>
@@ -437,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->globalClass->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/notes.txt b/src/declarative/qml/v8/notes.txt
new file mode 100644
index 0000000000..ff5a289b7c
--- /dev/null
+++ b/src/declarative/qml/v8/notes.txt
@@ -0,0 +1,4 @@
+Removed backwards compatible imports - QTBUG-17518
+
+autotest print() taking objects that don't ToString()
+autotest QDeclarativeV8Function
diff --git a/src/declarative/qml/v8/qhashedstring.cpp b/src/declarative/qml/v8/qhashedstring.cpp
new file mode 100644
index 0000000000..4a23e3b7dd
--- /dev/null
+++ b/src/declarative/qml/v8/qhashedstring.cpp
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhashedstring_p.h"
+
+inline unsigned stringHash(const QChar* data, unsigned length)
+{
+ return v8::String::ComputeHash((uint16_t *)data, length);
+}
+
+void QHashedString::computeHash() const
+{
+ m_hash = stringHash(constData(), length());
+}
+
+void QHashedStringRef::computeHash() const
+{
+ m_hash = stringHash(m_data, m_length);
+}
+
+/*
+ A QHash has initially around pow(2, MinNumBits) buckets. For
+ example, if MinNumBits is 4, it has 17 buckets.
+*/
+const int MinNumBits = 4;
+
+/*
+ The prime_deltas array is a table of selected prime values, even
+ though it doesn't look like one. The primes we are using are 1,
+ 2, 5, 11, 17, 37, 67, 131, 257, ..., i.e. primes in the immediate
+ surrounding of a power of two.
+
+ The primeForNumBits() function returns the prime associated to a
+ power of two. For example, primeForNumBits(8) returns 257.
+*/
+
+static const uchar prime_deltas[] = {
+ 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
+ 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
+};
+
+static inline int primeForNumBits(int numBits)
+{
+ return (1 << numBits) + prime_deltas[numBits];
+}
+
+void QStringHashData::rehash()
+{
+ numBits = qMax(MinNumBits, numBits + 1);
+ numBuckets = primeForNumBits(numBits);
+
+ delete [] buckets;
+ buckets = new QStringHashNode *[numBuckets];
+ ::memset(buckets, 0, sizeof(QStringHashNode *) * numBuckets);
+
+ QStringHashNode *nodeList = nodes;
+ while (nodeList) {
+ int bucket = nodeList->key.hash() % numBuckets;
+ nodeList->next = buckets[bucket];
+ buckets[bucket] = nodeList;
+
+ nodeList = nodeList->nlist;
+ }
+}
+
diff --git a/src/declarative/qml/v8/qhashedstring_p.h b/src/declarative/qml/v8/qhashedstring_p.h
new file mode 100644
index 0000000000..acee03a9b5
--- /dev/null
+++ b/src/declarative/qml/v8/qhashedstring_p.h
@@ -0,0 +1,572 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHASHEDSTRING_P_H
+#define QHASHEDSTRING_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 <QtCore/qglobal.h>
+#include <QtCore/qstring.h>
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QHashedStringRef;
+class QHashedString : public QString
+{
+public:
+ inline QHashedString();
+ inline QHashedString(const QString &string);
+ inline QHashedString(const QString &string, quint32);
+ inline QHashedString(const QHashedString &string);
+
+ inline QHashedString &operator=(const QHashedString &string);
+ inline bool operator==(const QHashedString &string) const;
+ inline bool operator==(const QHashedStringRef &string) const;
+
+ inline quint32 hash() const;
+ inline quint32 existingHash() const;
+
+ static inline bool isUpper(const QChar &);
+private:
+ friend class QHashedStringRef;
+
+ void computeHash() const;
+ mutable quint32 m_hash;
+};
+
+class QHashedStringRef
+{
+public:
+ inline QHashedStringRef();
+ inline QHashedStringRef(const QString &);
+ inline QHashedStringRef(const QChar *, int);
+ inline QHashedStringRef(const QChar *, int, quint32);
+ inline QHashedStringRef(const QHashedString &);
+ inline QHashedStringRef(const QHashedStringRef &);
+
+ inline bool operator==(const QHashedString &string) const;
+ inline bool operator==(const QHashedStringRef &string) const;
+
+ inline quint32 hash() const;
+
+ inline const QChar *constData() const;
+ inline quint32 length() const;
+ inline bool startsWithUpper() const;
+
+private:
+ friend class QHashedString;
+
+ void computeHash() const;
+
+ const QChar *m_data;
+ quint32 m_length;
+ mutable quint32 m_hash;
+};
+
+class QStringHashData;
+class QStringHashNode
+{
+public:
+ QStringHashNode(const QHashedString &key)
+ : nlist(0), next(0), key(key) {}
+
+ QStringHashNode *nlist;
+ QStringHashNode *next;
+ QHashedString key;
+};
+
+struct QStringHashData
+{
+public:
+ QStringHashData()
+ : nodes(0), buckets(0), numBuckets(0), size(0), numBits(0) {}
+
+ QStringHashNode *nodes;
+ QStringHashNode **buckets;
+ int numBuckets;
+ int size;
+ short numBits;
+
+ void rehash();
+};
+
+template<class T>
+class QStringHash
+{
+private:
+ struct Node : public QStringHashNode {
+ Node(const QHashedString &key, const T &value) : QStringHashNode(key), value(value) {}
+ T value;
+ };
+
+ QStringHashData data;
+
+ inline Node *findNode(const QHashedStringRef &) const;
+ inline Node *findNode(v8::Handle<v8::String> &, quint32) const;
+ Node *createNode(const QHashedString &, const T &);
+
+public:
+ inline QStringHash();
+ inline QStringHash(const QStringHash &);
+ inline ~QStringHash();
+
+ QStringHash &operator=(const QStringHash<T> &);
+
+ inline bool isEmpty() const;
+ inline void clear();
+ inline int count() const;
+
+ inline void insert(const QString &, const T &);
+ inline void insert(const QHashedString &, const T &);
+ inline void insert(const QHashedStringRef &, const T &);
+
+ inline T *value(const QString &) const;
+ inline T *value(const QHashedString &) const;
+ inline T *value(const QHashedStringRef &) const;
+ inline T *value(v8::Handle<v8::String> &) const;
+ inline T *value(v8::Handle<v8::String> &, quint32 hash) const;
+
+ inline bool contains(const QString &) const;
+ inline bool contains(const QHashedString &) const;
+ inline bool contains(const QHashedStringRef &) const;
+
+ T &operator[](const QString &);
+ T &operator[](const QHashedString &);
+ T &operator[](const QHashedStringRef &);
+
+ class ConstIterator {
+ public:
+ ConstIterator() : n(0) {}
+ ConstIterator(Node *n) : n(n) {}
+
+ ConstIterator &operator++() { n = (Node *)n->nlist; return *this; }
+ bool operator==(const ConstIterator &o) const { return n == o.n; }
+ bool operator!=(const ConstIterator &o) const { return n != o.n; }
+
+ const QHashedString &key() const { return n->key; }
+ const T &value() const { return n->value; }
+ const T &operator*() const { return n->value; }
+ private:
+ Node *n;
+ };
+
+ ConstIterator begin() const { return ConstIterator((Node *)data.nodes); }
+ ConstIterator end() const { return ConstIterator(); }
+};
+
+template<class T>
+QStringHash<T>::QStringHash()
+{
+}
+
+template<class T>
+QStringHash<T>::QStringHash(const QStringHash<T> &other)
+: data(other.data)
+{
+ data.nodes = 0;
+ data.buckets = 0;
+
+ QStringHashNode *n = other.data.nodes;
+ while (n) {
+ Node *o = (Node *)n;
+ Node *mynode = new Node(o->key, o->value);
+ mynode->nlist = data.nodes;
+ data.nodes = mynode;
+ n = o->nlist;
+ }
+
+ data.rehash();
+}
+
+template<class T>
+QStringHash<T> &QStringHash<T>::operator=(const QStringHash<T> &other)
+{
+ if (&other == this)
+ return *this;
+
+ clear();
+ data = other.data;
+ data.nodes = 0;
+ data.buckets = 0;
+
+ QStringHashNode *n = other.data.nodes;
+ while (n) {
+ Node *o = (Node *)n;
+ Node *mynode = new Node(o->key, o->value);
+ mynode->nlist = data.nodes;
+ data.nodes = mynode;
+ n = o->nlist;
+ }
+
+ data.rehash();
+
+ return *this;
+}
+
+template<class T>
+QStringHash<T>::~QStringHash()
+{
+ clear();
+}
+
+template<class T>
+void QStringHash<T>::clear()
+{
+ QStringHashNode *n = data.nodes;
+ while (n) {
+ Node *o = (Node *)n;
+ n = n->nlist;
+ delete o;
+ }
+
+ delete [] data.buckets;
+
+ data = QStringHashData();
+}
+
+template<class T>
+bool QStringHash<T>::isEmpty() const
+{
+ return data.nodes == 0;
+}
+
+template<class T>
+int QStringHash<T>::count() const
+{
+ return data.size;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::createNode(const QHashedString &key, const T &value)
+{
+ if (data.size == data.numBuckets)
+ data.rehash();
+
+ Node *n = new Node(key, value);
+ n->nlist = data.nodes;
+ data.nodes = n;
+
+ int bucket = key.hash() % data.numBuckets;
+ n->next = data.buckets[bucket];
+ data.buckets[bucket] = n;
+
+ data.size++;
+
+ return n;
+}
+
+template<class T>
+void QStringHash<T>::insert(const QString &key, const T &value)
+{
+ QHashedStringRef ch(key);
+ Node *n = findNode(key);
+ if (n) n->value = value;
+ else createNode(QHashedString(key, ch.hash()), value);
+}
+
+template<class T>
+void QStringHash<T>::insert(const QHashedString &key, const T &value)
+{
+ Node *n = findNode(key);
+ if (n) n->value = value;
+ else createNode(key, value);
+}
+
+template<class T>
+void QStringHash<T>::insert(const QHashedStringRef &key, const T &value)
+{
+ Node *n = findNode(key);
+ if (n) n->value = value;
+ else createNode(key, value);
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedStringRef &string) const
+{
+ QStringHashNode *node = 0;
+ if (data.numBuckets) {
+ node = data.buckets[string.hash() % data.numBuckets];
+ while (node && !(node->key == string))
+ node = node->next;
+ }
+
+ return (Node *)node;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::findNode(v8::Handle<v8::String> &string, quint32 hash) const
+{
+ QStringHashNode *node = 0;
+ if (data.numBuckets) {
+ node = data.buckets[hash % data.numBuckets];
+ int length = string->Length();
+ while (node && (length != node->key.length() || !string->Equals((uint16_t*)node->key.constData(), length)))
+ node = node->next;
+ }
+
+ return (Node *)node;
+}
+
+template<class T>
+T *QStringHash<T>::value(const QString &key) const
+{
+ Node *n = findNode(key);
+ return n?&n->value:0;
+}
+
+template<class T>
+T *QStringHash<T>::value(const QHashedString &key) const
+{
+ Node *n = findNode(key);
+ return n?&n->value:0;
+}
+
+template<class T>
+T *QStringHash<T>::value(const QHashedStringRef &key) const
+{
+ Node *n = findNode(key);
+ return n?&n->value:0;
+}
+
+template<class T>
+T *QStringHash<T>::value(v8::Handle<v8::String> &key) const
+{
+ return value(key, (quint32)key->Hash());
+}
+
+template<class T>
+T *QStringHash<T>::value(v8::Handle<v8::String> &key, quint32 hash) const
+{
+ Node *n = findNode(key, hash);
+ return n?&n->value:0;
+}
+
+template<class T>
+bool QStringHash<T>::contains(const QString &s) const
+{
+ return 0 != value(s);
+}
+
+template<class T>
+bool QStringHash<T>::contains(const QHashedString &s) const
+{
+ return 0 != value(s);
+}
+template<class T>
+bool QStringHash<T>::contains(const QHashedStringRef &s) const
+{
+ return 0 != value(s);
+}
+
+template<class T>
+T &QStringHash<T>::operator[](const QString &key)
+{
+ QHashedStringRef cs(key);
+ Node *n = findNode(cs);
+ if (n) return n->value;
+ else return createNode(QHashedString(key, cs.hash()), T())->value;
+}
+
+template<class T>
+T &QStringHash<T>::operator[](const QHashedString &key)
+{
+ Node *n = findNode(key);
+ if (n) return n->value;
+ else return createNode(key)->value;
+}
+
+template<class T>
+T &QStringHash<T>::operator[](const QHashedStringRef &key)
+{
+ Node *n = findNode(key);
+ if (n) return n->value;
+ else return createNode(key)->value;
+}
+
+inline uint qHash(const QHashedString &string)
+{
+ return uint(string.hash());
+}
+
+inline uint qHash(const QHashedStringRef &string)
+{
+ return uint(string.hash());
+}
+
+QHashedString::QHashedString()
+: QString(), m_hash(0)
+{
+}
+
+QHashedString::QHashedString(const QString &string)
+: QString(string), m_hash(0)
+{
+}
+
+QHashedString::QHashedString(const QString &string, quint32 hash)
+: QString(string), m_hash(hash)
+{
+}
+
+QHashedString::QHashedString(const QHashedString &string)
+: QString(string), m_hash(string.m_hash)
+{
+}
+
+QHashedString &QHashedString::operator=(const QHashedString &string)
+{
+ static_cast<QString &>(*this) = string;
+ m_hash = string.m_hash;
+ return *this;
+}
+
+bool QHashedString::operator==(const QHashedString &string) const
+{
+ return (string.m_hash == m_hash || !string.m_hash || !m_hash) &&
+ static_cast<const QString &>(*this) == static_cast<const QString &>(string);
+}
+
+bool QHashedString::operator==(const QHashedStringRef &string) const
+{
+ return (uint)length() == string.m_length &&
+ (string.m_hash == m_hash || !string.m_hash || !m_hash) &&
+ 0 == ::memcmp(constData(), string.m_data, string.m_length * sizeof(QChar));
+}
+
+quint32 QHashedString::hash() const
+{
+ if (!m_hash) computeHash();
+ return m_hash;
+}
+
+quint32 QHashedString::existingHash() const
+{
+ return m_hash;
+}
+
+bool QHashedString::isUpper(const QChar &qc)
+{
+ ushort c = qc.unicode();
+ // Optimize for _, a-z and A-Z.
+ return ((c != '_' ) && (!(c >= 'a' && c <= 'z')) &&
+ ((c >= 'A' && c <= 'Z') || QChar::category(c) == QChar::Letter_Uppercase));
+}
+
+QHashedStringRef::QHashedStringRef()
+: m_data(0), m_length(0), m_hash(0)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QString &str)
+: m_data(str.constData()), m_length(str.length()), m_hash(0)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QChar *data, int length)
+: m_data(data), m_length(length), m_hash(0)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QChar *data, int length, quint32 hash)
+: m_data(data), m_length(length), m_hash(hash)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QHashedString &string)
+: m_data(string.constData()), m_length(string.length()), m_hash(string.m_hash)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QHashedStringRef &string)
+: m_data(string.m_data), m_length(string.m_length), m_hash(string.m_hash)
+{
+}
+
+bool QHashedStringRef::operator==(const QHashedString &string) const
+{
+ return m_length == (uint)string.length() &&
+ (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
+ 0 == ::memcmp(string.constData(), m_data, m_length * sizeof(QChar));
+}
+
+bool QHashedStringRef::operator==(const QHashedStringRef &string) const
+{
+ return m_length == string.m_length &&
+ (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
+ 0 == ::memcmp(string.m_data, m_data, m_length * sizeof(QChar));
+}
+
+const QChar *QHashedStringRef::constData() const
+{
+ return m_data;
+}
+
+quint32 QHashedStringRef::length() const
+{
+ return m_length;
+}
+
+bool QHashedStringRef::startsWithUpper() const
+{
+ if (m_length < 1) return false;
+ return QHashedString::isUpper(m_data[0]);
+}
+
+quint32 QHashedStringRef::hash() const
+{
+ if (!m_hash) computeHash();
+ return m_hash;
+}
+
+QT_END_NAMESPACE
+
+#endif // QHASHEDSTRING_P_H
diff --git a/src/declarative/qml/v8/qv8_p.h b/src/declarative/qml/v8/qv8_p.h
new file mode 100644
index 0000000000..6aeb6f6458
--- /dev/null
+++ b/src/declarative/qml/v8/qv8_p.h
@@ -0,0 +1 @@
+#include "../../../3rdparty/v8/include/v8.h"
diff --git a/src/declarative/qml/v8/qv8contextwrapper.cpp b/src/declarative/qml/v8/qv8contextwrapper.cpp
new file mode 100644
index 0000000000..f0e52b1d64
--- /dev/null
+++ b/src/declarative/qml/v8/qv8contextwrapper.cpp
@@ -0,0 +1,432 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8contextwrapper_p.h"
+#include "qv8engine_p.h"
+
+#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativecontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static QString internal(QLatin1String("You've stumbled onto an internal implementation detail "
+ "that should never have been exposed."));
+
+class QV8ContextResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(ContextType);
+
+public:
+ QV8ContextResource(QV8Engine *engine, QDeclarativeContextData *context, QObject *scopeObject);
+ ~QV8ContextResource();
+
+ inline QDeclarativeContextData *getContext() const;
+
+ QDeclarativeGuard<QObject> scopeObject;
+
+ quint32 hasSubContexts:1;
+ quint32 ownsContext:1;
+ quint32 readOnly:1;
+ quint32 dummy:29;
+
+ QObject *secondaryScope;
+
+ // This is a pretty horrible hack, and an abuse of external strings. When we create a
+ // sub-context (a context created by a Qt.include() in an external javascript file),
+ // we pass a specially crafted SubContext external string as the v8::Script::Data() to
+ // the script, which contains a pointer to the context. We can then access the
+ // v8::Script::Data() later on to resolve names and URLs against the sub-context instead
+ // of the main outer context.
+ struct SubContext : public v8::String::ExternalStringResource {
+ SubContext(QDeclarativeContextData *context) : context(context) {}
+ QDeclarativeGuardedContextData context;
+
+ virtual const uint16_t* data() const { return (const uint16_t *)internal.constData(); }
+ virtual size_t length() const { return internal.length(); }
+ };
+
+private:
+ QDeclarativeGuardedContextData context;
+};
+
+QV8ContextResource::QV8ContextResource(QV8Engine *engine, QDeclarativeContextData *context, QObject *scopeObject)
+: QV8ObjectResource(engine), scopeObject(scopeObject), hasSubContexts(false), ownsContext(false),
+ readOnly(true), secondaryScope(0), context(context)
+{
+}
+
+QV8ContextResource::~QV8ContextResource()
+{
+ if (ownsContext && context)
+ context->destroy();
+}
+
+// Returns the context, including resolving a subcontext
+QDeclarativeContextData *QV8ContextResource::getContext() const
+{
+ if (!hasSubContexts)
+ return context;
+
+ v8::Local<v8::Value> callingdata = v8::Context::GetCallingScriptData();
+ if (callingdata.IsEmpty() || !callingdata->IsString())
+ return context;
+
+ v8::Local<v8::String> callingstring = callingdata->ToString();
+ Q_ASSERT(callingstring->IsExternal());
+ Q_ASSERT(callingstring->GetExternalStringResource());
+
+ SubContext *sc = static_cast<SubContext *>(callingstring->GetExternalStringResource());
+ return sc->context;
+}
+
+QV8ContextWrapper::QV8ContextWrapper()
+: m_engine(0)
+{
+}
+
+QV8ContextWrapper::~QV8ContextWrapper()
+{
+}
+
+void QV8ContextWrapper::destroy()
+{
+ qPersistentDispose(m_urlConstructor);
+ qPersistentDispose(m_constructor);
+}
+
+void QV8ContextWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
+ m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(NullGetter, NullSetter);
+ m_urlConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+}
+
+v8::Local<v8::Object> QV8ContextWrapper::qmlScope(QDeclarativeContextData *ctxt, QObject *scope)
+{
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8ContextResource *r = new QV8ContextResource(m_engine, ctxt, scope);
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+v8::Local<v8::Object> QV8ContextWrapper::urlScope(const QUrl &url)
+{
+ QDeclarativeContextData *context = new QDeclarativeContextData;
+ context->url = url;
+ context->isInternal = true;
+ context->isJSContext = true;
+
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv = m_urlConstructor->NewInstance();
+ QV8ContextResource *r = new QV8ContextResource(m_engine, context, 0);
+ r->ownsContext = true;
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+void QV8ContextWrapper::setReadOnly(v8::Handle<v8::Object> qmlglobal, bool readOnly)
+{
+ QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(qmlglobal);
+ Q_ASSERT(resource);
+ resource->readOnly = readOnly;
+}
+
+void QV8ContextWrapper::addSubContext(v8::Handle<v8::Object> qmlglobal, v8::Handle<v8::Script> script,
+ QDeclarativeContextData *ctxt)
+{
+ QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(qmlglobal);
+ Q_ASSERT(resource);
+ resource->hasSubContexts = true;
+ script->SetData(v8::String::NewExternal(new QV8ContextResource::SubContext(ctxt)));
+}
+
+QObject *QV8ContextWrapper::setSecondaryScope(v8::Handle<v8::Object> ctxt, QObject *scope)
+{
+ QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(ctxt);
+ if (!resource) return 0;
+
+ QObject *rv = resource->secondaryScope;
+ resource->secondaryScope = scope;
+ return rv;
+}
+
+QDeclarativeContextData *QV8ContextWrapper::callingContext()
+{
+ v8::Local<v8::Object> qmlglobal = v8::Context::GetCallingQmlGlobal();
+ if (qmlglobal.IsEmpty()) return 0;
+
+ QV8ContextResource *r = v8_resource_cast<QV8ContextResource>(qmlglobal);
+ return r?r->getContext():0;
+}
+
+QDeclarativeContextData *QV8ContextWrapper::context(v8::Handle<v8::Value> value)
+{
+ if (!value->IsObject())
+ return 0;
+
+ v8::Handle<v8::Object> qmlglobal = v8::Handle<v8::Object>::Cast(value);
+ QV8ContextResource *r = v8_resource_cast<QV8ContextResource>(qmlglobal);
+ return r?r->getContext():0;
+}
+
+v8::Handle<v8::Value> QV8ContextWrapper::NullGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(info.This());
+
+ if (!resource)
+ return v8::Undefined();
+
+ QV8Engine *engine = resource->engine;
+
+ QString error = QLatin1String("Can't find variable: ") + engine->toString(property);
+ v8::ThrowException(v8::Exception::ReferenceError(engine->toString(error)));
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(info.This());
+
+ if (!resource)
+ return v8::Undefined();
+
+ // Its possible we could delay the calculation of the "actual" context (in the case
+ // of sub contexts) until it is definately needed.
+ QDeclarativeContextData *context = resource->getContext();
+
+ if (!context)
+ return v8::Undefined();
+
+ // Search type (attached property/enum/imported scripts) names
+ // Secondary scope object
+ // while (context) {
+ // Search context properties
+ // Search scope object
+ // Search context object
+ // context = context->parent
+ // }
+
+ QV8Engine *engine = resource->engine;
+ QObject *scopeObject = resource->scopeObject;
+
+ if (context->imports && QV8Engine::startsWithUpper(property)) {
+ // Search for attached properties, enums and imported scripts
+ QDeclarativeTypeNameCache::Data *data = context->imports->data(property);
+
+ if (data) {
+ if (data->importedScriptIndex != -1) {
+ int index = data->importedScriptIndex;
+ if (index < context->importedScripts.count())
+ return context->importedScripts.at(index);
+ else
+ return v8::Undefined();
+ } else if (data->type) {
+ return engine->typeWrapper()->newObject(scopeObject, data->type);
+ } else if (data->typeNamespace) {
+ return engine->typeWrapper()->newObject(scopeObject, data->typeNamespace);
+ }
+ Q_ASSERT(!"Unreachable");
+ }
+
+ // Fall through
+ }
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine());
+ QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
+
+ if (resource->secondaryScope) {
+ v8::Handle<v8::Value> result = qobjectWrapper->getProperty(resource->secondaryScope, property,
+ QV8QObjectWrapper::IgnoreRevision);
+ if (!result.IsEmpty()) return result;
+ }
+
+ while (context) {
+ // Search context properties
+ if (context->propertyNames) {
+ int propertyIdx = context->propertyNames->value(property);
+
+ if (propertyIdx != -1) {
+ typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty;
+
+ if (propertyIdx < context->idValueCount) {
+
+ if (ep->captureProperties)
+ ep->capturedProperties << CapturedProperty(&context->idValues[propertyIdx].bindings);
+
+ return engine->newQObject(context->idValues[propertyIdx]);
+ } else {
+
+ QDeclarativeContextPrivate *cp = context->asQDeclarativeContextPrivate();
+
+ if (ep->captureProperties)
+ ep->capturedProperties << CapturedProperty(context->asQDeclarativeContext(), -1,
+ propertyIdx + cp->notifyIndex);
+
+ const QVariant &value = cp->propertyValues.at(propertyIdx);
+ if (value.userType() == qMetaTypeId<QList<QObject*> >()) {
+ QDeclarativeListProperty<QObject> prop(context->asQDeclarativeContext(), (void*)propertyIdx,
+ 0,
+ QDeclarativeContextPrivate::context_count,
+ QDeclarativeContextPrivate::context_at);
+ return engine->listWrapper()->newList(prop, qMetaTypeId<QDeclarativeListProperty<QObject> >());
+ } else {
+ return engine->fromVariant(cp->propertyValues.at(propertyIdx));
+ }
+ }
+ }
+ }
+
+ // Search scope object
+ if (scopeObject) {
+ v8::Handle<v8::Value> result = qobjectWrapper->getProperty(scopeObject, property,
+ QV8QObjectWrapper::CheckRevision);
+ if (!result.IsEmpty()) return result;
+ }
+ scopeObject = 0;
+
+
+ // Search context object
+ if (context->contextObject) {
+ v8::Handle<v8::Value> result = qobjectWrapper->getProperty(context->contextObject, property,
+ QV8QObjectWrapper::CheckRevision);
+ if (!result.IsEmpty()) return result;
+ }
+
+ context = context->parent;
+ }
+
+ QString error = QLatin1String("Can't find variable: ") + engine->toString(property);
+ v8::ThrowException(v8::Exception::ReferenceError(engine->toString(error)));
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8ContextWrapper::NullSetter(v8::Local<v8::String> property,
+ v8::Local<v8::Value>,
+ const v8::AccessorInfo &info)
+{
+ QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(info.This());
+
+ if (!resource)
+ return v8::Handle<v8::Value>();
+
+ QV8Engine *engine = resource->engine;
+
+ if (!resource->readOnly) {
+ return v8::Handle<v8::Value>();
+ } else {
+ QString error = QLatin1String("Invalid write to global property \"") + engine->toString(property) +
+ QLatin1String("\"");
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return v8::Handle<v8::Value>();
+ }
+}
+
+v8::Handle<v8::Value> QV8ContextWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(info.This());
+
+ if (!resource)
+ return v8::Undefined();
+
+ // Its possible we could delay the calculation of the "actual" context (in the case
+ // of sub contexts) until it is definately needed.
+ QDeclarativeContextData *context = resource->getContext();
+
+ if (!context)
+ return v8::Undefined();
+
+ // See QV8ContextWrapper::Getter for resolution order
+
+ QV8Engine *engine = resource->engine;
+ QObject *scopeObject = resource->scopeObject;
+
+ QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
+
+ // Search scope object
+ if (resource->secondaryScope && qobjectWrapper->setProperty(resource->secondaryScope, property, value,
+ QV8QObjectWrapper::IgnoreRevision))
+ return value;
+
+ while (context) {
+ // Search context properties
+ if (context->propertyNames && -1 != context->propertyNames->value(property))
+ return value;
+
+ // Search scope object
+ if (scopeObject &&
+ qobjectWrapper->setProperty(scopeObject, property, value, QV8QObjectWrapper::CheckRevision))
+ return value;
+ scopeObject = 0;
+
+ // Search context object
+ if (context->contextObject &&
+ qobjectWrapper->setProperty(context->contextObject, property, value, QV8QObjectWrapper::CheckRevision))
+ return value;
+
+ context = context->parent;
+ }
+
+ if (!resource->readOnly) {
+ return v8::Handle<v8::Value>();
+ } else {
+ QString error = QLatin1String("Invalid write to global property \"") + engine->toString(property) +
+ QLatin1String("\"");
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return v8::Undefined();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativecontextscriptclass_p.h b/src/declarative/qml/v8/qv8contextwrapper_p.h
index 04d3e9a4d5..12e01bab76 100644
--- a/src/declarative/qml/qdeclarativecontextscriptclass_p.h
+++ b/src/declarative/qml/v8/qv8contextwrapper_p.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QDECLARATIVECONTEXTSCRIPTCLASS_P_H
-#define QDECLARATIVECONTEXTSCRIPTCLASS_P_H
+#ifndef QV8CONTEXTWRAPPER_P_H
+#define QV8CONTEXTWRAPPER_P_H
//
// W A R N I N G
@@ -53,54 +53,59 @@
// We mean it.
//
-#include "private/qdeclarativetypenamecache_p.h"
-#include <private/qscriptdeclarativeclass_p.h>
+#include <QtCore/qglobal.h>
+#include <private/qv8_p.h>
QT_BEGIN_NAMESPACE
-class QDeclarativeEngine;
-class QDeclarativeContext;
+class QUrl;
+class QObject;
+class QV8Engine;
class QDeclarativeContextData;
-class QDeclarativeContextScriptClass : public QScriptDeclarativeClass
+class QV8ContextWrapper
{
public:
- QDeclarativeContextScriptClass(QDeclarativeEngine *);
- ~QDeclarativeContextScriptClass();
+ QV8ContextWrapper();
+ ~QV8ContextWrapper();
- QScriptValue newContext(QDeclarativeContextData *, QObject * = 0);
- QScriptValue newUrlContext(QDeclarativeContextData *, QObject *, const QString &);
- QScriptValue newUrlContext(const QString &);
- QScriptValue newSharedContext();
+ void init(QV8Engine *);
+ void destroy();
- QDeclarativeContextData *contextFromValue(const QScriptValue &);
- QUrl urlFromValue(const QScriptValue &);
+ v8::Local<v8::Object> qmlScope(QDeclarativeContextData *ctxt, QObject *scope);
+ v8::Local<v8::Object> urlScope(const QUrl &);
- QObject *setOverrideObject(QScriptValue &, QObject *);
+ void setReadOnly(v8::Handle<v8::Object>, bool);
-protected:
- virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
- QScriptClass::QueryFlags flags);
- virtual Value property(Object *, const Identifier &);
- virtual void setProperty(Object *, const Identifier &name, const QScriptValue &);
+ void addSubContext(v8::Handle<v8::Object> qmlglobal, v8::Handle<v8::Script>,
+ QDeclarativeContextData *ctxt);
-private:
- QScriptClass::QueryFlags queryProperty(QDeclarativeContextData *, QObject *scopeObject,
- const Identifier &,
- QScriptClass::QueryFlags flags,
- bool includeTypes);
-
- QDeclarativeEngine *engine;
+ // XXX We only use the secondary scope to pass the "arguments" of the signal to
+ // on<SignalName> properties. Instead of doing this we should rewrite the
+ // JavaScript closure function to accept these arguments as named parameters.
+ // To keep backwards compatibility we have to check that the argument names are
+ // not members of the QV8Engine::illegalNames() set.
+ QObject *setSecondaryScope(v8::Handle<v8::Object>, QObject *);
- QObject *lastScopeObject;
- QDeclarativeContextData *lastContext;
- QDeclarativeTypeNameCache::Data *lastData;
- int lastPropertyIndex;
- QScriptValue lastFunction;
-
- uint m_id;
+ QDeclarativeContextData *callingContext();
+ QDeclarativeContextData *context(v8::Handle<v8::Value>);
+private:
+ static v8::Handle<v8::Value> NullGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> NullSetter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+
+ QV8Engine *m_engine;
+ v8::Persistent<v8::Function> m_constructor;
+ v8::Persistent<v8::Function> m_urlConstructor;
};
QT_END_NAMESPACE
-#endif // QDECLARATIVECONTEXTSCRIPTCLASS_P_H
+#endif // QV8CONTEXTWRAPPER_P_H
diff --git a/src/declarative/qml/v8/qv8engine.cpp b/src/declarative/qml/v8/qv8engine.cpp
new file mode 100644
index 0000000000..3ddac007d2
--- /dev/null
+++ b/src/declarative/qml/v8/qv8engine.cpp
@@ -0,0 +1,1479 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8engine_p.h"
+
+#include "qv8contextwrapper_p.h"
+#include "qv8include_p.h"
+#include "../../../3rdparty/javascriptcore/DateMath.h"
+
+#include <private/qdeclarativelist_p.h>
+#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativecomponent_p.h>
+#include <private/qdeclarativestringconverters_p.h>
+
+#include <QtDeclarative/qdeclarativecomponent.h>
+
+#include <QtCore/qstring.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qcryptographichash.h>
+#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>
+
+// 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
+
+QV8Engine::QV8Engine()
+: m_xmlHttpRequestData(0), m_sqlDatabaseData(0), m_listModelData(0)
+{
+}
+
+QV8Engine::~QV8Engine()
+{
+ for (int ii = 0; ii < m_extensionData.count(); ++ii)
+ delete m_extensionData[ii];
+ m_extensionData.clear();
+
+ qt_rem_qmlsqldatabase(this, m_sqlDatabaseData);
+ m_sqlDatabaseData = 0;
+ qt_rem_qmlxmlhttprequest(this, m_xmlHttpRequestData);
+ m_xmlHttpRequestData = 0;
+ delete m_listModelData;
+ m_listModelData = 0;
+
+ qPersistentDispose(m_freezeObject);
+ qPersistentDispose(m_getOwnPropertyNames);
+ m_valueTypeWrapper.destroy();
+ m_variantWrapper.destroy();
+ m_listWrapper.destroy();
+ m_typeWrapper.destroy();
+ 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);
+
+ 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));
+ }
+
+ initializeGlobal(m_context->Global());
+ freezeObject(m_context->Global());
+}
+
+QString QV8Engine::toStringStatic(v8::Handle<v8::Value> jsstr)
+{
+ return toStringStatic(jsstr->ToString());
+}
+
+QString QV8Engine::toStringStatic(v8::Handle<v8::String> jsstr)
+{
+ QString qstr;
+ qstr.resize(jsstr->Length());
+ jsstr->Write((uint16_t*)qstr.data());
+ return qstr;
+}
+
+QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint)
+{
+ if (value.IsEmpty())
+ return QVariant();
+
+ if (value->IsObject()) {
+ QV8ObjectResource *r = (QV8ObjectResource *)value->ToObject()->GetExternalResource();
+ if (r) {
+ switch (r->resourceType()) {
+ case QV8ObjectResource::ContextType:
+ case QV8ObjectResource::TypeType:
+ case QV8ObjectResource::XMLHttpRequestType:
+ case QV8ObjectResource::DOMNodeType:
+ case QV8ObjectResource::SQLDatabaseType:
+ case QV8ObjectResource::ListModelType:
+ case QV8ObjectResource::Context2DType:
+ return QVariant();
+ case QV8ObjectResource::QObjectType:
+ return qVariantFromValue<QObject *>(m_qobjectWrapper.toQObject(r));
+ case QV8ObjectResource::ListType:
+ return m_listWrapper.toVariant(r);
+ case QV8ObjectResource::VariantType:
+ return m_variantWrapper.toVariant(r);
+ case QV8ObjectResource::ValueTypeType:
+ return m_valueTypeWrapper.toVariant(r);
+ }
+ }
+ }
+
+ if (typeHint == qMetaTypeId<QList<QObject *> >() && value->IsArray()) {
+ v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value);
+
+ QList<QObject *> list;
+ uint32_t length = array->Length();
+ for (uint32_t ii = 0; ii < length; ++ii) {
+ v8::Local<v8::Value> arrayItem = array->Get(ii);
+ if (arrayItem->IsObject()) {
+ list << toQObject(arrayItem->ToObject());
+ } else {
+ list << 0;
+ }
+ }
+
+ return qVariantFromValue<QList<QObject*> >(list);
+ }
+
+ return toBasicVariant(value);
+}
+
+static v8::Handle<v8::Array> arrayFromStringList(QV8Engine *engine, const QStringList &list)
+{
+ v8::Context::Scope scope(engine->context());
+ v8::Local<v8::Array> result = v8::Array::New(list.count());
+ for (int ii = 0; ii < list.count(); ++ii)
+ result->Set(ii, engine->toString(list.at(ii)));
+ return result;
+}
+
+static v8::Handle<v8::Array> arrayFromVariantList(QV8Engine *engine, const QVariantList &list)
+{
+ v8::Context::Scope scope(engine->context());
+ v8::Local<v8::Array> result = v8::Array::New(list.count());
+ for (int ii = 0; ii < list.count(); ++ii)
+ result->Set(ii, engine->fromVariant(list.at(ii)));
+ return result;
+}
+
+static v8::Handle<v8::Object> objectFromVariantMap(QV8Engine *engine, const QVariantMap &map)
+{
+ v8::Context::Scope scope(engine->context());
+ v8::Local<v8::Object> object = v8::Object::New();
+ for (QVariantMap::ConstIterator iter = map.begin(); iter != map.end(); ++iter)
+ object->Set(engine->toString(iter.key()), engine->fromVariant(iter.value()));
+ return object;
+}
+
+Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
+
+// 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> regexpFromQRegExp(QV8Engine *engine, 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(engine->toString(pattern), static_cast<v8::RegExp::Flags>(flags));
+}
+
+v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant)
+{
+ int type = variant.userType();
+ const void *ptr = variant.constData();
+
+ if (type < QMetaType::User) {
+ switch (QMetaType::Type(type)) {
+ case QMetaType::Void:
+ return v8::Undefined();
+ case QMetaType::Bool:
+ return v8::Boolean::New(*reinterpret_cast<const bool*>(ptr));
+ case QMetaType::Int:
+ return v8::Integer::New(*reinterpret_cast<const int*>(ptr));
+ case QMetaType::UInt:
+ return v8::Integer::NewFromUnsigned(*reinterpret_cast<const uint*>(ptr));
+ case QMetaType::LongLong:
+ return v8::Number::New(*reinterpret_cast<const qlonglong*>(ptr));
+ case QMetaType::ULongLong:
+ return v8::Number::New(*reinterpret_cast<const qulonglong*>(ptr));
+ case QMetaType::Double:
+ return v8::Number::New(*reinterpret_cast<const double*>(ptr));
+ case QMetaType::QString:
+ return m_stringWrapper.toString(*reinterpret_cast<const QString*>(ptr));
+ case QMetaType::Float:
+ return v8::Number::New(*reinterpret_cast<const float*>(ptr));
+ case QMetaType::Short:
+ return v8::Integer::New(*reinterpret_cast<const short*>(ptr));
+ case QMetaType::UShort:
+ return v8::Integer::NewFromUnsigned(*reinterpret_cast<const unsigned short*>(ptr));
+ case QMetaType::Char:
+ return v8::Integer::New(*reinterpret_cast<const char*>(ptr));
+ case QMetaType::UChar:
+ return v8::Integer::NewFromUnsigned(*reinterpret_cast<const unsigned char*>(ptr));
+ case QMetaType::QChar:
+ return v8::Integer::New((*reinterpret_cast<const QChar*>(ptr)).unicode());
+ case QMetaType::QDateTime:
+ return v8::Date::New(qtDateTimeToJsDate(*reinterpret_cast<const QDateTime *>(ptr)));
+ case QMetaType::QDate:
+ return v8::Date::New(qtDateTimeToJsDate(QDateTime(*reinterpret_cast<const QDate *>(ptr))));
+ case QMetaType::QTime:
+ return v8::Date::New(qtDateTimeToJsDate(QDateTime(QDate(1970,1,1), *reinterpret_cast<const QTime *>(ptr))));
+ case QMetaType::QRegExp:
+ return regexpFromQRegExp(this, *reinterpret_cast<const QRegExp *>(ptr));
+ case QMetaType::QObjectStar:
+ case QMetaType::QWidgetStar:
+ return newQObject(*reinterpret_cast<QObject* const *>(ptr));
+ case QMetaType::QStringList:
+ return arrayFromStringList(this, *reinterpret_cast<const QStringList *>(ptr));
+ case QMetaType::QVariantList:
+ return arrayFromVariantList(this, *reinterpret_cast<const QVariantList *>(ptr));
+ case QMetaType::QVariantMap:
+ return objectFromVariantMap(this, *reinterpret_cast<const QVariantMap *>(ptr));
+
+ default:
+ break;
+ }
+
+ if (QDeclarativeValueType *vt = QDeclarativeEnginePrivate::get(m_engine)->valueTypes[type])
+ return m_valueTypeWrapper.newValueType(variant, vt);
+
+ } else {
+ if (type == qMetaTypeId<QDeclarativeListReference>()) {
+ typedef QDeclarativeListReferencePrivate QDLRP;
+ QDLRP *p = QDLRP::get((QDeclarativeListReference*)ptr);
+ if (p->object) {
+ return m_listWrapper.newList(p->property, p->propertyType);
+ } else {
+ return v8::Null();
+ }
+ } else if (type == qMetaTypeId<QList<QObject *> >()) {
+ // XXX Can this be made more by using Array as a prototype and implementing
+ // directly against QList<QObject*>?
+ const QList<QObject *> &list = *(QList<QObject *>*)ptr;
+ v8::Local<v8::Array> array = v8::Array::New(list.count());
+ for (int ii = 0; ii < list.count(); ++ii)
+ array->Set(ii, newQObject(list.at(ii)));
+ return array;
+ }
+
+ bool objOk;
+ QObject *obj = QDeclarativeMetaType::toQObject(variant, &objOk);
+ if (objOk)
+ return newQObject(obj);
+ }
+
+ // XXX TODO: To be compatible, we still need to handle:
+ // + QScriptValue
+ // + QObjectList
+ // + QList<int>
+
+ return m_variantWrapper.newVariant(variant);
+}
+
+// A handle scope and context must be entered
+v8::Local<v8::Script> QV8Engine::qmlModeCompile(const QString &source, const QString &fileName, int lineNumber)
+{
+ v8::Local<v8::String> v8source = m_stringWrapper.toString(source);
+ v8::Local<v8::String> v8fileName = m_stringWrapper.toString(fileName);
+
+ v8::ScriptOrigin origin(v8fileName, v8::Integer::New(lineNumber - 1));
+
+ v8::Local<v8::Script> script = v8::Script::Compile(v8source, &origin, 0, v8::Handle<v8::String>(),
+ v8::Script::QmlMode);
+
+ return script;
+}
+
+QNetworkAccessManager *QV8Engine::networkAccessManager()
+{
+ return QDeclarativeEnginePrivate::get(m_engine)->getNetworkAccessManager();
+}
+
+const QSet<QString> &QV8Engine::illegalNames() const
+{
+ return m_illegalNames;
+}
+
+// Requires a handle scope
+v8::Local<v8::Array> QV8Engine::getOwnPropertyNames(v8::Handle<v8::Object> o)
+{
+ v8::TryCatch tc;
+ v8::Handle<v8::Value> args[] = { o };
+ v8::Local<v8::Value> r = m_getOwnPropertyNames->Call(global(), 1, args);
+ if (tc.HasCaught())
+ return v8::Array::New();
+ else
+ return v8::Local<v8::Array>::Cast(r);
+}
+
+QDeclarativeContextData *QV8Engine::callingContext()
+{
+ return m_contextWrapper.callingContext();
+}
+
+// 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::toBasicVariant(v8::Handle<v8::Value> value)
+{
+ if (value->IsNull() || value->IsUndefined())
+ return QVariant();
+ else if (value->IsBoolean())
+ return value->ToBoolean()->Value();
+ else if (value->IsInt32())
+ return value->ToInt32()->Value();
+ else if (value->IsNumber())
+ return value->ToNumber()->Value();
+ else if (value->IsString())
+ return m_stringWrapper.toString(value->ToString());
+ if (value->IsDate())
+ return qtDateTimeFromJsDate(v8::Handle<v8::Date>::Cast(value)->NumberValue());
+ // NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)!
+
+ Q_ASSERT(value->IsObject());
+
+ if (value->IsRegExp()) {
+ v8::Context::Scope scope(context());
+ v8::Handle<v8::RegExp> jsRegExp = v8::Handle<v8::RegExp>::Cast(value);
+ // Copied from QtScript
+ // 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.
+ QString pattern = toString(jsRegExp->GetSource());
+ Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive;
+ if (jsRegExp->GetFlags() & v8::RegExp::kIgnoreCase)
+ caseSensitivity = Qt::CaseInsensitive;
+ return QRegExp(pattern, caseSensitivity, QRegExp::RegExp2);
+ } else if (value->IsArray()) {
+ v8::Context::Scope scope(context());
+ QVariantList rv;
+
+ v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value);
+ int length = array->Length();
+ for (int ii = 0; ii < length; ++ii)
+ rv << toVariant(array->Get(ii), -1);
+
+ return rv;
+ } else if (!value->IsFunction()) {
+ v8::Context::Scope scope(context());
+ v8::Handle<v8::Object> object = value->ToObject();
+ v8::Local<v8::Array> properties = object->GetPropertyNames();
+ int length = properties->Length();
+ if (length == 0)
+ return QVariant();
+
+ QVariantMap map;
+ for (int ii = 0; ii < length; ++ii) {
+ v8::Handle<v8::Value> property = properties->Get(ii);
+ map.insert(toString(property), toVariant(object->Get(property), -1));
+ }
+ return map;
+ }
+
+ return QVariant();
+}
+
+
+
+#include <QtGui/qvector3d.h>
+
+struct StaticQtMetaObject : public QObject
+{
+ static const QMetaObject *get()
+ { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
+};
+
+void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global)
+{
+ v8::Local<v8::Function> printFn = V8FUNCTION(print, this);
+
+ v8::Local<v8::Object> console = v8::Object::New();
+ console->Set(v8::String::New("log"), printFn);
+ console->Set(v8::String::New("debug"), printFn);
+
+ v8::Local<v8::Object> qt = v8::Object::New();
+
+ // Set all the enums from the "Qt" namespace
+ const QMetaObject *qtMetaObject = StaticQtMetaObject::get();
+ for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) {
+ QMetaEnum enumerator = qtMetaObject->enumerator(ii);
+ for (int jj = 0; jj < enumerator.keyCount(); ++jj) {
+ qt->Set(v8::String::New(enumerator.key(jj)), v8::Integer::New(enumerator.value(jj)));
+ }
+ }
+
+ 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));
+ qt->Set(v8::String::New("hsla"), V8FUNCTION(hsla, this));
+ qt->Set(v8::String::New("rect"), V8FUNCTION(rect, this));
+ qt->Set(v8::String::New("point"), V8FUNCTION(point, this));
+ 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));
+
+ qt->Set(v8::String::New("openUrlExternally"), V8FUNCTION(openUrlExternally, this));
+ qt->Set(v8::String::New("fontFamilies"), V8FUNCTION(fontFamilies, this));
+ qt->Set(v8::String::New("md5"), V8FUNCTION(md5, this));
+ qt->Set(v8::String::New("btoa"), V8FUNCTION(btoa, this));
+ qt->Set(v8::String::New("atob"), V8FUNCTION(atob, this));
+ qt->Set(v8::String::New("resolvedUrl"), V8FUNCTION(resolvedUrl, this));
+
+ if (m_engine) {
+ 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));
+ }
+
+ // XXX TODO - Implement translator functions
+
+ global->Set(v8::String::New("print"), printFn);
+ global->Set(v8::String::New("console"), console);
+ global->Set(v8::String::New("Qt"), qt);
+ global->Set(v8::String::New("gc"), V8FUNCTION(gc, this));
+
+ m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(this);
+ m_sqlDatabaseData = qt_add_qmlsqldatabase(this);
+
+ {
+ v8::Handle<v8::Value> args[] = { global };
+ v8::Local<v8::Value> names = m_getOwnPropertyNames->Call(global, 1, args);
+ v8::Local<v8::Array> namesArray = v8::Local<v8::Array>::Cast(names);
+ for (quint32 ii = 0; ii < namesArray->Length(); ++ii)
+ m_illegalNames.insert(toString(namesArray->Get(ii)));
+ }
+
+ {
+#define FREEZE_SOURCE "(function freeze_recur(obj) { "\
+ " if (Qt.isQtObject(obj)) return;"\
+ " if (obj != Function.connect && obj != Function.disconnect && "\
+ " obj instanceof Object) {"\
+ " var properties = Object.getOwnPropertyNames(obj);"\
+ " for (var prop in properties) { "\
+ " if (prop == \"connect\" || prop == \"disconnect\") {"\
+ " Object.freeze(obj[prop]); "\
+ " continue;"\
+ " }"\
+ " freeze_recur(obj[prop]);"\
+ " }"\
+ " }"\
+ " if (obj instanceof Object) {"\
+ " Object.freeze(obj);"\
+ " }"\
+ "})"
+
+ v8::Local<v8::Script> freeze = v8::Script::New(v8::String::New(FREEZE_SOURCE));
+ v8::Local<v8::Value> result = freeze->Run();
+ Q_ASSERT(result->IsFunction());
+ m_freezeObject = qPersistentNew(v8::Local<v8::Function>::Cast(result));
+#undef FREEZE_SOURCE
+ }
+}
+
+void QV8Engine::freezeObject(v8::Handle<v8::Value> value)
+{
+ v8::Handle<v8::Value> args[] = { value };
+ m_freezeObject->Call(global(), 1, args);
+}
+
+void QV8Engine::gc()
+{
+ v8::V8::LowMemoryNotification();
+ while (!v8::V8::IdleNotification()) {}
+}
+
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+#include <QtCore/qthreadstorage.h>
+static QThreadStorage<QSet<void *> *> QV8Engine_activeHandles;
+
+void QV8Engine::registerHandle(void *handle)
+{
+ if (!handle) {
+ qWarning("Attempting to register a null handle");
+ return;
+ }
+
+ if (!QV8Engine_activeHandles.hasLocalData())
+ QV8Engine_activeHandles.setLocalData(new QSet<void *>);
+
+ if (QV8Engine_activeHandles.localData()->contains(handle)) {
+ qFatal("Handle %p already alive", handle);
+ } else {
+ QV8Engine_activeHandles.localData()->insert(handle);
+ }
+}
+
+void QV8Engine::releaseHandle(void *handle)
+{
+ if (!handle)
+ return;
+
+ if (!QV8Engine_activeHandles.hasLocalData())
+ QV8Engine_activeHandles.setLocalData(new QSet<void *>);
+
+ if (QV8Engine_activeHandles.localData()->contains(handle)) {
+ QV8Engine_activeHandles.localData()->remove(handle);
+ } else {
+ qFatal("Handle %p already dead", handle);
+ }
+}
+#endif
+
+struct QV8EngineRegistrationData
+{
+ QV8EngineRegistrationData() : extensionCount(0) {}
+
+ QMutex mutex;
+ int extensionCount;
+};
+Q_GLOBAL_STATIC(QV8EngineRegistrationData, registrationData);
+
+QMutex *QV8Engine::registrationMutex()
+{
+ return &registrationData()->mutex;
+}
+
+int QV8Engine::registerExtension()
+{
+ return registrationData()->extensionCount++;
+}
+
+void QV8Engine::setExtensionData(int index, Deletable *data)
+{
+ if (m_extensionData.count() <= index)
+ m_extensionData.resize(index + 1);
+
+ if (m_extensionData.at(index))
+ delete m_extensionData.at(index);
+
+ m_extensionData[index] = data;
+}
+
+v8::Handle<v8::Value> QV8Engine::gc(const v8::Arguments &args)
+{
+ gc();
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8Engine::print(const v8::Arguments &args)
+{
+ QString result;
+ for (int i = 0; i < args.Length(); ++i) {
+ if (i != 0)
+ result.append(QLatin1Char(' '));
+
+ v8::Local<v8::String> jsstr = args[i]->ToString();
+ if (!jsstr.IsEmpty()) {
+ QString qstr;
+ qstr.resize(jsstr->Length());
+ jsstr->Write((uint16_t*)qstr.data());
+ result.append(qstr);
+ }
+ }
+ qDebug("%s", qPrintable(result));
+ return v8::Undefined();
+}
+
+/*!
+\qmlmethod bool Qt::isQtObject(object)
+Returns true if \c object is a valid reference to a Qt or QML object, otherwise false.
+*/
+v8::Handle<v8::Value> QV8Engine::isQtObject(const v8::Arguments &args)
+{
+ if (args.Length() == 0)
+ return v8::Boolean::New(false);
+
+ return v8::Boolean::New(0 != V8ENGINE()->toQObject(args[0]));
+}
+
+/*!
+\qmlmethod color Qt::rgba(real red, real green, real blue, real alpha)
+
+Returns a color with the specified \c red, \c green, \c blue and \c alpha components.
+All components should be in the range 0-1 inclusive.
+*/
+v8::Handle<v8::Value> QV8Engine::rgba(const v8::Arguments &args)
+{
+ int argCount = args.Length();
+ if (argCount < 3 || argCount > 4)
+ V8THROW_ERROR("Qt.rgba(): Invalid arguments");
+
+ double r = args[0]->NumberValue();
+ double g = args[1]->NumberValue();
+ double b = args[2]->NumberValue();
+ double a = (argCount == 4) ? args[3]->NumberValue() : 1;
+
+ if (r < 0.0) r=0.0;
+ if (r > 1.0) r=1.0;
+ if (g < 0.0) g=0.0;
+ if (g > 1.0) g=1.0;
+ if (b < 0.0) b=0.0;
+ if (b > 1.0) b=1.0;
+ if (a < 0.0) a=0.0;
+ if (a > 1.0) a=1.0;
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QColor::fromRgbF(r, g, b, a)));
+}
+
+/*!
+\qmlmethod color Qt::hsla(real hue, real saturation, real lightness, real alpha)
+
+Returns a color with the specified \c hue, \c saturation, \c lightness and \c alpha components.
+All components should be in the range 0-1 inclusive.
+*/
+v8::Handle<v8::Value> QV8Engine::hsla(const v8::Arguments &args)
+{
+ int argCount = args.Length();
+ if (argCount < 3 || argCount > 4)
+ V8THROW_ERROR("Qt.hsla(): Invalid arguments");
+
+ double h = args[0]->NumberValue();
+ double s = args[1]->NumberValue();
+ double l = args[2]->NumberValue();
+ double a = (argCount == 4) ? args[3]->NumberValue() : 1;
+
+ if (h < 0.0) h=0.0;
+ if (h > 1.0) h=1.0;
+ if (s < 0.0) s=0.0;
+ if (s > 1.0) s=1.0;
+ if (l < 0.0) l=0.0;
+ if (l > 1.0) l=1.0;
+ if (a < 0.0) a=0.0;
+ if (a > 1.0) a=1.0;
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QColor::fromHslF(h, s, l, a)));
+}
+
+/*!
+\qmlmethod rect Qt::rect(int x, int y, int width, int height)
+
+Returns a \c rect with the top-left corner at \c x, \c y and the specified \c width and \c height.
+
+The returned object has \c x, \c y, \c width and \c height attributes with the given values.
+*/
+v8::Handle<v8::Value> QV8Engine::rect(const v8::Arguments &args)
+{
+ if (args.Length() != 4)
+ V8THROW_ERROR("Qt.rect(): Invalid arguments");
+
+ double x = args[0]->NumberValue();
+ double y = args[1]->NumberValue();
+ double w = args[2]->NumberValue();
+ double h = args[3]->NumberValue();
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
+}
+
+/*!
+\qmlmethod point Qt::point(int x, int y)
+Returns a Point with the specified \c x and \c y coordinates.
+*/
+v8::Handle<v8::Value> QV8Engine::point(const v8::Arguments &args)
+{
+ if (args.Length() != 2)
+ V8THROW_ERROR("Qt.point(): Invalid arguments");
+
+ double x = args[0]->ToNumber()->Value();
+ double y = args[1]->ToNumber()->Value();
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QPointF(x, y)));
+}
+
+/*!
+\qmlmethod Qt::size(int width, int height)
+Returns a Size with the specified \c width and \c height.
+*/
+v8::Handle<v8::Value> QV8Engine::size(const v8::Arguments &args)
+{
+ if (args.Length() != 2)
+ V8THROW_ERROR("Qt.size(): Invalid arguments");
+
+ double w = args[0]->ToNumber()->Value();
+ double h = args[1]->ToNumber()->Value();
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QSizeF(w, h)));
+}
+
+/*!
+\qmlmethod Qt::vector3d(real x, real y, real z)
+Returns a Vector3D with the specified \c x, \c y and \c z.
+*/
+v8::Handle<v8::Value> QV8Engine::vector3d(const v8::Arguments &args)
+{
+ if (args.Length() != 3)
+ V8THROW_ERROR("Qt.vector(): Invalid arguments");
+
+ double x = args[0]->ToNumber()->Value();
+ double y = args[1]->ToNumber()->Value();
+ double z = args[2]->ToNumber()->Value();
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QVector3D(x, y, z)));
+}
+
+/*!
+\qmlmethod color Qt::lighter(color baseColor, real factor)
+Returns a color lighter than \c baseColor by the \c factor provided.
+
+If the factor is greater than 1.0, this functions returns a lighter color.
+Setting factor to 1.5 returns a color that is 50% brighter. If the factor is less than 1.0,
+the return color is darker, but we recommend using the Qt.darker() function for this purpose.
+If the factor is 0 or negative, the return value is unspecified.
+
+The function converts the current RGB color to HSV, multiplies the value (V) component
+by factor and converts the color back to RGB.
+
+If \c factor is not supplied, returns a color 50% lighter than \c baseColor (factor 1.5).
+*/
+v8::Handle<v8::Value> QV8Engine::lighter(const v8::Arguments &args)
+{
+ if (args.Length() != 1 && args.Length() != 2)
+ V8THROW_ERROR("Qt.lighter(): Invalid arguments");
+
+ QColor color;
+ QVariant v = V8ENGINE()->toVariant(args[0], -1);
+ if (v.userType() == QVariant::Color) {
+ color = v.value<QColor>();
+ } else if (v.userType() == QVariant::String) {
+ bool ok = false;
+ color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok) {
+ return v8::Null();
+ }
+ } else {
+ return v8::Null();
+ }
+
+ qreal factor = 1.5;
+ if (args.Length() == 2)
+ factor = args[1]->ToNumber()->Value();
+
+ color = color.lighter(int(qRound(factor*100.)));
+ return V8ENGINE()->fromVariant(QVariant::fromValue(color));
+}
+
+/*!
+\qmlmethod color Qt::darker(color baseColor, real factor)
+Returns a color darker than \c baseColor by the \c factor provided.
+
+If the factor is greater than 1.0, this function returns a darker color.
+Setting factor to 3.0 returns a color that has one-third the brightness.
+If the factor is less than 1.0, the return color is lighter, but we recommend using
+the Qt.lighter() function for this purpose. If the factor is 0 or negative, the return
+value is unspecified.
+
+The function converts the current RGB color to HSV, divides the value (V) component
+by factor and converts the color back to RGB.
+
+If \c factor is not supplied, returns a color 50% darker than \c baseColor (factor 2.0).
+*/
+v8::Handle<v8::Value> QV8Engine::darker(const v8::Arguments &args)
+{
+ if (args.Length() != 1 && args.Length() != 2)
+ V8THROW_ERROR("Qt.darker(): Invalid arguments");
+
+ QColor color;
+ QVariant v = V8ENGINE()->toVariant(args[0], -1);
+ if (v.userType() == QVariant::Color) {
+ color = v.value<QColor>();
+ } else if (v.userType() == QVariant::String) {
+ bool ok = false;
+ color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok) {
+ return v8::Null();
+ }
+ } else {
+ return v8::Null();
+ }
+
+ qreal factor = 2.0;
+ if (args.Length() == 2)
+ factor = args[1]->ToNumber()->Value();
+
+ color = color.darker(int(qRound(factor*100.)));
+ return V8ENGINE()->fromVariant(QVariant::fromValue(color));
+}
+
+/*!
+ \qmlmethod color Qt::tint(color baseColor, color tintColor)
+ This function allows tinting one color with another.
+
+ The tint color should usually be mostly transparent, or you will not be
+ able to see the underlying color. The below example provides a slight red
+ tint by having the tint color be pure red which is only 1/16th opaque.
+
+ \qml
+ Item {
+ Rectangle {
+ x: 0; width: 80; height: 80
+ color: "lightsteelblue"
+ }
+ Rectangle {
+ x: 100; width: 80; height: 80
+ color: Qt.tint("lightsteelblue", "#10FF0000")
+ }
+ }
+ \endqml
+ \image declarative-rect_tint.png
+
+ Tint is most useful when a subtle change is intended to be conveyed due to some event; you can then use tinting to more effectively tune the visible color.
+*/
+v8::Handle<v8::Value> QV8Engine::tint(const v8::Arguments &args)
+{
+ if (args.Length() != 2)
+ V8THROW_ERROR("Qt.tint(): Invalid arguments");
+
+ // base color
+ QColor color;
+ QVariant v = V8ENGINE()->toVariant(args[0], -1);
+ if (v.userType() == QVariant::Color) {
+ color = v.value<QColor>();
+ } else if (v.userType() == QVariant::String) {
+ bool ok = false;
+ color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok) {
+ return v8::Null();
+ }
+ } else {
+ return v8::Null();
+ }
+
+ // tint color
+ QColor tintColor;
+ v = V8ENGINE()->toVariant(args[1], -1);
+ if (v.userType() == QVariant::Color) {
+ tintColor = v.value<QColor>();
+ } else if (v.userType() == QVariant::String) {
+ bool ok = false;
+ tintColor = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok) {
+ return v8::Null();
+ }
+ } else {
+ return v8::Null();
+ }
+
+ // tint the base color and return the final color
+ QColor finalColor;
+ int a = tintColor.alpha();
+ if (a == 0xFF)
+ finalColor = tintColor;
+ else if (a == 0x00)
+ finalColor = color;
+ else {
+ qreal a = tintColor.alphaF();
+ qreal inv_a = 1.0 - a;
+
+ finalColor.setRgbF(tintColor.redF() * a + color.redF() * inv_a,
+ tintColor.greenF() * a + color.greenF() * inv_a,
+ tintColor.blueF() * a + color.blueF() * inv_a,
+ a + inv_a * color.alphaF());
+ }
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(finalColor));
+}
+
+/*!
+\qmlmethod string Qt::formatDate(datetime date, variant format)
+
+Returns a string representation of \c date, optionally formatted according
+to \c format.
+
+The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
+property, a QDate, or QDateTime value. The \a format parameter may be any of
+the possible format values as described for
+\l{QML:Qt::formatDateTime()}{Qt.formatDateTime()}.
+
+If \a format is not specified, \a date is formatted using
+\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
+*/
+v8::Handle<v8::Value> QV8Engine::formatDate(const v8::Arguments &args)
+{
+ if (args.Length() < 1 || args.Length() > 2)
+ V8THROW_ERROR("Qt.formatDate(): Invalid arguments");
+
+ Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
+ QDate date = V8ENGINE()->toVariant(args[0], -1).toDateTime().date();
+ QString formattedDate;
+ if (args.Length() == 2) {
+ if (args[1]->IsString()) {
+ QString format = V8ENGINE()->toVariant(args[1], -1).toString();
+ formattedDate = date.toString(format);
+ } else if (args[1]->IsNumber()) {
+ quint32 intFormat = args[1]->ToNumber()->Value();
+ Qt::DateFormat format = Qt::DateFormat(intFormat);
+ formattedDate = date.toString(format);
+ } else {
+ V8THROW_ERROR("Qt.formatDate(): Invalid date format");
+ }
+ } else {
+ formattedDate = date.toString(enumFormat);
+ }
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(formattedDate));
+}
+
+/*!
+\qmlmethod string Qt::formatTime(datetime time, variant format)
+
+Returns a string representation of \c time, optionally formatted according to
+\c format.
+
+The \a time parameter may be a JavaScript \c Date object, a QTime, or QDateTime
+value. The \a format parameter may be any of the possible format values as
+described for \l{QML:Qt::formatDateTime()}{Qt.formatDateTime()}.
+
+If \a format is not specified, \a time is formatted using
+\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
+*/
+v8::Handle<v8::Value> QV8Engine::formatTime(const v8::Arguments &args)
+{
+ if (args.Length() < 1 || args.Length() > 2)
+ V8THROW_ERROR("Qt.formatTime(): Invalid arguments");
+
+ QVariant argVariant = V8ENGINE()->toVariant(args[0], -1);
+ QTime time;
+ if (args[0]->IsDate() || (argVariant.type() == QVariant::String))
+ time = argVariant.toDateTime().time();
+ else // if (argVariant.type() == QVariant::Time), or invalid.
+ time = argVariant.toTime();
+
+ Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
+ QString formattedTime;
+ if (args.Length() == 2) {
+ if (args[1]->IsString()) {
+ QString format = V8ENGINE()->toVariant(args[1], -1).toString();
+ formattedTime = time.toString(format);
+ } else if (args[1]->IsNumber()) {
+ quint32 intFormat = args[1]->ToNumber()->Value();
+ Qt::DateFormat format = Qt::DateFormat(intFormat);
+ formattedTime = time.toString(format);
+ } else {
+ V8THROW_ERROR("Qt.formatTime(): Invalid time format");
+ }
+ } else {
+ formattedTime = time.toString(enumFormat);
+ }
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(formattedTime));
+}
+
+/*!
+\qmlmethod string Qt::formatDateTime(datetime dateTime, variant format)
+
+Returns a string representation of \c datetime, optionally formatted according to
+\c format.
+
+The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
+property, a QDate, QTime, or QDateTime value.
+
+If \a format is not provided, \a dateTime is formatted using
+\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}. Otherwise,
+\a format should be either:
+
+\list
+\o One of the Qt::DateFormat enumeration values, such as
+ \c Qt.DefaultLocaleShortDate or \c Qt.ISODate
+\o A string that specifies the format of the returned string, as detailed below.
+\endlist
+
+If \a format specifies a format string, it should use the following expressions
+to specify the date:
+
+ \table
+ \header \i Expression \i Output
+ \row \i d \i the day as number without a leading zero (1 to 31)
+ \row \i dd \i the day as number with a leading zero (01 to 31)
+ \row \i ddd
+ \i the abbreviated localized day name (e.g. 'Mon' to 'Sun').
+ Uses QDate::shortDayName().
+ \row \i dddd
+ \i the long localized day name (e.g. 'Monday' to 'Qt::Sunday').
+ Uses QDate::longDayName().
+ \row \i M \i the month as number without a leading zero (1-12)
+ \row \i MM \i the month as number with a leading zero (01-12)
+ \row \i MMM
+ \i the abbreviated localized month name (e.g. 'Jan' to 'Dec').
+ Uses QDate::shortMonthName().
+ \row \i MMMM
+ \i the long localized month name (e.g. 'January' to 'December').
+ Uses QDate::longMonthName().
+ \row \i yy \i the year as two digit number (00-99)
+ \row \i yyyy \i the year as four digit number
+ \endtable
+
+In addition the following expressions can be used to specify the time:
+
+ \table
+ \header \i Expression \i Output
+ \row \i h
+ \i the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
+ \row \i hh
+ \i the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
+ \row \i m \i the minute without a leading zero (0 to 59)
+ \row \i mm \i the minute with a leading zero (00 to 59)
+ \row \i s \i the second without a leading zero (0 to 59)
+ \row \i ss \i the second with a leading zero (00 to 59)
+ \row \i z \i the milliseconds without leading zeroes (0 to 999)
+ \row \i zzz \i the milliseconds with leading zeroes (000 to 999)
+ \row \i AP
+ \i use AM/PM display. \e AP will be replaced by either "AM" or "PM".
+ \row \i ap
+ \i use am/pm display. \e ap will be replaced by either "am" or "pm".
+ \endtable
+
+ All other input characters will be ignored. Any sequence of characters that
+ are enclosed in single quotes will be treated as text and not be used as an
+ expression. Two consecutive single quotes ("''") are replaced by a single quote
+ in the output.
+
+For example, if the following date/time value was specified:
+
+ \code
+ // 21 May 2001 14:13:09
+ var dateTime = new Date(2001, 5, 21, 14, 13, 09)
+ \endcode
+
+This \a dateTime value could be passed to \c Qt.formatDateTime(),
+\l {QML:Qt::formatDate()}{Qt.formatDate()} or \l {QML:Qt::formatTime()}{Qt.formatTime()}
+with the \a format values below to produce the following results:
+
+ \table
+ \header \i Format \i Result
+ \row \i "dd.MM.yyyy" \i 21.05.2001
+ \row \i "ddd MMMM d yy" \i Tue May 21 01
+ \row \i "hh:mm:ss.zzz" \i 14:13:09.042
+ \row \i "h:m:s ap" \i 2:13:9 pm
+ \endtable
+*/
+v8::Handle<v8::Value> QV8Engine::formatDateTime(const v8::Arguments &args)
+{
+ if (args.Length() < 1 || args.Length() > 2)
+ V8THROW_ERROR("Qt.formatDateTime(): Invalid arguments");
+
+ Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
+ QDateTime dt = V8ENGINE()->toVariant(args[0], -1).toDateTime();
+ QString formattedDt;
+ if (args.Length() == 2) {
+ if (args[1]->IsString()) {
+ QString format = V8ENGINE()->toVariant(args[1], -1).toString();
+ formattedDt = dt.toString(format);
+ } else if (args[1]->IsNumber()) {
+ quint32 intFormat = args[1]->ToNumber()->Value();
+ Qt::DateFormat format = Qt::DateFormat(intFormat);
+ formattedDt = dt.toString(format);
+ } else {
+ V8THROW_ERROR("Qt.formatDateTime(): Invalid datetime format");
+ }
+ } else {
+ formattedDt = dt.toString(enumFormat);
+ }
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(formattedDt));
+}
+
+double QV8Engine::qtDateTimeToJsDate(const QDateTime &dt)
+{
+ // from QScriptEngine::DateTimeToMs()
+ if (!dt.isValid()) {
+ return qSNaN();
+ }
+ QDateTime utc = dt.toUTC();
+ QDate date = utc.date();
+ QTime time = utc.time();
+ QV8DateConverter::JSC::GregorianDateTime tm;
+ tm.year = date.year() - 1900;
+ tm.month = date.month() - 1;
+ tm.monthDay = date.day();
+ tm.weekDay = date.dayOfWeek();
+ tm.yearDay = date.dayOfYear();
+ tm.hour = time.hour();
+ tm.minute = time.minute();
+ tm.second = time.second();
+ return QV8DateConverter::JSC::gregorianDateTimeToMS(tm, time.msec());
+}
+
+QDateTime QV8Engine::qtDateTimeFromJsDate(double jsDate)
+{
+ // from QScriptEngine::MsToDateTime()
+ if (qIsNaN(jsDate))
+ return QDateTime();
+ QV8DateConverter::JSC::GregorianDateTime tm;
+ QV8DateConverter::JSC::msToGregorianDateTime(jsDate, tm);
+
+ // from QScriptEngine::MsFromTime()
+ int ms = int(::fmod(jsDate, 1000.0));
+ if (ms < 0)
+ ms += int(1000.0);
+
+ QDateTime convertedUTC = QDateTime(QDate(tm.year + 1900, tm.month + 1, tm.monthDay),
+ QTime(tm.hour, tm.minute, tm.second, ms), Qt::UTC);
+ return convertedUTC.toLocalTime();
+}
+
+/*!
+\qmlmethod bool Qt::openUrlExternally(url target)
+Attempts to open the specified \c target url in an external application, based on the user's desktop preferences. Returns true if it succeeds, and false otherwise.
+*/
+v8::Handle<v8::Value> QV8Engine::openUrlExternally(const v8::Arguments &args)
+{
+ if (args.Length() != 1)
+ return V8ENGINE()->fromVariant(false);
+
+ bool ret = false;
+#ifndef QT_NO_DESKTOPSERVICES
+ ret = QDesktopServices::openUrl(V8ENGINE()->toVariant(resolvedUrl(args), -1).toUrl());
+#endif
+ return V8ENGINE()->fromVariant(ret);
+}
+
+/*!
+ \qmlmethod url Qt::resolvedUrl(url url)
+ Returns \a url resolved relative to the URL of the caller.
+*/
+v8::Handle<v8::Value> QV8Engine::resolvedUrl(const v8::Arguments &args)
+{
+ QUrl url = V8ENGINE()->toVariant(args[0], -1).toUrl();
+ QDeclarativeEngine *e = V8ENGINE()->engine();
+ QDeclarativeEnginePrivate *p = 0;
+ if (e) p = QDeclarativeEnginePrivate::get(e);
+ if (p) {
+ QDeclarativeContextData *ctxt = V8ENGINE()->callingContext();
+ if (ctxt)
+ return V8ENGINE()->fromVariant(ctxt->resolvedUrl(url));
+ else
+ return V8ENGINE()->fromVariant(url);
+ }
+
+ return V8ENGINE()->fromVariant(e->baseUrl().resolved(url));
+}
+
+/*!
+\qmlmethod list<string> Qt::fontFamilies()
+Returns a list of the font families available to the application.
+*/
+v8::Handle<v8::Value> QV8Engine::fontFamilies(const v8::Arguments &args)
+{
+ if (args.Length() != 0)
+ V8THROW_ERROR("Qt.fontFamilies(): Invalid arguments");
+
+ QFontDatabase database;
+ return V8ENGINE()->fromVariant(database.families());
+}
+
+/*!
+\qmlmethod string Qt::md5(data)
+Returns a hex string of the md5 hash of \c data.
+*/
+v8::Handle<v8::Value> QV8Engine::md5(const v8::Arguments &args)
+{
+ if (args.Length() != 1)
+ V8THROW_ERROR("Qt.md5(): Invalid arguments");
+
+ QByteArray data = V8ENGINE()->toString(args[0]->ToString()).toUtf8();
+ QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5);
+ return V8ENGINE()->toString(QLatin1String(result.toHex()));
+}
+
+/*!
+\qmlmethod string Qt::btoa(data)
+Binary to ASCII - this function returns a base64 encoding of \c data.
+*/
+v8::Handle<v8::Value> QV8Engine::btoa(const v8::Arguments &args)
+{
+ if (args.Length() != 1)
+ V8THROW_ERROR("Qt.btoa(): Invalid arguments");
+
+ QByteArray data = V8ENGINE()->toString(args[0]->ToString()).toUtf8();
+
+ return V8ENGINE()->toString(QLatin1String(data.toBase64()));
+}
+
+/*!
+\qmlmethod string Qt::atob(data)
+ASCII to binary - this function returns a base64 decoding of \c data.
+*/
+v8::Handle<v8::Value> QV8Engine::atob(const v8::Arguments &args)
+{
+ if (args.Length() != 1)
+ V8THROW_ERROR("Qt.atob(): Invalid arguments");
+
+ QByteArray data = V8ENGINE()->toString(args[0]->ToString()).toUtf8();
+
+ return V8ENGINE()->toString(QLatin1String(QByteArray::fromBase64(data)));
+}
+
+/*!
+\qmlmethod Qt::quit()
+This function causes the QDeclarativeEngine::quit() signal to be emitted.
+Within the \l {QML Viewer}, this causes the launcher application to exit;
+to quit a C++ application when this method is called, connect the
+QDeclarativeEngine::quit() signal to the QCoreApplication::quit() slot.
+*/
+v8::Handle<v8::Value> QV8Engine::quit(const v8::Arguments &args)
+{
+ QDeclarativeEnginePrivate::get(V8ENGINE()->engine())->sendQuit();
+ return v8::Undefined();
+}
+
+/*!
+\qmlmethod object Qt::createQmlObject(string qml, object parent, string filepath)
+
+Returns a new object created from the given \a string of QML which will have the specified \a parent,
+or \c null if there was an error in creating the object.
+
+If \a filepath is specified, it will be used for error reporting for the created object.
+
+Example (where \c parentItem is the id of an existing QML item):
+
+\snippet doc/src/snippets/declarative/createQmlObject.qml 0
+
+In the case of an error, a QtScript Error object is thrown. This object has an additional property,
+\c qmlErrors, which is an array of the errors encountered.
+Each object in this array has the members \c lineNumber, \c columnNumber, \c fileName and \c message.
+For example, if the above snippet had misspelled color as 'colro' then the array would contain an object like the following:
+{ "lineNumber" : 1, "columnNumber" : 32, "fileName" : "dynamicSnippet1", "message" : "Cannot assign to non-existent property \"colro\""}.
+
+Note that this function returns immediately, and therefore may not work if
+the \a qml string loads new components (that is, external QML files that have not yet been loaded).
+If this is the case, consider using \l{QML:Qt::createComponent()}{Qt.createComponent()} instead.
+
+See \l {Dynamic Object Management in QML} for more information on using this function.
+*/
+v8::Handle<v8::Value> QV8Engine::createQmlObject(const v8::Arguments &args)
+{
+ if (args.Length() < 2 || args.Length() > 3)
+ V8THROW_ERROR("Qt.createQmlObject(): Invalid arguments");
+
+ struct Error {
+ static v8::Local<v8::Value> create(QV8Engine *engine, const QList<QDeclarativeError> &errors) {
+ QString errorstr = QLatin1String("Qt.createQmlObject(): failed to create object: ");
+
+ v8::Local<v8::Array> qmlerrors = v8::Array::New(errors.count());
+ for (int ii = 0; ii < errors.count(); ++ii) {
+ const QDeclarativeError &error = errors.at(ii);
+ errorstr += QLatin1String("\n ") + error.toString();
+ v8::Local<v8::Object> qmlerror = v8::Object::New();
+ qmlerror->Set(v8::String::New("lineNumber"), v8::Integer::New(error.line()));
+ qmlerror->Set(v8::String::New("columnNumber"), v8::Integer::New(error.line()));
+ qmlerror->Set(v8::String::New("fileName"), engine->toString(error.url().toString()));
+ qmlerror->Set(v8::String::New("message"), engine->toString(error.description()));
+ qmlerrors->Set(ii, qmlerror);
+ }
+
+ v8::Local<v8::Value> error = v8::Exception::Error(engine->toString(errorstr));
+ v8::Local<v8::Object> errorObject = error->ToObject();
+ errorObject->Set(v8::String::New("qmlErrors"), qmlerrors);
+ return error;
+ }
+ };
+
+ QV8Engine *v8engine = V8ENGINE();
+ QDeclarativeEngine *engine = v8engine->engine();
+
+ QDeclarativeContextData *context = v8engine->callingContext();
+ Q_ASSERT(context);
+
+ QString qml = v8engine->toString(args[0]->ToString());
+ if (qml.isEmpty())
+ return v8::Null();
+
+ QUrl url;
+ if(args.Length() > 2)
+ url = QUrl(v8engine->toString(args[2]->ToString()));
+ else
+ url = QUrl(QLatin1String("inline"));
+
+ if (url.isValid() && url.isRelative())
+ url = context->resolvedUrl(url);
+
+ QObject *parentArg = v8engine->toQObject(args[1]);
+ if(!parentArg)
+ V8THROW_ERROR("Qt.createQmlObject(): Missing parent object");
+
+ QDeclarativeComponent component(engine);
+ component.setData(qml.toUtf8(), url);
+
+ if(component.isError()) {
+ v8::ThrowException(Error::create(v8engine, component.errors()));
+ return v8::Undefined();
+ }
+
+ if (!component.isReady())
+ V8THROW_ERROR("Qt.createQmlObject(): Component is not ready");
+
+ QObject *obj = component.beginCreate(context->asQDeclarativeContext());
+ if(obj)
+ QDeclarativeData::get(obj, true)->setImplicitDestructible();
+ component.completeCreate();
+
+ if(component.isError()) {
+ v8::ThrowException(Error::create(v8engine, component.errors()));
+ return v8::Undefined();
+ }
+
+ Q_ASSERT(obj);
+
+ obj->setParent(parentArg);
+
+ QList<QDeclarativePrivate::AutoParentFunction> functions = QDeclarativeMetaType::parentFunctions();
+ for (int ii = 0; ii < functions.count(); ++ii) {
+ if (QDeclarativePrivate::Parented == functions.at(ii)(obj, parentArg))
+ break;
+ }
+
+ return v8engine->newQObject(obj);
+}
+
+/*!
+\qmlmethod object Qt::createComponent(url)
+
+Returns a \l Component object created using the QML file at the specified \a url,
+or \c null if an empty string was given.
+
+The returned component's \l Component::status property indicates whether the
+component was successfully created. If the status is \c Component.Error,
+see \l Component::errorString() for an error description.
+
+Call \l {Component::createObject()}{Component.createObject()} on the returned
+component to create an object instance of the component.
+
+For example:
+
+\snippet doc/src/snippets/declarative/createComponent-simple.qml 0
+
+See \l {Dynamic Object Management in QML} for more information on using this function.
+
+To create a QML object from an arbitrary string of QML (instead of a file),
+use \l{QML:Qt::createQmlObject()}{Qt.createQmlObject()}.
+*/
+v8::Handle<v8::Value> QV8Engine::createComponent(const v8::Arguments &args)
+{
+ if (args.Length() != 1)
+ V8THROW_ERROR("Qt.createComponent(): Invalid arguments");
+
+ QV8Engine *v8engine = V8ENGINE();
+ QDeclarativeEngine *engine = v8engine->engine();
+
+ QDeclarativeContextData *context = v8engine->callingContext();
+ Q_ASSERT(context);
+
+ QString arg = v8engine->toString(args[0]->ToString());
+ if (arg.isEmpty())
+ return v8::Null();
+
+ QUrl url = context->resolvedUrl(QUrl(arg));
+ QDeclarativeComponent *c = new QDeclarativeComponent(engine, url, engine);
+ QDeclarativeComponentPrivate::get(c)->creationContext = context;
+ QDeclarativeData::get(c, true)->setImplicitDestructible();
+ return v8engine->newQObject(c);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/qml/v8/qv8engine_p.h b/src/declarative/qml/v8/qv8engine_p.h
new file mode 100644
index 0000000000..7398944ff5
--- /dev/null
+++ b/src/declarative/qml/v8/qv8engine_p.h
@@ -0,0 +1,450 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV8ENGINE_P_H
+#define QDECLARATIVEV8ENGINE_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 <QtCore/qglobal.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qset.h>
+#include <QtCore/qmutex.h>
+#include <private/qv8_p.h>
+
+#include <private/qdeclarativepropertycache_p.h>
+
+#include "qv8contextwrapper_p.h"
+#include "qv8qobjectwrapper_p.h"
+#include "qv8stringwrapper_p.h"
+#include "qv8typewrapper_p.h"
+#include "qv8listwrapper_p.h"
+#include "qv8variantwrapper_p.h"
+#include "qv8valuetypewrapper_p.h"
+
+QT_BEGIN_NAMESPACE
+
+
+// Uncomment the following line to enable global handle debugging. When enabled, all the persistent
+// handles allocated using qPersistentNew() (or registered with qPersistentRegsiter()) and disposed
+// with qPersistentDispose() are tracked. If you try and do something illegal, like double disposing
+// a handle, qFatal() is called.
+// #define QML_GLOBAL_HANDLE_DEBUGGING
+
+#define V8_RESOURCE_TYPE(resourcetype) \
+public: \
+ enum { V8ResourceType = QV8ObjectResource:: resourcetype }; \
+ virtual QV8ObjectResource::ResourceType resourceType() const { return QV8ObjectResource:: resourcetype; } \
+private:
+
+#define V8ENGINE() ((QV8Engine *)v8::External::Unwrap(args.Data()))
+#define V8FUNCTION(function, engine) v8::FunctionTemplate::New(function, v8::External::Wrap((QV8Engine*)engine))->GetFunction()
+#define V8THROW_ERROR(string) { \
+ v8::ThrowException(v8::Exception::Error(v8::String::New(string))); \
+ return v8::Handle<v8::Value>(); \
+}
+#define V8ENGINE_ACCESSOR() ((QV8Engine *)v8::External::Unwrap(info.Data()));
+#define V8THROW_ERROR_SETTER(string) { \
+ v8::ThrowException(v8::Exception::Error(v8::String::New(string))); \
+ return; \
+}
+
+#define V8_DEFINE_EXTENSION(dataclass, datafunction) \
+ inline dataclass *datafunction(QV8Engine *engine) \
+ { \
+ static int extensionId = -1; \
+ if (extensionId == -1) { \
+ QV8Engine::registrationMutex()->lock(); \
+ if (extensionId == -1) \
+ extensionId = QV8Engine::registerExtension(); \
+ QV8Engine::registrationMutex()->unlock(); \
+ } \
+ dataclass *rv = (dataclass *)engine->extensionData(extensionId); \
+ if (!rv) { \
+ rv = new dataclass(engine); \
+ engine->setExtensionData(extensionId, rv); \
+ } \
+ return rv; \
+ } \
+
+class QV8Engine;
+class QV8ObjectResource : public v8::Object::ExternalResource
+{
+public:
+ QV8ObjectResource(QV8Engine *engine) : engine(engine) { Q_ASSERT(engine); }
+ enum ResourceType { ContextType, QObjectType, TypeType, ListType, VariantType,
+ ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType,
+ ListModelType, Context2DType };
+ virtual ResourceType resourceType() const = 0;
+
+ QV8Engine *engine;
+};
+
+template<class T>
+T *v8_resource_cast(v8::Handle<v8::Object> object) {
+ QV8ObjectResource *resource = static_cast<QV8ObjectResource *>(object->GetExternalResource());
+ return (resource && (quint32)resource->resourceType() == (quint32)T::V8ResourceType)?static_cast<T *>(resource):0;
+}
+
+// Used to allow a QObject method take and return raw V8 handles without having to expose
+// v8 in the public API.
+// Use like this:
+// class MyClass : public QObject {
+// Q_OBJECT
+// ...
+// Q_INVOKABLE void myMethod(QDeclarativeV8Function*);
+// };
+// The QDeclarativeV8Function - and consequently the arguments and return value - only remains
+// valid during the call. If the return value isn't set within myMethod(), the will return
+// undefined.
+class QV8Engine;
+class QDeclarativeV8Function
+{
+public:
+ int Length() const { return _ac; }
+ v8::Local<v8::Value> operator[](int idx) { return (*_a)->Get(idx); }
+ QDeclarativeContextData *context() { return _c; }
+ v8::Handle<v8::Object> qmlGlobal() { return *_g; }
+ void returnValue(v8::Handle<v8::Value> rv) { *_r = rv; }
+ QV8Engine *engine() const { return _e; }
+private:
+ friend class QV8QObjectWrapper;
+ QDeclarativeV8Function();
+ QDeclarativeV8Function(const QDeclarativeV8Function &);
+ QDeclarativeV8Function &operator=(const QDeclarativeV8Function &);
+
+ QDeclarativeV8Function(int length, v8::Handle<v8::Object> &args,
+ v8::Handle<v8::Value> &rv, v8::Handle<v8::Object> &global,
+ QDeclarativeContextData *c, QV8Engine *e)
+ : _ac(length), _a(&args), _r(&rv), _g(&global), _c(c), _e(e) {}
+
+ int _ac;
+ v8::Handle<v8::Object> *_a;
+ v8::Handle<v8::Value> *_r;
+ v8::Handle<v8::Object> *_g;
+ QDeclarativeContextData *_c;
+ QV8Engine *_e;
+};
+
+class QDeclarativeV8Handle
+{
+public:
+ QDeclarativeV8Handle() : d(0) {}
+ QDeclarativeV8Handle(const QDeclarativeV8Handle &other) : d(other.d) {}
+ QDeclarativeV8Handle &operator=(const QDeclarativeV8Handle &other) { d = other.d; return *this; }
+
+ static QDeclarativeV8Handle fromHandle(v8::Handle<v8::Value> h) {
+ return reinterpret_cast<QDeclarativeV8Handle &>(h);
+ }
+ v8::Handle<v8::Value> toHandle() const {
+ return reinterpret_cast<const v8::Handle<v8::Value> &>(*this);
+ }
+private:
+ void *d;
+};
+
+class QObject;
+class QDeclarativeEngine;
+class QDeclarativeValueType;
+class QNetworkAccessManager;
+class QDeclarativeContextData;
+class Q_AUTOTEST_EXPORT QV8Engine
+{
+public:
+ QV8Engine();
+ ~QV8Engine();
+
+ struct Deletable {
+ ~Deletable() {}
+ };
+
+ void init(QDeclarativeEngine *);
+
+ QDeclarativeEngine *engine() { return m_engine; }
+ v8::Local<v8::Object> global() { return m_context->Global(); }
+ v8::Handle<v8::Context> context() { return m_context; }
+ QV8ContextWrapper *contextWrapper() { return &m_contextWrapper; }
+ QV8QObjectWrapper *qobjectWrapper() { return &m_qobjectWrapper; }
+ QV8TypeWrapper *typeWrapper() { return &m_typeWrapper; }
+ QV8ListWrapper *listWrapper() { return &m_listWrapper; }
+ QV8VariantWrapper *variantWrapper() { return &m_variantWrapper; }
+
+ void *xmlHttpRequestData() { return m_xmlHttpRequestData; }
+ void *sqlDatabaseData() { return m_sqlDatabaseData; }
+
+ Deletable *listModelData() { return m_listModelData; }
+ void setListModelData(Deletable *d) { if (m_listModelData) delete m_listModelData; m_listModelData = d; }
+
+ QDeclarativeContextData *callingContext();
+
+ v8::Local<v8::Array> getOwnPropertyNames(v8::Handle<v8::Object>);
+ void freezeObject(v8::Handle<v8::Value>);
+
+ inline QString toString(v8::Handle<v8::Value> string);
+ inline QString toString(v8::Handle<v8::String> string);
+ static QString toStringStatic(v8::Handle<v8::Value>);
+ static QString toStringStatic(v8::Handle<v8::String>);
+ static inline bool startsWithUpper(v8::Handle<v8::String>);
+
+ QVariant toVariant(v8::Handle<v8::Value>, int typeHint);
+ v8::Handle<v8::Value> fromVariant(const QVariant &);
+ inline bool isVariant(v8::Handle<v8::Value>);
+
+ // Compile \a source (from \a fileName at \a lineNumber) in QML mode
+ v8::Local<v8::Script> qmlModeCompile(const QString &source,
+ const QString &fileName = QString(),
+ int lineNumber = 1);
+
+ // 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);
+
+ // 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>);
+ inline QObject *toQObject(v8::Handle<v8::Value>);
+
+ // Return a JS string for the given QString \a string
+ inline v8::Local<v8::String> toString(const QString &string);
+
+ // Create a new value type object
+ inline v8::Handle<v8::Value> newValueType(QObject *, int coreIndex, QDeclarativeValueType *);
+ inline v8::Handle<v8::Value> newValueType(const QVariant &, QDeclarativeValueType *);
+
+ // Create a new QVariant object. This doesn't examine the type of the variant, but always returns
+ // a QVariant wrapper
+ inline v8::Handle<v8::Value> newQVariant(const QVariant &);
+
+ // Return the network access manager for this engine. By default this returns the network
+ // access manager of the QDeclarativeEngine. It is overridden in the case of a threaded v8
+ // instance (like in WorkerScript).
+ virtual QNetworkAccessManager *networkAccessManager();
+
+ // Return the list of illegal id names (the names of the properties on the global object)
+ const QSet<QString> &illegalNames() const;
+
+ static void gc();
+
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+ // Used for handle debugging
+ static void registerHandle(void *);
+ static void releaseHandle(void *);
+#endif
+
+ static QMutex *registrationMutex();
+ static int registerExtension();
+
+ inline Deletable *extensionData(int) const;
+ void setExtensionData(int, Deletable *);
+
+private:
+ QDeclarativeEngine *m_engine;
+ v8::Persistent<v8::Context> m_context;
+
+ QV8StringWrapper m_stringWrapper;
+ QV8ContextWrapper m_contextWrapper;
+ QV8QObjectWrapper m_qobjectWrapper;
+ QV8TypeWrapper m_typeWrapper;
+ QV8ListWrapper m_listWrapper;
+ QV8VariantWrapper m_variantWrapper;
+ QV8ValueTypeWrapper m_valueTypeWrapper;
+
+ v8::Persistent<v8::Function> m_getOwnPropertyNames;
+ v8::Persistent<v8::Function> m_freezeObject;
+
+ void *m_xmlHttpRequestData;
+ void *m_sqlDatabaseData;
+
+ QVector<Deletable *> m_extensionData;
+ Deletable *m_listModelData;
+
+ QSet<QString> m_illegalNames;
+
+ QVariant toBasicVariant(v8::Handle<v8::Value>);
+
+ void initializeGlobal(v8::Handle<v8::Object>);
+
+ static v8::Handle<v8::Value> gc(const v8::Arguments &args);
+ static v8::Handle<v8::Value> print(const v8::Arguments &args);
+ static v8::Handle<v8::Value> isQtObject(const v8::Arguments &args);
+ static v8::Handle<v8::Value> rgba(const v8::Arguments &args);
+ static v8::Handle<v8::Value> hsla(const v8::Arguments &args);
+ static v8::Handle<v8::Value> rect(const v8::Arguments &args);
+ static v8::Handle<v8::Value> point(const v8::Arguments &args);
+ static v8::Handle<v8::Value> size(const v8::Arguments &args);
+ static v8::Handle<v8::Value> vector3d(const v8::Arguments &args);
+ static v8::Handle<v8::Value> lighter(const v8::Arguments &args);
+ static v8::Handle<v8::Value> darker(const v8::Arguments &args);
+ static v8::Handle<v8::Value> tint(const v8::Arguments &args);
+ static v8::Handle<v8::Value> formatDate(const v8::Arguments &args);
+ static v8::Handle<v8::Value> formatTime(const v8::Arguments &args);
+ static v8::Handle<v8::Value> formatDateTime(const v8::Arguments &args);
+ static v8::Handle<v8::Value> openUrlExternally(const v8::Arguments &args);
+ static v8::Handle<v8::Value> fontFamilies(const v8::Arguments &args);
+ static v8::Handle<v8::Value> md5(const v8::Arguments &args);
+ static v8::Handle<v8::Value> btoa(const v8::Arguments &args);
+ static v8::Handle<v8::Value> atob(const v8::Arguments &args);
+ static v8::Handle<v8::Value> quit(const v8::Arguments &args);
+ static v8::Handle<v8::Value> resolvedUrl(const v8::Arguments &args);
+ static v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args);
+ static v8::Handle<v8::Value> createComponent(const v8::Arguments &args);
+
+ double qtDateTimeToJsDate(const QDateTime &dt);
+ QDateTime qtDateTimeFromJsDate(double jsDate);
+};
+
+// Allocate a new Persistent handle. *ALL* persistent handles in QML must be allocated
+// using this method.
+template<class T>
+v8::Persistent<T> qPersistentNew(v8::Handle<T> that)
+{
+ v8::Persistent<T> rv = v8::Persistent<T>::New(that);
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+ QV8Engine::registerHandle(*rv);
+#endif
+ return rv;
+}
+
+// Register a Persistent handle that was returned to you by V8 (such as by
+// v8::Context::New). This allows us to do handle tracking on these handles too.
+template<class T>
+void qPersistentRegister(v8::Persistent<T> handle)
+{
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+ QV8Engine::registerHandle(*handle);
+#else
+ Q_UNUSED(handle);
+#endif
+}
+
+// Dispose and clear a persistent handle. *ALL* persistent handles in QML must be
+// disposed using this method.
+template<class T>
+void qPersistentDispose(v8::Persistent<T> &that)
+{
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+ QV8Engine::releaseHandle(*that);
+#endif
+ that.Dispose();
+ that.Clear();
+}
+
+QString QV8Engine::toString(v8::Handle<v8::Value> string)
+{
+ return m_stringWrapper.toString(string->ToString());
+}
+
+QString QV8Engine::toString(v8::Handle<v8::String> string)
+{
+ return m_stringWrapper.toString(string);
+}
+
+bool QV8Engine::isVariant(v8::Handle<v8::Value> value)
+{
+ return m_variantWrapper.isVariant(value);
+}
+
+v8::Local<v8::Object> QV8Engine::qmlScope(QDeclarativeContextData *ctxt, QObject *scope)
+{
+ return m_contextWrapper.qmlScope(ctxt, scope);
+}
+
+bool QV8Engine::isQObject(v8::Handle<v8::Value> obj)
+{
+ return obj->IsObject()?m_qobjectWrapper.isQObject(v8::Handle<v8::Object>::Cast(obj)):false;
+}
+
+QObject *QV8Engine::toQObject(v8::Handle<v8::Value> obj)
+{
+ return obj->IsObject()?m_qobjectWrapper.toQObject(v8::Handle<v8::Object>::Cast(obj)):0;
+}
+
+v8::Handle<v8::Value> QV8Engine::newQObject(QObject *object)
+{
+ return m_qobjectWrapper.newQObject(object);
+}
+
+v8::Local<v8::String> QV8Engine::toString(const QString &string)
+{
+ return m_stringWrapper.toString(string);
+}
+
+v8::Handle<v8::Value> QV8Engine::newValueType(QObject *object, int property, QDeclarativeValueType *type)
+{
+ return m_valueTypeWrapper.newValueType(object, property, type);
+}
+
+v8::Handle<v8::Value> QV8Engine::newValueType(const QVariant &value, QDeclarativeValueType *type)
+{
+ return m_valueTypeWrapper.newValueType(value, type);
+}
+
+// XXX Can this be made more optimal? It is called prior to resolving each and every
+// unqualified name in QV8ContextWrapper.
+bool QV8Engine::startsWithUpper(v8::Handle<v8::String> string)
+{
+ uint16_t buffer[2];
+ int written = string->Write(buffer, 0, 1);
+ if (written == 0) return false;
+ uint16_t c = buffer[0];
+ return ((c != '_' ) && (!(c >= 'a' && c <= 'z')) &&
+ ((c >= 'A' && c <= 'Z') || QChar::category(c) == QChar::Letter_Uppercase));
+}
+
+QV8Engine::Deletable *QV8Engine::extensionData(int index) const
+{
+ if (index < m_extensionData.count())
+ return m_extensionData[index];
+ else
+ return 0;
+}
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEV8ENGINE_P_H
diff --git a/src/declarative/qml/v8/qv8include.cpp b/src/declarative/qml/v8/qv8include.cpp
new file mode 100644
index 0000000000..f8ef8a6af4
--- /dev/null
+++ b/src/declarative/qml/v8/qv8include.cpp
@@ -0,0 +1,243 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8include_p.h"
+
+#include <QtScript/qscriptengine.h>
+#include <QtNetwork/qnetworkrequest.h>
+#include <QtNetwork/qnetworkreply.h>
+#include <QtCore/qfile.h>
+
+#include <private/qdeclarativeengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QV8Include::QV8Include(const QUrl &url, QV8Engine *engine, QDeclarativeContextData *context,
+ v8::Handle<v8::Object> qmlglobal, v8::Handle<v8::Function> callback)
+: m_engine(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0), m_context(context)
+{
+ m_qmlglobal = qPersistentNew<v8::Object>(qmlglobal);
+ if (!callback.IsEmpty())
+ m_callbackFunction = qPersistentNew<v8::Function>(callback);
+
+ m_resultObject = qPersistentNew<v8::Object>(resultValue());
+
+ m_network = engine->networkAccessManager();
+
+ QNetworkRequest request;
+ request.setUrl(url);
+
+ m_reply = m_network->get(request);
+ QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
+}
+
+QV8Include::~QV8Include()
+{
+ delete m_reply; m_reply = 0;
+ qPersistentDispose(m_callbackFunction);
+ qPersistentDispose(m_resultObject);
+}
+
+v8::Local<v8::Object> QV8Include::resultValue(Status status)
+{
+ // XXX It seems inefficient to create this object from scratch each time.
+ v8::Local<v8::Object> result = v8::Object::New();
+ result->Set(v8::String::New("OK"), v8::Integer::New(Ok));
+ result->Set(v8::String::New("LOADING"), v8::Integer::New(Loading));
+ result->Set(v8::String::New("NETWORK_ERROR"), v8::Integer::New(NetworkError));
+ result->Set(v8::String::New("EXCEPTION"), v8::Integer::New(Exception));
+
+ result->Set(v8::String::New("status"), v8::Integer::New(status));
+
+ return result;
+}
+
+void QV8Include::callback(QV8Engine *engine, v8::Handle<v8::Function> callback, v8::Handle<v8::Object> status)
+{
+ if (!callback.IsEmpty()) {
+ v8::Handle<v8::Value> args[] = { status };
+ v8::TryCatch tc;
+ callback->Call(engine->global(), 1, args);
+ }
+}
+
+v8::Handle<v8::Object> QV8Include::result()
+{
+ return m_resultObject;
+}
+
+#define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15
+void QV8Include::finished()
+{
+ m_redirectCount++;
+
+ if (m_redirectCount < INCLUDE_MAXIMUM_REDIRECT_RECURSION) {
+ QVariant redirect = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ m_url = m_url.resolved(redirect.toUrl());
+ delete m_reply;
+
+ QNetworkRequest request;
+ request.setUrl(m_url);
+
+ m_reply = m_network->get(request);
+ QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
+ return;
+ }
+ }
+
+ v8::HandleScope handle_scope;
+
+ if (m_reply->error() == QNetworkReply::NoError) {
+ QByteArray data = m_reply->readAll();
+
+ QString code = QString::fromUtf8(data);
+ QDeclarativeScriptParser::extractPragmas(code);
+
+ QDeclarativeContextData *importContext = new QDeclarativeContextData;
+ importContext->isInternal = true;
+ importContext->isJSContext = true;
+ importContext->url = m_url;
+ importContext->setParent(m_context, true);
+
+ v8::Context::Scope ctxtscope(m_engine->context());
+ v8::TryCatch try_catch;
+
+ v8::Local<v8::Script> script = m_engine->qmlModeCompile(code, m_url.toString());
+
+ if (!try_catch.HasCaught()) {
+ m_engine->contextWrapper()->addSubContext(m_qmlglobal, script, importContext);
+ script->Run(m_qmlglobal);
+ }
+
+ if (try_catch.HasCaught()) {
+ m_resultObject->Set(v8::String::New("status"), v8::Integer::New(Exception));
+ m_resultObject->Set(v8::String::New("exception"), try_catch.Exception());
+ } else {
+ m_resultObject->Set(v8::String::New("status"), v8::Integer::New(Ok));
+ }
+ } else {
+ m_resultObject->Set(v8::String::New("status"), v8::Integer::New(NetworkError));
+ }
+
+ callback(m_engine, m_callbackFunction, m_resultObject);
+
+ disconnect();
+ deleteLater();
+}
+
+/*
+ Documented in qv8engine.cpp
+*/
+v8::Handle<v8::Value> QV8Include::include(const v8::Arguments &args)
+{
+ if (args.Length() == 0)
+ return v8::Undefined();
+
+ QV8Engine *engine = V8ENGINE();
+ QDeclarativeContextData *context = engine->callingContext();
+
+ if (!context || !context->isJSContext)
+ V8THROW_ERROR("Qt.include(): Can only be called from JavaScript files");
+
+ QUrl url(context->resolvedUrl(QUrl(engine->toString(args[0]->ToString()))));
+
+ v8::Local<v8::Function> callbackFunction;
+ if (args.Length() >= 2 && args[1]->IsFunction())
+ callbackFunction = v8::Local<v8::Function>::Cast(args[1]);
+
+ QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
+
+ v8::Local<v8::Object> result;
+
+ if (localFile.isEmpty()) {
+
+ QV8Include *i = new QV8Include(url, engine, context,
+ v8::Context::GetCallingQmlGlobal(),
+ callbackFunction);
+ result = v8::Local<v8::Object>::New(i->result());
+
+ } else {
+
+ QFile f(localFile);
+
+ if (f.open(QIODevice::ReadOnly)) {
+ QByteArray data = f.readAll();
+ QString code = QString::fromUtf8(data);
+ QDeclarativeScriptParser::extractPragmas(code);
+
+ QDeclarativeContextData *importContext = new QDeclarativeContextData;
+ importContext->isInternal = true;
+ importContext->isJSContext = true;
+ importContext->url = url;
+ importContext->setParent(context, true);
+
+ v8::TryCatch try_catch;
+
+ v8::Local<v8::Script> script = engine->qmlModeCompile(code, url.toString());
+
+ if (!try_catch.HasCaught()) {
+ v8::Local<v8::Object> qmlglobal = v8::Context::GetCallingQmlGlobal();
+ engine->contextWrapper()->addSubContext(qmlglobal, script, importContext);
+ script->Run(qmlglobal);
+ }
+
+ if (try_catch.HasCaught()) {
+ result = resultValue(Exception);
+ result->Set(v8::String::New("exception"), try_catch.Exception());
+ } else {
+ result = resultValue(Ok);
+ }
+
+ } else {
+ result = resultValue(NetworkError);
+ }
+
+ callback(engine, callbackFunction, result);
+ }
+
+ if (result.IsEmpty())
+ return v8::Undefined();
+ else
+ return result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativeinclude_p.h b/src/declarative/qml/v8/qv8include_p.h
index e923d39d43..eb5c2a0103 100644
--- a/src/declarative/qml/qdeclarativeinclude_p.h
+++ b/src/declarative/qml/v8/qv8include_p.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QDECLARATIVEINCLUDE_P_H
-#define QDECLARATIVEINCLUDE_P_H
+#ifndef QV8INCLUDE_P_H
+#define QV8INCLUDE_P_H
//
// W A R N I N G
@@ -55,19 +55,19 @@
#include <QtCore/qobject.h>
#include <QtCore/qurl.h>
-#include <QtScript/qscriptvalue.h>
#include <private/qdeclarativecontext_p.h>
#include <private/qdeclarativeguard_p.h>
+#include <private/qv8_p.h>
+
QT_BEGIN_NAMESPACE
class QDeclarativeEngine;
-class QScriptContext;
-class QScriptEngine;
class QNetworkAccessManager;
class QNetworkReply;
-class QDeclarativeInclude : public QObject
+class QV8Engine;
+class QV8Include : public QObject
{
Q_OBJECT
public:
@@ -78,38 +78,36 @@ public:
Exception = 3
};
- QDeclarativeInclude(const QUrl &, QDeclarativeEngine *, QScriptContext *ctxt);
- ~QDeclarativeInclude();
-
- void setCallback(const QScriptValue &);
- QScriptValue callback() const;
+ static v8::Handle<v8::Value> include(const v8::Arguments &args);
- QScriptValue result() const;
+private slots:
+ void finished();
- static QScriptValue resultValue(QScriptEngine *, Status status = Loading);
- static void callback(QScriptEngine *, QScriptValue &callback, QScriptValue &status);
+private:
+ QV8Include(const QUrl &, QV8Engine *, QDeclarativeContextData *,
+ v8::Handle<v8::Object>, v8::Handle<v8::Function>);
+ ~QV8Include();
- static QScriptValue include(QScriptContext *ctxt, QScriptEngine *engine);
- static QScriptValue worker_include(QScriptContext *ctxt, QScriptEngine *engine);
+ v8::Handle<v8::Object> result();
-public slots:
- void finished();
+ static v8::Local<v8::Object> resultValue(Status status = Loading);
+ static void callback(QV8Engine *engine, v8::Handle<v8::Function> callback, v8::Handle<v8::Object> status);
-private:
- QDeclarativeEngine *m_engine;
- QScriptEngine *m_scriptEngine;
+ QV8Engine *m_engine;
QNetworkAccessManager *m_network;
QDeclarativeGuard<QNetworkReply> m_reply;
QUrl m_url;
int m_redirectCount;
- QScriptValue m_callback;
- QScriptValue m_result;
+
+ v8::Persistent<v8::Function> m_callbackFunction;
+ v8::Persistent<v8::Object> m_resultObject;
+
QDeclarativeGuardedContextData m_context;
- QScriptValue m_scope[2];
+ v8::Persistent<v8::Object> m_qmlglobal;
};
QT_END_NAMESPACE
-#endif // QDECLARATIVEINCLUDE_P_H
+#endif // QV8INCLUDE_P_H
diff --git a/src/declarative/qml/v8/qv8listwrapper.cpp b/src/declarative/qml/v8/qv8listwrapper.cpp
new file mode 100644
index 0000000000..5f2d9fb91e
--- /dev/null
+++ b/src/declarative/qml/v8/qv8listwrapper.cpp
@@ -0,0 +1,178 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8listwrapper_p.h"
+#include "qv8engine_p.h"
+#include <private/qdeclarativelist_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8ListResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(ListType);
+public:
+ QV8ListResource(QV8Engine *engine) : QV8ObjectResource(engine) {}
+
+ QDeclarativeGuard<QObject> object;
+ QDeclarativeListProperty<QObject> property;
+ int propertyType;
+};
+
+QV8ListWrapper::QV8ListWrapper()
+: m_engine(0)
+{
+}
+
+QV8ListWrapper::~QV8ListWrapper()
+{
+}
+
+void QV8ListWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
+ ft->InstanceTemplate()->SetIndexedPropertyHandler(IndexedGetter);
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("length"), LengthGetter, 0,
+ v8::Handle<v8::Value>(), v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+}
+
+void QV8ListWrapper::destroy()
+{
+ qPersistentDispose(m_constructor);
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::newList(QObject *object, int propId, int propType)
+{
+ if (!object || propId == -1)
+ return v8::Null();
+
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8ListResource *r = new QV8ListResource(m_engine);
+ r->object = object;
+ r->propertyType = propType;
+ void *args[] = { &r->property, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, propId, args);
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::newList(const QDeclarativeListProperty<QObject> &prop, int propType)
+{
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8ListResource *r = new QV8ListResource(m_engine);
+ r->object = prop.object;
+ r->property = prop;
+ r->propertyType = propType;
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+QVariant QV8ListWrapper::toVariant(v8::Handle<v8::Object> obj)
+{
+ QV8ListResource *resource = v8_resource_cast<QV8ListResource>(obj);
+ if (resource) return toVariant(resource);
+ else return QVariant();
+}
+
+QVariant QV8ListWrapper::toVariant(QV8ObjectResource *r)
+{
+ Q_ASSERT(r->resourceType() == QV8ObjectResource::ListType);
+ QV8ListResource *resource = static_cast<QV8ListResource *>(r);
+
+ if (!resource->object)
+ return QVariant();
+
+ return QVariant::fromValue(QDeclarativeListReferencePrivate::init(resource->property, resource->propertyType,
+ m_engine->engine()));
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ Q_UNUSED(info);
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ Q_UNUSED(info);
+ return value;
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::IndexedGetter(uint32_t index, const v8::AccessorInfo &info)
+{
+ QV8ListResource *resource = v8_resource_cast<QV8ListResource>(info.This());
+
+ if (!resource || resource->object.isNull()) return v8::Undefined();
+
+ quint32 count = resource->property.count?resource->property.count(&resource->property):0;
+ if (index < count && resource->property.at) {
+ return resource->engine->newQObject(resource->property.at(&resource->property, index));
+ } else {
+ return v8::Undefined();
+ }
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::LengthGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+
+ QV8ListResource *resource = v8_resource_cast<QV8ListResource>(info.This());
+
+ if (!resource || resource->object.isNull()) return v8::Undefined();
+
+ quint32 count = resource->property.count?resource->property.count(&resource->property):0;
+
+ return v8::Integer::NewFromUnsigned(count);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/v8/qv8listwrapper_p.h b/src/declarative/qml/v8/qv8listwrapper_p.h
new file mode 100644
index 0000000000..82fdaa7271
--- /dev/null
+++ b/src/declarative/qml/v8/qv8listwrapper_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8LISTWRAPPER_P_H
+#define QV8LISTWRAPPER_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 <QtCore/qglobal.h>
+#include <QtDeclarative/qdeclarativelist.h>
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8Engine;
+class QV8ObjectResource;
+class QV8ListWrapper
+{
+public:
+ QV8ListWrapper();
+ ~QV8ListWrapper();
+
+ void init(QV8Engine *);
+ void destroy();
+
+ v8::Handle<v8::Value> newList(QObject *, int, int);
+ v8::Handle<v8::Value> newList(const QDeclarativeListProperty<QObject> &, int);
+ QVariant toVariant(v8::Handle<v8::Object>);
+ QVariant toVariant(QV8ObjectResource *);
+
+private:
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> IndexedGetter(uint32_t index,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> LengthGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+
+ QV8Engine *m_engine;
+ v8::Persistent<v8::Function> m_constructor;
+};
+
+QT_END_NAMESPACE
+
+#endif // QV8LISTWRAPPER_P_H
+
diff --git a/src/declarative/qml/v8/qv8qobjectwrapper.cpp b/src/declarative/qml/v8/qv8qobjectwrapper.cpp
new file mode 100644
index 0000000000..02eb346137
--- /dev/null
+++ b/src/declarative/qml/v8/qv8qobjectwrapper.cpp
@@ -0,0 +1,1868 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8qobjectwrapper_p.h"
+#include "qv8contextwrapper_p.h"
+#include "qv8engine_p.h"
+
+#include <private/qdeclarativeguard_p.h>
+#include <private/qdeclarativepropertycache_p.h>
+#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativevmemetaobject_p.h>
+#include <private/qdeclarativebinding_p.h>
+
+#include <QtScript/qscriptvalue.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qatomic.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_METATYPE(QScriptValue);
+Q_DECLARE_METATYPE(QDeclarativeV8Handle);
+
+#if defined(__GNUC__)
+# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
+// The code in this file does not violate strict aliasing, but GCC thinks it does
+// so turn off the warnings for us to have a clean build
+# pragma GCC diagnostic ignored "-Wstrict-aliasing"
+# endif
+#endif
+
+#define QOBJECT_TOSTRING_INDEX -2
+#define QOBJECT_DESTROY_INDEX -3
+
+// XXX TODO: Need to review all calls to QDeclarativeEngine *engine() to confirm QObjects work
+// correctly in a worker thread
+
+class QV8QObjectResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(QObjectType);
+
+public:
+ QV8QObjectResource(QV8Engine *engine, QObject *object);
+
+ QDeclarativeGuard<QObject> object;
+};
+
+class QV8QObjectInstance : public QDeclarativeGuard<QObject>
+{
+public:
+ QV8QObjectInstance(QObject *o, QV8QObjectWrapper *w)
+ : QDeclarativeGuard<QObject>(o), wrapper(w)
+ {
+ }
+
+ ~QV8QObjectInstance()
+ {
+ qPersistentDispose(v8object);
+ }
+
+ virtual void objectDestroyed(QObject *o)
+ {
+ if (wrapper)
+ wrapper->m_taintedObjects.remove(o);
+ delete this;
+ }
+
+ v8::Persistent<v8::Object> v8object;
+ QV8QObjectWrapper *wrapper;
+};
+
+namespace {
+struct MetaCallArgument {
+ inline MetaCallArgument();
+ inline ~MetaCallArgument();
+ inline void *dataPtr();
+
+ inline void initAsType(int type);
+ inline void fromValue(int type, QV8Engine *, v8::Handle<v8::Value>);
+ inline v8::Handle<v8::Value> toValue(QV8Engine *);
+
+private:
+ MetaCallArgument(const MetaCallArgument &);
+
+ inline void cleanup();
+
+ char data[4 * sizeof(void *)];
+ int type;
+ bool isObjectType;
+};
+}
+
+QV8QObjectResource::QV8QObjectResource(QV8Engine *engine, QObject *object)
+: QV8ObjectResource(engine), object(object)
+{
+}
+
+static QAtomicInt objectIdCounter(1);
+
+QV8QObjectWrapper::QV8QObjectWrapper()
+: m_engine(0), m_id(objectIdCounter.fetchAndAddOrdered(1))
+{
+}
+
+QV8QObjectWrapper::~QV8QObjectWrapper()
+{
+ for (TaintedHash::Iterator iter = m_taintedObjects.begin();
+ iter != m_taintedObjects.end();
+ ++iter) {
+ (*iter)->wrapper = 0;
+ }
+ m_taintedObjects.clear();
+}
+
+void QV8QObjectWrapper::destroy()
+{
+ qDeleteAll(m_connections);
+ m_connections.clear();
+
+ qPersistentDispose(m_hiddenObject);
+ qPersistentDispose(m_destroySymbol);
+ qPersistentDispose(m_toStringSymbol);
+ qPersistentDispose(m_methodConstructor);
+ qPersistentDispose(m_constructor);
+}
+
+#define FAST_VALUE_GETTER(name, cpptype, defaultvalue, constructor) \
+static v8::Handle<v8::Value> name ## ValueGetter(v8::Local<v8::String>, const v8::AccessorInfo &info) \
+{ \
+ v8::Handle<v8::Object> This = info.This(); \
+ QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(This); \
+ \
+ if (!resource || resource->object.isNull()) return v8::Undefined(); \
+ \
+ QObject *object = resource->object; \
+ \
+ uint32_t data = info.Data()->Uint32Value(); \
+ int index = data & 0x7FFF; \
+ int notify = (data & 0x7FFF0000) >> 16; \
+ if (notify == 0x7FFF) notify = -1; \
+ \
+ QDeclarativeEnginePrivate *ep = resource->engine->engine()?QDeclarativeEnginePrivate::get(resource->engine->engine()):0; \
+ if (ep && notify /* 0 means constant */ && ep->captureProperties) { \
+ typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty; \
+ ep->capturedProperties << CapturedProperty(object, index, notify); \
+ } \
+ \
+ cpptype value = defaultvalue; \
+ void *args[] = { &value, 0 }; \
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, index, args); \
+ \
+ return constructor(value); \
+}
+
+#define CREATE_FUNCTION \
+ "(function(method) { "\
+ "return (function(object, data, qmlglobal) { "\
+ "return (function() { "\
+ "return method(object, data, qmlglobal, arguments.length, arguments); "\
+ "});"\
+ "});"\
+ "})"
+
+void QV8QObjectWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+
+ m_toStringSymbol = qPersistentNew<v8::String>(v8::String::NewSymbol("toString"));
+ m_destroySymbol = qPersistentNew<v8::String>(v8::String::NewSymbol("destroy"));
+ m_hiddenObject = qPersistentNew<v8::Object>(v8::Object::New());
+
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter, Query, 0, Enumerator);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+ {
+ v8::ScriptOrigin origin(m_hiddenObject); // Hack to allow us to identify these functions
+ v8::Local<v8::Script> script = v8::Script::New(v8::String::New(CREATE_FUNCTION), &origin);
+ v8::Local<v8::Function> fn = v8::Local<v8::Function>::Cast(script->Run());
+ v8::Handle<v8::Value> invokeFn = v8::FunctionTemplate::New(Invoke)->GetFunction();
+ v8::Handle<v8::Value> args[] = { invokeFn };
+ v8::Local<v8::Function> createFn = v8::Local<v8::Function>::Cast(fn->Call(engine->global(), 1, args));
+ m_methodConstructor = qPersistentNew<v8::Function>(createFn);
+ }
+
+ {
+ v8::Local<v8::Object> prototype = engine->global()->Get(v8::String::New("Function"))->ToObject()->Get(v8::String::New("prototype"))->ToObject();
+ prototype->Set(v8::String::New("connect"), V8FUNCTION(Connect, engine));
+ prototype->Set(v8::String::New("disconnect"), V8FUNCTION(Disconnect, engine));
+ }
+}
+
+bool QV8QObjectWrapper::isQObject(v8::Handle<v8::Object> obj)
+{
+ return v8_resource_cast<QV8QObjectResource>(obj) != 0;
+}
+
+QObject *QV8QObjectWrapper::toQObject(v8::Handle<v8::Object> obj)
+{
+ QV8QObjectResource *r = v8_resource_cast<QV8QObjectResource>(obj);
+ return r?r->object:0;
+}
+
+// r *MUST* be a QV8ObjectResource (r->type() == QV8ObjectResource::QObjectType)
+QObject *QV8QObjectWrapper::QV8QObjectWrapper::toQObject(QV8ObjectResource *r)
+{
+ Q_ASSERT(r->resourceType() == QV8ObjectResource::QObjectType);
+ return static_cast<QV8QObjectResource *>(r)->object;
+}
+
+// Load value properties
+static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object,
+ const QDeclarativePropertyCache::Data &property)
+{
+ Q_ASSERT(!property.isFunction());
+
+#define PROPERTY_LOAD(metatype, cpptype, constructor) \
+ if (property.propType == QMetaType:: metatype) { \
+ cpptype type = cpptype(); \
+ void *args[] = { &type, 0 }; \
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, property.coreIndex, args); \
+ return constructor(type); \
+ }
+
+ if (property.isQObject()) {
+ QObject *rv = 0;
+ void *args[] = { &rv, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, property.coreIndex, args);
+ return engine->newQObject(rv);
+ } else if (property.isQList()) {
+ return engine->listWrapper()->newList(object, property.coreIndex, property.propType);
+ } else PROPERTY_LOAD(QReal, qreal, v8::Number::New)
+ else PROPERTY_LOAD(Int || property.isEnum(), int, v8::Number::New)
+ else PROPERTY_LOAD(Bool, bool, v8::Boolean::New)
+ else PROPERTY_LOAD(QString, QString, engine->toString)
+ else PROPERTY_LOAD(UInt, uint, v8::Integer::NewFromUnsigned)
+ else PROPERTY_LOAD(Float, float, v8::Number::New)
+ else PROPERTY_LOAD(Double, double, v8::Number::New)
+ else if(property.isV8Handle()) {
+ QDeclarativeV8Handle handle;
+ void *args[] = { &handle, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, property.coreIndex, args);
+ return reinterpret_cast<v8::Handle<v8::Value> &>(handle);
+ } else if (QDeclarativeValueTypeFactory::isValueType((uint)property.propType)) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine());
+ QDeclarativeValueType *valueType = ep->valueTypes[property.propType];
+ if (valueType)
+ return engine->newValueType(object, property.coreIndex, valueType);
+ }
+
+ QVariant var = object->metaObject()->property(property.coreIndex).read(object);
+ return engine->fromVariant(var);
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject *object,
+ v8::Handle<v8::Value> *objectHandle,
+ v8::Handle<v8::String> property,
+ QV8QObjectWrapper::RevisionMode revisionMode)
+{
+ // XXX More recent versions of V8 introduced "Callable" objects. It is possible that these
+ // will be a faster way of creating QObject method objects.
+ struct MethodClosure {
+ static v8::Handle<v8::Value> create(QV8Engine *engine, QObject *object,
+ v8::Handle<v8::Value> *objectHandle,
+ int index) {
+ v8::Handle<v8::Value> argv[] = {
+ objectHandle?*objectHandle:engine->newQObject(object),
+ v8::Integer::New(index)
+ };
+ return engine->qobjectWrapper()->m_methodConstructor->Call(engine->global(), 2, argv);
+ }
+ static v8::Handle<v8::Value> createWithGlobal(QV8Engine *engine, QObject *object,
+ v8::Handle<v8::Value> *objectHandle,
+ int index) {
+ v8::Handle<v8::Value> argv[] = {
+ objectHandle?*objectHandle:engine->newQObject(object),
+ v8::Integer::New(index),
+ v8::Context::GetCallingQmlGlobal()
+ };
+ return engine->qobjectWrapper()->m_methodConstructor->Call(engine->global(), 3, argv);
+ }
+ };
+
+ if (engine->qobjectWrapper()->m_toStringSymbol->StrictEquals(property)) {
+ return MethodClosure::create(engine, object, objectHandle, QOBJECT_TOSTRING_INDEX);
+ } else if (engine->qobjectWrapper()->m_destroySymbol->StrictEquals(property)) {
+ return MethodClosure::create(engine, object, objectHandle, QOBJECT_DESTROY_INDEX);
+ }
+
+ QDeclarativePropertyCache::Data local;
+ QDeclarativePropertyCache::Data *result = 0;
+ result = QDeclarativePropertyCache::property(engine->engine(), object, property, local);
+
+ if (!result)
+ return v8::Handle<v8::Value>();
+
+ QDeclarativeEnginePrivate *ep = engine->engine()?QDeclarativeEnginePrivate::get(engine->engine()):0;
+
+ if (revisionMode == QV8QObjectWrapper::CheckRevision && result->revision != 0) {
+ QDeclarativeData *ddata = QDeclarativeData::get(object);
+ if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result))
+ return v8::Handle<v8::Value>();
+ }
+
+ typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty;
+
+ if (result->isFunction()) {
+ if (result->flags & QDeclarativePropertyCache::Data::IsVMEFunction) {
+ return ((QDeclarativeVMEMetaObject *)(object->metaObject()))->vmeMethod(result->coreIndex);
+ } else if (result->flags & QDeclarativePropertyCache::Data::IsV8Function) {
+ return MethodClosure::createWithGlobal(engine, object, objectHandle, result->coreIndex);
+ } else {
+ return MethodClosure::create(engine, object, objectHandle, result->coreIndex);
+ }
+ }
+
+ if (ep && ep->captureProperties && !result->isConstant()) {
+ if (result->coreIndex == 0)
+ ep->capturedProperties << CapturedProperty(QDeclarativeData::get(object, true)->objectNameNotifier());
+ else
+ ep->capturedProperties << CapturedProperty(object, result->coreIndex, result->notifyIndex);
+ }
+
+ return LoadProperty(engine, object, *result);
+}
+
+// Setter for writable properties. Shared between the interceptor and fast property accessor
+static inline void StoreProperty(QV8Engine *engine, QObject *object, QDeclarativePropertyCache::Data *property,
+ v8::Handle<v8::Value> value)
+{
+ QDeclarativeBinding *newBinding = 0;
+
+ if (value->IsFunction()) {
+ QDeclarativeContextData *context = engine->callingContext();
+ v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
+
+ v8::Local<v8::StackTrace> trace =
+ v8::StackTrace::CurrentStackTrace(1, (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber |
+ v8::StackTrace::kScriptName));
+ v8::Local<v8::StackFrame> frame = trace->GetFrame(0);
+ int lineNumber = frame->GetLineNumber();
+ QString url = engine->toString(frame->GetScriptName());
+
+ QDeclarativePropertyCache::ValueTypeData valueTypeData;
+ newBinding = new QDeclarativeBinding(&function, object, context);
+ newBinding->setSourceLocation(url, lineNumber);
+ newBinding->setTarget(QDeclarativePropertyPrivate::restore(*property, valueTypeData, object, context));
+ newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject);
+ }
+
+ QDeclarativeAbstractBinding *oldBinding =
+ QDeclarativePropertyPrivate::setBinding(object, property->coreIndex, -1, newBinding);
+ if (oldBinding)
+ oldBinding->destroy();
+
+#define PROPERTY_STORE(cpptype, value) \
+ cpptype o = value; \
+ int status = -1; \
+ int flags = 0; \
+ void *argv[] = { &o, 0, &status, &flags }; \
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, property->coreIndex, argv);
+
+
+ if (value->IsNull() && property->isQObject()) {
+ PROPERTY_STORE(QObject*, 0);
+ } else if (value->IsUndefined() && property->isResettable()) {
+ void *a[] = { 0 };
+ QMetaObject::metacall(object, QMetaObject::ResetProperty, property->coreIndex, a);
+ } else if (value->IsUndefined() && property->propType == qMetaTypeId<QVariant>()) {
+ PROPERTY_STORE(QVariant, QVariant());
+ } else if (value->IsUndefined()) {
+ QString error = QLatin1String("Cannot assign [undefined] to ") +
+ QLatin1String(QMetaType::typeName(property->propType));
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ } else if (value->IsFunction()) {
+ // this is handled by the binding creation above
+ } else if (property->propType == QMetaType::Int && value->IsNumber()) {
+ PROPERTY_STORE(int, qRound(value->ToNumber()->Value()));
+ } else if (property->propType == QMetaType::QReal && value->IsNumber()) {
+ PROPERTY_STORE(qreal, qreal(value->ToNumber()->Value()));
+ } else if (property->propType == QMetaType::Float && value->IsNumber()) {
+ PROPERTY_STORE(float, float(value->ToNumber()->Value()));
+ } else if (property->propType == QMetaType::Double && value->IsNumber()) {
+ PROPERTY_STORE(double, double(value->ToNumber()->Value()));
+ } else if (property->propType == QMetaType::QString && value->IsString()) {
+ PROPERTY_STORE(QString, engine->toString(value->ToString()));
+ } else {
+ QVariant v;
+ if (property->isQList())
+ v = engine->toVariant(value, qMetaTypeId<QList<QObject *> >());
+ else
+ v = engine->toVariant(value, property->propType);
+
+ QDeclarativeContextData *context = engine->callingContext();
+
+ if (!QDeclarativePropertyPrivate::write(object, *property, v, context)) {
+ const char *valueType = 0;
+ if (v.userType() == QVariant::Invalid) valueType = "null";
+ else valueType = QMetaType::typeName(v.userType());
+
+ QString error = QLatin1String("Cannot assign ") +
+ QLatin1String(valueType) +
+ QLatin1String(" to ") +
+ QLatin1String(QMetaType::typeName(property->propType));
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ }
+ }
+}
+
+bool QV8QObjectWrapper::SetProperty(QV8Engine *engine, QObject *object, v8::Handle<v8::String> property,
+ v8::Handle<v8::Value> value, QV8QObjectWrapper::RevisionMode revisionMode)
+{
+ if (engine->qobjectWrapper()->m_toStringSymbol->StrictEquals(property) ||
+ engine->qobjectWrapper()->m_destroySymbol->StrictEquals(property))
+ return true;
+
+ QDeclarativePropertyCache::Data local;
+ QDeclarativePropertyCache::Data *result = 0;
+ result = QDeclarativePropertyCache::property(engine->engine(), object, property, local);
+
+ if (!result)
+ return false;
+
+ if (revisionMode == QV8QObjectWrapper::CheckRevision && result->revision != 0) {
+ QDeclarativeData *ddata = QDeclarativeData::get(object);
+ if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result))
+ return false;
+ }
+
+ if (!result->isWritable() && !result->isQList()) {
+ QString error = QLatin1String("Cannot assign to read-only property \"") +
+ engine->toString(property) + QLatin1Char('\"');
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return true;
+ }
+
+ StoreProperty(engine, object, result, value);
+
+ return true;
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(info.This());
+ v8::Handle<v8::Value> This = info.This();
+
+ if (!resource || resource->object.isNull()) return v8::Undefined();
+
+ QObject *object = resource->object;
+
+ QV8Engine *v8engine = resource->engine;
+ v8::Handle<v8::Value> result = GetProperty(v8engine, object, &This, property, QV8QObjectWrapper::IgnoreRevision);
+ if (!result.IsEmpty())
+ return result;
+
+ if (QV8Engine::startsWithUpper(property)) {
+ // Check for attached properties
+ QDeclarativeContextData *context = v8engine->callingContext();
+ QDeclarativeTypeNameCache::Data *data = context && (context->imports)?context->imports->data(property):0;
+
+ if (data) {
+ if (data->type) {
+ return v8engine->typeWrapper()->newObject(object, data->type, QV8TypeWrapper::ExcludeEnums);
+ } else if (data->typeNamespace) {
+ return v8engine->typeWrapper()->newObject(object, data->typeNamespace, QV8TypeWrapper::ExcludeEnums);
+ }
+ }
+ }
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(info.This());
+
+ if (!resource || resource->object.isNull())
+ return value;
+
+ QObject *object = resource->object;
+
+ QV8Engine *v8engine = resource->engine;
+ bool result = SetProperty(v8engine, object, property, value, QV8QObjectWrapper::IgnoreRevision);
+
+ if (!result) {
+ QString error = QLatin1String("Cannot assign to non-existent property \"") +
+ v8engine->toString(property) + QLatin1Char('\"');
+ v8::ThrowException(v8::Exception::Error(v8engine->toString(error)));
+ return value;
+ }
+
+ return value;
+}
+
+v8::Handle<v8::Integer> QV8QObjectWrapper::Query(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(info.This());
+
+ if (!resource || resource->object.isNull())
+ return v8::Handle<v8::Integer>();
+
+ QV8Engine *engine = resource->engine;
+ QObject *object = resource->object;
+
+ QDeclarativePropertyCache::Data local;
+ QDeclarativePropertyCache::Data *result = 0;
+ result = QDeclarativePropertyCache::property(engine->engine(), object, property, local);
+
+ if (!result)
+ return v8::Handle<v8::Integer>();
+ else if (!result->isWritable() && !result->isQList())
+ return v8::Integer::New(v8::ReadOnly | v8::DontDelete);
+ else
+ return v8::Integer::New(v8::DontDelete);
+}
+
+v8::Handle<v8::Array> QV8QObjectWrapper::Enumerator(const v8::AccessorInfo &info)
+{
+ QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(info.This());
+
+ if (!resource || resource->object.isNull())
+ return v8::Array::New();
+
+ QObject *object = resource->object;
+
+ QStringList result;
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(resource->engine->engine());
+
+ QDeclarativePropertyCache *cache = 0;
+ QDeclarativeData *ddata = QDeclarativeData::get(object);
+ if (ddata)
+ cache = ddata->propertyCache;
+
+ if (!cache) {
+ cache = ep->cache(object);
+ if (cache) {
+ if (ddata) { cache->addref(); ddata->propertyCache = cache; }
+ } else {
+ // Not cachable - fall back to QMetaObject (eg. dynamic meta object)
+ const QMetaObject *mo = object->metaObject();
+ int pc = mo->propertyCount();
+ int po = mo->propertyOffset();
+ for (int i=po; i<pc; ++i)
+ result << QString::fromUtf8(mo->property(i).name());
+ }
+ } else {
+ result = cache->propertyNames();
+ }
+
+ v8::Local<v8::Array> rv = v8::Array::New(result.count());
+
+ for (int ii = 0; ii < result.count(); ++ii)
+ rv->Set(ii, resource->engine->toString(result.at(ii)));
+
+ return rv;
+}
+
+FAST_VALUE_GETTER(QObject, QObject*, 0, resource->engine->newQObject);
+FAST_VALUE_GETTER(Int, int, 0, v8::Integer::New);
+FAST_VALUE_GETTER(Bool, bool, false, v8::Boolean::New);
+FAST_VALUE_GETTER(QString, QString, QString(), resource->engine->toString);
+FAST_VALUE_GETTER(UInt, uint, 0, v8::Integer::NewFromUnsigned);
+FAST_VALUE_GETTER(Float, float, 0, v8::Number::New);
+FAST_VALUE_GETTER(Double, double, 0, v8::Number::New);
+
+static void FastValueSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
+ const v8::AccessorInfo& info)
+{
+ QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(info.This());
+
+ if (!resource || resource->object.isNull())
+ return;
+
+ QObject *object = resource->object;
+
+ uint32_t data = info.Data()->Uint32Value();
+ int index = data & 0x7FFF; // So that we can use the same data for Setter and Getter
+
+ QDeclarativeData *ddata = QDeclarativeData::get(object, false);
+ Q_ASSERT(ddata);
+ Q_ASSERT(ddata->propertyCache);
+
+ QDeclarativePropertyCache::Data *pdata = ddata->propertyCache->property(index);
+ Q_ASSERT(pdata);
+
+ Q_ASSERT(pdata->isWritable() || pdata->isQList());
+
+ StoreProperty(resource->engine, object, pdata, value);
+}
+
+static void WeakQObjectReferenceCallback(v8::Persistent<v8::Value> handle, void *)
+{
+ Q_ASSERT(handle->IsObject());
+
+ QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(handle->ToObject());
+
+ Q_ASSERT(resource);
+
+ QObject *object = resource->object;
+ if (object) {
+ QDeclarativeData *ddata = QDeclarativeData::get(object, false);
+ if (ddata) {
+ ddata->v8object.Clear();
+ if (!object->parent() && !ddata->indestructible)
+ object->deleteLater();
+ }
+ }
+
+ qPersistentDispose(handle);
+}
+
+static void WeakQObjectInstanceCallback(v8::Persistent<v8::Value> handle, void *data)
+{
+ QV8QObjectInstance *instance = (QV8QObjectInstance *)data;
+ instance->v8object.Clear();
+ qPersistentDispose(handle);
+}
+
+v8::Local<v8::Object> QDeclarativePropertyCache::newQObject(QObject *object, QV8Engine *engine)
+{
+ Q_ASSERT(object);
+
+ Q_ASSERT(QDeclarativeData::get(object, false));
+ Q_ASSERT(QDeclarativeData::get(object, false)->propertyCache == this);
+
+ // Setup constructor
+ if (constructor.IsEmpty()) {
+ v8::Local<v8::FunctionTemplate> ft;
+
+ QString toString = QLatin1String("toString");
+ QString destroy = QLatin1String("destroy");
+
+ // XXX TODO: Enables fast property accessors. These more than double the property access
+ // performance, but the cost of setting up this structure hasn't been measured so
+ // its not guarenteed that this is a win overall. We need to try and measure the cost.
+ for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) {
+ Data *property = *iter;
+ if (property->isFunction() || !property->isWritable() ||
+ property->coreIndex >= 0x7FFF || property->notifyIndex >= 0x7FFF ||
+ property->coreIndex == 0)
+ continue;
+
+ v8::AccessorGetter fastgetter = 0;
+
+
+ if (property->isQObject())
+ fastgetter = QObjectValueGetter;
+ else if (property->propType == QMetaType::Int || property->isEnum())
+ fastgetter = IntValueGetter;
+ else if (property->propType == QMetaType::Bool)
+ fastgetter = BoolValueGetter;
+ else if (property->propType == QMetaType::QString)
+ fastgetter = QStringValueGetter;
+ else if (property->propType == QMetaType::UInt)
+ fastgetter = UIntValueGetter;
+ else if (property->propType == QMetaType::Float)
+ fastgetter = FloatValueGetter;
+ else if (property->propType == QMetaType::Double)
+ fastgetter = DoubleValueGetter;
+
+ if (fastgetter) {
+ int notifyIndex = property->notifyIndex;
+ if (property->isConstant()) notifyIndex = 0;
+ else if (notifyIndex == -1) notifyIndex = 0x7FFF;
+ uint32_t data = (property->notifyIndex & 0x7FFF) << 16 | property->coreIndex;
+
+ QString name = iter.key();
+ if (name == toString || name == destroy)
+ continue;
+
+ if (ft.IsEmpty()) {
+ ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(QV8QObjectWrapper::Getter,
+ QV8QObjectWrapper::Setter,
+ QV8QObjectWrapper::Query,
+ 0,
+ QV8QObjectWrapper::Enumerator);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ }
+
+ ft->InstanceTemplate()->SetAccessor(engine->toString(name), fastgetter, FastValueSetter,
+ v8::Integer::NewFromUnsigned(data));
+ }
+ }
+
+ if (ft.IsEmpty()) {
+ constructor = qPersistentNew<v8::Function>(engine->qobjectWrapper()->m_constructor);
+ } else {
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(QV8QObjectWrapper::Getter,
+ QV8QObjectWrapper::Setter,
+ QV8QObjectWrapper::Query,
+ 0,
+ QV8QObjectWrapper::Enumerator);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+ }
+
+ v8::Local<v8::Object> result = constructor->NewInstance();
+ QV8QObjectResource *r = new QV8QObjectResource(engine, object);
+ result->SetExternalResource(r);
+ return result;
+}
+
+v8::Local<v8::Object> QV8QObjectWrapper::newQObject(QObject *object, QDeclarativeData *ddata, QV8Engine *engine)
+{
+ v8::Local<v8::Object> rv;
+
+ if (ddata->propertyCache) {
+ rv = ddata->propertyCache->newQObject(object, engine);
+ } else {
+ // XXX NewInstance() should be optimized
+ rv = m_constructor->NewInstance();
+ QV8QObjectResource *r = new QV8QObjectResource(engine, object);
+ rv->SetExternalResource(r);
+ }
+
+ return rv;
+}
+
+/*
+As V8 doesn't support an equality callback, for QObject's we have to return exactly the same
+V8 handle for subsequent calls to newQObject for the same QObject. To do this we have a two
+pronged strategy:
+ 1. If there is no current outstanding V8 handle to the QObject, we create one and store a
+ persistent handle in QDeclarativeData::v8object. We mark the QV8QObjectWrapper that
+ "owns" this handle by setting the QDeclarativeData::v8objectid to the id of this
+ QV8QObjectWrapper.
+ 2. If another QV8QObjectWrapper has create the handle in QDeclarativeData::v8object we create
+ an entry in the m_taintedObject hash where we store the handle and mark the object as
+ "tainted" in the QDeclarativeData::hasTaintedV8Object flag.
+We have to mark the object as tainted to ensure that we search our m_taintedObject hash even
+in the case that the original QV8QObjectWrapper owner of QDeclarativeData::v8object has
+released the handle.
+*/
+v8::Handle<v8::Value> QV8QObjectWrapper::newQObject(QObject *object)
+{
+ if (!object)
+ return v8::Null();
+
+ if (QObjectPrivate::get(object)->wasDeleted)
+ return v8::Undefined();
+
+ QDeclarativeData *ddata = QDeclarativeData::get(object, true);
+
+ if (!ddata)
+ return v8::Undefined();
+
+ if (ddata->v8objectid == m_id && !ddata->v8object.IsEmpty()) {
+ // We own the v8object
+ return v8::Local<v8::Object>::New(ddata->v8object);
+ } else if (ddata->v8object.IsEmpty() &&
+ (ddata->v8objectid == m_id || // We own the QObject
+ ddata->v8objectid == 0 || // No one owns the QObject
+ !ddata->hasTaintedV8Object)) { // Someone else has used the QObject, but it isn't tainted
+
+ v8::Local<v8::Object> rv = newQObject(object, ddata, m_engine);
+ ddata->v8object = qPersistentNew<v8::Object>(rv);
+ ddata->v8object.MakeWeak(0, WeakQObjectReferenceCallback);
+ ddata->v8objectid = m_id;
+ return rv;
+
+ } else {
+ // If this object is tainted, we have to check to see if it is in our
+ // tainted object list
+ TaintedHash::Iterator iter =
+ ddata->hasTaintedV8Object?m_taintedObjects.find(object):m_taintedObjects.end();
+ bool found = iter != m_taintedObjects.end();
+
+ // If our tainted handle doesn't exist or has been collected, and there isn't
+ // a handle in the ddata, we can assume ownership of the ddata->v8object
+ if ((!found || (*iter)->v8object.IsEmpty()) && ddata->v8object.IsEmpty()) {
+ v8::Local<v8::Object> rv = newQObject(object, ddata, m_engine);
+ ddata->v8object = qPersistentNew<v8::Object>(rv);
+ ddata->v8object.MakeWeak(0, WeakQObjectReferenceCallback);
+ ddata->v8objectid = m_id;
+
+ if (found) {
+ delete (*iter);
+ m_taintedObjects.erase(iter);
+ }
+
+ return rv;
+ } else if (!found) {
+ QV8QObjectInstance *instance = new QV8QObjectInstance(object, this);
+ iter = m_taintedObjects.insert(object, instance);
+ ddata->hasTaintedV8Object = true;
+ }
+
+ if ((*iter)->v8object.IsEmpty()) {
+ v8::Local<v8::Object> rv = newQObject(object, ddata, m_engine);
+ (*iter)->v8object = qPersistentNew<v8::Object>(rv);
+ (*iter)->v8object.MakeWeak((*iter), WeakQObjectInstanceCallback);
+ }
+
+ return v8::Local<v8::Object>::New((*iter)->v8object);
+ }
+}
+
+QPair<QObject *, int> QV8QObjectWrapper::ExtractQtMethod(QV8Engine *engine, v8::Handle<v8::Function> function)
+{
+ v8::ScriptOrigin origin = function->GetScriptOrigin();
+ if (origin.ResourceName()->StrictEquals(engine->qobjectWrapper()->m_hiddenObject)) {
+
+ // This is one of our special QObject method wrappers
+ v8::Handle<v8::Value> args[] = { engine->qobjectWrapper()->m_hiddenObject };
+ v8::Local<v8::Value> data = function->Call(engine->global(), 1, args);
+
+ if (data->IsArray()) {
+ v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(data);
+ return qMakePair(engine->toQObject(array->Get(0)), array->Get(1)->Int32Value());
+ }
+
+ // In theory this can't fall through, but I suppose V8 might run out of memory or something
+ }
+
+ return qMakePair((QObject *)0, -1);
+}
+
+struct QV8QObjectConnectionList : public QObject, public QDeclarativeGuard<QObject>
+{
+ QV8QObjectConnectionList(QObject *object, QV8Engine *engine);
+ ~QV8QObjectConnectionList();
+
+ struct Connection {
+ Connection()
+ : needsDestroy(false) {}
+ Connection(const Connection &other)
+ : thisObject(other.thisObject), function(other.function), needsDestroy(false) {}
+ Connection &operator=(const Connection &other) {
+ thisObject = other.thisObject;
+ function = other.function;
+ needsDestroy = other.needsDestroy;
+ return *this;
+ }
+
+ v8::Persistent<v8::Object> thisObject;
+ v8::Persistent<v8::Function> function;
+
+ void dispose() {
+ qPersistentDispose(thisObject);
+ qPersistentDispose(function);
+ }
+
+ bool needsDestroy;
+ };
+
+ struct ConnectionList : public QList<Connection> {
+ ConnectionList() : connectionsInUse(0), connectionsNeedClean(false) {}
+ int connectionsInUse;
+ bool connectionsNeedClean;
+ };
+
+ QV8Engine *engine;
+
+ typedef QHash<int, ConnectionList> SlotHash;
+ SlotHash slotHash;
+ bool needsDestroy;
+ int inUse;
+
+ virtual void objectDestroyed(QObject *);
+ virtual int qt_metacall(QMetaObject::Call, int, void **);
+};
+
+QV8QObjectConnectionList::QV8QObjectConnectionList(QObject *object, QV8Engine *engine)
+: QDeclarativeGuard<QObject>(object), engine(engine), needsDestroy(false), inUse(0)
+{
+}
+
+QV8QObjectConnectionList::~QV8QObjectConnectionList()
+{
+ for (SlotHash::Iterator iter = slotHash.begin(); iter != slotHash.end(); ++iter) {
+ QList<Connection> &connections = *iter;
+ for (int ii = 0; ii < connections.count(); ++ii) {
+ qPersistentDispose(connections[ii].thisObject);
+ qPersistentDispose(connections[ii].function);
+ }
+ }
+ slotHash.clear();
+}
+
+void QV8QObjectConnectionList::objectDestroyed(QObject *object)
+{
+ engine->qobjectWrapper()->m_connections.remove(object);
+
+ if (inUse)
+ needsDestroy = true;
+ else
+ delete this;
+}
+
+int QV8QObjectConnectionList::qt_metacall(QMetaObject::Call method, int index, void **metaArgs)
+{
+ if (method == QMetaObject::InvokeMetaMethod) {
+ SlotHash::Iterator iter = slotHash.find(index);
+ if (iter == slotHash.end())
+ return -1;
+ ConnectionList &connectionList = *iter;
+ if (connectionList.isEmpty())
+ return -1;
+
+ inUse++;
+
+ connectionList.connectionsInUse++;
+
+ QList<Connection> connections = connectionList;
+
+ QMetaMethod method = data()->metaObject()->method(index);
+ Q_ASSERT(method.methodType() == QMetaMethod::Signal);
+ // XXX TODO: We should figure out a way to cache the parameter types to avoid resolving
+ // them each time.
+ QList<QByteArray> params = method.parameterTypes();
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(engine->context());
+
+ QVarLengthArray<v8::Handle<v8::Value> > args(params.count());
+ int argCount = params.count();
+
+ for (int ii = 0; ii < argCount; ++ii) {
+ int type = QMetaType::type(params.at(ii).constData());
+ if (type == qMetaTypeId<QVariant>()) {
+ args[ii] = engine->fromVariant(*((QVariant *)metaArgs[ii + 1]));
+ } else {
+ args[ii] = engine->fromVariant(QVariant(type, metaArgs[ii + 1]));
+ }
+ }
+
+ for (int ii = 0; ii < connections.count(); ++ii) {
+ Connection &connection = connections[ii];
+ if (connection.needsDestroy)
+ continue;
+ if (connection.thisObject.IsEmpty()) {
+ connection.function->Call(engine->global(), argCount, args.data());
+ } else {
+ connection.function->Call(connection.thisObject, argCount, args.data());
+ }
+ }
+
+ connectionList.connectionsInUse--;
+ if (connectionList.connectionsInUse == 0 && connectionList.connectionsNeedClean) {
+ for (QList<Connection>::Iterator iter = connectionList.begin();
+ iter != connectionList.end(); ) {
+ if (iter->needsDestroy) {
+ iter->dispose();
+ iter = connectionList.erase(iter);
+ } else {
+ ++iter;
+ }
+ }
+ }
+
+ inUse--;
+ if (inUse == 0 && needsDestroy)
+ delete this;
+ }
+
+ return -1;
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::Connect(const v8::Arguments &args)
+{
+ if (args.Length() == 0)
+ V8THROW_ERROR("Function.prototype.connect: no arguments given");
+
+ QV8Engine *engine = V8ENGINE();
+
+ if (!args.This()->IsFunction())
+ V8THROW_ERROR("Function.prototype.connect: this object is not a signal");
+
+ QPair<QObject *, int> signalInfo = ExtractQtMethod(engine, v8::Handle<v8::Function>::Cast(args.This()));
+ QObject *signalObject = signalInfo.first;
+ int signalIndex = signalInfo.second;
+
+ if (signalIndex == -1)
+ V8THROW_ERROR("Function.prototype.connect: this object is not a signal");
+
+ if (!signalObject)
+ V8THROW_ERROR("Function.prototype.connect: cannot connect to deleted QObject");
+
+ if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
+ V8THROW_ERROR("Function.prototype.connect: this object is not a signal");
+
+ v8::Local<v8::Value> functionValue;
+ v8::Local<v8::Value> functionThisValue;
+
+ if (args.Length() == 1) {
+ functionValue = args[0];
+ } else {
+ functionThisValue = args[0];
+ functionValue = args[1];
+ }
+
+ if (!functionValue->IsFunction())
+ V8THROW_ERROR("Function.prototype.connect: target is not a function");
+
+ if (!functionThisValue.IsEmpty() && !functionThisValue->IsObject())
+ V8THROW_ERROR("Function.prototype.connect: target this is not an object");
+
+ QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
+ QHash<QObject *, QV8QObjectConnectionList *> &connections = qobjectWrapper->m_connections;
+ QHash<QObject *, QV8QObjectConnectionList *>::Iterator iter = connections.find(signalObject);
+ if (iter == connections.end())
+ iter = connections.insert(signalObject, new QV8QObjectConnectionList(signalObject, engine));
+
+ QV8QObjectConnectionList *connectionList = *iter;
+ QV8QObjectConnectionList::SlotHash::Iterator slotIter = connectionList->slotHash.find(signalIndex);
+ if (slotIter == connectionList->slotHash.end()) {
+ slotIter = connectionList->slotHash.insert(signalIndex, QV8QObjectConnectionList::ConnectionList());
+ QMetaObject::connect(signalObject, signalIndex, connectionList, signalIndex);
+ }
+
+ QV8QObjectConnectionList::Connection connection;
+ if (!functionThisValue.IsEmpty())
+ connection.thisObject = qPersistentNew<v8::Object>(functionThisValue->ToObject());
+ connection.function = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(functionValue));
+
+ slotIter->append(connection);
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::Disconnect(const v8::Arguments &args)
+{
+ if (args.Length() == 0)
+ V8THROW_ERROR("Function.prototype.disconnect: no arguments given");
+
+ QV8Engine *engine = V8ENGINE();
+
+ if (!args.This()->IsFunction())
+ V8THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
+
+ QPair<QObject *, int> signalInfo = ExtractQtMethod(engine, v8::Handle<v8::Function>::Cast(args.This()));
+ QObject *signalObject = signalInfo.first;
+ int signalIndex = signalInfo.second;
+
+ if (signalIndex == -1)
+ V8THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
+
+ if (!signalObject)
+ V8THROW_ERROR("Function.prototype.disconnect: cannot disconnect from deleted QObject");
+
+ if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
+ V8THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
+
+ v8::Local<v8::Value> functionValue;
+ v8::Local<v8::Value> functionThisValue;
+
+ if (args.Length() == 1) {
+ functionValue = args[0];
+ } else {
+ functionThisValue = args[0];
+ functionValue = args[1];
+ }
+
+ if (!functionValue->IsFunction())
+ V8THROW_ERROR("Function.prototype.disconnect: target is not a function");
+
+ if (!functionThisValue.IsEmpty() && !functionThisValue->IsObject())
+ V8THROW_ERROR("Function.prototype.disconnect: target this is not an object");
+
+ QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
+ QHash<QObject *, QV8QObjectConnectionList *> &connectionsList = qobjectWrapper->m_connections;
+ QHash<QObject *, QV8QObjectConnectionList *>::Iterator iter = connectionsList.find(signalObject);
+ if (iter == connectionsList.end())
+ return v8::Undefined(); // Nothing to disconnect from
+
+ QV8QObjectConnectionList *connectionList = *iter;
+ QV8QObjectConnectionList::SlotHash::Iterator slotIter = connectionList->slotHash.find(signalIndex);
+ if (slotIter == connectionList->slotHash.end())
+ return v8::Undefined(); // Nothing to disconnect from
+
+ QV8QObjectConnectionList::ConnectionList &connections = *slotIter;
+
+ v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(functionValue);
+ QPair<QObject *, int> functionData = ExtractQtMethod(engine, function);
+
+ if (functionData.second != -1) {
+ // This is a QObject function wrapper
+ for (int ii = 0; ii < connections.count(); ++ii) {
+ QV8QObjectConnectionList::Connection &connection = connections[ii];
+
+ if (connection.thisObject.IsEmpty() == functionThisValue.IsEmpty() &&
+ (connection.thisObject.IsEmpty() || connection.thisObject->StrictEquals(functionThisValue))) {
+
+ QPair<QObject *, int> connectedFunctionData = ExtractQtMethod(engine, connection.function);
+ if (connectedFunctionData == functionData) {
+ // Match!
+ if (connections.connectionsInUse) {
+ connection.needsDestroy = true;
+ } else {
+ connection.dispose();
+ connections.removeAt(ii);
+ }
+ return v8::Undefined();
+ }
+ }
+ }
+
+ } else {
+ // This is a normal JS function
+ for (int ii = 0; ii < connections.count(); ++ii) {
+ QV8QObjectConnectionList::Connection &connection = connections[ii];
+ if (connection.function->StrictEquals(function) &&
+ connection.thisObject.IsEmpty() == functionThisValue.IsEmpty() &&
+ (connection.thisObject.IsEmpty() || connection.thisObject->StrictEquals(functionThisValue))) {
+ // Match!
+ if (connections.connectionsInUse) {
+ connection.needsDestroy = true;
+ } else {
+ connection.dispose();
+ connections.removeAt(ii);
+ }
+ return v8::Undefined();
+ }
+ }
+ }
+
+ return v8::Undefined();
+}
+
+/*!
+ Get the \a property of \a object. Returns an empty handle if the property doesn't exist.
+
+ Only searches for real properties of \a object (including methods), not attached properties etc.
+*/
+v8::Handle<v8::Value> QV8QObjectWrapper::getProperty(QObject *object, v8::Handle<v8::String> property,
+ QV8QObjectWrapper::RevisionMode revisionMode)
+{
+ return GetProperty(m_engine, object, 0, property, revisionMode);
+}
+
+/*
+ Set the \a property of \a object to \a value.
+
+ Returns true if the property was "set" - even if this results in an exception being thrown -
+ and false if the object has no such property.
+
+ Only searches for real properties of \a object (including methods), not attached properties etc.
+*/
+bool QV8QObjectWrapper::setProperty(QObject *object, v8::Handle<v8::String> property,
+ v8::Handle<v8::Value> value, RevisionMode revisionMode)
+{
+ return SetProperty(m_engine, object, property, value, revisionMode);
+}
+
+namespace {
+struct CallArgs
+{
+ CallArgs(int length, v8::Handle<v8::Object> *args) : _length(length), _args(args) {}
+ int Length() const { return _length; }
+ v8::Local<v8::Value> operator[](int idx) { return (*_args)->Get(idx); }
+
+private:
+ int _length;
+ v8::Handle<v8::Object> *_args;
+};
+}
+
+static v8::Handle<v8::Value> CallMethod(QObject *object, int index, int returnType, int argCount,
+ int *argTypes, QV8Engine *engine, CallArgs &callArgs)
+{
+ if (argCount > 0) {
+
+ QVarLengthArray<MetaCallArgument, 9> args(argCount + 1);
+ args[0].initAsType(returnType);
+
+ for (int ii = 0; ii < argCount; ++ii)
+ args[ii + 1].fromValue(argTypes[ii], engine, callArgs[ii]);
+
+ QVarLengthArray<void *, 9> argData(args.count());
+ for (int ii = 0; ii < args.count(); ++ii)
+ argData[ii] = args[ii].dataPtr();
+
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, argData.data());
+
+ return args[0].toValue(engine);
+
+ } else if (returnType != 0) {
+
+ MetaCallArgument arg;
+ arg.initAsType(returnType);
+
+ void *args[] = { arg.dataPtr() };
+
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
+
+ return arg.toValue(engine);
+
+ } else {
+
+ void *args[] = { 0 };
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
+ return v8::Undefined();
+
+ }
+}
+
+static int EnumType(const QMetaObject *meta, const QString &strname)
+{
+ QByteArray str = strname.toUtf8();
+ QByteArray scope;
+ QByteArray name;
+ int scopeIdx = str.lastIndexOf("::");
+ if (scopeIdx != -1) {
+ scope = str.left(scopeIdx);
+ name = str.mid(scopeIdx + 2);
+ } else {
+ name = str;
+ }
+ for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
+ QMetaEnum m = meta->enumerator(i);
+ if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
+ return QVariant::Int;
+ }
+ return QVariant::Invalid;
+}
+
+/*!
+ Returns the match score for converting \a actual to be of type \a conversionType. A
+ zero score means "perfect match" whereas a higher score is worse.
+
+ The conversion table is copied out of the QtScript callQtMethod() function.
+*/
+static int MatchScore(v8::Handle<v8::Value> actual, int conversionType,
+ const QByteArray &conversionTypeName)
+{
+ if (actual->IsNumber()) {
+ switch (conversionType) {
+ case QMetaType::Double:
+ return 0;
+ case QMetaType::Float:
+ return 1;
+ case QMetaType::LongLong:
+ case QMetaType::ULongLong:
+ return 2;
+ case QMetaType::Long:
+ case QMetaType::ULong:
+ return 3;
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ return 4;
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ return 5;
+ break;
+ case QMetaType::Char:
+ case QMetaType::UChar:
+ return 6;
+ default:
+ return 10;
+ }
+ } else if (actual->IsString()) {
+ switch (conversionType) {
+ case QMetaType::QString:
+ return 0;
+ default:
+ return 10;
+ }
+ } else if (actual->IsBoolean()) {
+ switch (conversionType) {
+ case QMetaType::Bool:
+ return 0;
+ default:
+ return 10;
+ }
+ } else if (actual->IsDate()) {
+ switch (conversionType) {
+ case QMetaType::QDateTime:
+ return 0;
+ case QMetaType::QDate:
+ return 1;
+ case QMetaType::QTime:
+ return 2;
+ default:
+ return 10;
+ }
+ } else if (actual->IsRegExp()) {
+ switch (conversionType) {
+ case QMetaType::QRegExp:
+ return 0;
+ default:
+ return 10;
+ }
+ } else if (actual->IsArray()) {
+ switch (conversionType) {
+ case QMetaType::QStringList:
+ case QMetaType::QVariantList:
+ return 5;
+ default:
+ return 10;
+ }
+ } else if (actual->IsNull()) {
+ switch (conversionType) {
+ case QMetaType::VoidStar:
+ case QMetaType::QObjectStar:
+ return 0;
+ default:
+ if (!conversionTypeName.endsWith('*'))
+ return 10;
+ else
+ return 0;
+ }
+ } else if (actual->IsObject()) {
+ v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(actual);
+
+ QV8ObjectResource *r = static_cast<QV8ObjectResource *>(obj->GetExternalResource());
+ if (r && r->resourceType() == QV8ObjectResource::QObjectType) {
+ switch (conversionType) {
+ case QMetaType::QObjectStar:
+ return 0;
+ default:
+ return 10;
+ }
+ } else if (r && r->resourceType() == QV8ObjectResource::VariantType) {
+ if (conversionType == qMetaTypeId<QVariant>())
+ return 0;
+ else if (r->engine->toVariant(actual, -1).userType() == conversionType)
+ return 0;
+ else
+ return 10;
+ } else {
+ return 10;
+ }
+
+ } else {
+ return 10;
+ }
+}
+
+static inline int QMetaObject_methods(const QMetaObject *metaObject)
+{
+ struct Private
+ {
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ };
+
+ return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
+}
+
+static QByteArray QMetaMethod_name(const QMetaMethod &m)
+{
+ QByteArray sig = m.signature();
+ int paren = sig.indexOf('(');
+ if (paren == -1)
+ return sig;
+ else
+ return sig.left(paren);
+}
+
+/*!
+Returns the next related method, if one, or 0.
+*/
+static const QDeclarativePropertyCache::Data * RelatedMethod(QObject *object,
+ const QDeclarativePropertyCache::Data *current,
+ QDeclarativePropertyCache::Data &dummy)
+{
+ QDeclarativePropertyCache *cache = QDeclarativeData::get(object)->propertyCache;
+ if (current->relatedIndex == -1)
+ return 0;
+
+ if (cache) {
+ return cache->method(current->relatedIndex);
+ } else {
+ const QMetaObject *mo = object->metaObject();
+ int methodOffset = mo->methodCount() - QMetaObject_methods(mo);
+
+ while (methodOffset > current->relatedIndex) {
+ mo = mo->superClass();
+ methodOffset -= QMetaObject_methods(mo);
+ }
+
+ QMetaMethod method = mo->method(current->relatedIndex);
+ dummy.load(method);
+
+ // Look for overloaded methods
+ QByteArray methodName = QMetaMethod_name(method);
+ for (int ii = current->relatedIndex - 1; ii >= methodOffset; --ii) {
+ if (methodName == QMetaMethod_name(mo->method(ii))) {
+ dummy.relatedIndex = ii;
+ return &dummy;
+ }
+ }
+
+ return &dummy;
+ }
+}
+
+static v8::Handle<v8::Value> CallPrecise(QObject *object, const QDeclarativePropertyCache::Data &data,
+ QV8Engine *engine, CallArgs &callArgs)
+{
+ if (data.flags & QDeclarativePropertyCache::Data::HasArguments) {
+
+ QMetaMethod m = object->metaObject()->method(data.coreIndex);
+ QList<QByteArray> argTypeNames = m.parameterTypes();
+ QVarLengthArray<int, 9> argTypes(argTypeNames.count());
+
+ // ### Cache
+ for (int ii = 0; ii < argTypeNames.count(); ++ii) {
+ argTypes[ii] = QMetaType::type(argTypeNames.at(ii));
+ if (argTypes[ii] == QVariant::Invalid)
+ argTypes[ii] = EnumType(object->metaObject(), QString::fromLatin1(argTypeNames.at(ii)));
+ if (argTypes[ii] == QVariant::Invalid) {
+ QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(QLatin1String(argTypeNames.at(ii)));
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return v8::Handle<v8::Value>();
+ }
+ }
+
+ if (argTypes.count() > callArgs.Length()) {
+ QString error = QLatin1String("Insufficient arguments");
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return v8::Handle<v8::Value>();
+ }
+
+ return CallMethod(object, data.coreIndex, data.propType, argTypes.count(),
+ argTypes.data(), engine, callArgs);
+
+ } else {
+
+ return CallMethod(object, data.coreIndex, data.propType, 0, 0, engine, callArgs);
+
+ }
+}
+
+/*!
+Resolve the overloaded method to call. The algorithm works conceptually like this:
+ 1. Resolve the set of overloads it is *possible* to call.
+ Impossible overloads include those that have too many parameters or have parameters
+ of unknown type.
+ 2. Filter the set of overloads to only contain those with the closest number of
+ parameters.
+ For example, if we are called with 3 parameters and there are 2 overloads that
+ take 2 parameters and one that takes 3, eliminate the 2 parameter overloads.
+ 3. Find the best remaining overload based on its match score.
+ If two or more overloads have the same match score, call the last one. The match
+ score is constructed by adding the matchScore() result for each of the parameters.
+*/
+static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QDeclarativePropertyCache::Data &data,
+ QV8Engine *engine, CallArgs &callArgs)
+{
+ int argumentCount = callArgs.Length();
+
+ const QDeclarativePropertyCache::Data *best = 0;
+ int bestParameterScore = INT_MAX;
+ int bestMatchScore = INT_MAX;
+
+ QDeclarativePropertyCache::Data dummy;
+ const QDeclarativePropertyCache::Data *attempt = &data;
+
+ do {
+ QList<QByteArray> methodArgTypeNames;
+
+ if (attempt->flags & QDeclarativePropertyCache::Data::HasArguments)
+ methodArgTypeNames = object->metaObject()->method(attempt->coreIndex).parameterTypes();
+
+ int methodArgumentCount = methodArgTypeNames.count();
+
+ if (methodArgumentCount > argumentCount)
+ continue; // We don't have sufficient arguments to call this method
+
+ int methodParameterScore = argumentCount - methodArgumentCount;
+ if (methodParameterScore > bestParameterScore)
+ continue; // We already have a better option
+
+ int methodMatchScore = 0;
+ QVarLengthArray<int, 9> methodArgTypes(methodArgumentCount);
+
+ bool unknownArgument = false;
+ for (int ii = 0; ii < methodArgumentCount; ++ii) {
+ methodArgTypes[ii] = QMetaType::type(methodArgTypeNames.at(ii));
+ if (methodArgTypes[ii] == QVariant::Invalid)
+ methodArgTypes[ii] = EnumType(object->metaObject(),
+ QString::fromLatin1(methodArgTypeNames.at(ii)));
+ if (methodArgTypes[ii] == QVariant::Invalid) {
+ unknownArgument = true;
+ break;
+ }
+ methodMatchScore += MatchScore(callArgs[ii], methodArgTypes[ii], methodArgTypeNames.at(ii));
+ }
+ if (unknownArgument)
+ continue; // We don't understand all the parameters
+
+ if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
+ best = attempt;
+ bestParameterScore = methodParameterScore;
+ bestMatchScore = methodMatchScore;
+ }
+
+ if (bestParameterScore == 0 && bestMatchScore == 0)
+ break; // We can't get better than that
+
+ } while((attempt = RelatedMethod(object, attempt, dummy)) != 0);
+
+ if (best) {
+ return CallPrecise(object, *best, engine, callArgs);
+ } else {
+ QString error = QLatin1String("Unable to determine callable overload. Candidates are:");
+ const QDeclarativePropertyCache::Data *candidate = &data;
+ while (candidate) {
+ error += QLatin1String("\n ") +
+ QString::fromUtf8(object->metaObject()->method(candidate->coreIndex).signature());
+ candidate = RelatedMethod(object, candidate, dummy);
+ }
+
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return v8::Handle<v8::Value>();
+ }
+}
+
+static v8::Handle<v8::Value> ToString(QV8Engine *engine, QObject *object, int, v8::Handle<v8::Object>)
+{
+ QString result;
+ if (object) {
+ QString objectName = object->objectName();
+
+ result += QString::fromUtf8(object->metaObject()->className());
+ result += QLatin1String("(0x");
+ result += QString::number((quintptr)object,16);
+
+ if (!objectName.isEmpty()) {
+ result += QLatin1String(", \"");
+ result += objectName;
+ result += QLatin1Char('\"');
+ }
+
+ result += QLatin1Char(')');
+ } else {
+ result = QLatin1String("null");
+ }
+
+ return engine->toString(result);
+}
+
+static v8::Handle<v8::Value> Destroy(QV8Engine *, QObject *object, int argCount, v8::Handle<v8::Object> args)
+{
+ QDeclarativeData *ddata = QDeclarativeData::get(object, false);
+ if (!ddata || ddata->indestructible) {
+ const char *error = "Invalid attempt to destroy() an indestructible object";
+ v8::ThrowException(v8::Exception::Error(v8::String::New(error)));
+ return v8::Undefined();
+ }
+
+ int delay = 0;
+ if (argCount > 0)
+ delay = args->Get(0)->Uint32Value();
+
+ if (delay > 0)
+ QTimer::singleShot(delay, object, SLOT(deleteLater()));
+ else
+ object->deleteLater();
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::Invoke(const v8::Arguments &args)
+{
+ // object, index, qmlglobal, argCount, args
+ Q_ASSERT(args.Length() == 5);
+ Q_ASSERT(args[0]->IsObject());
+
+ QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(args[0]->ToObject());
+
+ if (!resource)
+ return v8::Undefined();
+
+ int argCount = args[3]->Int32Value();
+ v8::Handle<v8::Object> arguments = v8::Handle<v8::Object>::Cast(args[4]);
+
+ // Special hack to return info about this closure.
+ if (argCount == 1 && arguments->Get(0)->StrictEquals(resource->engine->qobjectWrapper()->m_hiddenObject)) {
+ v8::Local<v8::Array> data = v8::Array::New(2);
+ data->Set(0, args[0]);
+ data->Set(1, args[1]);
+ return data;
+ }
+
+ QObject *object = resource->object;
+ int index = args[1]->Int32Value();
+
+ if (!object)
+ return v8::Undefined();
+
+ if (index < 0) {
+ // Builtin functions
+ if (index == QOBJECT_TOSTRING_INDEX) {
+ return ToString(resource->engine, object, argCount, arguments);
+ } else if (index == QOBJECT_DESTROY_INDEX) {
+ return Destroy(resource->engine, object, argCount, arguments);
+ } else {
+ return v8::Undefined();
+ }
+ }
+
+ QDeclarativePropertyCache::Data method;
+
+ if (QDeclarativeData *ddata = static_cast<QDeclarativeData *>(QObjectPrivate::get(object)->declarativeData)) {
+ if (ddata->propertyCache) {
+ QDeclarativePropertyCache::Data *d = ddata->propertyCache->method(index);
+ if (!d)
+ return v8::Undefined();
+ method = *d;
+ }
+ }
+
+ if (method.coreIndex == -1) {
+ QMetaMethod mm = object->metaObject()->method(index);
+ method.load(object->metaObject()->method(index));
+
+ if (method.coreIndex == -1)
+ return v8::Undefined();
+ }
+
+ if (method.flags & QDeclarativePropertyCache::Data::IsV8Function) {
+ v8::Handle<v8::Value> rv;
+ v8::Handle<v8::Object> qmlglobal = args[2]->ToObject();
+
+ QDeclarativeV8Function func(argCount, arguments, rv, qmlglobal,
+ resource->engine->contextWrapper()->context(qmlglobal),
+ resource->engine);
+ QDeclarativeV8Function *funcptr = &func;
+
+ void *args[] = { 0, &funcptr };
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, method.coreIndex, args);
+
+ if (rv.IsEmpty()) return v8::Undefined();
+ return rv;
+ }
+
+ CallArgs callArgs(argCount, &arguments);
+ if (method.relatedIndex == -1) {
+ return CallPrecise(object, method, resource->engine, callArgs);
+ } else {
+ return CallOverloaded(object, method, resource->engine, callArgs);
+ }
+}
+
+MetaCallArgument::MetaCallArgument()
+: type(QVariant::Invalid), isObjectType(false)
+{
+}
+
+MetaCallArgument::~MetaCallArgument()
+{
+ cleanup();
+}
+
+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();
+ } else if (type == qMetaTypeId<QList<QObject *> >()) {
+ ((QList<QObject *> *)&data)->~QList<QObject *>();
+ }
+}
+
+void *MetaCallArgument::dataPtr()
+{
+ if (type == -1)
+ return ((QVariant *)data)->data();
+ else
+ return (void *)&data;
+}
+
+void MetaCallArgument::initAsType(int callType)
+{
+ if (type != 0) { cleanup(); type = 0; }
+ if (callType == 0) return;
+
+ if (callType == qMetaTypeId<QScriptValue>()) {
+ new (&data) QScriptValue();
+ type = callType;
+ } else if (callType == QMetaType::Int ||
+ callType == QMetaType::UInt ||
+ callType == QMetaType::Bool ||
+ callType == QMetaType::Double ||
+ callType == QMetaType::Float) {
+ type = callType;
+ } else if (callType == QMetaType::QObjectStar) {
+ *((QObject **)&data) = 0;
+ type = callType;
+ } else if (callType == QMetaType::QString) {
+ new (&data) QString();
+ type = callType;
+ } else if (callType == qMetaTypeId<QVariant>()) {
+ type = callType;
+ new (&data) QVariant();
+ } else if (callType == qMetaTypeId<QList<QObject *> >()) {
+ type = callType;
+ new (&data) QList<QObject *>();
+ } else if (callType == qMetaTypeId<QDeclarativeV8Handle>()) {
+ type = callType;
+ new (&data) v8::Handle<v8::Value>();
+ } else {
+ type = -1;
+ new (&data) QVariant(callType, (void *)0);
+ }
+}
+
+void MetaCallArgument::fromValue(int callType, QV8Engine *engine, v8::Handle<v8::Value> value)
+{
+ if (type != 0) { cleanup(); type = 0; }
+
+ if (callType == qMetaTypeId<QScriptValue>()) {
+ new (&data) QScriptValue();
+ type = qMetaTypeId<QScriptValue>();
+ } else if (callType == QMetaType::Int) {
+ *((int *)&data) = int(value->Int32Value());
+ type = callType;
+ } else if (callType == QMetaType::UInt) {
+ *((uint *)&data) = uint(value->Uint32Value());
+ type = callType;
+ } else if (callType == QMetaType::Bool) {
+ *((bool *)&data) = value->BooleanValue();
+ type = callType;
+ } else if (callType == QMetaType::Double) {
+ *((double *)&data) = double(value->NumberValue());
+ type = callType;
+ } else if (callType == QMetaType::Float) {
+ *((float *)&data) = float(value->NumberValue());
+ type = callType;
+ } else if (callType == QMetaType::QString) {
+ if (value->IsNull() || value->IsUndefined())
+ new (&data) QString();
+ else
+ new (&data) QString(engine->toString(value->ToString()));
+ type = callType;
+ } else if (callType == QMetaType::QObjectStar) {
+ *((QObject **)&data) = engine->toQObject(value);
+ type = callType;
+ } else if (callType == qMetaTypeId<QVariant>()) {
+ new (&data) QVariant(engine->toVariant(value, -1));
+ type = callType;
+ } else if (callType == qMetaTypeId<QList<QObject*> >()) {
+ QList<QObject *> *list = new (&data) 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)));
+ } else {
+ list->append(engine->toQObject(value));
+ }
+ type = callType;
+ } else if (callType == qMetaTypeId<QDeclarativeV8Handle>()) {
+ new (&data) v8::Handle<v8::Value>(value);
+ type = callType;
+ } else {
+ new (&data) QVariant();
+ type = -1;
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine());
+ QVariant v = engine->toVariant(value, -1);
+
+ if (v.userType() == callType) {
+ *((QVariant *)&data) = 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)) {
+ QObject *obj = ep->toQObject(v);
+
+ if (obj) {
+ const QMetaObject *objMo = obj->metaObject();
+ while (objMo && objMo != mo) objMo = objMo->superClass();
+ if (!objMo) obj = 0;
+ }
+
+ *((QVariant *)&data) = QVariant(callType, &obj);
+ } else {
+ *((QVariant *)&data) = QVariant(callType, (void *)0);
+ }
+ }
+}
+
+v8::Handle<v8::Value> MetaCallArgument::toValue(QV8Engine *engine)
+{
+ if (type == qMetaTypeId<QScriptValue>()) {
+ return v8::Undefined();
+ } else if (type == QMetaType::Int) {
+ return v8::Integer::New(*((int *)&data));
+ } else if (type == QMetaType::UInt) {
+ return v8::Integer::NewFromUnsigned(*((uint *)&data));
+ } else if (type == QMetaType::Bool) {
+ return v8::Boolean::New(*((bool *)&data));
+ } else if (type == QMetaType::Double) {
+ return v8::Number::New(*((double *)&data));
+ } else if (type == QMetaType::Float) {
+ return v8::Number::New(*((float *)&data));
+ } else if (type == QMetaType::QString) {
+ return engine->toString(*((QString *)&data));
+ } else if (type == QMetaType::QObjectStar) {
+ QObject *object = *((QObject **)&data);
+ 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;
+ 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;
+ } else if (type == -1 || type == qMetaTypeId<QVariant>()) {
+ QVariant value = *((QVariant *)&data);
+ v8::Handle<v8::Value> rv = engine->fromVariant(value);
+ if (QObject *object = engine->toQObject(rv))
+ QDeclarativeData::get(object, true)->setImplicitDestructible();
+ return rv;
+ } else {
+ return v8::Undefined();
+ }
+}
diff --git a/src/declarative/qml/v8/qv8qobjectwrapper_p.h b/src/declarative/qml/v8/qv8qobjectwrapper_p.h
new file mode 100644
index 0000000000..5100c3f51b
--- /dev/null
+++ b/src/declarative/qml/v8/qv8qobjectwrapper_p.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8QOBJECTWRAPPER_P_H
+#define QV8QOBJECTWRAPPER_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 <QtCore/qglobal.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qhash.h>
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+class QV8Engine;
+class QDeclarativeData;
+class QV8ObjectResource;
+class QV8QObjectInstance;
+class QV8QObjectConnectionList;
+class QDeclarativePropertyCache;
+class Q_AUTOTEST_EXPORT QV8QObjectWrapper
+{
+public:
+ QV8QObjectWrapper();
+ ~QV8QObjectWrapper();
+
+ void init(QV8Engine *);
+ void destroy();
+
+ v8::Handle<v8::Value> newQObject(QObject *object);
+ bool isQObject(v8::Handle<v8::Object>);
+ QObject *toQObject(v8::Handle<v8::Object>);
+ QObject *toQObject(QV8ObjectResource *);
+
+ enum RevisionMode { IgnoreRevision, CheckRevision };
+ v8::Handle<v8::Value> getProperty(QObject *, v8::Handle<v8::String>, RevisionMode);
+ bool setProperty(QObject *, v8::Handle<v8::String>, v8::Handle<v8::Value>, RevisionMode);
+
+private:
+ friend class QDeclarativePropertyCache;
+ friend class QV8QObjectConnectionList;
+ friend class QV8QObjectInstance;
+
+ v8::Local<v8::Object> newQObject(QObject *, QDeclarativeData *, QV8Engine *);
+ static v8::Handle<v8::Value> GetProperty(QV8Engine *, QObject *, v8::Handle<v8::Value> *,
+ v8::Handle<v8::String>, QV8QObjectWrapper::RevisionMode);
+ static bool SetProperty(QV8Engine *, QObject *, v8::Handle<v8::String>,
+ v8::Handle<v8::Value>, QV8QObjectWrapper::RevisionMode);
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Integer> Query(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Connect(const v8::Arguments &args);
+ static v8::Handle<v8::Value> Disconnect(const v8::Arguments &args);
+ static v8::Handle<v8::Value> Invoke(const v8::Arguments &args);
+ static QPair<QObject *, int> ExtractQtMethod(QV8Engine *, v8::Handle<v8::Function>);
+
+ QV8Engine *m_engine;
+ quint32 m_id;
+ v8::Persistent<v8::Function> m_constructor;
+ v8::Persistent<v8::Function> m_methodConstructor;
+ v8::Persistent<v8::String> m_toStringSymbol;
+ v8::Persistent<v8::String> m_destroySymbol;
+ v8::Persistent<v8::Object> m_hiddenObject;
+ QHash<QObject *, QV8QObjectConnectionList *> m_connections;
+ typedef QHash<QObject *, QV8QObjectInstance *> TaintedHash;
+ TaintedHash m_taintedObjects;
+};
+
+QT_END_NAMESPACE
+
+#endif // QV8QOBJECTWRAPPER_P_H
+
+
diff --git a/src/declarative/qml/v8/qv8stringwrapper.cpp b/src/declarative/qml/v8/qv8stringwrapper.cpp
new file mode 100644
index 0000000000..883c4826c5
--- /dev/null
+++ b/src/declarative/qml/v8/qv8stringwrapper.cpp
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8stringwrapper_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QV8StringResource : public v8::String::ExternalStringResource
+{
+public:
+ QV8StringResource(const QString &str) : str(str) {}
+ virtual const uint16_t* data() const { return (uint16_t*)str.constData(); }
+ virtual size_t length() const { return str.length(); }
+ virtual void Dispose() { delete this; }
+
+ QString str;
+};
+
+QV8StringWrapper::QV8StringWrapper()
+{
+}
+
+QV8StringWrapper::~QV8StringWrapper()
+{
+}
+
+void QV8StringWrapper::init()
+{
+}
+
+void QV8StringWrapper::destroy()
+{
+}
+
+v8::Local<v8::String> QV8StringWrapper::toString(const QString &qstr)
+{
+// return v8::String::NewExternal(new QV8StringResource(qstr));
+ return v8::String::New((uint16_t*)qstr.constData(), qstr.length());
+}
+
+QString QV8StringWrapper::toString(v8::Handle<v8::String> jsstr)
+{
+ if (jsstr.IsEmpty()) {
+ return QString();
+ } else if (jsstr->IsExternal()) {
+ QV8StringResource *r = (QV8StringResource *)jsstr->GetExternalStringResource();
+ return r->str;
+ } else {
+ QString qstr;
+ qstr.resize(jsstr->Length());
+ jsstr->Write((uint16_t*)qstr.data());
+ return qstr;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/v8/qv8stringwrapper_p.h b/src/declarative/qml/v8/qv8stringwrapper_p.h
new file mode 100644
index 0000000000..8dde5c8c44
--- /dev/null
+++ b/src/declarative/qml/v8/qv8stringwrapper_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV8STRINGWRAPPER_P_H
+#define QDECLARATIVEV8STRINGWRAPPER_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 <QtCore/qstring.h>
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QV8StringWrapper
+{
+public:
+ QV8StringWrapper();
+ ~QV8StringWrapper();
+
+ void init();
+ void destroy();
+
+ v8::Local<v8::String> toString(const QString &);
+ QString toString(v8::Handle<v8::String>);
+};
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEV8STRINGWRAPPER_P_H
diff --git a/src/declarative/qml/v8/qv8typewrapper.cpp b/src/declarative/qml/v8/qv8typewrapper.cpp
new file mode 100644
index 0000000000..70af6037de
--- /dev/null
+++ b/src/declarative/qml/v8/qv8typewrapper.cpp
@@ -0,0 +1,211 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8contextwrapper_p.h"
+#include "qv8engine_p.h"
+
+#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativecontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8TypeResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(TypeType);
+
+public:
+ QV8TypeResource(QV8Engine *engine);
+ virtual ~QV8TypeResource();
+
+ QV8TypeWrapper::TypeNameMode mode;
+
+ QDeclarativeGuard<QObject> object;
+ QDeclarativeType *type;
+ QDeclarativeTypeNameCache *typeNamespace;
+};
+
+QV8TypeResource::QV8TypeResource(QV8Engine *engine)
+: QV8ObjectResource(engine), mode(QV8TypeWrapper::IncludeEnums), type(0), typeNamespace(0)
+{
+}
+
+QV8TypeResource::~QV8TypeResource()
+{
+ if (typeNamespace) typeNamespace->release();
+}
+
+QV8TypeWrapper::QV8TypeWrapper()
+: m_engine(0)
+{
+}
+
+QV8TypeWrapper::~QV8TypeWrapper()
+{
+}
+
+void QV8TypeWrapper::destroy()
+{
+ qPersistentDispose(m_constructor);
+}
+
+void QV8TypeWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+}
+
+v8::Local<v8::Object> QV8TypeWrapper::newObject(QObject *o, QDeclarativeType *t, TypeNameMode mode)
+{
+ Q_ASSERT(t);
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8TypeResource *r = new QV8TypeResource(m_engine);
+ r->mode = mode; r->object = o; r->type = t;
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+v8::Local<v8::Object> QV8TypeWrapper::newObject(QObject *o, QDeclarativeTypeNameCache *t, TypeNameMode mode)
+{
+ Q_ASSERT(t);
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8TypeResource *r = new QV8TypeResource(m_engine);
+ t->addref();
+ r->mode = mode; r->object = o; r->typeNamespace = t;
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ v8::Object::ExternalResource *r = info.This()->GetExternalResource();
+ QV8TypeResource *resource = v8_resource_cast<QV8TypeResource>(info.This());
+
+ if (!resource)
+ return v8::Undefined();
+
+ QV8Engine *v8engine = resource->engine;
+ QObject *object = resource->object;
+
+ if (resource->type) {
+ QDeclarativeType *type = resource->type;
+
+ if (QV8Engine::startsWithUpper(property)) {
+ if (resource->mode == IncludeEnums) {
+ QString name = v8engine->toString(property);
+
+ // ### Optimize
+ QByteArray enumName = name.toUtf8();
+ const QMetaObject *metaObject = type->baseMetaObject();
+ for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
+ QMetaEnum e = metaObject->enumerator(ii);
+ int value = e.keyToValue(enumName.constData());
+ if (value != -1)
+ return v8::Integer::New(value);
+ }
+ }
+
+ // Fall through to undefined
+
+ } else if (resource->object) {
+ QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
+ if (ao)
+ return v8engine->qobjectWrapper()->getProperty(ao, property, QV8QObjectWrapper::IgnoreRevision);
+
+ // Fall through to undefined
+ }
+
+ // Fall through to undefined
+
+ } else if (resource->typeNamespace) {
+
+ QDeclarativeTypeNameCache *typeNamespace = resource->typeNamespace;
+ QDeclarativeTypeNameCache::Data *d = typeNamespace->data(property);
+ Q_ASSERT(!d || !d->typeNamespace); // Nested namespaces not supported
+
+ if (d && d->type) {
+ 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 here until the QtScript/V8 binding is complete.
+ return v8::Undefined();
+
+ }
+
+ // Fall through to undefined
+
+ } else {
+ Q_ASSERT(!"Unreachable");
+ }
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ v8::Object::ExternalResource *r = info.This()->GetExternalResource();
+ QV8TypeResource *resource = v8_resource_cast<QV8TypeResource>(info.This());
+
+ if (!resource)
+ return value;
+
+ QV8Engine *v8engine = resource->engine;
+
+ // XXX TODO: Implement writes to module API objects
+
+ if (resource->type && resource->object) {
+ QDeclarativeType *type = resource->type;
+ QObject *object = resource->object;
+ QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
+ if (ao)
+ v8engine->qobjectWrapper()->setProperty(ao, property, value, QV8QObjectWrapper::IgnoreRevision);
+ }
+
+ return value;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativetypenamescriptclass_p.h b/src/declarative/qml/v8/qv8typewrapper_p.h
index 9f386ba3a2..e7403dfa40 100644
--- a/src/declarative/qml/qdeclarativetypenamescriptclass_p.h
+++ b/src/declarative/qml/v8/qv8typewrapper_p.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QDECLARATIVETYPENAMESCRIPTCLASS_P_H
-#define QDECLARATIVETYPENAMESCRIPTCLASS_P_H
+#ifndef QV8TYPEWRAPPER_P_H
+#define QV8TYPEWRAPPER_P_H
//
// W A R N I N G
@@ -52,42 +52,41 @@
//
// We mean it.
//
-#include "private/qdeclarativeengine_p.h"
-#include <private/qscriptdeclarativeclass_p.h>
-#include <QtScript/qscriptclass.h>
+#include <QtCore/qglobal.h>
+#include <private/qv8_p.h>
QT_BEGIN_NAMESPACE
-class QDeclarativeEngine;
+class QObject;
+class QV8Engine;
class QDeclarativeType;
class QDeclarativeTypeNameCache;
-class QDeclarativeTypeNameScriptClass : public QScriptDeclarativeClass
+class QV8TypeWrapper
{
public:
- QDeclarativeTypeNameScriptClass(QDeclarativeEngine *);
- ~QDeclarativeTypeNameScriptClass();
+ QV8TypeWrapper();
+ ~QV8TypeWrapper();
- enum TypeNameMode { IncludeEnums, ExcludeEnums };
- QScriptValue newObject(QObject *, QDeclarativeType *, TypeNameMode = IncludeEnums);
- QScriptValue newObject(QObject *, QDeclarativeTypeNameCache *, TypeNameMode = IncludeEnums);
-
-protected:
- virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
- QScriptClass::QueryFlags flags);
+ void init(QV8Engine *);
+ void destroy();
- virtual Value property(Object *, const Identifier &);
- virtual void setProperty(Object *, const Identifier &name, const QScriptValue &);
+ enum TypeNameMode { IncludeEnums, ExcludeEnums };
+ v8::Local<v8::Object> newObject(QObject *, QDeclarativeType *, TypeNameMode = IncludeEnums);
+ v8::Local<v8::Object> newObject(QObject *, QDeclarativeTypeNameCache *, TypeNameMode = IncludeEnums);
private:
- QDeclarativeEngine *engine;
- QObject *object;
- QDeclarativeType *type;
- QDeclarativeMetaType::ModuleApiInstance *api;
- quint32 enumValue;
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+
+ QV8Engine *m_engine;
+ v8::Persistent<v8::Function> m_constructor;
};
QT_END_NAMESPACE
-#endif // QDECLARATIVETYPENAMESCRIPTCLASS_P_H
+#endif // QV8TYPEWRAPPER_P_H
diff --git a/src/declarative/qml/v8/qv8valuetypewrapper.cpp b/src/declarative/qml/v8/qv8valuetypewrapper.cpp
new file mode 100644
index 0000000000..f4f79ce92e
--- /dev/null
+++ b/src/declarative/qml/v8/qv8valuetypewrapper.cpp
@@ -0,0 +1,289 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8valuetypewrapper_p.h"
+#include "qv8engine_p.h"
+
+#include <private/qdeclarativevaluetype_p.h>
+#include <private/qdeclarativebinding_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8ValueTypeResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(ValueTypeType);
+
+public:
+ enum ObjectType { Reference, Copy };
+
+ QV8ValueTypeResource(QV8Engine *engine, ObjectType objectType);
+
+ ObjectType objectType;
+ QDeclarativeValueType *type;
+};
+
+class QV8ValueTypeReferenceResource : public QV8ValueTypeResource
+{
+public:
+ QV8ValueTypeReferenceResource(QV8Engine *engine);
+
+ QDeclarativeGuard<QObject> object;
+ int property;
+};
+
+class QV8ValueTypeCopyResource : public QV8ValueTypeResource
+{
+public:
+ QV8ValueTypeCopyResource(QV8Engine *engine);
+
+ QVariant value;
+};
+
+QV8ValueTypeResource::QV8ValueTypeResource(QV8Engine *engine, ObjectType objectType)
+: QV8ObjectResource(engine), objectType(objectType)
+{
+}
+
+QV8ValueTypeReferenceResource::QV8ValueTypeReferenceResource(QV8Engine *engine)
+: QV8ValueTypeResource(engine, Reference)
+{
+}
+
+QV8ValueTypeCopyResource::QV8ValueTypeCopyResource(QV8Engine *engine)
+: QV8ValueTypeResource(engine, Copy)
+{
+}
+
+QV8ValueTypeWrapper::QV8ValueTypeWrapper()
+: m_engine(0)
+{
+}
+
+QV8ValueTypeWrapper::~QV8ValueTypeWrapper()
+{
+}
+
+void QV8ValueTypeWrapper::destroy()
+{
+ qPersistentDispose(m_constructor);
+}
+
+void QV8ValueTypeWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+}
+
+v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(QObject *object, int property, QDeclarativeValueType *type)
+{
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8ValueTypeReferenceResource *r = new QV8ValueTypeReferenceResource(m_engine);
+ r->type = type; r->object = object; r->property = property;
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(const QVariant &value, QDeclarativeValueType *type)
+{
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8ValueTypeCopyResource *r = new QV8ValueTypeCopyResource(m_engine);
+ r->type = type; r->value = value;
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+QVariant QV8ValueTypeWrapper::toVariant(v8::Handle<v8::Object> obj)
+{
+ QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(obj);
+ if (r) return toVariant(r);
+ else return QVariant();
+}
+
+QVariant QV8ValueTypeWrapper::toVariant(QV8ObjectResource *r)
+{
+ Q_ASSERT(r->resourceType() == QV8ObjectResource::ValueTypeType);
+ QV8ValueTypeResource *resource = static_cast<QV8ValueTypeResource *>(r);
+
+ if (resource->objectType == QV8ValueTypeResource::Reference) {
+ QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource);
+
+ if (reference->object) {
+ reference->type->read(reference->object, reference->property);
+ return reference->type->value();
+ } else {
+ return QVariant();
+ }
+
+ } else {
+ Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy);
+
+ QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource);
+
+ return copy->value;
+ }
+}
+
+v8::Handle<v8::Value> QV8ValueTypeWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(info.This());
+ if (!r) return v8::Undefined();
+
+ // XXX This is horribly inefficient. Sadly people seem to have taken a liking to
+ // value type properties, so we should probably try and optimize it a little.
+ // We should probably just replace all value properties with dedicated accessors.
+
+ QByteArray propName = r->engine->toString(property).toUtf8();
+ int index = r->type->metaObject()->indexOfProperty(propName.constData());
+ if (index == -1)
+ return v8::Undefined();
+
+ if (r->objectType == QV8ValueTypeResource::Reference) {
+ QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
+
+ if (!reference->object)
+ return v8::Undefined();
+
+ r->type->read(reference->object, reference->property);
+ } else {
+ Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
+
+ QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
+
+ r->type->setValue(copy->value);
+ }
+
+ QMetaProperty prop = r->type->metaObject()->property(index);
+ QVariant result = prop.read(r->type);
+
+ return r->engine->fromVariant(result);
+}
+
+v8::Handle<v8::Value> QV8ValueTypeWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(info.This());
+ if (!r) return value;
+
+ QByteArray propName = r->engine->toString(property).toUtf8();
+ int index = r->type->metaObject()->indexOfProperty(propName.constData());
+ if (index == -1)
+ return value;
+
+ if (r->objectType == QV8ValueTypeResource::Reference) {
+ QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
+
+ if (!reference->object ||
+ !reference->object->metaObject()->property(reference->property).isWritable())
+ return value;
+
+ r->type->read(reference->object, reference->property);
+ QMetaProperty p = r->type->metaObject()->property(index);
+
+ QDeclarativeBinding *newBinding = 0;
+
+ if (value->IsFunction()) {
+ QDeclarativeContextData *context = r->engine->callingContext();
+ v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
+
+ QDeclarativePropertyCache::Data cacheData;
+ cacheData.flags = QDeclarativePropertyCache::Data::IsWritable;
+ cacheData.propType = reference->object->metaObject()->property(reference->property).userType();
+ cacheData.coreIndex = reference->property;
+
+ QDeclarativePropertyCache::ValueTypeData valueTypeData;
+ valueTypeData.valueTypeCoreIdx = index;
+ valueTypeData.valueTypePropType = p.userType();
+
+ v8::Local<v8::StackTrace> trace =
+ v8::StackTrace::CurrentStackTrace(1,
+ (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber |
+ v8::StackTrace::kScriptName));
+ v8::Local<v8::StackFrame> frame = trace->GetFrame(0);
+ int lineNumber = frame->GetLineNumber();
+ QString url = r->engine->toString(frame->GetScriptName());
+
+ newBinding = new QDeclarativeBinding(&function, reference->object, context);
+ newBinding->setSourceLocation(url, lineNumber);
+ newBinding->setTarget(QDeclarativePropertyPrivate::restore(cacheData, valueTypeData,
+ reference->object, context));
+ newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject);
+ }
+
+ QDeclarativeAbstractBinding *oldBinding =
+ QDeclarativePropertyPrivate::setBinding(reference->object, reference->property, index, newBinding);
+ if (oldBinding)
+ oldBinding->destroy();
+
+ if (!value->IsFunction()) {
+ QVariant v = r->engine->toVariant(value, -1);
+
+ if (p.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double)
+ v = v.toInt();
+
+ p.write(reference->type, v);
+
+ reference->type->write(reference->object, reference->property, 0);
+ }
+
+ } else {
+ Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
+
+ QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
+
+ QVariant v = r->engine->toVariant(value, -1);
+
+ r->type->setValue(copy->value);
+ QMetaProperty p = r->type->metaObject()->property(index);
+ p.write(r->type, v);
+ copy->value = r->type->value();
+ }
+
+ return value;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativevaluetypescriptclass_p.h b/src/declarative/qml/v8/qv8valuetypewrapper_p.h
index bafcff4ac2..d08d89392c 100644
--- a/src/declarative/qml/qdeclarativevaluetypescriptclass_p.h
+++ b/src/declarative/qml/v8/qv8valuetypewrapper_p.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QDECLARATIVEVALUETYPESCRIPTCLASS_P_H
-#define QDECLARATIVEVALUETYPESCRIPTCLASS_P_H
+#ifndef QV8VALUETYPEWRAPPER_P_H
+#define QV8VALUETYPEWRAPPER_P_H
//
// W A R N I N G
@@ -53,35 +53,43 @@
// We mean it.
//
-
-#include <private/qscriptdeclarativeclass_p.h>
+#include <QtCore/qglobal.h>
+#include <QtDeclarative/qdeclarativelist.h>
+#include <private/qv8_p.h>
QT_BEGIN_NAMESPACE
-class QDeclarativeEngine;
+class QV8Engine;
+class QV8ObjectResource;
class QDeclarativeValueType;
-class QDeclarativeValueTypeScriptClass : public QScriptDeclarativeClass
+class QV8ValueTypeWrapper
{
public:
- QDeclarativeValueTypeScriptClass(QDeclarativeEngine *);
- ~QDeclarativeValueTypeScriptClass();
+ QV8ValueTypeWrapper();
+ ~QV8ValueTypeWrapper();
+
+ void init(QV8Engine *);
+ void destroy();
- QScriptValue newObject(QObject *object, int coreIndex, QDeclarativeValueType *);
- QScriptValue newObject(const QVariant &, QDeclarativeValueType *);
+ v8::Local<v8::Object> newValueType(QObject *, int, QDeclarativeValueType *);
+ v8::Local<v8::Object> newValueType(const QVariant &, QDeclarativeValueType *);
- virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
- QScriptClass::QueryFlags flags);
- virtual Value property(Object *, const Identifier &);
- virtual void setProperty(Object *, const Identifier &name, const QScriptValue &);
+ QVariant toVariant(v8::Handle<v8::Object>);
+ QVariant toVariant(QV8ObjectResource *);
- virtual QVariant toVariant(Object *, bool *ok = 0);
- QVariant toVariant(const QScriptValue &);
private:
- QDeclarativeEngine *engine;
- int m_lastIndex;
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+
+ QV8Engine *m_engine;
+ v8::Persistent<v8::Function> m_constructor;
};
QT_END_NAMESPACE
-#endif // QDECLARATIVEVALUETYPESCRIPTCLASS_P_H
+#endif // QV8VALUETYPEWRAPPER_P_H
+
diff --git a/src/declarative/qml/v8/qv8variantwrapper.cpp b/src/declarative/qml/v8/qv8variantwrapper.cpp
new file mode 100644
index 0000000000..37e998d988
--- /dev/null
+++ b/src/declarative/qml/v8/qv8variantwrapper.cpp
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8variantwrapper_p.h"
+#include "qv8engine_p.h"
+#include "qdeclarativeengine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QV8VariantResource : public QV8ObjectResource,
+ public QDeclarativeEnginePrivate::ScarceResourceData
+{
+ V8_RESOURCE_TYPE(VariantType);
+public:
+ QV8VariantResource(QV8Engine *engine, const QVariant &data);
+};
+
+QV8VariantResource::QV8VariantResource(QV8Engine *engine, const QVariant &data)
+: QV8ObjectResource(engine), QDeclarativeEnginePrivate::ScarceResourceData(data)
+{
+}
+
+QV8VariantWrapper::QV8VariantWrapper()
+: m_engine(0)
+{
+}
+
+QV8VariantWrapper::~QV8VariantWrapper()
+{
+}
+
+void QV8VariantWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+ {
+ m_preserve = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(Preserve)->GetFunction());
+ m_destroy = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(Destroy)->GetFunction());
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("preserve"), PreserveGetter, 0,
+ m_preserve, v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("destroy"), DestroyGetter, 0,
+ m_destroy, v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+ m_scarceConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
+ }
+
+}
+
+void QV8VariantWrapper::destroy()
+{
+ qPersistentDispose(m_destroy);
+ qPersistentDispose(m_preserve);
+ qPersistentDispose(m_scarceConstructor);
+ qPersistentDispose(m_constructor);
+}
+
+v8::Local<v8::Object> QV8VariantWrapper::newVariant(const QVariant &value)
+{
+ bool scarceResource = value.type() == QVariant::Pixmap ||
+ value.type() == QVariant::Image;
+
+ // XXX NewInstance() should be optimized
+ v8::Local<v8::Object> rv;
+ QV8VariantResource *r = new QV8VariantResource(m_engine, value);
+
+ if (scarceResource) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_engine->engine());
+ Q_ASSERT(ep->scarceResourcesRefCount);
+ rv = m_scarceConstructor->NewInstance();
+ ep->scarceResources.insert(r);
+ } else {
+ rv = m_constructor->NewInstance();
+ }
+
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+bool QV8VariantWrapper::isVariant(v8::Handle<v8::Value> value)
+{
+ return value->IsObject() && v8_resource_cast<QV8VariantResource>(value->ToObject());
+}
+
+QVariant QV8VariantWrapper::toVariant(v8::Handle<v8::Object> obj)
+{
+ QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(obj);
+ return r?r->data:QVariant();
+}
+
+QVariant QV8VariantWrapper::toVariant(QV8ObjectResource *r)
+{
+ Q_ASSERT(r->resourceType() == QV8ObjectResource::VariantType);
+ return static_cast<QV8VariantResource *>(r)->data;
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::PreserveGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ return info.Data();
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::DestroyGetter(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());
+ if (resource) {
+ resource->node.remove();
+ }
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::Destroy(const v8::Arguments &args)
+{
+ QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This());
+ if (resource) {
+ resource->data = QVariant();
+ resource->node.remove();
+ }
+ return v8::Undefined();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativelistscriptclass_p.h b/src/declarative/qml/v8/qv8variantwrapper_p.h
index e6ea02e8eb..972d4e94ac 100644
--- a/src/declarative/qml/qdeclarativelistscriptclass_p.h
+++ b/src/declarative/qml/v8/qv8variantwrapper_p.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QDECLARATIVELISTSCRIPTCLASS_P_H
-#define QDECLARATIVELISTSCRIPTCLASS_P_H
+#ifndef QV8VARIANTWRAPPER_P_H
+#define QV8VARIANTWRAPPER_P_H
//
// W A R N I N G
@@ -53,35 +53,49 @@
// We mean it.
//
-#include <private/qscriptdeclarativeclass_p.h>
-#include "qdeclarativelist.h"
+#include <QtCore/qglobal.h>
+#include <QtDeclarative/qdeclarativelist.h>
+#include <private/qv8_p.h>
QT_BEGIN_NAMESPACE
-class QDeclarativeEngine;
-class QDeclarativeListScriptClass : public QScriptDeclarativeClass
+class QV8Engine;
+class QV8ObjectResource;
+class QV8VariantWrapper
{
public:
- QDeclarativeListScriptClass(QDeclarativeEngine *);
- ~QDeclarativeListScriptClass();
+ QV8VariantWrapper();
+ ~QV8VariantWrapper();
- QScriptValue newList(QObject *, int, int);
- QScriptValue newList(const QDeclarativeListProperty<QObject> &, int);
+ void init(QV8Engine *);
+ void destroy();
-protected:
- virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
- QScriptClass::QueryFlags flags);
- virtual Value property(Object *, const Identifier &);
- virtual QVariant toVariant(Object *, bool *ok);
+ v8::Local<v8::Object> newVariant(const QVariant &);
+ bool isVariant(v8::Handle<v8::Value>);
+ QVariant toVariant(v8::Handle<v8::Object>);
+ QVariant toVariant(QV8ObjectResource *);
private:
- PersistentIdentifier m_lengthId;
- QDeclarativeEngine *engine;
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> PreserveGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> DestroyGetter(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);
- quint32 lastIndex;
+ QV8Engine *m_engine;
+ v8::Persistent<v8::Function> m_constructor;
+ v8::Persistent<v8::Function> m_scarceConstructor;
+ v8::Persistent<v8::Function> m_preserve;
+ v8::Persistent<v8::Function> m_destroy;
};
QT_END_NAMESPACE
-#endif // QDECLARATIVELISTSCRIPTCLASS_P_H
+#endif // QV8VARIANTWRAPPER_P_H
diff --git a/src/declarative/qml/v8/qv8worker.cpp b/src/declarative/qml/v8/qv8worker.cpp
new file mode 100644
index 0000000000..0d396d3304
--- /dev/null
+++ b/src/declarative/qml/v8/qv8worker.cpp
@@ -0,0 +1,352 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8worker_p.h"
+
+#include <private/qdeclarativelistmodel_p.h>
+#include <private/qdeclarativelistmodelworkeragent_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// We allow the following JavaScript types to be passed between the main and
+// the secondary thread:
+// + undefined
+// + null
+// + Boolean
+// + String
+// + Function
+// + Array
+// + "Simple" Objects
+// + Number
+// + Date
+// + RegExp
+// <quint8 type><quint24 size><data>
+
+enum Type {
+ WorkerUndefined,
+ WorkerNull,
+ WorkerTrue,
+ WorkerFalse,
+ WorkerString,
+ WorkerFunction,
+ WorkerArray,
+ WorkerObject,
+ WorkerInt32,
+ WorkerUint32,
+ WorkerNumber,
+ WorkerDate,
+ WorkerRegexp,
+ WorkerListModel
+};
+
+static inline quint32 valueheader(Type type, quint32 size = 0)
+{
+ return quint8(type) << 24 | (size & 0xFFFFFF);
+}
+
+static inline Type headertype(quint32 header)
+{
+ return (Type)(header >> 24);
+}
+
+static inline quint32 headersize(quint32 header)
+{
+ return header & 0xFFFFFF;
+}
+
+static inline void push(QByteArray &data, quint32 value)
+{
+ data.append((const char *)&value, sizeof(quint32));
+}
+
+static inline void push(QByteArray &data, double value)
+{
+ data.append((const char *)&value, sizeof(double));
+}
+
+static inline void push(QByteArray &data, void *ptr)
+{
+ data.append((const char *)&ptr, sizeof(void *));
+}
+
+static inline void reserve(QByteArray &data, int extra)
+{
+ data.reserve(data.size() + extra);
+}
+
+static inline quint32 popUint32(const char *&data)
+{
+ quint32 rv = *((quint32 *)data);
+ data += sizeof(quint32);
+ return rv;
+}
+
+static inline double popDouble(const char *&data)
+{
+ double rv = *((double *)data);
+ data += sizeof(double);
+ return rv;
+}
+
+static inline void *popPtr(const char *&data)
+{
+ void *rv = *((void **)data);
+ data += sizeof(void *);
+ return rv;
+}
+
+// XXX TODO: Check that worker script is exception safe in the case of
+// serialization/deserialization failures
+
+#define ALIGN(size) (((size) + 3) & ~3)
+void QV8Worker::serialize(QByteArray &data, v8::Handle<v8::Value> v, QV8Engine *engine)
+{
+ if (v.IsEmpty()) {
+ } else if (v->IsUndefined()) {
+ push(data, valueheader(WorkerUndefined));
+ } else if (v->IsNull()) {
+ push(data, valueheader(WorkerNull));
+ } else if (v->IsTrue()) {
+ push(data, valueheader(WorkerTrue));
+ } else if (v->IsFalse()) {
+ push(data, valueheader(WorkerFalse));
+ } else if (v->IsString()) {
+ v8::Handle<v8::String> string = v->ToString();
+ int length = string->Length() + 1;
+ if (length > 0xFFFFFF) {
+ push(data, valueheader(WorkerUndefined));
+ return;
+ }
+ int utf16size = ALIGN(length * sizeof(uint16_t));
+
+ reserve(data, utf16size + sizeof(quint32));
+ push(data, valueheader(WorkerString, length));
+
+ int offset = data.size();
+ data.resize(data.size() + utf16size);
+ char *buffer = data.data() + offset;
+
+ string->Write((uint16_t*)buffer);
+ } else if (v->IsFunction()) {
+ // XXX TODO: Implement passing function objects between the main and
+ // worker scripts
+ push(data, valueheader(WorkerUndefined));
+ } else if (v->IsArray()) {
+ v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(v);
+ uint32_t length = array->Length();
+ if (length > 0xFFFFFF) {
+ push(data, valueheader(WorkerUndefined));
+ return;
+ }
+ reserve(data, sizeof(quint32) + length * sizeof(quint32));
+ push(data, valueheader(WorkerArray, length));
+ for (uint32_t ii = 0; ii < length; ++ii)
+ serialize(data, array->Get(ii), engine);
+ } else if (v->IsInt32()) {
+ reserve(data, 2 * sizeof(quint32));
+ push(data, valueheader(WorkerInt32));
+ push(data, (quint32)v->Int32Value());
+ } else if (v->IsUint32()) {
+ reserve(data, 2 * sizeof(quint32));
+ push(data, valueheader(WorkerUint32));
+ push(data, v->Uint32Value());
+ } else if (v->IsNumber()) {
+ reserve(data, sizeof(quint32) + sizeof(double));
+ push(data, valueheader(WorkerNumber));
+ push(data, v->NumberValue());
+ } else if (v->IsDate()) {
+ reserve(data, sizeof(quint32) + sizeof(double));
+ push(data, valueheader(WorkerDate));
+ push(data, v8::Handle<v8::Date>::Cast(v)->NumberValue());
+ } else if (v->IsRegExp()) {
+ v8::Handle<v8::RegExp> regexp = v8::Handle<v8::RegExp>::Cast(v);
+ quint32 flags = regexp->GetFlags();
+ v8::Local<v8::String> source = regexp->GetSource();
+
+ int length = source->Length() + 1;
+ if (length > 0xFFFFFF) {
+ push(data, valueheader(WorkerUndefined));
+ return;
+ }
+ int utf16size = ALIGN(length * sizeof(uint16_t));
+
+ reserve(data, sizeof(quint32) + utf16size);
+ push(data, valueheader(WorkerRegexp, flags));
+ push(data, (quint32)length);
+ int offset = data.size();
+ data.resize(data.size() + utf16size);
+ char *buffer = data.data() + offset;
+
+ source->Write((uint16_t*)buffer);
+ } else if (v->IsObject() && !v->ToObject()->GetExternalResource()) {
+ v8::Handle<v8::Object> object = v->ToObject();
+ v8::Local<v8::Array> properties = engine->getOwnPropertyNames(object);
+ quint32 length = properties->Length();
+ if (length > 0xFFFFFF) {
+ push(data, valueheader(WorkerUndefined));
+ return;
+ }
+ push(data, valueheader(WorkerObject, length));
+ v8::TryCatch tc;
+ for (quint32 ii = 0; ii < length; ++ii) {
+ v8::Local<v8::String> str = properties->Get(ii)->ToString();
+ serialize(data, str, engine);
+
+ v8::Local<v8::Value> val = object->Get(str);
+ if (tc.HasCaught()) {
+ serialize(data, v8::Undefined(), engine);
+ tc.Reset();
+ } else {
+ serialize(data, val, engine);
+ }
+ }
+ } else if (engine->isQObject(v)) {
+ // XXX TODO: Generalize passing objects between the main thread and worker scripts so
+ // that others can trivially plug in their elements.
+ QDeclarativeListModel *lm = qobject_cast<QDeclarativeListModel *>(engine->toQObject(v));
+ if (lm && lm->agent()) {
+ QDeclarativeListModelWorkerAgent *agent = lm->agent();
+ agent->addref();
+ push(data, valueheader(WorkerListModel));
+ push(data, (void *)agent);
+ return;
+ }
+ // No other QObject's are allowed to be sent
+ push(data, valueheader(WorkerUndefined));
+ } else {
+ push(data, valueheader(WorkerUndefined));
+ }
+}
+
+v8::Handle<v8::Value> QV8Worker::deserialize(const char *&data, QV8Engine *engine)
+{
+ quint32 header = popUint32(data);
+ Type type = headertype(header);
+
+ switch (type) {
+ case WorkerUndefined:
+ return v8::Undefined();
+ case WorkerNull:
+ return v8::Null();
+ case WorkerTrue:
+ return v8::True();
+ case WorkerFalse:
+ return v8::False();
+ case WorkerString:
+ {
+ quint32 size = headersize(header);
+ v8::Local<v8::String> string = v8::String::New((uint16_t*)data, size - 1);
+ data += ALIGN(size * sizeof(uint16_t));
+ return string;
+ }
+ case WorkerFunction:
+ Q_ASSERT(!"Unreachable");
+ break;
+ case WorkerArray:
+ {
+ quint32 size = headersize(header);
+ v8::Local<v8::Array> array = v8::Array::New(size);
+ for (quint32 ii = 0; ii < size; ++ii) {
+ array->Set(ii, deserialize(data, engine));
+ }
+ return array;
+ }
+ case WorkerObject:
+ {
+ quint32 size = headersize(header);
+ v8::Local<v8::Object> o = v8::Object::New();
+ for (quint32 ii = 0; ii < size; ++ii) {
+ v8::Handle<v8::Value> name = deserialize(data, engine);
+ v8::Handle<v8::Value> value = deserialize(data, engine);
+ o->Set(name, value);
+ }
+ return o;
+ }
+ case WorkerInt32:
+ return v8::Integer::New((qint32)popUint32(data));
+ case WorkerUint32:
+ return v8::Integer::NewFromUnsigned(popUint32(data));
+ case WorkerNumber:
+ return v8::Number::New(popDouble(data));
+ case WorkerDate:
+ return v8::Date::New(popDouble(data));
+ case WorkerRegexp:
+ {
+ quint32 flags = headersize(header);
+ quint32 length = popUint32(data);
+ v8::Local<v8::String> source = v8::String::New((uint16_t*)data, length - 1);
+ data += ALIGN(length * sizeof(uint16_t));
+ return v8::RegExp::New(source, (v8::RegExp::Flags)flags);
+ }
+ case WorkerListModel:
+ {
+ void *ptr = popPtr(data);
+ QDeclarativeListModelWorkerAgent *agent = (QDeclarativeListModelWorkerAgent *)ptr;
+ v8::Handle<v8::Value> rv = engine->newQObject(agent);
+ if (rv->IsObject()) {
+ QDeclarativeListModelWorkerAgent::VariantRef ref(agent);
+ QVariant var = qVariantFromValue(ref);
+ rv->ToObject()->SetHiddenValue(v8::String::New("qml::ref"), engine->fromVariant(var));
+ }
+ agent->release();
+ agent->setV8Engine(engine);
+ return rv;
+ }
+ }
+ Q_ASSERT(!"Unreachable");
+ return v8::Undefined();
+}
+
+QByteArray QV8Worker::serialize(v8::Handle<v8::Value> value, QV8Engine *engine)
+{
+ QByteArray rv;
+ serialize(rv, value, engine);
+ return rv;
+}
+
+v8::Handle<v8::Value> QV8Worker::deserialize(const QByteArray &data, QV8Engine *engine)
+{
+ const char *stream = data.constData();
+ return deserialize(stream, engine);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/qml/v8/qv8worker_p.h b/src/declarative/qml/v8/qv8worker_p.h
new file mode 100644
index 0000000000..086e18e7e0
--- /dev/null
+++ b/src/declarative/qml/v8/qv8worker_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8WORKER_P_H
+#define QV8WORKER_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"
+
+QT_BEGIN_NAMESPACE
+
+class QV8Worker {
+public:
+ struct SavedData {
+ };
+
+ static QByteArray serialize(v8::Handle<v8::Value>, QV8Engine *);
+ static v8::Handle<v8::Value> deserialize(const QByteArray &, QV8Engine *);
+
+private:
+ static void serialize(QByteArray &, v8::Handle<v8::Value>, QV8Engine *);
+ static v8::Handle<v8::Value> deserialize(const char *&, QV8Engine *);
+};
+
+QT_END_NAMESPACE
+
+#endif // QV8WORKER_P_H
diff --git a/src/declarative/qml/v8/v8.pri b/src/declarative/qml/v8/v8.pri
new file mode 100644
index 0000000000..d91acd7759
--- /dev/null
+++ b/src/declarative/qml/v8/v8.pri
@@ -0,0 +1,32 @@
+INCLUDEPATH += $$PWD/../../../3rdparty/javascriptcore
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qv8_p.h \
+ $$PWD/qv8stringwrapper_p.h \
+ $$PWD/qv8engine_p.h \
+ $$PWD/qhashedstring_p.h \
+ $$PWD/qv8contextwrapper_p.h \
+ $$PWD/qv8qobjectwrapper_p.h \
+ $$PWD/qv8typewrapper_p.h \
+ $$PWD/qv8listwrapper_p.h \
+ $$PWD/qv8variantwrapper_p.h \
+ $$PWD/qv8valuetypewrapper_p.h \
+ $$PWD/qv8include_p.h \
+ $$PWD/qv8worker_p.h \
+ $$PWD/../../../3rdparty/javascriptcore/DateMath.h \
+
+SOURCES += \
+ $$PWD/qv8stringwrapper.cpp \
+ $$PWD/qv8engine.cpp \
+ $$PWD/qhashedstring.cpp \
+ $$PWD/qv8contextwrapper.cpp \
+ $$PWD/qv8qobjectwrapper.cpp \
+ $$PWD/qv8typewrapper.cpp \
+ $$PWD/qv8listwrapper.cpp \
+ $$PWD/qv8variantwrapper.cpp \
+ $$PWD/qv8valuetypewrapper.cpp \
+ $$PWD/qv8include.cpp \
+ $$PWD/qv8worker.cpp \
+ $$PWD/../../../3rdparty/javascriptcore/DateMath.cpp \
+