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