src/hbcore/image/hbicon.cpp
changeset 34 ed14f46c0e55
parent 7 923ff622b8b9
--- a/src/hbcore/image/hbicon.cpp	Mon Oct 04 17:49:30 2010 +0300
+++ b/src/hbcore/image/hbicon.cpp	Mon Oct 18 18:23:13 2010 +0300
@@ -146,6 +146,14 @@
          HbIcon instance (before the first paint of the icon) to have any performance
          benefits.
 
+  \b KeepDefaultQIconSize \b (0x20) This flag disables all scaling for icons constructed
+         from QIcon. It has no effect on regular, native HbIcons. It only affects the
+         painting: The size of the HbIcon will remain whatever was set via setSize(), but
+         only a part of that area will be painted. This is similar to
+         HbIconItem::setIconScaling(false) but in that case the underlying icon's size
+         would also be changed to match the default size, while here size() remains
+         unaffected.
+
 */
 
 /*!
@@ -183,7 +191,10 @@
 HbIconPrivate::HbIconPrivate() :
     engine(new HbIconEngine(QString())),
     qicon(engine),
-    badgeInfo(0)
+    badgeInfo(0),
+    mQIconFlags(0),
+    mQIconPixmapMode(QIcon::Normal),
+    mQIconPixmapState(QIcon::Off)
 {
     ref.ref(); // Need to do extra ref so the shared null does not get destructed
 }
@@ -194,7 +205,10 @@
 HbIconPrivate::HbIconPrivate(const QIcon &qicon) :
     engine(0),
     qicon(qicon),
-    badgeInfo(0)
+    badgeInfo(0),
+    mQIconFlags(0),
+    mQIconPixmapMode(QIcon::Normal),
+    mQIconPixmapState(QIcon::Off)
 {
 }
 
@@ -204,7 +218,10 @@
 HbIconPrivate::HbIconPrivate(const QString &iconName) :
     engine(new HbIconEngine(iconName)),
     qicon(engine),
-    badgeInfo(0)
+    badgeInfo(0),
+    mQIconFlags(0),
+    mQIconPixmapMode(QIcon::Normal),
+    mQIconPixmapState(QIcon::Off)
 {
 }
 
@@ -216,7 +233,11 @@
     size(other.size),
     engine(0),
     qicon(),
-    badgeInfo(0)
+    badgeInfo(0),
+    mQIconFlags(other.mQIconFlags),
+    mQIconPixmap(other.mQIconPixmap),
+    mQIconPixmapMode(other.mQIconPixmapMode),
+    mQIconPixmapState(other.mQIconPixmapState)
 {
     if (other.engine) {
         engine = new HbIconEngine(*other.engine);
@@ -311,7 +332,7 @@
 QDataStream &operator>>(QDataStream &stream, HbIconPrivate &icon)
 {
     stream >> icon.size;
-    int enginePtr = 0;
+    qptrdiff enginePtr = 0;
     stream >> enginePtr;
     if (enginePtr) {
         icon.engine = new HbIconEngine(stream);
@@ -378,6 +399,27 @@
     return result;
 }
 
+/*!
+  \internal
+*/
+void HbIconPrivate::setAsync(bool async, HbIconEngine::AsyncCallback callback, void *param)
+{
+    if (engine) {
+        engine->setAsync(async, callback, param);
+    }
+}
+
+/*!
+  \internal
+*/
+bool HbIconPrivate::async() const
+{
+    if (engine) {
+        return engine->async();
+    }
+    return false;
+}
+
 /*! Default constructor. If this constructor is used, the icon name needs to be set
 * by calling HbIcon::setIconName.
 */
@@ -392,27 +434,31 @@
 
 /*! Constructs a new icon with the icon name \a iconName.
 */
-HbIcon::HbIcon(const QString &iconName)
+HbIcon::HbIcon(const QString &iconName) : d( new HbIconPrivate(iconName) )
 {
-    d = new HbIconPrivate(iconName);
 }
 
