Optimizations to imports.
authorMartin Jones <martin.jones@nokia.com>
Wed, 20 Jul 2011 04:03:03 +0000 (14:03 +1000)
committerQt by Nokia <qt-info@nokia.com>
Tue, 30 Aug 2011 11:18:28 +0000 (13:18 +0200)
Change-Id: If4a51ad3b7c0ecc2261eea1d07a949119c3ad860
Reviewed-on: http://codereview.qt.nokia.com/3754
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
src/declarative/qml/qdeclarativecompileddata.cpp
src/declarative/qml/qdeclarativecompiler.cpp
src/declarative/qml/qdeclarativeengine.cpp
src/declarative/qml/qdeclarativeengine_p.h
src/declarative/qml/qdeclarativeimport.cpp
src/declarative/qml/qdeclarativeimport_p.h
src/declarative/qml/qdeclarativemetatype.cpp
src/declarative/qml/qdeclarativetypeloader.cpp
src/declarative/qml/qdeclarativetypeloader_p.h

index da7c3fe..c59dd78 100644 (file)
@@ -100,6 +100,7 @@ int QDeclarativeCompiledData::indexForUrl(const QUrl &data)
 QDeclarativeCompiledData::QDeclarativeCompiledData(QDeclarativeEngine *engine)
 : QDeclarativeCleanup(engine), importCache(0), root(0), rootPropertyCache(0)
 {
+    bytecode.reserve(1024);
 }
 
 QDeclarativeCompiledData::~QDeclarativeCompiledData()
