static v8::Handle<v8::Value> qmlsqldatabase_changeVersion(const v8::Arguments& args) { if (args.Length() < 2) return v8::Undefined(); 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(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(r->version)); v8::Local<v8::Object> instance = databaseData(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()) { ok = false; db.transaction(); 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(SQLEXCEPTION_UNKNOWN_ERR,QQmlEngine::tr("SQL transaction failed")); } else { ok = true; } } r2->inTransaction = false; if (ok) { 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 v8::Undefined(); }
v8::Handle<v8::Value> QV8ContextWrapper::Setter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo &info) { QV8ContextResource *resource = v8_resource_check<QV8ContextResource>(info.This()); // Its possible we could delay the calculation of the "actual" context (in the case // of sub contexts) until it is definately needed. QQmlContextData *context = resource->getContext(); QQmlContextData *expressionContext = context; if (!context) return v8::Undefined(); if (v8::Context::GetCallingQmlGlobal() != info.This()) return v8::Handle<v8::Value>(); // See QV8ContextWrapper::Getter for resolution order QV8Engine *engine = resource->engine; QObject *scopeObject = resource->getScopeObject(); QHashedV8String propertystring(property); QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper(); while (context) { // Search context properties if (context->propertyNames && -1 != context->propertyNames->value(propertystring)) return value; // Search scope object if (scopeObject && qobjectWrapper->setProperty(scopeObject, propertystring, context, value, QV8QObjectWrapper::CheckRevision)) return value; scopeObject = 0; // Search context object if (context->contextObject && qobjectWrapper->setProperty(context->contextObject, propertystring, context, value, QV8QObjectWrapper::CheckRevision)) return value; context = context->parent; } expressionContext->unresolvedNames = true; if (!resource->readOnly) { return v8::Handle<v8::Value>(); } else { QString error = QLatin1String("Invalid write to global property \"") + engine->toString(property) + QLatin1Char('"'); v8::ThrowException(v8::Exception::Error(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_check<QV8ContextResource>(info.This()); QV8Engine *engine = resource->engine; if (!resource->readOnly) { return v8::Handle<v8::Value>(); } else { QString error = QLatin1String("Invalid write to global property \"") + engine->toString(property) + QLatin1Char('"'); v8::ThrowException(v8::Exception::Error(engine->toString(error))); return v8::Handle<v8::Value>(); } }
static v8::Handle<v8::Value> qmlsqldatabase_transaction_shared(const v8::Arguments& args, bool readOnly) { 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(SQLEXCEPTION_UNKNOWN_ERR,QQmlEngine::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 = databaseData(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(); 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(); } return v8::Undefined(); }
// Parts of this function mirror code in QQmlExpressionPrivate::value() and v8value(). // Changes made here may need to be made there and vice versa. void QQmlBoundSignalExpression::evaluate(void **a) { Q_ASSERT (context() && engine()); if (invalidParameterName()) return; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine()); QV4::Scope scope(ep->v4engine()); ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation. { if (!expressionFunctionValid()) { Q_ASSERT(!m_extra.isNull()); QString expression; // Add some leading whitespace to account for the binding's column offset. // It's 2 off because a, we start counting at 1 and b, the '(' below is not counted. expression.fill(QChar(QChar::Space), qMax(m_extra->m_sourceLocation.column, (quint16)2) - 2); expression += QStringLiteral("(function "); expression += m_extra->m_handlerName; expression += QLatin1Char('('); if (m_extra->m_parameterString.isEmpty()) { QString error; //TODO: look at using the property cache here (as in the compiler) // for further optimization QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index); expression += QQmlPropertyCache::signalParameterStringForJS(engine(), signal.parameterNames(), &error); if (!error.isEmpty()) { qmlInfo(scopeObject()) << error; setInvalidParameterName(true); ep->dereferenceScarceResources(); return; } } else expression += m_extra->m_parameterString; expression += QStringLiteral(") { "); expression += m_extra->m_expression; expression += QStringLiteral(" })"); m_extra->m_expression.clear(); m_extra->m_handlerName.clear(); m_extra->m_parameterString.clear(); m_v8function = evalFunction(context(), scopeObject(), expression, m_extra->m_sourceLocation.sourceFile, m_extra->m_sourceLocation.line, &m_extra->m_v8qmlscope); if (m_v8function.isNullOrUndefined()) { ep->dereferenceScarceResources(); return; // could not evaluate function. Not valid. } setExpressionFunctionValid(true); } QV8Engine *engine = ep->v8engine(); QVarLengthArray<int, 9> dummy; //TODO: lookup via signal index rather than method index as an optimization int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex(); int *argsTypes = QQmlPropertyCache::methodParameterTypes(m_target, methodIndex, dummy, 0); int argCount = argsTypes ? *argsTypes : 0; QV4::ScopedValue f(scope, m_v8function.value()); QV4::ScopedCallData callData(scope, argCount); for (int ii = 0; ii < argCount; ++ii) { int type = argsTypes[ii + 1]; //### ideally we would use metaTypeToJS, however it currently gives different results // for several cases (such as QVariant type and QObject-derived types) //args[ii] = engine->metaTypeToJS(type, a[ii + 1]); if (type == QMetaType::QVariant) { callData->args[ii] = engine->fromVariant(*((QVariant *)a[ii + 1])); } else if (type == QMetaType::Int) { //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise callData->args[ii] = QV4::Primitive::fromInt32(*reinterpret_cast<const int*>(a[ii + 1])); } else if (type == qMetaTypeId<QQmlV4Handle>()) { callData->args[ii] = *reinterpret_cast<QQmlV4Handle *>(a[ii + 1]); } else if (ep->isQObject(type)) { if (!*reinterpret_cast<void* const *>(a[ii + 1])) callData->args[ii] = QV4::Primitive::nullValue(); else callData->args[ii] = QV4::QObjectWrapper::wrap(ep->v4engine(), *reinterpret_cast<QObject* const *>(a[ii + 1])); } else { callData->args[ii] = engine->fromVariant(QVariant(type, a[ii + 1])); } } QQmlJavaScriptExpression::evaluate(context(), f, callData, 0); } ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. }
/*! \internal convert \a value to \a type, store the result in \a ptr */ bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr) { QJSValuePrivate *vp = QJSValuePrivate::get(value); QV8Engine *engine = vp->engine ? vp->engine->v8Engine : 0; if (engine) { QV4::Scope scope(engine->m_v4Engine); QV4::ScopedValue v(scope, vp->getValue(engine->m_v4Engine)); return engine->metaTypeFromJS(v, type, ptr); } else if (vp->value.isEmpty()) { // have a string based value without engine. Do conversion manually if (type == QMetaType::Bool) { *reinterpret_cast<bool*>(ptr) = vp->string.length() != 0; return true; } if (type == QMetaType::QString) { *reinterpret_cast<QString*>(ptr) = vp->string; return true; } double d = QV4::RuntimeHelpers::stringToNumber(vp->string); switch (type) { case QMetaType::Int: *reinterpret_cast<int*>(ptr) = QV4::Primitive::toInt32(d); return true; case QMetaType::UInt: *reinterpret_cast<uint*>(ptr) = QV4::Primitive::toUInt32(d); return true; case QMetaType::LongLong: *reinterpret_cast<qlonglong*>(ptr) = QV4::Primitive::toInteger(d); return true; case QMetaType::ULongLong: *reinterpret_cast<qulonglong*>(ptr) = QV4::Primitive::toInteger(d); return true; case QMetaType::Double: *reinterpret_cast<double*>(ptr) = d; return true; case QMetaType::Float: *reinterpret_cast<float*>(ptr) = d; return true; case QMetaType::Short: *reinterpret_cast<short*>(ptr) = QV4::Primitive::toInt32(d); return true; case QMetaType::UShort: *reinterpret_cast<unsigned short*>(ptr) = QV4::Primitive::toUInt32(d); return true; case QMetaType::Char: *reinterpret_cast<char*>(ptr) = QV4::Primitive::toInt32(d); return true; case QMetaType::UChar: *reinterpret_cast<unsigned char*>(ptr) = QV4::Primitive::toUInt32(d); return true; case QMetaType::QChar: *reinterpret_cast<QChar*>(ptr) = QV4::Primitive::toUInt32(d); return true; default: return false; } } else { switch (type) { case QMetaType::Bool: *reinterpret_cast<bool*>(ptr) = vp->value.toBoolean(); return true; case QMetaType::Int: *reinterpret_cast<int*>(ptr) = vp->value.toInt32(); return true; case QMetaType::UInt: *reinterpret_cast<uint*>(ptr) = vp->value.toUInt32(); return true; case QMetaType::LongLong: *reinterpret_cast<qlonglong*>(ptr) = vp->value.toInteger(); return true; case QMetaType::ULongLong: *reinterpret_cast<qulonglong*>(ptr) = vp->value.toInteger(); return true; case QMetaType::Double: *reinterpret_cast<double*>(ptr) = vp->value.toNumber(); return true; case QMetaType::QString: *reinterpret_cast<QString*>(ptr) = value.toString(); return true; case QMetaType::Float: *reinterpret_cast<float*>(ptr) = vp->value.toNumber(); return true; case QMetaType::Short: *reinterpret_cast<short*>(ptr) = vp->value.toInt32(); return true; case QMetaType::UShort: *reinterpret_cast<unsigned short*>(ptr) = vp->value.toUInt16(); return true; case QMetaType::Char: *reinterpret_cast<char*>(ptr) = vp->value.toInt32(); return true; case QMetaType::UChar: *reinterpret_cast<unsigned char*>(ptr) = vp->value.toUInt16(); return true; case QMetaType::QChar: *reinterpret_cast<QChar*>(ptr) = vp->value.toUInt16(); return true; default: return false; } } }
v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property, const v8::AccessorInfo &info) { QV8ContextResource *resource = v8_resource_check<QV8ContextResource>(info.This()); // Its possible we could delay the calculation of the "actual" context (in the case // of sub contexts) until it is definately needed. QQmlContextData *context = resource->getContext(); QQmlContextData *expressionContext = context; if (!context) return v8::Undefined(); if (v8::Context::GetCallingQmlGlobal() != info.This()) return v8::Handle<v8::Value>(); // Search type (attached property/enum/imported scripts) names // while (context) { // Search context properties // Search scope object // Search context object // context = context->parent // } QV8Engine *engine = resource->engine; QObject *scopeObject = resource->getScopeObject(); QHashedV8String propertystring(property); if (context->imports && QV8Engine::startsWithUpper(property)) { // Search for attached properties, enums and imported scripts QQmlTypeNameCache::Result r = context->imports->query(propertystring); if (r.isValid()) { if (r.scriptIndex != -1) { int index = r.scriptIndex; if (index < context->importedScripts.count()) return context->importedScripts.at(index); else return v8::Undefined(); } else if (r.type) { return engine->typeWrapper()->newObject(scopeObject, r.type); } else if (r.importNamespace) { return engine->typeWrapper()->newObject(scopeObject, context->imports, r.importNamespace); } Q_ASSERT(!"Unreachable"); } // Fall through } QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->engine()); QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper(); while (context) { // Search context properties if (context->propertyNames) { int propertyIdx = context->propertyNames->value(propertystring); if (propertyIdx != -1) { if (propertyIdx < context->idValueCount) { ep->captureProperty(&context->idValues[propertyIdx].bindings); return engine->newQObject(context->idValues[propertyIdx]); } else { QQmlContextPrivate *cp = context->asQQmlContextPrivate(); ep->captureProperty(context->asQQmlContext(), -1, propertyIdx + cp->notifyIndex); const QVariant &value = cp->propertyValues.at(propertyIdx); if (value.userType() == qMetaTypeId<QList<QObject*> >()) { QQmlListProperty<QObject> prop(context->asQQmlContext(), (void*) qintptr(propertyIdx), QQmlContextPrivate::context_count, QQmlContextPrivate::context_at); return engine->listWrapper()->newList(prop, qMetaTypeId<QQmlListProperty<QObject> >()); } else { return engine->fromVariant(cp->propertyValues.at(propertyIdx)); } } } } // Search scope object if (scopeObject) { v8::Handle<v8::Value> result = qobjectWrapper->getProperty(scopeObject, propertystring, context, QV8QObjectWrapper::CheckRevision); if (!result.IsEmpty()) return result; } scopeObject = 0; // Search context object if (context->contextObject) { v8::Handle<v8::Value> result = qobjectWrapper->getProperty(context->contextObject, propertystring, context, QV8QObjectWrapper::CheckRevision); if (!result.IsEmpty()) return result; } context = context->parent; } expressionContext->unresolvedNames = true; // V8 will throw a ReferenceError if appropriate ("typeof" should not throw) return v8::Handle<v8::Value>(); }
void QQuickLocalStorage::openDatabaseSync(QQmlV8Function *args) { #ifndef QT_NO_SETTINGS QV8Engine *engine = args->engine(); if (engine->engine()->offlineStoragePath().isEmpty()) V8THROW_SQL_VOID(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr("SQL: can't create database, offline storage is disabled.")); qmlsqldatabase_initDatabasesPath(engine); QSqlDatabase database; 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()); QString dbid(QLatin1String(md5.result().toHex())); QString basename = qmlsqldatabase_databaseFile(dbid, engine); bool created = false; QString version = dbversion; { QSettings ini(basename+QLatin1String(".ini"),QSettings::IniFormat); if (QSqlDatabase::connectionNames().contains(dbid)) { database = QSqlDatabase::database(dbid); version = ini.value(QLatin1String("Version")).toString(); if (version != dbversion && !dbversion.isEmpty() && !version.isEmpty()) V8THROW_SQL_VOID(SQLEXCEPTION_VERSION_ERR, QQmlEngine::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()) version = QString(); ini.setValue(QLatin1String("Version"), version); ini.setValue(QLatin1String("Description"), dbdescription); ini.setValue(QLatin1String("EstimatedSize"), dbestimatedsize); ini.setValue(QLatin1String("Driver"), QLatin1String("QSQLITE")); } else { if (!dbversion.isEmpty() && ini.value(QLatin1String("Version")) != dbversion) { // Incompatible V8THROW_SQL_VOID(SQLEXCEPTION_VERSION_ERR,QQmlEngine::tr("SQL: database version mismatch")); } version = ini.value(QLatin1String("Version")).toString(); } database.setDatabaseName(basename+QLatin1String(".sqlite")); } if (!database.isOpen()) database.open(); } v8::Local<v8::Object> instance = databaseData(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; } } args->returnValue(instance); #endif // QT_NO_SETTINGS }
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(SQLEXCEPTION_DATABASE_ERR,QQmlEngine::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(SQLEXCEPTION_SYNTAX_ERR, QQmlEngine::tr("Read-only Transaction")); } QSqlQuery query(db); bool err = false; v8::Handle<v8::Value> result = v8::Undefined(); if (query.prepare(sql)) { 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, engine->toVariant(values, -1)); } } if (query.exec()) { v8::Handle<v8::Object> rows = databaseData(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; } } else { err = true; } if (err) V8THROW_SQL(SQLEXCEPTION_DATABASE_ERR,query.lastError().text()); return result; }
// Parts of this function mirror code in QQmlExpressionPrivate::value() and v8value(). // Changes made here may need to be made there and vice versa. void QQmlBoundSignalExpression::evaluate(void **a) { Q_ASSERT (context() && engine()); if (m_invalidParameterName) return; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine()); ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation. { v8::HandleScope handle_scope; v8::Context::Scope context_scope(ep->v8engine()->context()); if (!m_expressionFunctionValid) { //TODO: look at using the property cache here (as in the compiler) // for further optimization QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index); QQmlRewrite::RewriteSignalHandler rewriter; QString expression; bool ok = true; if (m_expressionFunctionRewritten) { expression = QString::fromUtf8(m_expressionUtf8); //if we need parameters, and the rewrite doesn't include them, //create and insert the parameter string now if (m_parameterCountForJS == -1 && signal.parameterCount()) { const QString ¶meters = rewriter.createParameterString(signal.parameterNames(), ep->v8engine()->illegalNames()); int index = expression.indexOf(QLatin1Char('('), 1); Q_ASSERT(index > -1); expression.insert(index + 1, parameters); setParameterCountForJS(rewriter.parameterCountForJS()); } m_expressionUtf8.clear(); } else { //expression is still in its original form, so perform a full rewrite expression = rewriter(m_expression, QString()/*no name hint available*/, &ok, signal.parameterNames(), ep->v8engine()->illegalNames()); setParameterCountForJS(rewriter.parameterCountForJS()); m_expression.clear(); } if (rewriter.hasParameterError()) { qmlInfo(scopeObject()) << rewriter.parameterError(); m_invalidParameterName = true; ep->dereferenceScarceResources(); return; } if (ok) { m_v8function = evalFunction(context(), scopeObject(), expression, m_fileName, m_line, &m_v8qmlscope); } if (m_v8function.IsEmpty() || m_v8function->IsNull()) { ep->dereferenceScarceResources(); return; // could not evaluate function. Not valid. } setUseSharedContext(false); m_expressionFunctionValid = true; } if (!hasParameterInfo()) { QQmlJavaScriptExpression::evaluate(context(), m_v8function, 0); } else { QV8Engine *engine = ep->v8engine(); QVarLengthArray<int, 9> dummy; //TODO: lookup via signal index rather than method index as an optimization int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex(); int *argsTypes = QQmlPropertyCache::methodParameterTypes(m_target, methodIndex, dummy, 0); int argCount = argsTypes ? m_parameterCountForJS : 0; QVarLengthArray<v8::Handle<v8::Value>, 9> args(argCount); for (int ii = 0; ii < argCount; ++ii) { int type = argsTypes[ii + 1]; //### ideally we would use metaTypeToJS, however it currently gives different results // for several cases (such as QVariant type and QObject-derived types) //args[ii] = engine->metaTypeToJS(type, a[ii + 1]); if (type == QMetaType::QVariant) { args[ii] = engine->fromVariant(*((QVariant *)a[ii + 1])); } else if (type == QMetaType::Int) { //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise args[ii] = v8::Integer::New(*reinterpret_cast<const int*>(a[ii + 1])); } else if (type == qMetaTypeId<QQmlV8Handle>()) { args[ii] = reinterpret_cast<QQmlV8Handle *>(a[ii + 1])->toHandle(); } else if (ep->isQObject(type)) { if (!*reinterpret_cast<void* const *>(a[ii + 1])) args[ii] = v8::Null(); else args[ii] = engine->newQObject(*reinterpret_cast<QObject* const *>(a[ii + 1])); } else { args[ii] = engine->fromVariant(QVariant(type, a[ii + 1])); } } QQmlJavaScriptExpression::evaluate(context(), m_v8function, argCount, args.data(), 0); } } ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. }
/* 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; }