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