--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hbservers/hbthemeserver/hbthemeserverutils.cpp Mon Apr 19 14:02:13 2010 +0300
@@ -0,0 +1,432 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (developer.feedback@nokia.com)
+**
+** This file is part of the HbServers module of the UI Extensions for Mobile.
+**
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at developer.feedback@nokia.com.
+**
+****************************************************************************/
+
+#include "hbthemeserverutils_p.h"
+
+#include <QHash>
+#include <QString>
+#include <QFile>
+#include <QDebug>
+
+#include "hbmemoryutils_p.h"
+#include "hbcssparser_p.h"
+#include "hbeffectfxmldata_p.h"
+#include "hbeffectxmlparser_p.h"
+#include "hbdeviceprofiledatabase_p.h"
+#include "hbthemeperf_p.h"
+#include "hbcache_p.h"
+#include "hbiconsource_p.h"
+#include "hbwidgetloadersyntax_p.h"
+#include "hbwidgetloaderactions_p.h"
+
+//Hash of fileName-offset
+typedef QHash<QString, int> HbServerCache;
+
+Q_GLOBAL_STATIC(HbServerCache, effCache)
+
+// cache at the server side to maintain the offsets for
+// the filename,layout and section combination.
+typedef QHash<QString, int> ServerHashForLayoutDefs;
+Q_GLOBAL_STATIC(ServerHashForLayoutDefs, layoutDefsCache)
+
+HbSharedCache *sharedCache = 0;
+int HbThemeServerUtils::serverSecondaryCacheOffset = -1;
+static const int NumberOfSharedCacheItems = 50;
+
+static const int ICON_SOURCES_MAX_SIZE = 8;
+static QList<HbIconSource *> iconSources; // cache of recently used icon sources
+
+HbIconSource *HbThemeServerUtils::getIconSource(const QString &filename)
+{
+ foreach(HbIconSource *source, iconSources) {
+ if (source->filename() == filename) {
+ return source;
+ }
+ }
+ // Add new icon source last in the list, delete the first entry if the max size is exceeded.
+ QScopedPointer<HbIconSource> tempHbIconSource(new HbIconSource(filename));
+ HbIconSource *newSource = tempHbIconSource.data();
+
+ if (iconSources.count() >= ICON_SOURCES_MAX_SIZE) {
+ iconSources.removeFirst();
+ }
+ iconSources.append(newSource);
+ tempHbIconSource.take();
+ return newSource;
+}
+
+/**
+ * formatFromPath
+ */
+QString HbThemeServerUtils::formatFromPath(const QString &iconPath)
+{
+ QString suffix = QFileInfo(iconPath).suffix().toUpper();
+
+ if (suffix == "SVGZ") {
+ return "SVG";
+ }
+
+ if (suffix == "QPIC") {
+ return "PIC";
+ }
+ if (suffix == "XML" || suffix == "AXML" || suffix == "FXML") {
+ return "BLOB";
+ }
+ return suffix;
+}
+
+/**
+ * HbThemeServerUtils::getSharedStylesheet() parses the requested stylesheet
+ * in shared memory and returns its offset. The offset could be -1 in case of
+ * OOM condition or any error while parsing the css file.
+ *
+ * \param fileName required stylesheet (complete file path)
+ * \param priority layer priority
+ * \return offset of the shared style sheet in the shared memory, -1 if error
+ *
+ */
+int HbThemeServerUtils::getSharedStylesheet(const QString & fileName, HbLayeredStyleLoader::LayerPriority priority)
+{
+#ifdef THEME_SERVER_TRACES
+ qDebug() << "In " << Q_FUNC_INFO;
+#endif // THEME_SERVER_TRACES
+ int cssOffset = -1;
+ if (QFile::exists(fileName)) {
+ HbCss::Parser parser;
+ if (!parseCssFile(parser, fileName, cssOffset)) {
+ if (parser.errorCode == HbCss::Parser::OutOfMemoryError) {
+ return OUT_OF_MEMORY_ERROR;
+ }
+ }
+ }
+ // add the filename and css offset to the secondary cache.
+ if ((priority == HbLayeredStyleLoader::Priority_Core) && sharedCache && cssOffset != -1) {
+ // no need to check if this item is already present in the
+ // cache as the parsing of the file happens only once
+ // in the server side.
+ try {
+ HbSharedCacheItem cacheItem(fileName, cssOffset);
+ sharedCache->append(cacheItem);
+ } catch (std::bad_alloc &badAlloc) {
+ Q_UNUSED(badAlloc)
+ // item is not appended .
+ }
+
+ }
+ return cssOffset;
+}
+
+/**
+ * HbThemeServerUtils::parseCssFile()
+ *
+ * Returns false in case Css file has some error or there is not enough memory
+ */
+bool HbThemeServerUtils::parseCssFile(HbCss::Parser &parser, const QString &fileName, int &cssOffset)
+{
+ bool retVal = false;
+ // 1. Create a styleSheet in shared memory
+ GET_MEMORY_MANAGER(HbMemoryManager::SharedMemory) ;
+ HB_START_SHAREDMEMORY_PRINT("");
+ HB_START_HEAPMEMORY_PRINT("");
+ HbCss::StyleSheet *styleSheet = 0;
+ try {
+ cssOffset = manager->alloc(sizeof(HbCss::StyleSheet));
+ styleSheet = new((char*)manager->base() + cssOffset) HbCss::StyleSheet(HbMemoryManager::SharedMemory);
+ } catch (std::bad_alloc &badAlloc) {
+ Q_UNUSED(badAlloc)
+ // if manager->alloc in the previous try block suceeds but creation of
+ // HbCss::StyleSheet on shared memory failed
+ if (cssOffset != -1) {
+ manager->free(cssOffset);
+ cssOffset = -1;
+ }
+ // if manager->alloc itself failed, in that case cssOffset will still be -1,
+ // just return offset as -1 to represent error
+ return retVal;
+ }
+ // 2. Parse the required file into styleSheet.
+ parser.init(fileName, true);
+
+ if (parser.parse(styleSheet)) {
+ retVal = true;
+ } else {
+ //parser::parse returns false in a number of scenarios
+ // 1. css file has some error
+ // 2. shared memory operations on HbVector/HbString/HbVariant threw an exception
+ // in either case free the memory occupied by stylesheet
+ HbMemoryUtils::release<HbCss::StyleSheet>(styleSheet);
+ manager->free(cssOffset);
+ cssOffset = -1;
+ }
+ HB_END_SHAREDMEMORY_PRINT("");
+ HB_END_HEAPMEMORY_PRINT("");
+ return retVal;
+}
+
+/*
+ Returns of the offset for the given filename,layout and section name.
+ */
+
+int HbThemeServerUtils::getSharedLayoutDefinition(const QString & fileName, const QString &layout, const QString §ion)
+{
+ int layoutDefOffset = -1;
+ // check in the cache.
+ QString key(fileName + layout + section);
+ if (layoutDefsCache()->contains(key)) {
+ layoutDefOffset = layoutDefsCache()->value(key);
+ return layoutDefOffset;
+ }
+ HbWidgetLoaderActions loader(HbMemoryManager::SharedMemory);
+ HbWidgetLoaderSyntax widgetMLSyntax(&loader);
+
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly | QFile::Text)) {
+ qWarning("Unable to open file");
+ return -1;
+ }
+#ifdef THEME_SERVER_TRACES
+ qDebug() << "Trying to load: " << fileName << "::" << layout << "::" << section;
+#endif // THEME_SERVER_TRACES
+
+ bool load = widgetMLSyntax.load(&file, layout, section);
+ if (load) {
+ layoutDefOffset = loader.getLayoutDefintionOffset();
+ } else {
+ // load() failed. free the memory
+ LayoutDefinition *layoutDef =
+ HbMemoryUtils::getAddress<LayoutDefinition>(HbMemoryManager::SharedMemory,
+ loader.getLayoutDefintionOffset());
+ if (layoutDef) {
+ GET_MEMORY_MANAGER(HbMemoryManager::SharedMemory);
+ layoutDef->~LayoutDefinition();
+ manager->free(loader.getLayoutDefintionOffset());
+ loader.setLayoutDefintionOffset(-1);
+ }
+ }
+
+ if (layoutDefOffset != -1) {
+ layoutDefsCache()->insert(key, layoutDefOffset);
+ // add the filename and css offset to the secondary cache.
+ if (sharedCache) {
+ // no need to check if this item is already present in the
+ // cache as the parsing of the file happens only once
+ // in the server side.
+ try {
+ HbSharedCacheItem cacheItem(key, layoutDefOffset);
+ sharedCache->append(cacheItem);
+ } catch (std::bad_alloc &badAlloc) {
+ // item is not appended.
+ Q_UNUSED(badAlloc)
+ }
+ }
+ }
+
+ return layoutDefOffset;
+}
+
+/**
+ * Creates the singleton HbDeviceProfileDatabase instance in shared memory
+ *
+ */
+void HbThemeServerUtils::createDeviceProfileDatabase()
+{
+ HbDeviceProfileDatabase::instance(HbMemoryManager::SharedMemory);
+}
+
+/**
+ * Creates/Returns the Shared Cache.
+ *
+ */
+HbSharedCache *HbThemeServerUtils::createSharedCache()
+{
+ if (!sharedCache) {
+ // secondary cache is not created. Create it.
+ GET_MEMORY_MANAGER(HbMemoryManager::SharedMemory)
+ try {
+ serverSecondaryCacheOffset = manager->alloc(sizeof(HbSharedCache));
+ sharedCache = new((char*)manager->base() + serverSecondaryCacheOffset)
+ HbSharedCache(HbMemoryManager::SharedMemory);
+ // reserving memory so that realloc calls will be minimized in future.
+ sharedCache->reserve(NumberOfSharedCacheItems);
+ } catch (std::bad_alloc &exception) {
+ Q_UNUSED(exception)
+ if (serverSecondaryCacheOffset != -1) {
+ manager->free(serverSecondaryCacheOffset);
+ }
+ serverSecondaryCacheOffset = -1;
+ sharedCache = 0;
+ }
+ }
+ return sharedCache;
+}
+
+/**
+ * Returns the Secondary Cache Offset.
+ *
+ */
+int HbThemeServerUtils::sharedCacheOffset()
+{
+ return serverSecondaryCacheOffset;
+}
+
+/**
+ * getSharedEffect parses the requested fxml document into the shared
+ * memory and returns the offset of the parsed data.
+ *
+ * \param fileName requested fxml file
+ * \return offset of the parsed effect data in the shared memory, -1 if error
+ *
+ */
+int HbThemeServerUtils::getSharedEffect(const QString &fileName)
+{
+#ifdef THEME_SERVER_TRACES
+ qDebug() << "In " << Q_FUNC_INFO << fileName;
+#endif // THEME_SERVER_TRACES
+
+ int effOffset = -1;
+ if (effCache()->contains(fileName)) {
+ effOffset = effCache()->value(fileName);
+
+#ifdef THEME_SERVER_TRACES
+ qDebug() << "Got effect in cache: " << fileName << "offset=" << effOffset;
+#endif //THEME_SERVER_TRACES
+
+ } else {
+
+#ifdef THEME_SERVER_TRACES
+ qDebug() << "Not in cache, parsing: " << fileName;
+#endif //THEME_SERVER_TRACES
+
+ // 1. Create an effect in shared memory
+ GET_MEMORY_MANAGER(HbMemoryManager::SharedMemory);
+ HbEffectFxmlData *data = 0;
+ try {
+ effOffset = manager->alloc(sizeof(HbEffectFxmlData));
+ data = new((char*)manager->base() + effOffset) HbEffectFxmlData(HbMemoryManager::SharedMemory);
+ } catch (std::bad_alloc &badAlloc) {
+ Q_UNUSED(badAlloc)
+ // if manager->alloc in the previous try block suceeds but creation of
+ // HbEffectFxmlData on shared memory failed
+ if (effOffset != -1) {
+ manager->free(effOffset);
+ effOffset = -1;
+ }
+ // if manager->alloc itself failed, in that case effOffset will still be -1,
+ // just return offset as -1 to represent error
+ return effOffset;
+ }
+ // 2. Parse the file.
+ HbEffectXmlParser parser;
+
+
+ QFile f(fileName);
+ if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ try {
+ parser.read(&f, data);
+ f.close();
+
+ // 3. Mark an entry for this styleSheet into the table
+ effCache()->insert(fileName, effOffset);
+ } catch (std::bad_alloc &badAlloc) {
+ Q_UNUSED(badAlloc)
+ f.close();
+ //HbMemoryUtils::release<HbEffectFxmlData>(data);
+ manager->free(effOffset);
+ effOffset = -1;
+ }
+
+ } else {
+#ifdef THEME_SERVER_TRACES
+ qWarning() << "Cannot open" << fileName;
+#endif // THEME_SERVER_TRACES
+ //-1 represents invalid offset
+ manager->free(effOffset);
+ effOffset = -1;
+ }
+
+ // add the filename and css offset to the secondary cache.
+ if (sharedCache && effOffset != -1) {
+ // no need to check if this item is already present in the
+ // cache as the parsing of the file happens only once
+ // in the server side.
+ try {
+ HbSharedCacheItem cacheItem(fileName, effOffset);
+ sharedCache->append(cacheItem);
+ } catch (std::bad_alloc &badAlloc) {
+ // item is not appended.
+ Q_UNUSED(badAlloc)
+ }
+ }
+ }
+
+#ifdef THEME_SERVER_TRACES
+ qDebug() << "returning offset: " << effOffset;
+#endif // THEME_SERVER_TRACES
+
+ return effOffset;
+}
+
+/**
+ * cleanupUnusedCss function removes css-resources (stylesheets), whose reference count
+ * is zero, it also releases the shared memory occupied by those resources.
+ * \param cache server css-cache
+ *
+ */
+void HbThemeServerUtils::cleanupUnusedCss(HbCache *cache)
+{
+ QList<HbCacheItem*> list = cache->lruList();
+ while (!list.isEmpty()) {
+ HbCacheItem* itemToRemove = list.takeFirst();
+ if (itemToRemove->offset != -1) {
+ HbCss::StyleSheet *styleSheet =
+ HbMemoryUtils::getAddress<HbCss::StyleSheet>(HbMemoryManager::SharedMemory,
+ itemToRemove->offset);
+ HbMemoryUtils::release<HbCss::StyleSheet>(styleSheet);
+ itemToRemove->offset = -1;
+ }
+ //Since we are cleaning up css-resources whose ref-count is zero, these entries will be
+ // removed from actual cache.
+ cache->cacheHandle().remove(itemToRemove->fileName);
+ }
+}
+
+/**
+ * sharedCacheItemOffset function returns the offset of the cache item
+ * for the given key
+ * \param key
+ *
+ */
+int HbThemeServerUtils::sharedCacheItemOffset(const QString & key)
+{
+ if (sharedCache) {
+ int count = sharedCache->count();
+ for (int i = 0; i < count ; i++) {
+ if (key == sharedCache->at(i).key) {
+ return sharedCache->at(i).offset;
+ }
+ }
+ }
+ return -1;
+}