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