diff options
author | Andrew den Exter <andrew.den-exter@nokia.com> | 2012-05-11 17:37:07 +1000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-05-24 05:52:32 +0200 |
commit | 4709f30b26042427b225dd164648e3f5907c9d33 (patch) | |
tree | 3edac8d14d3fb77406ef93aa2c34c42131109625 /src | |
parent | 2542778d4837143a61dfcf143c32683acc8b998a (diff) |
Enable binding to properties of type QJSValue.
This allows javascript objects of all types to be bound to properties
declared in c++. Compared to a QVariant the primary benefit this offers
is a type which functions and objects with functions can be bound to.
Change-Id: Idb3313e7ff1d616ab12d44f616083c8296201f3a
Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/qml/qqmlcompiler.cpp | 29 | ||||
-rw-r--r-- | src/qml/qml/qqmlinstruction_p.h | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlproperty.cpp | 10 | ||||
-rw-r--r-- | src/qml/qml/qqmlvme.cpp | 5 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4bindings.cpp | 191 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4compiler.cpp | 22 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4instruction.cpp | 30 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4instruction_p.h | 10 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4ir.cpp | 1 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4ir_p.h | 1 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4irbuilder.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4program_p.h | 3 | ||||
-rw-r--r-- | src/qml/qml/v8/qv8engine.cpp | 3 | ||||
-rw-r--r-- | src/qml/qml/v8/qv8qobjectwrapper.cpp | 10 |
14 files changed, 319 insertions, 4 deletions
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index c3d134f6a8..d568cc463f 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -77,6 +77,7 @@ Q_DECLARE_METATYPE(QList<qreal>) Q_DECLARE_METATYPE(QList<bool>) Q_DECLARE_METATYPE(QList<QString>) Q_DECLARE_METATYPE(QList<QUrl>) +Q_DECLARE_METATYPE(QJSValue) QT_BEGIN_NAMESPACE @@ -395,6 +396,8 @@ bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop, COMPILE_EXCEPTION(v, tr("Invalid property assignment: url or array of urls expected")); } break; + } else if (type == qMetaTypeId<QJSValue>()) { + break; } // otherwise, check for existence of string converter to custom type @@ -724,6 +727,32 @@ void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop, instr.value = output->indexForString(v->value.asString()); output->addInstruction(instr); break; + } else if (type == qMetaTypeId<QJSValue>()) { + if (v->value.isBoolean()) { + Instruction::StoreJSValueBool instr; + instr.propertyIndex = prop->index; + instr.value = v->value.asBoolean(); + output->addInstruction(instr); + } else if (v->value.isNumber()) { + double n = v->value.asNumber(); + if (double(int(n)) == n) { + Instruction::StoreJSValueInteger instr; + instr.propertyIndex = prop->index; + instr.value = int(n); + output->addInstruction(instr); + } else { + Instruction::StoreJSValueDouble instr; + instr.propertyIndex = prop->index; + instr.value = n; + output->addInstruction(instr); + } + } else { + Instruction::StoreJSValueString instr; + instr.propertyIndex = prop->index; + instr.value = output->indexForString(v->value.asString()); + output->addInstruction(instr); + } + break; } // otherwise, generate custom type literal assignment diff --git a/src/qml/qml/qqmlinstruction_p.h b/src/qml/qml/qqmlinstruction_p.h index 533734b622..04f419d9d5 100644 --- a/src/qml/qml/qqmlinstruction_p.h +++ b/src/qml/qml/qqmlinstruction_p.h @@ -79,6 +79,10 @@ QT_BEGIN_NAMESPACE F(StoreVarDouble, storeDouble) \ F(StoreVarBool, storeBool) \ F(StoreString, storeString) \ + F(StoreJSValueString, storeString) \ + F(StoreJSValueInteger, storeInteger) \ + F(StoreJSValueDouble, storeDouble) \ + F(StoreJSValueBool, storeBool) \ F(StoreStringList, storeString) \ F(StoreStringQList, storeString) \ F(StoreTrString, storeTrString) \ diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 761b75acf4..087fbaa9bf 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -62,6 +62,7 @@ #include <math.h> +Q_DECLARE_METATYPE(QJSValue) Q_DECLARE_METATYPE(QList<int>) Q_DECLARE_METATYPE(QList<qreal>) Q_DECLARE_METATYPE(QList<bool>) @@ -1489,7 +1490,7 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object, value = QVariant::fromValue((QObject *)0); } else if (core.propType == qMetaTypeId<QList<QUrl> >()) { value = resolvedUrlSequence(v8engine->toVariant(result, qMetaTypeId<QList<QUrl> >()), context); - } else if (!isVmeProperty) { + } else if (!isVmeProperty && type != qMetaTypeId<QJSValue>()) { value = v8engine->toVariant(result, type); } @@ -1511,6 +1512,13 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object, QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args); } else if (isUndefined && type == qMetaTypeId<QVariant>()) { writeValueProperty(object, engine, core, QVariant(), context, flags); + } else if (type == qMetaTypeId<QJSValue>()) { + if (!result.IsEmpty() && result->IsFunction() + && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) { + expression->delayedError()->error.setDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); + return false; + } + writeValueProperty(object, engine, core, QVariant::fromValue(v8engine->scriptValueFromInternal(result)), context, flags); } else if (isUndefined) { expression->delayedError()->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + QLatin1String(QMetaType::typeName(type))); return false; diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp index b86e3beaae..1665342ffd 100644 --- a/src/qml/qml/qqmlvme.cpp +++ b/src/qml/qml/qqmlvme.cpp @@ -426,6 +426,11 @@ QObject *QQmlVME::run(QList<QQmlError> *errors, QML_STORE_VAR(StoreVarDouble, v8::Number::New(instr.value)); QML_STORE_VAR(StoreVarBool, v8::Boolean::New(instr.value)); + // Store a literal value in a QJSValue property. + QML_STORE_VALUE(StoreJSValueString, QJSValue, QJSValue(PRIMITIVES.at(instr.value))); + QML_STORE_VALUE(StoreJSValueInteger, QJSValue, QJSValue(instr.value)); + QML_STORE_VALUE(StoreJSValueDouble, QJSValue, QJSValue(instr.value)); + QML_STORE_VALUE(StoreJSValueBool, QJSValue, QJSValue(instr.value)); QML_BEGIN_INSTR(Init) // Ensure that the compiled data has been initialized diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp index d4665ac9be..3c03edbca6 100644 --- a/src/qml/qml/v4/qv4bindings.cpp +++ b/src/qml/qml/v4/qv4bindings.cpp @@ -51,6 +51,8 @@ #include <private/qv8_p.h> #include <private/qjsconverter_p.h> #include <private/qjsconverter_impl_p.h> +#include <private/qjsvalue_impl_p.h> +#include <private/qv8engine_impl_p.h> #include <private/qqmlaccessors_p.h> #include <private/qqmlprofilerservice_p.h> @@ -65,6 +67,8 @@ #include <QtCore/qmath.h> #include <math.h> // ::fmod +Q_DECLARE_METATYPE(QJSValue) + QT_BEGIN_NAMESPACE using namespace QQmlJS; @@ -101,11 +105,13 @@ struct Register { inline QString *getstringptr() { return reinterpret_cast<QString *>(typeDataPtr()); } inline QUrl *geturlptr() { return reinterpret_cast<QUrl *>(typeDataPtr()); } inline v8::Handle<v8::Value> *gethandleptr() { return reinterpret_cast<v8::Handle<v8::Value> *>(typeDataPtr()); } + inline QJSValue *getjsvalueptr() { return reinterpret_cast<QJSValue *>(typeDataPtr()); } inline const QVariant *getvariantptr() const { return reinterpret_cast<const QVariant *>(typeDataPtr()); } inline const QString *getstringptr() const { return reinterpret_cast<const QString *>(typeDataPtr()); } inline const QUrl *geturlptr() const { return reinterpret_cast<const QUrl *>(typeDataPtr()); } inline const v8::Handle<v8::Value> *gethandleptr() const { return reinterpret_cast<const v8::Handle<v8::Value> *>(typeDataPtr()); } + inline const QJSValue *getjsvalueptr() const { return reinterpret_cast<const QJSValue *>(typeDataPtr()); } size_t dataSize() { return sizeof(data); } inline void *typeDataPtr() { return (void *)&data; } @@ -134,6 +140,7 @@ struct Register { inline void cleanupColor(); inline void cleanupVariant(); inline void cleanupHandle(); + inline void cleanupJSValue(); inline void copy(const Register &other); inline void init(Type type); @@ -180,6 +187,8 @@ void Register::cleanup() getvariantptr()->~QVariant(); } else if (dataType == qMetaTypeId<v8::Handle<v8::Value> >()) { destroyPointee(gethandleptr()); + } else if (dataType == qMetaTypeId<QJSValue>()) { + getjsvalueptr()->~QJSValue(); } } setUndefined(); @@ -215,6 +224,12 @@ void Register::cleanupHandle() setUndefined(); } +void Register::cleanupJSValue() +{ + getjsvalueptr()->~QJSValue(); + setUndefined(); +} + void Register::copy(const Register &other) { *this = other; @@ -229,6 +244,8 @@ void Register::copy(const Register &other) new (getvariantptr()) QVariant(*other.getvariantptr()); else if (other.dataType == qMetaTypeId<v8::Handle<v8::Value> >()) copyConstructPointee(gethandleptr(), other.gethandleptr()); + else if (other.dataType == qMetaTypeId<QJSValue>()) + new (getjsvalueptr()) QJSValue(*other.getjsvalueptr()); } } @@ -246,6 +263,8 @@ void Register::init(Type type) new (getvariantptr()) QVariant(); else if (dataType == qMetaTypeId<v8::Handle<v8::Value> >()) defaultConstructPointee(gethandleptr()); + else if (dataType == qMetaTypeId<QJSValue>()) + new (getjsvalueptr()) QJSValue(); } } @@ -716,6 +735,11 @@ inline quint32 QV4Bindings::toUint32(double n) MARK_REGISTER(reg); \ } +#define JSVALUE_REGISTER(reg) { \ + registers[(reg)].settype(QJSValueType); \ + MARK_REGISTER(reg); \ +} + #ifdef QML_THREADED_INTERPRETER void **QV4Bindings::getDecodeInstrTable() { @@ -935,6 +959,19 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertBoolToInt, unaryop) + QML_V4_BEGIN_INSTR(ConvertBoolToJSValue, unaryop) + { + const Register &src = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + if (src.isUndefined()) { + output.setUndefined(); + } else { + new (output.getjsvalueptr()) QJSValue(src.getbool()); + JSVALUE_REGISTER(instr->unaryop.output); + } + } + QML_V4_END_INSTR(ConvertBoolToJSValue, unaryop) + QML_V4_BEGIN_INSTR(ConvertBoolToNumber, unaryop) { const Register &src = registers[instr->unaryop.src]; @@ -992,6 +1029,19 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertIntToBool, unaryop) + QML_V4_BEGIN_INSTR(ConvertIntToJSValue, unaryop) + { + const Register &src = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + if (src.isUndefined()) { + output.setUndefined(); + } else { + new (output.getjsvalueptr()) QJSValue(src.getint()); + JSVALUE_REGISTER(instr->unaryop.output); + } + } + QML_V4_END_INSTR(ConvertIntToJSValue, unaryop) + QML_V4_BEGIN_INSTR(ConvertIntToNumber, unaryop) { const Register &src = registers[instr->unaryop.src]; @@ -1040,6 +1090,30 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertIntToVar, unaryop) + QML_V4_BEGIN_INSTR(ConvertJSValueToVar, unaryop) + { + const Register &src = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + if (src.isUndefined()) { + output.setUndefined(); + } else { + QJSValue tmp(*src.getjsvalueptr()); + if (instr->unaryop.src == instr->unaryop.output) { + output.cleanupJSValue(); + MARK_CLEAN_REGISTER(instr->unaryop.output); + } + if (tmp.isUndefined()) { + output.setUndefined(); + } else { + QV8Engine *v8engine = QQmlEnginePrivate::get(context->engine)->v8engine(); + new (output.gethandleptr()) v8::Handle<v8::Value>( + QJSValuePrivate::get(tmp)->asV8Value(v8engine)); + V8HANDLE_REGISTER(instr->unaryop.output); + } + } + } + QML_V4_END_INSTR(ConvertJSValueToVar, unaryop) + QML_V4_BEGIN_INSTR(ConvertNumberToBool, unaryop) { const Register &src = registers[instr->unaryop.src]; @@ -1058,6 +1132,19 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertNumberToInt, unaryop) + QML_V4_BEGIN_INSTR(ConvertNumberToJSValue, unaryop) + { + const Register &src = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + if (src.isUndefined()) { + output.setUndefined(); + } else { + new (output.getjsvalueptr()) QJSValue(src.getnumber()); + JSVALUE_REGISTER(instr->unaryop.output); + } + } + QML_V4_END_INSTR(ConvertNumberToJSValue, unaryop) + QML_V4_BEGIN_INSTR(ConvertNumberToString, unaryop) { const Register &src = registers[instr->unaryop.src]; @@ -1138,6 +1225,24 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertStringToInt, unaryop) + QML_V4_BEGIN_INSTR(ConvertStringToJSValue, unaryop) + { + const Register &src = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + if (src.isUndefined()) { + output.setUndefined(); + } else { + QString tmp(*src.getstringptr()); + if (instr->unaryop.src == instr->unaryop.output) { + output.cleanupString(); + MARK_CLEAN_REGISTER(instr->unaryop.output); + } + new (output.getjsvalueptr()) QJSValue(tmp); + JSVALUE_REGISTER(instr->unaryop.output); + } + } + QML_V4_END_INSTR(ConvertStringToJSValue, unaryop) + QML_V4_BEGIN_INSTR(ConvertStringToNumber, unaryop) { const Register &src = registers[instr->unaryop.src]; @@ -1253,6 +1358,24 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertUrlToBool, unaryop) + QML_V4_BEGIN_INSTR(ConvertUrlToJSValue, unaryop) + { + const Register &src = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + if (src.isUndefined()) { + output.setUndefined(); + } else { + const QUrl tmp(*src.geturlptr()); + if (instr->unaryop.src == instr->unaryop.output) { + output.cleanupUrl(); + MARK_CLEAN_REGISTER(instr->unaryop.output); + } + new (output.getjsvalueptr()) QJSValue(tmp.toString()); + JSVALUE_REGISTER(instr->unaryop.output); + } + } + QML_V4_END_INSTR(ConvertUrlToJSValue, unaryop) + QML_V4_BEGIN_INSTR(ConvertUrlToString, unaryop) { const Register &src = registers[instr->unaryop.src]; @@ -1324,6 +1447,31 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertColorToBool, unaryop) + QML_V4_BEGIN_INSTR(ConvertColorToJSValue, unaryop) + { + const Register &src = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + if (src.isUndefined()) { + output.setUndefined(); + } else { + const QVariant tmp(QMetaType::QColor, src.typeDataPtr()); + if (instr->unaryop.src == instr->unaryop.output) { + output.cleanupColor(); + MARK_CLEAN_REGISTER(instr->unaryop.output); + } + + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine); + QV8Engine *v8engine = ep->v8engine(); + QQmlValueType *vt = ep->valueTypes[QMetaType::QColor]; + v8::HandleScope handle_scope; + v8::Context::Scope scope(v8engine->context()); + new (output.getjsvalueptr()) QJSValue(v8engine->scriptValueFromInternal( + v8engine->valueTypeWrapper()->newValueType(tmp, vt))); + JSVALUE_REGISTER(instr->unaryop.output); + } + } + QML_V4_END_INSTR(ConvertColorToJSValue, unaryop) + QML_V4_BEGIN_INSTR(ConvertColorToString, unaryop) { const Register &src = registers[instr->unaryop.src]; @@ -1391,6 +1539,22 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertObjectToBool, unaryop) + QML_V4_BEGIN_INSTR(ConvertObjectToJSValue, unaryop) + { + const Register &src = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + if (src.isUndefined()) { + output.setUndefined(); + } else { + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine); + v8::HandleScope handle_scope; + v8::Context::Scope scope(ep->v8engine()->context()); + new (output.getjsvalueptr()) QJSValue(context->engine->newQObject(src.getQObject())); + JSVALUE_REGISTER(instr->unaryop.output); + } + } + QML_V4_END_INSTR(ConvertObjectToJSValue, unaryop) + QML_V4_BEGIN_INSTR(ConvertObjectToVariant, unaryop) { const Register &src = registers[instr->unaryop.src]; @@ -1420,6 +1584,33 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertObjectToVar, unaryop) + QML_V4_BEGIN_INSTR(ConvertVarToJSValue, unaryop) + { + const Register &src = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + if (src.isUndefined()) { + output.setUndefined(); + } else { + v8::Handle<v8::Value> tmp(*src.gethandleptr()); + if (instr->unaryop.src == instr->unaryop.output) { + output.cleanupHandle(); + MARK_CLEAN_REGISTER(instr->unaryop.output); + } + QV8Engine *v8engine = QQmlEnginePrivate::get(context->engine)->v8engine(); + new (output.getjsvalueptr()) QJSValue(v8engine->scriptValueFromInternal(tmp)); + JSVALUE_REGISTER(instr->unaryop.output); + } + } + QML_V4_END_INSTR(ConvertVarToJSValue, unaryop) + + QML_V4_BEGIN_INSTR(ConvertNullToJSValue, unaryop) + { + Register &output = registers[instr->unaryop.output]; + new (output.getjsvalueptr()) QJSValue(QJSValue::NullValue); + JSVALUE_REGISTER(instr->unaryop.output); + } + QML_V4_END_INSTR(ConvertNullToJSValue, unaryop) + QML_V4_BEGIN_INSTR(ConvertNullToObject, unaryop) { Register &output = registers[instr->unaryop.output]; diff --git a/src/qml/qml/v4/qv4compiler.cpp b/src/qml/qml/v4/qv4compiler.cpp index 783e147ba0..1c163364a3 100644 --- a/src/qml/qml/v4/qv4compiler.cpp +++ b/src/qml/qml/v4/qv4compiler.cpp @@ -50,6 +50,8 @@ #include <private/qqmlaccessors_p.h> #include <private/qqmljsengine_p.h> +Q_DECLARE_METATYPE(QJSValue) + QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP) @@ -971,6 +973,7 @@ void QV4CompilerPrivate::visitMove(IR::Move *s) case IR::StringType: case IR::VariantType: case IR::VarType: + case IR::JSValueType: // nothing to do. V4 will generate optimized // url-to-xxx conversions. break; @@ -1098,9 +1101,25 @@ void QV4CompilerPrivate::visitMove(IR::Move *s) case IR::StringType: opcode = V4Instr::ConvertStringToVar; break; case IR::ObjectType: opcode = V4Instr::ConvertObjectToVar; break; case IR::NullType: opcode = V4Instr::ConvertNullToVar; break; + case IR::JSValueType: opcode = V4Instr::ConvertJSValueToVar; break; default: break; } // switch } + } else if (targetTy == IR::JSValueType) { + if (s->isMoveForReturn) { + switch (sourceTy) { + case IR::BoolType: opcode = V4Instr::ConvertBoolToJSValue; break; + case IR::IntType: opcode = V4Instr::ConvertIntToJSValue; break; + case IR::NumberType: opcode = V4Instr::ConvertNumberToJSValue; break; + case IR::UrlType: opcode = V4Instr::ConvertUrlToJSValue; break; + case IR::ColorType: opcode = V4Instr::ConvertColorToJSValue; break; + case IR::StringType: opcode = V4Instr::ConvertStringToJSValue; break; + case IR::ObjectType: opcode = V4Instr::ConvertObjectToJSValue; break; + case IR::VarType: opcode = V4Instr::ConvertVarToJSValue; break; + case IR::NullType: opcode = V4Instr::ConvertNullToJSValue; break; + default: break; + } + } } if (opcode != V4Instr::Noop) { V4Instr conv; @@ -1180,6 +1199,9 @@ void QV4CompilerPrivate::visitRet(IR::Ret *s) case IR::VarType: test.regType = qMetaTypeId<v8::Handle<v8::Value> >(); break; + case IR::JSValueType: + test.regType = qMetaTypeId<QJSValue>(); + break; case IR::BoolType: test.regType = QMetaType::Bool; break; diff --git a/src/qml/qml/v4/qv4instruction.cpp b/src/qml/qml/v4/qv4instruction.cpp index fccb0f7b98..1fbdf3e325 100644 --- a/src/qml/qml/v4/qv4instruction.cpp +++ b/src/qml/qml/v4/qv4instruction.cpp @@ -138,6 +138,9 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::ConvertBoolToInt: INSTR_DUMP << '\t' << "ConvertBoolToInt" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; + case V4Instr::ConvertBoolToJSValue: + INSTR_DUMP << '\t' << "ConvertBoolToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; + break; case V4Instr::ConvertBoolToNumber: INSTR_DUMP << '\t' << "ConvertBoolToNumber" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; @@ -153,6 +156,9 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::ConvertIntToBool: INSTR_DUMP << '\t' << "ConvertIntToBool" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; + case V4Instr::ConvertIntToJSValue: + INSTR_DUMP << '\t' << "ConvertIntToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; + break; case V4Instr::ConvertIntToNumber: INSTR_DUMP << '\t' << "ConvertIntToNumber" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; @@ -165,12 +171,18 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::ConvertIntToVar: INSTR_DUMP << '\t' << "ConvertIntToVar" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; + case V4Instr::ConvertJSValueToVar: + INSTR_DUMP << '\t' << "ConvertJSValueToVar" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; + break; case V4Instr::ConvertNumberToBool: INSTR_DUMP << '\t' << "ConvertNumberToBool" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; case V4Instr::ConvertNumberToInt: INSTR_DUMP << '\t' << "ConvertNumberToInt" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; + case V4Instr::ConvertNumberToJSValue: + INSTR_DUMP << '\t' << "ConvertNumberToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; + break; case V4Instr::ConvertNumberToString: INSTR_DUMP << '\t' << "ConvertNumberToString" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; @@ -186,6 +198,9 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::ConvertStringToInt: INSTR_DUMP << '\t' << "ConvertStringToInt" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; + case V4Instr::ConvertStringToJSValue: + INSTR_DUMP << '\t' << "ConvertStringToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; + break; case V4Instr::ConvertStringToNumber: INSTR_DUMP << '\t' << "ConvertStringToNumber" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; @@ -204,6 +219,9 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::ConvertUrlToBool: INSTR_DUMP << '\t' << "ConvertUrlToBool" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; + case V4Instr::ConvertUrlToJSValue: + INSTR_DUMP << '\t' << "ConvertUrlToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; + break; case V4Instr::ConvertUrlToString: INSTR_DUMP << '\t' << "ConvertUrlToString" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; @@ -216,6 +234,9 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::ConvertColorToBool: INSTR_DUMP << '\t' << "ConvertColorToBool" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; + case V4Instr::ConvertColorToJSValue: + INSTR_DUMP << '\t' << "ConvertColorToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; + break; case V4Instr::ConvertColorToString: INSTR_DUMP << '\t' << "ConvertColorToString" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; @@ -228,12 +249,21 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::ConvertObjectToBool: INSTR_DUMP << '\t' << "ConvertObjectToBool" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; + case V4Instr::ConvertObjectToJSValue: + INSTR_DUMP << '\t' << "ConvertObjectToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; + break; case V4Instr::ConvertObjectToVariant: INSTR_DUMP << '\t' << "ConvertObjectToVariant" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; case V4Instr::ConvertObjectToVar: INSTR_DUMP << '\t' << "ConvertObjectToVar" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; + case V4Instr::ConvertVarToJSValue: + INSTR_DUMP << '\t' << "ConvertVarToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; + break; + case V4Instr::ConvertNullToJSValue: + INSTR_DUMP << '\t' << "ConvertNullToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; + break; case V4Instr::ConvertNullToObject: INSTR_DUMP << '\t' << "ConvertNullToObject" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')'; break; diff --git a/src/qml/qml/v4/qv4instruction_p.h b/src/qml/qml/v4/qv4instruction_p.h index c9e244e6b4..2e06bd0850 100644 --- a/src/qml/qml/v4/qv4instruction_p.h +++ b/src/qml/qml/v4/qv4instruction_p.h @@ -81,38 +81,48 @@ QT_BEGIN_NAMESPACE F(UnaryPlusNumber, unaryop) \ F(UnaryPlusInt, unaryop) \ F(ConvertBoolToInt, unaryop) \ + F(ConvertBoolToJSValue, unaryop) \ F(ConvertBoolToNumber, unaryop) \ F(ConvertBoolToString, unaryop) \ F(ConvertBoolToVariant, unaryop) \ F(ConvertBoolToVar, unaryop) \ F(ConvertIntToBool, unaryop) \ + F(ConvertIntToJSValue, unaryop) \ F(ConvertIntToNumber, unaryop) \ F(ConvertIntToString, unaryop) \ F(ConvertIntToVariant, unaryop) \ F(ConvertIntToVar, unaryop) \ + F(ConvertJSValueToVar, unaryop) \ F(ConvertNumberToBool, unaryop) \ F(ConvertNumberToInt, unaryop) \ + F(ConvertNumberToJSValue, unaryop) \ F(ConvertNumberToString, unaryop) \ F(ConvertNumberToVariant, unaryop) \ F(ConvertNumberToVar, unaryop) \ F(ConvertStringToBool, unaryop) \ F(ConvertStringToInt, unaryop) \ + F(ConvertStringToJSValue, unaryop) \ F(ConvertStringToNumber, unaryop) \ F(ConvertStringToUrl, unaryop) \ F(ConvertStringToColor, unaryop) \ F(ConvertStringToVariant, unaryop) \ F(ConvertStringToVar, unaryop) \ F(ConvertUrlToBool, unaryop) \ + F(ConvertUrlToJSValue, unaryop) \ F(ConvertUrlToString, unaryop) \ F(ConvertUrlToVariant, unaryop) \ F(ConvertUrlToVar, unaryop) \ F(ConvertColorToBool, unaryop) \ + F(ConvertColorToJSValue, unaryop) \ F(ConvertColorToString, unaryop) \ F(ConvertColorToVariant, unaryop) \ F(ConvertColorToVar, unaryop) \ F(ConvertObjectToBool, unaryop) \ + F(ConvertObjectToJSValue, unaryop) \ F(ConvertObjectToVariant, unaryop) \ F(ConvertObjectToVar, unaryop) \ + F(ConvertVarToJSValue, unaryop) \ + F(ConvertNullToJSValue, unaryop) \ F(ConvertNullToObject, unaryop) \ F(ConvertNullToVariant, unaryop) \ F(ConvertNullToVar, unaryop) \ diff --git a/src/qml/qml/v4/qv4ir.cpp b/src/qml/qml/v4/qv4ir.cpp index a111bbf6e7..bb4a0d8df0 100644 --- a/src/qml/qml/v4/qv4ir.cpp +++ b/src/qml/qml/v4/qv4ir.cpp @@ -65,6 +65,7 @@ const char *typeName(Type t) case ObjectType: return "object"; case VariantType: return "variant"; case VarType: return "var"; + case JSValueType: return "QJSValue"; case BoolType: return "bool"; case IntType: return "int"; case FloatType: return "float"; diff --git a/src/qml/qml/v4/qv4ir_p.h b/src/qml/qml/v4/qv4ir_p.h index 485c24586c..982acc5a44 100644 --- a/src/qml/qml/v4/qv4ir_p.h +++ b/src/qml/qml/v4/qv4ir_p.h @@ -148,6 +148,7 @@ enum Type { ObjectType, VariantType, VarType, + JSValueType, FirstNumberType, BoolType = FirstNumberType, diff --git a/src/qml/qml/v4/qv4irbuilder.cpp b/src/qml/qml/v4/qv4irbuilder.cpp index 52f0696be9..47acaaf67c 100644 --- a/src/qml/qml/v4/qv4irbuilder.cpp +++ b/src/qml/qml/v4/qv4irbuilder.cpp @@ -48,6 +48,8 @@ DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER) +Q_DECLARE_METATYPE(QJSValue) + QT_BEGIN_NAMESPACE using namespace QQmlJS; @@ -81,6 +83,8 @@ static IR::Type irTypeFromVariantType(int t, QQmlEnginePrivate *engine, const QM return IR::SGAnchorLineType; } else if (engine->metaObjectForType(t)) { return IR::ObjectType; + } else if (t == qMetaTypeId<QJSValue>()) { + return IR::JSValueType; } return IR::InvalidType; diff --git a/src/qml/qml/v4/qv4program_p.h b/src/qml/qml/v4/qv4program_p.h index 3fb1670411..d859a83abb 100644 --- a/src/qml/qml/v4/qv4program_p.h +++ b/src/qml/qml/v4/qv4program_p.h @@ -103,7 +103,8 @@ enum QQmlRegisterType { QUrlType, QVariantType, QColorType, - V8HandleType + V8HandleType, + QJSValueType }; const char *QV4Program::data() const diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 275b648ee4..c075fc9d1b 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -229,6 +229,9 @@ QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint) if (typeHint == QMetaType::QJsonValue) return QVariant::fromValue(jsonValueFromJS(value)); + if (typeHint == qMetaTypeId<QJSValue>()) + return QVariant::fromValue(scriptValueFromInternal(value)); + if (value->IsObject()) { QV8ObjectResource *r = (QV8ObjectResource *)value->ToObject()->GetExternalResource(); if (r) { diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp index aab66e33a2..f540ce126b 100644 --- a/src/qml/qml/v8/qv8qobjectwrapper.cpp +++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp @@ -433,6 +433,10 @@ static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object, QQmlV8Handle handle; ReadFunction(object, property, &handle, notifier); return handle.toHandle(); + } else if (property.propType == qMetaTypeId<QJSValue>()) { + QJSValue v; + ReadFunction(object, property, &v, notifier); + return QJSValuePrivate::get(v)->asV8Value(engine); } else if (property.isQVariant()) { QVariant v; ReadFunction(object, property, &v, notifier); @@ -590,8 +594,8 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert QQmlBinding *newBinding = 0; if (value->IsFunction()) { if (value->ToObject()->GetHiddenValue(engine->bindingFlagKey()).IsEmpty()) { - if (!property->isVMEProperty()) { - // assigning a JS function to a non-var-property is not allowed. + if (!property->isVMEProperty() && property->propType != qMetaTypeId<QJSValue>()) { + // assigning a JS function to a non var or QJSValue property or is not allowed. QString error = QLatin1String("Cannot assign JavaScript function to ") + QLatin1String(QMetaType::typeName(property->propType)); v8::ThrowException(v8::Exception::Error(engine->toString(error))); @@ -647,6 +651,8 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert PROPERTY_STORE(QVariant, QVariant()); } else if (value->IsUndefined() && property->propType == QMetaType::QJsonValue) { PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined)); + } else if (!newBinding && property->propType == qMetaTypeId<QJSValue>()) { + PROPERTY_STORE(QJSValue, engine->scriptValueFromInternal(value)); } else if (value->IsUndefined()) { QString error = QLatin1String("Cannot assign [undefined] to ") + QLatin1String(QMetaType::typeName(property->propType)); |