DALi Version 2.2.11
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / animated-vector-image / vector-animation-task.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/math/math-utils.h>
24 #include <dali/public-api/object/property-array.h>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-manager.h>
28 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h>
29 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
30
31 namespace Dali
32 {
33 namespace Toolkit
34 {
35 namespace Internal
36 {
37 namespace
38 {
39 constexpr auto LOOP_FOREVER = -1;
40 constexpr auto MICROSECONDS_PER_SECOND(1e+6);
41
42 #if defined(DEBUG_ENABLED)
43 Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_ANIMATION");
44 #endif
45
46 } // unnamed namespace
47
48 VectorAnimationTask::VectorAnimationTask(VisualFactoryCache& factoryCache)
49 : AsyncTask(MakeCallback(this, &VectorAnimationTask::TaskCompleted), AsyncTask::ThreadType::WORKER_THREAD),
50   mUrl(),
51   mVectorRenderer(VectorAnimationRenderer::New()),
52   mAnimationData(),
53   mVectorAnimationThread(factoryCache.GetVectorAnimationManager().GetVectorAnimationThread()),
54   mConditionalWait(),
55   mResourceReadySignal(),
56   mAnimationFinishedTrigger(),
57   mLoadCompletedTrigger(new EventThreadCallback(MakeCallback(this, &VectorAnimationTask::OnLoadCompleted))),
58   mPlayState(PlayState::STOPPED),
59   mStopBehavior(DevelImageVisual::StopBehavior::CURRENT_FRAME),
60   mLoopingMode(DevelImageVisual::LoopingMode::RESTART),
61   mNextFrameStartTime(),
62   mFrameDurationMicroSeconds(MICROSECONDS_PER_SECOND / 60.0f),
63   mFrameRate(60.0f),
64   mCurrentFrame(0),
65   mTotalFrame(0),
66   mStartFrame(0),
67   mEndFrame(0),
68   mDroppedFrames(0),
69   mWidth(0),
70   mHeight(0),
71   mAnimationDataIndex(0),
72   mLoopCount(LOOP_FOREVER),
73   mCurrentLoop(0),
74   mForward(true),
75   mUpdateFrameNumber(false),
76   mNeedAnimationFinishedTrigger(true),
77   mAnimationDataUpdated(false),
78   mDestroyTask(false),
79   mLoadRequest(false),
80   mLoadFailed(false),
81   mRasterized(false),
82   mKeepAnimation(false)
83 {
84   mVectorRenderer.UploadCompletedSignal().Connect(this, &VectorAnimationTask::OnUploadCompleted);
85 }
86
87 VectorAnimationTask::~VectorAnimationTask()
88 {
89   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::~VectorAnimationTask: destructor [%p]\n", this);
90 }
91
92 void VectorAnimationTask::Process()
93 {
94   mRasterized = Rasterize();
95 }
96
97 bool VectorAnimationTask::IsReady()
98 {
99   return true;
100 }
101
102 void VectorAnimationTask::Finalize()
103 {
104   ConditionalWait::ScopedLock lock(mConditionalWait);
105
106   // Release some objects in the main thread
107   if(mAnimationFinishedTrigger)
108   {
109     mAnimationFinishedTrigger.reset();
110   }
111   if(mLoadCompletedTrigger)
112   {
113     mLoadCompletedTrigger.reset();
114   }
115
116   mVectorRenderer.Finalize();
117
118   mDestroyTask = true;
119 }
120
121 void VectorAnimationTask::TaskCompleted(VectorAnimationTaskPtr task)
122 {
123   mVectorAnimationThread.OnTaskCompleted(task, task->IsRasterized(), task->IsAnimating());
124 }
125
126 bool VectorAnimationTask::IsRasterized()
127 {
128   return mRasterized;
129 }
130
131 bool VectorAnimationTask::IsAnimating()
132 {
133   return mKeepAnimation;
134 }
135
136 bool VectorAnimationTask::Load(bool synchronousLoading)
137 {
138   if(!mVectorRenderer.Load(mUrl))
139   {
140     DALI_LOG_ERROR("VectorAnimationTask::Load: Load failed [%s]\n", mUrl.c_str());
141     mLoadRequest = false;
142     mLoadFailed  = true;
143     if(!synchronousLoading)
144     {
145       mLoadCompletedTrigger->Trigger();
146     }
147     return false;
148   }
149
150   mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
151
152   mEndFrame = mTotalFrame - 1;
153
154   mFrameRate                 = mVectorRenderer.GetFrameRate();
155   mFrameDurationMicroSeconds = MICROSECONDS_PER_SECOND / mFrameRate;
156
157   mLoadRequest = false;
158   if(!synchronousLoading)
159   {
160     mLoadCompletedTrigger->Trigger();
161   }
162
163   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Load: file = %s [%d frames, %f fps] [%p]\n", mUrl.c_str(), mTotalFrame, mFrameRate, this);
164
165   return true;
166 }
167
168 void VectorAnimationTask::SetRenderer(Renderer renderer)
169 {
170   ConditionalWait::ScopedLock lock(mConditionalWait);
171
172   mVectorRenderer.SetRenderer(renderer);
173
174   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetRenderer [%p]\n", this);
175 }
176
177 void VectorAnimationTask::RequestLoad(const std::string& url, bool synchronousLoading)
178 {
179   mUrl = url;
180
181   if(!synchronousLoading)
182   {
183     mLoadRequest = true;
184
185     mVectorAnimationThread.AddTask(this);
186   }
187   else
188   {
189     Load(true);
190
191     OnLoadCompleted();
192   }
193 }
194
195 bool VectorAnimationTask::IsLoadRequested() const
196 {
197   return mLoadRequest;
198 }
199
200 void VectorAnimationTask::SetAnimationData(const AnimationData& data)
201 {
202   ConditionalWait::ScopedLock lock(mConditionalWait);
203
204   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetAnimationData [%p]\n", this);
205
206   uint32_t index = mAnimationDataIndex == 0 ? 1 : 0; // Use the other buffer
207
208   mAnimationData[index] = data;
209   mAnimationDataUpdated = true;
210
211   if(data.resendFlag & VectorAnimationTask::RESEND_SIZE)
212   {
213     // The size should be changed in the main thread.
214     SetSize(data.width, data.height);
215   }
216
217   mVectorAnimationThread.AddTask(this);
218 }
219
220 void VectorAnimationTask::SetSize(uint32_t width, uint32_t height)
221 {
222   if(mWidth != width || mHeight != height)
223   {
224     mVectorRenderer.SetSize(width, height);
225
226     mWidth  = width;
227     mHeight = height;
228
229     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetSize: width = %d, height = %d [%p]\n", width, height, this);
230   }
231 }
232
233 void VectorAnimationTask::PlayAnimation()
234 {
235   if(mPlayState != PlayState::PLAYING)
236   {
237     mNeedAnimationFinishedTrigger = true;
238     mUpdateFrameNumber            = false;
239     mPlayState                    = PlayState::PLAYING;
240
241     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PlayAnimation: Play [%p]\n", this);
242   }
243 }
244
245 void VectorAnimationTask::StopAnimation()
246 {
247   if(mPlayState != PlayState::STOPPING)
248   {
249     mNeedAnimationFinishedTrigger = false;
250     mPlayState                    = PlayState::STOPPING;
251
252     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::StopAnimation: Stop [%p]\n", this);
253   }
254 }
255
256 void VectorAnimationTask::PauseAnimation()
257 {
258   if(mPlayState == PlayState::PLAYING)
259   {
260     mPlayState = PlayState::PAUSED;
261
262     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PauseAnimation: Pause [%p]\n", this);
263   }
264 }
265
266 void VectorAnimationTask::SetAnimationFinishedCallback(EventThreadCallback* callback)
267 {
268   ConditionalWait::ScopedLock lock(mConditionalWait);
269   if(callback)
270   {
271     mAnimationFinishedTrigger = std::unique_ptr<EventThreadCallback>(callback);
272   }
273 }
274
275 void VectorAnimationTask::SetLoopCount(int32_t count)
276 {
277   if(mLoopCount != count)
278   {
279     mLoopCount   = count;
280     mCurrentLoop = 0;
281
282     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopCount: [%d] [%p]\n", count, this);
283   }
284 }
285
286 void VectorAnimationTask::SetPlayRange(const Property::Array& playRange)
287 {
288   bool     valid      = false;
289   uint32_t startFrame = 0, endFrame = 0;
290   size_t   count = playRange.Count();
291
292   if(count >= 2)
293   {
294     int32_t start = 0, end = 0;
295     if(playRange.GetElementAt(0).Get(start) && playRange.GetElementAt(1).Get(end))
296     {
297       startFrame = static_cast<uint32_t>(start);
298       endFrame   = static_cast<uint32_t>(end);
299       valid      = true;
300     }
301     else
302     {
303       std::string startMarker, endMarker;
304       if(playRange.GetElementAt(0).Get(startMarker) && playRange.GetElementAt(1).Get(endMarker))
305       {
306         if(mVectorRenderer)
307         {
308           uint32_t frame; // We don't use this later
309           if(mVectorRenderer.GetMarkerInfo(startMarker, startFrame, frame) && mVectorRenderer.GetMarkerInfo(endMarker, frame, endFrame))
310           {
311             valid = true;
312           }
313         }
314       }
315     }
316   }
317   else if(count == 1)
318   {
319     std::string marker;
320     if(playRange.GetElementAt(0).Get(marker))
321     {
322       if(mVectorRenderer && mVectorRenderer.GetMarkerInfo(marker, startFrame, endFrame))
323       {
324         valid = true;
325       }
326     }
327   }
328
329   if(!valid)
330   {
331     DALI_LOG_ERROR("VectorAnimationTask::SetPlayRange: Invalid range [%p]\n", this);
332     return;
333   }
334
335   // Make sure the range specified is between 0 and the total frame number
336   startFrame = std::min(startFrame, mTotalFrame - 1);
337   endFrame   = std::min(endFrame, mTotalFrame - 1);
338
339   // If the range is not in order swap values
340   if(startFrame > endFrame)
341   {
342     uint32_t temp = startFrame;
343     startFrame    = endFrame;
344     endFrame      = temp;
345   }
346
347   if(startFrame != mStartFrame || endFrame != mEndFrame)
348   {
349     mStartFrame = startFrame;
350     mEndFrame   = endFrame;
351
352     // If the current frame is out of the range, change the current frame also.
353     if(mStartFrame > mCurrentFrame)
354     {
355       mCurrentFrame = mStartFrame;
356     }
357     else if(mEndFrame < mCurrentFrame)
358     {
359       mCurrentFrame = mEndFrame;
360     }
361
362     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%s] [%p]\n", mStartFrame, mEndFrame, mUrl.c_str(), this);
363   }
364 }
365
366 void VectorAnimationTask::GetPlayRange(uint32_t& startFrame, uint32_t& endFrame)
367 {
368   startFrame = mStartFrame;
369   endFrame   = mEndFrame;
370 }
371
372 void VectorAnimationTask::SetCurrentFrameNumber(uint32_t frameNumber)
373 {
374   if(mCurrentFrame == frameNumber)
375   {
376     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: Set same frame [%d] [%p]\n", frameNumber, this);
377     return;
378   }
379
380   if(frameNumber >= mStartFrame && frameNumber <= mEndFrame)
381   {
382     mCurrentFrame      = frameNumber;
383     mUpdateFrameNumber = false;
384
385     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this);
386   }
387   else
388   {
389     DALI_LOG_ERROR("Invalid frame number [%d (%d, %d)] [%p]\n", frameNumber, mStartFrame, mEndFrame, this);
390   }
391 }
392
393 uint32_t VectorAnimationTask::GetCurrentFrameNumber() const
394 {
395   return mCurrentFrame;
396 }
397
398 uint32_t VectorAnimationTask::GetTotalFrameNumber() const
399 {
400   return mTotalFrame;
401 }
402
403 void VectorAnimationTask::GetDefaultSize(uint32_t& width, uint32_t& height) const
404 {
405   mVectorRenderer.GetDefaultSize(width, height);
406 }
407
408 void VectorAnimationTask::SetStopBehavior(DevelImageVisual::StopBehavior::Type stopBehavior)
409 {
410   mStopBehavior = stopBehavior;
411
412   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetStopBehavior: stop behavor = %d [%p]\n", mStopBehavior, this);
413 }
414
415 void VectorAnimationTask::SetLoopingMode(DevelImageVisual::LoopingMode::Type loopingMode)
416 {
417   mLoopingMode = loopingMode;
418
419   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopingMode: looping mode = %d [%p]\n", mLoopingMode, this);
420 }
421
422 void VectorAnimationTask::GetLayerInfo(Property::Map& map) const
423 {
424   mVectorRenderer.GetLayerInfo(map);
425 }
426
427 VectorAnimationTask::ResourceReadySignalType& VectorAnimationTask::ResourceReadySignal()
428 {
429   return mResourceReadySignal;
430 }
431
432 bool VectorAnimationTask::Rasterize()
433 {
434   bool     stopped = false;
435   uint32_t currentFrame;
436   mKeepAnimation = false;
437
438   {
439     ConditionalWait::ScopedLock lock(mConditionalWait);
440     if(mDestroyTask)
441     {
442       // The task will be destroyed. We don't need rasterization.
443       return false;
444     }
445   }
446
447   if(mLoadRequest)
448   {
449     return Load(false);
450   }
451
452   if(mLoadFailed)
453   {
454     return false;
455   }
456
457   ApplyAnimationData();
458
459   if(mPlayState == PlayState::PLAYING && mUpdateFrameNumber)
460   {
461     mCurrentFrame = mForward ? mCurrentFrame + mDroppedFrames + 1 : (mCurrentFrame > mDroppedFrames ? mCurrentFrame - mDroppedFrames - 1 : 0);
462     Dali::ClampInPlace(mCurrentFrame, mStartFrame, mEndFrame);
463   }
464
465   currentFrame = mCurrentFrame;
466
467   mUpdateFrameNumber = true;
468
469   if(mPlayState == PlayState::STOPPING)
470   {
471     mCurrentFrame = GetStoppedFrame(mStartFrame, mEndFrame, mCurrentFrame);
472     currentFrame  = mCurrentFrame;
473     stopped       = true;
474   }
475   else if(mPlayState == PlayState::PLAYING)
476   {
477     bool animationFinished = false;
478
479     if(currentFrame >= mEndFrame) // last frame
480     {
481       if(mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE)
482       {
483         mForward = false;
484       }
485       else
486       {
487         if(mLoopCount < 0 || ++mCurrentLoop < mLoopCount) // repeat forever or before the last loop
488         {
489           mCurrentFrame      = mStartFrame;
490           mUpdateFrameNumber = false;
491         }
492         else
493         {
494           animationFinished = true; // end of animation
495         }
496       }
497     }
498     else if(currentFrame == mStartFrame && !mForward) // first frame
499     {
500       if(mLoopCount < 0 || ++mCurrentLoop < mLoopCount) // repeat forever or before the last loop
501       {
502         mForward = true;
503       }
504       else
505       {
506         animationFinished = true; // end of animation
507       }
508     }
509
510     if(animationFinished)
511     {
512       if(mStopBehavior == DevelImageVisual::StopBehavior::CURRENT_FRAME)
513       {
514         stopped = true;
515       }
516       else
517       {
518         mPlayState = PlayState::STOPPING;
519       }
520     }
521   }
522
523   // Rasterize
524   bool renderSuccess = false;
525   if(mVectorRenderer)
526   {
527     renderSuccess = mVectorRenderer.Render(currentFrame);
528     if(!renderSuccess)
529     {
530       DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Rendering failed. Try again later.[%d] [%p]\n", currentFrame, this);
531       mUpdateFrameNumber = false;
532     }
533   }
534
535   if(stopped && renderSuccess)
536   {
537     mPlayState   = PlayState::STOPPED;
538     mForward     = true;
539     mCurrentLoop = 0;
540
541     if(mVectorRenderer)
542     {
543       // Notify the Renderer that rendering is stopped.
544       mVectorRenderer.RenderStopped();
545     }
546
547     // Animation is finished
548     {
549       ConditionalWait::ScopedLock lock(mConditionalWait);
550       if(mNeedAnimationFinishedTrigger && mAnimationFinishedTrigger)
551       {
552         mAnimationFinishedTrigger->Trigger();
553       }
554     }
555
556     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this);
557   }
558
559   if(mPlayState != PlayState::PAUSED && mPlayState != PlayState::STOPPED)
560   {
561     mKeepAnimation = true;
562   }
563
564   return true;
565 }
566
567 uint32_t VectorAnimationTask::GetStoppedFrame(uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame)
568 {
569   uint32_t frame = currentFrame;
570
571   switch(mStopBehavior)
572   {
573     case DevelImageVisual::StopBehavior::FIRST_FRAME:
574     {
575       frame = startFrame;
576       break;
577     }
578     case DevelImageVisual::StopBehavior::LAST_FRAME:
579     {
580       if(mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE)
581       {
582         frame = startFrame;
583       }
584       else
585       {
586         frame = endFrame;
587       }
588       break;
589     }
590     case DevelImageVisual::StopBehavior::CURRENT_FRAME:
591     {
592       frame = currentFrame;
593       break;
594     }
595   }
596
597   return frame;
598 }
599
600 VectorAnimationTask::TimePoint VectorAnimationTask::CalculateNextFrameTime(bool renderNow)
601 {
602   // std::chrono::time_point template has second parameter duration which defaults to the std::chrono::steady_clock supported
603   // duration. In some C++11 implementations it is a milliseconds duration, so it fails to compile unless mNextFrameStartTime
604   // is casted to use the default duration.
605   mNextFrameStartTime = std::chrono::time_point_cast<TimePoint::duration>(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds));
606   auto current        = std::chrono::steady_clock::now();
607   mDroppedFrames      = 0;
608
609   if(renderNow)
610   {
611     mNextFrameStartTime = current;
612   }
613   else if(mNextFrameStartTime < current)
614   {
615     uint32_t droppedFrames = 0;
616
617     while(current > std::chrono::time_point_cast<TimePoint::duration>(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds)) && droppedFrames < mTotalFrame)
618     {
619       droppedFrames++;
620       mNextFrameStartTime = std::chrono::time_point_cast<TimePoint::duration>(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds));
621     }
622
623     mNextFrameStartTime = current;
624     mDroppedFrames      = droppedFrames;
625   }
626
627   return mNextFrameStartTime;
628 }
629
630 VectorAnimationTask::TimePoint VectorAnimationTask::GetNextFrameTime()
631 {
632   return mNextFrameStartTime;
633 }
634
635 void VectorAnimationTask::ApplyAnimationData()
636 {
637   uint32_t index;
638
639   {
640     ConditionalWait::ScopedLock lock(mConditionalWait);
641
642     if(!mAnimationDataUpdated || mAnimationData[mAnimationDataIndex].resendFlag != 0)
643     {
644       // Data is not updated or the previous data is not applied yet.
645       return;
646     }
647
648     mAnimationDataIndex   = mAnimationDataIndex == 0 ? 1 : 0; // Swap index
649     mAnimationDataUpdated = false;
650
651     index = mAnimationDataIndex;
652   }
653
654   if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_LOOP_COUNT)
655   {
656     SetLoopCount(mAnimationData[index].loopCount);
657   }
658
659   if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_PLAY_RANGE)
660   {
661     SetPlayRange(mAnimationData[index].playRange);
662   }
663
664   if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_STOP_BEHAVIOR)
665   {
666     SetStopBehavior(mAnimationData[index].stopBehavior);
667   }
668
669   if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_LOOPING_MODE)
670   {
671     SetLoopingMode(mAnimationData[index].loopingMode);
672   }
673
674   if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_CURRENT_FRAME)
675   {
676     SetCurrentFrameNumber(mAnimationData[index].currentFrame);
677   }
678
679   if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_NEED_RESOURCE_READY)
680   {
681     mVectorRenderer.InvalidateBuffer();
682   }
683
684   if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_DYNAMIC_PROPERTY)
685   {
686     for(auto&& iter : mAnimationData[index].dynamicProperties)
687     {
688       mVectorRenderer.AddPropertyValueCallback(iter.keyPath, static_cast<VectorAnimationRenderer::VectorProperty>(iter.property), iter.callback, iter.id);
689     }
690   }
691
692   if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_PLAY_STATE)
693   {
694     if(mAnimationData[index].playState == DevelImageVisual::PlayState::PLAYING)
695     {
696       PlayAnimation();
697     }
698     else if(mAnimationData[index].playState == DevelImageVisual::PlayState::PAUSED)
699     {
700       PauseAnimation();
701     }
702     else if(mAnimationData[index].playState == DevelImageVisual::PlayState::STOPPED)
703     {
704       StopAnimation();
705     }
706   }
707
708   // reset data
709   mAnimationData[index].dynamicProperties.clear();
710   mAnimationData[index].resendFlag = 0;
711 }
712
713 void VectorAnimationTask::OnUploadCompleted()
714 {
715   mResourceReadySignal.Emit(ResourceStatus::READY);
716 }
717
718 void VectorAnimationTask::OnLoadCompleted()
719 {
720   if(!mLoadFailed)
721   {
722     mResourceReadySignal.Emit(ResourceStatus::LOADED);
723   }
724   else
725   {
726     mResourceReadySignal.Emit(ResourceStatus::FAILED);
727   }
728 }
729 } // namespace Internal
730
731 } // namespace Toolkit
732
733 } // namespace Dali