Fixed memory leak of registered QML modules
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlmetatype.cpp
index 4af08c2..595f9e8 100644 (file)
@@ -1,38 +1,38 @@
 /****************************************************************************
 **
-** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
 **
 ** This file is part of the QtQml module of the Qt Toolkit.
 **
 ** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
 ** 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.
+** Alternatively, 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
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia 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.
-**
-**
-**
-**
+** 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.
 **
 **
 ** $QT_END_LICENSE$
@@ -73,7 +73,7 @@ struct QQmlMetaTypeData
     QList<QQmlType *> types;
     typedef QHash<int, QQmlType *> Ids;
     Ids idToType;
-    typedef QHash<QString, QQmlType *> Names;
+    typedef QHash<QHashedStringRef,QQmlType *> Names;
     Names nameToType;
     typedef QHash<const QMetaObject *, QQmlType *> MetaObjects;
     MetaObjects metaObjectToType;
@@ -83,31 +83,27 @@ struct QQmlMetaTypeData
     struct VersionedUri {
         VersionedUri()
         : majorVersion(0) {}
-        VersionedUri(const QString &uri, int majorVersion)
+        VersionedUri(const QHashedString &uri, int majorVersion)
         : uri(uri), majorVersion(majorVersion) {}
         bool operator==(const VersionedUri &other) const {
             return other.majorVersion == majorVersion && other.uri == uri;
         }
-        QString uri;
+        QHashedString uri;
         int majorVersion;
     };
     typedef QHash<VersionedUri, QQmlTypeModule *> TypeModules;
     TypeModules uriToModule;
 
-    struct ModuleApiList {
-        ModuleApiList() : sorted(true) {}
-        QList<QQmlMetaType::ModuleApi> moduleApis;
-        bool sorted;
-    };
-    typedef QHash<QString, ModuleApiList> ModuleApis;
-    ModuleApis moduleApis;
-    int moduleApiCount;
-
     QBitArray objects;
     QBitArray interfaces;
     QBitArray lists;
 
     QList<QQmlPrivate::AutoParentFunction> parentFunctions;
+
+    QSet<QString> protectedNamespaces;
+
+    QString typeRegistrationNamespace;
+    QStringList typeRegistrationFailures;
 };
 
 class QQmlTypeModulePrivate
@@ -128,15 +124,14 @@ public:
 };
 
 Q_GLOBAL_STATIC(QQmlMetaTypeData, metaTypeData)
-Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock)
+Q_GLOBAL_STATIC_WITH_ARGS(QReadWriteLock, metaTypeDataLock, (QReadWriteLock::Recursive))
 
 static uint qHash(const QQmlMetaTypeData::VersionedUri &v)
 {
-    return qHash(v.uri) ^ qHash(v.majorVersion);
+    return v.uri.hash() ^ qHash(v.majorVersion);
 }
 
 QQmlMetaTypeData::QQmlMetaTypeData()
-: moduleApiCount(0)
 {
 }
 
@@ -144,19 +139,25 @@ QQmlMetaTypeData::~QQmlMetaTypeData()
 {
     for (int i = 0; i < types.count(); ++i)
         delete types.at(i);
+
+    TypeModules::const_iterator i = uriToModule.constBegin();
+    for (; i != uriToModule.constEnd(); ++i)
+        delete *i;
 }
 
 class QQmlTypePrivate
 {
 public:
     QQmlTypePrivate();
+    ~QQmlTypePrivate();
 
     void init() const;
     void initEnums() const;
+    void insertEnums(const QMetaObject *metaObject) const;
 
     bool m_isInterface : 1;
     const char *m_iid;
-    QString m_module;
+    QHashedString m_module;
     QString m_name;
     QString m_elementName;
     int m_version_maj;
@@ -186,10 +187,69 @@ public:
     mutable bool m_haveSuperType:1;
     mutable QList<QQmlProxyMetaObject::ProxyData> m_metaObjects;
     mutable QStringHash<int> m_enums;
+    QQmlType::SingletonInstanceInfo *m_singletonInstanceInfo;
 
     static QHash<const QMetaObject *, int> m_attachedPropertyIds;
 };
 
+// Avoid multiple fromUtf8(), copies and hashing of the module name.
+// This is only called when metaTypeDataLock is locked.
+static QHashedString moduleFromUtf8(const char *module)
+{
+    if (!module)
+        return QHashedString();
+
+    static const char *lastModule = 0;
+    static QHashedString lastModuleStr;
+
+    // Separate plugins may have different strings at the same address
+    QHashedCStringRef currentModule(module, ::strlen(module));
+    if ((lastModule != module) || (lastModuleStr.hash() != currentModule.hash())) {
+        lastModuleStr = QString::fromUtf8(module);
+        lastModuleStr.hash();
+        lastModule = module;
+    }
+
+    return lastModuleStr;
+}
+
+void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
+{
+    if (scriptCallback && scriptApi(e).isUndefined()) {
+        setScriptApi(e, scriptCallback(e, e));
+    } else if (qobjectCallback && !qobjectApi(e)) {
+        setQObjectApi(e, qobjectCallback(e, e));
+    }
+}
+
+void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e)
+{
+    // cleans up the engine-specific singleton instances if they exist.
+    scriptApis.remove(e);
+    QObject *o = qobjectApis.take(e);
+    delete o;
+}
+
+void QQmlType::SingletonInstanceInfo::setQObjectApi(QQmlEngine *e, QObject *o)
+{
+    qobjectApis.insert(e, o);
+}
+
+QObject *QQmlType::SingletonInstanceInfo::qobjectApi(QQmlEngine *e) const
+{
+    return qobjectApis.value(e);
+}
+
+void QQmlType::SingletonInstanceInfo::setScriptApi(QQmlEngine *e, QJSValue v)
+{
+    scriptApis.insert(e, v);
+}
+
+QJSValue QQmlType::SingletonInstanceInfo::scriptApi(QQmlEngine *e) const
+{
+    return scriptApis.value(e);
+}
+
 QHash<const QMetaObject *, int> QQmlTypePrivate::m_attachedPropertyIds;
 
 QQmlTypePrivate::QQmlTypePrivate()
@@ -197,10 +257,14 @@ QQmlTypePrivate::QQmlTypePrivate()
   m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0), 
   m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1), 
   m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0), 
-  m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false)
+  m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false), m_singletonInstanceInfo(0)
 {
 }
 
+QQmlTypePrivate::~QQmlTypePrivate()
+{
+    delete m_singletonInstanceInfo;
+}
 
 QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
 : d(new QQmlTypePrivate)
@@ -216,15 +280,40 @@ QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
     d->m_version_min = 0;
 }
 
-QQmlType::QQmlType(int index, const QQmlPrivate::RegisterType &type)
+QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterSingletonType &type)
 : d(new QQmlTypePrivate)
 {
-    QString name = QString::fromUtf8(type.uri);
-    if (type.uri) name += QLatin1Char('/');
-    name += QString::fromUtf8(type.elementName);
+    d->m_elementName = elementName;
+    d->m_module = moduleFromUtf8(type.uri);
+
+    d->m_version_maj = type.versionMajor;
+    d->m_version_min = type.versionMinor;
+
+    if (type.qobjectApi) {
+        if (type.version >= 1) // static metaobject added in version 1
+            d->m_baseMetaObject = type.instanceMetaObject;
+        if (type.version >= 2) // typeId added in version 2
+            d->m_typeId = type.typeId;
+        if (type.version >= 2) // revisions added in version 2
+            d->m_revision = type.revision;
+    }
+
+    d->m_newFunc = 0;
+    d->m_index = index;
+
+    d->m_singletonInstanceInfo = new SingletonInstanceInfo;
+    d->m_singletonInstanceInfo->scriptCallback = type.scriptApi;
+    d->m_singletonInstanceInfo->qobjectCallback = type.qobjectApi;
+    d->m_singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
+    d->m_singletonInstanceInfo->instanceMetaObject = (type.qobjectApi && type.version >= 1) ? type.instanceMetaObject : 0;
+}
+
+QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterType &type)
+: d(new QQmlTypePrivate)
+{
+    d->m_elementName = elementName;
+    d->m_module = moduleFromUtf8(type.uri);
 
-    d->m_module = QString::fromUtf8(type.uri);
-    d->m_name = name;
     d->m_version_maj = type.versionMajor;
     d->m_version_min = type.versionMinor;
     if (type.version >= 1) // revisions added in version 1
@@ -262,7 +351,7 @@ QQmlType::~QQmlType()
     delete d;
 }
 
-QString QQmlType::module() const
+const QHashedString &QQmlType::module() const
 {
     return d->m_module;
 }
@@ -283,7 +372,7 @@ bool QQmlType::availableInVersion(int vmajor, int vminor) const
     return vmajor == d->m_version_maj && vminor >= d->m_version_min;
 }
 
-bool QQmlType::availableInVersion(const QString &module, int vmajor, int vminor) const
+bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const
 {
     Q_ASSERT(vmajor >= 0 && vminor >= 0);
     return module == d->m_module && vmajor == d->m_version_maj && vminor >= d->m_version_min;
@@ -292,7 +381,7 @@ bool QQmlType::availableInVersion(const QString &module, int vmajor, int vminor)
 // returns the nearest _registered_ super class
 QQmlType *QQmlType::superType() const
 {
-    if (!d->m_haveSuperType) {
+    if (!d->m_haveSuperType && d->m_baseMetaObject) {
         const QMetaObject *mo = d->m_baseMetaObject->superClass();
         while (mo && !d->m_superType) {
             d->m_superType = QQmlMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min);
@@ -398,9 +487,14 @@ void QQmlTypePrivate::init() const
     if (m_isSetup)
         return;
 
+    const QMetaObject *mo = m_baseMetaObject;
+    if (!mo) {
+        // singleton type without metaobject information
+        return;
+    }
+
     // Setup extended meta object
     // XXX - very inefficient
-    const QMetaObject *mo = m_baseMetaObject;
     if (m_extFunc) {
         QMetaObjectBuilder builder;
         clone(builder, m_extMetaObject, m_extMetaObject, m_extMetaObject);
@@ -469,20 +563,35 @@ void QQmlTypePrivate::initEnums() const
     QWriteLocker lock(metaTypeDataLock());
     if (m_isEnumSetup) return;
 
-    const QMetaObject *metaObject = m_baseMetaObject;
-    for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
+    if (m_baseMetaObject) // could be singleton type without metaobject
+        insertEnums(m_baseMetaObject);
 
-        QMetaEnum e = metaObject->enumerator(ii);
+    m_isEnumSetup = true;
+}
 
-        for (int jj = 0; jj < e.keyCount(); ++jj) 
-            m_enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
+void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
+{
+    // Add any enum values defined by 'related' classes
+    if (metaObject->d.relatedMetaObjects) {
+        const QMetaObject **related = metaObject->d.relatedMetaObjects;
+        if (related) {
+            while (*related)
+                insertEnums(*related++);
+        }
     }
 
-    m_isEnumSetup = true;
+    // Add any enum values defined by this class, overwriting any inherited values
+    for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
+        QMetaEnum e = metaObject->enumerator(ii);
+        for (int jj = 0; jj < e.keyCount(); ++jj)
+            m_enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
+    }
 }
 
 QByteArray QQmlType::typeName() const
 {
+    if (d->m_singletonInstanceInfo)
+        return d->m_singletonInstanceInfo->typeName.toUtf8();
     if (d->m_baseMetaObject)
         return d->m_baseMetaObject->className();
     else
@@ -491,16 +600,18 @@ QByteArray QQmlType::typeName() const
 
 const QString &QQmlType::elementName() const
 {
-    if (d->m_elementName.isEmpty()) {
-        QString n = qmlTypeName();
-        int idx = n.lastIndexOf(QLatin1Char('/'));
-        d->m_elementName = n.mid(idx + 1);
-    }
     return d->m_elementName;
 }
 
 const QString &QQmlType::qmlTypeName() const
 {
+    if (d->m_name.isEmpty()) {
+        if (!d->m_module.isEmpty())
+            d->m_name = static_cast<QString>(d->m_module) + QLatin1Char('/') + d->m_elementName;
+        else
+            d->m_name = d->m_elementName;
+    }
+
     return d->m_name;
 }
 
@@ -531,6 +642,11 @@ void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) con
     *memory = ((char *)rv) + d->m_allocationSize;
 }
 
+QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const
+{
+    return d->m_singletonInstanceInfo;
+}
+
 QQmlCustomParser *QQmlType::customParser() const
 {
     return d->m_customParser;
@@ -563,6 +679,11 @@ bool QQmlType::isExtendedType() const
     return !d->m_metaObjects.isEmpty();
 }
 
+bool QQmlType::isSingleton() const
+{
+    return d->m_singletonInstanceInfo != 0;
+}
+
 bool QQmlType::isInterface() const
 {
     return d->m_isInterface;
@@ -651,20 +772,49 @@ int QQmlType::index() const
     return d->m_index;
 }
 
-int QQmlType::enumValue(const QHashedStringRef &name) const
+int QQmlType::enumValue(const QHashedStringRef &name, bool *ok) const
 {
+    Q_ASSERT(ok);
+    *ok = true;
+
     d->initEnums();
 
     int *rv = d->m_enums.value(name);
-    return rv?*rv:-1;
+    if (rv)
+        return *rv;
+
+    *ok = false;
+    return -1;
 }
 
-int QQmlType::enumValue(const QHashedV8String &name) const
+int QQmlType::enumValue(const QHashedCStringRef &name, bool *ok) const
 {
+    Q_ASSERT(ok);
+    *ok = true;
+
     d->initEnums();
 
     int *rv = d->m_enums.value(name);
-    return rv?*rv:-1;
+    if (rv)
+        return *rv;
+
+    *ok = false;
+    return -1;
+}
+
+int QQmlType::enumValue(const QHashedV8String &name, bool *ok) const
+{
+    Q_ASSERT(ok);
+    *ok = true;
+
+    d->initEnums();
+
+    int *rv = d->m_enums.value(name);
+    if (rv)
+        return *rv;
+
+    *ok = false;
+    return -1;
 }
 
 QQmlTypeModule::QQmlTypeModule()
@@ -699,8 +849,6 @@ int QQmlTypeModule::maximumMinorVersion() const
 
 void QQmlTypeModulePrivate::add(QQmlType *type)
 {
-    types << type;
-
     minMinorVersion = qMin(minMinorVersion, type->minorVersion());
     maxMinorVersion = qMax(maxMinorVersion, type->minorVersion());
 
@@ -714,25 +862,6 @@ void QQmlTypeModulePrivate::add(QQmlType *type)
     list.append(type);
 }
 
-QList<QQmlType *> QQmlTypeModule::types()
-{
-    QList<QQmlType *> rv;
-    QReadLocker lock(metaTypeDataLock());
-    rv = d->types;
-    return rv;
-}
-
-QList<QQmlType *> QQmlTypeModule::type(const QString &name)
-{
-    QReadLocker lock(metaTypeDataLock());
-    QList<QQmlType *> rv;
-    for (int ii = 0; ii < d->types.count(); ++ii) {
-        if (d->types.at(ii)->elementName() == name)
-            rv << d->types.at(ii);
-    }
-    return rv;
-}
-
 QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
 {
     QReadLocker lock(metaTypeDataLock());
@@ -761,6 +890,20 @@ QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
     return 0;
 }
 
+QList<QQmlType*> QQmlTypeModule::singletonTypes(int minor) const
+{
+    QReadLocker lock(metaTypeDataLock());
+
+    QList<QQmlType *> retn;
+    for (int ii = 0; ii < d->types.count(); ++ii) {
+        QQmlType *curr = d->types.at(ii);
+        if (curr->isSingleton() && curr->minorVersion() <= minor)
+            retn.append(curr);
+    }
+
+    return retn;
+}
+
 
 QQmlTypeModuleVersion::QQmlTypeModuleVersion()
 : m_module(0), m_minor(0)
@@ -835,8 +978,8 @@ int registerInterface(const QQmlPrivate::RegisterInterface &interface)
     data->idToType.insert(type->typeId(), type);
     data->idToType.insert(type->qListTypeId(), type);
     // XXX No insertMulti, so no multi-version interfaces?
-    if (!type->qmlTypeName().isEmpty())
-        data->nameToType.insert(type->qmlTypeName(), type);
+    if (!type->elementName().isEmpty())
+        data->nameToType.insert(type->elementName(), type);
 
     if (data->interfaces.size() <= interface.typeId)
         data->interfaces.resize(interface.typeId + 16);
@@ -848,29 +991,73 @@ int registerInterface(const QQmlPrivate::RegisterInterface &interface)
     return index;
 }
 
-int registerType(const QQmlPrivate::RegisterType &type)
+QString registrationTypeString(QQmlType::RegistrationType typeType)
+{
+    QString typeStr;
+    if (typeType == QQmlType::CppType)
+        typeStr = QStringLiteral("element");
+    else if (typeType == QQmlType::SingletonType)
+        typeStr = QStringLiteral("singleton type");
+    return typeStr;
+}
+
+// NOTE: caller must hold a QWriteLocker on "data"
+bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, const char *uri, const QString &typeName)
 {
-    if (type.elementName) {
-        for (int ii = 0; type.elementName[ii]; ++ii) {
-            if (!isalnum(type.elementName[ii])) {
-                qWarning("qmlRegisterType(): Invalid QML element name \"%s\"", type.elementName);
-                return -1;
+    if (!typeName.isEmpty()) {
+        int typeNameLen = typeName.length();
+        for (int ii = 0; ii < typeNameLen; ++ii) {
+            if (!typeName.at(ii).isLetterOrNumber()) {
+                QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\""));
+                data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName));
+                return false;
             }
         }
     }
 
+    if (uri && !typeName.isEmpty()) {
+        QString nameSpace = moduleFromUtf8(uri);
+
+        if (!data->typeRegistrationNamespace.isEmpty()) {
+            // We can only install types into the registered namespace
+            if (nameSpace != data->typeRegistrationNamespace) {
+                QString failure(QCoreApplication::translate("qmlRegisterType",
+                                                            "Cannot install %1 '%2' into unregistered namespace '%3'"));
+                data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace));
+                return false;
+            }
+        } else if (data->typeRegistrationNamespace != nameSpace) {
+            // Is the target namespace protected against further registrations?
+            if (data->protectedNamespaces.contains(nameSpace)) {
+                QString failure(QCoreApplication::translate("qmlRegisterType",
+                                                            "Cannot install %1 '%2' into protected namespace '%3'"));
+                data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace));
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+int registerType(const QQmlPrivate::RegisterType &type)
+{
     QWriteLocker lock(metaTypeDataLock());
     QQmlMetaTypeData *data = metaTypeData();
+    QString elementName = QString::fromUtf8(type.elementName);
+    if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName))
+        return -1;
+
     int index = data->types.count();
 
-    QQmlType *dtype = new QQmlType(index, type);
+    QQmlType *dtype = new QQmlType(index, elementName, type);
 
     data->types.append(dtype);
     data->idToType.insert(dtype->typeId(), dtype);
     if (dtype->qListTypeId()) data->idToType.insert(dtype->qListTypeId(), dtype);
 
-    if (!dtype->qmlTypeName().isEmpty())
-        data->nameToType.insertMulti(dtype->qmlTypeName(), dtype);
+    if (!dtype->elementName().isEmpty())
+        data->nameToType.insertMulti(dtype->elementName(), dtype);
 
     data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
 
@@ -881,8 +1068,8 @@ int registerType(const QQmlPrivate::RegisterType &type)
     data->objects.setBit(type.typeId, true);
     if (type.listId) data->lists.setBit(type.listId, true);
 
-    if (type.uri) {
-        QString mod = QString::fromUtf8(type.uri);
+    if (!dtype->module().isEmpty()) {
+        const QHashedString &mod = dtype->module();
 
         QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
         QQmlTypeModule *module = data->uriToModule.value(versionedUri);
@@ -897,28 +1084,44 @@ int registerType(const QQmlPrivate::RegisterType &type)
     return index;
 }
 
-int registerModuleApi(const QQmlPrivate::RegisterModuleApi &api)
+int registerSingletonType(const QQmlPrivate::RegisterSingletonType &type)
 {
     QWriteLocker lock(metaTypeDataLock());
-
     QQmlMetaTypeData *data = metaTypeData();
-    QString uri = QString::fromUtf8(api.uri);
-    QQmlMetaType::ModuleApi import;
-    import.major = api.versionMajor;
-    import.minor = api.versionMinor;
-    import.script = api.scriptApi;
-    import.qobject = api.qobjectApi;
-
-    int index = data->moduleApiCount++;
-
-    QQmlMetaTypeData::ModuleApis::Iterator iter = data->moduleApis.find(uri);
-    if (iter == data->moduleApis.end()) {
-        QQmlMetaTypeData::ModuleApiList apis;
-        apis.moduleApis << import;
-        data->moduleApis.insert(uri, apis);
-    } else {
-        iter->moduleApis << import;
-        iter->sorted = false;
+    QString typeName = QString::fromUtf8(type.typeName);
+    if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName))
+        return -1;
+
+    int index = data->types.count();
+
+    QQmlType *dtype = new QQmlType(index, typeName, type);
+
+    data->types.append(dtype);
+    data->idToType.insert(dtype->typeId(), dtype);
+
+    if (!dtype->elementName().isEmpty())
+        data->nameToType.insertMulti(dtype->elementName(), dtype);
+
+    if (dtype->baseMetaObject())
+        data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
+
+    if (type.typeId) {
+        if (data->objects.size() <= type.typeId)
+            data->objects.resize(type.typeId + 16);
+        data->objects.setBit(type.typeId, true);
+    }
+
+    if (!dtype->module().isEmpty()) {
+        const QHashedString &mod = dtype->module();
+
+        QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
+        QQmlTypeModule *module = data->uriToModule.value(versionedUri);
+        if (!module) {
+            module = new QQmlTypeModule;
+            module->d->uri = versionedUri;
+            data->uriToModule.insert(versionedUri, module);
+        }
+        module->d->add(dtype);
     }
 
     return index;
@@ -937,12 +1140,52 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
         return registerInterface(*reinterpret_cast<RegisterInterface *>(data));
     } else if (type == AutoParentRegistration) {
         return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data));
-    } else if (type == ModuleApiRegistration) {
-        return registerModuleApi(*reinterpret_cast<RegisterModuleApi *>(data));
+    } else if (type == SingletonRegistration) {
+        return registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data));
     }
     return -1;
 }
 
+bool QQmlMetaType::namespaceContainsRegistrations(const QString &uri)
+{
+    QQmlMetaTypeData *data = metaTypeData();
+
+    // Has any type previously been installed to this namespace?
+    QHashedString nameSpace(uri);
+    foreach (const QQmlType *type, data->types)
+        if (type->module() == nameSpace)
+            return true;
+
+    return false;
+}
+
+void QQmlMetaType::protectNamespace(const QString &uri)
+{
+    QQmlMetaTypeData *data = metaTypeData();
+
+    data->protectedNamespaces.insert(uri);
+}
+
+void QQmlMetaType::setTypeRegistrationNamespace(const QString &uri)
+{
+    QQmlMetaTypeData *data = metaTypeData();
+
+    data->typeRegistrationNamespace = uri;
+    data->typeRegistrationFailures.clear();
+}
+
+QStringList QQmlMetaType::typeRegistrationFailures()
+{
+    QQmlMetaTypeData *data = metaTypeData();
+
+    return data->typeRegistrationFailures;
+}
+
+QReadWriteLock *QQmlMetaType::typeRegistrationLock()
+{
+    return metaTypeDataLock();
+}
+
 /*
     Returns true if a module \a uri of any version is installed.
 */
