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