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