src/hbcore/image/hbiconloader.cpp
changeset 28 b7da29130b0e
parent 23 e6ad4ef83b23
child 30 80e4d18b72f5
--- a/src/hbcore/image/hbiconloader.cpp	Thu Sep 02 20:44:51 2010 +0300
+++ b/src/hbcore/image/hbiconloader.cpp	Fri Sep 17 08:32:10 2010 +0300
@@ -63,18 +63,22 @@
 
 #ifdef HB_NVG_CS_ICON
 #include "hbeglstate_p.h"
+#include "hbnvgrasterizer_p.h"
 #endif
 
 // SVG animation is currently disabled because of bugs in QT's svg engine
 #undef HB_SVG_ANIMATION
 
+//#define HB_ICON_CACHE_DEBUG
+
 // Icon name without extension
 static const char *s_unknown = "unknown";
 
 /*!
     \class HbIconLoader
 
-    \brief HbIconLoader loads icons according to the Freedesktop Icon Theme Specification
+    \brief HbIconLoader loads and caches vector and raster icons
+    either via the Theme Server or directly from files/resources.
 
     \internal
 */
@@ -82,51 +86,7 @@
 // Allocated dynamically so it can be deleted before the application object is destroyed.
 // Deleting it later causes segmentation fault.
 static HbIconLoader *theLoader = 0;
-
-/*
- * Client side caching of sgimage icon required, as sgimage lite cannot be
- * opened multiple times
- *
- * It is also beneficial for performance, because it reduces IPC in certain
- * cases.
- *
- * Note that by default this is not a permanent cache, i.e. when an iconimpl's
- * refcount reaches zero it is removed from the cache.  This means that the
- * cache is beneficial for having the same icon rendered by two or more HbIcons
- * at the same time (very typical in some itemview (e.g. list widget) cases),
- * but it would not benefit a load-unload-load scenario because the icon is
- * removed from the cache during the unload when there are no references
- * anymore.
- *
- * However the cachekeeper below will change this behavior, preventing refcounts
- * reaching zero in unLoadIcon(), so this cache may contain also icons that are
- * not really in use and are only referenced by the cachekeeper. This is
- * required for further reduction of IPC calls.
- */
-static QHash<QByteArray, HbIconImpl *> iconImplCache;
-
-// The global cachekeeper instance will hold references to icons that would
-// normally be unloaded (i.e. mIcons will contain icons with refcount 1).
-// 
-// Icons get added from unLoadIcon(), meaning that if the cachekeeper decides to
-// hold a reference then the icon is not really unloaded (and thus stays in
-// iconImplCache).
-//
-// When the icon gets referenced due to a cache hit, in loadIcon() and other
-// places, the icon is removed from the cachekeeper.
-class CacheKeeper {
-public:
-    CacheKeeper() : mConsumption(0) { }
-    void ref(HbIconImpl *icon);
-    void unref(HbIconImpl *icon);
-    void clear();
-private:
-    void del(HbIconImpl *icon, bool sendUnloadReq);
-    QList<HbIconImpl *> mIcons;
-    int mConsumption;
-};
-
-Q_GLOBAL_STATIC(CacheKeeper, cacheKeeper)
+static bool loaderDestroyed = false;
 
 // The max consumption for the icons held by the cachekeeper, assuming that each
 // icon is 32bpp. Note that the cachekeeper's content is cleared also when
@@ -212,6 +172,53 @@
     QMutex mLocalLoadMutex;
     QMutex mIconSourceMutex;
     friend class HbLocalLoaderThread;
