Revert "[Tizen] Add log if destroyed visual get some signal"
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / animated-vector-image / animated-vector-image-visual.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/animated-vector-image-visual.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/window-devel.h>
23 #include <dali/devel-api/common/stage.h>
24 #include <dali/devel-api/rendering/renderer-devel.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/public-api/math/math-utils.h>
27 #include <dali/public-api/rendering/decorated-visual-renderer.h>
28
29 // INTERNAL INCLUDES
30 #include <dali-toolkit/devel-api/visuals/animated-vector-image-visual-signals-devel.h>
31 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
32 #include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
33 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-manager.h>
34 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
35 #include <dali-toolkit/internal/visuals/image-visual-shader-feature-builder.h>
36 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
37 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
38 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
39 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
40 #include <dali-toolkit/public-api/visuals/visual-properties.h>
41
42 namespace Dali
43 {
44 namespace Toolkit
45 {
46 namespace Internal
47 {
48 namespace
49 {
50 const int CUSTOM_PROPERTY_COUNT(1); // pixel area,
51
52 const Dali::Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
53
54 // stop behavior
55 DALI_ENUM_TO_STRING_TABLE_BEGIN(STOP_BEHAVIOR)
56   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::DevelImageVisual::StopBehavior, CURRENT_FRAME)
57   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::DevelImageVisual::StopBehavior, FIRST_FRAME)
58   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::DevelImageVisual::StopBehavior, LAST_FRAME)
59 DALI_ENUM_TO_STRING_TABLE_END(STOP_BEHAVIOR)
60
61 // looping mode
62 DALI_ENUM_TO_STRING_TABLE_BEGIN(LOOPING_MODE)
63   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::DevelImageVisual::LoopingMode, RESTART)
64   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::DevelImageVisual::LoopingMode, AUTO_REVERSE)
65 DALI_ENUM_TO_STRING_TABLE_END(LOOPING_MODE)
66
67 #if defined(DEBUG_ENABLED)
68 Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_ANIMATION");
69 #endif
70
71 } // unnamed namespace
72
73 AnimatedVectorImageVisualPtr AnimatedVectorImageVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties)
74 {
75   AnimatedVectorImageVisualPtr visual(new AnimatedVectorImageVisual(factoryCache, shaderFactory, imageUrl, ImageDimensions{}));
76   visual->SetProperties(properties);
77   visual->Initialize();
78   return visual;
79 }
80
81 AnimatedVectorImageVisualPtr AnimatedVectorImageVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, ImageDimensions size)
82 {
83   AnimatedVectorImageVisualPtr visual(new AnimatedVectorImageVisual(factoryCache, shaderFactory, imageUrl, size));
84   visual->Initialize();
85   return visual;
86 }
87
88 AnimatedVectorImageVisual::AnimatedVectorImageVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, ImageDimensions size)
89 : Visual::Base(factoryCache, Visual::FittingMode::FILL, static_cast<Toolkit::Visual::Type>(Toolkit::DevelVisual::ANIMATED_VECTOR_IMAGE)),
90   mImageUrl(imageUrl),
91   mAnimationData(),
92   mVectorAnimationTask(new VectorAnimationTask(factoryCache)),
93   mImageVisualShaderFactory(shaderFactory),
94   mVisualSize(),
95   mVisualScale(Vector2::ONE),
96   mDesiredSize(size),
97   mPlacementActor(),
98   mPlayState(DevelImageVisual::PlayState::STOPPED),
99   mEventCallback(nullptr),
100   mLoadFailed(false),
101   mRendererAdded(false),
102   mCoreShutdown(false),
103   mRedrawInScalingDown(true)
104 {
105   // the rasterized image is with pre-multiplied alpha format
106   mImpl->mFlags |= Visual::Base::Impl::IS_PREMULTIPLIED_ALPHA;
107
108   // By default, load a file synchronously
109   mImpl->mFlags |= Visual::Base::Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
110 }
111
112 AnimatedVectorImageVisual::~AnimatedVectorImageVisual()
113 {
114   if(!mCoreShutdown)
115   {
116     if(mImageUrl.IsBufferResource())
117     {
118       TextureManager& textureManager = mFactoryCache.GetTextureManager();
119       textureManager.RemoveEncodedImageBuffer(mImageUrl.GetUrl());
120     }
121
122     auto& vectorAnimationManager = mFactoryCache.GetVectorAnimationManager();
123     vectorAnimationManager.RemoveObserver(*this);
124
125     if(mEventCallback)
126     {
127       mFactoryCache.GetVectorAnimationManager().UnregisterEventCallback(mEventCallback);
128       mEventCallback = nullptr;
129     }
130
131     // Finalize animation task and disconnect the signal in the main thread
132     mVectorAnimationTask->ResourceReadySignal().Disconnect(this, &AnimatedVectorImageVisual::OnResourceReady);
133     mVectorAnimationTask->Finalize();
134   }
135 }
136
137 void AnimatedVectorImageVisual::VectorAnimationManagerDestroyed()
138 {
139   // Core is shutting down. Don't talk to the plugin any more.
140   mCoreShutdown = true;
141 }
142
143 void AnimatedVectorImageVisual::GetNaturalSize(Vector2& naturalSize)
144 {
145   if(mDesiredSize.GetWidth() > 0 && mDesiredSize.GetHeight() > 0)
146   {
147     naturalSize.x = mDesiredSize.GetWidth();
148     naturalSize.y = mDesiredSize.GetHeight();
149   }
150   else if(mVisualSize != Vector2::ZERO)
151   {
152     naturalSize = mVisualSize;
153   }
154   else
155   {
156     if(mLoadFailed && mImpl->mRenderer)
157     {
158       // Load failed, use broken image size
159       auto textureSet = mImpl->mRenderer.GetTextures();
160       if(textureSet && textureSet.GetTextureCount())
161       {
162         auto texture = textureSet.GetTexture(0);
163         if(texture)
164         {
165           naturalSize.x = texture.GetWidth();
166           naturalSize.y = texture.GetHeight();
167           return;
168         }
169       }
170     }
171     else
172     {
173       uint32_t width, height;
174       mVectorAnimationTask->GetDefaultSize(width, height);
175       naturalSize.x = width;
176       naturalSize.y = height;
177     }
178   }
179
180   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::GetNaturalSize: w = %f, h = %f [%p]\n", naturalSize.width, naturalSize.height, this);
181 }
182
183 void AnimatedVectorImageVisual::DoCreatePropertyMap(Property::Map& map) const
184 {
185   map.Clear();
186   map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::DevelVisual::ANIMATED_VECTOR_IMAGE);
187   if(mImageUrl.IsValid())
188   {
189     map.Insert(Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl());
190   }
191   map.Insert(Toolkit::DevelImageVisual::Property::LOOP_COUNT, mAnimationData.loopCount);
192
193   uint32_t startFrame, endFrame;
194   mVectorAnimationTask->GetPlayRange(startFrame, endFrame);
195
196   Property::Array playRange;
197   playRange.PushBack(static_cast<int32_t>(startFrame));
198   playRange.PushBack(static_cast<int32_t>(endFrame));
199   map.Insert(Toolkit::DevelImageVisual::Property::PLAY_RANGE, playRange);
200
201   map.Insert(Toolkit::DevelImageVisual::Property::PLAY_STATE, static_cast<int32_t>(mPlayState));
202   map.Insert(Toolkit::DevelImageVisual::Property::CURRENT_FRAME_NUMBER, static_cast<int32_t>(mVectorAnimationTask->GetCurrentFrameNumber()));
203   map.Insert(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, static_cast<int32_t>(mVectorAnimationTask->GetTotalFrameNumber()));
204
205   map.Insert(Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, mAnimationData.stopBehavior);
206   map.Insert(Toolkit::DevelImageVisual::Property::LOOPING_MODE, mAnimationData.loopingMode);
207   map.Insert(Toolkit::DevelImageVisual::Property::REDRAW_IN_SCALING_DOWN, mRedrawInScalingDown);
208
209   Property::Map layerInfo;
210   mVectorAnimationTask->GetLayerInfo(layerInfo);
211   map.Insert(Toolkit::DevelImageVisual::Property::CONTENT_INFO, layerInfo);
212
213   Property::Map markerInfo;
214   mVectorAnimationTask->GetMarkerInfo(markerInfo);
215   map.Insert(Toolkit::DevelImageVisual::Property::MARKER_INFO, markerInfo);
216
217   map.Insert(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, IsSynchronousLoadingRequired());
218   map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
219   map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
220 }
221
222 void AnimatedVectorImageVisual::DoCreateInstancePropertyMap(Property::Map& map) const
223 {
224   // Do nothing
225 }
226
227 void AnimatedVectorImageVisual::EnablePreMultipliedAlpha(bool preMultiplied)
228 {
229   // Make always enable pre multiplied alpha whether preMultiplied value is false.
230   if(!preMultiplied)
231   {
232     DALI_LOG_WARNING("Note : AnimatedVectorVisual cannot disable PreMultipliedAlpha\n");
233   }
234 }
235
236 void AnimatedVectorImageVisual::DoSetProperties(const Property::Map& propertyMap)
237 {
238   // url already passed in from constructor
239   for(Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter)
240   {
241     KeyValuePair keyValue = propertyMap.GetKeyValue(iter);
242     if(keyValue.first.type == Property::Key::INDEX)
243     {
244       DoSetProperty(keyValue.first.indexKey, keyValue.second);
245     }
246     else
247     {
248       if(keyValue.first == LOOP_COUNT_NAME)
249       {
250         DoSetProperty(Toolkit::DevelImageVisual::Property::LOOP_COUNT, keyValue.second);
251       }
252       else if(keyValue.first == PLAY_RANGE_NAME)
253       {
254         DoSetProperty(Toolkit::DevelImageVisual::Property::PLAY_RANGE, keyValue.second);
255       }
256       else if(keyValue.first == STOP_BEHAVIOR_NAME)
257       {
258         DoSetProperty(Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, keyValue.second);
259       }
260       else if(keyValue.first == LOOPING_MODE_NAME)
261       {
262         DoSetProperty(Toolkit::DevelImageVisual::Property::LOOPING_MODE, keyValue.second);
263       }
264       else if(keyValue.first == REDRAW_IN_SCALING_DOWN_NAME)
265       {
266         DoSetProperty(Toolkit::DevelImageVisual::Property::REDRAW_IN_SCALING_DOWN, keyValue.second);
267       }
268       else if(keyValue.first == SYNCHRONOUS_LOADING)
269       {
270         DoSetProperty(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second);
271       }
272       else if(keyValue.first == IMAGE_DESIRED_WIDTH)
273       {
274         DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_WIDTH, keyValue.second);
275       }
276       else if(keyValue.first == IMAGE_DESIRED_HEIGHT)
277       {
278         DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, keyValue.second);
279       }
280     }
281   }
282
283   TriggerVectorRasterization();
284 }
285
286 void AnimatedVectorImageVisual::DoSetProperty(Property::Index index, const Property::Value& value)
287 {
288   switch(index)
289   {
290     case Toolkit::DevelImageVisual::Property::LOOP_COUNT:
291     {
292       int32_t loopCount;
293       if(value.Get(loopCount))
294       {
295         mAnimationData.loopCount = loopCount;
296         mAnimationData.resendFlag |= VectorAnimationTask::RESEND_LOOP_COUNT;
297       }
298       break;
299     }
300     case Toolkit::DevelImageVisual::Property::PLAY_RANGE:
301     {
302       const Property::Array* array = value.GetArray();
303       if(array)
304       {
305         mAnimationData.playRange = *array;
306         mAnimationData.resendFlag |= VectorAnimationTask::RESEND_PLAY_RANGE;
307       }
308       else if(value.GetType() == Property::STRING)
309       {
310         std::string markerName;
311         if(value.Get(markerName))
312         {
313           Property::Array array;
314           array.Add(markerName);
315           mAnimationData.playRange = std::move(array);
316           mAnimationData.resendFlag |= VectorAnimationTask::RESEND_PLAY_RANGE;
317         }
318       }
319       break;
320     }
321     case Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR:
322     {
323       int32_t stopBehavior = mAnimationData.stopBehavior;
324       if(Scripting::GetEnumerationProperty(value, STOP_BEHAVIOR_TABLE, STOP_BEHAVIOR_TABLE_COUNT, stopBehavior))
325       {
326         mAnimationData.stopBehavior = DevelImageVisual::StopBehavior::Type(stopBehavior);
327         mAnimationData.resendFlag |= VectorAnimationTask::RESEND_STOP_BEHAVIOR;
328       }
329       break;
330     }
331     case Toolkit::DevelImageVisual::Property::LOOPING_MODE:
332     {
333       int32_t loopingMode = mAnimationData.loopingMode;
334       if(Scripting::GetEnumerationProperty(value, LOOPING_MODE_TABLE, LOOPING_MODE_TABLE_COUNT, loopingMode))
335       {
336         mAnimationData.loopingMode = DevelImageVisual::LoopingMode::Type(loopingMode);
337         mAnimationData.resendFlag |= VectorAnimationTask::RESEND_LOOPING_MODE;
338       }
339       break;
340     }
341     case Toolkit::DevelImageVisual::Property::REDRAW_IN_SCALING_DOWN:
342     {
343       bool redraw;
344       if(value.Get(redraw))
345       {
346         mRedrawInScalingDown = redraw;
347       }
348       break;
349     }
350     case Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING:
351     {
352       bool sync = false;
353       if(value.Get(sync))
354       {
355         if(sync)
356         {
357           mImpl->mFlags |= Visual::Base::Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
358         }
359         else
360         {
361           mImpl->mFlags &= ~Visual::Base::Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
362         }
363       }
364       break;
365     }
366     case Toolkit::ImageVisual::Property::DESIRED_WIDTH:
367     {
368       int32_t desiredWidth = 0;
369       if(value.Get(desiredWidth))
370       {
371         mDesiredSize.SetWidth(desiredWidth);
372       }
373       break;
374     }
375
376     case Toolkit::ImageVisual::Property::DESIRED_HEIGHT:
377     {
378       int32_t desiredHeight = 0;
379       if(value.Get(desiredHeight))
380       {
381         mDesiredSize.SetHeight(desiredHeight);
382       }
383       break;
384     }
385   }
386 }
387
388 void AnimatedVectorImageVisual::OnInitialize(void)
389 {
390   mVectorAnimationTask->ResourceReadySignal().Connect(this, &AnimatedVectorImageVisual::OnResourceReady);
391   mVectorAnimationTask->SetAnimationFinishedCallback(MakeCallback(this, &AnimatedVectorImageVisual::OnAnimationFinished));
392
393   EncodedImageBuffer encodedImageBuffer;
394
395   if(mImageUrl.IsBufferResource())
396   {
397     // Increase reference count of External Resources :
398     // EncodedImageBuffer.
399     // Reference count will be decreased at destructor of the visual.
400     TextureManager& textureManager = mFactoryCache.GetTextureManager();
401     textureManager.UseExternalResource(mImageUrl.GetUrl());
402
403     encodedImageBuffer = textureManager.GetEncodedImageBuffer(mImageUrl.GetUrl());
404   }
405
406   mVectorAnimationTask->RequestLoad(mImageUrl, encodedImageBuffer, IsSynchronousLoadingRequired());
407
408   auto& vectorAnimationManager = mFactoryCache.GetVectorAnimationManager();
409   vectorAnimationManager.AddObserver(*this);
410
411   Shader shader = GenerateShader();
412
413   Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
414
415   mImpl->mRenderer = DecoratedVisualRenderer::New(geometry, shader);
416   mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
417
418   TextureSet textureSet = TextureSet::New();
419   mImpl->mRenderer.SetTextures(textureSet);
420
421   // Register transform properties
422   mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
423
424   mVectorAnimationTask->SetRenderer(mImpl->mRenderer);
425 }
426
427 void AnimatedVectorImageVisual::DoSetOnScene(Actor& actor)
428 {
429   // Defer the rasterisation task until we get given a size (by Size Negotiation algorithm)
430
431   // Hold the weak handle of the placement actor and delay the adding of renderer until the rasterization is finished.
432   mPlacementActor = actor;
433
434   if(mLoadFailed)
435   {
436     Vector2 imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
437     mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize, false);
438     actor.AddRenderer(mImpl->mRenderer);
439     ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
440   }
441   else
442   {
443     // Add property notification for scaling & size
444     mScaleNotification = actor.AddPropertyNotification(Actor::Property::WORLD_SCALE, StepCondition(0.1f, 1.0f));
445     mScaleNotification.NotifySignal().Connect(this, &AnimatedVectorImageVisual::OnScaleNotification);
446
447     mSizeNotification = actor.AddPropertyNotification(Actor::Property::SIZE, StepCondition(3.0f));
448     mSizeNotification.NotifySignal().Connect(this, &AnimatedVectorImageVisual::OnSizeNotification);
449
450     DevelActor::VisibilityChangedSignal(actor).Connect(this, &AnimatedVectorImageVisual::OnControlVisibilityChanged);
451
452     Window window = DevelWindow::Get(actor);
453     if(window)
454     {
455       DevelWindow::VisibilityChangedSignal(window).Connect(this, &AnimatedVectorImageVisual::OnWindowVisibilityChanged);
456     }
457
458     if(mImpl->mEventObserver)
459     {
460       // The visual needs it's size set before it can be rasterized hence request relayout once on stage
461       mImpl->mEventObserver->RelayoutRequest(*this);
462     }
463
464     mAnimationData.resendFlag |= VectorAnimationTask::RESEND_NEED_RESOURCE_READY;
465     TriggerVectorRasterization();
466   }
467
468   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::DoSetOnScene [%p]\n", this);
469 }
470
471 void AnimatedVectorImageVisual::DoSetOffScene(Actor& actor)
472 {
473   StopAnimation();
474   TriggerVectorRasterization();
475
476   if(mImpl->mRenderer)
477   {
478     actor.RemoveRenderer(mImpl->mRenderer);
479     mRendererAdded = false;
480   }
481
482   // Remove property notification
483   actor.RemovePropertyNotification(mScaleNotification);
484   actor.RemovePropertyNotification(mSizeNotification);
485
486   DevelActor::VisibilityChangedSignal(actor).Disconnect(this, &AnimatedVectorImageVisual::OnControlVisibilityChanged);
487
488   Window window = DevelWindow::Get(actor);
489   if(window)
490   {
491     DevelWindow::VisibilityChangedSignal(window).Disconnect(this, &AnimatedVectorImageVisual::OnWindowVisibilityChanged);
492   }
493
494   mPlacementActor.Reset();
495
496   // Reset the visual size to zero so that when adding the actor back to stage the rasterization is forced
497   mVisualSize           = Vector2::ZERO;
498   mVisualScale          = Vector2::ONE;
499   mAnimationData.width  = 0;
500   mAnimationData.height = 0;
501
502   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::DoSetOffScene [%p]\n", this);
503 }
504
505 void AnimatedVectorImageVisual::OnSetTransform()
506 {
507   Vector2 visualSize = mImpl->mTransform.GetVisualSize(mImpl->mControlSize);
508
509   if(IsOnScene() && visualSize != mVisualSize)
510   {
511     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnSetTransform: width = %f, height = %f [%p]\n", visualSize.width, visualSize.height, this);
512
513     mVisualSize = visualSize;
514
515     SetVectorImageSize();
516
517     if(mPlayState == DevelImageVisual::PlayState::PLAYING && mAnimationData.playState != DevelImageVisual::PlayState::PLAYING)
518     {
519       mAnimationData.playState = DevelImageVisual::PlayState::PLAYING;
520       mAnimationData.resendFlag |= VectorAnimationTask::RESEND_PLAY_STATE;
521     }
522
523     TriggerVectorRasterization();
524   }
525 }
526
527 void AnimatedVectorImageVisual::UpdateShader()
528 {
529   if(mImpl->mRenderer)
530   {
531     Shader shader = GenerateShader();
532     mImpl->mRenderer.SetShader(shader);
533   }
534 }
535
536 void AnimatedVectorImageVisual::OnDoAction(const Property::Index actionId, const Property::Value& attributes)
537 {
538   // Check if action is valid for this visual type and perform action if possible
539   switch(actionId)
540   {
541     case DevelAnimatedVectorImageVisual::Action::PLAY:
542     {
543       if(IsOnScene() && mVisualSize != Vector2::ZERO)
544       {
545         if(mAnimationData.playState != DevelImageVisual::PlayState::PLAYING)
546         {
547           mAnimationData.playState = DevelImageVisual::PlayState::PLAYING;
548           mAnimationData.resendFlag |= VectorAnimationTask::RESEND_PLAY_STATE;
549         }
550       }
551       mPlayState = DevelImageVisual::PlayState::PLAYING;
552       break;
553     }
554     case DevelAnimatedVectorImageVisual::Action::PAUSE:
555     {
556       if(mAnimationData.playState == DevelImageVisual::PlayState::PLAYING)
557       {
558         mAnimationData.playState = DevelImageVisual::PlayState::PAUSED;
559         mAnimationData.resendFlag |= VectorAnimationTask::RESEND_PLAY_STATE;
560       }
561       mPlayState = DevelImageVisual::PlayState::PAUSED;
562       break;
563     }
564     case DevelAnimatedVectorImageVisual::Action::STOP:
565     {
566       if(mAnimationData.playState != DevelImageVisual::PlayState::STOPPED)
567       {
568         mAnimationData.playState = DevelImageVisual::PlayState::STOPPED;
569         mAnimationData.resendFlag |= VectorAnimationTask::RESEND_PLAY_STATE;
570       }
571       mPlayState = DevelImageVisual::PlayState::STOPPED;
572       break;
573     }
574     case DevelAnimatedVectorImageVisual::Action::JUMP_TO:
575     {
576       int32_t frameNumber;
577       if(attributes.Get(frameNumber))
578       {
579         mAnimationData.currentFrame = frameNumber;
580         mAnimationData.resendFlag |= VectorAnimationTask::RESEND_CURRENT_FRAME;
581       }
582       break;
583     }
584     case DevelAnimatedVectorImageVisual::Action::FLUSH:
585     {
586       if(DALI_LIKELY(!mCoreShutdown))
587       {
588         SendAnimationData();
589       }
590       break;
591     }
592   }
593
594   TriggerVectorRasterization();
595 }
596
597 void AnimatedVectorImageVisual::OnDoActionExtension(const Property::Index actionId, Dali::Any attributes)
598 {
599   switch(actionId)
600   {
601     case DevelAnimatedVectorImageVisual::Action::SET_DYNAMIC_PROPERTY:
602     {
603       DevelAnimatedVectorImageVisual::DynamicPropertyInfo info = AnyCast<DevelAnimatedVectorImageVisual::DynamicPropertyInfo>(attributes);
604       mAnimationData.dynamicProperties.push_back(info);
605       mAnimationData.resendFlag |= VectorAnimationTask::RESEND_DYNAMIC_PROPERTY;
606       break;
607     }
608   }
609
610   TriggerVectorRasterization();
611 }
612
613 void AnimatedVectorImageVisual::OnResourceReady(VectorAnimationTask::ResourceStatus status)
614 {
615   AnimatedVectorImageVisualPtr self = this; // Keep reference until this API finished
616
617   if(status == VectorAnimationTask::ResourceStatus::LOADED)
618   {
619     if(mImpl->mEventObserver)
620     {
621       mImpl->mEventObserver->RelayoutRequest(*this);
622     }
623   }
624   else
625   {
626     mLoadFailed = status == VectorAnimationTask::ResourceStatus::FAILED ? true : false;
627
628     // If weak handle is holding a placement actor, it is the time to add the renderer to actor.
629     Actor actor = mPlacementActor.GetHandle();
630     if(actor && !mRendererAdded)
631     {
632       if(!mLoadFailed)
633       {
634         actor.AddRenderer(mImpl->mRenderer);
635         ResourceReady(Toolkit::Visual::ResourceStatus::READY);
636       }
637       else
638       {
639         Vector2 imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
640         mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize, false);
641         actor.AddRenderer(mImpl->mRenderer);
642         ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
643       }
644
645       mRendererAdded = true;
646     }
647   }
648
649   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "status = %d [%p]\n", status, this);
650 }
651
652 void AnimatedVectorImageVisual::OnAnimationFinished()
653 {
654   AnimatedVectorImageVisualPtr self = this; // Keep reference until this API finished
655
656   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnAnimationFinished: action state = %d [%p]\n", mPlayState, this);
657
658   if(mPlayState != DevelImageVisual::PlayState::STOPPED)
659   {
660     mPlayState = DevelImageVisual::PlayState::STOPPED;
661
662     mAnimationData.playState = DevelImageVisual::PlayState::STOPPED;
663
664     if(mImpl->mEventObserver)
665     {
666       mImpl->mEventObserver->NotifyVisualEvent(*this, DevelAnimatedVectorImageVisual::Signal::ANIMATION_FINISHED);
667     }
668   }
669
670   if(mImpl->mRenderer)
671   {
672     mImpl->mRenderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED);
673   }
674 }
675
676 void AnimatedVectorImageVisual::SendAnimationData()
677 {
678   if(mAnimationData.resendFlag)
679   {
680     mVectorAnimationTask->SetAnimationData(mAnimationData);
681
682     if(mImpl->mRenderer)
683     {
684       if(mAnimationData.playState == DevelImageVisual::PlayState::PLAYING)
685       {
686         mImpl->mRenderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY);
687       }
688       else
689       {
690         mImpl->mRenderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED);
691       }
692     }
693
694     mAnimationData.resendFlag = 0;
695   }
696 }
697
698 void AnimatedVectorImageVisual::SetVectorImageSize()
699 {
700   uint32_t width, height;
701   if(mDesiredSize.GetWidth() > 0 && mDesiredSize.GetHeight() > 0)
702   {
703     width  = mDesiredSize.GetWidth();
704     height = mDesiredSize.GetHeight();
705   }
706   else
707   {
708     width  = static_cast<uint32_t>(mVisualSize.width * mVisualScale.width);
709     height = static_cast<uint32_t>(mVisualSize.height * mVisualScale.height);
710   }
711
712   if(mAnimationData.width != width || mAnimationData.height != height)
713   {
714     mAnimationData.width  = width;
715     mAnimationData.height = height;
716     mAnimationData.resendFlag |= VectorAnimationTask::RESEND_SIZE;
717   }
718 }
719
720 void AnimatedVectorImageVisual::StopAnimation()
721 {
722   if(mAnimationData.playState != DevelImageVisual::PlayState::STOPPED)
723   {
724     mAnimationData.playState = DevelImageVisual::PlayState::STOPPED;
725     mAnimationData.resendFlag |= VectorAnimationTask::RESEND_PLAY_STATE;
726
727     mPlayState = DevelImageVisual::PlayState::STOPPED;
728   }
729 }
730
731 void AnimatedVectorImageVisual::TriggerVectorRasterization()
732 {
733   if(!mEventCallback && !mCoreShutdown)
734   {
735     mEventCallback               = MakeCallback(this, &AnimatedVectorImageVisual::OnProcessEvents);
736     auto& vectorAnimationManager = mFactoryCache.GetVectorAnimationManager();
737     vectorAnimationManager.RegisterEventCallback(mEventCallback);
738     Stage::GetCurrent().KeepRendering(0.0f); // Trigger event processing
739   }
740 }
741
742 void AnimatedVectorImageVisual::OnScaleNotification(PropertyNotification& source)
743 {
744   Actor actor = mPlacementActor.GetHandle();
745   if(actor)
746   {
747     Vector3 scale = actor.GetProperty<Vector3>(Actor::Property::WORLD_SCALE);
748
749     if((!Dali::Equals(mVisualScale.width, scale.width) || !Dali::Equals(mVisualScale.height, scale.height)) && (mRedrawInScalingDown || scale.width >= 1.0f || scale.height >= 1.0f))
750     {
751       mVisualScale.width  = scale.width;
752       mVisualScale.height = scale.height;
753
754       DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnScaleNotification: scale = %f, %f [%p]\n", mVisualScale.width, mVisualScale.height, this);
755
756       SetVectorImageSize();
757       SendAnimationData();
758
759       Stage::GetCurrent().KeepRendering(0.0f); // Trigger event processing
760     }
761   }
762 }
763
764 void AnimatedVectorImageVisual::OnSizeNotification(PropertyNotification& source)
765 {
766   Actor actor = mPlacementActor.GetHandle();
767   if(actor)
768   {
769     Vector3 size = actor.GetCurrentProperty<Vector3>(Actor::Property::SIZE);
770
771     if(!Dali::Equals(mVisualSize.width, size.width) || !Dali::Equals(mVisualSize.height, size.height))
772     {
773       mVisualSize.width  = size.width;
774       mVisualSize.height = size.height;
775
776       DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnSizeNotification: size = %f, %f [%p]\n", mVisualSize.width, mVisualSize.height, this);
777
778       SetVectorImageSize();
779       SendAnimationData();
780
781       Stage::GetCurrent().KeepRendering(0.0f); // Trigger event processing
782     }
783   }
784 }
785
786 void AnimatedVectorImageVisual::OnControlVisibilityChanged(Actor actor, bool visible, DevelActor::VisibilityChange::Type type)
787 {
788   if(!visible)
789   {
790     StopAnimation();
791     TriggerVectorRasterization();
792
793     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnControlVisibilityChanged: invisibile. Pause animation [%p]\n", this);
794   }
795 }
796
797 void AnimatedVectorImageVisual::OnWindowVisibilityChanged(Window window, bool visible)
798 {
799   if(!visible)
800   {
801     StopAnimation();
802     TriggerVectorRasterization();
803
804     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnWindowVisibilityChanged: invisibile. Pause animation [%p]\n", this);
805   }
806 }
807
808 void AnimatedVectorImageVisual::OnProcessEvents()
809 {
810   SendAnimationData();
811
812   mEventCallback = nullptr; // The callback will be deleted in the VectorAnimationManager
813 }
814
815 Shader AnimatedVectorImageVisual::GenerateShader() const
816 {
817   Shader shader;
818   if(mImpl->mCustomShader)
819   {
820     shader = Shader::New(mImpl->mCustomShader->mVertexShader.empty() ? mImageVisualShaderFactory.GetVertexShaderSource().data() : mImpl->mCustomShader->mVertexShader,
821                          mImpl->mCustomShader->mFragmentShader.empty() ? mImageVisualShaderFactory.GetFragmentShaderSource().data() : mImpl->mCustomShader->mFragmentShader,
822                          mImpl->mCustomShader->mHints);
823
824     shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
825   }
826   else
827   {
828     shader = mImageVisualShaderFactory.GetShader(
829       mFactoryCache,
830       ImageVisualShaderFeatureBuilder()
831         .EnableRoundedCorner(IsRoundedCornerRequired())
832         .EnableBorderline(IsBorderlineRequired()));
833   }
834   return shader;
835 }
836
837 } // namespace Internal
838
839 } // namespace Toolkit
840
841 } // namespace Dali