QQmlBinding *
QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt)
{
    if (id < 0)
        return 0;

    QQmlBinding *rv = 0;

    QQmlContextData *ctxtdata = QQmlContextData::get(ctxt);
    QQmlEnginePrivate *engine = QQmlEnginePrivate::get(ctxt->engine());
    if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
        QQmlTypeData *typeData = engine->typeLoader.getType(ctxtdata->url);
        Q_ASSERT(typeData);

        if (QQmlCompiledData *cdata = typeData->compiledData()) {
            QV4::ExecutionEngine *v4 = engine->v4engine();
            QV4::Scope valueScope(v4);
            QV4::Function *runtimeFunction = cdata->compilationUnit->runtimeFunctions[cdata->customParserBindings[id]];
            QV4::ScopedValue function(valueScope, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, obj, runtimeFunction));
            rv = new QQmlBinding(function, obj, ctxtdata);
        }

        typeData->release();
    }

    return rv;
}
Exemplo n.º 2
0
// 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 (!expressionFunctionValid())
        return;

    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine());
    QV4::Scope scope(ep->v4engine());

    ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.

    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 = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, dummy, 0);
    int argCount = argsTypes ? *argsTypes : 0;

    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] = scope.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] = scope.engine->fromVariant(QVariant(type, a[ii + 1]));
        }
    }

    QQmlJavaScriptExpression::evaluate(callData, 0);

    ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
Exemplo n.º 3
0
QT_BEGIN_NAMESPACE

QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
                                                     QQmlContextData *ctxt, QObject *scope, const QString &expression,
                                                     const QString &fileName, quint16 line, quint16 column,
                                                     const QString &handlerName,
                                                     const QString &parameterString)
    : QQmlJavaScriptExpression(),
      m_index(index),
      m_target(target)
{
    init(ctxt, scope);

    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine());
    QV4::ExecutionEngine *v4 = ep->v4engine();

    QString function;

    // 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.
    function.fill(QChar(QChar::Space), qMax(column, (quint16)2) - 2);
    function += QStringLiteral("(function ");
    function += handlerName;
    function += QLatin1Char('(');

    if (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);
        function += QQmlPropertyCache::signalParameterStringForJS(v4, signal.parameterNames(), &error);

        if (!error.isEmpty()) {
            qmlInfo(scopeObject()) << error;
            return;
        }
    } else
        function += parameterString;

    function += QStringLiteral(") { ");
    function += expression;
    function += QStringLiteral(" })");

    m_function.set(v4, evalFunction(context(), scopeObject(), function, fileName, line));

    if (m_function.isNullOrUndefined())
        return; // could not evaluate function.  Not valid.

}
Exemplo n.º 4
0
QString QQmlBinding::expressionIdentifier(QQmlJavaScriptExpression *e)
{
    QQmlBinding *This = static_cast<QQmlBinding *>(e);

    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(This->context()->engine);
    QV4::Scope scope(ep->v4engine());
    QV4::ScopedValue f(scope, This->v4function.value());
    QV4::Function *function = f->asFunctionObject()->function();

    QString url = function->sourceFile();
    quint16 lineNumber = function->compiledFunction->location.line;
    quint16 columnNumber = function->compiledFunction->location.column;

    return url + QLatin1Char(':') + QString::number(lineNumber) + QLatin1Char(':') + QString::number(columnNumber);
}
Exemplo n.º 5
0
QVariant QQmlBinding::evaluate()
{
    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine);
    QV4::Scope scope(ep->v4engine());
    ep->referenceScarceResources();

    bool isUndefined = false;

    QV4::ScopedValue f(scope, v4function.value());
    QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(context(), f, &isUndefined));

    ep->dereferenceScarceResources();

    return ep->v8engine()->toVariant(result, qMetaTypeId<QList<QObject*> >());
}
Exemplo n.º 6
0
void QQmlBoundSignalExpression::evaluate(const QList<QVariant> &args)
{
    Q_ASSERT (context() && engine());

    if (!expressionFunctionValid())
        return;

    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine());
    QV4::Scope scope(ep->v4engine());

    ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.

    QV4::ScopedCallData callData(scope, args.count());
    for (int ii = 0; ii < args.count(); ++ii) {
        callData->args[ii] = scope.engine->fromVariant(args[ii]);
    }

    QQmlJavaScriptExpression::evaluate(callData, 0);

    ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
