diff options
author | Armin Berres <armin.berres@basyskom.de> | 2010-07-27 16:00:15 +0200 |
---|---|---|
committer | Tomas Junnonen <tomas.junnonen@nokia.com> | 2010-07-29 11:18:13 +0300 |
commit | 974150ffbad93fd4be23afeb7f083944e9c4f3be (patch) | |
tree | 55c6b108eb4d6bff7bedc2133834998a35fd5631 /src | |
parent | 73947f0e1c6afd0577797c1b2357cecc5290b12b (diff) |
Changes: themedaemon extract ids from all svgs
RevBy: Janne Heikkilä, Peter Penz, Tomas Junnonen
Details:
When the themedaemon is supposed to return an pixmap for a special id it could
theoretically be part of any available svg. In the worst case the themedaemon
has to iterate over all svgs to find an id. To speed this up so called .ids files
could be used to specify which ids are contained in an svg. If an id from
an .ids file has been requested the lookup has been fast. Ff not the
themedaemon had to to the iteration. Quite some svg files did not have .ids
files.
To solve this problem the .ids files are obsolet with this commit. The
themedaemon extracts the ids contained in all svgs now at startup and caches
the result. When an id is requested now the themedaemon can use a lookup table
to directly determine the needed svg file.
As extracting the ids from the svgs is not the cheapest opertion the ids
are saved in cache file which are updated whenever the svg changes.
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/theme/mimagedirectory.cpp | 167 | ||||
-rw-r--r-- | src/corelib/theme/mimagedirectory.h | 14 |
2 files changed, 119 insertions, 62 deletions
diff --git a/src/corelib/theme/mimagedirectory.cpp b/src/corelib/theme/mimagedirectory.cpp index d94b2c67..848ebc92 100644 --- a/src/corelib/theme/mimagedirectory.cpp +++ b/src/corelib/theme/mimagedirectory.cpp @@ -19,6 +19,7 @@ #include "mimagedirectory.h" #include "mthemeresourcemanager.h" +#include "mthemedaemon.h" #include "mdebug.h" #include <QDir> @@ -30,6 +31,10 @@ #include <QX11Info> #endif +namespace { + const unsigned int ID_CACHE_VERSION = 1; +} + uint qHash(const QSize &size) { return (size.width() & 0x0000ffff) | (size.height() << 16); @@ -205,7 +210,6 @@ const QString MThemeImagesDirectory::pixmapsDir = "images"; const QString MThemeImagesDirectory::iconsDir = "icons"; const QString MThemeImagesDirectory::svgDir = "svg"; - MThemeImagesDirectory::MThemeImagesDirectory(const QString &path, const QString &locale) : m_path(path), m_locale(locale) @@ -227,10 +231,10 @@ MThemeImagesDirectory::MThemeImagesDirectory(const QString &path, const QString if (i->isDir()) { directories.append(i->absoluteFilePath()); } else if (i->suffix() == "png" || i->suffix() == "jpg") { - if (imageIds.contains(i->baseName())) { - mDebug("MThemeDaemon") << "Path" << i->absolutePath() << "contains multiple images with id" << i->baseName(); + if (imageResources.contains(i->baseName()) || idsInSvgImages.contains(i->baseName())) { + mWarning("MThemeDaemon") << "Path" << i->absolutePath() << "contains multiple images with id" << i->baseName(); } else { - imageIds.insert(i->baseName(), new PixmapImageResource(i->absoluteFilePath())); + imageResources.insert(i->baseName(), new PixmapImageResource(i->absoluteFilePath())); } } } @@ -252,17 +256,20 @@ MThemeImagesDirectory::MThemeImagesDirectory(const QString &path, const QString if (i->isDir()) { directories.append(i->absoluteFilePath()); } else if (i->suffix() == "svg") { - if (imageIds.contains(i->baseName())) { + if (imageResources.contains(i->baseName())) { mDebug("MThemeDaemon") << "Path" << path + QDir::separator() + "meegotouch" << "contains multiple images with id" << i->baseName(); } else { - imageIds.insert(i->baseName(), new IconImageResource(i->absoluteFilePath())); + imageResources.insert(i->baseName(), new IconImageResource(i->absoluteFilePath())); } } } } - // then go trough the svg dir + // then go through the svg dir directories.append(path + QDir::separator() + svgDir); + // matches and id specified in a svg file. + // the id may either appear in a g or image tag. + QRegExp idRegexp("<(g|image)\\s[^>]*id=\"([^\"]*)\"[^>]*>"); while (!directories.isEmpty()) { QDir dir(directories.takeFirst()); if (!dir.exists()) { @@ -277,23 +284,22 @@ MThemeImagesDirectory::MThemeImagesDirectory(const QString &path, const QString if (i->isDir()) { directories.append(i->absoluteFilePath()); } else if (i->suffix() == "svg") { - if(QFile::exists(i->absoluteFilePath() + ".ids")) { - // read file ids and create svg resources - QFile file(i->absoluteFilePath() + ".ids"); - if(file.open(QIODevice::ReadOnly)) { - while(!file.atEnd()) { - QString id = file.readLine().trimmed(); - if (imageIds.contains(id)) { - mDebug("MThemeDaemon") << "Path" << path << "contains multiple images with id" << id; - } else { - imageIds.insert(id, new SvgImageResource(id, i->absoluteFilePath())); - } + if (!loadIdsFromCache(*i)) { + QFile svgFile(i->filePath()); + if (svgFile.open(QIODevice::ReadOnly)) { + QByteArray content = svgFile.readAll(); + int pos = 0; + QStringList ids; + while ((pos = idRegexp.indexIn(content, pos)) != -1) { + QString id = idRegexp.cap(2); + idsInSvgImages.insert(id, i->absoluteFilePath()); + pos += idRegexp.matchedLength(); + ids << id; } + saveIdsInCache(ids, *i); + } else { + mWarning("MThemeImagesDirectory") << "Failed to load ids from" << i->absoluteFilePath(); } - } else { - mWarning("MThemeDaemon") << "SLOW: SVG file" << i->absoluteFilePath() << "doesn't have .ids file!"; - // insert this to svg lookup list, this acts as a fallback to old implementation - svgFiles.insert(i->absoluteFilePath(), QSharedPointer<QSvgRenderer>()); } } } @@ -304,12 +310,11 @@ MThemeImagesDirectory::MThemeImagesDirectory(const QString &path, const QString MThemeImagesDirectory::~MThemeImagesDirectory() { - qDeleteAll(imageIds); - imageIds.clear(); + qDeleteAll(imageResources); + imageResources.clear(); qDeleteAll(localeSpecificIcons); localeSpecificIcons.clear(); svgFiles.clear(); - notFoundIds.clear(); } ImageResource *MThemeImagesDirectory::findImage(const QString &imageId) @@ -322,39 +327,20 @@ ImageResource *MThemeImagesDirectory::findImage(const QString &imageId) if (!resource) { // Check if we have this id already resolved - resource = imageIds.value(imageId, NULL); + resource = imageResources.value(imageId, NULL); } if (!resource) { - - // is this image already marked as not found? - if (notFoundIds.contains(imageId)) { - return NULL; - } - - // it was not resolved, so we need to go trough all svg-files. - QHash< QString, QSharedPointer<QSvgRenderer> >::iterator i = svgFiles.begin(); - QHash< QString, QSharedPointer<QSvgRenderer> >::iterator end = svgFiles.end(); - - for (; i != end; ++i) { - - QSvgRenderer* renderer = MThemeResourceManager::instance().svgRenderer(i.key()); - Q_ASSERT_X(renderer, "SvgImageResource", "SVG renderer not found"); - - // does this svg contain the element we're looking for? - if (renderer->elementExists(imageId)) { - resource = new SvgImageResource(imageId, i.key()); - imageIds.insert(imageId, resource); - break; + QList<QString> svgPaths = idsInSvgImages.values(imageId); + if (!svgPaths.empty()) { + if (svgPaths.count() > 1) { + mWarning("MThemeImagesDirectory") << "Found multiple svgs with candidates for id" << imageId << "Using first one: " << svgPaths; } + resource = new SvgImageResource(imageId, svgPaths.first()); + imageResources.insert(imageId, resource); } } - if (!resource) { - // mark the image id as not found, so next time someone is asking this, we don't need to go trough all svg-files - notFoundIds.insert(imageId); - } - return resource; } @@ -391,7 +377,7 @@ void MThemeImagesDirectory::reloadLocaleSpecificImages(const QString &locale) if (i->isDir()) { directories.append(i->absoluteFilePath()); } else if (i->suffix() == "svg") { - if (!imageIds.contains(i->baseName())) { + if (!imageResources.contains(i->baseName())) { mWarning("MThemeDaemon") << "Path" << dir.absolutePath() << "contains imageId" << i->baseName() << "which was not found from the original theme!"; } else { localeSpecificIcons.insert(i->baseName(), new IconImageResource(i->absoluteFilePath())); @@ -411,6 +397,71 @@ QString MThemeImagesDirectory::locale() const return m_locale; } +bool MThemeImagesDirectory::loadIdsFromCache(const QFileInfo& svgFileInfo) +{ + const QString idCacheFile = createIdCacheFilename(svgFileInfo.absoluteFilePath()); + if (QFile::exists(idCacheFile)) { + QFile file(idCacheFile); + if (file.open(QFile::ReadOnly)) { + QDataStream stream(&file); + uint version; + stream >> version; + if (version != ID_CACHE_VERSION) { + file.close(); + return false; + } + uint timestamp; + stream >> timestamp; + if (timestamp != svgFileInfo.lastModified().toTime_t()) { + file.close(); + return false; + } + + QStringList ids; + stream >> ids; + foreach(const QString& id, ids) { + idsInSvgImages.insert(id, svgFileInfo.absoluteFilePath()); + } + file.close(); + return true; + } else { + mWarning("MThemeImagesDirectory") << "Failed to load id cache file" << idCacheFile; + } + return false; + } + return false; +} + +void MThemeImagesDirectory::saveIdsInCache(const QStringList& ids, const QFileInfo& svgFileInfo) const +{ + const QString idCacheFile = createIdCacheFilename(svgFileInfo.absoluteFilePath()); + + QFile file(idCacheFile); + if (!file.open(QFile::WriteOnly)) { + //Maybe it failed because the directory doesn't exist + QDir().mkpath(QFileInfo(idCacheFile).absolutePath()); + if (!file.open(QFile::WriteOnly)) { + mDebug("MThemeImagesDirectory") << "Failed to save id cache file" << svgFileInfo.fileName() << "to" << idCacheFile; + return; + } + } + + QDataStream stream(&file); + stream << ID_CACHE_VERSION; + stream << svgFileInfo.lastModified().toTime_t(); + stream << ids; + file.close(); +} + +// TODO: inspired by MStyleSheetParserPrivate::createBinaryFilename(). consider merging both. +QString MThemeImagesDirectory::createIdCacheFilename(const QString &filePath) const +{ + QString filePathEncoded(filePath); + filePathEncoded.replace('_', "__"); + filePathEncoded.replace('/', "_."); + return MThemeDaemon::systemThemeCacheDirectory() + "ids/" + filePathEncoded; +} + MImageDirectory::MImageDirectory(const QString &path, M::RecursionMode recursionMode) { QList<QDir> directories; @@ -433,10 +484,10 @@ MImageDirectory::MImageDirectory(const QString &path, M::RecursionMode recursion if (i->isDir() && recursionMode == M::Recursive) { directories.append(QDir(i->absoluteFilePath())); } else if (i->suffix() == "png" || i->suffix() == "jpg") { - if (imageIds.contains(i->baseName())) { + if (imageResources.contains(i->baseName())) { mDebug("MThemeDaemon") << "Path" << path << "contains multiple images with id" << i->baseName(); } else { - imageIds.insert(i->baseName(), new PixmapImageResource(i->absoluteFilePath())); + imageResources.insert(i->baseName(), new PixmapImageResource(i->absoluteFilePath())); } } else if (i->suffix() == "svg") { svgFiles.insert(i->absoluteFilePath(), QSharedPointer<QSvgRenderer>()); @@ -447,15 +498,15 @@ MImageDirectory::MImageDirectory(const QString &path, M::RecursionMode recursion MImageDirectory::~MImageDirectory() { - qDeleteAll(imageIds); - imageIds.clear(); + qDeleteAll(imageResources); + imageResources.clear(); svgFiles.clear(); notFoundIds.clear(); } ImageResource *MImageDirectory::findImage(const QString &imageId) { - ImageResource *resource = imageIds.value(imageId, NULL); + ImageResource *resource = imageResources.value(imageId, NULL); if (!resource) { @@ -475,7 +526,7 @@ ImageResource *MImageDirectory::findImage(const QString &imageId) // does this svg contain the element we're looking for? if (renderer->elementExists(imageId)) { resource = new SvgImageResource(imageId, i.key()); - imageIds.insert(imageId, resource); + imageResources.insert(imageId, resource); break; } } diff --git a/src/corelib/theme/mimagedirectory.h b/src/corelib/theme/mimagedirectory.h index 4fc4ffe4..512c2534 100644 --- a/src/corelib/theme/mimagedirectory.h +++ b/src/corelib/theme/mimagedirectory.h @@ -31,6 +31,7 @@ #include <mnamespace.h> class QPixmap; +class QFileInfo; uint qHash(const QSize &size); @@ -131,8 +132,15 @@ public: QString locale() const; private: + bool loadIdsFromCache(const QFileInfo& svgFileInfo); + void saveIdsInCache(const QStringList& ids, const QFileInfo& svgFileInfo) const; + QString createIdCacheFilename(const QString &filePath) const; + // image id => image resource - QHash<QString, ImageResource *> imageIds; + QHash<QString, ImageResource *> imageResources; + // image id => svg filename + QMultiHash<QString, QString> idsInSvgImages; + // locale specific icon QHash<QString, ImageResource *> localeSpecificIcons; @@ -140,8 +148,6 @@ private: // svg renderer file path => shared svg renderer pointer QHash< QString, QSharedPointer<QSvgRenderer> > svgFiles; - QSet<QString> notFoundIds; - QString m_path; QString m_locale; }; @@ -159,7 +165,7 @@ public: private: // image id => image resource - QHash<QString, ImageResource *> imageIds; + QHash<QString, ImageResource *> imageResources; // svg renderer file path => shared svg renderer pointer QHash< QString, QSharedPointer<QSvgRenderer> > svgFiles; |