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