// 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.
}
Exemplo n.º 8
0
void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
{
    if (!enabledFlag() || !context() || !context()->isValid())
        return;

    // Check that the target has not been deleted
    if (QQmlData::wasDeleted(object()))
        return;

    QString url;
    quint16 lineNumber;
    quint16 columnNumber;

    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine);
    QV4::Scope scope(ep->v4engine());
    QV4::ScopedFunctionObject f(scope, v4function.value());
    Q_ASSERT(f);
    if (f->bindingKeyFlag()) {
        Q_ASSERT(f->as<QV4::QQmlBindingFunction>());
        QQmlSourceLocation loc = static_cast<QV4::QQmlBindingFunction *>(f.getPointer())->d()->bindingLocation;
        url = loc.sourceFile;
        lineNumber = loc.line;
        columnNumber = loc.column;
    } else {
        QV4::Function *function = f->asFunctionObject()->function();
        Q_ASSERT(function);

        url = function->sourceFile();
        lineNumber = function->compiledFunction->location.line;
        columnNumber = function->compiledFunction->location.column;
    }

    int lineNo = qmlSourceCoordinate(lineNumber);
    int columnNo = qmlSourceCoordinate(columnNumber);

    QQmlTrace trace("General Binding Update");
    trace.addDetail("URL", url);
    trace.addDetail("Line", lineNo);
    trace.addDetail("Column", columnNo);

    if (!updatingFlag()) {
        QQmlBindingProfiler prof(ep->profiler, url, lineNo, columnNo);
        setUpdatingFlag(true);

        QQmlAbstractExpression::DeleteWatcher watcher(this);

        if (m_core.propType == qMetaTypeId<QQmlBinding *>()) {

            int idx = m_core.coreIndex;
            Q_ASSERT(idx != -1);

            QQmlBinding *t = this;
            int status = -1;
            void *a[] = { &t, 0, &status, &flags };
            QMetaObject::metacall(*m_coreObject, QMetaObject::WriteProperty, idx, a);

        } else {
            ep->referenceScarceResources();

            bool isUndefined = false;

            QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(context(), f, &isUndefined));

            trace.event("writing binding result");

            bool needsErrorLocationData = false;
            if (!watcher.wasDeleted() && !hasError())
                needsErrorLocationData = !QQmlPropertyPrivate::writeBinding(*m_coreObject, m_core, context(),
                                                                    this, result, isUndefined, flags);

            if (!watcher.wasDeleted()) {

                if (needsErrorLocationData)
                    delayedError()->setErrorLocation(QUrl(url), lineNumber, columnNumber);

                if (hasError()) {
                    if (!delayedError()->addError(ep)) ep->warning(this->error(context()->engine));
                } else {
                    clearError();
                }

            }

            ep->dereferenceScarceResources();
        }

        if (!watcher.wasDeleted())
            setUpdatingFlag(false);
    } else {
        QQmlProperty p = property();
        QQmlAbstractBinding::printBindingLoopError(p);
    }
}
Exemplo n.º 9
0
bool QmcTypeCompiler::precompile()
{
    // QQmlTypeCompiler::compile
    // qqmltypecompiler.cpp:68
    compiledData->importCache = new QQmlTypeNameCache;

    // namespaces
    // qqmltypecompiler.cpp:72
    // qqmltypeloader.cpp:2356
    foreach (const QString &ns, compilation->namespaces) {
        compiledData->importCache->add(ns);
    }

    // TBD: qqmltypecompiler.cpp:72 namespaces, copy from QmlCompilation->namespaces

    // qqmltypecompiler.cpp:76 composite singletons
    // Add any Composite Singletons that were used to the import cache
    foreach (const QmlCompilation::TypeReference &singleton, compilation->m_compositeSingletons) {
        compiledData->importCache->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix);
    }

    compilation->importCache->populateCache(compiledData->importCache);

    // create typemap qqmltypecompiler.cpp:81
    if (!createTypeMap())
        return false;

    // qqmltypecompiler.cpp:134
    // Build property caches and VME meta object data
    if (!createPropertyCacheVmeMetaData()) {
        return false;
    }

    // default property merger
    mergeDefaultProperties();

    // convert signal handlers to functions
    if (!convertSignalHandlersToFunctions())
        return false;

    // resolve enums
    if (!resolveEnums())
        return false;

    // index custom parser scripts
    indexCustomParserScripts();

    // annotate aliases
    annotateAliases();

    // collect imported scripts
    // qqmltypecompiler.cpp:180
    // script data collection
    // 1. QQmlTypeData::continueLoadFromIR qqmltypeloader.cpp:2271 from QmlIR::Document -> QQmlTypeData::m_scripts
    // 2. QQmlTypeData::resolveTypes qqmltypeloader.cpp:2356 from QQmlImports -> QQmlTypeData::m_scripts
    // TBD: are actual script blobs needed ?
