diff options
Diffstat (limited to 'src/qml/qml')
26 files changed, 516 insertions, 859 deletions
diff --git a/src/qml/qml/ftw/qfastmetabuilder.cpp b/src/qml/qml/ftw/qfastmetabuilder.cpp index 08ea76b37e..9d956054d9 100644 --- a/src/qml/qml/ftw/qfastmetabuilder.cpp +++ b/src/qml/qml/ftw/qfastmetabuilder.cpp @@ -79,7 +79,8 @@ static inline const QFastMetaBuilderHeader *header(const QByteArray &data) { return reinterpret_cast<const QFastMetaBuilderHeader*>(data.constData()); } QFastMetaBuilder::QFastMetaBuilder() -: m_zeroPtr(0), m_stringData(0), m_stringDataLength(0), m_stringDataAllocated(0) + : m_stringData(0), m_stringCount(0), m_stringDataLength(0), + m_stringCountAllocated(0), m_stringCountLoaded(0) { } @@ -89,7 +90,8 @@ QFastMetaBuilder::~QFastMetaBuilder() QFastMetaBuilder::StringRef QFastMetaBuilder::init(int classNameLength, int propertyCount, int methodCount, - int signalCount, int classInfoCount) + int signalCount, int classInfoCount, + int paramDataSize, int *paramIndex) { Q_ASSERT(m_data.isEmpty()); Q_ASSERT(classNameLength > 0); @@ -97,20 +99,29 @@ QFastMetaBuilder::StringRef QFastMetaBuilder::init(int classNameLength, Q_ASSERT(methodCount >= 0); Q_ASSERT(signalCount >= 0); Q_ASSERT(classInfoCount >= 0); + Q_ASSERT(paramDataSize >= 0); + Q_ASSERT((paramIndex != 0) || (methodCount + signalCount == 0)); int fieldCount = FMBHEADER_FIELD_COUNT + HEADER_FIELD_COUNT + propertyCount * (PROPERTY_FIELD_COUNT + PROPERTY_NOTIFY_FIELD_COUNT) + methodCount * (METHOD_FIELD_COUNT) + signalCount * (METHOD_FIELD_COUNT) + + paramDataSize + classInfoCount * CLASSINFO_FIELD_COUNT; + // Ensure stringdata alignment (void*) + fieldCount += fieldCount % (sizeof(void*) / sizeof(uint)); - m_data.resize(fieldCount * sizeof(uint) + classNameLength + 1); - m_stringData = m_data.data() + m_data.size() - classNameLength - 1; + m_stringCount = 2; // class name and zero string m_stringDataLength = classNameLength + 1; - m_stringDataAllocated = classNameLength + 1; - m_stringData[classNameLength] = 0; - m_zeroPtr = classNameLength; + m_data.resize(fieldCount * sizeof(uint) + m_stringCount * sizeof(QByteArrayData) + m_stringDataLength); + m_stringCountAllocated = m_stringCount; + m_stringData = reinterpret_cast<QByteArrayData *>(m_data.data() + fieldCount * sizeof(uint)); + + m_zeroString._b = this; + m_zeroString._i = 1; + m_zeroString._o = classNameLength; + m_zeroString._l = 0; header(m_data)->fieldCount = fieldCount; @@ -118,7 +129,7 @@ QFastMetaBuilder::StringRef QFastMetaBuilder::init(int classNameLength, int dataIndex = HEADER_FIELD_COUNT; - p->revision = 6; + p->revision = 7; p->className = 0; // Class infos @@ -135,6 +146,8 @@ QFastMetaBuilder::StringRef QFastMetaBuilder::init(int classNameLength, if (p->methodCount) { p->methodData = dataIndex; dataIndex += p->methodCount * METHOD_FIELD_COUNT; + *paramIndex = dataIndex; + dataIndex += paramDataSize; } else { p->methodData = 0; } @@ -160,6 +173,7 @@ QFastMetaBuilder::StringRef QFastMetaBuilder::init(int classNameLength, StringRef className; className._b = this; + className._i = 0; className._o = 0; className._l = classNameLength; return className; @@ -169,12 +183,16 @@ QFastMetaBuilder::StringRef QFastMetaBuilder::init(int classNameLength, QFastMetaBuilder::StringRef QFastMetaBuilder::newString(int length) { Q_ASSERT(length > 0); + Q_ASSERT_X(m_stringCountLoaded == 0, Q_FUNC_INFO, + "All strings must be created before string loading begins"); StringRef sr; sr._b = this; + sr._i = m_stringCount; sr._o = m_stringDataLength; sr._l = length; + ++m_stringCount; m_stringDataLength += length + 1 /* for null terminator */; return sr; @@ -190,47 +208,24 @@ void QFastMetaBuilder::setClassInfo(int index, const StringRef &key, const Strin uint *ptr = fieldPointer(m_data) + p->classInfoData + index * CLASSINFO_FIELD_COUNT; // classinfo: key, value - ptr[0] = key.offset(); ptr[1] = value.offset(); + ptr[0] = key.index(); ptr[1] = value.index(); } -void QFastMetaBuilder::setProperty(int index, const StringRef &name, const StringRef &type, - QMetaType::Type mtype, PropertyFlag flags, int notifySignal) +void QFastMetaBuilder::setProperty(int index, const StringRef &name, int type, + PropertyFlag flags, int notifySignal) { Q_ASSERT(!m_data.isEmpty()); Q_ASSERT(!name.isEmpty()); - Q_ASSERT(!type.isEmpty()); - - QMetaObjectPrivate *p = priv(m_data); - Q_ASSERT(index < p->propertyCount); - - uint *ptr = fieldPointer(m_data) + p->propertyData + index * PROPERTY_FIELD_COUNT; - // properties: name, type, flags - ptr[0] = name.offset(); - ptr[1] = type.offset(); - if (notifySignal == -1) { - ptr[2] = mtype << 24; - ptr[2] |= flags | Scriptable | Readable; - *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = 0; - } else { - ptr[2] = mtype << 24; - ptr[2] |= flags | Scriptable | Readable | Notify; - *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = notifySignal; - } -} - -void QFastMetaBuilder::setProperty(int index, const StringRef &name, const StringRef &type, - QFastMetaBuilder::PropertyFlag flags, int notifySignal) -{ - Q_ASSERT(!m_data.isEmpty()); - Q_ASSERT(!name.isEmpty() && !type.isEmpty()); + Q_ASSERT(type != 0); + Q_ASSERT(QMetaType::isRegistered(type)); QMetaObjectPrivate *p = priv(m_data); Q_ASSERT(index < p->propertyCount); uint *ptr = fieldPointer(m_data) + p->propertyData + index * PROPERTY_FIELD_COUNT; // properties: name, type, flags - ptr[0] = name.offset(); - ptr[1] = type.offset(); + ptr[0] = name.index(); + ptr[1] = type; if (notifySignal == -1) { ptr[2] = flags | Scriptable | Readable; *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = 0; @@ -240,42 +235,72 @@ void QFastMetaBuilder::setProperty(int index, const StringRef &name, const Strin } } -void QFastMetaBuilder::setSignal(int index, const StringRef &signature, - const StringRef ¶meterNames, - const StringRef &type) +void QFastMetaBuilder::setSignal(int index, const StringRef &name, + int paramIndex, int argc, const int *types, + const StringRef *parameterNames, + QMetaType::Type type) { Q_ASSERT(!m_data.isEmpty()); - Q_ASSERT(!signature.isEmpty()); + Q_ASSERT(!name.isEmpty()); + Q_ASSERT(QMetaType::isRegistered(type)); QMetaObjectPrivate *p = priv(m_data); int mindex = metaObjectIndexForSignal(index); uint *ptr = fieldPointer(m_data) + p->methodData + mindex * METHOD_FIELD_COUNT; - // methods: signature, parameters, type, tag, flags - ptr[0] = signature.offset(); - ptr[1] = parameterNames.isEmpty()?m_zeroPtr:parameterNames.offset(); - ptr[2] = type.isEmpty()?m_zeroPtr:type.offset(); - ptr[3] = m_zeroPtr; + // methods: name, arc, parameters, tag, flags + ptr[0] = name.index(); + ptr[1] = argc; + ptr[2] = paramIndex; + ptr[3] = m_zeroString.index(); ptr[4] = AccessProtected | MethodSignal; + + uint *paramPtr = fieldPointer(m_data) + paramIndex; + paramPtr[0] = type; + if (argc) { + Q_ASSERT(types != 0); + Q_ASSERT(parameterNames != 0); + for (int i = 0; i < argc; ++i) { + Q_ASSERT(types[i] != 0); + Q_ASSERT(QMetaType::isRegistered(types[i])); + paramPtr[1+i] = types[i]; + paramPtr[1+argc+i] = parameterNames[i].index(); + } + } } -void QFastMetaBuilder::setMethod(int index, const StringRef &signature, - const StringRef ¶meterNames, - const StringRef &type) +void QFastMetaBuilder::setMethod(int index, const StringRef &name, + int paramIndex, int argc, const int *types, + const StringRef *parameterNames, + QMetaType::Type type) { Q_ASSERT(!m_data.isEmpty()); - Q_ASSERT(!signature.isEmpty()); + Q_ASSERT(!name.isEmpty()); + Q_ASSERT(QMetaType::isRegistered(type)); QMetaObjectPrivate *p = priv(m_data); int mindex = metaObjectIndexForMethod(index); uint *ptr = fieldPointer(m_data) + p->methodData + mindex * METHOD_FIELD_COUNT; - // methods: signature, parameters, type, tag, flags - ptr[0] = signature.offset(); - ptr[1] = parameterNames.isEmpty()?m_zeroPtr:parameterNames.offset(); - ptr[2] = type.isEmpty()?m_zeroPtr:type.offset(); - ptr[3] = m_zeroPtr; + // methods: name, arc, parameters, tag, flags + ptr[0] = name.index(); + ptr[1] = argc; + ptr[2] = paramIndex; + ptr[3] = m_zeroString.index(); ptr[4] = AccessProtected | MethodSlot; + + uint *paramPtr = fieldPointer(m_data) + paramIndex; + paramPtr[0] = type; + if (argc) { + Q_ASSERT(types != 0); + Q_ASSERT(parameterNames != 0); + for (int i = 0; i < argc; ++i) { + Q_ASSERT(types[i] != 0); + Q_ASSERT(QMetaType::isRegistered(types[i])); + paramPtr[1+i] = types[i]; + paramPtr[1+argc+i] = parameterNames[i].index(); + } + } } int QFastMetaBuilder::metaObjectIndexForSignal(int index) const @@ -296,17 +321,19 @@ int QFastMetaBuilder::metaObjectIndexForMethod(int index) const void QFastMetaBuilder::allocateStringData() { - if (m_stringDataAllocated < m_stringDataLength) { - m_data.resize(m_data.size() + m_stringDataLength - m_stringDataAllocated); - m_stringDataAllocated = m_stringDataLength; - m_stringData = m_data.data() + header(m_data)->fieldCount * sizeof(uint); + if (m_stringCountAllocated < m_stringCount) { + m_data.resize(header(m_data)->fieldCount * sizeof(uint) + + m_stringCount * sizeof(QByteArrayData) + m_stringDataLength); + m_stringCountAllocated = m_stringCount; + char *rawStringData = m_data.data() + header(m_data)->fieldCount * sizeof(uint); + m_stringData = reinterpret_cast<QByteArrayData *>(rawStringData); } } void QFastMetaBuilder::fromData(QMetaObject *output, const QMetaObject *parent, const QByteArray &data) { output->d.superdata = parent; - output->d.stringdata = data.constData() + header(data)->fieldCount * sizeof(uint); + output->d.stringdata = reinterpret_cast<const QByteArrayData *>(data.constData() + header(data)->fieldCount * sizeof(uint)); output->d.data = fieldPointer(data); output->d.extradata = 0; } diff --git a/src/qml/qml/ftw/qfastmetabuilder_p.h b/src/qml/qml/ftw/qfastmetabuilder_p.h index c1f6a3de5c..16f7b6e749 100644 --- a/src/qml/qml/ftw/qfastmetabuilder_p.h +++ b/src/qml/qml/ftw/qfastmetabuilder_p.h @@ -80,13 +80,15 @@ public: inline bool isEmpty() const; inline QFastMetaBuilder *builder() const; - inline int offset() const; + inline int index() const; inline char *data(); inline int length() const; + inline void loadByteArrayData(); private: friend class QFastMetaBuilder; QFastMetaBuilder *_b; + int _i; int _o; int _l; }; @@ -95,7 +97,8 @@ public: // Returns class name StringRef init(int classNameLength, int propertyCount, int methodCount, - int signalCount, int classInfoCount); + int signalCount, int classInfoCount, + int paramDataSize, int *paramIndex); void setClassInfo(int index, const StringRef &key, const StringRef &value); @@ -106,48 +109,55 @@ public: Constant = 0x00000400, Final = 0x00000800 }; - // void setProperty(int index, const StringRef &name, QMetaType::Type type, int notifySignal = -1); - void setProperty(int index, const StringRef &name, const StringRef &type, - QMetaType::Type mtype, PropertyFlag flags, int notifySignal = -1); - void setProperty(int index, const StringRef &name, const StringRef &type, + void setProperty(int index, const StringRef &name, int type, PropertyFlag flags, int notifySignal = -1); - void setMethod(int index, const StringRef &signature, - const StringRef ¶meterNames = StringRef(), - const StringRef &type = StringRef()); - void setSignal(int index, const StringRef &signature, - const StringRef ¶meterNames = StringRef(), - const StringRef &type = StringRef()); + void setMethod(int index, const StringRef &name, int paramIndex, int argc = 0, + const int *types = 0, const StringRef *parameterNames = 0, + QMetaType::Type type = QMetaType::Void); + void setSignal(int index, const StringRef &name, int paramIndex, int argc = 0, + const int *types = 0, const StringRef *parameterNames = 0, + QMetaType::Type type = QMetaType::Void); int metaObjectIndexForSignal(int) const; int metaObjectIndexForMethod(int) const; - QByteArray toData() const { return m_data; } + QByteArray toData() const { + if (m_stringCountLoaded == m_stringCount - 1) { + // zero-string is lazily loaded last + const_cast<StringRef &>(m_zeroString).loadByteArrayData(); + } + Q_ASSERT(m_stringCountLoaded == m_stringCount); + return m_data; + } static void fromData(QMetaObject *, const QMetaObject *parent, const QByteArray &); private: friend struct StringRef; QByteArray m_data; - int m_zeroPtr; + StringRef m_zeroString; void allocateStringData(); - char *m_stringData; + QByteArrayData *m_stringData; + int m_stringCount; int m_stringDataLength; - int m_stringDataAllocated; + int m_stringCountAllocated; + int m_stringCountLoaded; }; QFastMetaBuilder::StringRef::StringRef() -: _b(0), _o(0), _l(0) +: _b(0), _i(0), _o(0), _l(0) { } QFastMetaBuilder::StringRef::StringRef(const StringRef &o) -: _b(o._b), _o(o._o), _l(o._l) +: _b(o._b), _i(o._i), _o(o._o), _l(o._l) { } QFastMetaBuilder::StringRef &QFastMetaBuilder::StringRef::operator=(const StringRef &o) { _b = o._b; + _i = o._i; _o = o._o; _l = o._l; return *this; @@ -163,17 +173,17 @@ QFastMetaBuilder *QFastMetaBuilder::StringRef::builder() const return _b; } -int QFastMetaBuilder::StringRef::offset() const +int QFastMetaBuilder::StringRef::index() const { - return _o; + return _i; } char *QFastMetaBuilder::StringRef::data() { Q_ASSERT(_b); - if (_b->m_stringDataLength != _b->m_stringDataAllocated) - _b->allocateStringData(); - return _b->m_stringData + _o; + if (_b->m_stringCountAllocated < _b->m_stringCount) + _b->allocateStringData(); + return reinterpret_cast<char *>(&_b->m_stringData[_b->m_stringCount]) + _o; } int QFastMetaBuilder::StringRef::length() const @@ -186,18 +196,36 @@ void QFastMetaBuilder::StringRef::load(const QHashedStringRef &str) Q_ASSERT(str.utf8length() == _l); str.writeUtf8(data()); *(data() + _l) = 0; + loadByteArrayData(); } void QFastMetaBuilder::StringRef::load(const QByteArray &str) { Q_ASSERT(str.length() == _l); strcpy(data(), str.constData()); + loadByteArrayData(); } void QFastMetaBuilder::StringRef::load(const char *str) { Q_ASSERT(strlen(str) == (uint)_l); strcpy(data(), str); + loadByteArrayData(); +} + +void QFastMetaBuilder::StringRef::loadByteArrayData() +{ + if (_b->m_stringCountAllocated < _b->m_stringCount) + _b->allocateStringData(); + Q_ASSERT(_b->m_stringCountLoaded < _b->m_stringCount); + + int offsetofCstrings = _b->m_stringCount * sizeof(QByteArrayData); + qptrdiff offset = offsetofCstrings + _o - _i * sizeof(QByteArrayData); + + const QByteArrayData bad = { Q_REFCOUNT_INITIALIZE_STATIC, _l, 0, 0, offset }; + memcpy(&_b->m_stringData[_i], &bad, sizeof(QByteArrayData)); + + ++_b->m_stringCountLoaded; } QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qqmlpool_p.h b/src/qml/qml/ftw/qqmlpool_p.h index e4fa03ce34..8e8f367890 100644 --- a/src/qml/qml/ftw/qqmlpool_p.h +++ b/src/qml/qml/ftw/qqmlpool_p.h @@ -132,6 +132,7 @@ public: Q_ASSERT(index < m_length); return m_data[index]; }; + const T *data() const { return m_data; } private: friend class QQmlPool; List(T *d, int l) : m_length(l), m_data(d) {} diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri index c75e4c9681..5d26197b1c 100644 --- a/src/qml/qml/qml.pri +++ b/src/qml/qml/qml.pri @@ -40,7 +40,6 @@ SOURCES += \ $$PWD/qqmltypenamecache.cpp \ $$PWD/qqmlscriptstring.cpp \ $$PWD/qquickworkerscript.cpp \ - $$PWD/qqmlimageprovider.cpp \ $$PWD/qqmlnetworkaccessmanagerfactory.cpp \ $$PWD/qqmldirparser.cpp \ $$PWD/qqmlextensionplugin.cpp \ @@ -109,7 +108,6 @@ HEADERS += \ $$PWD/qqmlscriptstring.h \ $$PWD/qquickworkerscript_p.h \ $$PWD/qqmlguard_p.h \ - $$PWD/qqmlimageprovider.h \ $$PWD/qqmlnetworkaccessmanagerfactory.h \ $$PWD/qqmldirparser_p.h \ $$PWD/qqmlextensioninterface.h \ diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index ca6b13e7f8..aa130d9493 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -172,11 +172,11 @@ int QQmlBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a) return -1; if (QQmlDebugService::isDebuggingEnabled()) - QV8DebugService::instance()->signalEmitted(QString::fromAscii(m_signal.signature())); + QV8DebugService::instance()->signalEmitted(QString::fromAscii(m_signal.methodSignature().constData())); QQmlHandlingSignalProfiler prof; if (prof.enabled) { - prof.setSignalInfo(QString::fromLatin1(m_signal.signature()), + prof.setSignalInfo(QString::fromLatin1(m_signal.methodSignature().constData()), m_expression->expression()); prof.setLocation(m_expression->sourceFile(), m_expression->lineNumber(), m_expression->columnNumber()); @@ -226,14 +226,14 @@ QQmlBoundSignalParameters::QQmlBoundSignalParameters(const QMetaMethod &method, continue; } - QVariant::Type t = (QVariant::Type)QMetaType::type(type.constData()); + int t = QMetaType::type(type.constData()); if (QQmlMetaType::isQObject(t)) { types[ii] = QMetaType::QObjectStar; QMetaPropertyBuilder prop = mob.addProperty(name, "QObject*"); prop.setWritable(false); } else { QByteArray propType = type; - if (t >= QVariant::UserType || t == QVariant::Invalid) { + if (t >= int(QVariant::UserType) || t == QMetaType::UnknownType || t == QMetaType::Void) { QByteArray scope; QByteArray name; int scopeIdx = propType.lastIndexOf("::"); diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index 9304a75fbf..51343b64d5 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -71,6 +71,7 @@ #include <QAtomicInt> #include <QtCore/qdebug.h> #include <QtCore/qdatetime.h> +#include <QtCore/qvarlengtharray.h> Q_DECLARE_METATYPE(QList<int>) Q_DECLARE_METATYPE(QList<qreal>) @@ -2830,32 +2831,37 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod } } + // Size of the array that describes parameter types & names + int paramDataSize = (obj->aggregateDynamicSignalParameterCount() + obj->aggregateDynamicSlotParameterCount()) * 2 + + obj->dynamicProperties.count() // for Changed() signals return types + // Return "parameters" don't have names + - (obj->dynamicSignals.count() + obj->dynamicSlots.count()); + QFastMetaBuilder builder; + int paramIndex; QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(), obj->dynamicProperties.count() - (resolveAlias?0:aliasCount), obj->dynamicSlots.count(), obj->dynamicSignals.count() + obj->dynamicProperties.count(), - defaultProperty?1:0); + defaultProperty?1:0, paramDataSize, ¶mIndex); struct TypeData { Object::DynamicProperty::Type dtype; int metaType; - const char *cppType; } builtinTypes[] = { - { Object::DynamicProperty::Var, QMetaType::QVariant, "QVariant" }, - { Object::DynamicProperty::Variant, QMetaType::QVariant, "QVariant" }, - { Object::DynamicProperty::Int, QMetaType::Int, "int" }, - { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" }, - { Object::DynamicProperty::Real, QMetaType::Double, "double" }, - { Object::DynamicProperty::String, QMetaType::QString, "QString" }, - { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" }, - { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" }, - { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" }, - { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" }, - { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" }, + { Object::DynamicProperty::Var, QMetaType::QVariant }, + { Object::DynamicProperty::Variant, QMetaType::QVariant }, + { Object::DynamicProperty::Int, QMetaType::Int }, + { Object::DynamicProperty::Bool, QMetaType::Bool }, + { Object::DynamicProperty::Real, QMetaType::Double }, + { Object::DynamicProperty::String, QMetaType::QString }, + { Object::DynamicProperty::Url, QMetaType::QUrl }, + { Object::DynamicProperty::Color, QMetaType::QColor }, + { Object::DynamicProperty::Time, QMetaType::QTime }, + { Object::DynamicProperty::Date, QMetaType::QDate }, + { Object::DynamicProperty::DateTime, QMetaType::QDateTime }, }; static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData); - QFastMetaBuilder::StringRef typeRefs[builtinTypeCount]; // Reserve dynamic properties if (obj->dynamicProperties.count()) { @@ -2868,18 +2874,16 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod if (p->type != Object::DynamicProperty::Alias || resolveAlias) p->nameRef = builder.newString(p->name.utf8length()); - int propertyType = 0; + int metaType = 0; + int propertyType = 0; // for VMD bool readonly = false; - QFastMetaBuilder::StringRef typeRef; if (p->type == Object::DynamicProperty::Alias) { continue; } else if (p->type < builtinTypeCount) { Q_ASSERT(builtinTypes[p->type].dtype == p->type); - propertyType = builtinTypes[p->type].metaType; - if (typeRefs[p->type].isEmpty()) - typeRefs[p->type] = builder.newString(strlen(builtinTypes[p->type].cppType)); - typeRef = typeRefs[p->type]; + metaType = builtinTypes[p->type].metaType; + propertyType = metaType; } else { Q_ASSERT(p->type == Object::DynamicProperty::CustomList || @@ -2915,9 +2919,9 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod propertyType = qMetaTypeId<QQmlListProperty<QObject> >(); } - p->resolvedCustomTypeName = pool->NewByteArray(customTypeName); - p->typeRef = builder.newString(customTypeName.length()); - typeRef = p->typeRef; + metaType = QMetaType::type(customTypeName); + Q_ASSERT(metaType != QMetaType::UnknownType); + Q_ASSERT(metaType != QMetaType::Void); } if (p->type == Object::DynamicProperty::Var) @@ -2932,17 +2936,13 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType; } - if (p->type < builtinTypeCount) - builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)propertyType, - readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, - effectivePropertyIndex); - else - builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, - readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, - effectivePropertyIndex); + builder.setProperty(effectivePropertyIndex, p->nameRef, metaType, + readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, + effectivePropertyIndex); - p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()")); - builder.setSignal(effectivePropertyIndex, p->changedSignatureRef); + p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed")); + builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex); + paramIndex++; effectivePropertyIndex++; } @@ -2955,19 +2955,19 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod totalPropCount = varPropCount + effectivePropertyIndex; for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { if (p->type == Object::DynamicProperty::Var) { - QFastMetaBuilder::StringRef typeRef = typeRefs[p->type]; if (buildData) { vmd->propertyCount++; (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant; } - builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, + builder.setProperty(effectivePropertyIndex, p->nameRef, QMetaType::QVariant, p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, effectivePropertyIndex); - p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()")); - builder.setSignal(effectivePropertyIndex, p->changedSignatureRef); + p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed")); + builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex); + paramIndex++; effectivePropertyIndex++; } @@ -2986,8 +2986,9 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod } // Even if we aren't resolving the alias, we need a fake signal so that the // metaobject remains consistent across the resolve and non-resolve alias runs - p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()")); - builder.setSignal(effectivePropertyIndex, p->changedSignatureRef); + p->changedNameRef = builder.newString(p->name.utf8length() + strlen("Changed")); + builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex); + paramIndex++; effectivePropertyIndex++; aliasIndex++; } @@ -3006,49 +3007,56 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod int signalIndex = 0; for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) { - int paramCount = s->parameterNames.count(); - - int signatureSize = s->name.utf8length() + 2 /* paren */; - int namesSize = 0; - if (paramCount) signatureSize += s->parameterTypesLength() + (paramCount - 1) /* commas */; - if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1) /* commas */; + s->nameRef = builder.newString(s->name.utf8length()); - s->signatureRef = builder.newString(signatureSize); - if (namesSize) s->parameterNamesRef = builder.newString(namesSize); + int paramCount = s->parameterNames.count(); + QVarLengthArray<int, 10> paramTypes(paramCount); + if (paramCount) { + s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount); + for (int i = 0; i < paramCount; ++i) { + s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).utf8length()); + Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount); + paramTypes[i] = builtinTypes[s->parameterTypes.at(i)].metaType; + } + } if (buildData) ((QQmlVMEMetaData *)dynamicData.data())->signalCount++; - builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->signatureRef, s->parameterNamesRef); + builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->nameRef, + paramIndex, paramCount, paramTypes.constData(), s->parameterNamesRef.data()); + paramIndex += paramCount*2 + 1; ++signalIndex; } // Reserve dynamic slots if (obj->dynamicSlots.count()) { - // Allocate QVariant string - if (typeRefs[0].isEmpty()) - typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType)); - typedef QQmlVMEMetaData VMD; int methodIndex = 0; for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { + s->nameRef = builder.newString(s->name.utf8length()); int paramCount = s->parameterNames.count(); - int signatureSize = s->name.utf8length() + 2 /* paren */; - int namesSize = 0; - if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1)); - if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */); - - s->signatureRef = builder.newString(signatureSize); - if (namesSize) s->parameterNamesRef = builder.newString(namesSize); + QVarLengthArray<int, 10> paramTypes(paramCount); + if (paramCount) { + s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount); + for (int i = 0; i < paramCount; ++i) { + s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).size()); + paramTypes[i] = QMetaType::QVariant; + } + } - builder.setMethod(methodIndex, s->signatureRef, s->parameterNamesRef, typeRefs[0]); + builder.setMethod(methodIndex, s->nameRef, paramIndex, paramCount, + paramTypes.constData(), s->parameterNamesRef.data(), QMetaType::QVariant); + paramIndex += paramCount*2 + 1; if (buildData) { QString funcScript; - funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ + + int namesSize = 0; + if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */); + funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ + namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */); funcScript = QLatin1String("(function ") + s->name.toString() + QLatin1Char('('); for (int jj = 0; jj < paramCount; ++jj) { @@ -3077,28 +3085,18 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod } } - // Now allocate used builtin types - for (int ii = 0; ii < builtinTypeCount; ++ii) { - if (!typeRefs[ii].isEmpty()) - typeRefs[ii].load(builtinTypes[ii].cppType); - } - // Now allocate properties for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { - char *d = p->changedSignatureRef.data(); + char *d = p->changedNameRef.data(); p->name.writeUtf8(d); - strcpy(d + p->name.utf8length(), "Changed()"); + strcpy(d + p->name.utf8length(), "Changed"); + p->changedNameRef.loadByteArrayData(); if (p->type == Object::DynamicProperty::Alias && !resolveAlias) continue; p->nameRef.load(p->name); - - if (p->type >= builtinTypeCount) { - Q_ASSERT(p->resolvedCustomTypeName); - p->typeRef.load(*p->resolvedCustomTypeName); - } } // Allocate default property if necessary @@ -3108,39 +3106,18 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod // Now allocate signals for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) { - char *d = s->signatureRef.data(); - char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data(); - s->name.writeUtf8(d); d += s->name.utf8length(); - *d++ = '('; + s->nameRef.load(s->name); - for (int jj = 0; jj < s->parameterNames.count(); ++jj) { - if (jj != 0) { *d++ = ','; *d2++ = ','; } - strcpy(d, s->parameterTypes.at(jj).constData()); - d += s->parameterTypes.at(jj).length(); - s->parameterNames.at(jj).writeUtf8(d2); - d2 += s->parameterNames.at(jj).utf8length(); - } - *d++ = ')'; - *d = 0; - if (d2) *d2 = 0; + for (int jj = 0; jj < s->parameterNames.count(); ++jj) + s->parameterNamesRef[jj].load(s->parameterNames.at(jj)); } // Now allocate methods for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { - char *d = s->signatureRef.data(); - char *d2 = s->parameterNamesRef.isEmpty()?0:s->parameterNamesRef.data(); - s->name.writeUtf8(d); d += s->name.utf8length(); - *d++ = '('; - for (int jj = 0; jj < s->parameterNames.count(); ++jj) { - if (jj != 0) { *d++ = ','; *d2++ = ','; } - strcpy(d, "QVariant"); - d += strlen("QVariant"); - strcpy(d2, s->parameterNames.at(jj).constData()); - d2 += s->parameterNames.at(jj).length(); - } - *d++ = ')'; - *d = 0; - if (d2) *d2 = 0; + s->nameRef.load(s->name); + + for (int jj = 0; jj < s->parameterNames.count(); ++jj) + s->parameterNamesRef[jj].load(s->parameterNames.at(jj).constData()); } // Now allocate class name @@ -3233,7 +3210,6 @@ bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder, Object::DynamicProperty &prop) { Q_ASSERT(!prop.nameRef.isEmpty()); - Q_ASSERT(prop.typeRef.isEmpty()); if (!prop.defaultValue) COMPILE_EXCEPTION(obj, tr("No property alias location")); @@ -3278,9 +3254,7 @@ bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder, writable = aliasProperty.isWritable() && !prop.isReadOnly; resettable = aliasProperty.isResettable() && !prop.isReadOnly; - if (aliasProperty.type() < QVariant::UserType - || uint(aliasProperty.type()) == QMetaType::QVariant) - type = aliasProperty.type(); + type = aliasProperty.userType(); if (alias.count() == 3) { QQmlValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()]; @@ -3298,9 +3272,7 @@ bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder, propIdx |= (valueTypeIndex << 16); // update the property type - type = aliasProperty.type(); - if (type >= (int)QVariant::UserType) - type = 0; + type = aliasProperty.userType(); } if (aliasProperty.isEnumType()) @@ -3322,22 +3294,26 @@ bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder, if (typeName.endsWith('*')) flags |= QML_ALIAS_FLAG_PTR; + if (type == QMetaType::UnknownType) { + Q_ASSERT(!typeName.isEmpty()); + type = QMetaType::type(typeName); + Q_ASSERT(type != QMetaType::UnknownType); + Q_ASSERT(type != QMetaType::Void); + } + QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags }; typedef QQmlVMEMetaData VMD; VMD *vmd = (QQmlVMEMetaData *)data.data(); *(vmd->aliasData() + aliasIndex) = aliasData; - prop.resolvedCustomTypeName = pool->NewByteArray(typeName); - prop.typeRef = builder.newString(typeName.length()); - int propertyFlags = 0; if (writable) propertyFlags |= QFastMetaBuilder::Writable; if (resettable) propertyFlags |= QFastMetaBuilder::Resettable; - builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type, + builder.setProperty(propIndex, prop.nameRef, type, (QFastMetaBuilder::PropertyFlag)propertyFlags, propIndex); diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 489b4f895a..16cd1ecde6 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -59,7 +59,6 @@ #include "qquickworkerscript_p.h" #include "qqmlcomponent_p.h" #include "qqmlnetworkaccessmanagerfactory.h" -#include "qqmlimageprovider.h" #include "qqmldirparser_p.h" #include "qqmlextensioninterface.h" #include "qqmllist_p.h" @@ -179,6 +178,12 @@ void QQmlEnginePrivate::defineModule() qmlRegisterUncreatableType<QQmlLocale>("QtQuick",2,0,"Locale",QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()")); } + +QQmlImageProviderBase::~QQmlImageProviderBase() +{ +} + + /*! \qmlclass Qt QQmlEnginePrivate \ingroup qml-utility-elements @@ -670,27 +675,29 @@ QNetworkAccessManager *QQmlEngine::networkAccessManager() const takes ownership of \a provider. Image providers enable support for pixmap and threaded image - requests. See the QQmlImageProvider documentation for details on + requests. See the QQuickImageProvider documentation for details on implementing and using image providers. All required image providers should be added to the engine before any QML sources files are loaded. - \sa removeImageProvider() + \sa removeImageProvider(), QQuickImageProvider */ -void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProvider *provider) +void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider) { Q_D(QQmlEngine); QMutexLocker locker(&d->mutex); - d->imageProviders.insert(providerId.toLower(), QSharedPointer<QQmlImageProvider>(provider)); + d->imageProviders.insert(providerId.toLower(), QSharedPointer<QQmlImageProviderBase>(provider)); } /*! - Returns the QQmlImageProvider set for \a providerId. + Returns the image provider set for \a providerId. Returns the provider if it was found; otherwise returns 0. + + \sa QQuickImageProvider */ -QQmlImageProvider *QQmlEngine::imageProvider(const QString &providerId) const +QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) const { Q_D(const QQmlEngine); QMutexLocker locker(&d->mutex); @@ -698,9 +705,9 @@ QQmlImageProvider *QQmlEngine::imageProvider(const QString &providerId) const } /*! - Removes the QQmlImageProvider for \a providerId. + Removes the image provider for \a providerId. - \sa addImageProvider() + \sa addImageProvider(), QQuickImageProvider */ void QQmlEngine::removeImageProvider(const QString &providerId) { @@ -709,54 +716,6 @@ void QQmlEngine::removeImageProvider(const QString &providerId) d->imageProviders.take(providerId); } -QQmlImageProvider::ImageType QQmlEnginePrivate::getImageProviderType(const QUrl &url) -{ - QMutexLocker locker(&mutex); - QSharedPointer<QQmlImageProvider> provider = imageProviders.value(url.host()); - locker.unlock(); - if (provider) - return provider->imageType(); - return QQmlImageProvider::Invalid; -} - -QQuickTextureFactory *QQmlEnginePrivate::getTextureFromProvider(const QUrl &url, QSize *size, const QSize& req_size) -{ - QMutexLocker locker(&mutex); - QSharedPointer<QQmlImageProvider> provider = imageProviders.value(url.host()); - locker.unlock(); - if (provider) { - QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1); - return provider->requestTexture(imageId, size, req_size); - } - return 0; -} - -QImage QQmlEnginePrivate::getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size) -{ - QMutexLocker locker(&mutex); - QImage image; - QSharedPointer<QQmlImageProvider> provider = imageProviders.value(url.host()); - locker.unlock(); - if (provider) { - QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1); - image = provider->requestImage(imageId, size, req_size); - } - return image; -} - -QPixmap QQmlEnginePrivate::getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size) -{ - QMutexLocker locker(&mutex); - QPixmap pixmap; - QSharedPointer<QQmlImageProvider> provider = imageProviders.value(url.host()); - locker.unlock(); - if (provider) { - QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1); - pixmap = provider->requestPixmap(imageId, size, req_size); - } - return pixmap; -} - /*! Return the base URL for this engine. The base URL is only used to resolve components when a relative URL is passed to the diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index 04ac61c05b..41696923c5 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -54,6 +54,12 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE +class Q_QML_EXPORT QQmlImageProviderBase +{ +public: + virtual ~QQmlImageProviderBase(); +}; + class QQmlComponent; class QQmlEnginePrivate; class QQmlImportsPrivate; @@ -62,7 +68,6 @@ class QQmlContext; class QQmlType; class QUrl; class QScriptContext; -class QQmlImageProvider; class QNetworkAccessManager; class QQmlNetworkAccessManagerFactory; class QQmlIncubationController; @@ -94,8 +99,8 @@ public: QNetworkAccessManager *networkAccessManager() const; - void addImageProvider(const QString &id, QQmlImageProvider *); - QQmlImageProvider *imageProvider(const QString &id) const; + void addImageProvider(const QString &id, QQmlImageProviderBase *); + QQmlImageProviderBase *imageProvider(const QString &id) const; void removeImageProvider(const QString &id); void setIncubationController(QQmlIncubationController *); diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index db834489ba..73a0b5a217 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -63,7 +63,6 @@ #include "qqmlcontext.h" #include "qqmlcontext_p.h" #include "qqmlexpression.h" -#include "qqmlimageprovider.h" #include "qqmlproperty_p.h" #include "qqmlpropertycache_p.h" #include "qqmlmetatype_p.h" @@ -173,11 +172,7 @@ public: mutable QNetworkAccessManager *networkAccessManager; mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory; - QHash<QString,QSharedPointer<QQmlImageProvider> > imageProviders; - QQmlImageProvider::ImageType getImageProviderType(const QUrl &url); - QQuickTextureFactory *getTextureFromProvider(const QUrl &url, QSize *size, const QSize& req_size); - QImage getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size); - QPixmap getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size); + QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders; // Scarce resources are "exceptionally high cost" QVariant types where allowing the // normal JavaScript GC to clean them up is likely to lead to out-of-memory or other diff --git a/src/qml/qml/qqmlerror.h b/src/qml/qml/qqmlerror.h index 3c148549d0..73581e29aa 100644 --- a/src/qml/qml/qqmlerror.h +++ b/src/qml/qml/qqmlerror.h @@ -80,6 +80,8 @@ private: QDebug Q_QML_EXPORT operator<<(QDebug debug, const QQmlError &error); +Q_DECLARE_TYPEINFO(QQmlError, Q_MOVABLE_TYPE); + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/qml/qml/qqmlimageprovider.cpp b/src/qml/qml/qqmlimageprovider.cpp deleted file mode 100644 index d1afa54498..0000000000 --- a/src/qml/qml/qqmlimageprovider.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmlimageprovider.h" - -QT_BEGIN_NAMESPACE - -class QQmlImageProviderPrivate -{ -public: - QQmlImageProvider::ImageType type; -}; - -/*! - \class QQuickTextureFactory - \since 5.0 - \brief The QQuickTextureFactory class provides an interface for loading custom textures from QML. - - The purpose of the texture factory is to provide a placeholder for a image - data that can be converted into an OpenGL texture. - - Creating a texture directly is not possible as there is rarely an OpenGL context - available in the thread that is responsible for loading the image data. - */ - -QQuickTextureFactory::QQuickTextureFactory() -{ -} - -QQuickTextureFactory::~QQuickTextureFactory() -{ -} - - -/*! - \fn QImage QQuickTextureFactory::image() const - - Returns an image version of this texture. - - The lifespan of the returned image is unknown, so the implementation should - return a self contained QImage, not make use of the QImage(uchar *, ...) - constructor. - - This function is not commonly used and is expected to be slow. - */ - -QImage QQuickTextureFactory::image() const -{ - return QImage(); -} - - -/*! - \fn QSGTexture *QQuickTextureFactory::createTexture() const - - This function is called on the scene graph rendering thread to create a QSGTexture - instance from the factory. - - QML will internally cache the returned texture as needed. Each call to this - function should return a unique instance. - - The OpenGL context used for rendering is bound when this function is called. - */ - -/*! - \fn QSize QQuickTextureFactory::textureSize() const - - Returns the size of the texture. This function will be called from arbitrary threads - and should not rely on an OpenGL context bound. - */ - - -/*! - \class QQmlImageProvider - \since 4.7 - \brief The QQmlImageProvider class provides an interface for supporting pixmaps and threaded image requests in QML. - - QQmlImageProvider is used to provide advanced image loading features - in QML applications. It allows images in QML to be: - - \list - \li Loaded using QPixmaps rather than actual image files - \li Loaded asynchronously in a separate thread, if imageType() is \l{QQmlImageProvider::ImageType}{ImageType::Image} - \endlist - - To specify that an image should be loaded by an image provider, use the - \b {"image:"} scheme for the URL source of the image, followed by the - identifiers of the image provider and the requested image. For example: - - \qml - Image { source: "image://myimageprovider/image.png" } - \endqml - - This specifies that the image should be loaded by the image provider named - "myimageprovider", and the image to be loaded is named "image.png". The QML engine - invokes the appropriate image provider according to the providers that have - been registered through QQmlEngine::addImageProvider(). - - Note that the identifiers are case-insensitive, but the rest of the URL will be passed on with - preserved case. For example, the below snippet would still specify that the image is loaded by the - image provider named "myimageprovider", but it would request a different image than the above snippet - ("Image.png" instead of "image.png"). - \qml - Image { source: "image://MyImageProvider/Image.png" } - \endqml - - If you want the rest of the URL to be case insensitive, you will have to take care - of that yourself inside your image provider. - - \section2 An example - - Here are two images. Their \c source values indicate they should be loaded by - an image provider named "colors", and the images to be loaded are "yellow" - and "red", respectively: - - \snippet examples/declarative/cppextensions/imageprovider/imageprovider-example.qml 0 - - When these images are loaded by QML, it looks for a matching image provider - and calls its requestImage() or requestPixmap() method (depending on its - imageType()) to load the image. The method is called with the \c id - parameter set to "yellow" for the first image, and "red" for the second. - - Here is an image provider implementation that can load the images - requested by the above QML. This implementation dynamically - generates QPixmap images that are filled with the requested color: - - \snippet examples/declarative/cppextensions/imageprovider/imageprovider.cpp 0 - \codeline - \snippet examples/declarative/cppextensions/imageprovider/imageprovider.cpp 1 - - To make this provider accessible to QML, it is registered with the QML engine - with a "colors" identifier: - - \code - int main(int argc, char *argv[]) - { - ... - - QQmlEngine engine; - engine->addImageProvider(QLatin1String("colors"), new ColorPixmapProvider); - - ... - } - \endcode - - Now the images can be successfully loaded in QML: - - \image imageprovider.png - - A complete example is available in Qt's - \l {declarative/cppextensions/imageprovider}{examples/declarative/cppextensions/imageprovider} - directory. Note the example registers the provider via a \l{QQmlExtensionPlugin}{plugin} - instead of registering it in the application \c main() function as shown above. - - - \section2 Asynchronous image loading - - Image providers that support QImage loading automatically include support - for asychronous loading of images. To enable asynchronous loading for an - image source, set the \c asynchronous property to \c true for the relevant - \l Image, \l BorderImage or \l AnimatedImage object. When this is enabled, - the image request to the provider is run in a low priority thread, - allowing image loading to be executed in the background, and reducing the - performance impact on the user interface. - - Asynchronous loading is not supported for image providers that provide - QPixmap rather than QImage values, as pixmaps can only be created in the - main thread. In this case, if \l {Image::}{asynchronous} is set to - \c true, the value is ignored and the image is loaded - synchronously. - - - \section2 Image caching - - Images returned by a QQmlImageProvider are automatically cached, - similar to any image loaded by the QML engine. When an image with a - "image://" prefix is loaded from cache, requestImage() and requestPixmap() - will not be called for the relevant image provider. If an image should always - be fetched from the image provider, and should not be cached at all, set the - \c cache property to \c false for the relevant \l Image, \l BorderImage or - \l AnimatedImage object. - - \sa QQmlEngine::addImageProvider() -*/ - -/*! - \enum QQmlImageProvider::ImageType - - Defines the type of image supported by this image provider. - - \value Image The Image Provider provides QImage images. The - requestImage() method will be called for all image requests. - \value Pixmap The Image Provider provides QPixmap images. The - requestPixmap() method will be called for all image requests. - \value Texture The Image Provider provides QSGTextureProvider based images. - The requestTexture() method will be called for all image requests. \omitvalue -*/ - -/*! - Creates an image provider that will provide images of the given \a type. -*/ -QQmlImageProvider::QQmlImageProvider(ImageType type) - : d(new QQmlImageProviderPrivate) -{ - d->type = type; -} - -/*! - Destroys the QQmlImageProvider - - \note The destructor of your derived class need to be thread safe. -*/ -QQmlImageProvider::~QQmlImageProvider() -{ - delete d; -} - -/*! - Returns the image type supported by this provider. -*/ -QQmlImageProvider::ImageType QQmlImageProvider::imageType() const -{ - return d->type; -} - -/*! - Implement this method to return the image with \a id. The default - implementation returns an empty image. - - The \a id is the requested image source, with the "image:" scheme and - provider identifier removed. For example, if the image \l{Image::}{source} - was "image://myprovider/icons/home", the given \a id would be "icons/home". - - The \a requestedSize corresponds to the \l {Image::sourceSize} requested by - an Image element. If \a requestedSize is a valid size, the image - returned should be of that size. - - In all cases, \a size must be set to the original size of the image. This - is used to set the \l {Item::}{width} and \l {Item::}{height} of the - relevant \l Image if these values have not been set explicitly. - - \note this method may be called by multiple threads, so ensure the - implementation of this method is reentrant. -*/ -QImage QQmlImageProvider::requestImage(const QString &id, QSize *size, const QSize& requestedSize) -{ - Q_UNUSED(id); - Q_UNUSED(size); - Q_UNUSED(requestedSize); - if (d->type == Image) - qWarning("ImageProvider supports Image type but has not implemented requestImage()"); - return QImage(); -} - -/*! - Implement this method to return the pixmap with \a id. The default - implementation returns an empty pixmap. - - The \a id is the requested image source, with the "image:" scheme and - provider identifier removed. For example, if the image \l{Image::}{source} - was "image://myprovider/icons/home", the given \a id would be "icons/home". - - The \a requestedSize corresponds to the \l {Image::sourceSize} requested by - an Image element. If \a requestedSize is a valid size, the image - returned should be of that size. - - In all cases, \a size must be set to the original size of the image. This - is used to set the \l {Item::}{width} and \l {Item::}{height} of the - relevant \l Image if these values have not been set explicitly. -*/ -QPixmap QQmlImageProvider::requestPixmap(const QString &id, QSize *size, const QSize& requestedSize) -{ - Q_UNUSED(id); - Q_UNUSED(size); - Q_UNUSED(requestedSize); - if (d->type == Pixmap) - qWarning("ImageProvider supports Pixmap type but has not implemented requestPixmap()"); - return QPixmap(); -} - - -/*! - Implement this method to return the texture with \a id. The default - implementation returns 0. - - The \a id is the requested image source, with the "image:" scheme and - provider identifier removed. For example, if the image \l{Image::}{source} - was "image://myprovider/icons/home", the given \a id would be "icons/home". - - The \a requestedSize corresponds to the \l {Image::sourceSize} requested by - an Image element. If \a requestedSize is a valid size, the image - returned should be of that size. - - In all cases, \a size must be set to the original size of the image. This - is used to set the \l {Item::}{width} and \l {Item::}{height} of the - relevant \l Image if these values have not been set explicitly. - - \note this method may be called by multiple threads, so ensure the - implementation of this method is reentrant. -*/ - -QQuickTextureFactory *QQmlImageProvider::requestTexture(const QString &id, QSize *size, const QSize &requestedSize) -{ - Q_UNUSED(id); - Q_UNUSED(size); - Q_UNUSED(requestedSize); - if (d->type == Texture) - qWarning("ImageProvider supports Texture type but has not implemented requestTexture()"); - return 0; -} - -QT_END_NAMESPACE - diff --git a/src/qml/qml/qqmlimageprovider.h b/src/qml/qml/qqmlimageprovider.h deleted file mode 100644 index da4d8c8248..0000000000 --- a/src/qml/qml/qqmlimageprovider.h +++ /dev/null @@ -1,97 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQMLIMAGEPROVIDER_H -#define QQMLIMAGEPROVIDER_H - -#include <QtQml/qtqmlglobal.h> -#include <QtGui/qimage.h> -#include <QtGui/qpixmap.h> - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - - -class QQmlImageProviderPrivate; -class QSGTexture; -class QQuickCanvas; - -class Q_QML_EXPORT QQuickTextureFactory : public QObject -{ -public: - QQuickTextureFactory(); - virtual ~QQuickTextureFactory(); - - virtual QSGTexture *createTexture(QQuickCanvas *canvas) const = 0; - virtual QSize textureSize() const = 0; - virtual int textureByteCount() const = 0; - virtual QImage image() const; -}; - -class Q_QML_EXPORT QQmlImageProvider -{ -public: - enum ImageType { - Image, - Pixmap, - Texture, - Invalid - }; - - QQmlImageProvider(ImageType type); - virtual ~QQmlImageProvider(); - - ImageType imageType() const; - - virtual QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize); - virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize); - virtual QQuickTextureFactory *requestTexture(const QString &id, QSize *size, const QSize &requestedSize); - -private: - QQmlImageProviderPrivate *d; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QQMLIMAGEPROVIDER diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 2061530dc5..5b80f57d01 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -340,9 +340,7 @@ static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, QMetaMethod method = mo->method(ii); // More complex - need to search name - QByteArray name = method.signature(); - int parenIdx = name.indexOf('('); - if (parenIdx != -1) name = name.left(parenIdx); + QByteArray name = method.name(); bool found = false; @@ -352,11 +350,8 @@ static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, ++ii) { QMetaMethod other = ignoreEnd->method(ii); - QByteArray othername = other.signature(); - int parenIdx = othername.indexOf('('); - if (parenIdx != -1) othername = othername.left(parenIdx); - found = name == othername; + found = name == other.name(); } QMetaMethodBuilder m = builder.addMethod(method); diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 14778ce6c8..d3778fa5c5 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -334,7 +334,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) signalName[0] = signalName.at(0).toLower(); QMetaMethod method = findSignalByName(currentObject->metaObject(), signalName.toLatin1().constData()); - if (method.signature()) { + if (method.isValid()) { object = currentObject; core.load(method); return; @@ -1148,7 +1148,7 @@ bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, return false; } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) { int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name())); - if ((enumMetaTypeId == 0) || (v.userType() != enumMetaTypeId) || !v.constData()) + if ((enumMetaTypeId == QMetaType::UnknownType) || (v.userType() != enumMetaTypeId) || !v.constData()) return false; v = QVariant(*reinterpret_cast<const int *>(v.constData())); } @@ -1487,6 +1487,17 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object, if (expression->hasError()) { return false; + } else if (isVmeProperty) { + typedef QQmlVMEMetaObject VMEMO; + if (!result.IsEmpty() && result->IsFunction() + && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) { + // we explicitly disallow this case to avoid confusion. Users can still store one + // in an array in a var property if they need to, but the common case is user error. + expression->delayedError()->error.setDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); + return false; + } + VMEMO *vmemo = static_cast<VMEMO *>(const_cast<QMetaObject *>(object->metaObject())); + vmemo->setVMEProperty(core.coreIndex, result); } else if (isUndefined && core.isResettable()) { void *args[] = { 0 }; QMetaObject::metacall(object, QMetaObject::ResetProperty, core.coreIndex, args); @@ -1496,12 +1507,11 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object, expression->delayedError()->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + QLatin1String(QMetaType::typeName(type))); return false; } else if (result->IsFunction()) { - expression->delayedError()->error.setDescription(QLatin1String("Unable to assign a function to a property.")); + if (!result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) + expression->delayedError()->error.setDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); + else + expression->delayedError()->error.setDescription(QLatin1String("Unable to assign a function to a property of any type other than var.")); return false; - } else if (isVmeProperty) { - typedef QQmlVMEMetaObject VMEMO; - VMEMO *vmemo = static_cast<VMEMO *>(const_cast<QMetaObject *>(object->metaObject())); - vmemo->setVMEProperty(core.coreIndex, result); } else if (!writeValueProperty(object, engine, core, value, context, flags)) { if (watcher.wasDeleted()) @@ -1680,7 +1690,7 @@ bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex); if (prop.hasNotifySignal()) { - QByteArray signal(QByteArray("2") + prop.notifySignal().signature()); + QByteArray signal(QByteArray("2") + prop.notifySignal().methodSignature()); return QObject::connect(d->object, signal.constData(), dest, slot); } else { return false; @@ -1786,11 +1796,8 @@ QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const Q int methods = mo->methodCount(); for (int ii = methods - 1; ii >= 2; --ii) { // >= 2 to block the destroyed signal QMetaMethod method = mo->method(ii); - QByteArray methodName = method.signature(); - int idx = methodName.indexOf('('); - methodName = methodName.left(idx); - if (methodName == name) + if (method.name() == name) return method; } diff --git a/src/qml/qml/qqmlproperty.h b/src/qml/qml/qqmlproperty.h index 2c4b2544c1..bd2b1d35ba 100644 --- a/src/qml/qml/qqmlproperty.h +++ b/src/qml/qml/qqmlproperty.h @@ -136,6 +136,8 @@ inline uint qHash (const QQmlProperty &key) return qHash(key.object()) + qHash(key.name()); } +Q_DECLARE_TYPEINFO(QQmlProperty, Q_MOVABLE_TYPE); + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 93c6aa1f00..af6cd9285b 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -176,19 +176,11 @@ void QQmlPropertyData::load(const QMetaMethod &m) flags |= IsFunction; if (m.methodType() == QMetaMethod::Signal) flags |= IsSignal; - propType = QVariant::Invalid; - - const char *returnType = m.typeName(); - if (returnType) - propType = QMetaType::type(returnType); + propType = m.returnType(); - const char *signature = m.signature(); - while (*signature != '(') { Q_ASSERT(*signature != 0); ++signature; } - - ++signature; - if (*signature != ')') { + if (m.parameterCount()) { flags |= HasArguments; - if (0 == ::strcmp(signature, "QQmlV8Function*)")) { + if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV8Function*")) { flags |= IsV8Function; } } @@ -212,13 +204,9 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m) flags |= NotFullyResolved; } - const char *signature = m.signature(); - while (*signature != '(') { Q_ASSERT(*signature != 0); ++signature; } - - ++signature; - if (*signature != ')') { + if (m.parameterCount()) { flags |= HasArguments; - if (0 == ::strcmp(signature, "QQmlV8Function*)")) { + if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV8Function*")) { flags |= IsV8Function; } } @@ -414,10 +402,17 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject continue; // Extract method name - const char *signature = m.signature(); + const char *signature; + if (QMetaObjectPrivate::get(metaObject)->revision >= 7) { + // Safe to use the raw name pointer + signature = m.name().constData(); + } else { + // Safe to use the raw signature pointer + signature = m.methodSignature().constData(); + } const char *cptr = signature; char utf8 = 0; - while (*cptr != '(') { + while (*cptr && *cptr != '(') { Q_ASSERT(*cptr != 0); utf8 |= *cptr & 0x80; ++cptr; @@ -663,11 +658,7 @@ QString QQmlPropertyData::name(const QMetaObject *metaObject) if (flags & IsFunction) { QMetaMethod m = metaObject->method(coreIndex); - QString name = QString::fromUtf8(m.signature()); - int parenIdx = name.indexOf(QLatin1Char('(')); - if (parenIdx != -1) - name = name.left(parenIdx); - return name; + return QString::fromUtf8(m.name().constData()); } else { QMetaProperty p = metaObject->property(coreIndex); return QString::fromUtf8(p.name()); @@ -727,15 +718,19 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, const QMetaObject *metaObject = object->metaObject(); QMetaMethod m = metaObject->method(index); - QList<QByteArray> argTypeNames = m.parameterTypes(); - A *args = static_cast<A *>(malloc(sizeof(A) + (argTypeNames.count() + 1) * sizeof(int))); - args->arguments[0] = argTypeNames.count(); + int argc = m.parameterCount(); + A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int))); + args->arguments[0] = argc; + QList<QByteArray> argTypeNames; // Only loaded if needed - for (int ii = 0; ii < argTypeNames.count(); ++ii) { - int type = QMetaType::type(argTypeNames.at(ii)); - if (type == QVariant::Invalid) + for (int ii = 0; ii < argc; ++ii) { + int type = m.parameterType(ii); + if (type == QVariant::Invalid) { + if (argTypeNames.isEmpty()) + argTypeNames = m.parameterTypes(); type = EnumType(object->metaObject(), argTypeNames.at(ii)); + } if (type == QVariant::Invalid) { if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii); free(args); @@ -751,14 +746,18 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, } else { QMetaMethod m = object->metaObject()->method(index); - QList<QByteArray> argTypeNames = m.parameterTypes(); - dummy.resize(argTypeNames.count() + 1); - dummy[0] = argTypeNames.count(); + int argc = m.parameterCount(); + dummy.resize(argc + 1); + dummy[0] = argc; + QList<QByteArray> argTypeNames; // Only loaded if needed - for (int ii = 0; ii < argTypeNames.count(); ++ii) { - int type = QMetaType::type(argTypeNames.at(ii)); - if (type == QVariant::Invalid) + for (int ii = 0; ii < argc; ++ii) { + int type = m.parameterType(ii); + if (type == QVariant::Invalid) { + if (argTypeNames.isEmpty()) + argTypeNames = m.parameterTypes(); type = EnumType(object->metaObject(), argTypeNames.at(ii)); + } if (type == QVariant::Invalid) { if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii); return 0; @@ -804,13 +803,9 @@ QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, QMetaMethod m = metaObject->method(ii); if (m.access() == QMetaMethod::Private) continue; - QString methodName = QString::fromUtf8(m.signature()); - - int parenIdx = methodName.indexOf(QLatin1Char('(')); - Q_ASSERT(parenIdx != -1); - QStringRef methodNameRef = methodName.leftRef(parenIdx); + QString methodName = QString::fromUtf8(m.name().constData()); - if (methodNameRef == property) { + if (methodName == property) { rv.load(m); return rv; } diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp index 8e22e488ed..e1925eb238 100644 --- a/src/qml/qml/qqmlscript.cpp +++ b/src/qml/qml/qqmlscript.cpp @@ -182,33 +182,30 @@ Property *QQmlScript::Object::getProperty(const QString &name, bool create) } } -QQmlScript::Object::DynamicProperty::DynamicProperty() -: isDefaultProperty(false), isReadOnly(false), type(Variant), defaultValue(0), nextProperty(0), - resolvedCustomTypeName(0) +int QQmlScript::Object::aggregateDynamicSignalParameterCount() const { + int sum = 0; + for (DynamicSignal *s = dynamicSignals.first(); s; s = dynamicSignals.next(s)) + sum += s->parameterTypes.count() + 1; // +1 for return type + return sum; } -QQmlScript::Object::DynamicSignal::DynamicSignal() -: nextSignal(0) +int QQmlScript::Object::aggregateDynamicSlotParameterCount() const { + int sum = 0; + for (DynamicSlot *s = dynamicSlots.first(); s; s = dynamicSlots.next(s)) + sum += s->parameterNames.count() + 1; // +1 for return type + return sum; } -// Returns length in utf8 bytes -int QQmlScript::Object::DynamicSignal::parameterTypesLength() const +QQmlScript::Object::DynamicProperty::DynamicProperty() +: isDefaultProperty(false), isReadOnly(false), type(Variant), defaultValue(0), nextProperty(0) { - int rv = 0; - for (int ii = 0; ii < parameterTypes.count(); ++ii) - rv += parameterTypes.at(ii).length(); - return rv; } -// Returns length in utf8 bytes -int QQmlScript::Object::DynamicSignal::parameterNamesLength() const +QQmlScript::Object::DynamicSignal::DynamicSignal() +: nextSignal(0) { - int rv = 0; - for (int ii = 0; ii < parameterNames.count(); ++ii) - rv += parameterNames.at(ii).utf8length(); - return rv; } QQmlScript::Object::DynamicSlot::DynamicSlot() @@ -919,25 +916,23 @@ bool ProcessAST::visit(AST::UiPublicMember *node) const char *name; int nameLength; Object::DynamicProperty::Type type; - const char *qtName; - int qtNameLength; } propTypeNameToTypes[] = { - { "int", strlen("int"), Object::DynamicProperty::Int, "int", strlen("int") }, - { "bool", strlen("bool"), Object::DynamicProperty::Bool, "bool", strlen("bool") }, - { "double", strlen("double"), Object::DynamicProperty::Real, "double", strlen("double") }, - { "real", strlen("real"), Object::DynamicProperty::Real, "double", strlen("double") }, - { "string", strlen("string"), Object::DynamicProperty::String, "QString", strlen("QString") }, - { "url", strlen("url"), Object::DynamicProperty::Url, "QUrl", strlen("QUrl") }, - { "color", strlen("color"), Object::DynamicProperty::Color, "QColor", strlen("QColor") }, + { "int", strlen("int"), Object::DynamicProperty::Int }, + { "bool", strlen("bool"), Object::DynamicProperty::Bool }, + { "double", strlen("double"), Object::DynamicProperty::Real }, + { "real", strlen("real"), Object::DynamicProperty::Real }, + { "string", strlen("string"), Object::DynamicProperty::String }, + { "url", strlen("url"), Object::DynamicProperty::Url }, + { "color", strlen("color"), Object::DynamicProperty::Color }, // Internally QTime, QDate and QDateTime are all supported. // To be more consistent with JavaScript we expose only // QDateTime as it matches closely with the Date JS type. // We also call it "date" to match. - // { "time", strlen("time"), Object::DynamicProperty::Time, "QTime", strlen("QTime") }, - // { "date", strlen("date"), Object::DynamicProperty::Date, "QDate", strlen("QDate") }, - { "date", strlen("date"), Object::DynamicProperty::DateTime, "QDateTime", strlen("QDateTime") }, - { "variant", strlen("variant"), Object::DynamicProperty::Variant, "QVariant", strlen("QVariant") }, - { "var", strlen("var"), Object::DynamicProperty::Var, "QVariant", strlen("QVariant") } + // { "time", strlen("time"), Object::DynamicProperty::Time }, + // { "date", strlen("date"), Object::DynamicProperty::Date }, + { "date", strlen("date"), Object::DynamicProperty::DateTime }, + { "variant", strlen("variant"), Object::DynamicProperty::Variant }, + { "var", strlen("var"), Object::DynamicProperty::Var } }; static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) / sizeof(propTypeNameToTypes[0]); @@ -952,7 +947,7 @@ bool ProcessAST::visit(AST::UiPublicMember *node) p = node->parameters; if (paramLength) { - signal->parameterTypes = _parser->_pool.NewRawList<QHashedCStringRef>(paramLength); + signal->parameterTypes = _parser->_pool.NewRawList<Object::DynamicProperty::Type>(paramLength); signal->parameterNames = _parser->_pool.NewRawList<QHashedStringRef>(paramLength); } @@ -979,7 +974,7 @@ bool ProcessAST::visit(AST::UiPublicMember *node) return false; } - signal->parameterTypes[index] = QHashedCStringRef(type->qtName, type->qtNameLength); + signal->parameterTypes[index] = type->type; signal->parameterNames[index] = QHashedStringRef(p->name); p = p->next; index++; diff --git a/src/qml/qml/qqmlscript_p.h b/src/qml/qml/qqmlscript_p.h index ddf4c9a392..8705f2aef9 100644 --- a/src/qml/qml/qqmlscript_p.h +++ b/src/qml/qml/qqmlscript_p.h @@ -406,10 +406,8 @@ public: DynamicProperty *nextProperty; // Used by the compiler - QByteArray *resolvedCustomTypeName; - QFastMetaBuilder::StringRef typeRef; QFastMetaBuilder::StringRef nameRef; - QFastMetaBuilder::StringRef changedSignatureRef; + QFastMetaBuilder::StringRef changedNameRef; }; struct DynamicSignal : public QQmlPool::POD @@ -417,18 +415,15 @@ public: DynamicSignal(); QHashedStringRef name; - QQmlPool::List<QHashedCStringRef> parameterTypes; + QQmlPool::List<DynamicProperty::Type> parameterTypes; QQmlPool::List<QHashedStringRef> parameterNames; - int parameterTypesLength() const; - int parameterNamesLength() const; - // Used by Object::DynamicSignalList DynamicSignal *nextSignal; // Used by the compiler - QFastMetaBuilder::StringRef signatureRef; - QFastMetaBuilder::StringRef parameterNamesRef; + QFastMetaBuilder::StringRef nameRef; + QQmlPool::List<QFastMetaBuilder::StringRef> parameterNamesRef; LocationSpan location; }; @@ -447,8 +442,8 @@ public: DynamicSlot *nextSlot; // Used by the compiler - QFastMetaBuilder::StringRef signatureRef; - QFastMetaBuilder::StringRef parameterNamesRef; + QFastMetaBuilder::StringRef nameRef; + QQmlPool::List<QFastMetaBuilder::StringRef> parameterNamesRef; }; // The list of dynamic properties @@ -461,6 +456,9 @@ public: typedef QFieldList<DynamicSlot, &DynamicSlot::nextSlot> DynamicSlotList; DynamicSlotList dynamicSlots; + int aggregateDynamicSignalParameterCount() const; + int aggregateDynamicSlotParameterCount() const; + // Used by compiler QQmlCompilerTypes::ComponentCompileState *componentCompileState; diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp index 2a7ea45053..86e9f0963a 100644 --- a/src/qml/qml/qqmlvme.cpp +++ b/src/qml/qml/qqmlvme.cpp @@ -690,11 +690,14 @@ QObject *QQmlVME::run(QList<QQmlError> *errors, if (prop.type() & QQmlProperty::SignalProperty) { QMetaMethod method = QQmlMetaType::defaultMethod(assign); - if (method.signature() == 0) + if (!method.isValid()) VME_EXCEPTION(tr("Cannot assign object type %1 with no default method").arg(QString::fromLatin1(assign->metaObject()->className())), instr.line); - if (!QMetaObject::checkConnectArgs(prop.method().signature(), method.signature())) - VME_EXCEPTION(tr("Cannot connect mismatched signal/slot %1 %vs. %2").arg(QString::fromLatin1(method.signature())).arg(QString::fromLatin1(prop.method().signature())), instr.line); + if (!QMetaObject::checkConnectArgs(prop.method(), method)) { + VME_EXCEPTION(tr("Cannot connect mismatched signal/slot %1 %vs. %2") + .arg(QString::fromLatin1(method.methodSignature().constData())) + .arg(QString::fromLatin1(prop.method().methodSignature().constData())), instr.line); + } QQmlPropertyPrivate::connect(target, prop.index(), assign, method.methodIndex()); diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index cc4ba091ce..c4e801f2db 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -760,7 +760,7 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) // 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).signature()))); + arg(QLatin1String(QMetaObject::method(_id).methodSignature().constData()))); ep->warning(e); return -1; // The dynamic method with that id is not available. } diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index b9f2b627da..68c62ef240 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -1333,6 +1333,65 @@ v8::Handle<v8::Value> locale(const v8::Arguments &args) return QQmlLocale::locale(v8engine, code); } +/*! + \qmlmethod Qt::binding(function) + + Returns a JS object representing a binding expression which may be + assigned to any property in imperative code to cause a binding + assignment. + + There are two main use-cases for the function: firstly, in imperative + JavaScript code to cause a binding assignment: + + \snippet doc/src/snippets/declarative/qtBinding.1.qml 0 + + and secondly, when defining initial property values of dynamically + constructed objects (via Component.createObject() or + Loader.setSource()) as being bound to the result of an expression. + + For example, assuming the existence of a DynamicText component: + \snippet doc/src/snippets/declarative/DynamicText.qml 0 + + the output from: + \snippet doc/src/snippets/declarative/qtBinding.2.qml 0 + + and from: + \snippet doc/src/snippets/declarative/qtBinding.3.qml 0 + + should both be: + \code + Root text extra text + Modified root text extra text + Dynamic text extra text + Modified dynamic text extra text + \endcode + + This function cannot be used in property binding declarations + (see the documentation on \l{qml-javascript-assignment}{binding + declarations and binding assignments}) except when the result is + stored in an array bound to a var property. + + \snippet doc/src/snippets/declarative/qtBinding.4.qml 0 + + Note: in QtQuick 1.x, all function assignment was treated as + binding assignment, so the Qt.binding() function is new in + QtQuick 2.0. + + \since QtQuick 2.0 +*/ +v8::Handle<v8::Value> binding(const v8::Arguments &args) +{ + QString code; + if (args.Length() != 1) + V8THROW_ERROR("binding() requires 1 argument"); + if (!args[0]->IsFunction()) + V8THROW_TYPE("binding(): argument (binding expression) must be a function"); + + v8::Handle<v8::Object> rv = args[0]->ToObject()->Clone(); + rv->SetHiddenValue(V8ENGINE()->bindingFlagKey(), v8::Boolean::New(true)); + return rv; +} + } // namespace QQmlBuiltinFunctions QT_END_NAMESPACE diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index ddb1c64243..bbfe88a292 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -103,6 +103,7 @@ v8::Handle<v8::Value> qsTrId(const v8::Arguments &args); v8::Handle<v8::Value> qsTrIdNoOp(const v8::Arguments &args); v8::Handle<v8::Value> stringArg(const v8::Arguments &args); v8::Handle<v8::Value> locale(const v8::Arguments &args); +v8::Handle<v8::Value> binding(const v8::Arguments &args); } QT_END_NAMESPACE diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 8e8223fea1..ab3283f727 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -147,6 +147,8 @@ QV8Engine::QV8Engine(QJSEngine* qq, QJSEngine::ContextOwnership ownership) QV8GCCallback::registerGcPrologueCallback(); m_strongReferencer = qPersistentNew(v8::Object::New()); + m_bindingFlagKey = qPersistentNew(v8::String::New("qml::binding")); + m_stringWrapper.init(); m_contextWrapper.init(this); m_qobjectWrapper.init(this); @@ -191,6 +193,8 @@ QV8Engine::~QV8Engine() m_contextWrapper.destroy(); m_stringWrapper.destroy(); + qPersistentDispose(m_bindingFlagKey); + m_originalGlobalObject.destroy(); if (m_ownsV8Context) @@ -314,6 +318,7 @@ v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant) if (type < QMetaType::User) { switch (QMetaType::Type(type)) { + case QMetaType::UnknownType: case QMetaType::Void: return v8::Undefined(); case QMetaType::Bool: @@ -598,6 +603,7 @@ void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global) qt->Set(v8::String::New("atob"), V8FUNCTION(atob, this)); qt->Set(v8::String::New("resolvedUrl"), V8FUNCTION(resolvedUrl, this)); qt->Set(v8::String::New("locale"), V8FUNCTION(locale, this)); + qt->Set(v8::String::New("binding"), V8FUNCTION(binding, this)); if (m_engine) { qt->Set(v8::String::New("application"), newQObject(new QQuickApplication(m_engine))); @@ -1112,6 +1118,7 @@ v8::Handle<v8::Value> QV8Engine::metaTypeToJS(int type, const void *data) // check if it's one of the types we know switch (QMetaType::Type(type)) { + case QMetaType::UnknownType: case QMetaType::Void: return v8::Undefined(); case QMetaType::Bool: diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h index bc57b27085..825d7a3583 100644 --- a/src/qml/qml/v8/qv8engine_p.h +++ b/src/qml/qml/v8/qv8engine_p.h @@ -357,6 +357,9 @@ public: // a QVariant wrapper inline v8::Handle<v8::Value> newQVariant(const QVariant &); + // Return the JS string key for the "function is a binding" flag + inline v8::Handle<v8::String> bindingFlagKey() const; + // Return the network access manager for this engine. By default this returns the network // access manager of the QQmlEngine. It is overridden in the case of a threaded v8 // instance (like in WorkerScript). @@ -461,6 +464,8 @@ protected: v8::Persistent<v8::Context> m_context; QScriptOriginalGlobalObject m_originalGlobalObject; + v8::Persistent<v8::String> m_bindingFlagKey; + QV8StringWrapper m_stringWrapper; QV8ContextWrapper m_contextWrapper; QV8QObjectWrapper m_qobjectWrapper; @@ -609,6 +614,11 @@ v8::Handle<v8::Value> QV8Engine::newSequence(int sequenceType, QObject *object, return m_sequenceWrapper.newSequence(sequenceType, object, property, succeeded); } +v8::Handle<v8::String> QV8Engine::bindingFlagKey() const +{ + return m_bindingFlagKey; +} + // XXX Can this be made more optimal? It is called prior to resolving each and every // unqualified name in QV8ContextWrapper. bool QV8Engine::startsWithUpper(v8::Handle<v8::String> string) diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp index 3faea2c97b..2350b9dc2c 100644 --- a/src/qml/qml/v8/qv8qobjectwrapper.cpp +++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp @@ -449,7 +449,7 @@ static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object, return retn; } - if (property.propType == QVariant::Invalid) { + if (property.propType == QMetaType::UnknownType) { QMetaProperty p = object->metaObject()->property(property.coreIndex); qWarning("QMetaProperty::read: Unable to handle unregistered datatype '%s' for property " "'%s::%s'", p.typeName(), object->metaObject()->className(), p.name()); @@ -519,7 +519,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject return v8::Handle<v8::Value>(); } - if (result->isFunction()) { + if (result->isFunction() && !result->isVMEProperty()) { if (result->isVMEFunction()) { return ((QQmlVMEMetaObject *)(object->metaObject()))->vmeMethod(result->coreIndex); } else if (result->isV8Function()) { @@ -579,23 +579,53 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert v8::Handle<v8::Value> value) { QQmlBinding *newBinding = 0; - if (value->IsFunction()) { - QQmlContextData *context = engine->callingContext(); - v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value); - - v8::Local<v8::StackTrace> trace = - v8::StackTrace::CurrentStackTrace(1, (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber | - v8::StackTrace::kScriptName)); - v8::Local<v8::StackFrame> frame = trace->GetFrame(0); - int lineNumber = frame->GetLineNumber(); - int columnNumber = frame->GetColumn(); - QString url = engine->toString(frame->GetScriptName()); - - newBinding = new QQmlBinding(&function, object, context, url, lineNumber, columnNumber); - newBinding->setTarget(object, *property, context); - newBinding->setEvaluateFlags(newBinding->evaluateFlags() | - QQmlBinding::RequiresThisObject); + if (value->ToObject()->GetHiddenValue(engine->bindingFlagKey()).IsEmpty()) { + if (!property->isVMEProperty()) { + // XXX TODO: uncomment the following lines + // assigning a JS function to a non-var-property is not allowed. + //QString error = QLatin1String("Cannot assign JavaScript function to ") + + // QLatin1String(QMetaType::typeName(property->propType)); + //v8::ThrowException(v8::Exception::Error(engine->toString(error))); + //return; + // XXX TODO: remove the following transition behaviour + // Temporarily allow assignment of functions to non-var properties + // to mean binding assignment (as per old behaviour). + QQmlContextData *context = engine->callingContext(); + v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value); + + v8::Local<v8::StackTrace> trace = + v8::StackTrace::CurrentStackTrace(1, (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber | + v8::StackTrace::kScriptName)); + v8::Local<v8::StackFrame> frame = trace->GetFrame(0); + int lineNumber = frame->GetLineNumber(); + int columnNumber = frame->GetColumn(); + QString url = engine->toString(frame->GetScriptName()); + + newBinding = new QQmlBinding(&function, object, context, url, lineNumber, columnNumber); + newBinding->setTarget(object, *property, context); + newBinding->setEvaluateFlags(newBinding->evaluateFlags() | + QQmlBinding::RequiresThisObject); + qWarning("WARNING: function assignment is DEPRECATED and will be removed! Wrap RHS in Qt.binding(): %s:%d", qPrintable(engine->toString(frame->GetScriptName())), frame->GetLineNumber()); + } + } else { + // binding assignment. + QQmlContextData *context = engine->callingContext(); + v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value); + + v8::Local<v8::StackTrace> trace = + v8::StackTrace::CurrentStackTrace(1, (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber | + v8::StackTrace::kScriptName)); + v8::Local<v8::StackFrame> frame = trace->GetFrame(0); + int lineNumber = frame->GetLineNumber(); + int columnNumber = frame->GetColumn(); + QString url = engine->toString(frame->GetScriptName()); + + newBinding = new QQmlBinding(&function, object, context, url, lineNumber, columnNumber); + newBinding->setTarget(object, *property, context); + newBinding->setEvaluateFlags(newBinding->evaluateFlags() | + QQmlBinding::RequiresThisObject); + } } QQmlAbstractBinding *oldBinding = @@ -603,6 +633,12 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert if (oldBinding) oldBinding->destroy(); + if (!newBinding && property->isVMEProperty()) { + // allow assignment of "special" values (null, undefined, function) to var properties + static_cast<QQmlVMEMetaObject *>(const_cast<QMetaObject *>(object->metaObject()))->setVMEProperty(property->coreIndex, value); + return; + } + #define PROPERTY_STORE(cpptype, value) \ cpptype o = value; \ int status = -1; \ @@ -649,10 +685,14 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert if (v.userType() == QVariant::Invalid) valueType = "null"; else valueType = QMetaType::typeName(v.userType()); + const char *targetTypeName = QMetaType::typeName(property->propType); + if (!targetTypeName) + targetTypeName = "an unregistered type"; + QString error = QLatin1String("Cannot assign ") + QLatin1String(valueType) + QLatin1String(" to ") + - QLatin1String(QMetaType::typeName(property->propType)); + QLatin1String(targetTypeName); v8::ThrowException(v8::Exception::Error(engine->toString(error))); } } @@ -1640,16 +1680,6 @@ static inline int QMetaObject_methods(const QMetaObject *metaObject) return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount; } -static QByteArray QMetaMethod_name(const QMetaMethod &m) -{ - QByteArray sig = m.signature(); - int paren = sig.indexOf('('); - if (paren == -1) - return sig; - else - return sig.left(paren); -} - /*! Returns the next related method, if one, or 0. */ @@ -1678,9 +1708,9 @@ static const QQmlPropertyData * RelatedMethod(QObject *object, dummy.load(method); // Look for overloaded methods - QByteArray methodName = QMetaMethod_name(method); + QByteArray methodName = method.name(); for (int ii = current->overrideIndex - 1; ii >= methodOffset; --ii) { - if (methodName == QMetaMethod_name(mo->method(ii))) { + if (methodName == mo->method(ii).name()) { dummy.setFlags(dummy.getFlags() | QQmlPropertyData::IsOverload); dummy.overrideIndexIsProperty = 0; dummy.overrideIndex = ii; @@ -1794,7 +1824,7 @@ static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QQmlPropertyD const QQmlPropertyData *candidate = &data; while (candidate) { error += QLatin1String("\n ") + - QString::fromUtf8(object->metaObject()->method(candidate->coreIndex).signature()); + QString::fromUtf8(object->metaObject()->method(candidate->coreIndex).methodSignature().constData()); candidate = RelatedMethod(object, candidate, dummy); } @@ -1963,7 +1993,7 @@ void *CallArgument::dataPtr() void CallArgument::initAsType(int callType) { if (type != 0) { cleanup(); type = 0; } - if (callType == 0) return; + if (callType == QMetaType::UnknownType) return; if (callType == qMetaTypeId<QJSValue>()) { qjsValuePtr = new (&allocData) QJSValue(); @@ -1989,6 +2019,9 @@ void CallArgument::initAsType(int callType) } else if (callType == qMetaTypeId<QQmlV8Handle>()) { type = callType; handlePtr = new (&allocData) QQmlV8Handle; + } else if (callType == QMetaType::Void) { + type = -1; + qvariantPtr = new (&allocData) QVariant(); } else { type = -1; qvariantPtr = new (&allocData) QVariant(callType, (void *)0); @@ -2043,6 +2076,8 @@ void CallArgument::fromValue(int callType, QV8Engine *engine, v8::Handle<v8::Val } else if (callType == qMetaTypeId<QQmlV8Handle>()) { handlePtr = new (&allocData) QQmlV8Handle(QQmlV8Handle::fromHandle(value)); type = callType; + } else if (callType == QMetaType::Void) { + *qvariantPtr = QVariant(); } else { qvariantPtr = new (&allocData) QVariant(); type = -1; diff --git a/src/qml/qml/v8/qv8valuetypewrapper.cpp b/src/qml/qml/v8/qv8valuetypewrapper.cpp index 7a3c675d49..cf2c13fce9 100644 --- a/src/qml/qml/v8/qv8valuetypewrapper.cpp +++ b/src/qml/qml/v8/qv8valuetypewrapper.cpp @@ -324,6 +324,13 @@ v8::Handle<v8::Value> QV8ValueTypeWrapper::Setter(v8::Local<v8::String> property QQmlBinding *newBinding = 0; if (value->IsFunction()) { + if (value->ToObject()->GetHiddenValue(r->engine->bindingFlagKey()).IsEmpty()) { + // assigning a JS function to a non-var-property is not allowed. + QString error = QLatin1String("Cannot assign JavaScript function to value-type property"); + v8::ThrowException(v8::Exception::Error(r->engine->toString(error))); + return value; + } + QQmlContextData *context = r->engine->callingContext(); v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value); |