-/*! Constructs a new icon to be a copy of the given QIcon.
-* Due to the limitations listed below, this constructor should be used only for
-* compatibility reasons if a QIcon instance needs to be passed as a parameter
-* to a method taking a HbIcon parameter.
-* \note If this constructor is used, there are the following limitations in the HbIcon methods.
-* - HbIcon::defaultSize() may return QSizeF().
-* - HbIcon::paint() ignores the parameter aspectRatioMode and converts the given QRectF to QRect.
-* - HbIcon::iconName() returns empty string by default.
-* - HbIcon::pixmap() returns null pixmap.
-* - Colorization and mirroring support are not available.
-* This method should only be used if absolute necessary, as this is not ideal for hardware accelerated environment
-* and there may be huge differences in painting performance when compared to a native HbIcon.
-*/
-HbIcon::HbIcon(const QIcon &icon)
+/*!
+ * Constructs a new icon to be a copy of the given QIcon.  Due to the
+ * limitations listed below, this constructor should be used only for
+ * compatibility reasons if a QIcon instance needs to be passed as a parameter
+ * to a method taking a HbIcon parameter.
+ *
+ * \note If this constructor is used, the following limitations apply:
+ *
+ * - HbIcon::defaultSize() may return QSizeF().
+ * - HbIcon::paint() ignores the parameter aspectRatioMode and converts the given QRectF to QRect.
+ * - HbIcon::iconName() returns empty string by default.
+ * - HbIcon::pixmap() returns null pixmap.
+ * - Colorization and mirroring support are not available.
+ *
+ * This method should only be used if absolute necessary, as this is not ideal
+ * for hardware accelerated environment and there may be huge differences in
+ * painting performance when compared to a native HbIcon.  Some advanced resource
+ * management features are not available for such icons either.
+ */
+HbIcon::HbIcon(const QIcon &icon) : d( new HbIconPrivate(icon) )
 {
-    d = new HbIconPrivate(icon);
 }
 
 /*!
@@ -518,9 +564,6 @@
 * However it is possible to override this theme-specific color with a custom one
 * by calling this function.
 *
-* \warning Currently this method makes use of pixmap() routine in case of NVG icons.
-* pixmap() slows down the hardware accelerated rendering.
-*
 * \sa HbIcon::color(), HbIcon::Colorized
 */
 void HbIcon::setColor(const QColor &color)