#if 0
    compiledData->scripts.reserve(compilation->scripts.count());
#endif
    for (int scriptIndex = 0; scriptIndex < compilation->scripts.count(); ++scriptIndex) {
        const QmlCompilation::ScriptReference &script = compilation->scripts.at(scriptIndex);

        QString qualifier = script.qualifier;
        QString enclosingNamespace;

        const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
        if (lastDotIndex != -1) {
            enclosingNamespace = qualifier.left(lastDotIndex);
            qualifier = qualifier.mid(lastDotIndex+1);
        }

        compiledData->importCache->add(qualifier, scriptIndex, enclosingNamespace);
#if 0
        QQmlScriptData *scriptData = script.script->scriptData();
        scriptData->addref();
        compiledData->scripts << scriptData;
#endif
    }

    // resolve component boundaries and aliases
    if (!resolveComponentBoundariesAndAliases())
        return false;

    // Compile JS binding expressions and signal handlers
    if (!compilation->document->javaScriptCompilationUnit) {
        // We can compile script strings ahead of time, but they must be compiled
        // without type optimizations as their scope is always entirely dynamic.
        scanScriptStrings();

        // TBD: check how it uses importCache
        // TBD: check how links with other scripts
        QmlIR::JSCodeGen v4CodeGenerator(compilation->urlString, compilation->document->code, &compilation->document->jsModule,
                                         &compilation->document->jsParserEngine, compilation->document->program,
                                         compiledData->importCache, &compilation->document->jsGenerator.stringTable);
        JSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
        if (!jsCodeGen.generateCodeForComponents())
            return false;

        simplifyJavaScriptBindingExpressions();

        QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(compilation->engine);
        QV4::ExecutionEngine *v4 = enginePrivate->v4engine();
        // TBD: store unlinked binaries
#if 0
        QScopedPointer<QV4::EvalInstructionSelection> isel(
                    v4->iselFactory->create(enginePrivate, v4->executableAllocator,
                                            &compilation->document->jsModule, &compilation->document->jsGenerator));
#endif
        QScopedPointer<QmcInstructionSelection> isel(
                    new QmcInstructionSelection(enginePrivate, v4->executableAllocator,
                                            &compilation->document->jsModule, &compilation->document->jsGenerator));
        isel->setUseFastLookups(false);
        compilation->document->javaScriptCompilationUnit = isel->compile(/*generated unit data*/false);
        compilation->linkData = isel->linkData();
        compilation->exceptionReturnLabels = isel->exceptionReturnLabelsData();
        compilation->exceptionPropagationJumps = isel->exceptionPropagationJumpsData();
#if CPU(ARM_THUMB2)
        compilation->jumpsToLinkData = isel->linkRecordData();
        compilation->unlinkedCodeData = isel->unlinkedCodeData();
#endif
    }

    // Generate QML compiled type data structures

    QmlIR::QmlUnitGenerator qmlGenerator;
    QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(*compilation->document);

    Q_ASSERT(compilation->document->javaScriptCompilationUnit);
    Q_ASSERT((void*)qmlUnit == (void*)&qmlUnit->header);
    // The js unit owns the data and will free the qml unit.
    compilation->document->javaScriptCompilationUnit->data = &qmlUnit->header;

    compiledData->compilationUnit = compilation->document->javaScriptCompilationUnit;
    if (compiledData->compilationUnit)
        compiledData->compilationUnit->ref();
    compiledData->qmlUnit = qmlUnit; // ownership transferred to m_compiledData

    // add to type registry
    // qqmltypecompiler.cpp:248
    if (compiledData->isCompositeType()) {
        if (compilation->singleton)
            qmlUnit->header.flags |= QV4::CompiledData::Unit::IsSingleton;
        QQmlEnginePrivate::get(compilation->engine)->registerInternalCompositeType(compiledData);
    } else {
        if (compilation->singleton) {
             qmlUnit->header.flags = qmlUnit->header.flags | QV4::CompiledData::Unit::IsSingleton;
        }

        const QV4::CompiledData::Object *obj = qmlUnit->objectAt(qmlUnit->indexOfRootObject);
        QQmlCompiledData::TypeReference *typeRef = compiledData->resolvedTypes.value(obj->inheritedTypeNameIndex);
        Q_ASSERT(typeRef);
        if (typeRef->component) {
            compiledData->metaTypeId = typeRef->component->metaTypeId;
            compiledData->listMetaTypeId = typeRef->component->listMetaTypeId;
        } else {
            compiledData->metaTypeId = typeRef->type->typeId();
            compiledData->listMetaTypeId = typeRef->type->qListTypeId();
        }
    }

    // Sanity check property bindings and compile custom parsers
    if (!validateProperties())
        return false;

    return true;
}
Exemplo n.º 10
0
int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
{
    int id = _id;
    if (c == QMetaObject::WriteProperty && interceptors &&
       !(*reinterpret_cast<int*>(a[3]) & QQmlPropertyPrivate::BypassInterceptor)) {

        for (QQmlPropertyValueInterceptor *vi = interceptors; vi; vi = vi->m_next) {
            if (vi->m_coreIndex != id)
                continue;

            int valueIndex = vi->m_valueTypeCoreIndex;
            int type = QQmlData::get(object)->propertyCache->property(id)->propType;

            if (type != QVariant::Invalid) {
                if (valueIndex != -1) {
                    QQmlValueType *valueType = QQmlValueTypeFactory::valueType(type);
                    Q_ASSERT(valueType);

                    //
                    // Consider the following case:
                    //  color c = { 0.1, 0.2, 0.3 }
                    //  interceptor exists on c.r
                    //  write { 0.2, 0.4, 0.6 }
                    //
                    // The interceptor may choose not to update the r component at this
                    // point (for example, a behavior that creates an animation). But we
                    // need to ensure that the g and b components are updated correctly.
                    //
                    // So we need to perform a full write where the value type is:
                    //    r = old value, g = new value, b = new value
                    //
                    // And then call the interceptor which may or may not write the
                    // new value to the r component.
                    //
                    // This will ensure that the other components don't contain stale data
                    // and any relevant signals are emitted.
                    //
                    // To achieve this:
                    //   (1) Store the new value type as a whole (needed due to
                    //       aliasing between a[0] and static storage in value type).
                    //   (2) Read the entire existing value type from object -> valueType temp.
                    //   (3) Read the previous value of the component being changed
                    //       from the valueType temp.
                    //   (4) Write the entire new value type into the temp.
                    //   (5) Overwrite the component being changed with the old value.
                    //   (6) Perform a full write to the value type (which may emit signals etc).
                    //   (7) Issue the interceptor call with the new component value.
                    //

                    QMetaProperty valueProp = valueType->metaObject()->property(valueIndex);
                    QVariant newValue(type, a[0]);

                    valueType->read(object, id);
                    QVariant prevComponentValue = valueProp.read(valueType);

                    valueType->setValue(newValue);
                    QVariant newComponentValue = valueProp.read(valueType);

                    // Don't apply the interceptor if the intercepted value has not changed
                    bool updated = false;
                    if (newComponentValue != prevComponentValue) {
                        valueProp.write(valueType, prevComponentValue);
                        valueType->write(object, id, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor);

                        vi->write(newComponentValue);
                        updated = true;
                    }

                    if (updated)
                        return -1;
                } else {
                    vi->write(QVariant(type, a[0]));
                    return -1;
                }
            }
        }
    }
    if (c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty) {
        if (id >= propOffset()) {
            id -= propOffset();

            if (id < metaData->propertyCount) {
               int t = (metaData->propertyData() + id)->propertyType;
                bool needActivate = false;

                if (id >= firstVarPropertyIndex) {
                    Q_ASSERT(t == QMetaType::QVariant);
                    // the context can be null if accessing var properties from cpp after re-parenting an item.
                    QQmlEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QQmlEnginePrivate::get(ctxt->engine);
                    QV8Engine *v8e = (ep == 0) ? 0 : ep->v8engine();
                    if (v8e) {
                        if (c == QMetaObject::ReadProperty) {
                            *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
                        } else if (c == QMetaObject::WriteProperty) {
                            writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
                        }
                    } else if (c == QMetaObject::ReadProperty) {
                        // if the context was disposed, we just return an invalid variant from read.
                        *reinterpret_cast<QVariant *>(a[0]) = QVariant();
                    }

                } else {

                    if (c == QMetaObject::ReadProperty) {
                        switch(t) {
                        case QVariant::Int:
                            *reinterpret_cast<int *>(a[0]) = data[id].asInt();
                            break;
                        case QVariant::Bool:
                            *reinterpret_cast<bool *>(a[0]) = data[id].asBool();
                            break;
                        case QVariant::Double:
                            *reinterpret_cast<double *>(a[0]) = data[id].asDouble();
                            break;
                        case QVariant::String:
                            *reinterpret_cast<QString *>(a[0]) = data[id].asQString();
                            break;
                        case QVariant::Url:
                            *reinterpret_cast<QUrl *>(a[0]) = data[id].asQUrl();
                            break;
                        case QVariant::Date:
                            *reinterpret_cast<QDate *>(a[0]) = data[id].asQDate();
                            break;
                        case QVariant::DateTime:
                            *reinterpret_cast<QDateTime *>(a[0]) = data[id].asQDateTime();
                            break;
                        case QVariant::RectF:
                            *reinterpret_cast<QRectF *>(a[0]) = data[id].asQRectF();
                            break;
                        case QVariant::SizeF:
                            *reinterpret_cast<QSizeF *>(a[0]) = data[id].asQSizeF();
                            break;
                        case QVariant::PointF:
                            *reinterpret_cast<QPointF *>(a[0]) = data[id].asQPointF();
                            break;
                        case QMetaType::QObjectStar:
                            *reinterpret_cast<QObject **>(a[0]) = data[id].asQObject();
                            break;
                        case QMetaType::QVariant:
                            *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
                            break;
                        default:
                            QQml_valueTypeProvider()->readValueType(data[id].dataType(), data[id].dataPtr(), data->dataSize(), t, a[0]);
                            break;
                        }
                        if (t == qMetaTypeId<QQmlListProperty<QObject> >()) {
                            int listIndex = data[id].asInt();
                            const List *list = &listProperties.at(listIndex);
                            *reinterpret_cast<QQmlListProperty<QObject> *>(a[0]) =
                                QQmlListProperty<QObject>(object, (void *)list,
                                                                  list_append, list_count, list_at,
                                                                  list_clear);
                        }

                    } else if (c == QMetaObject::WriteProperty) {

                        switch(t) {
                        case QVariant::Int:
                            needActivate = *reinterpret_cast<int *>(a[0]) != data[id].asInt();
                            data[id].setValue(*reinterpret_cast<int *>(a[0]));
                            break;
                        case QVariant::Bool:
                            needActivate = *reinterpret_cast<bool *>(a[0]) != data[id].asBool();
                            data[id].setValue(*reinterpret_cast<bool *>(a[0]));
                            break;
                        case QVariant::Double:
                            needActivate = *reinterpret_cast<double *>(a[0]) != data[id].asDouble();
                            data[id].setValue(*reinterpret_cast<double *>(a[0]));
                            break;
                        case QVariant::String:
                            needActivate = *reinterpret_cast<QString *>(a[0]) != data[id].asQString();
                            data[id].setValue(*reinterpret_cast<QString *>(a[0]));
                            break;
                        case QVariant::Url:
                            needActivate = *reinterpret_cast<QUrl *>(a[0]) != data[id].asQUrl();
                            data[id].setValue(*reinterpret_cast<QUrl *>(a[0]));
                            break;
                        case QVariant::Date:
                            needActivate = *reinterpret_cast<QDate *>(a[0]) != data[id].asQDate();
                            data[id].setValue(*reinterpret_cast<QDate *>(a[0]));
                            break;
                        case QVariant::DateTime:
                            needActivate = *reinterpret_cast<QDateTime *>(a[0]) != data[id].asQDateTime();
                            data[id].setValue(*reinterpret_cast<QDateTime *>(a[0]));
                            break;
                        case QVariant::RectF:
                            needActivate = *reinterpret_cast<QRectF *>(a[0]) != data[id].asQRectF();
                            data[id].setValue(*reinterpret_cast<QRectF *>(a[0]));
                            break;
                        case QVariant::SizeF:
                            needActivate = *reinterpret_cast<QSizeF *>(a[0]) != data[id].asQSizeF();
                            data[id].setValue(*reinterpret_cast<QSizeF *>(a[0]));
                            break;
                        case QVariant::PointF:
                            needActivate = *reinterpret_cast<QPointF *>(a[0]) != data[id].asQPointF();
                            data[id].setValue(*reinterpret_cast<QPointF *>(a[0]));
                            break;
                        case QMetaType::QObjectStar:
                            needActivate = *reinterpret_cast<QObject **>(a[0]) != data[id].asQObject();
                            data[id].setValue(*reinterpret_cast<QObject **>(a[0]), this, id);
                            break;
                        case QMetaType::QVariant:
                            writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
                            break;
                        default:
                            data[id].ensureValueType(t);
                            needActivate = !QQml_valueTypeProvider()->equalValueType(t, a[0], data[id].dataPtr(), data[id].dataSize());
                            QQml_valueTypeProvider()->writeValueType(t, a[0], data[id].dataPtr(), data[id].dataSize());
                            break;
                        }
                    }

                }

                if (c == QMetaObject::WriteProperty && needActivate) {
                    activate(object, methodOffset() + id, 0);
                }

                return -1;
            }

            id -= metaData->propertyCount;

            if (id < metaData->aliasCount) {

                QQmlVMEMetaData::AliasData *d = metaData->aliasData() + id;

                if (d->flags & QML_ALIAS_FLAG_PTR && c == QMetaObject::ReadProperty)
                        *reinterpret_cast<void **>(a[0]) = 0;

                if (!ctxt) return -1;

                QQmlContext *context = ctxt->asQQmlContext();
                QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context);

                QObject *target = ctxtPriv->data->idValues[d->contextIdx].data();
                if (!target)
                    return -1;

                connectAlias(id);

                if (d->isObjectAlias()) {
                    *reinterpret_cast<QObject **>(a[0]) = target;
                    return -1;
                }

                // Remove binding (if any) on write
                if(c == QMetaObject::WriteProperty) {
                    int flags = *reinterpret_cast<int*>(a[3]);
                    if (flags & QQmlPropertyPrivate::RemoveBindingOnAliasWrite) {
                        QQmlData *targetData = QQmlData::get(target);
                        if (targetData && targetData->hasBindingBit(d->propertyIndex())) {
                            QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(target, d->propertyIndex(), d->isValueTypeAlias()?d->valueTypeIndex():-1, 0);
                            if (binding) binding->destroy();
                        }
                    }
                }

                if (d->isValueTypeAlias()) {
                    // Value type property
                    QQmlValueType *valueType = QQmlValueTypeFactory::valueType(d->valueType());
                    Q_ASSERT(valueType);

                    valueType->read(target, d->propertyIndex());
                    int rv = QMetaObject::metacall(valueType, c, d->valueTypeIndex(), a);

                    if (c == QMetaObject::WriteProperty)
                        valueType->write(target, d->propertyIndex(), 0x00);

                    return rv;

                } else {
                    return QMetaObject::metacall(target, c, d->propertyIndex(), a);
                }

            }
            return -1;

        }

    } else if(c == QMetaObject::InvokeMetaMethod) {

        if (id >= methodOffset()) {

            id -= methodOffset();
            int plainSignals = metaData->signalCount + metaData->propertyCount +
                               metaData->aliasCount;
            if (id < plainSignals) {
                activate(object, _id, a);
                return -1;
            }

            id -= plainSignals;

            if (id < metaData->methodCount) {
                if (!ctxt->engine)
                    return -1; // We can't run the method

                QQmlEnginePrivate *ep = QQmlEnginePrivate::get(ctxt->engine);
                ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
                QV4::Scope scope(ep->v4engine());


                QV4::Scoped<QV4::FunctionObject> function(scope, method(id));
                if (!function) {
                    // The function was not compiled.  There are some exceptional cases which the
                    // expression rewriter does not rewrite properly (e.g., \r-terminated lines
                    // are not rewritten correctly but this bug is deemed out-of-scope to fix for
                    // performance reasons; see QTBUG-24064) and thus compilation will have failed.
                    QQmlError e;
                    e.setDescription(QString(QLatin1String("Exception occurred during compilation of function: %1")).
                                     arg(QLatin1String(QMetaObject::method(_id).methodSignature().constData())));
                    ep->warning(e);
                    return -1; // The dynamic method with that id is not available.
                }

                QQmlVMEMetaData::MethodData *data = metaData->methodData() + id;

                QV4::ScopedCallData callData(scope, data->parameterCount);
                callData->thisObject = ep->v8engine()->global();

                for (int ii = 0; ii < data->parameterCount; ++ii)
                    callData->args[ii] = ep->v8engine()->fromVariant(*(QVariant *)a[ii + 1]);

                QV4::ScopedValue result(scope);
                QV4::ExecutionContext *ctx = function->engine()->currentContext();
                result = function->call(callData);
                if (scope.hasException()) {
                    QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx);
                    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);
                }

                ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
                return -1;
            }
            return -1;
        }
    }

    if (parent.isT1())
        return parent.asT1()->metaCall(object, c, _id, a);
    else
        return object->qt_metacall(c, _id, a);
}
Exemplo n.º 11
0
void QQmlVMEMetaObject::ensureQObjectWrapper()
{
    QQmlEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QQmlEnginePrivate::get(ctxt->engine);
    QV4::ExecutionEngine *v4 = (ep == 0) ? 0 : ep->v4engine();
    QV4::QObjectWrapper::wrap(v4, object);
}