+
+    /*
+     * Client side caching of sgimage icon required, as sgimage lite cannot be
+     * opened multiple times
+     *
+     * It is also beneficial for performance, because it reduces IPC in certain
+     * cases.
+     *
+     * Note that by default this is not a permanent cache, i.e. when an iconimpl's
+     * refcount reaches zero it is removed from the cache.  This means that the
+     * cache is beneficial for having the same icon rendered by two or more HbIcons
+     * at the same time (very typical in some itemview (e.g. list widget) cases),
+     * but it would not benefit a load-unload-load scenario because the icon is
+     * removed from the cache during the unload when there are no references
+     * anymore.
+     *
+     * However the cachekeeper below will change this behavior, preventing refcounts
+     * reaching zero in unLoadIcon(), so this cache may contain also icons that are
+     * not really in use and are only referenced by the cachekeeper. This is
+     * required for further reduction of IPC calls.
+     */
+    QHash<QByteArray, HbIconImpl *> iconImplCache;
+
+    // The global cachekeeper instance will hold references to icons that would
+    // normally be unloaded (i.e. mIcons will contain icons with refcount 1).
+    //
+    // Icons get added from unLoadIcon(), meaning that if the cachekeeper decides to
+    // hold a reference then the icon is not really unloaded (and thus stays in
+    // iconImplCache).
+    //
+    // When the icon gets referenced due to a cache hit, in loadIcon() and other
+    // places, the icon is removed from the cachekeeper.
+    class CacheKeeper {
+    public:
+        CacheKeeper(HbIconLoaderPrivate *p) : mConsumption(0), mIconLoaderPrivate(p) { }
+        void ref(HbIconImpl *icon);
+        void unref(HbIconImpl *icon);
+        void clear();
+    private:
+        void del(HbIconImpl *icon, bool sendUnloadReq);
+        QList<HbIconImpl *> mIcons;
+        int mConsumption;
+        HbIconLoaderPrivate *mIconLoaderPrivate;
+        friend class HbIconLoaderPrivate;
+    };
+
+    CacheKeeper cacheKeeper;
 };
 
 void HbLocalLoaderThread::run()
@@ -231,7 +238,8 @@
     lastIconSource(0),
     layoutMirrored(Unknown),
     mLocalLoadMutex(QMutex::Recursive),
-    mIconSourceMutex(QMutex::Recursive)
+    mIconSourceMutex(QMutex::Recursive),
+    cacheKeeper(this)
 {
     qRegisterMetaType<HbIconImpl *>();
     qRegisterMetaType<HbIconLoadingParams>();
@@ -249,6 +257,12 @@
     mLocalLoaderThread.wait();
     delete lastIconSource;
     qDeleteAll(mActiveAsyncRequests);
+    cacheKeeper.clear();
+    // There may be icons in iconImplCache at this point and they are not
+    // leftovers so they must not be destroyed. In many cases the HbIconLoader
+    // is destroyed before the destructors of icon engines or framedrawers are run
+    // so it must be left up to them to correctly unref all icons.
+    iconImplCache.clear();
 }
 
 HbIconLoaderPrivate *HbIconLoaderPrivate::global()
@@ -607,28 +621,32 @@
     renderMode = EHWRendering;
 
     // Delete the icon loader when the application is destroyed.
-    connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(destroy()));
+    connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), SLOT(destroy()));
 
     connect(HbLayoutDirectionNotifier::instance(), SIGNAL(layoutDirectionChangeStarted()),
             this, SLOT(updateLayoutDirection()));
 