@@ -202,10 +203,9 @@ int QDeclarativeCompiledData::addInstruction(const QDeclarativeInstruction &inst
 { 
     int ptrOffset = bytecode.size();
     int size = instr.size();
-    bytecode.resize(bytecode.size() + size);
-    char *data = bytecode.data() + ptrOffset;
-    qMemCopy(data, &instr,  size);
-
+    if (bytecode.capacity() <= bytecode.size() + size)
+        bytecode.reserve(bytecode.size() + size + 512);
+    bytecode.append(reinterpret_cast<const char *>(&instr), size);
     return ptrOffset;
 }
 
index 3a1987e..c75570d 100644 (file)
@@ -607,7 +607,7 @@ void QDeclarativeCompiler::reset(QDeclarativeCompiledData *data)
     data->types.clear();
     data->primitives.clear();
     data->datas.clear();
-    data->bytecode.clear();
+    data->bytecode.resize(0);
 }
 
 /*!
@@ -2523,12 +2523,12 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn
             {
                 QByteArray customTypeName;
                 QDeclarativeType *qmltype = 0;
-                QUrl url;
+                QString url;
                 if (!unit->imports().resolveType(p.customType, &qmltype, &url, 0, 0, 0)) 
                     COMPILE_EXCEPTION(&p, tr("Invalid property type"));
 
                 if (!qmltype) {
-                    QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(url);
+                    QDeclarativeTypeData *tdata = enginePrivate->typeLoader.get(QUrl(url));
                     Q_ASSERT(tdata);
                     Q_ASSERT(tdata->isComplete());
 
index f6d4832..7e8f93e 100644 (file)
@@ -1126,6 +1126,34 @@ QString QDeclarativeEnginePrivate::urlToLocalFileOrQrc(const QUrl& url)
     return url.toLocalFile();
 }
 
+
+static QString toLocalFile(const QString &url)
+{
+    if (!url.startsWith(QLatin1String("file://"), Qt::CaseInsensitive))
+        return QString();
+
+    QString file = url.mid(7);
+
+    //XXX TODO: handle windows hostnames: "//servername/path/to/file.txt"
+
+    // magic for drives on windows
+    if (file.length() > 2 && file.at(0) == QLatin1Char('/') && file.at(2) == QLatin1Char(':'))
+        file.remove(0, 1);
+
+    return file;
+}
+
+QString QDeclarativeEnginePrivate::urlToLocalFileOrQrc(const QString& url)
+{
+    if (url.startsWith(QLatin1String("qrc:"), Qt::CaseInsensitive)) {
+        if (url.length() > 4)
+            return QLatin1Char(':') + url.mid(4);
+        return QString();
+    }
+
+    return toLocalFile(url);
+}
+
 void QDeclarativeEnginePrivate::sendQuit()
 {
     Q_Q(QDeclarativeEngine);
index 6ff1218..be4f714 100644 (file)
@@ -262,6 +262,7 @@ public:
     static QDeclarativeEngine *get(QDeclarativeEnginePrivate *p) { return p->q_func(); }
 
     static QString urlToLocalFileOrQrc(const QUrl& url);
+    static QString urlToLocalFileOrQrc(const QString& url);
 
     static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor);
     static void defineModule();
index 89b6814..61ece7a 100644 (file)
@@ -65,25 +65,48 @@ static bool greaterThan(const QString &s1, const QString &s2)
     return s1 > s2;
 }
 
+QString resolveLocalUrl(const QString &url, const QString &relative)
+{
+    if (relative.contains(QLatin1Char(':'))) {
+        // contains a host name
+        return QUrl(url).resolved(QUrl(relative)).toString();
+    } else if (relative.isEmpty()) {
+        return url;
+    } else if (relative.at(0) == QLatin1Char('/') || !url.contains(QLatin1Char('/'))) {
+        return relative;
+    } else {
+        if (relative == QLatin1String("."))
+            return url.left(url.lastIndexOf(QLatin1Char('/')) + 1);
+        else if (relative.startsWith(QLatin1String("./")))
+            return url.left(url.lastIndexOf(QLatin1Char('/')) + 1) + relative.mid(2);
+        return url.left(url.lastIndexOf(QLatin1Char('/')) + 1) + relative;
+    }
+}
+
+
+
 typedef QMap<QString, QString> StringStringMap;
 Q_GLOBAL_STATIC(StringStringMap, qmlEnginePluginsWithRegisteredTypes); // stores the uri
 
 class QDeclarativeImportedNamespace 
 {
 public:
-    QList<QByteArray> uris;
-    QStringList urls;
-    QList<int> majversions;
-    QList<int> minversions;
-    QList<bool> isLibrary;
-    QList<QDeclarativeDirComponents> qmlDirComponents;
-
-
-    bool find_helper(QDeclarativeTypeLoader *typeLoader, int i, const QByteArray& type, int *vmajor, int *vminor,
-                                 QDeclarativeType** type_return, QUrl* url_return,
-                                 QUrl *base = 0, bool *typeRecursionDetected = 0);
+    struct Data {
+        QByteArray uri;
+        QString url;
+        int majversion;
+        int minversion;
+        bool isLibrary;
+        QDeclarativeDirComponents qmlDirComponents;
+    };
+    QList<Data> imports;
+
+
+    bool find_helper(QDeclarativeTypeLoader *typeLoader, const Data &data, const QByteArray& type, int *vmajor, int *vminor,
+                                 QDeclarativeType** type_return, QString* url_return,
+                                 QString *base = 0, bool *typeRecursionDetected = 0);
     bool find(QDeclarativeTypeLoader *typeLoader, const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
-              QUrl* url_return, QUrl *base = 0, QList<QDeclarativeError> *errors = 0);
+              QString* url_return, QString *base = 0, QList<QDeclarativeError> *errors = 0);
 };
 
 class QDeclarativeImportsPrivate {
@@ -101,11 +124,12 @@ public:
              int vmaj, int vmin, QDeclarativeScriptParser::Import::Type importType, 
              QDeclarativeImportDatabase *database, QList<QDeclarativeError> *errors);
     bool find(const QByteArray& type, int *vmajor, int *vminor, 
-              QDeclarativeType** type_return, QUrl* url_return, QList<QDeclarativeError> *errors);
+              QDeclarativeType** type_return, QString* url_return, QList<QDeclarativeError> *errors);
 
     QDeclarativeImportedNamespace *findNamespace(const QString& type);
 
-    QUrl base;
+    QUrl baseUrl;
+    QString base;
     int ref;
 
     QSet<QString> qmlDirFilesForWhichPluginsHaveBeenLoaded;
@@ -151,7 +175,8 @@ QDeclarativeImports::~QDeclarativeImports()
 */
 void QDeclarativeImports::setBaseUrl(const QUrl& url)
 {
-    d->base = url;
+    d->baseUrl = url;
+    d->base = url.toString();
 }
 
 /*!
@@ -159,19 +184,18 @@ void QDeclarativeImports::setBaseUrl(const QUrl& url)
 */
 QUrl QDeclarativeImports::baseUrl() const
 {
-    return d->base;
+    return d->baseUrl;
 }
 
 void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDeclarativeEngine *engine) const
 {
     const QDeclarativeImportedNamespace &set = d->unqualifiedset;
 
-    for (int ii = set.uris.count() - 1; ii >= 0; --ii) {
-        const QByteArray uri = set.uris.at(ii);
-        int majversion = set.majversions.at(ii);
-        int minversion = set.minversions.at(ii);
-        QDeclarativeTypeModule *module = QDeclarativeMetaType::typeModule(uri, majversion);
-        if (module) cache->m_anonymousImports.append(QDeclarativeTypeModuleVersion(module, minversion));
+    for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+        const QDeclarativeImportedNamespace::Data &data = set.imports.at(ii);
+        QDeclarativeTypeModule *module = QDeclarativeMetaType::typeModule(data.uri, data.majversion);
+        if (module)
+            cache->m_anonymousImports.append(QDeclarativeTypeModuleVersion(module, data.minversion));
     }
 
     for (QHash<QString,QDeclarativeImportedNamespace* >::ConstIterator iter = d->set.begin();
@@ -180,14 +204,13 @@ void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDecla
 
         const QDeclarativeImportedNamespace &set = *iter.value();
         QDeclarativeTypeNameCache::Import &import = cache->m_namedImports[iter.key()];
-        for (int ii = set.uris.count() - 1; ii >= 0; --ii) {
-            const QByteArray uri = set.uris.at(ii);
-            int majversion = set.majversions.at(ii);
-            int minversion = set.minversions.at(ii);
-            QDeclarativeTypeModule *module = QDeclarativeMetaType::typeModule(uri, majversion);
-            if (module) import.modules.append(QDeclarativeTypeModuleVersion(module, minversion));
-
-            QDeclarativeMetaType::ModuleApi moduleApi = QDeclarativeMetaType::moduleApi(uri, majversion, minversion);
+        for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+            const QDeclarativeImportedNamespace::Data &data = set.imports.at(ii);
+            QDeclarativeTypeModule *module = QDeclarativeMetaType::typeModule(data.uri, data.majversion);
+            if (module)
+                import.modules.append(QDeclarativeTypeModuleVersion(module, data.minversion));
+
+            QDeclarativeMetaType::ModuleApi moduleApi = QDeclarativeMetaType::moduleApi(data.uri, data.majversion, data.minversion);
             if (moduleApi.script || moduleApi.qobject) {
                 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
                 QDeclarativeMetaType::ModuleApiInstance *a = ep->moduleApiInstances.value(moduleApi);
@@ -219,8 +242,8 @@ void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDecla
 
   \sa addImport()
 */
-bool QDeclarativeImports::resolveType(const QByteArray& type, 
-                                      QDeclarativeType** type_return, QUrl* url_return, int *vmaj, int *vmin,
+bool QDeclarativeImports::resolveType(const QByteArray& type,
+                                      QDeclarativeType** type_return, QString* url_return, int *vmaj, int *vmin,
                                       QDeclarativeImportedNamespace** ns_return, QList<QDeclarativeError> *errors) const
 {
     QDeclarativeImportedNamespace* ns = d->findNamespace(QString::fromUtf8(type));
@@ -259,19 +282,16 @@ bool QDeclarativeImports::resolveType(const QByteArray& type,
   If either return pointer is 0, the corresponding search is not done.
 */
 bool QDeclarativeImports::resolveType(QDeclarativeImportedNamespace* ns, const QByteArray& type, 
-                                      QDeclarativeType** type_return, QUrl* url_return, 
+                                      QDeclarativeType** type_return, QString* url_return,
                                       int *vmaj, int *vmin) const
 {
     return ns->find(d->typeLoader,type,vmaj,vmin,type_return,url_return);
 }
 
-bool QDeclarativeImportedNamespace::find_helper(QDeclarativeTypeLoader *typeLoader, int i, const QByteArray& type, int *vmajor, int *vminor,
-                                 QDeclarativeType** type_return, QUrl* url_return,
-                                 QUrl *base, bool *typeRecursionDetected)
+bool QDeclarativeImportedNamespace::find_helper(QDeclarativeTypeLoader *typeLoader, const Data &data, const QByteArray& type, int *vmajor, int *vminor,
+                                 QDeclarativeType** type_return, QString* url_return,
+                                 QString *base, bool *typeRecursionDetected)
 {
-    int vmaj = data.majversion;
-    int vmin = data.minversion;
-
     if (vmaj >= 0 && vmin >= 0) {
         QString qt = data.uri + QLatin1Char('/') + type;
         QDeclarativeType *t = QDeclarativeMetaType::qmlType(qt,vmaj,vmin);
@@ -284,19 +304,18 @@ bool QDeclarativeImportedNamespace::find_helper(QDeclarativeTypeLoader *typeLoad
         }
     }
 
-    QDeclarativeDirComponents qmldircomponents = qmlDirComponents.at(i);
+    const QDeclarativeDirComponents &qmldircomponents = data.qmlDirComponents;
     bool typeWasDeclaredInQmldir = false;
     if (!qmldircomponents.isEmpty()) {
         foreach (const QDeclarativeDirParser::Component &c, qmldircomponents) {
             if (c.typeName == type) {
                 typeWasDeclaredInQmldir = true;
-
                 // importing version -1 means import ALL versions
                 if ((vmaj == -1) || (c.majorVersion == vmaj && vmin >= c.minorVersion)) {
-                    QUrl url = QUrl(urls.at(i) + QLatin1Char('/') + QString::fromUtf8(type) + QLatin1String(".qml"));
-                    QUrl candidate = url.resolved(QUrl(c.fileName));
+                    QString url(data.url + type + QLatin1String(".qml"));
+                    QString candidate = resolveLocalUrl(url, c.fileName);
                     if (c.internal && base) {
-                        if (base->resolved(QUrl(c.fileName)) != candidate)
+                        if (resolveLocalUrl(*base, c.fileName) != candidate)
                             continue; // failed attempt to access an internal type
                     }
                     if (base && *base == candidate) {
@@ -312,9 +331,9 @@ bool QDeclarativeImportedNamespace::find_helper(QDeclarativeTypeLoader *typeLoad
         }
     }
 
-    if (!typeWasDeclaredInQmldir  && !isLibrary.at(i)) {
+    if (!typeWasDeclaredInQmldir && !data.isLibrary) {
         // XXX search non-files too! (eg. zip files, see QT-524)
-        QUrl url = QUrl(urls.at(i) + QLatin1Char('/') + QString::fromUtf8(type) + QLatin1String(".qml"));
+        QString url(data.url + QString::fromUtf8(type) + QLatin1String(".qml"));
         QString file = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
         if (!typeLoader->absoluteFilePath(file).isEmpty()) {
             if (base && *base == url) { // no recursion
@@ -355,16 +374,19 @@ bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath
     }
 
     if (qmlImportTrace())
-        qDebug().nospace() << "QDeclarativeImports(" << qPrintable(base.toString()) << "::importExtension: "
+        qDebug().nospace() << "QDeclarativeImports(" << qPrintable(base) << "::importExtension: "
                            << "loaded " << absoluteFilePath;
 
     if (! qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(absoluteFilePath)) {
         qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(absoluteFilePath);
 
-        QDir dir = QFileInfo(absoluteFilePath).dir();
+        QString qmldirPath = absoluteFilePath;
+        int slash = absoluteFilePath.lastIndexOf(QLatin1Char('/'));
+        if (slash > 0)
+            qmldirPath.truncate(slash);
         foreach (const QDeclarativeDirParser::Plugin &plugin, qmldirParser->plugins()) {
 
-            QString resolvedFilePath = database->resolvePlugin(dir, plugin.path, plugin.name);
+            QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath, plugin.path, plugin.name);
 #if defined(QT_LIBINFIX) && defined(Q_OS_SYMBIAN)
             if (resolvedFilePath.isEmpty()) {
                 // In case of libinfixed build, attempt to load libinfixed version, too.
@@ -440,6 +462,9 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
                                      QDeclarativeScriptParser::Import::Type importType, 
                                      QDeclarativeImportDatabase *database, QList<QDeclarativeError> *errors)
 {
+    static QLatin1String Slash_qmldir("/qmldir");
+    static QLatin1Char Slash('/');
+
     QDeclarativeDirComponents qmldircomponents = qmldircomponentsnetwork;
     QString uri = uri_arg;
     QDeclarativeImportedNamespace *s;
@@ -456,7 +481,7 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
 
         Q_ASSERT(vmaj >= 0 && vmin >= 0); // Versions are always specified for libraries
 
-        url.replace(QLatin1Char('.'), QLatin1Char('/'));
+        url.replace(QLatin1Char('.'), Slash);
         bool found = false;
         QString dir;
         QString qmldir;
@@ -501,14 +526,14 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
             // step 3: search for extension without version number
 
             foreach (const QString &p, database->fileImportPath) {
-                dir = p+QLatin1Char('/')+url;
-                qmldir = dir+QLatin1String("/qmldir");
+                dir = p+Slash+url;
+                qmldir = dir+Slash_qmldir;
 
                 QString absoluteFilePath = typeLoader->absoluteFilePath(qmldir);
                 if (!absoluteFilePath.isEmpty()) {
                     found = true;
-                    QString absolutePath = absoluteFilePath.left(absoluteFilePath.lastIndexOf(QLatin1Char('/')));
-                    url = QUrl::fromLocalFile(absolutePath).toString();
+                    QString absolutePath = absoluteFilePath.left(absoluteFilePath.lastIndexOf(Slash)+1);
+                    url = QLatin1String("file://") + absolutePath;
                     uri = resolvedUri(dir, database);
                     if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errors))
                         return false;
@@ -534,22 +559,21 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
         }
     } else {
         if (importType == QDeclarativeScriptParser::Import::File && qmldircomponents.isEmpty()) {
-            QUrl importUrl = base.resolved(QUrl(uri + QLatin1String("/qmldir")));
+            QString importUrl = resolveLocalUrl(base, uri + Slash_qmldir);
             QString localFileOrQrc = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(importUrl);
             if (!localFileOrQrc.isEmpty()) {
-                QString dir = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri)));
-                QFileInfo dirinfo(dir);
-                if (dir.isEmpty() || !dirinfo.exists() || !dirinfo.isDir()) {
+                QString dir = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(resolveLocalUrl(base, uri));
+                if (!typeLoader->directoryExists(dir)) {
                     if (errors) {
                         QDeclarativeError error; // we don't set the line or column as these will be set by the loader.
                         error.setDescription(QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri_arg));
-                        error.setUrl(importUrl);
+                        error.setUrl(QUrl(importUrl));
                         errors->prepend(error);
                     }
                     return false; // local import dirs must exist
                 }
-                uri = resolvedUri(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri))), database);
-                if (uri.endsWith(QLatin1Char('/')))
+                uri = resolvedUri(dir, database);
+                if (uri.endsWith(Slash))
                     uri.chop(1);
                 if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty()) {
                     if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,errors))
@@ -558,16 +582,15 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
             } else {
                 if (prefix.isEmpty()) {
                     // directory must at least exist for valid import
-                    QString localFileOrQrc = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri)));
-                    QFileInfo dirinfo(localFileOrQrc);
-                    if (localFileOrQrc.isEmpty() || !dirinfo.exists() || !dirinfo.isDir()) {
+                    QString localFileOrQrc = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(resolveLocalUrl(base, uri));
+                    if (!typeLoader->directoryExists(localFileOrQrc)) {
                         if (errors) {
                             QDeclarativeError error; // we don't set the line or column as these will be set by the loader.
                             if (localFileOrQrc.isEmpty())
                                 error.setDescription(QDeclarativeImportDatabase::tr("import \"%1\" has no qmldir and no namespace").arg(uri));
                             else
                                 error.setDescription(QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri));
-                            error.setUrl(importUrl);
+                            error.setUrl(QUrl(importUrl));
                             errors->prepend(error);
                         }
                         return false;
@@ -576,9 +599,7 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
             }
         }
 
-        url = base.resolved(QUrl(url)).toString();
-        if (url.endsWith(QLatin1Char('/')))
-            url.chop(1);
+        url = resolveLocalUrl(base, url);
     }
 
     if (!versionFound && vmaj > -1 && vmin > -1 && !qmldircomponents.isEmpty()) {
@@ -601,17 +622,23 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
         }
     }
 
-    s->uris.prepend(uri.toUtf8());
-    s->urls.prepend(url);
-    s->majversions.prepend(vmaj);
-    s->minversions.prepend(vmin);
-    s->isLibrary.prepend(importType == QDeclarativeScriptParser::Import::Library);
-    s->qmlDirComponents.prepend(qmldircomponents);
+    if (!url.endsWith(Slash))
+        url += Slash;
+
+    QDeclarativeImportedNamespace::Data data;
+    data.uri = uri.toUtf8();
+    data.url = url;
+    data.majversion = vmaj;
+    data.minversion = vmin;
+    data.isLibrary = importType == QDeclarativeScriptParser::Import::Library;
+    data.qmlDirComponents = qmldircomponents;
+    s->imports.prepend(data);
+
     return true;
 }
 
 bool QDeclarativeImportsPrivate::find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
-                                      QUrl* url_return, QList<QDeclarativeError> *errors)
+                                      QString* url_return, QList<QDeclarativeError> *errors)
 {
     QDeclarativeImportedNamespace *s = 0;
     int slash = type.indexOf('/');
@@ -642,9 +669,9 @@ bool QDeclarativeImportsPrivate::find(const QByteArray& type, int *vmajor, int *
     if (s) {
         if (s->find(typeLoader,unqualifiedtype,vmajor,vminor,type_return,url_return, &base, errors))
             return true;
-        if (s->urls.count() == 1 && !s->isLibrary[0] && url_return && s != &unqualifiedset) {
+        if (s->imports.count() == 1 && !s->imports.at(0).isLibrary && url_return && s != &unqualifiedset) {
             // qualified, and only 1 url
-            *url_return = QUrl(s->urls[0]+QLatin1Char('/')).resolved(QUrl(QString::fromUtf8(unqualifiedtype) + QLatin1String(".qml")));
+            *url_return = resolveLocalUrl(s->imports.at(0).url, QString::fromUtf8(unqualifiedtype) + QLatin1String(".qml"));
             return true;
         }
     }
@@ -658,20 +685,20 @@ QDeclarativeImportedNamespace *QDeclarativeImportsPrivate::findNamespace(const Q
 }
 
 bool QDeclarativeImportedNamespace::find(QDeclarativeTypeLoader *typeLoader, const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
-          QUrl* url_return, QUrl *base, QList<QDeclarativeError> *errors)
+          QString* url_return, QString *base, QList<QDeclarativeError> *errors)
 {
     bool typeRecursionDetected = false;
-    for (int i=0; i<urls.count(); ++i) {
-        if (find_helper(typeLoader, i, type, vmajor, vminor, type_return, url_return, base, &typeRecursionDetected)) {
+    for (int i=0; i<imports.count(); ++i) {
+        if (find_helper(typeLoader, imports.at(i), type, vmajor, vminor, type_return, url_return, base, &typeRecursionDetected)) {
             if (qmlCheckTypes()) {
                 // check for type clashes
-                for (int j = i+1; j<urls.count(); ++j) {
-                    if (find_helper(typeLoader, j, type, vmajor, vminor, 0, 0, base)) {
+                for (int j = i+1; j<imports.count(); ++j) {
+                    if (find_helper(typeLoader, imports.at(j), type, vmajor, vminor, 0, 0, base)) {
                         if (errors) {
-                            QString u1 = urls.at(i);
-                            QString u2 = urls.at(j);
+                            QString u1 = imports.at(i).url;
+                            QString u2 = imports.at(j).url;
                             if (base) {
-                                QString b = base->toString();
+                                QString b = *base;
                                 int slash = b.lastIndexOf(QLatin1Char('/'));
                                 if (slash >= 0) {
                                     b = b.left(slash+1);
@@ -693,8 +720,8 @@ bool QDeclarativeImportedNamespace::find(QDeclarativeTypeLoader *typeLoader, con
                             } else {
                                 error.setDescription(QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5")
                                                         .arg(u1)
-                                                        .arg(majversions.at(i)).arg(minversions.at(i))
-                                                        .arg(majversions.at(j)).arg(minversions.at(j)));
+                                                        .arg(imports.at(i).majversion).arg(imports.at(i).minversion)
+                                                        .arg(imports.at(j).majversion).arg(imports.at(j).minversion));
                             }
                             errors->prepend(error);
                         }
@@ -815,7 +842,8 @@ bool QDeclarativeImports::addImport(QDeclarativeImportDatabase *importDb,
 
   \a qmldirPath is the location of the qmldir file.
  */
-QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath, 
+QString QDeclarativeImportDatabase::resolvePlugin(QDeclarativeTypeLoader *typeLoader,
+                                                  const QString &qmldirPath, const QString &qmldirPluginPath,
                                                   const QString &baseName, const QStringList &suffixes,
                                                   const QString &prefix)
 {
@@ -827,36 +855,40 @@ QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const
     foreach (const QString &pluginPath, searchPaths) {
 
         QString resolvedPath;
-
         if (pluginPath == QLatin1String(".")) {
-            if (qmldirPluginPathIsRelative)
-                resolvedPath = qmldirPath.absoluteFilePath(qmldirPluginPath);
+            if (qmldirPluginPathIsRelative && !qmldirPluginPath.isEmpty() && qmldirPluginPath != QLatin1String("."))
+                resolvedPath = QDir::cleanPath(qmldirPath + QLatin1Char('/') + qmldirPluginPath);
             else
-                resolvedPath = qmldirPath.absolutePath();
+                resolvedPath = qmldirPath;
         } else {
-            resolvedPath = pluginPath;
+            if (QDir::isRelativePath(pluginPath))
+                resolvedPath = QDir::cleanPath(qmldirPath + QLatin1Char('/') + pluginPath);
+            else
+                resolvedPath = pluginPath;
         }
 
         // hack for resources, should probably go away
         if (resolvedPath.startsWith(QLatin1Char(':')))
             resolvedPath = QCoreApplication::applicationDirPath();
-        QDir dir(resolvedPath);
+
+        if (!resolvedPath.endsWith(QLatin1Char('/')))
+            resolvedPath += QLatin1Char('/');
+
         foreach (const QString &suffix, suffixes) {
             QString pluginFileName = prefix;
 
             pluginFileName += baseName;
             pluginFileName += suffix;
 
-            QFileInfo fileInfo(dir, pluginFileName);
-
-            if (fileInfo.exists())
-                return fileInfo.absoluteFilePath();
+            QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + pluginFileName);
+            if (!absolutePath.isEmpty())
+                return absolutePath;
         }
     }
 
     if (qmlImportTrace())
         qDebug() << "QDeclarativeImportDatabase::resolvePlugin: Could not resolve plugin" << baseName 
-                 << "in" << qmldirPath.absolutePath();
+                 << "in" << qmldirPath;
 
     return QString();
 }
@@ -878,18 +910,19 @@ QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const
 
   Version number on unix are ignored.
 */
-QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath, 
+QString QDeclarativeImportDatabase::resolvePlugin(QDeclarativeTypeLoader *typeLoader,
+                                                  const QString &qmldirPath, const QString &qmldirPluginPath,
                                                   const QString &baseName)
 {
 #if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
-    return resolvePlugin(qmldirPath, qmldirPluginPath, baseName,
+    return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName,
                          QStringList()
 # ifdef QT_DEBUG
                          << QLatin1String("d.dll") // try a qmake-style debug build first
 # endif
                          << QLatin1String(".dll"));
 #elif defined(Q_OS_SYMBIAN)
-    return resolvePlugin(qmldirPath, qmldirPluginPath, baseName,
+    return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName,
                          QStringList()
                          << QLatin1String(".dll")
                          << QLatin1String(".qtplugin"));
@@ -897,7 +930,7 @@ QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const
 
 # if defined(Q_OS_DARWIN)
 
-    return resolvePlugin(qmldirPath, qmldirPluginPath, baseName,
+    return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName,
                          QStringList()
 # ifdef QT_DEBUG
                          << QLatin1String("_debug.dylib") // try a qmake-style debug build first
@@ -931,7 +964,7 @@ QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const
     // Examples of valid library names:
     //  libfoo.so
 
-    return resolvePlugin(qmldirPath, qmldirPluginPath, baseName, validSuffixList, QLatin1String("lib"));
+    return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, validSuffixList, QLatin1String("lib"));
 # endif
 
 #endif
index d3e4933..94639bd 100644 (file)
@@ -82,13 +82,13 @@ public:
     QUrl baseUrl() const;
 
     bool resolveType(const QByteArray& type,
-                     QDeclarativeType** type_return, QUrl* url_return,
+                     QDeclarativeType** type_return, QString* url_return,
                      int *version_major, int *version_minor,
                      QDeclarativeImportedNamespace** ns_return,
                      QList<QDeclarativeError> *errors = 0) const;
     bool resolveType(QDeclarativeImportedNamespace*, 
                      const QByteArray& type,
-                     QDeclarativeType** type_return, QUrl* url_return,
+                     QDeclarativeType** type_return, QString* url_return,
                      int *version_major, int *version_minor) const;
 
     bool addImport(QDeclarativeImportDatabase *, 
@@ -123,10 +123,12 @@ public:
 
 private:
     friend class QDeclarativeImportsPrivate;
-    QString resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath, 
+    QString resolvePlugin(QDeclarativeTypeLoader *typeLoader,
+                          const QString &qmldirPath, const QString &qmldirPluginPath,
                           const QString &baseName, const QStringList &suffixes,
                           const QString &prefix = QString());
-    QString resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath, 
+    QString resolvePlugin(QDeclarativeTypeLoader *typeLoader,
+                          const QString &qmldirPath, const QString &qmldirPluginPath,
                           const QString &baseName);
 
 
index bd4b935..e0bef56 100644 (file)
@@ -1250,12 +1250,14 @@ QDeclarativeType *QDeclarativeMetaType::qmlType(const QByteArray &name, int vers
     QReadLocker lock(metaTypeDataLock());
     QDeclarativeMetaTypeData *data = metaTypeData();
 
-    QList<QDeclarativeType*> types = data->nameToType.values(name);
-    foreach (QDeclarativeType *t, types) {
+    QDeclarativeMetaTypeData::Names::ConstIterator it = data->nameToType.find(name);
+    while (it != data->nameToType.end()) {
         // XXX version_major<0 just a kludge for QDeclarativePropertyPrivate::initProperty
-        if (version_major<0 || t->availableInVersion(version_major,version_minor))
-            return t;
+        if (version_major<0 || (*it)->availableInVersion(version_major,version_minor))
+            return (*it);
+        ++it;
     }
+
     return 0;
 }
 
index 6b9dfc1..64fb1ec 100644 (file)
@@ -64,6 +64,7 @@ QT_BEGIN_NAMESPACE
 /*
 Returns the set of QML files in path (qmldir, *.qml, *.js).  The caller
 is responsible for deleting the returned data.
+Returns 0 if the directory does not exist.
 */
 #if defined (Q_OS_UNIX)
 static QStringHash<bool> *qmlFilesInDirectory(const QString &path)
@@ -90,6 +91,14 @@ static QStringHash<bool> *qmlFilesInDirectory(const QString &path)
             continue;
         if (!strcmp(u.d.d_name+len-4, ".qml") || !strcmp(u.d.d_name+len-3, ".js"))
             files->insert(QFile::decodeName(u.d.d_name), true);
+#if defined(Q_OS_DARWIN)
+        else if ((len > 6 && !strcmp(u.d.d_name+len-6, ".dylib")) || !strcmp(u.d.d_name+len-3, ".so")
+                  || (len > 7 && !strcmp(u.d.d_name+len-7, ".bundle"))
+            files->insert(QFile::decodeName(u.d.d_name), true);
+#else  // Unix
+        else if (!strcmp(u.d.d_name+len-3, ".so") || !strcmp(u.d.d_name+len-3, ".sl"))
+            files->insert(QFile::decodeName(u.d.d_name), true);
+#endif
     }
 
     closedir(dd);
@@ -107,7 +116,18 @@ static QStringHash<bool> *qmlFilesInDirectory(const QString &path)
         QString fileName = dir.fileName();
         if (fileName == QLatin1String("qmldir")
                 || fileName.endsWith(QLatin1String(".qml"))
-                || fileName.endsWith(QLatin1String(".js")))
+                || fileName.endsWith(QLatin1String(".js"))
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
+                || fileName.endsWith(QLatin1String(".dll"))
+#elif defined(Q_OS_DARWIN)
+                || fileName.endsWith(QLatin1String(".dylib"))
+                || fileName.endsWith(QLatin1String(".so"))
+                || fileName.endsWith(QLatin1String(".bundle"))
+#else  // Unix
+                || fileName.endsWith(QLatin1String(".so"))
+                || fileName.endsWith(QLatin1String(".sl"))
+#endif
+                )
             files->insert(fileName, true);
     }
     return files;
@@ -785,7 +805,7 @@ QDeclarativeQmldirData *QDeclarativeTypeLoader::getQmldir(const QUrl &url)
 
 /*!
 Returns the absolute filename of path via a directory cache for files named
-"qmldir", "*.qml", "*.js"
+"qmldir", "*.qml", "*.js", and plugins.
 Returns a empty string if the path does not exist.
 */
 QString QDeclarativeTypeLoader::absoluteFilePath(const QString &path)
@@ -818,6 +838,37 @@ QString QDeclarativeTypeLoader::absoluteFilePath(const QString &path)
 }
 
 /*!
+Returns true if the path is a directory via a directory cache.  Cache is
+shared with absoluteFilePath().
+*/
+bool QDeclarativeTypeLoader::directoryExists(const QString &path)
+{
+    if (path.isEmpty())
+        return false;
+    if (path.at(0) == QLatin1Char(':')) {
+        // qrc resource
+        QFileInfo fileInfo(path);
+        return fileInfo.exists() && fileInfo.isDir();
+    }
+
+    int length = path.length();
+    if (path.endsWith(QLatin1Char('/')))
+        --length;
+    QStringRef dirPath(&path, 0, length);
+
+    StringSet **fileSet = m_importDirCache.value(QHashedStringRef(dirPath.constData(), dirPath.length()));
+    if (!fileSet) {
+        QHashedString dirPathString(dirPath.toString());
+        StringSet *files = qmlFilesInDirectory(dirPathString);
+        m_importDirCache.insert(dirPathString, files);
+        fileSet = m_importDirCache.value(dirPathString);
+    }
+
+    return (*fileSet);
+}
+
+
+/*!
 Return a QDeclarativeDirParser for absoluteFilePath.  The QDeclarativeDirParser may be cached.
 */
 const QDeclarativeDirParser *QDeclarativeTypeLoader::qmlDirParser(const QString &absoluteFilePath)
@@ -1132,7 +1183,7 @@ void QDeclarativeTypeData::resolveTypes()
 
         TypeReference ref;
 
-        QUrl url;
+        QString url;
         int majorVersion;
         int minorVersion;
         QDeclarativeImportedNamespace *typeNamespace = 0;
@@ -1175,7 +1226,7 @@ void QDeclarativeTypeData::resolveTypes()
             ref.majorVersion = majorVersion;
             ref.minorVersion = minorVersion;
         } else {
-            ref.typeData = typeLoader()->get(url);
+            ref.typeData = typeLoader()->get(QUrl(url));
             addDependency(ref.typeData);
         }
 
index a090f25..cfe80ae 100644 (file)
@@ -205,6 +205,7 @@ public:
     QDeclarativeQmldirData *getQmldir(const QUrl &);
 
     QString absoluteFilePath(const QString &path);
+    bool directoryExists(const QString &path);
     const QDeclarativeDirParser *qmlDirParser(const QString &absoluteFilePath);
 
 private: