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