src/hbcore/image/hbiconanimation.cpp
changeset 0 16d8024aca5e
child 5 627c4a0fd0e7
equal deleted inserted replaced
-1:000000000000 0:16d8024aca5e
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (developer.feedback@nokia.com)
       
     6 **
       
     7 ** This file is part of the HbCore module of the UI Extensions for Mobile.
       
     8 **
       
     9 ** GNU Lesser General Public License Usage
       
    10 ** This file may be used under the terms of the GNU Lesser General Public
       
    11 ** License version 2.1 as published by the Free Software Foundation and
       
    12 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
       
    13 ** Please review the following information to ensure the GNU Lesser General
       
    14 ** Public License version 2.1 requirements will be met:
       
    15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    16 **
       
    17 ** In addition, as a special exception, Nokia gives you certain additional
       
    18 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    20 **
       
    21 ** If you have questions regarding the use of this file, please contact
       
    22 ** Nokia at developer.feedback@nokia.com.
       
    23 **
       
    24 ****************************************************************************/
       
    25 
       
    26 #include "hbiconanimation_p.h"
       
    27 #include "hbimagetraces_p.h"
       
    28 #include "hbiconloader_p.h"
       
    29 #include "hbiconanimationmanager_p.h"
       
    30 #include "hbiconanimator.h"
       
    31 #include "hbiconanimator_p.h"
       
    32 #include "hbtimer_p.h"
       
    33 
       
    34 
       
    35 #include <QSvgRenderer>
       
    36 #include <QImageReader>
       
    37 #include <QPainter>
       
    38 #include <QPixmap>
       
    39 #include <QDebug>
       
    40 #include <QStyleOption>
       
    41 #include <QApplication>
       
    42 #include <QPalette>
       
    43 
       
    44 HbIconAnimation::HbIconAnimation(HbIconAnimator *animator, const QString &iconName) :
       
    45     mIconName(iconName),
       
    46     mMirrored(false),
       
    47     mResolutionCorrected(false),
       
    48     mAspectRatioMode(Qt::KeepAspectRatio),
       
    49     mMode(QIcon::Normal),
       
    50     mPlayMode(HbIconAnimationDefinition::PlayOnce),
       
    51     mStartSignalTimer(0),
       
    52     mFresh(true),
       
    53     mAnimMgrD(HbIconAnimationManagerPrivate::d_ptr(HbIconAnimationManager::global())),
       
    54     mColor(QColor()),
       
    55     mAnimator(animator),
       
    56     mView(0),
       
    57     mPaused(false),
       
    58     mPausedDueToBackground(false)
       
    59     {
       
    60     Q_ASSERT(!(animator->d->animation));
       
    61     // Set the animation in the animator, it takes ownership of this object.
       
    62     animator->d->animation = this;
       
    63 
       
    64 #ifdef HB_ICON_TRACES
       
    65     qDebug() << "HbIconAnimation created: " << mIconName;
       
    66 #endif
       
    67     }
       
    68 
       
    69 HbIconAnimation::~HbIconAnimation()
       
    70 {
       
    71 #ifdef HB_ICON_TRACES
       
    72     qDebug() << "HbIconAnimation destroyed: " << mIconName;
       
    73 #endif
       
    74     mAnimMgrD->animNotPlaying(this);
       
    75 }
       
    76 
       
    77 QString HbIconAnimation::iconName() const
       
    78 {
       
    79     return mIconName;
       
    80 }
       
    81 
       
    82 QSizeF HbIconAnimation::size() const
       
    83 {
       
    84     return mSize;
       
    85 }
       
    86 
       
    87 void HbIconAnimation::setSize(const QSizeF &size)
       
    88 {
       
    89     // If size changed, invalidate calculated render size
       
    90     if (size != mSize) {
       
    91         mRenderSize = QSizeF();
       
    92     }
       
    93 
       
    94     mSize = size;
       
    95 }
       
    96 
       
    97 QColor HbIconAnimation::color() const
       
    98 {
       
    99     return mColor;
       
   100 }
       
   101 	
       
   102 void HbIconAnimation::setColor(const QColor &color)
       
   103 {
       
   104     mColor = color;
       
   105 }
       
   106 
       
   107 Qt::AspectRatioMode HbIconAnimation::aspectRatioMode() const
       
   108 {
       
   109     return mAspectRatioMode;
       
   110 }
       
   111 
       
   112 void HbIconAnimation::setAspectRatioMode(Qt::AspectRatioMode mode)
       
   113 {
       
   114     // If aspect ratio mode changed, invalidate calculated render size
       
   115     if (mode != mAspectRatioMode) {
       
   116         mRenderSize = QSizeF();
       
   117     }
       
   118 
       
   119     mAspectRatioMode = mode;
       
   120 }
       
   121 
       
   122 QIcon::Mode HbIconAnimation::mode() const
       
   123 {
       
   124     return mMode;
       
   125 }
       
   126 
       
   127 void HbIconAnimation::setMode(QIcon::Mode mode)
       
   128 {
       
   129     mMode = mode;
       
   130 }
       
   131 
       
   132 QSizeF HbIconAnimation::defaultSize() const
       
   133 {
       
   134     return mDefaultSize;
       
   135 }
       
   136 
       
   137 void HbIconAnimation::setDefaultSize(const QSizeF &size)
       
   138 {
       
   139     mDefaultSize = size;
       
   140 }
       
   141 
       
   142 QSizeF HbIconAnimation::renderSize() const
       
   143 {
       
   144     if (mRenderSize.isEmpty()) {
       
   145         const_cast<QSizeF &>(mRenderSize) = mDefaultSize;
       
   146         if (!mSize.isEmpty()) {
       
   147             const_cast<QSizeF &>(mRenderSize).scale(mSize, mAspectRatioMode);
       
   148         }
       
   149         // Apply resolution correction
       
   150         if (mResolutionCorrected) {
       
   151             HbIconLoader *loader = HbIconLoader::global();
       
   152             loader->applyResolutionCorrection(const_cast<QSizeF &>(mRenderSize));
       
   153         }
       
   154     }
       
   155 
       
   156     return mRenderSize;
       
   157 }
       
   158 
       
   159 void HbIconAnimation::setRenderSize(const QSizeF &size)
       
   160 {
       
   161     mRenderSize = size;
       
   162 }
       
   163 
       
   164 bool HbIconAnimation::mirrored() const
       
   165 {
       
   166     return mMirrored;
       
   167 }
       
   168 
       
   169 void HbIconAnimation::setMirrored(bool mirrored)
       
   170 {
       
   171     mMirrored = mirrored;
       
   172 }
       
   173 
       
   174 bool HbIconAnimation::resolutionCorrected() const
       
   175 {
       
   176     return mResolutionCorrected;
       
   177 }
       
   178 
       
   179 void HbIconAnimation::setResolutionCorrected(bool corrected)
       
   180 {
       
   181     mResolutionCorrected = corrected;
       
   182 }
       
   183 
       
   184 HbIconAnimationDefinition::PlayMode HbIconAnimation::playMode() const
       
   185 {
       
   186     return mPlayMode;
       
   187 }
       
   188 
       
   189 void HbIconAnimation::setPlayMode(HbIconAnimationDefinition::PlayMode playMode)
       
   190 {
       
   191     this->mPlayMode = playMode;
       
   192 }
       
   193 
       
   194 void HbIconAnimation::delayedEmitStarted()
       
   195 {
       
   196     if (!mStartSignalTimer) {
       
   197         mStartSignalTimer = new QTimer(this);
       
   198         connect(mStartSignalTimer, SIGNAL(timeout()), SLOT(notifyAnimationStarted()));
       
   199     }
       
   200     mStartSignalTimer->setSingleShot(true);
       
   201     mStartSignalTimer->start(0);
       
   202 }
       
   203 
       
   204 void HbIconAnimation::notifyAnimationStarted()
       
   205 {
       
   206     mAnimMgrD->animPlaying(this);
       
   207     emit animationStarted();
       
   208 }
       
   209 
       
   210 void HbIconAnimation::notifyAnimationStopped()
       
   211 {
       
   212     mAnimMgrD->animNotPlaying(this);
       
   213     emit animationStopped();
       
   214 }
       
   215 
       
   216 void HbIconAnimation::notifyAnimationFinished()
       
   217 {
       
   218     mAnimMgrD->animNotPlaying(this);
       
   219     emit animationFinished();
       
   220 }
       
   221 
       
   222 // -----------------------------------------------------------------------------
       
   223 // Class HbIconAnimationSvg
       
   224 // -----------------------------------------------------------------------------
       
   225 HbIconAnimationSvg::HbIconAnimationSvg(
       
   226     HbIconAnimator *animator,
       
   227     const QString &iconName,
       
   228     QSvgRenderer *renderer,
       
   229     const QString &iconPath) :
       
   230 
       
   231     HbIconAnimation(animator, iconName),
       
   232     mSvgRenderer(renderer),
       
   233     mIconPath(iconPath)
       
   234 {
       
   235     connect(mSvgRenderer, SIGNAL(repaintNeeded()), this, SLOT(handleSvgAnimationUpdated()));
       
   236 }
       
   237 
       
   238 HbIconAnimationSvg::~HbIconAnimationSvg()
       
   239 {
       
   240     delete mSvgRenderer;
       
   241 }
       
   242 
       
   243 int HbIconAnimationSvg::type() const
       
   244 {
       
   245     return SVG;
       
   246 }
       
   247 
       
   248 void HbIconAnimationSvg::start()
       
   249 {
       
   250     // TODO
       
   251 }
       
   252 
       
   253 void HbIconAnimationSvg::stop()
       
   254 {
       
   255     // TODO
       
   256 }
       
   257 
       
   258 void HbIconAnimationSvg::pause()
       
   259 {
       
   260     // TODO
       
   261 }
       
   262 
       
   263 void HbIconAnimationSvg::resume()
       
   264 {
       
   265     // TODO
       
   266 }
       
   267 
       
   268 QPixmap HbIconAnimationSvg::currentFrame() const
       
   269 {
       
   270     QSize pixelSize = renderSize().toSize();
       
   271     if (!pixelSize.isEmpty()) {
       
   272         QPixmap canvasPixmap(pixelSize);
       
   273         canvasPixmap.fill(Qt::transparent);
       
   274         QPainter painter(&canvasPixmap);
       
   275         mSvgRenderer->render(&painter, QRectF(QPointF(), pixelSize));
       
   276         painter.end();
       
   277 
       
   278         // Apply mirroring if required
       
   279         if (mMirrored) {
       
   280             QTransform t;
       
   281             t.scale(-1,1);
       
   282             canvasPixmap = canvasPixmap.transformed(t);
       
   283         }
       
   284 
       
   285         // Apply mode
       
   286         if (mMode != QIcon::Normal) {
       
   287             QStyleOption opt(0);
       
   288             opt.palette = QApplication::palette();
       
   289             canvasPixmap = QApplication::style()->generatedIconPixmap(mMode, canvasPixmap, &opt);
       
   290         }
       
   291 
       
   292         return canvasPixmap;
       
   293     } else {
       
   294 #ifdef HB_ICON_TRACES
       
   295         qDebug() << "Warning: HbIconAnimationSvg::currentFrame() - SVG default size is empty.";
       
   296 #endif
       
   297         return QPixmap();
       
   298     }
       
   299 }
       
   300 
       
   301 void HbIconAnimationSvg::handleSvgAnimationUpdated()
       
   302 {
       
   303 #ifdef HB_ICON_TRACES
       
   304     qDebug() << "HbIconAnimation updated: " << iconName();
       
   305 #endif
       
   306 
       
   307     emit animationUpdated();
       
   308 }
       
   309 
       
   310 // -----------------------------------------------------------------------------
       
   311 // Class HbIconAnimationImage
       
   312 // -----------------------------------------------------------------------------
       
   313 HbIconAnimationImage::HbIconAnimationImage(
       
   314     HbIconAnimator *animator,
       
   315     const QString &iconName,
       
   316     const QString &iconFileName,
       
   317     QImageReader *renderer,
       
   318     int type) :
       
   319 
       
   320     HbIconAnimation(animator, iconName),
       
   321     mImageRenderer(renderer),
       
   322     mIconFileName(iconFileName),
       
   323     mType(type),
       
   324     mTimerEntry(0)
       
   325 {
       
   326     // This class supports these types
       
   327     Q_ASSERT(mType == MNG || mType == GIF);
       
   328 
       
   329     // Read the first frame. QImageReader::read() must be called before
       
   330     // QImageReader::nextImageDelay()
       
   331     QImage img = mImageRenderer->read();
       
   332 
       
   333     // Store the first frame in the current frame pixmap
       
   334     mCurrentFrame = QPixmap::fromImage(img);
       
   335 
       
   336     // Set default size based on the first frame
       
   337     setDefaultSize(mCurrentFrame.size());
       
   338 
       
   339     // Do not start the timer or initiate any signal emission here.
       
   340     // Do it in start() instead, since mFresh is true by default.
       
   341 }
       
   342 
       
   343 HbIconAnimationImage::~HbIconAnimationImage()
       
   344 {
       
   345     delete mImageRenderer;
       
   346 }
       
   347 
       
   348 int HbIconAnimationImage::type() const
       
   349 {
       
   350     return mType;
       
   351 }
       
   352 
       
   353 inline void stopTimer(HbTimerSignalEntry *&entry)
       
   354 {
       
   355     // entry may be non-null and may already be deleted, however this is not a
       
   356     // problem because we avoid double deletion by checking the return value of
       
   357     // unregisterEntry().
       
   358     if (entry && HbTimer::instance()->unregisterEntry(entry)) {
       
   359         delete entry;
       
   360         entry = 0;
       
   361     }
       
   362 }
       
   363 
       
   364 void HbIconAnimationImage::start()
       
   365 {
       
   366     if (mStartSignalTimer && mStartSignalTimer->isActive()) {
       
   367         return;
       
   368     }
       
   369     if (mFresh) {
       
   370         mFresh = false;
       
   371         mTimerInterval = mImageRenderer->nextImageDelay();
       
   372         mTimerEntry = HbTimer::instance()->addTimeout(mTimerInterval, this, SLOT(handleAnimationUpdated()));
       
   373         // Emit the signal later as nobody is connected at this point (if the
       
   374         // animation is auto-started, because the start() comes straight after
       
   375         // construction in that case).
       
   376         delayedEmitStarted();
       
   377     } else {
       
   378         stopTimer(mTimerEntry);
       
   379 
       
   380         // Recreate the image reader. It's slow but QImageReader::jumpToImage does not work.
       
   381         delete mImageRenderer;
       
   382         mImageRenderer = 0;
       
   383         mImageRenderer = new QImageReader(mIconFileName, mType == MNG ? "MNG" : "GIF");
       
   384     
       
   385         // New image reader starts from the first frame. Handle animation update.
       
   386         notifyAnimationStarted();
       
   387         handleAnimationUpdated();
       
   388     }
       
   389 }
       
   390 
       
   391 void HbIconAnimationImage::stop()
       
   392 {
       
   393     // If there is still a pending 'started' signal then drop it.
       
   394     if (mStartSignalTimer && mStartSignalTimer->isActive()) {
       
   395         mStartSignalTimer->stop();
       
   396     }
       
   397 
       
   398     // Stop the animation and go to the last frame.
       
   399     stopTimer(mTimerEntry);
       
   400 
       
   401     // Has the last frame been read already?
       
   402     if (!mLastFrame.isNull()) {
       
   403         mCurrentFrame = mLastFrame;
       
   404     } else {
       
   405         // Read all frames until the last one.
       
   406         // QImageReader::jumpToImage does not work so cannot jump to the last frame if it has not been read yet.
       
   407         while (true) {
       
   408             QImage img = mImageRenderer->read();
       
   409             // Reached last frame?
       
   410             if (!mImageRenderer->canRead()) {
       
   411                 mCurrentFrame = QPixmap::fromImage(img);
       
   412                 mLastFrame = mCurrentFrame;
       
   413                 break;
       
   414             }
       
   415         }
       
   416     }
       
   417 
       
   418     // Inform client to update display
       
   419     emit animationUpdated();
       
   420     
       
   421     notifyAnimationStopped();
       
   422 }
       
   423 
       
   424 void HbIconAnimationImage::pause()
       
   425 {
       
   426     stopTimer(mTimerEntry);
       
   427 }
       
   428 
       
   429 void HbIconAnimationImage::resume()
       
   430 {
       
   431     if (!mTimerEntry) {
       
   432         mTimerEntry = HbTimer::instance()->addTimeout(mTimerInterval, this, SLOT(handleAnimationUpdated()));
       
   433     }
       
   434 }
       
   435 
       
   436 QPixmap HbIconAnimationImage::currentFrame() const
       
   437 {
       
   438     QSize pixelSize = renderSize().toSize();
       
   439     QPixmap canvasPixmap;
       
   440 
       
   441     if (!pixelSize.isEmpty()) {
       
   442         if (pixelSize != mCurrentFrame.size()) {
       
   443             canvasPixmap = mCurrentFrame.scaled(pixelSize, mAspectRatioMode, Qt::SmoothTransformation);
       
   444         } else {
       
   445             canvasPixmap = mCurrentFrame;
       
   446         }
       
   447 
       
   448         // Apply mirroring if required
       
   449         if (mMirrored) {
       
   450             QTransform t;
       
   451             t.scale(-1,1);
       
   452             canvasPixmap = canvasPixmap.transformed(t);
       
   453         }
       
   454 
       
   455         // Apply mode
       
   456         if (mMode != QIcon::Normal) {
       
   457             QStyleOption opt(0);
       
   458             opt.palette = QApplication::palette();
       
   459             canvasPixmap = QApplication::style()->generatedIconPixmap(mMode, canvasPixmap, &opt);
       
   460         }
       
   461 
       
   462         return canvasPixmap;
       
   463     } else {
       
   464 #ifdef HB_ICON_TRACES
       
   465         qDebug() << "Warning: HbIconAnimationImage::currentFrame() - default size is empty.";
       
   466 #endif
       
   467         return QPixmap();
       
   468     }
       
   469 }
       
   470 
       
   471 void HbIconAnimationImage::handleAnimationUpdated()
       
   472 {
       
   473     bool finished = false;
       
   474 
       
   475     // Read the new frame. QImageReader::read() must be called before
       
   476     // QImageReader::nextImageDelay()
       
   477     QImage img = mImageRenderer->read();
       
   478 
       
   479     int delay = mImageRenderer->nextImageDelay();
       
   480     // If there is next image, restart the timer
       
   481     if (!img.isNull() && delay > 0) {
       
   482         // Restart timer
       
   483         mTimerInterval = delay;
       
   484         mTimerEntry = HbTimer::instance()->addTimeout(mTimerInterval, this, SLOT(handleAnimationUpdated()));
       
   485     }
       
   486 
       
   487     // Store the new frame in the current frame pixmap
       
   488     if (!img.isNull()) {
       
   489         mCurrentFrame = QPixmap::fromImage(img);
       
   490     }
       
   491     // Reached the last frame. Store it so it can be used by stop().
       
   492     else {
       
   493         mLastFrame = mCurrentFrame;
       
   494         finished = true;
       
   495     }
       
   496 
       
   497 #ifdef HB_ICON_TRACES
       
   498     qDebug() << "HbIconAnimation updated: " << iconName();
       
   499 #endif
       
   500 
       
   501     // Inform client
       
   502     emit animationUpdated();
       
   503 
       
   504     if (finished) {
       
   505         notifyAnimationFinished();
       
   506     }
       
   507 }
       
   508 
       
   509 HbIconAnimationFrameSet::HbIconAnimationFrameSet(
       
   510     HbIconAnimator *animator, const QString &iconName,const QList<FrameData> &frames) :
       
   511         HbIconAnimation(animator, iconName),
       
   512         mFrames(frames),
       
   513         mCurrentFrameIndex(0),
       
   514         mTimerEntry(0)
       
   515 {
       
   516     // Do not start the timer or initiate any signal emission here.
       
   517     // Do it in start() instead, since mFresh is true by default.
       
   518 }
       
   519 
       
   520 HbIconAnimationFrameSet::~HbIconAnimationFrameSet()
       
   521 {
       
   522     mFrames.clear(); // This destroys the pixmaps
       
   523 }
       
   524 
       
   525 int HbIconAnimationFrameSet::type() const
       
   526 {
       
   527     return FrameSet;
       
   528 }
       
   529 
       
   530 void HbIconAnimationFrameSet::resetJumpCount(FrameData &frame)
       
   531 {
       
   532     for (int i = 0, ie = frame.jumps.count(); i != ie; ++i) {
       
   533         // Note that the default value of execCount is 0 because frames are
       
   534         // shown once anyway so if there is a loop element with count="1"
       
   535         // then the frames need to be shown twice (because it "loops once").
       
   536         frame.jumps[i].execCount = 0;
       
   537     }
       
   538 }
       
   539 
       
   540 void HbIconAnimationFrameSet::resetJumpCounts()
       
   541 {
       
   542     for (int i = 0, ie = mFrames.count(); i != ie; ++i) {
       
   543         resetJumpCount(mFrames[i]);
       
   544     }
       
   545 }
       
   546 
       
   547 void HbIconAnimationFrameSet::start()
       
   548 {
       
   549     if (mStartSignalTimer && mStartSignalTimer->isActive()) {
       
   550         return;
       
   551     }
       
   552 #ifdef HB_ICON_TRACES
       
   553     qDebug("HbIconAnimationFrameSet::start() mFresh=%d", mFresh);
       
   554 #endif
       
   555     if (mFresh) {
       
   556         mFresh = false;
       
   557         mTimerInterval = mFrames.at(0).duration;
       
   558         mTimerEntry = HbTimer::instance()->addTimeout(mTimerInterval, this, SLOT(animationTimeout()));
       
   559         // Emit the signal later as nobody is connected at this point (if the
       
   560         // animation is auto-started, because the start() comes straight after
       
   561         // construction in that case).
       
   562         delayedEmitStarted();
       
   563     } else {
       
   564         stopTimer(mTimerEntry);
       
   565         resetJumpCounts();
       
   566         // Go to first frame and handle animation update
       
   567         mCurrentFrameIndex = -1;
       
   568         notifyAnimationStarted();
       
   569         animationTimeout();
       
   570     }
       
   571 }
       
   572 
       
   573 void HbIconAnimationFrameSet::stop()
       
   574 {
       
   575     stopTimer(mTimerEntry);
       
   576     // Go to last frame and handle animation update
       
   577     mCurrentFrameIndex = mFrames.count() - 1;
       
   578     emit animationUpdated();
       
   579     notifyAnimationStopped();
       
   580 }
       
   581 
       
   582 void HbIconAnimationFrameSet::pause()
       
   583 {
       
   584     stopTimer(mTimerEntry);
       
   585     mPaused = true;
       
   586     mPausedDueToBackground = false;
       
   587 }
       
   588 
       
   589 void HbIconAnimationFrameSet::resume()
       
   590 {
       
   591     if (!mTimerEntry) {
       
   592         mTimerEntry = HbTimer::instance()->addTimeout(mTimerInterval, this, SLOT(animationTimeout()));
       
   593     }
       
   594     mPaused = false;
       
   595     mPausedDueToBackground = false;
       
   596 }
       
   597 
       
   598 QPixmap HbIconAnimationFrameSet::currentFrame() const
       
   599 {
       
   600     if (mFrames.count()) {
       
   601         QPixmap pm = mFrames.at(mCurrentFrameIndex).pixmap;
       
   602 
       
   603         // Mirroring is not needed here. Frames are mirrored if needed when they are loaded.
       
   604 
       
   605         // Apply mode
       
   606         if (mMode != QIcon::Normal) {
       
   607             QStyleOption opt(0);
       
   608             opt.palette = QApplication::palette();
       
   609             pm = QApplication::style()->generatedIconPixmap(mMode, pm, &opt);
       
   610         }
       
   611 
       
   612         return pm;
       
   613     } else {
       
   614         return QPixmap();
       
   615     }
       
   616 }
       
   617 
       
   618 void HbIconAnimationFrameSet::moveToNextFrame()
       
   619 {
       
   620     if (mCurrentFrameIndex >= 0 && mCurrentFrameIndex < mFrames.count()) {
       
   621         for (int i = 0, ie = mFrames[mCurrentFrameIndex].jumps.count(); i != ie; ++i) {
       
   622             JumpData &jumpData(mFrames[mCurrentFrameIndex].jumps[i]);
       
   623             if (jumpData.execCount < jumpData.repeatCount) {
       
   624                 ++jumpData.execCount;
       
   625                 // Before returning, the exec counts of all previous jumps in
       
   626                 // this frame must be resetted, because they were caused by
       
   627                 // <loop> elements that were embedded into the <loop> that
       
   628                 // generated this jump.
       
   629                 for (int j = 0; j < i; ++j) {
       
   630                     mFrames[mCurrentFrameIndex].jumps[j].execCount = 0;
       
   631                 }
       
   632                 // And similarly, all jumps in frames that fall between the
       
   633                 // target (incl.) and the current frame (excl.) must be
       
   634                 // resetted. Note that jumping forward is not supported and such
       
   635                 // jumps are never generated by the animation xml parser.
       
   636                 for (int j = jumpData.targetFrameIndex; j < mCurrentFrameIndex; ++j) {
       
   637                     resetJumpCount(mFrames[j]);
       
   638                 }
       
   639                 mCurrentFrameIndex = jumpData.targetFrameIndex;
       
   640                 return;
       
   641             }
       
   642         }
       
   643     }
       
   644 
       
   645     ++mCurrentFrameIndex;
       
   646 }
       
   647 
       
   648 void HbIconAnimationFrameSet::animationTimeout()
       
   649 {
       
   650     // Frame delay has passed, pick the next frame index.
       
   651     moveToNextFrame();
       
   652 
       
   653     bool finished = false;
       
   654 
       
   655     // Go back to the beginning if indexing goes beyond frame count
       
   656     // and looping is enabled. Change to the last valid frame and
       
   657     // finish if looping is disabled.
       
   658     if (mCurrentFrameIndex >= mFrames.count()) {
       
   659         if (playMode() == HbIconAnimationDefinition::Loop) {
       
   660             mCurrentFrameIndex = 0;
       
   661         } else {
       
   662             finished = true;
       
   663             mCurrentFrameIndex = mFrames.count() - 1;
       
   664         }
       
   665         resetJumpCounts();
       
   666     }
       
   667 
       
   668     // If there are more frames to come or the animation is looping,
       
   669     // restart the timer.
       
   670     if (!finished) {
       
   671         mTimerInterval = mFrames.at(mCurrentFrameIndex).duration;
       
   672         mTimerEntry = HbTimer::instance()->addTimeout(mTimerInterval, this, SLOT(animationTimeout()));
       
   673     }
       
   674 
       
   675 #ifdef HB_ICON_TRACES
       
   676     //qDebug() << "HbIconAnimation updated: " << iconName();
       
   677 #endif
       
   678 
       
   679     // Inform client.
       
   680     if (finished) {
       
   681         notifyAnimationFinished();
       
   682     } else {
       
   683         emit animationUpdated();
       
   684     }
       
   685 }
       
   686 
       
   687 // End of File