X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fqml%2Fqml%2Fqqmlpropertycache.cpp;h=50674fa1e42442f994b854e3ee11b36c84006b43;hb=7223f1861d3309d336123c90866665cfe2507d7f;hp=1e8cfb6c2095d425f9b0250eafa13d486caaaf80;hpb=a896d4b39ec3d45ba708d9b36ea9c864b1df2136;p=profile%2Fivi%2Fqtdeclarative.git diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 1e8cfb6..50674fa 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -41,16 +41,25 @@ #include "qqmlpropertycache_p.h" -#include "qqmlengine_p.h" -#include "qqmlbinding_p.h" +#include +#include +#include #include #include #include +#include +#include #include #include // for toupper +#include + +#ifdef Q_CC_MSVC +// nonstandard extension used : zero-sized array in struct/union. +# pragma warning( disable : 4200 ) +#endif Q_DECLARE_METATYPE(QJSValue) Q_DECLARE_METATYPE(QQmlV8Handle); @@ -59,10 +68,18 @@ QT_BEGIN_NAMESPACE #define Q_INT16_MAX 32767 -class QQmlPropertyCacheMethodArguments +class QQmlPropertyCacheMethodArguments { public: QQmlPropertyCacheMethodArguments *next; + + //for signal handler rewrites + QString *signalParameterStringForJS; + int signalParameterCountForJS:30; + int parameterError:1; + int argumentsValid:1; + + QList *names; int arguments[0]; }; @@ -86,7 +103,7 @@ static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p) return flags; } -// Flags that do depend on the property's QMetaProperty::userType() and thus are slow to +// Flags that do depend on the property's QMetaProperty::userType() and thus are slow to // load static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *engine) { @@ -94,7 +111,7 @@ static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *en QQmlPropertyData::Flags flags; - if (propType == QMetaType::QObjectStar || propType == QMetaType::QWidgetStar) { + if (propType == QMetaType::QObjectStar) { flags |= QQmlPropertyData::IsQObjectDerived; } else if (propType == QMetaType::QVariant) { flags |= QQmlPropertyData::IsQVariant; @@ -106,7 +123,7 @@ static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *en } else if (propType == qMetaTypeId()) { flags |= QQmlPropertyData::IsV8Handle; } else { - QQmlMetaType::TypeCategory cat = + QQmlMetaType::TypeCategory cat = engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType) : QQmlMetaType::typeCategory(propType); @@ -138,14 +155,14 @@ void QQmlPropertyData::lazyLoad(const QMetaProperty &p, QQmlEngine *engine) Q_UNUSED(engine); coreIndex = p.propertyIndex(); - notifyIndex = p.notifySignalIndex(); + notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal()); Q_ASSERT(p.revision() <= Q_INT16_MAX); revision = p.revision(); flags = fastFlagsForProperty(p); int type = p.type(); - if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) { + if (type == QMetaType::QObjectStar) { propType = type; flags |= QQmlPropertyData::IsQObjectDerived; } else if (type == QMetaType::QVariant) { @@ -163,7 +180,7 @@ void QQmlPropertyData::load(const QMetaProperty &p, QQmlEngine *engine) { propType = p.userType(); coreIndex = p.propertyIndex(); - notifyIndex = p.notifySignalIndex(); + notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal()); flags = fastFlagsForProperty(p) | flagsForPropertyType(propType, engine); Q_ASSERT(p.revision() <= Q_INT16_MAX); revision = p.revision(); @@ -185,6 +202,9 @@ void QQmlPropertyData::load(const QMetaMethod &m) } } + if (m.attributes() & QMetaMethod::Cloned) + flags |= IsCloned; + Q_ASSERT(m.revision() <= Q_INT16_MAX); revision = m.revision(); } @@ -199,7 +219,8 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m) propType = QMetaType::Void; const char *returnType = m.typeName(); - Q_ASSERT(returnType != 0); + if (!returnType) + returnType = "\0"; if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) { propTypeName = returnType; flags |= NotFullyResolved; @@ -212,6 +233,9 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m) } } + if (m.attributes() & QMetaMethod::Cloned) + flags |= IsCloned; + Q_ASSERT(m.revision() <= Q_INT16_MAX); revision = m.revision(); } @@ -220,8 +244,9 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m) Creates a new empty QQmlPropertyCache. */ QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e) -: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), - signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0) +: engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), + signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false), + _metaObject(0), argumentsCache(0) { Q_ASSERT(engine); } @@ -230,8 +255,9 @@ QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e) Creates a new QQmlPropertyCache of \a metaObject. */ QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e, const QMetaObject *metaObject) -: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), - signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0) +: engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), + signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false), + _metaObject(0), argumentsCache(0) { Q_ASSERT(engine); Q_ASSERT(metaObject); @@ -246,6 +272,8 @@ QQmlPropertyCache::~QQmlPropertyCache() QQmlPropertyCacheMethodArguments *args = argumentsCache; while (args) { QQmlPropertyCacheMethodArguments *next = args->next; + if (args->signalParameterStringForJS) delete args->signalParameterStringForJS; + if (args->names) delete args->names; free(args); args = next; } @@ -253,8 +281,11 @@ QQmlPropertyCache::~QQmlPropertyCache() // We must clear this prior to releasing the parent incase it is a // linked hash stringCache.clear(); - if (parent) parent->release(); - parent = 0; + if (_parent) _parent->release(); + + if (_ownMetaObject) free((void *)_metaObject); + _metaObject = 0; + _parent = 0; engine = 0; } @@ -278,14 +309,15 @@ void QQmlPropertyCache::clear() QQmlPropertyCache *QQmlPropertyCache::copy(int reserve) { QQmlPropertyCache *cache = new QQmlPropertyCache(engine); - cache->parent = this; - cache->parent->addref(); + cache->_parent = this; + cache->_parent->addref(); cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart; cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart; - cache->signalHanderIndexCacheStart = signalHandlerIndexCache.count() + signalHanderIndexCacheStart; + cache->signalHandlerIndexCacheStart = signalHandlerIndexCache.count() + signalHandlerIndexCacheStart; cache->stringCache.linkAndReserve(stringCache, reserve); cache->allowedRevisionCache = allowedRevisionCache; - cache->metaObject = metaObject; + cache->_metaObject = _metaObject; + cache->_defaultPropertyName = _defaultPropertyName; // We specifically do *NOT* copy the constructor @@ -297,6 +329,269 @@ QQmlPropertyCache *QQmlPropertyCache::copy() return copy(0); } +QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(QQmlEngine *, int propertyCount, int methodCount, + int signalCount) +{ + QQmlPropertyCache *rv = copy(propertyCount + methodCount + signalCount); + rv->propertyIndexCache.reserve(propertyCount); + rv->methodIndexCache.reserve(methodCount); + rv->signalHandlerIndexCache.reserve(signalCount); + rv->_metaObject = 0; + + return rv; +} + +/*! \internal + + \a notifyIndex MUST be in the signal index range (see QObjectPrivate::signalIndex()). + This is different from QMetaMethod::methodIndex(). +*/ +void QQmlPropertyCache::appendProperty(const QString &name, + quint32 flags, int coreIndex, int propType, int notifyIndex) +{ + QQmlPropertyData data; + data.propType = propType; + data.coreIndex = coreIndex; + data.notifyIndex = notifyIndex; + data.flags = flags; + + QQmlPropertyData *old = findNamedProperty(name); + if (old) + data.markAsOverrideOf(old); + + int index = propertyIndexCache.count(); + propertyIndexCache.append(data); + + setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != 0)); +} + +void QQmlPropertyCache::appendProperty(const QHashedCStringRef &name, + quint32 flags, int coreIndex, int propType, int notifyIndex) +{ + QQmlPropertyData data; + data.propType = propType; + data.coreIndex = coreIndex; + data.notifyIndex = notifyIndex; + data.flags = flags; + + QQmlPropertyData *old = findNamedProperty(name); + if (old) + data.markAsOverrideOf(old); + + int index = propertyIndexCache.count(); + propertyIndexCache.append(data); + + setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != 0)); +} + +void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int coreIndex, + const int *types, const QList &names) +{ + QQmlPropertyData data; + data.propType = QVariant::Invalid; + data.coreIndex = coreIndex; + data.flags = flags; + data.arguments = 0; + + QQmlPropertyData handler = data; + handler.flags |= QQmlPropertyData::IsSignalHandler; + + if (types) { + int argumentCount = *types; + typedef QQmlPropertyCacheMethodArguments A; + A *args = static_cast(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int))); + ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int)); + args->argumentsValid = true; + args->signalParameterStringForJS = 0; + args->signalParameterCountForJS = 0; + args->parameterError = false; + args->names = new QList(names); + args->next = argumentsCache; + argumentsCache = args; + data.arguments = args; + } + + QQmlPropertyData *old = findNamedProperty(name); + if (old) + data.markAsOverrideOf(old); + + int methodIndex = methodIndexCache.count(); + methodIndexCache.append(data); + + int signalHandlerIndex = signalHandlerIndexCache.count(); + signalHandlerIndexCache.append(handler); + + QString handlerName = QLatin1String("on") + name; + handlerName[2] = handlerName[2].toUpper(); + + setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0)); + setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != 0)); +} + +void QQmlPropertyCache::appendSignal(const QHashedCStringRef &name, quint32 flags, int coreIndex, + const int *types, const QList &names) +{ + QQmlPropertyData data; + data.propType = QVariant::Invalid; + data.coreIndex = coreIndex; + data.flags = flags; + data.arguments = 0; + + QQmlPropertyData handler = data; + handler.flags |= QQmlPropertyData::IsSignalHandler; + + if (types) { + int argumentCount = *types; + typedef QQmlPropertyCacheMethodArguments A; + A *args = static_cast(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int))); + ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int)); + args->argumentsValid = true; + args->signalParameterStringForJS = 0; + args->signalParameterCountForJS = 0; + args->parameterError = false; + args->names = new QList(names); + args->next = argumentsCache; + argumentsCache = args; + data.arguments = args; + } + + QQmlPropertyData *old = findNamedProperty(name); + if (old) + data.markAsOverrideOf(old); + + int methodIndex = methodIndexCache.count(); + methodIndexCache.append(data); + + int signalHandlerIndex = signalHandlerIndexCache.count(); + signalHandlerIndexCache.append(handler); + + QString handlerName = QLatin1String("on") + name.toUtf16(); + handlerName[2] = handlerName[2].toUpper(); + + setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0)); + setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != 0)); +} + +void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int coreIndex, + const QList &names) +{ + int argumentCount = names.count(); + + QQmlPropertyData data; + data.propType = QMetaType::QVariant; + data.coreIndex = coreIndex; + + typedef QQmlPropertyCacheMethodArguments A; + A *args = static_cast(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int))); + args->arguments[0] = argumentCount; + for (int ii = 0; ii < argumentCount; ++ii) + args->arguments[ii + 1] = QMetaType::QVariant; + args->argumentsValid = true; + args->signalParameterStringForJS = 0; + args->signalParameterCountForJS = 0; + args->parameterError = false; + args->names = 0; + if (argumentCount) + args->names = new QList(names); + args->next = argumentsCache; + argumentsCache = args; + data.arguments = args; + + data.flags = flags; + + QQmlPropertyData *old = findNamedProperty(name); + if (old) + data.markAsOverrideOf(old); + + int methodIndex = methodIndexCache.count(); + methodIndexCache.append(data); + + setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0)); +} + +void QQmlPropertyCache::appendMethod(const QHashedCStringRef &name, quint32 flags, int coreIndex, + const QList &names) +{ + int argumentCount = names.count(); + + QQmlPropertyData data; + data.propType = QMetaType::QVariant; + data.coreIndex = coreIndex; + + typedef QQmlPropertyCacheMethodArguments A; + A *args = static_cast(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int))); + args->arguments[0] = argumentCount; + for (int ii = 0; ii < argumentCount; ++ii) + args->arguments[ii + 1] = QMetaType::QVariant; + args->argumentsValid = true; + args->signalParameterStringForJS = 0; + args->signalParameterCountForJS = 0; + args->parameterError = false; + args->names = 0; + if (argumentCount) + args->names = new QList(names); + args->next = argumentsCache; + argumentsCache = args; + data.arguments = args; + + data.flags = flags; + + QQmlPropertyData *old = findNamedProperty(name); + if (old) + data.markAsOverrideOf(old); + + int methodIndex = methodIndexCache.count(); + methodIndexCache.append(data); + + setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0)); +} + +// Returns this property cache's metaObject. May be null if it hasn't been created yet. +const QMetaObject *QQmlPropertyCache::metaObject() const +{ + return _metaObject; +} + +// Returns this property cache's metaObject, creating it if necessary. +const QMetaObject *QQmlPropertyCache::createMetaObject() +{ + if (!_metaObject) { + _ownMetaObject = true; + + QMetaObjectBuilder builder; + toMetaObjectBuilder(builder); + builder.setSuperClass(_parent->createMetaObject()); + _metaObject = builder.toMetaObject(); + } + + return _metaObject; +} + +// Returns the name of the default property for this cache +QString QQmlPropertyCache::defaultPropertyName() const +{ + return _defaultPropertyName; +} + +QQmlPropertyData *QQmlPropertyCache::defaultProperty() const +{ + return property(defaultPropertyName(), 0, 0); +} + +QQmlPropertyCache *QQmlPropertyCache::parent() const +{ + return _parent; +} + +// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by +// QML +const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const +{ + while (_parent && (_metaObject == 0 || _ownMetaObject)) + return _parent->firstCppMetaObject(); + return _metaObject; +} + QQmlPropertyCache * QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject, QQmlPropertyData::Flag propertyFlags, @@ -327,16 +622,8 @@ QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObje return rv; } -void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject, - QQmlPropertyData::Flag propertyFlags, - QQmlPropertyData::Flag methodFlags, - QQmlPropertyData::Flag signalFlags) -{ - append(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags); -} - -void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject, - int revision, +void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject, + int revision, QQmlPropertyData::Flag propertyFlags, QQmlPropertyData::Flag methodFlags, QQmlPropertyData::Flag signalFlags) @@ -344,7 +631,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject Q_UNUSED(revision); Q_ASSERT(constructor.IsEmpty()); // We should not be appending to an in-use property cache - this->metaObject = metaObject; + _metaObject = metaObject; bool dynamicMetaObject = isDynamicMetaObject(metaObject); @@ -357,10 +644,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject QQmlAccessorProperties::Properties accessorProperties; - // Special case QObject as we don't want to add a qt_HasQmlAccessors classinfo to it - if (metaObject == &QObject::staticMetaObject) { - accessorProperties = QQmlAccessorProperties::properties(metaObject); - } else if (classInfoCount) { + if (classInfoCount) { int classInfoOffset = metaObject->classInfoOffset(); bool hasFastProperty = false; for (int ii = 0; ii < classInfoCount; ++ii) { @@ -368,7 +652,8 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) { hasFastProperty = true; - break; + } else if (0 == qstrcmp(metaObject->classInfo(idx).name(), "DefaultProperty")) { + _defaultPropertyName = QString::fromUtf8(metaObject->classInfo(idx).value()); } } @@ -387,34 +672,33 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject } } - // qMax(defaultMethods, methodOffset) to block the signals and slots of QObject::staticMetaObject - // incl. destroyed signals, objectNameChanged signal, deleteLater slot, _q_reregisterTimers slot. - int methodOffset = qMax(QObject::staticMetaObject.methodCount(), metaObject->methodOffset()); + //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML + static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)"); + static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()"); + static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()"); + + int methodOffset = metaObject->methodOffset(); int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount; // update() should have reserved enough space in the vector that this doesn't cause a realloc // and invalidate the stringCache. methodIndexCache.resize(methodCount - methodIndexCacheStart); - signalHandlerIndexCache.resize(signalCount - signalHanderIndexCacheStart); + signalHandlerIndexCache.resize(signalCount - signalHandlerIndexCacheStart); int signalHandlerIndex = signalOffset; for (int ii = methodOffset; ii < methodCount; ++ii) { + if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx) + continue; QMetaMethod m = metaObject->method(ii); - if (m.access() == QMetaMethod::Private) + if (m.access() == QMetaMethod::Private) continue; // Extract method name - 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; + // It's safe to keep the raw name pointer + Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 7); + const char *rawName = m.name().constData(); + const char *cptr = rawName; char utf8 = 0; - while (*cptr && *cptr != '(') { - Q_ASSERT(*cptr != 0); + while (*cptr) { utf8 |= *cptr & 0x80; ++cptr; } @@ -436,7 +720,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject data->metaObjectOffset = allowedRevisionCache.count() - 1; if (data->isSignal()) { - sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHanderIndexCacheStart]; + sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart]; *sigdata = *data; sigdata->flags |= QQmlPropertyData::IsSignalHandler; } @@ -444,21 +728,21 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject QQmlPropertyData *old = 0; if (utf8) { - QHashedString methodName(QString::fromUtf8(signature, cptr - signature)); - if (QQmlPropertyData **it = stringCache.value(methodName)) - old = *it; - stringCache.insert(methodName, data); + QHashedString methodName(QString::fromUtf8(rawName, cptr - rawName)); + if (StringCache::mapped_type *it = stringCache.value(methodName)) + old = it->second; + setNamedProperty(methodName, ii, data, (old != 0)); if (data->isSignal()) { QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1)); - stringCache.insert(on, sigdata); + setNamedProperty(on, ii, sigdata, (old != 0)); ++signalHandlerIndex; } } else { - QHashedCStringRef methodName(signature, cptr - signature); - if (QQmlPropertyData **it = stringCache.value(methodName)) - old = *it; - stringCache.insert(methodName, data); + QHashedCStringRef methodName(rawName, cptr - rawName); + if (StringCache::mapped_type *it = stringCache.value(methodName)) + old = it->second; + setNamedProperty(methodName, ii, data, (old != 0)); if (data->isSignal()) { int length = methodName.length(); @@ -466,13 +750,13 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject QVarLengthArray str(length+3); str[0] = 'o'; str[1] = 'n'; - str[2] = toupper(signature[0]); + str[2] = toupper(rawName[0]); if (length > 1) - memcpy(&str[3], &signature[1], length - 1); + memcpy(&str[3], &rawName[1], length - 1); str[length + 2] = '\0'; QHashedString on(QString::fromLatin1(str.data())); - stringCache.insert(on, sigdata); + setNamedProperty(on, ii, data, (old != 0)); ++signalHandlerIndex; } } @@ -481,8 +765,8 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject // We only overload methods in the same class, exactly like C++ if (old->isFunction() && old->coreIndex >= methodOffset) data->flags |= QQmlPropertyData::IsOverload; - data->overrideIndexIsProperty = !old->isFunction(); - data->overrideIndex = old->coreIndex; + + data->markAsOverrideOf(old); } } @@ -510,7 +794,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject data->lazyLoad(p, engine); data->flags |= propertyFlags; - if (!dynamicMetaObject) + if (!dynamicMetaObject) data->flags |= QQmlPropertyData::IsDirect; Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX); @@ -520,14 +804,14 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject if (utf8) { QHashedString propName(QString::fromUtf8(str, cptr - str)); - if (QQmlPropertyData **it = stringCache.value(propName)) - old = *it; - stringCache.insert(propName, data); + if (StringCache::mapped_type *it = stringCache.value(propName)) + old = it->second; + setNamedProperty(propName, ii, data, (old != 0)); } else { QHashedCStringRef propName(str, cptr - str); - if (QQmlPropertyData **it = stringCache.value(propName)) - old = *it; - stringCache.insert(propName, data); + if (StringCache::mapped_type *it = stringCache.value(propName)) + old = it->second; + setNamedProperty(propName, ii, data, (old != 0)); } QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str); @@ -540,12 +824,19 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject data->accessors = accessorProperty->accessors; data->accessorData = accessorProperty->data; } else if (old) { - data->overrideIndexIsProperty = !old->isFunction(); - data->overrideIndex = old->coreIndex; + data->markAsOverrideOf(old); } } } +QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p) const +{ + if (p && p->notFullyResolved()) + resolve(p); + + return p; +} + void QQmlPropertyCache::resolve(QQmlPropertyData *data) const { Q_ASSERT(data->notFullyResolved()); @@ -565,7 +856,7 @@ void QQmlPropertyCache::updateRecur(QQmlEngine *engine, const QMetaObject *metaO updateRecur(engine, metaObject->superClass()); - append(engine, metaObject); + append(engine, metaObject, -1); } void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject) @@ -582,7 +873,7 @@ void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject int sc = metaObjectSignalCount(metaObject); propertyIndexCache.reserve(pc - propertyIndexCacheStart); methodIndexCache.reserve(mc - methodIndexCacheStart); - signalHandlerIndexCache.reserve(sc - signalHanderIndexCacheStart); + signalHandlerIndexCache.reserve(sc - signalHandlerIndexCacheStart); // Reserve enough space in the stringCache for all properties/methods/signals including those // cached in a parent cache. @@ -591,18 +882,48 @@ void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject updateRecur(engine,metaObject); } +/*! \internal + \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()). + This is different from QMetaMethod::methodIndex(). +*/ +QQmlPropertyData * +QQmlPropertyCache::signal(int index, QQmlPropertyCache **c) const +{ + if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count())) + return 0; + + if (index < signalHandlerIndexCacheStart) + return _parent->signal(index, c); + + QQmlPropertyData *rv = const_cast(&methodIndexCache.at(index - signalHandlerIndexCacheStart)); + if (rv->notFullyResolved()) resolve(rv); + Q_ASSERT(rv->isSignal() || rv->coreIndex == -1); + if (c) *c = const_cast(this); + return rv; +} + +int QQmlPropertyCache::methodIndexToSignalIndex(int index) const +{ + if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count())) + return index; + + if (index < methodIndexCacheStart) + return _parent->methodIndexToSignalIndex(index); + + return index - methodIndexCacheStart + signalHandlerIndexCacheStart; +} + QQmlPropertyData * QQmlPropertyCache::property(int index) const { if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count())) return 0; - + if (index < propertyIndexCacheStart) - return parent->property(index); + return _parent->property(index); QQmlPropertyData *rv = const_cast(&propertyIndexCache.at(index - propertyIndexCacheStart)); - if (rv->notFullyResolved()) resolve(rv); - return rv; + return ensureResolved(rv); } QQmlPropertyData * @@ -612,35 +933,63 @@ QQmlPropertyCache::method(int index) const return 0; if (index < methodIndexCacheStart) - return parent->method(index); + return _parent->method(index); QQmlPropertyData *rv = const_cast(&methodIndexCache.at(index - methodIndexCacheStart)); - if (rv->notFullyResolved()) resolve(rv); - return rv; + return ensureResolved(rv); } -QQmlPropertyData * -QQmlPropertyCache::property(const QHashedStringRef &str) const +QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, QObject *object, QQmlContextData *context) const { - QQmlPropertyData **rv = stringCache.value(str); - if (rv && (*rv)->notFullyResolved()) resolve(*rv); - return rv?*rv:0; + QQmlData *data = (object ? QQmlData::get(object) : 0); + const QQmlVMEMetaObject *vmemo = (data && data->hasVMEMetaObject ? static_cast(object->metaObject()) : 0); + return findProperty(it, vmemo, context); } -QQmlPropertyData * -QQmlPropertyCache::property(const QHashedCStringRef &str) const +namespace { + +inline bool contextHasNoExtensions(QQmlContextData *context) { - QQmlPropertyData **rv = stringCache.value(str); - if (rv && (*rv)->notFullyResolved()) resolve(*rv); - return rv?*rv:0; + // This context has no extension if its parent is the engine's rootContext, + // which has children but no imports + return (!context->parent || !context->parent->imports); } -QQmlPropertyData * -QQmlPropertyCache::property(const QString &str) const +inline int maximumIndexForProperty(QQmlPropertyData *prop, const QQmlVMEMetaObject *vmemo) +{ + return (prop->isFunction() ? vmemo->methodCount() + : prop->isSignalHandler() ? vmemo->signalCount() + : vmemo->propertyCount()); +} + +} + +QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *vmemo, QQmlContextData *context) const { - QQmlPropertyData **rv = stringCache.value(str); - if (rv && (*rv)->notFullyResolved()) resolve(*rv); - return rv?*rv:0; + StringCache::ConstIterator end = stringCache.end(); + + if (it != end) { + if (vmemo && context && !contextHasNoExtensions(context)) { + // Find the highest property offset known to the supplied context + do { + if (vmemo->ctxt == context) + break; + + vmemo = vmemo->parentVMEMetaObject(); + } while (vmemo); + } + + do { + // Is this property available to this context? + const StringCache::mapped_type &property(it.value()); + if (!vmemo || (property.first < maximumIndexForProperty(property.second, vmemo))) + return ensureResolved(property.second); + + it = stringCache.findNext(it); + } while (it != end); + } + + return 0; } QString QQmlPropertyData::name(QObject *object) @@ -666,10 +1015,18 @@ QString QQmlPropertyData::name(const QMetaObject *metaObject) } } +void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor) +{ + overrideIndexIsProperty = !predecessor->isFunction(); + overrideIndex = predecessor->coreIndex; + + predecessor->flags |= QQmlPropertyData::IsOverridden; +} + QStringList QQmlPropertyCache::propertyNames() const { QStringList keys; - for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) + for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) keys.append(iter.key()); return keys; } @@ -688,7 +1045,7 @@ static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type) if (scopeIdx != -1) { scope = str.left(scopeIdx); name = str.mid(scopeIdx + 2); - } else { + } else { name = str; } const QMetaObject *meta; @@ -704,9 +1061,72 @@ static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type) return type; } +/*! \internal + \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()). + This is different from QMetaMethod::methodIndex(). +*/ +QString QQmlPropertyCache::signalParameterStringForJS(int index, int *count, QString *errorString) +{ + QQmlPropertyCache *c = 0; + QQmlPropertyData *signalData = signal(index, &c); + if (!signalData) + return QString(); + + typedef QQmlPropertyCacheMethodArguments A; + + if (signalData->arguments) { + A *arguments = static_cast(signalData->arguments); + if (arguments->signalParameterStringForJS) { + if (count) + *count = arguments->signalParameterCountForJS; + if (arguments->parameterError) { + if (errorString) + *errorString = *arguments->signalParameterStringForJS; + return QString(); + } + return *arguments->signalParameterStringForJS; + } + } + + QList parameterNameList = signalParameterNames(index); + + if (!signalData->arguments) { + int argc = parameterNameList.count(); + A *args = static_cast(malloc(sizeof(A) + (argc + 1) * sizeof(int))); + args->arguments[0] = argc; + args->argumentsValid = false; + args->signalParameterStringForJS = 0; + args->signalParameterCountForJS = 0; + args->parameterError = false; + args->names = new QList(parameterNameList); + signalData->arguments = args; + args->next = c->argumentsCache; + c->argumentsCache = args; + } + + QQmlRewrite::RewriteSignalHandler rewriter; + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); + const QString ¶meters = rewriter.createParameterString(parameterNameList, + ep->v8engine()->illegalNames()); + + bool error = rewriter.hasParameterError(); + A *arguments = static_cast(signalData->arguments); + arguments->signalParameterStringForJS = new QString(error ? rewriter.parameterError() : parameters); + arguments->signalParameterCountForJS = rewriter.parameterCountForJS(); + if (count) + *count = arguments->signalParameterCountForJS; + if (error) { + arguments->parameterError = true; + if (errorString) + *errorString = *arguments->signalParameterStringForJS; + return QString(); + } + return *arguments->signalParameterStringForJS; +} + // Returns an array of the arguments for method \a index. The first entry in the array // is the number of arguments. -int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, +int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, QVarLengthArray &dummy, QByteArray *unknownTypeError) { @@ -721,19 +1141,32 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count()); while (index < c->methodIndexCacheStart) - c = c->parent; + c = c->_parent; QQmlPropertyData *rv = const_cast(&c->methodIndexCache.at(index - c->methodIndexCacheStart)); - if (rv->arguments) + if (rv->arguments && static_cast(rv->arguments)->argumentsValid) return static_cast(rv->arguments)->arguments; - const QMetaObject *metaObject = object->metaObject(); + const QMetaObject *metaObject = c->createMetaObject(); + Q_ASSERT(metaObject); QMetaMethod m = metaObject->method(index); int argc = m.parameterCount(); - A *args = static_cast(malloc(sizeof(A) + (argc + 1) * sizeof(int))); - args->arguments[0] = argc; + if (!rv->arguments) { + A *args = static_cast(malloc(sizeof(A) + (argc + 1) * sizeof(int))); + args->arguments[0] = argc; + args->argumentsValid = false; + args->signalParameterStringForJS = 0; + args->signalParameterCountForJS = 0; + args->parameterError = false; + args->names = 0; + rv->arguments = args; + args->next = c->argumentsCache; + c->argumentsCache = args; + } + A *args = static_cast(rv->arguments); + QList argTypeNames; // Only loaded if needed for (int ii = 0; ii < argc; ++ii) { @@ -751,15 +1184,11 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, } if (type == QMetaType::UnknownType) { if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii); - free(args); return 0; } args->arguments[ii + 1] = type; } - - rv->arguments = args; - args->next = c->argumentsCache; - c->argumentsCache = args; + args->argumentsValid = true; return static_cast(rv->arguments)->arguments; } else { @@ -793,8 +1222,78 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, } } -QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, - const QString &property) +// Returns the return type of the method. +int QQmlPropertyCache::methodReturnType(QObject *object, const QQmlPropertyData &data, + QByteArray *unknownTypeError) +{ + Q_ASSERT(object && data.coreIndex >= 0); + + int type = data.propType; + + const char *propTypeName = 0; + + if (type == QMetaType::UnknownType) { + // Find the return type name from the method info + QMetaMethod m; + + QQmlData *ddata = QQmlData::get(object, false); + if (ddata && ddata->propertyCache) { + QQmlPropertyCache *c = ddata->propertyCache; + Q_ASSERT(data.coreIndex < c->methodIndexCacheStart + c->methodIndexCache.count()); + + while (data.coreIndex < c->methodIndexCacheStart) + c = c->_parent; + + const QMetaObject *metaObject = c->createMetaObject(); + Q_ASSERT(metaObject); + m = metaObject->method(data.coreIndex); + } else { + m = object->metaObject()->method(data.coreIndex); + } + + type = m.returnType(); + propTypeName = m.typeName(); + } + + QMetaType::TypeFlags flags = QMetaType::typeFlags(type); + if (flags & QMetaType::IsEnumeration) { + type = QVariant::Int; + } else if (type == QMetaType::UnknownType || + (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) && + type != qMetaTypeId())) { + //the UserType clause is to catch registered QFlags + type = EnumType(object->metaObject(), propTypeName, type); + } + + if (type == QMetaType::UnknownType) { + if (unknownTypeError) *unknownTypeError = propTypeName; + } + + return type; +} + +int QQmlPropertyCache::originalClone(int index) +{ + while (signal(index)->isCloned()) + --index; + return index; +} + +int QQmlPropertyCache::originalClone(QObject *object, int index) +{ + QQmlData *data = QQmlData::get(object, false); + if (data && data->propertyCache) { + QQmlPropertyCache *cache = data->propertyCache; + while (cache->signal(index)->isCloned()) + --index; + } else { + while (QMetaObjectPrivate::signal(object->metaObject(), index).attributes() & QMetaMethod::Cloned) + --index; + } + return index; +} + +QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QString &property) { Q_ASSERT(metaObject); @@ -819,11 +1318,15 @@ QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, } } + //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML + static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)"); + static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()"); + static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()"); + int methodCount = metaObject->methodCount(); - int defaultMethods = QObject::staticMetaObject.methodCount(); - for (int ii = methodCount - 1; ii >= defaultMethods; --ii) { - // >=defaultMethods to block the signals and slots of QObject::staticMetaObject - // incl. destroyed signals, objectNameChanged signal, deleteLater slot, _q_reregisterTimers slot. + for (int ii = methodCount - 1; ii >= 0; --ii) { + if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx) + continue; QMetaMethod m = metaObject->method(ii); if (m.access() == QMetaMethod::Private) continue; @@ -850,34 +1353,31 @@ inline QString qQmlPropertyCacheToString(const QHashedV8String &string) template QQmlPropertyData * -qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, - const T &name, QQmlPropertyData &local) +qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name, + QQmlContextData *context, QQmlPropertyData &local) { QQmlPropertyCache *cache = 0; - if (engine) { - QQmlData *ddata = QQmlData::get(obj); + QQmlData *ddata = QQmlData::get(obj, false); - if (ddata && ddata->propertyCache) { - cache = ddata->propertyCache; - } else if (engine) { - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); - cache = ep->cache(obj); - if (cache) { - ddata = QQmlData::get(obj, true); - cache->addref(); - ddata->propertyCache = cache; - } + if (ddata && ddata->propertyCache) { + cache = ddata->propertyCache; + } else if (engine) { + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); + cache = ep->cache(obj); + if (cache) { + ddata = QQmlData::get(obj, true); + cache->addref(); + ddata->propertyCache = cache; } } QQmlPropertyData *rv = 0; if (cache) { - rv = cache->property(name); + rv = cache->property(name, obj, context); } else { - local = qQmlPropertyCacheCreate(obj->metaObject(), - qQmlPropertyCacheToString(name)); + local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name)); if (local.isValid()) rv = &local; } @@ -886,17 +1386,17 @@ qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, } QQmlPropertyData * -QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, - const QHashedV8String &name, QQmlPropertyData &local) +QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, const QHashedV8String &name, + QQmlContextData *context, QQmlPropertyData &local) { - return qQmlPropertyCacheProperty(engine, obj, name, local); + return qQmlPropertyCacheProperty(engine, obj, name, context, local); } QQmlPropertyData * QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, - const QString &name, QQmlPropertyData &local) + const QString &name, QQmlContextData *context, QQmlPropertyData &local) { - return qQmlPropertyCacheProperty(engine, obj, name, local); + return qQmlPropertyCacheProperty(engine, obj, name, context, local); } static inline const QMetaObjectPrivate *priv(const uint* data) @@ -907,4 +1407,198 @@ bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo) return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject; } +const char *QQmlPropertyCache::className() const +{ + if (!_ownMetaObject && _metaObject) + return _metaObject->className(); + else + return _dynamicClassName.constData(); +} + +void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) +{ + struct Sort { static bool lt(const QPair &lhs, + const QPair &rhs) { + return lhs.second->coreIndex < rhs.second->coreIndex; + } }; + + struct Insert { static void in(QQmlPropertyCache *This, + QList > &properties, + QList > &methods, + StringCache::ConstIterator iter, QQmlPropertyData *data) { + if (data->isSignalHandler()) + return; + + if (data->isFunction()) { + if (data->coreIndex < This->methodIndexCacheStart) + return; + + QPair entry = qMakePair((QString)iter.key(), data); + // Overrides can cause the entry to already exist + if (!methods.contains(entry)) methods.append(entry); + + data = This->overrideData(data); + if (data && !data->isFunction()) Insert::in(This, properties, methods, iter, data); + } else { + if (data->coreIndex < This->propertyIndexCacheStart) + return; + + QPair entry = qMakePair((QString)iter.key(), data); + // Overrides can cause the entry to already exist + if (!properties.contains(entry)) properties.append(entry); + + data = This->overrideData(data); + if (data) Insert::in(This, properties, methods, iter, data); + } + + } }; + + builder.setClassName(_dynamicClassName); + + QList > properties; + QList > methods; + + for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) + Insert::in(this, properties, methods, iter, iter.value().second); + + Q_ASSERT(properties.count() == propertyIndexCache.count()); + Q_ASSERT(methods.count() == methodIndexCache.count()); + + qSort(properties.begin(), properties.end(), Sort::lt); + qSort(methods.begin(), methods.end(), Sort::lt); + + for (int ii = 0; ii < properties.count(); ++ii) { + QQmlPropertyData *data = properties.at(ii).second; + + int notifierId = -1; + if (data->notifyIndex != -1) + notifierId = data->notifyIndex - signalHandlerIndexCacheStart; + + QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(), + QMetaType::typeName(data->propType), + notifierId); + + property.setReadable(true); + property.setWritable(data->isWritable()); + property.setResettable(data->isResettable()); + } + + for (int ii = 0; ii < methods.count(); ++ii) { + QQmlPropertyData *data = methods.at(ii).second; + + QByteArray returnType; + if (data->propType != 0) + returnType = QMetaType::typeName(data->propType); + + QByteArray signature = methods.at(ii).first.toUtf8() + "("; + + QQmlPropertyCacheMethodArguments *arguments = 0; + if (data->hasArguments()) { + arguments = (QQmlPropertyCacheMethodArguments *)data->arguments; + Q_ASSERT(arguments->argumentsValid); + for (int ii = 0; ii < arguments->arguments[0]; ++ii) { + if (ii != 0) signature.append(","); + signature.append(QMetaType::typeName(arguments->arguments[1 + ii])); + } + } + + signature.append(")"); + + QMetaMethodBuilder method; + if (data->isSignal()) { + method = builder.addSignal(signature); + } else { + method = builder.addSlot(signature); + } + method.setAccess(QMetaMethod::Protected); + + if (arguments && arguments->names) + method.setParameterNames(*arguments->names); + + if (!returnType.isEmpty()) + method.setReturnType(returnType); + } + + if (!_defaultPropertyName.isEmpty()) { + QQmlPropertyData *dp = property(_defaultPropertyName, 0, 0); + if (dp && dp->coreIndex >= propertyIndexCacheStart) { + Q_ASSERT(!dp->isFunction()); + builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8()); + } + } +} + +/*! \internal + \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()). + This is different from QMetaMethod::methodIndex(). +*/ +QList QQmlPropertyCache::signalParameterNames(int index) const +{ + QQmlPropertyData *signalData = signal(index); + if (signalData && signalData->hasArguments()) { + QQmlPropertyCacheMethodArguments *args = (QQmlPropertyCacheMethodArguments *)signalData->arguments; + if (args && args->names) + return *args->names; + const QMetaMethod &method = QMetaObjectPrivate::signal(firstCppMetaObject(), index); + return method.parameterNames(); + } + return QList(); +} + +// Returns true if \a from is assignable to a property of type \a to +bool QQmlMetaObject::canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to) +{ + Q_ASSERT(!from.isNull() && !to.isNull()); + + struct I { static bool equal(const QMetaObject *lhs, const QMetaObject *rhs) { + return lhs == rhs || (lhs && rhs && lhs->d.stringdata == rhs->d.stringdata); + } }; + + const QMetaObject *tom = to._m.isT1()?to._m.asT1()->metaObject():to._m.asT2(); + if (tom == &QObject::staticMetaObject) return true; + + if (from._m.isT1() && to._m.isT1()) { // QQmlPropertyCache -> QQmlPropertyCache + QQmlPropertyCache *fromp = from._m.asT1(); + QQmlPropertyCache *top = to._m.asT1(); + + while (fromp) { + if (fromp == top) return true; + fromp = fromp->parent(); + } + } else if (from._m.isT1() && to._m.isT2()) { // QQmlPropertyCache -> QMetaObject + QQmlPropertyCache *fromp = from._m.asT1(); + + while (fromp) { + const QMetaObject *fromm = fromp->metaObject(); + if (fromm && I::equal(fromm, tom)) return true; + fromp = fromp->parent(); + } + } else if (from._m.isT2() && to._m.isT1()) { // QMetaObject -> QQmlPropertyCache + const QMetaObject *fromm = from._m.asT2(); + + if (!tom) return false; + + while (fromm) { + if (I::equal(fromm, tom)) return true; + fromm = fromm->superClass(); + } + } else { // QMetaObject -> QMetaObject + const QMetaObject *fromm = from._m.asT2(); + + while (fromm) { + if (I::equal(fromm, tom)) return true; + fromm = fromm->superClass(); + } + } + + return false; +} + +QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const +{ + if (_m.isNull()) return 0; + if (_m.isT1()) return _m.asT1(); + else return e->cache(_m.asT2()); +} + QT_END_NAMESPACE