-#ifdef HB_TOOL_INTERFACE
-    // This enables partial theme updates.
-    connect(&hbInstance->theme()->d_ptr->iconTheme, SIGNAL(iconsUpdated(QStringList)), this, SLOT(themeChange(QStringList)));
-#endif
+    HbTheme *theme = hbInstance->theme();
+    connect(&theme->d_ptr->iconTheme, SIGNAL(iconsUpdated(QStringList)), SLOT(themeChange(QStringList)));
+    connect(theme, SIGNAL(changeFinished()), SLOT(themeChangeFinished()));
 }
 
 HbIconLoader::~HbIconLoader()
 {
-    cacheKeeper()->clear();
     delete d;
+    loaderDestroyed = true;
 }
 
 HbIconLoader *HbIconLoader::global()
 {
     // Allocated dynamically so it can be deleted before the application object is destroyed.
     // Deleting it later causes segmentation fault.
-    if (!theLoader) {
+    // Once destroyed, creating the loader again must not be allowed (e.g. because there
+    // may not be a QApplication instance anymore at this stage). It is normal to
+    // return null pointer in this case, it can happen only during app shutdown. If anybody
+    // is using HbIconLoader::global() from destructors, they have to be prepared for the
+    // null ptr result too.
+    if (!theLoader && !loaderDestroyed) {
         theLoader = new HbIconLoader;
     }
 
@@ -784,7 +802,29 @@
 
 void HbIconLoader::themeChange(const QStringList &updatedFiles)
 {
-    foreach(HbFrameDrawerPrivate * frameDrawer, frameDrawerInstanceList) frameDrawer->themeChange(updatedFiles);
+    // For icons, the content is dropped in HbIconEngine.
+    // For framedrawers, HbFrameItem notifies the framedrawer when the theme changes.
+    // This below is only needed to support partial theme updates for framedrawers in external tools.
+    // (standalone framedrawers do not update automatically, except in tools)
+#ifdef HB_TOOL_INTERFACE
+    foreach(HbFrameDrawerPrivate * frameDrawer, frameDrawerInstanceList) {
+        frameDrawer->themeChange(updatedFiles);
+    }
+#else
+    Q_UNUSED(updatedFiles);
+#endif
+}
+
+void HbIconLoader::themeChangeFinished()
+{
+#ifdef HB_ICON_CACHE_DEBUG
+    qDebug("HbIconLoader::themeChangeFinished: dropping unused icons");
+#endif
+    // We need to drop unused icons to prevent reusing them now that the theme is different.
+    // Doing it in themeChange() would not be right, it would be too early,
+    // because unloading would make the dropped icons unused (but referenced) so
+    // we would end up with reusing the old graphics. This here is safe.
+    d->cacheKeeper.clear();
 }
 
 void HbIconLoader::destroy()
@@ -813,8 +853,7 @@
 void HbIconLoader::handleForegroundLost()
 {
 #if defined(HB_SGIMAGE_ICON) || defined(HB_NVG_CS_ICON)
-    // Remove SGImage/NVG type of icons
-    freeGpuIconData();
+    freeIconData();
     // delete the VGImage
     HbEglStates *eglStateInstance = HbEglStates::global();
     eglStateInstance->handleForegroundLost();
@@ -829,7 +868,12 @@
 void HbIconLoader::removeItemInCache(HbIconImpl *iconImpl)
 {
     if (iconImpl) {
-        iconImplCache.remove(iconImplCache.key(iconImpl));
+        if (d->iconImplCache.remove(d->iconImplCache.key(iconImpl)) > 0) {
+#ifdef HB_ICON_CACHE_DEBUG
+            qDebug() << "HbIconLoader::removeItemInCache: Removed"
+                     << iconImpl->iconFileName() << iconImpl->keySize();
+#endif
+        }
     }
 }
 
@@ -840,20 +884,41 @@
 void HbIconLoader::freeGpuIconData()
 {
 #if defined(HB_SGIMAGE_ICON) || defined(HB_NVG_CS_ICON)
-    cacheKeeper()->clear(); // unref all unused icons
+    d->cacheKeeper.clear(); // unref all unused icons
+    for (int i = 0; i < iconEngineList.count(); i++) {
+        HbIconEngine *engine = iconEngineList.at(i);
+        if (engine->iconFormatType() == SGIMAGE || engine->iconFormatType() == NVG) {
+            engine->resetIconImpl();
+        }
+    }
+    for (int i = 0; i < frameDrawerInstanceList.count(); i++) {
+        HbFrameDrawerPrivate *fd = frameDrawerInstanceList.at(i);
+        if (fd->iconFormatType() == SGIMAGE || fd->iconFormatType() == NVG) {
+            fd->resetMaskableIcon();
+        }
+    }
+#endif
+}
+
+/*!
+ *  Cleans up (deletes) the HbIconImpl instances at the client side
+ *  It also resets the engine's iconImpl and MaskableIcon's iconImpl
+ */
+void HbIconLoader::freeIconData()
+{
+    d->cacheKeeper.clear(); // unref all unused icons
     for (int i = 0; i < iconEngineList.count(); i++) {
         HbIconEngine *engine = iconEngineList.at(i);
         engine->resetIconImpl();
     }
     for (int i = 0; i < frameDrawerInstanceList.count(); i++) {
         HbFrameDrawerPrivate *fd = frameDrawerInstanceList.at(i);
-        if ((fd->iconFormatType() == SGIMAGE) || (fd->iconFormatType() == NVG)) {
-            fd->resetMaskableIcon();
-        }
+        fd->resetMaskableIcon();
+
     }
-#endif
 }
 
+
 /*!
   \internal
 
@@ -1200,8 +1265,8 @@
 
 #endif // HB_SVG_ANIMATION
 
-        params.image = QImage(renderSize.toSize(), QImage::Format_ARGB32); // should be _Premultiplied but that results in incorrect rendering
-        params.image.fill(Qt::transparent);
+        params.image = QImage(renderSize.toSize(), QImage::Format_ARGB32_Premultiplied);
+        params.image.fill(QColor(Qt::transparent).rgba());
         QPainter painter;
         painter.begin(&params.image);
         svgRenderer->render(&painter, QRectF(QPointF(), renderSize.toSize()));
@@ -1241,8 +1306,8 @@
             sy = renderSize.height() / picSize.height();
         }
 
-        params.image = QImage(renderSize.toSize(), QImage::Format_ARGB32);
-        params.image.fill(Qt::transparent);
+        params.image = QImage(renderSize.toSize(), QImage::Format_ARGB32_Premultiplied);
+        params.image.fill(QColor(Qt::transparent).rgba());
         QPainter painter;
         painter.begin(&params.image);
         if (scale) {
@@ -1356,6 +1421,47 @@
     source->deleteImageIfLargerThan(IMAGE_SIZE_LIMIT);
 }
 
+void HbIconLoader::loadNvgIcon(HbIconLoadingParams &params )
+{
+#ifdef HB_NVG_CS_ICON
+    HbIconSource *source = getIconSource(params.iconFileName, "NVG");
+    if (!source) {
+        return;
+    }
+
+    HbNvgRasterizer * nvgRasterizer = HbNvgRasterizer::global();
+    QByteArray *sourceByteArray = source->byteArray();
+    if( !sourceByteArray ) {
+       return;
+    }
+
+    QByteArray nvgArray = *sourceByteArray;
+    QSizeF renderSize = source->defaultSize();
+    if (!params.isDefaultSize) {
+        renderSize.scale(params.size, params.aspectRatioMode);
+    } else if (params.options.testFlag(ResolutionCorrected)) {
+        applyResolutionCorrection(renderSize);
+    }
+
+    QSize iconSize = renderSize.toSize();
+    QImage image(iconSize, QImage::Format_ARGB32_Premultiplied);
+    QImage::Format imageFormat = image.format();
+    int stride = image.bytesPerLine();
+    void * rasterizedData = image.bits();
+
+    bool success = nvgRasterizer->rasterize(nvgArray, iconSize,
+                                            params.aspectRatioMode,
+                                            rasterizedData, stride,imageFormat);
+    if (success) {
+        params.image = image;
+    }
+
+#else
+    Q_UNUSED(params)
+#endif
+
+}
+
 /*!
  * \fn void HbIconLoader::switchRenderingMode()
  *
@@ -1375,7 +1481,7 @@
 
 #if defined(HB_SGIMAGE_ICON) || defined(HB_NVG_CS_ICON)
     if (newRenderMode != renderMode) {
-        cacheKeeper()->clear(); // unref all unused icons
+        d->cacheKeeper.clear(); // unref all unused icons
         if (newRenderMode == ESWRendering) {
             // switching from HW to SW mode
             freeGpuIconData();
@@ -1396,6 +1502,8 @@
     }
 }
 
+// Note that this is not the same as HbThemeUtils::isLogicalName.
+// A non-logical name can still indicate content that must go through themeserver.
 inline bool isLocalContent(const QString &iconName)
 {
     // Check if we have a simple file or embedded resource, given with full
@@ -1406,11 +1514,6 @@
         || (iconName.length() > 1 && iconName.at(1) == ':')
         || (iconName.contains('.') && !iconName.startsWith("qtg_", Qt::CaseInsensitive));
 
-    // Cannot load NVG locally. Remove this check when local loading for NVG is available.
-    if (iconName.endsWith(".nvg", Qt::CaseInsensitive)) {
-        localContent = false;
-    }
-
     return localContent;
 }
 
@@ -1552,12 +1655,12 @@
             if (serverUseAllowed(iconName, options)
             // Use the server only for theme graphics.
             // For local files, i.e. anything that is not a single logical name, use local loading.
-            && !isLocalContent(iconName) 
+            && !isLocalContent(iconName)
             && format != "MNG"
             && format != "GIF"
             && manager) {
 
-            //Initiate an IPC to themeserver to get the icon-data from the server.
+            // Initiate an IPC to themeserver to get the icon-data from the server.
 
             if (callback) {
                 getIconFromServerAsync(params, callback, callbackParam);
@@ -1566,6 +1669,9 @@
 
             icon = getIconFromServer(params);
 
+            // No check for DoNotCache here. If we decided to use the server regardless of
+            // the flag then there's a chance that we have to cache (in case of SgImage
+            // for example) for proper operation, no matter what.
             if (icon) {
                 cacheIcon(params, icon, &cacheKey);
                 return icon;
@@ -1600,6 +1706,12 @@
 
 HbIconImpl *HbIconLoader::lookupInCache(const HbIconLoadingParams &params, QByteArray *outCacheKey)
 {
+    // Stop right away for resolution corrected icons, these may get false cache
+    // hits. The use of such icons should be very rare anyway.
+    if (params.options.testFlag(ResolutionCorrected)) {
+        return 0;
+    }
+
     QByteArray cacheKey = d->createCacheKeyFrom(params.iconName,
                                                 params.size,
                                                 params.aspectRatioMode,
@@ -1609,13 +1721,13 @@
     if (outCacheKey) {
         *outCacheKey = cacheKey;
     }
-    if (iconImplCache.contains(cacheKey)) {
-        HbIconImpl *icon = iconImplCache.value(cacheKey);
+    if (d->iconImplCache.contains(cacheKey)) {
+        HbIconImpl *icon = d->iconImplCache.value(cacheKey);
         icon->incrementRefCount();
-        cacheKeeper()->unref(icon);
+        d->cacheKeeper.unref(icon);
 #ifdef HB_ICON_CACHE_DEBUG
-        qDebug() << "HbIconLoader::loadIcon(): " << "Cache hit in iconImplCache for" << params.iconName << params.size;
-        qDebug() << "HbIconLoader::loadIcon(): Client RefCount now = " << icon->refCount();
+        qDebug() << "HbIconLoader::lookupInCache: Cache hit for" << params.iconName << params.size
+                 << "Client refcount now" << icon->refCount();
 #endif
         return icon;
     }
@@ -1628,6 +1740,9 @@
     QMutexLocker iconSourceLocker(&d->mIconSourceMutex);
     if (format == "SVG") {
         loadSvgIcon(params);
+    } else if(format == "NVG") {
+        //support for client side rendering of nvg icons
+        loadNvgIcon(params);
     } else if (format == "PIC") {
         loadPictureIcon(params);
     } else if (format == "MNG" || format == "GIF") {
@@ -1683,7 +1798,7 @@
         }
     }
 
-    return new HbPixmapIconImpl(pm, params.iconFileName);
+    return HbIconImplCreator::createIconImpl(pm, params);
 }
 
 void HbIconLoader::cacheIcon(const HbIconLoadingParams &params, HbIconImpl *icon, QByteArray *existingCacheKey)
@@ -1692,17 +1807,18 @@
     if (existingCacheKey) {
         cacheKey = *existingCacheKey;
     } else {
-        cacheKey = d->createCacheKeyFrom(params.iconName, 
+        cacheKey = d->createCacheKeyFrom(params.iconName,
                                          params.size,
                                          params.aspectRatioMode,
-                                         params.mode, 
-                                         params.mirrored, 
+                                         params.mode,
+                                         params.mirrored,
                                          params.color);
     }
-    iconImplCache.insert(cacheKey, icon);
+    d->iconImplCache.insert(cacheKey, icon);
 
 #ifdef HB_ICON_CACHE_DEBUG
-    qDebug() << "HbIconLoader::loadIcon(): " << params.iconName << " inserted into impl-cache, ref-count now = " << icon->refCount();
+    qDebug() << "HbIconLoader:cacheIcon: " << params.iconName
+             << "inserted into local cache, client refcount now" << icon->refCount();
 #endif
 }
 
@@ -1759,6 +1875,8 @@
         const QColor &color)
 {
     Q_UNUSED(color);
+    Q_UNUSED(multiPieceImpls);
+
     HbIconImpl *icon = 0;
     if (listOfIcons.count() == 0) {
         return icon;
@@ -1771,7 +1889,8 @@
     bool mirroredIconFound = false;
 
     // We don't want to get the consolidated icon for only NVG build, ie. without SGImage lite support.
-    // Consolidated icon will be created for NVG with SGImage lite support and when NVG is not available.
+    // Consolidated icon will be created for NVG with SGImage lite support.
+    // and when NVG is not available.
     QByteArray cacheKey = d->createCacheKeyFrom(
         multiPartIconData.multiPartIconId,
         size,
@@ -1780,13 +1899,13 @@
         mirrored,
         color);
     //If consolidated icon found in the client's cache, increment ref-count and return
-    if (iconImplCache.contains(cacheKey)) {
-        HbIconImpl *ptr = iconImplCache.value(cacheKey);
+    if (d->iconImplCache.contains(cacheKey)) {
+        HbIconImpl *ptr = d->iconImplCache.value(cacheKey);
         ptr->incrementRefCount();
-        cacheKeeper()->unref(ptr);
+        d->cacheKeeper.unref(ptr);
 #ifdef HB_ICON_CACHE_DEBUG
-        qDebug() << "HbIconLoader::loadMultiPieceIcon()" << "Cache hit in iconImplCache " << multiPartIconData.multiPartIconId << size;
-        qDebug() << "HbIconLoader::loadMultiPieceIcon : Client RefCount now = " << ptr->refCount();
+        qDebug() << "HbIconLoader::loadMultiPieceIcon: Cache hit" << multiPartIconData.multiPartIconId
+                 << size << "Client refcount now" << ptr->refCount();
 #endif
         return ptr;
     }
@@ -1835,56 +1954,83 @@
         // Creating HbIconImpl for the consolidated icon-data returned from themeserver.
         icon = HbIconImplCreator::createIconImpl(iconInfo, params);
         if (icon) {
-            // Not yet in local cache (was checked before the server request) so insert.
-            iconImplCache.insert(cacheKey, icon);
             icon->setMultiPieceIcon();
-#ifdef HB_ICON_CACHE_DEBUG
-            qDebug() << "HbIconLoader::loadMultiPieceIcon(): " << params.iconName << " inserted into impl-cache, ref-count now = " << icon->refCount();
-#endif
         }
-        return icon;
     } else {
-        //themeserver wasn't successful in stitching of consolidated icon
-        multiPieceImpls.clear();
-        int count = iconPathList.count();
-        QVector<QSizeF> sizeList;
-        for (int i = 0; i < count; i++) {
-            sizeList << multiPartIconData.pixmapSizes[i];
-        }
-
-#ifdef Q_OS_SYMBIAN
-        //Since the consolidated icon-creation failed on themeserver, request loading of individual
-        //frame-items in a single IPC request to themeserver
-        getMultiIconImplFromServer(iconPathList, sizeList,
+        //Consolidated (stitched) icon could not be loaded on themeserver side, taking
+        //fallback path for creating the consolidated icon on the client side.
+        icon = createLocalConsolidatedIcon(multiPartIconData,
+                                   iconPathList,
+                                   size,
                                    aspectRatioMode,
                                    mode,
-                                   mirrored,
-                                   mirroredIconFound,
                                    options,
-                                   color,
-                                   HbIconLoader::AnyType,
-                                   HbIconLoader::AnyPurpose,
-                                   multiPieceImpls,
-                                   renderMode);
-#else
-        //For OS other than Symbian, call HbIconLoader::loadIcon to individually load icons
-        for (int i = 0; i < count; i++) {
-            HbIconImpl *impl = loadIcon(iconPathList[i], HbIconLoader::AnyType,
-                                        HbIconLoader::AnyPurpose,
-                                        sizeList.at(i),
-                                        Qt::IgnoreAspectRatio,
-                                        QIcon::Normal,
-                                        (options | DoNotCache));
-            impl->setMultiPieceIcon();
-            if (impl) {
-                multiPieceImpls.append(impl);
-            }
-        }
+                                   color);
+    }
+    
+    if (icon) {
+        // Not yet in local cache (was checked before the server request) so insert.
+        d->iconImplCache.insert(cacheKey, icon);
+#ifdef HB_ICON_CACHE_DEBUG
+        qDebug() << "HbIconLoader::loadMultiPieceIcon: " << multiPartIconData.multiPartIconId
+                 << " inserted into local cache, client refcount now" << icon->refCount();
+#endif
+    }
+    return icon;
+}
 
-#endif
+HbIconImpl * HbIconLoader::createLocalConsolidatedIcon(const HbMultiPartSizeData &multiPartIconData,
+                           const QStringList & iconPathList,
+                           const QSizeF &consolidatedSize,
+                           Qt::AspectRatioMode aspectRatioMode,
+                           QIcon::Mode mode,
+                           const IconLoaderOptions & options,
+                           const QColor &color)
+{
+    // load the icons in to QImage
+    HbIconLoadingParams params;
+    params.purpose = HbIconLoader::AnyPurpose;
+    params.aspectRatioMode = aspectRatioMode;
+    params.mode = mode;
+    params.color = color;
+    params.animator = 0;
+    params.mirrored = options.testFlag(HorizontallyMirrored);
+    params.mirroredIconFound = false;
+    params.mirroringHandled = false;
+    params.modeHandled = false;
+    params.renderMode = renderMode;
+    params.canCache = false;
+    params.animationCreated = false;
+
+    QStringList::const_iterator iterFiles = iconPathList.begin();
+    QStringList::const_iterator iterFilesEnd = iconPathList.end();
 
-        return icon;
+    QImage finalImage(consolidatedSize.toSize(), QImage::Format_ARGB32_Premultiplied);
+    finalImage.fill(QColor(Qt::transparent).rgba());
+    QPainter painter(&finalImage);
+
+    for (int i=0; iterFiles != iterFilesEnd; ++iterFiles, ++i) {
+
+        // Populate icon loading parameters
+        params.iconFileName = *iterFiles;
+        params.size = multiPartIconData.pixmapSizes[i];
+        params.options = options;
+        params.isDefaultSize = params.size.isNull();
+
+        QString format = formatFromPath(params.iconFileName);
+
+        loadLocal(params, format);
+
+        painter.drawImage(multiPartIconData.targets[i].topLeft(),
+                           params.image);
+
+        params.image = QImage();
     }
+    painter.end();
+
+    params.image = finalImage;
+
+    return finishLocal(params);
 }
 
 inline int iconImplConsumption(HbIconImpl *icon)
@@ -1893,7 +2039,7 @@
     return sz.width() * sz.height() * 4;
 }
 
-void CacheKeeper::ref(HbIconImpl *icon)
+void HbIconLoaderPrivate::CacheKeeper::ref(HbIconImpl *icon)
 {
     int consumption = iconImplConsumption(icon);
     // Never hold something more than once and do not ref anything when icons
@@ -1903,11 +2049,16 @@
     if (!mIcons.contains(icon)
         && !HbInstancePrivate::d_ptr()->mDropHiddenIconData
         && consumption < MAX_KEEPALIVE_ITEM_SIZE_BYTES
-        && !iconImplCache.key(icon).isEmpty())
+        && !mIconLoaderPrivate->iconImplCache.key(icon).isEmpty())
     {
         icon->incrementRefCount();
         mIcons.append(icon);
         mConsumption += consumption;
+#ifdef HB_ICON_CACHE_DEBUG
+        qDebug() << "CacheKeeper::ref: Accepted" << icon->iconFileName()
+                 << icon->keySize() << consumption
+                 << "Total consumption now" << mConsumption;
+#endif
         // Now do some housekeeping.
         while (mConsumption > MAX_KEEPALIVE_CACHE_SIZE_BYTES) {
             HbIconImpl *oldest = mIcons.first();
@@ -1919,16 +2070,19 @@
     }
 }
 
-void CacheKeeper::unref(HbIconImpl *icon)
+void HbIconLoaderPrivate::CacheKeeper::unref(HbIconImpl *icon)
 {
     if (mIcons.contains(icon)) {
+#ifdef HB_ICON_CACHE_DEBUG
+        qDebug() << "CacheKeeper::unref: Releasing" << icon->iconFileName() << icon->keySize();
+#endif
         mIcons.removeOne(icon);
         mConsumption -= iconImplConsumption(icon);
         icon->decrementRefCount();
     }
 }
 
-void CacheKeeper::clear()
+void HbIconLoaderPrivate::CacheKeeper::clear()
 {
     // Get rid of all unused icons in the iconimplcache, regardless of
     // the icons' rendering mode. Note that the list may contain non-sgimage
@@ -1952,7 +2106,7 @@
     }
 }
 
-void CacheKeeper::del(HbIconImpl *icon, bool sendUnloadReq)
+void HbIconLoaderPrivate::CacheKeeper::del(HbIconImpl *icon, bool sendUnloadReq)
 {
     HbIconLoader::global()->removeItemInCache(icon);
     if (sendUnloadReq && icon->isCreatedOnServer()) {
@@ -1977,7 +2131,7 @@
         if (!unloadedByServer) {
             // Offer the icon to the cacheKeeper first.
             if (!noKeep) {
-                cacheKeeper()->ref(icon);
+                d->cacheKeeper.ref(icon);
             }
             // If it was accepted then the refcount was increased so stop here.
             if (icon->refCount() > 0) {
@@ -2011,117 +2165,6 @@
 }
 
 /*!
- * \fn void HbIconLoader::getMultiIconImplFromServer()
- *
- * This function is responsible for loading individual pieces of a multi-piece icon.
- * This gets called if the consolidated icon-creation process on themeserver has failed.
- * This function initiates a single IPC to themeserver in which it sends out icon-parameters
- * for each of the frame-items and gets back a list of HbSharedIconInfo corresponding to
- * individual pieces.
- *
- */
-void HbIconLoader::getMultiIconImplFromServer(QStringList &multiPartIconList,
-        QVector<QSizeF> &sizeList,
-        Qt::AspectRatioMode aspectRatioMode,
-        QIcon::Mode mode,
-        bool mirrored,
-        bool mirroredIconFound,
-        HbIconLoader::IconLoaderOptions options,
-        const QColor &color,
-        HbIconLoader::IconDataType type,
-        HbIconLoader::Purpose,
-        QVector<HbIconImpl *> & iconImplList,
-        HbRenderingMode currRenderMode)
-{
-    Q_UNUSED(type);
-    QVector<int> posList;
-    // Search the client cache first before asking the server.
-    int count = multiPartIconList.count();
-    QVector<QByteArray> cacheKeys;
-    for (int i = 0; i < count; i++) {
-        QByteArray cacheKey = d->createCacheKeyFrom(multiPartIconList[i],
-                                                    sizeList[i],
-                                                    aspectRatioMode,
-                                                    mode,
-                                                    mirrored,
-                                                    color);
-        cacheKeys.append(cacheKey);
-        // Look up in the local iconImplCache.
-        HbIconImpl *ptr = 0;
-        if (iconImplCache.contains(cacheKey)) {
-            ptr = iconImplCache.value(cacheKey);
-            // If a specific frame-item is found in local impl-cache,
-            // increment the ref count and remove the entry from the
-            // list that needs to be sent to server.
-            ptr->incrementRefCount();
-            cacheKeeper()->unref(ptr);
-#ifdef HB_ICON_CACHE_DEBUG
-            qDebug() << "HbIconLoader::getMultiIconImplFromServer()" << "Cache hit in iconImplCache ";
-            qDebug() << "HbIconLoader::getMultiIconImplFromServer : Client RefCount now = " << ptr->refCount();
-#endif
-            iconImplList.append(ptr);
-            multiPartIconList.replace(i, QString());
-        } else {
-            posList << i;
-        }
-    }
-    for (int i = 0; i < count; i++) {
-        if (multiPartIconList[i].isEmpty()) {
-            multiPartIconList.removeAt(i);
-            sizeList.remove(i);
-            i--;
-        }
-    }
-
-    // If no hit in local cache, ask server for all the pieces' information.
-    if (count > 0) {
-        HbSharedIconInfoList iconInfoList = HbThemeClient::global()->getMultiIconInfo(multiPartIconList, sizeList,
-                                            aspectRatioMode, mode, mirrored, options, color, currRenderMode);
-
-        HbIconImpl *impl = 0;
-
-        HbIconLoadingParams params;
-
-        params.aspectRatioMode = aspectRatioMode;
-        params.mode = mode;
-        params.mirrored = mirrored;
-        params.mirroredIconFound = mirroredIconFound;
-
-        for (int i = 0; i < count;  i++) {
-            params.iconFileName = multiPartIconList[i];
-            params.size = sizeList.at(i);
-            impl = HbIconImplCreator::createIconImpl(iconInfoList.icon[i], params);
-            if (impl) {
-                // Not yet in local cache (was checked before the server request) so insert.
-                iconImplCache.insert(cacheKeys[i], impl);
-#ifdef HB_ICON_CACHE_DEBUG
-                qDebug() << "HbIconLoader::getMultiIconImplFromServer(): "
-                    << params.iconName << " inserted into impl-cache, ref-count now = " << impl->refCount();
-#endif
-            } else {
-                //If for some reason individual frame-item's loading in themeserver fails, use HbIconLoader::loadIcon()
-                // as a fallback option to load it.
-                impl = loadIcon(multiPartIconList[i],
-                                HbIconLoader::AnyType,
-                                HbIconLoader::AnyPurpose,
-                                sizeList.at(i),
-                                Qt::IgnoreAspectRatio,
-                                QIcon::Normal,
-                                (options | DoNotCache));
-            }
-
-            if (impl) {
-                impl->setMultiPieceIcon();
-                if (posList.count() > 0) {
-                    iconImplList.insert(posList.front(), impl);
-                    posList.pop_front();
-                }
-            }
-        }
-    }
-}
-
-/*!
  * HbIconLoader::unLoadMultiIcon
  *
  * This function initiates a single IPC to unload each of the frame-items in a multi-piece icon.
@@ -2136,10 +2179,10 @@
     foreach(HbIconImpl * impl, multiPieceImpls) {
         impl->decrementRefCount();
         if (impl->refCount() == 0) {
-            int rem = iconImplCache.remove(iconImplCache.key(impl));
-            if (rem > 0) {
-#ifdef HB_ICON_TRACES
-                qDebug() << "HbIconLoader::unLoadMultiIcon :Removed from HbIconImpl Cache " << rem << impl->iconFileName() << impl->keySize();
+            if (d->iconImplCache.remove(d->iconImplCache.key(impl)) > 0) {
+#ifdef HB_ICON_CACHE_DEBUG
+                qDebug() << "HbIconLoader::unLoadMultiIcon: Removed from cache"
+                         << impl->iconFileName() << impl->keySize();
 #endif
             }
             if (impl->isCreatedOnServer()) {