--- 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(¶ms.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(¶ms.image);
if (scale) {
@@ -1356,6 +1421,47 @@
source->deleteImageIfLargerThan(IMAGE_SIZE_LIMIT);
}
+void HbIconLoader::loadNvgIcon(HbIconLoadingParams ¶ms )
+{
+#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 ¶ms, 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 ¶ms, 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()) {