[dali_2.2.51] Merge branch '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   mImageUrl(),
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 #ifdef TRACE_ENABLED
147   if(gTraceFilter && gTraceFilter->IsTraceEnabled())
148   {
149     std::ostringstream oss;
150     oss << "[url:" << mImageUrl.GetUrl() << "]";
151     DALI_TRACE_BEGIN_WITH_MESSAGE(gTraceFilter, "DALI_LOTTIE_LOADING_TASK", oss.str().c_str());
152   }
153 #endif
154
155   if(!mVectorRenderer.Load(mImageUrl.GetUrl()))
156   {
157     DALI_LOG_ERROR("VectorAnimationTask::Load: Load failed [%s]\n", mImageUrl.GetUrl().c_str());
158     mLoadFailed = true;
159   }
160
161   if(mLoadFailed)
162   {
163     mLoadRequest = false;
164     if(!synchronousLoading && mLoadCompletedCallback)
165     {
166       mVectorAnimationThread.AddEventTriggerCallback(mLoadCompletedCallback.get());
167     }
168 #ifdef TRACE_ENABLED
169     if(gTraceFilter && gTraceFilter->IsTraceEnabled())
170     {
171       std::ostringstream oss;
172       oss << "[url:" << mImageUrl.GetUrl() << "]";
173       DALI_TRACE_END_WITH_MESSAGE(gTraceFilter, "DALI_LOTTIE_LOADING_TASK", oss.str().c_str());
174     }
175 #endif
176     return false;
177   }
178
179   mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
180
181   mEndFrame = mTotalFrame - 1;
182
183   mFrameRate                 = mVectorRenderer.GetFrameRate();
184   mFrameDurationMicroSeconds = MICROSECONDS_PER_SECOND / mFrameRate;
185
186   mLoadRequest = false;
187   if(!synchronousLoading && mLoadCompletedCallback)
188   {
189     mVectorAnimationThread.AddEventTriggerCallback(mLoadCompletedCallback.get());
190   }
191
192   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Load: file = %s [%d frames, %f fps] [%p]\n", mImageUrl.GetUrl().c_str(), mTotalFrame, mFrameRate, this);
193
194 #ifdef TRACE_ENABLED
195   if(gTraceFilter && gTraceFilter->IsTraceEnabled())
196   {
197     std::ostringstream oss;
198     oss << "[url:" << mImageUrl.GetUrl() << "]";
199     DALI_TRACE_END_WITH_MESSAGE(gTraceFilter, "DALI_LOTTIE_LOADING_TASK", oss.str().c_str());
200   }
201 #endif
202
203   return true;
204 }
205
206 void VectorAnimationTask::SetRenderer(Renderer renderer)
207 {
208   ConditionalWait::ScopedLock lock(mConditionalWait);
209
210   mVectorRenderer.SetRenderer(renderer);
211
212   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetRenderer [%p]\n", this);
213 }
214
215 void VectorAnimationTask::RequestLoad(const VisualUrl& url, bool synchronousLoading)
216 {
217   mImageUrl = url;
218
219   if(!synchronousLoading)
220   {
221     mLoadRequest = true;
222
223     mVectorAnimationThread.AddTask(this);
224   }
225   else
226   {
227     Load(true);
228
229     OnLoadCompleted();
230   }
231 }
232
233 bool VectorAnimationTask::IsLoadRequested() const
234 {
235   return mLoadRequest;
236 }
237
238 void VectorAnimationTask::SetAnimationData(const AnimationData& data)
239 {
240   ConditionalWait::ScopedLock lock(mConditionalWait);
241
242   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetAnimationData [%p]\n", this);
243
244   uint32_t index = mAnimationDataIndex == 0 ? 1 : 0; // Use the other buffer
245
246   mAnimationData[index].push_back(data);
247   mAnimationDataUpdated = true;
248
249   if(data.resendFlag & VectorAnimationTask::RESEND_SIZE)
250   {
251     // The size should be changed in the main thread.
252     SetSize(data.width, data.height);
253   }
254
255   mVectorAnimationThread.AddTask(this);
256 }
257
258 void VectorAnimationTask::SetSize(uint32_t width, uint32_t height)
259 {
260   if(mWidth != width || mHeight != height)
261   {
262     mVectorRenderer.SetSize(width, height);
263
264     mWidth  = width;
265     mHeight = height;
266
267     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetSize: width = %d, height = %d [%p]\n", width, height, this);
268   }
269 }
270
271 void VectorAnimationTask::PlayAnimation()
272 {
273   if(mPlayState != PlayState::PLAYING)
274   {
275     mNeedAnimationFinishedTrigger = true;
276     mUpdateFrameNumber            = false;
277     mPlayState                    = PlayState::PLAYING;
278
279     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PlayAnimation: Play [%p]\n", this);
280   }
281 }
282
283 void VectorAnimationTask::StopAnimation()
284 {
285   if(mPlayState != PlayState::STOPPING)
286   {
287     mNeedAnimationFinishedTrigger = false;
288     mPlayState                    = PlayState::STOPPING;
289
290     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::StopAnimation: Stop [%p]\n", this);
291   }
292 }
293
294 void VectorAnimationTask::PauseAnimation()
295 {
296   if(mPlayState == PlayState::PLAYING)
297   {
298     mPlayState = PlayState::PAUSED;
299
300     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PauseAnimation: Pause [%p]\n", this);
301   }
302 }
303
304 void VectorAnimationTask::SetAnimationFinishedCallback(CallbackBase* callback)
305 {
306   ConditionalWait::ScopedLock lock(mConditionalWait);
307   mAnimationFinishedCallback = std::unique_ptr<CallbackBase>(callback);
308 }
309
310 void VectorAnimationTask::SetLoopCount(int32_t count)
311 {
312   if(mLoopCount != count)
313   {
314     mLoopCount   = count;
315     mCurrentLoop = 0;
316
317     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopCount: [%d] [%p]\n", count, this);
318   }
319 }
320
321 void VectorAnimationTask::SetPlayRange(const Property::Array& playRange)
322 {
323   bool     valid      = false;
324   uint32_t startFrame = 0, endFrame = 0;
325   size_t   count = playRange.Count();
326
327   if(count >= 2)
328   {
329     int32_t start = 0, end = 0;
330     if(playRange.GetElementAt(0).Get(start) && playRange.GetElementAt(1).Get(end))
331     {
332       startFrame = static_cast<uint32_t>(start);
333       endFrame   = static_cast<uint32_t>(end);
334       valid      = true;
335     }
336     else
337     {
338       std::string startMarker, endMarker;
339       if(playRange.GetElementAt(0).Get(startMarker) && playRange.GetElementAt(1).Get(endMarker))
340       {
341         if(mVectorRenderer)
342         {
343           uint32_t frame; // We don't use this later
344           if(mVectorRenderer.GetMarkerInfo(startMarker, startFrame, frame) && mVectorRenderer.GetMarkerInfo(endMarker, frame, endFrame))
345           {
346             valid = true;
347           }
348         }
349       }
350     }
351   }
352   else if(count == 1)
353   {
354     std::string marker;
355     if(playRange.GetElementAt(0).Get(marker))
356     {
357       if(mVectorRenderer && mVectorRenderer.GetMarkerInfo(marker, startFrame, endFrame))
358       {
359         valid = true;
360       }
361     }
362   }
363
364   if(!valid)
365   {
366     DALI_LOG_ERROR("VectorAnimationTask::SetPlayRange: Invalid range [%p]\n", this);
367     return;
368   }
369
370   // Make sure the range specified is between 0 and the total frame number
371   startFrame = std::min(startFrame, mTotalFrame - 1);
372   endFrame   = std::min(endFrame, mTotalFrame - 1);
373
374   // If the range is not in order swap values
375   if(startFrame > endFrame)
376   {
377     uint32_t temp = startFrame;
378     startFrame    = endFrame;
379     endFrame      = temp;
380   }
381
382   if(startFrame != mStartFrame || endFrame != mEndFrame)
383   {
384     mStartFrame = startFrame;
385     mEndFrame   = endFrame;
386
387     // If the current frame is out of the range, change the current frame also.
388     if(mStartFrame > mCurrentFrame)
389     {
390       mCurrentFrame = mStartFrame;
391     }
392     else if(mEndFrame < mCurrentFrame)
393     {
394       mCurrentFrame = mEndFrame;
395     }
396
397     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%s] [%p]\n", mStartFrame, mEndFrame, mImageUrl.GetUrl().c_str(), this);
398   }
399 }
400
401 void VectorAnimationTask::GetPlayRange(uint32_t& startFrame, uint32_t& endFrame)
402 {
403   startFrame = mStartFrame;
404   endFrame   = mEndFrame;
405 }
406
407 void VectorAnimationTask::SetCurrentFrameNumber(uint32_t frameNumber)
408 {
409   if(mCurrentFrame == frameNumber)
410   {
411     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: Set same frame [%d] [%p]\n", frameNumber, this);
412     return;
413   }
414
415   if(frameNumber >= mStartFrame && frameNumber <= mEndFrame)
416   {
417     mCurrentFrame      = frameNumber;
418     mUpdateFrameNumber = false;
419
420     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this);
421   }
422   else
423   {
424     DALI_LOG_ERROR("Invalid frame number [%d (%d, %d)] [%p]\n", frameNumber, mStartFrame, mEndFrame, this);
425   }
426 }
427
428 uint32_t VectorAnimationTask::GetCurrentFrameNumber() const
429 {
430   return mCurrentFrame;
431 }
432
433 uint32_t VectorAnimationTask::GetTotalFrameNumber() const
434 {
435   return mTotalFrame;
436 }
437
438 void VectorAnimationTask::GetDefaultSize(uint32_t& width, uint32_t& height) const
439 {
440   mVectorRenderer.GetDefaultSize(width, height);
441 }
442
443 void VectorAnimationTask::SetStopBehavior(DevelImageVisual::StopBehavior::Type stopBehavior)
444 {
445   mStopBehavior = stopBehavior;
446
447   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetStopBehavior: stop behavor = %d [%p]\n", mStopBehavior, this);
448 }
449
450 void VectorAnimationTask::SetLoopingMode(DevelImageVisual::LoopingMode::Type loopingMode)
451 {
452   mLoopingMode = loopingMode;
453
454   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopingMode: looping mode = %d [%p]\n", mLoopingMode, this);
455 }
456
457 void VectorAnimationTask::GetLayerInfo(Property::Map& map) const
458 {
459   mVectorRenderer.GetLayerInfo(map);
460 }
461
462 VectorAnimationTask::ResourceReadySignalType& VectorAnimationTask::ResourceReadySignal()
463 {
464   return mResourceReadySignal;
465 }
466
467 bool VectorAnimationTask::Rasterize()
468 {
469   bool     stopped = false;
470   uint32_t currentFrame;
471   mKeepAnimation = false;
472
473   {
474     ConditionalWait::ScopedLock lock(mConditionalWait);
475     if(mDestroyTask)
476     {
477       // The task will be destroyed. We don't need rasterization.
478       return false;
479     }
480   }
481
482   if(mLoadRequest)
483   {
484     return Load(false);
485   }
486
487   if(mLoadFailed)
488   {
489     return false;
490   }
491
492 #ifdef TRACE_ENABLED
493   if(gTraceFilter && gTraceFilter->IsTraceEnabled())
494   {
495     std::ostringstream oss;
496     oss << "[size:" << mWidth << "x" << mHeight << " ";
497     oss << "url:" << mImageUrl.GetUrl() << "]";
498     DALI_TRACE_BEGIN_WITH_MESSAGE(gTraceFilter, "DALI_LOTTIE_RASTERIZE_TASK", oss.str().c_str());
499   }
500 #endif
501
502   ApplyAnimationData();
503
504   if(mPlayState == PlayState::PLAYING && mUpdateFrameNumber)
505   {
506     mCurrentFrame = mForward ? mCurrentFrame + mDroppedFrames + 1 : (mCurrentFrame > mDroppedFrames ? mCurrentFrame - mDroppedFrames - 1 : 0);
507     Dali::ClampInPlace(mCurrentFrame, mStartFrame, mEndFrame);
508   }
509
510   currentFrame = mCurrentFrame;
511
512   mUpdateFrameNumber = true;
513
514   if(mPlayState == PlayState::STOPPING)
515   {
516     mCurrentFrame = GetStoppedFrame(mStartFrame, mEndFrame, mCurrentFrame);
517     currentFrame  = mCurrentFrame;
518     stopped       = true;
519   }
520   else if(mPlayState == PlayState::PLAYING)
521   {
522     bool animationFinished = false;
523
524     if(currentFrame >= mEndFrame) // last frame
525     {
526       if(mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE)
527       {
528         mForward = false;
529       }
530       else
531       {
532         if(mLoopCount < 0 || ++mCurrentLoop < mLoopCount) // repeat forever or before the last loop
533         {
534           mCurrentFrame      = mStartFrame;
535           mUpdateFrameNumber = false;
536         }
537         else
538         {
539           animationFinished = true; // end of animation
540         }
541       }
542     }
543     else if(currentFrame == mStartFrame && !mForward) // first frame
544     {
545       if(mLoopCount < 0 || ++mCurrentLoop < mLoopCount) // repeat forever or before the last loop
546       {
547         mForward = true;
548       }
549       else
550       {
551         animationFinished = true; // end of animation
552       }
553     }
554
555     if(animationFinished)
556     {
557       if(mStopBehavior == DevelImageVisual::StopBehavior::CURRENT_FRAME)
558       {
559         stopped = true;
560       }
561       else
562       {
563         mPlayState = PlayState::STOPPING;
564       }
565     }
566   }
567
568   // Rasterize
569   bool renderSuccess = false;
570   if(mVectorRenderer)
571   {
572     renderSuccess = mVectorRenderer.Render(currentFrame);
573     if(!renderSuccess)
574     {
575       DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Rendering failed. Try again later.[%d] [%p]\n", currentFrame, this);
576       mUpdateFrameNumber = false;
577     }
578   }
579
580   if(stopped && renderSuccess)
581   {
582     mPlayState   = PlayState::STOPPED;
583     mForward     = true;
584     mCurrentLoop = 0;
585
586     if(mVectorRenderer)
587     {
588       // Notify the Renderer that rendering is stopped.
589       mVectorRenderer.RenderStopped();
590     }
591
592     // Animation is finished
593     {
594       ConditionalWait::ScopedLock lock(mConditionalWait);
595       if(mNeedAnimationFinishedTrigger && mAnimationFinishedCallback)
596       {
597         mVectorAnimationThread.AddEventTriggerCallback(mAnimationFinishedCallback.get());
598       }
599     }
600
601     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this);
602   }
603
604   if(mPlayState != PlayState::PAUSED && mPlayState != PlayState::STOPPED)
605   {
606     mKeepAnimation = true;
607   }
608
609 #ifdef TRACE_ENABLED
610   if(gTraceFilter && gTraceFilter->IsTraceEnabled())
611   {
612     std::ostringstream oss;
613     oss << "[size:" << mWidth << "x" << mHeight << " ";
614     oss << "frame:" << mCurrentFrame << " ";
615     oss << "loop:" << mCurrentLoop << " ";
616     oss << "state:" << mPlayState << " ";
617     oss << "url:" << mImageUrl.GetUrl() << "]";
618     DALI_TRACE_END_WITH_MESSAGE(gTraceFilter, "DALI_LOTTIE_RASTERIZE_TASK", oss.str().c_str());
619   }
620 #endif
621
622   return true;
623 }
624
625 uint32_t VectorAnimationTask::GetStoppedFrame(uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame)
626 {
627   uint32_t frame = currentFrame;
628
629   switch(mStopBehavior)
630   {
631     case DevelImageVisual::StopBehavior::FIRST_FRAME:
632     {
633       frame = startFrame;
634       break;
635     }
636     case DevelImageVisual::StopBehavior::LAST_FRAME:
637     {
638       if(mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE)
639       {
640         frame = startFrame;
641       }
642       else
643       {
644         frame = endFrame;
645       }
646       break;
647     }
648     case DevelImageVisual::StopBehavior::CURRENT_FRAME:
649     {
650       frame = currentFrame;
651       break;
652     }
653   }
654
655   return frame;
656 }
657
658 VectorAnimationTask::TimePoint VectorAnimationTask::CalculateNextFrameTime(bool renderNow)
659 {
660   // std::chrono::time_point template has second parameter duration which defaults to the std::chrono::steady_clock supported
661   // duration. In some C++11 implementations it is a milliseconds duration, so it fails to compile unless mNextFrameStartTime
662   // is casted to use the default duration.
663   mNextFrameStartTime = std::chrono::time_point_cast<TimePoint::duration>(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds));
664   auto current        = std::chrono::steady_clock::now();
665   mDroppedFrames      = 0;
666
667   if(renderNow)
668   {
669     mNextFrameStartTime = current;
670   }
671   else if(mNextFrameStartTime < current)
672   {
673     uint32_t droppedFrames = 0;
674
675     while(current > std::chrono::time_point_cast<TimePoint::duration>(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds)) && droppedFrames < mTotalFrame)
676     {
677       droppedFrames++;
678       mNextFrameStartTime = std::chrono::time_point_cast<TimePoint::duration>(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds));
679     }
680
681     mNextFrameStartTime = current;
682     mDroppedFrames      = droppedFrames;
683   }
684
685   return mNextFrameStartTime;
686 }
687
688 VectorAnimationTask::TimePoint VectorAnimationTask::GetNextFrameTime()
689 {
690   return mNextFrameStartTime;
691 }
692
693 void VectorAnimationTask::ApplyAnimationData()
694 {
695   uint32_t index;
696
697   {
698     ConditionalWait::ScopedLock lock(mConditionalWait);
699
700     if(!mAnimationDataUpdated || mAnimationData[mAnimationDataIndex].size() != 0)
701     {
702       // Data is not updated or the previous data is not applied yet.
703       return;
704     }
705
706     mAnimationDataIndex   = mAnimationDataIndex == 0 ? 1 : 0; // Swap index
707     mAnimationDataUpdated = false;
708
709     index = mAnimationDataIndex;
710   }
711
712   for(const auto& animationData : mAnimationData[index])
713   {
714     if(animationData.resendFlag & VectorAnimationTask::RESEND_LOOP_COUNT)
715     {
716       SetLoopCount(animationData.loopCount);
717     }
718
719     if(animationData.resendFlag & VectorAnimationTask::RESEND_PLAY_RANGE)
720     {
721       SetPlayRange(animationData.playRange);
722     }
723
724     if(animationData.resendFlag & VectorAnimationTask::RESEND_STOP_BEHAVIOR)
725     {
726       SetStopBehavior(animationData.stopBehavior);
727     }
728
729     if(animationData.resendFlag & VectorAnimationTask::RESEND_LOOPING_MODE)
730     {
731       SetLoopingMode(animationData.loopingMode);
732     }
733
734     if(animationData.resendFlag & VectorAnimationTask::RESEND_CURRENT_FRAME)
735     {
736       SetCurrentFrameNumber(animationData.currentFrame);
737     }
738
739     if(animationData.resendFlag & VectorAnimationTask::RESEND_NEED_RESOURCE_READY)
740     {
741       mVectorRenderer.InvalidateBuffer();
742     }
743
744     if(animationData.resendFlag & VectorAnimationTask::RESEND_DYNAMIC_PROPERTY)
745     {
746       for(auto&& iter : animationData.dynamicProperties)
747       {
748         mVectorRenderer.AddPropertyValueCallback(iter.keyPath, static_cast<VectorAnimationRenderer::VectorProperty>(iter.property), iter.callback, iter.id);
749       }
750     }
751
752     if(animationData.resendFlag & VectorAnimationTask::RESEND_PLAY_STATE)
753     {
754       if(animationData.playState == DevelImageVisual::PlayState::PLAYING)
755       {
756         PlayAnimation();
757       }
758       else if(animationData.playState == DevelImageVisual::PlayState::PAUSED)
759       {
760         PauseAnimation();
761       }
762       else if(animationData.playState == DevelImageVisual::PlayState::STOPPED)
763       {
764         StopAnimation();
765       }
766     }
767   }
768
769   // reset data list
770   mAnimationData[index].clear();
771 }
772
773 void VectorAnimationTask::OnUploadCompleted()
774 {
775   mResourceReadySignal.Emit(ResourceStatus::READY);
776 }
777
778 void VectorAnimationTask::OnLoadCompleted()
779 {
780   if(!mLoadFailed)
781   {
782     mResourceReadySignal.Emit(ResourceStatus::LOADED);
783   }
784   else
785   {
786     mResourceReadySignal.Emit(ResourceStatus::FAILED);
787   }
788 }
789 } // namespace Internal
790
791 } // namespace Toolkit
792
793 } // namespace Dali