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