@@ -980,12 +1223,6 @@ bool QQmlMetaType::isModule(const QString &module, int versionMajor, int version
     if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
         return true;
 
-    // then, check ModuleApis
-    foreach (const QQmlMetaType::ModuleApi &mApi, data->moduleApis.value(module).moduleApis) {
-        if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
-            return true;
-    }
-
     return false;
 }
 
@@ -1003,50 +1240,6 @@ QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
     return data->parentFunctions;
 }
 
-static bool operator<(const QQmlMetaType::ModuleApi &lhs, const QQmlMetaType::ModuleApi &rhs)
-{
-    return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
-}
-
-QQmlMetaType::ModuleApi
-QQmlMetaType::moduleApi(const QString &uri, int versionMajor, int versionMinor)
-{
-    QReadLocker lock(metaTypeDataLock());
-    QQmlMetaTypeData *data = metaTypeData();
-
-    QQmlMetaTypeData::ModuleApis::Iterator iter = data->moduleApis.find(uri);
-    if (iter == data->moduleApis.end())
-        return ModuleApi();
-
-    if (iter->sorted == false) {
-        qSort(iter->moduleApis.begin(), iter->moduleApis.end());
-        iter->sorted = true;
-    }
-
-    for (int ii = iter->moduleApis.count() - 1; ii >= 0; --ii) {
-        const ModuleApi &import = iter->moduleApis.at(ii);
-        if (import.major == versionMajor && import.minor <= versionMinor)
-            return import;
-    }
-
-    return ModuleApi();
-}
-
-QHash<QString, QList<QQmlMetaType::ModuleApi> > QQmlMetaType::moduleApis()
-{
-    QReadLocker lock(metaTypeDataLock());
-    QQmlMetaTypeData *data = metaTypeData();
-
-    QHash<QString, QList<ModuleApi> > moduleApis;
-    QHashIterator<QString, QQmlMetaTypeData::ModuleApiList> it(data->moduleApis);
-    while (it.hasNext()) {
-        it.next();
-        moduleApis[it.key()] = it.value().moduleApis;
-    }
-
-    return moduleApis;
-}
-
 QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
 {
     if (!isQObject(v.userType())) {
@@ -1237,19 +1430,35 @@ QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
 }
 
 /*!
-    Returns the type (if any) of URI-qualified named \a name in version specified
+    Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
+    by \a version_major and \a version_minor.
+*/
+QQmlType *QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
+{
+    int slash = qualifiedName.indexOf(QLatin1Char('/'));
+    if (slash <= 0)
+        return 0;
+
+    QHashedStringRef module(qualifiedName.constData(), slash);
+    QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
+
+    return qmlType(name, module, version_major, version_minor);
+}
+
+/*!
+    Returns the type (if any) of \a name in \a module and version specified
     by \a version_major and \a version_minor.
 */
-QQmlType *QQmlMetaType::qmlType(const QString &name, int version_major, int version_minor)
+QQmlType *QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
 {
     Q_ASSERT(version_major >= 0 && version_minor >= 0);
     QReadLocker lock(metaTypeDataLock());
     QQmlMetaTypeData *data = metaTypeData();
 
     QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
-    while (it != data->nameToType.end()) {
+    while (it != data->nameToType.end() && it.key() == name) {
         // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
-        if (it.key() == name && (version_major<0 || (*it)->availableInVersion(version_major,version_minor)))
+        if (version_major < 0 || (*it)->availableInVersion(module, version_major,version_minor))
             return (*it);
         ++it;
     }
@@ -1274,7 +1483,7 @@ QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject)
     by \a version_major and \a version_minor in module specified by \a uri.  Returns null if no
     type is registered.
 */
-QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QString &module, int version_major, int version_minor)
+QQmlType *QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
 {
     Q_ASSERT(version_major >= 0 && version_minor >= 0);
     QReadLocker lock(metaTypeDataLock());
@@ -1315,7 +1524,14 @@ QList<QString> QQmlMetaType::qmlTypeNames()
     QReadLocker lock(metaTypeDataLock());
     QQmlMetaTypeData *data = metaTypeData();
 
-    return data->nameToType.keys();
+    QList<QString> names;
+    QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.begin();
+    while (it != data->nameToType.end()) {
+        names += (*it)->qmlTypeName();
+        ++it;
+    }
+
+    return names;
 }
 
 /*!
@@ -1329,6 +1545,25 @@ QList<QQmlType*> QQmlMetaType::qmlTypes()
     return data->nameToType.values();
 }
 
+/*!
+    Returns the list of registered QML singleton types.
+*/
+QList<QQmlType*> QQmlMetaType::qmlSingletonTypes()
+{
+    QReadLocker lock(metaTypeDataLock());
+    QQmlMetaTypeData *data = metaTypeData();
+
+    QList<QQmlType*> alltypes = data->nameToType.values();
+    QList<QQmlType*> retn;
+    foreach (QQmlType* t, alltypes) {
+        if (t->isSingleton()) {
+            retn.append(t);
+        }
+    }
+
+    return retn;
+}
+
 int QQmlMetaType::QQuickAnchorLineMetaTypeId()
 {
     static int id = 0;