@@ -569,9 +612,10 @@
 void HbIcon::setIconName(const QString &iconName)
 {
     if (d->engine && d->engine->iconName() != iconName) {
+        // Icon was normal HbIcon and the name is changed.
         d.detach();
         d->engine->setIconName(iconName);
-    } else {
+    } else if (!d->engine) {
         // Icon was earlier copy constructed from QIcon, but now its name is set,
         // so it becomes a 'real' HbIcon.
         d.detach();
@@ -581,7 +625,9 @@
         // QIcon's assignment operator shares the engine.
         QIcon temp(d->engine);
         d->qicon = temp;
+        d->mQIconPixmap = QPixmap();
     }
+    // Otherwise icon was normal HbIcon and the name is same as before, so do nothing.
 }
 
 /*!
@@ -637,24 +683,50 @@
         } else {
             // This HbIcon was copy constructed from QIcon and
             // we cannot use HbIconEngine for painting.
+
+            // Find out the size: It can be the size set via setSize(), or, in case of
+            // KeepDefaultQIconSize, the first available size, or, if none are set, the
+            // target area's size.
             QSizeF size = this->size();
-            if (!size.isValid()) {
-                // If size is not set, have to use rect size because QIcon
-                // does not provide defaultSize information.
-                size = rect.size();
+            if (flags().testFlag(KeepDefaultQIconSize)) {
+                QList<QSize> sizes = d->qicon.availableSizes();
+                if (!sizes.isEmpty()) {
+                    size = sizes.at(0);
+                }
+            } else {
+                if (!size.isValid()) {
+                    size = rect.size();
+                }
             }
 
-            QPixmap pixmap = d->qicon.pixmap(size.toSize(), mode, state);
+            // Get the pixmap with the needed size.
+            QPixmap pixmap;
+            QSize intSize = size.toSize();
+            bool usingCached = false;
+            if (d->mQIconPixmap.size() == intSize
+                && mode == d->mQIconPixmapMode
+                && state == d->mQIconPixmapState)
+            {
+                pixmap = d->mQIconPixmap;
+                usingCached = true;
+            } else {
+                pixmap = d->qicon.pixmap(intSize, mode, state);
+                d->mQIconPixmap = pixmap;
+                d->mQIconPixmapMode = mode;
+                d->mQIconPixmapState = state;
+            }
             QSizeF pixmapSize = pixmap.size();
 
-            // QIcon::pixmap() will not do upscaling.
-            if (pixmapSize.width() < size.width() || pixmapSize.height() < size.height()) {
+            // QIcon::pixmap() will not do upscaling, do it here if needed.
+            if (!pixmap.isNull() && !usingCached && !flags().testFlag(KeepDefaultQIconSize)
+                && (pixmapSize.width() < size.width() || pixmapSize.height() < size.height()))
+            {
                 // Native HbIcons are scaled using SmoothTransformation so use the same.
                 pixmap = pixmap.scaled(size.toSize(), aspectRatioMode, Qt::SmoothTransformation);
                 pixmapSize = pixmap.size();
             }
 
-            // Adjust the alignment
+            // Adjust the alignment.
             QPointF topLeft = rect.topLeft();
 
             if (alignment & Qt::AlignRight) {
@@ -669,9 +741,10 @@
                 topLeft.setY(topLeft.y() + (rect.height() - pixmapSize.height()) / 2);
             }
 
+            // Draw.
             painter->drawPixmap(topLeft, pixmap, pixmap.rect());
 
-            // Draw the badges on this icon
+            // Draw the badges on this icon.
             if (d->badgeInfo) {
                 d->badgeInfo->paint(painter, rect, mode, state, false);
             }
@@ -684,7 +757,7 @@
 */
 QSizeF HbIcon::size() const
 {
-    if ((static_cast<int>(flags()) & HbIcon::ResolutionCorrected)) {
+    if (flags().testFlag(HbIcon::ResolutionCorrected)) {
         if (d->engine) {
             d->size = d->engine->size();
         }
@@ -794,7 +867,7 @@
     if (d->engine) {
         return d->engine->flags();
     } else {
-        return (HbIcon::Flags)0;
+        return d->mQIconFlags;
     }
 }
 
@@ -807,6 +880,9 @@
             d.detach();
             d->engine->setFlags(flags);
         }
+    } else if (flags != d->mQIconFlags) {
+        d.detach();
+        d->mQIconFlags = flags;
     }
 }
 
@@ -912,7 +988,7 @@
  * Adds a badge icon to the existing icon. The badge icons
  * are drawn relative to the alignment you specify with the
  * z-order you provide.
- * 
+ *
  * By default the badge icon will use its default size.  If this is
  * not suitable (which is typical in case of vector graphics) then
  * call setSize() explicitly on \a badge before passing it to this
@@ -1002,14 +1078,14 @@
     Clears the icon data (e.g. QPixmaps that are stored internally) but does not
     touch the settings, e.g. the size, state, flags, unlike clear().
 
-    The call is simply forwarded to the underlying HbIconEngine. This function
-    has no effect when the icon was constructed from a QIcon.
-
     \internal
 */
 void HbIconPrivate::clearStoredIconContent()
 {
+    // No need to detach here, usually the more icon's data we drop, the better. There are
+    // no visual results anyway, icon data is reloaded next time the icon is painted.
     if (engine) {
         engine->clearStoredIconContent();
     }
+    mQIconPixmap = QPixmap();
 }