[dali_2.3.20] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / animated-image / animated-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-image/animated-image-visual.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/window-devel.h>
23 #include <dali/devel-api/adaptor-framework/image-loading.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/public-api/rendering/decorated-visual-renderer.h>
26 #include <memory>
27
28 // INTERNAL INCLUDES
29 #include <dali-toolkit/devel-api/image-loader/image-atlas.h>
30 #include <dali-toolkit/devel-api/image-loader/texture-manager.h>
31 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
32 #include <dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h>
33 #include <dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.h>
34 #include <dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h>
35 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
36 #include <dali-toolkit/internal/visuals/image-visual-shader-feature-builder.h>
37 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
38 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
39 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
40 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
41 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
42 #include <dali-toolkit/public-api/visuals/visual-properties.h>
43
44 namespace Dali
45 {
46 namespace Toolkit
47 {
48 namespace Internal
49 {
50 namespace
51 {
52 const int CUSTOM_PROPERTY_COUNT(5); // ltr, wrap, pixel area, crop to mask, mask texture ratio
53
54 // fitting modes
55 DALI_ENUM_TO_STRING_TABLE_BEGIN(FITTING_MODE)
56   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, SHRINK_TO_FIT)
57   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, SCALE_TO_FILL)
58   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, FIT_WIDTH)
59   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, FIT_HEIGHT)
60   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, DEFAULT)
61 DALI_ENUM_TO_STRING_TABLE_END(FITTING_MODE)
62
63 // sampling modes
64 DALI_ENUM_TO_STRING_TABLE_BEGIN(SAMPLING_MODE)
65   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX)
66   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, NEAREST)
67   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, LINEAR)
68   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX_THEN_NEAREST)
69   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX_THEN_LINEAR)
70   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, NO_FILTER)
71   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, DONT_CARE)
72 DALI_ENUM_TO_STRING_TABLE_END(SAMPLING_MODE)
73
74 // stop behavior
75 DALI_ENUM_TO_STRING_TABLE_BEGIN(STOP_BEHAVIOR)
76   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::DevelImageVisual::StopBehavior, CURRENT_FRAME)
77   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::DevelImageVisual::StopBehavior, FIRST_FRAME)
78   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::DevelImageVisual::StopBehavior, LAST_FRAME)
79 DALI_ENUM_TO_STRING_TABLE_END(STOP_BEHAVIOR)
80
81 // wrap modes
82 DALI_ENUM_TO_STRING_TABLE_BEGIN(WRAP_MODE)
83   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, DEFAULT)
84   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, CLAMP_TO_EDGE)
85   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, REPEAT)
86   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, MIRRORED_REPEAT)
87 DALI_ENUM_TO_STRING_TABLE_END(WRAP_MODE)
88
89 // load policies
90 DALI_ENUM_TO_STRING_TABLE_BEGIN(LOAD_POLICY)
91   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::LoadPolicy, IMMEDIATE)
92   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::LoadPolicy, ATTACHED)
93 DALI_ENUM_TO_STRING_TABLE_END(LOAD_POLICY)
94
95 // release policies
96 DALI_ENUM_TO_STRING_TABLE_BEGIN(RELEASE_POLICY)
97   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, DETACHED)
98   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, DESTROYED)
99   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, NEVER)
100 DALI_ENUM_TO_STRING_TABLE_END(RELEASE_POLICY)
101
102 static constexpr uint32_t SINGLE_IMAGE_COUNT = 1u;
103 static constexpr uint32_t FIRST_FRAME_INDEX  = 0u;
104 static constexpr uint16_t MINIMUM_CACHESIZE  = 1;
105 static constexpr Vector4  FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
106 static constexpr auto     LOOP_FOREVER = -1;
107 static constexpr auto     FIRST_LOOP   = 0u;
108
109 constexpr uint32_t TEXTURE_COUNT_FOR_GPU_ALPHA_MASK = 2u;
110
111 #if defined(DEBUG_ENABLED)
112 Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ANIMATED_IMAGE");
113 #endif
114 } // namespace
115
116 /**
117  * Multi-image  Flow of execution
118  *
119  *   | New
120  *   |   DoSetProperties()
121  *   |   OnInitialize()
122  *   |     CreateImageCache()
123  *   |
124  *   | DoSetOnScene()
125  *   |   PrepareTextureSet()
126  *   |     cache->FirstFrame()
127  *   |
128  *   | FrameReady(textureSet)
129  *   |   StartFirstFrame:
130  *   |     actor.AddRenderer
131  *   |     start timer
132  *   |   mRenderer.SetTextures(textureSet)
133  *   |
134  *   | Timer ticks
135  *   |   DisplayNextFrame()
136  *   |     if front frame is ready,
137  *   |       mRenderer.SetTextures( front frame's texture )
138  *   |     else
139  *   |       Waiting for frame ready.
140  *   |
141  *   | FrameReady(textureSet)
142  *   |   mRenderer.SetTextures(textureSet)
143  *   V
144  *  Time
145  */
146
147 AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties)
148 {
149   AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory, ImageDimensions()));
150   visual->InitializeAnimatedImage(imageUrl);
151   visual->SetProperties(properties);
152
153   visual->Initialize();
154
155   return visual;
156 }
157
158 AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const Property::Array& imageUrls, const Property::Map& properties)
159 {
160   AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory, ImageDimensions()));
161   visual->mImageUrls = new ImageCache::UrlList();
162   visual->mImageUrls->reserve(imageUrls.Count());
163
164   for(unsigned int i = 0; i < imageUrls.Count(); ++i)
165   {
166     ImageCache::UrlStore urlStore;
167     urlStore.mTextureId = TextureManager::INVALID_TEXTURE_ID;
168     urlStore.mUrl       = imageUrls[i].Get<std::string>();
169     visual->mImageUrls->push_back(urlStore);
170   }
171   visual->mFrameCount = imageUrls.Count();
172   visual->SetProperties(properties);
173
174   visual->Initialize();
175
176   return visual;
177 }
178
179 AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, ImageDimensions size)
180 {
181   AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory, size));
182   visual->InitializeAnimatedImage(imageUrl);
183
184   visual->Initialize();
185
186   return visual;
187 }
188
189 void AnimatedImageVisual::InitializeAnimatedImage(const VisualUrl& imageUrl)
190 {
191   mImageUrl             = imageUrl;
192   mAnimatedImageLoading = AnimatedImageLoading::New(imageUrl.GetUrl(), imageUrl.IsLocalResource());
193 }
194
195 void AnimatedImageVisual::CreateImageCache()
196 {
197   DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::CreateImageCache()  batchSize:%d  cacheSize:%d\n", mBatchSize, mCacheSize);
198
199   TextureManager& textureManager = mFactoryCache.GetTextureManager();
200
201   if(mAnimatedImageLoading)
202   {
203     mImageCache = new RollingAnimatedImageCache(textureManager, mDesiredSize, mFittingMode, mSamplingMode, mAnimatedImageLoading, mMaskingData, *this, mCacheSize, mBatchSize, mWrapModeU, mWrapModeV, IsSynchronousLoadingRequired(), IsPreMultipliedAlphaEnabled());
204   }
205   else if(mImageUrls)
206   {
207     // Ensure the batch size and cache size are no bigger than the number of URLs,
208     // and that the cache is at least as big as the batch size.
209     uint16_t numUrls   = mImageUrls->size();
210     uint16_t batchSize = std::max(std::min(mBatchSize, numUrls), MINIMUM_CACHESIZE);
211     uint16_t cacheSize = std::max(std::min(std::max(batchSize, mCacheSize), numUrls), MINIMUM_CACHESIZE);
212     if(cacheSize < numUrls)
213     {
214       mImageCache = new RollingImageCache(textureManager, mDesiredSize, mFittingMode, mSamplingMode, *mImageUrls, mMaskingData, *this, cacheSize, batchSize, mFrameDelay, IsPreMultipliedAlphaEnabled());
215     }
216     else
217     {
218       mImageCache = new FixedImageCache(textureManager, mDesiredSize, mFittingMode, mSamplingMode, *mImageUrls, mMaskingData, *this, batchSize, mFrameDelay, IsPreMultipliedAlphaEnabled());
219     }
220   }
221
222   if(!mImageCache)
223   {
224     DALI_LOG_ERROR("mImageCache is null\n");
225   }
226 }
227
228 AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, ImageDimensions desiredSize)
229 : Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::ANIMATED_IMAGE),
230   mFrameDelayTimer(),
231   mPlacementActor(),
232   mImageVisualShaderFactory(shaderFactory),
233   mPixelArea(FULL_TEXTURE_RECT),
234   mImageUrl(),
235   mAnimatedImageLoading(),
236   mFrameIndexForJumpTo(0),
237   mCurrentFrameIndex(FIRST_FRAME_INDEX),
238   mImageUrls(NULL),
239   mImageCache(NULL),
240   mCacheSize(2),
241   mBatchSize(2),
242   mFrameDelay(100),
243   mLoopCount(LOOP_FOREVER),
244   mCurrentLoopIndex(FIRST_LOOP),
245   mLoadPolicy(Toolkit::ImageVisual::LoadPolicy::ATTACHED),
246   mReleasePolicy(Toolkit::ImageVisual::ReleasePolicy::DETACHED),
247   mMaskingData(),
248   mDesiredSize(desiredSize),
249   mFrameCount(0),
250   mImageSize(),
251   mActionStatus(DevelAnimatedImageVisual::Action::PLAY),
252   mWrapModeU(WrapMode::DEFAULT),
253   mWrapModeV(WrapMode::DEFAULT),
254   mFittingMode(FittingMode::SCALE_TO_FILL),
255   mSamplingMode(SamplingMode::BOX_THEN_LINEAR),
256   mStopBehavior(DevelImageVisual::StopBehavior::CURRENT_FRAME),
257   mStartFirstFrame(false),
258   mIsJumpTo(false)
259 {
260   EnablePreMultipliedAlpha(mFactoryCache.GetPreMultiplyOnLoad());
261 }
262
263 AnimatedImageVisual::~AnimatedImageVisual()
264 {
265   // AnimatedImageVisual destroyed so remove texture unless ReleasePolicy is set to never release
266   // If this is animated image, clear cache. Else if this is single frame image, this is affected be release policy.
267   if(mFrameCount > SINGLE_IMAGE_COUNT || mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER)
268   {
269     mImageCache->ClearCache();
270   }
271   delete mImageCache;
272   delete mImageUrls;
273 }
274
275 void AnimatedImageVisual::GetNaturalSize(Vector2& naturalSize)
276 {
277   if(mDesiredSize.GetWidth() > 0 && mDesiredSize.GetHeight() > 0)
278   {
279     naturalSize.x = mDesiredSize.GetWidth();
280     naturalSize.y = mDesiredSize.GetHeight();
281     return;
282   }
283
284   naturalSize = Vector2::ZERO;
285   if(mImageSize.GetWidth() == 0 && mImageSize.GetHeight() == 0)
286   {
287     if(mMaskingData && mMaskingData->mAlphaMaskUrl.IsValid() &&
288        mMaskingData->mCropToMask)
289     {
290       ImageDimensions dimensions = Dali::GetClosestImageSize(mMaskingData->mAlphaMaskUrl.GetUrl());
291       if(dimensions != ImageDimensions(0, 0))
292       {
293         mImageSize    = dimensions;
294         naturalSize.x = dimensions.GetWidth();
295         naturalSize.y = dimensions.GetHeight();
296         return;
297       }
298     }
299
300     if(mImageUrl.IsValid())
301     {
302       mImageSize = mAnimatedImageLoading.GetImageSize();
303     }
304     else if(mImageUrls && mImageUrls->size() > 0)
305     {
306       mImageSize = Dali::GetClosestImageSize((*mImageUrls)[0].mUrl.GetUrl());
307     }
308   }
309
310   naturalSize.width  = mImageSize.GetWidth();
311   naturalSize.height = mImageSize.GetHeight();
312 }
313
314 void AnimatedImageVisual::DoCreatePropertyMap(Property::Map& map) const
315 {
316   map.Clear();
317
318   bool sync = IsSynchronousLoadingRequired();
319   map.Insert(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, sync);
320
321   map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::ANIMATED_IMAGE);
322
323   if(mImageUrl.IsValid())
324   {
325     map.Insert(Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl());
326   }
327   if(mImageUrls != NULL && !mImageUrls->empty())
328   {
329     Property::Array urls;
330     for(unsigned int i = 0; i < mImageUrls->size(); ++i)
331     {
332       urls.Add((*mImageUrls)[i].mUrl.GetUrl());
333     }
334     Property::Value value(const_cast<Property::Array&>(urls));
335     map.Insert(Toolkit::ImageVisual::Property::URL, value);
336   }
337
338   map.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, mPixelArea);
339   map.Insert(Toolkit::ImageVisual::Property::WRAP_MODE_U, mWrapModeU);
340   map.Insert(Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV);
341
342   map.Insert(Toolkit::ImageVisual::Property::BATCH_SIZE, static_cast<int>(mBatchSize));
343   map.Insert(Toolkit::ImageVisual::Property::CACHE_SIZE, static_cast<int>(mCacheSize));
344   map.Insert(Toolkit::ImageVisual::Property::FRAME_DELAY, static_cast<int>(mFrameDelay));
345   map.Insert(Toolkit::DevelImageVisual::Property::LOOP_COUNT, static_cast<int>(mLoopCount));
346   map.Insert(Toolkit::DevelImageVisual::Property::CURRENT_FRAME_NUMBER, (mImageCache) ? static_cast<int32_t>(mImageCache->GetCurrentFrameIndex()) : -1);
347   map.Insert(Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, (mImageCache) ? static_cast<int32_t>((mAnimatedImageLoading) ? mAnimatedImageLoading.GetImageCount() : mImageCache->GetTotalFrameCount()) : -1);
348
349   map.Insert(Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, mStopBehavior);
350
351   if(mMaskingData != nullptr)
352   {
353     map.Insert(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mMaskingData->mAlphaMaskUrl.GetUrl());
354     map.Insert(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskingData->mContentScaleFactor);
355     map.Insert(Toolkit::ImageVisual::Property::CROP_TO_MASK, mMaskingData->mCropToMask);
356     map.Insert(Toolkit::DevelImageVisual::Property::MASKING_TYPE, mMaskingData->mPreappliedMasking ? DevelImageVisual::MaskingType::MASKING_ON_LOADING : DevelImageVisual::MaskingType::MASKING_ON_RENDERING);
357   }
358
359   map.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, mLoadPolicy);
360   map.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy);
361   map.Insert(Toolkit::ImageVisual::Property::FITTING_MODE, mFittingMode);
362   map.Insert(Toolkit::ImageVisual::Property::SAMPLING_MODE, mSamplingMode);
363   map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
364   map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
365 }
366
367 void AnimatedImageVisual::DoCreateInstancePropertyMap(Property::Map& map) const
368 {
369   map.Clear();
370   map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::ANIMATED_IMAGE);
371   if(mImageUrl.IsValid())
372   {
373     map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
374     map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
375   }
376 }
377
378 void AnimatedImageVisual::OnDoAction(const Dali::Property::Index actionId, const Dali::Property::Value& attributes)
379 {
380   // Make not set any action when the resource status is already failed.
381   if(mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::FAILED)
382   {
383     return;
384   }
385
386   // Check if action is valid for this visual type and perform action if possible
387   switch(actionId)
388   {
389     case DevelAnimatedImageVisual::Action::PAUSE:
390     {
391       // Pause will be executed on next timer tick
392       mActionStatus = DevelAnimatedImageVisual::Action::PAUSE;
393       break;
394     }
395     case DevelAnimatedImageVisual::Action::PLAY:
396     {
397       if(mFrameDelayTimer && IsOnScene() && mActionStatus != DevelAnimatedImageVisual::Action::PLAY)
398       {
399         mFrameDelayTimer.Start();
400       }
401       mActionStatus = DevelAnimatedImageVisual::Action::PLAY;
402       break;
403     }
404     case DevelAnimatedImageVisual::Action::STOP:
405     {
406       // STOP reset functionality will actually be done in a future change
407       // Stop will be executed on next timer tick
408       mActionStatus     = DevelAnimatedImageVisual::Action::STOP;
409       mCurrentLoopIndex = FIRST_LOOP;
410       if(IsOnScene())
411       {
412         DisplayNextFrame();
413       }
414       break;
415     }
416     case DevelAnimatedImageVisual::Action::JUMP_TO:
417     {
418       int32_t frameNumber;
419       if(attributes.Get(frameNumber))
420       {
421         if(frameNumber < 0 || frameNumber >= static_cast<int32_t>(mFrameCount))
422         {
423           DALI_LOG_ERROR("Invalid frame index used.\n");
424         }
425         else
426         {
427           mIsJumpTo            = true;
428           mFrameIndexForJumpTo = frameNumber;
429           if(IsOnScene())
430           {
431             DisplayNextFrame();
432           }
433         }
434       }
435       break;
436     }
437   }
438 }
439
440 void AnimatedImageVisual::DoSetProperties(const Property::Map& propertyMap)
441 {
442   // url[s] already passed in from constructor
443   for(Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter)
444   {
445     KeyValuePair keyValue = propertyMap.GetKeyValue(iter);
446     if(keyValue.first.type == Property::Key::INDEX)
447     {
448       DoSetProperty(keyValue.first.indexKey, keyValue.second);
449     }
450     else
451     {
452       if(keyValue.first == PIXEL_AREA_UNIFORM_NAME)
453       {
454         DoSetProperty(Toolkit::ImageVisual::Property::PIXEL_AREA, keyValue.second);
455       }
456       else if(keyValue.first == IMAGE_WRAP_MODE_U)
457       {
458         DoSetProperty(Toolkit::ImageVisual::Property::WRAP_MODE_U, keyValue.second);
459       }
460       else if(keyValue.first == IMAGE_WRAP_MODE_V)
461       {
462         DoSetProperty(Toolkit::ImageVisual::Property::WRAP_MODE_V, keyValue.second);
463       }
464       else if(keyValue.first == BATCH_SIZE_NAME)
465       {
466         DoSetProperty(Toolkit::ImageVisual::Property::BATCH_SIZE, keyValue.second);
467       }
468       else if(keyValue.first == CACHE_SIZE_NAME)
469       {
470         DoSetProperty(Toolkit::ImageVisual::Property::CACHE_SIZE, keyValue.second);
471       }
472       else if(keyValue.first == FRAME_DELAY_NAME)
473       {
474         DoSetProperty(Toolkit::ImageVisual::Property::FRAME_DELAY, keyValue.second);
475       }
476       else if(keyValue.first == LOOP_COUNT_NAME)
477       {
478         DoSetProperty(Toolkit::DevelImageVisual::Property::LOOP_COUNT, keyValue.second);
479       }
480       else if(keyValue.first == STOP_BEHAVIOR_NAME)
481       {
482         DoSetProperty(Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, keyValue.second);
483       }
484       else if(keyValue.first == ALPHA_MASK_URL)
485       {
486         DoSetProperty(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, keyValue.second);
487       }
488       else if(keyValue.first == MASK_CONTENT_SCALE_NAME)
489       {
490         DoSetProperty(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, keyValue.second);
491       }
492       else if(keyValue.first == CROP_TO_MASK_NAME)
493       {
494         DoSetProperty(Toolkit::ImageVisual::Property::CROP_TO_MASK, keyValue.second);
495       }
496       else if(keyValue.first == MASKING_TYPE_NAME)
497       {
498         DoSetProperty(Toolkit::DevelImageVisual::Property::MASKING_TYPE, keyValue.second);
499       }
500       else if(keyValue.first == LOAD_POLICY_NAME)
501       {
502         DoSetProperty(Toolkit::ImageVisual::Property::LOAD_POLICY, keyValue.second);
503       }
504       else if(keyValue.first == RELEASE_POLICY_NAME)
505       {
506         DoSetProperty(Toolkit::ImageVisual::Property::RELEASE_POLICY, keyValue.second);
507       }
508       else if(keyValue.first == SYNCHRONOUS_LOADING)
509       {
510         DoSetProperty(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second);
511       }
512       else if(keyValue.first == IMAGE_FITTING_MODE)
513       {
514         DoSetProperty(Toolkit::ImageVisual::Property::FITTING_MODE, keyValue.second);
515       }
516       else if(keyValue.first == IMAGE_SAMPLING_MODE)
517       {
518         DoSetProperty(Toolkit::ImageVisual::Property::SAMPLING_MODE, keyValue.second);
519       }
520       else if(keyValue.first == IMAGE_DESIRED_WIDTH)
521       {
522         DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_WIDTH, keyValue.second);
523       }
524       else if(keyValue.first == IMAGE_DESIRED_HEIGHT)
525       {
526         DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, keyValue.second);
527       }
528     }
529   }
530   // Load image immediately if LOAD_POLICY requires it
531   if(mLoadPolicy == Toolkit::ImageVisual::LoadPolicy::IMMEDIATE)
532   {
533     PrepareTextureSet();
534   }
535 }
536
537 void AnimatedImageVisual::DoSetProperty(Property::Index        index,
538                                         const Property::Value& value)
539 {
540   switch(index)
541   {
542     case Toolkit::ImageVisual::Property::PIXEL_AREA:
543     {
544       value.Get(mPixelArea);
545       break;
546     }
547     case Toolkit::ImageVisual::Property::WRAP_MODE_U:
548     {
549       int wrapMode = 0;
550       if(Scripting::GetEnumerationProperty(value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode))
551       {
552         mWrapModeU = Dali::WrapMode::Type(wrapMode);
553       }
554       else
555       {
556         mWrapModeU = Dali::WrapMode::Type::DEFAULT;
557       }
558       break;
559     }
560     case Toolkit::ImageVisual::Property::WRAP_MODE_V:
561     {
562       int wrapMode = 0;
563       if(Scripting::GetEnumerationProperty(value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode))
564       {
565         mWrapModeV = Dali::WrapMode::Type(wrapMode);
566       }
567       else
568       {
569         mWrapModeV = Dali::WrapMode::Type::DEFAULT;
570       }
571       break;
572     }
573
574     case Toolkit::ImageVisual::Property::BATCH_SIZE:
575     {
576       int batchSize;
577       if(value.Get(batchSize))
578       {
579         if(batchSize < 2)
580         {
581           DALI_LOG_ERROR("The minimum value of batch size is 2.");
582         }
583         else
584         {
585           mBatchSize = batchSize;
586         }
587       }
588       break;
589     }
590
591     case Toolkit::ImageVisual::Property::CACHE_SIZE:
592     {
593       int cacheSize;
594       if(value.Get(cacheSize))
595       {
596         if(cacheSize < 2)
597         {
598           DALI_LOG_ERROR("The minimum value of cache size is 2.");
599         }
600         else
601         {
602           mCacheSize = cacheSize;
603         }
604       }
605       break;
606     }
607
608     case Toolkit::ImageVisual::Property::FRAME_DELAY:
609     {
610       int frameDelay;
611       if(value.Get(frameDelay))
612       {
613         mFrameDelay = frameDelay;
614         if(mImageCache)
615         {
616           mImageCache->SetInterval(static_cast<uint32_t>(mFrameDelay));
617         }
618       }
619       break;
620     }
621
622     case Toolkit::DevelImageVisual::Property::LOOP_COUNT:
623     {
624       int loopCount;
625       if(value.Get(loopCount))
626       {
627         mLoopCount = loopCount;
628       }
629       break;
630     }
631
632     case Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR:
633     {
634       int32_t stopBehavior = mStopBehavior;
635       if(Scripting::GetEnumerationProperty(value, STOP_BEHAVIOR_TABLE, STOP_BEHAVIOR_TABLE_COUNT, stopBehavior))
636       {
637         mStopBehavior = DevelImageVisual::StopBehavior::Type(stopBehavior);
638       }
639       break;
640     }
641
642     case Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING:
643     {
644       bool sync = false;
645       value.Get(sync);
646       if(sync)
647       {
648         mImpl->mFlags |= Visual::Base::Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
649       }
650       else
651       {
652         mImpl->mFlags &= ~Visual::Base::Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
653       }
654       break;
655     }
656
657     case Toolkit::ImageVisual::Property::ALPHA_MASK_URL:
658     {
659       std::string alphaUrl = "";
660       if(value.Get(alphaUrl))
661       {
662         AllocateMaskData();
663         mMaskingData->mAlphaMaskUrl = alphaUrl;
664       }
665       break;
666     }
667
668     case Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE:
669     {
670       float scale = 1.0f;
671       if(value.Get(scale))
672       {
673         AllocateMaskData();
674         mMaskingData->mContentScaleFactor = scale;
675       }
676       break;
677     }
678
679     case Toolkit::ImageVisual::Property::CROP_TO_MASK:
680     {
681       bool crop = false;
682       if(value.Get(crop))
683       {
684         AllocateMaskData();
685         mMaskingData->mCropToMask = crop;
686       }
687       break;
688     }
689
690     case Toolkit::DevelImageVisual::Property::MASKING_TYPE:
691     {
692       int maskingType = 0;
693       if(value.Get(maskingType))
694       {
695         AllocateMaskData();
696         mMaskingData->mPreappliedMasking = Toolkit::DevelImageVisual::MaskingType::Type(maskingType) == Toolkit::DevelImageVisual::MaskingType::MASKING_ON_LOADING ? true : false;
697       }
698       break;
699     }
700
701     case Toolkit::ImageVisual::Property::RELEASE_POLICY:
702     {
703       int releasePolicy = 0;
704       Scripting::GetEnumerationProperty(value, RELEASE_POLICY_TABLE, RELEASE_POLICY_TABLE_COUNT, releasePolicy);
705       mReleasePolicy = Toolkit::ImageVisual::ReleasePolicy::Type(releasePolicy);
706       break;
707     }
708
709     case Toolkit::ImageVisual::Property::LOAD_POLICY:
710     {
711       int loadPolicy = 0;
712       Scripting::GetEnumerationProperty(value, LOAD_POLICY_TABLE, LOAD_POLICY_TABLE_COUNT, loadPolicy);
713       mLoadPolicy = Toolkit::ImageVisual::LoadPolicy::Type(loadPolicy);
714       break;
715     }
716
717     case Toolkit::ImageVisual::Property::FITTING_MODE:
718     {
719       int fittingMode = 0;
720       Scripting::GetEnumerationProperty(value, FITTING_MODE_TABLE, FITTING_MODE_TABLE_COUNT, fittingMode);
721       mFittingMode = Dali::FittingMode::Type(fittingMode);
722       break;
723     }
724
725     case Toolkit::ImageVisual::Property::SAMPLING_MODE:
726     {
727       int samplingMode = 0;
728       Scripting::GetEnumerationProperty(value, SAMPLING_MODE_TABLE, SAMPLING_MODE_TABLE_COUNT, samplingMode);
729       mSamplingMode = Dali::SamplingMode::Type(samplingMode);
730       break;
731     }
732
733     case Toolkit::ImageVisual::Property::DESIRED_WIDTH:
734     {
735       float desiredWidth = 0.0f;
736       if(value.Get(desiredWidth))
737       {
738         mDesiredSize.SetWidth(desiredWidth);
739       }
740       else
741       {
742         DALI_LOG_ERROR("AnimatedImageVisual: desiredWidth property has incorrect type\n");
743       }
744       break;
745     }
746
747     case Toolkit::ImageVisual::Property::DESIRED_HEIGHT:
748     {
749       float desiredHeight = 0.0f;
750       if(value.Get(desiredHeight))
751       {
752         mDesiredSize.SetHeight(desiredHeight);
753       }
754       else
755       {
756         DALI_LOG_ERROR("AnimatedImageVisual: desiredHeight property has incorrect type\n");
757       }
758       break;
759     }
760   }
761 }
762
763 void AnimatedImageVisual::DoSetOnScene(Actor& actor)
764 {
765   mStartFirstFrame = true;
766   mPlacementActor  = actor;
767   PrepareTextureSet();
768
769   DevelActor::VisibilityChangedSignal(actor).Connect(this, &AnimatedImageVisual::OnControlVisibilityChanged);
770
771   Window window = DevelWindow::Get(actor);
772   if(window)
773   {
774     mPlacementWindow = window;
775     DevelWindow::VisibilityChangedSignal(window).Connect(this, &AnimatedImageVisual::OnWindowVisibilityChanged);
776   }
777 }
778
779 void AnimatedImageVisual::DoSetOffScene(Actor& actor)
780 {
781   DALI_ASSERT_DEBUG((bool)mImpl->mRenderer && "There should always be a renderer whilst on stage");
782
783   if(mFrameDelayTimer)
784   {
785     mFrameDelayTimer.Stop();
786     mFrameDelayTimer.Reset();
787   }
788
789   actor.RemoveRenderer(mImpl->mRenderer);
790   if(mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED)
791   {
792     mImageCache->ClearCache(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas
793     mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING;
794
795     TextureSet textureSet = TextureSet::New();
796     mImpl->mRenderer.SetTextures(textureSet);
797   }
798
799   mPlacementActor.Reset();
800   mStartFirstFrame   = false;
801   mCurrentFrameIndex = FIRST_FRAME_INDEX;
802   mCurrentLoopIndex  = FIRST_LOOP;
803
804   DevelActor::VisibilityChangedSignal(actor).Disconnect(this, &AnimatedImageVisual::OnControlVisibilityChanged);
805
806   Window window = mPlacementWindow.GetHandle();
807   if(window)
808   {
809     DevelWindow::VisibilityChangedSignal(window).Disconnect(this, &AnimatedImageVisual::OnWindowVisibilityChanged);
810     mPlacementWindow.Reset();
811   }
812 }
813
814 void AnimatedImageVisual::OnSetTransform()
815 {
816   if(mImpl->mRenderer)
817   {
818     mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
819   }
820 }
821
822 void AnimatedImageVisual::UpdateShader()
823 {
824   if(mImpl->mRenderer)
825   {
826     Shader shader = GenerateShader();
827     mImpl->mRenderer.SetShader(shader);
828   }
829 }
830
831 Shader AnimatedImageVisual::GenerateShader() const
832 {
833   bool   defaultWrapMode                 = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
834   bool   requiredAlphaMaskingOnRendering = (mMaskingData && !mMaskingData->mMaskImageLoadingFailed) ? !mMaskingData->mPreappliedMasking : false;
835   Shader shader;
836   shader = mImageVisualShaderFactory.GetShader(
837     mFactoryCache,
838     ImageVisualShaderFeatureBuilder()
839       .ApplyDefaultTextureWrapMode(defaultWrapMode)
840       .EnableRoundedCorner(IsRoundedCornerRequired())
841       .EnableBorderline(IsBorderlineRequired())
842       .EnableAlphaMaskingOnRendering(requiredAlphaMaskingOnRendering));
843   return shader;
844 }
845
846 void AnimatedImageVisual::OnInitialize()
847 {
848   CreateImageCache();
849
850   bool   defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
851   Shader shader          = GenerateShader();
852
853   Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
854
855   mImpl->mRenderer = DecoratedVisualRenderer::New(geometry, shader);
856   mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
857
858   // Register transform properties
859   mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
860
861   if(!defaultWrapMode) // custom wrap mode
862   {
863     Vector2 wrapMode(mWrapModeU - WrapMode::CLAMP_TO_EDGE, mWrapModeV - WrapMode::CLAMP_TO_EDGE);
864     wrapMode.Clamp(Vector2::ZERO, Vector2(2.f, 2.f));
865     mImpl->mRenderer.RegisterProperty(WRAP_MODE_UNIFORM_NAME, wrapMode);
866   }
867
868   if(mPixelArea != FULL_TEXTURE_RECT)
869   {
870     mImpl->mRenderer.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, mPixelArea);
871   }
872
873   if(mMaskingData)
874   {
875     mImpl->mRenderer.RegisterProperty(CROP_TO_MASK_NAME, static_cast<float>(mMaskingData->mCropToMask));
876   }
877
878   // Enable PreMultipliedAlpha if it need premultiplied
879   auto preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader
880                              ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD
881                              : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
882   EnablePreMultipliedAlpha(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
883 }
884
885 void AnimatedImageVisual::StartFirstFrame(TextureSet& textureSet, uint32_t firstInterval)
886 {
887   DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::StartFirstFrame()\n");
888
889   mStartFirstFrame = false;
890   if(mImpl->mRenderer)
891   {
892     mImpl->mRenderer.SetTextures(textureSet);
893     CheckMaskTexture();
894
895     Actor actor = mPlacementActor.GetHandle();
896     if(actor)
897     {
898       actor.AddRenderer(mImpl->mRenderer);
899       mPlacementActor.Reset();
900     }
901   }
902
903   if(mImpl->mResourceStatus != Toolkit::Visual::ResourceStatus::FAILED)
904   {
905     if(mFrameCount > SINGLE_IMAGE_COUNT)
906     {
907       mFrameDelayTimer = Timer::New(firstInterval);
908       mFrameDelayTimer.TickSignal().Connect(this, &AnimatedImageVisual::DisplayNextFrame);
909       mFrameDelayTimer.Start();
910     }
911
912     DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "ResourceReady(ResourceStatus::READY)\n");
913     ResourceReady(Toolkit::Visual::ResourceStatus::READY);
914   }
915
916   mCurrentFrameIndex = FIRST_FRAME_INDEX;
917 }
918
919 void AnimatedImageVisual::PrepareTextureSet()
920 {
921   TextureSet textureSet;
922   if(mImageCache)
923   {
924     textureSet = mImageCache->FirstFrame();
925   }
926
927   // Check whether synchronous loading is true or false for the first frame.
928   if(textureSet)
929   {
930     SetImageSize(textureSet);
931   }
932 }
933
934 void AnimatedImageVisual::SetImageSize(TextureSet& textureSet)
935 {
936   if(textureSet)
937   {
938     Texture texture = textureSet.GetTexture(0);
939     if(texture)
940     {
941       mImageSize.SetWidth(texture.GetWidth());
942       mImageSize.SetHeight(texture.GetHeight());
943     }
944
945     if(textureSet.GetTextureCount() > 1u && mMaskingData && mMaskingData->mCropToMask)
946     {
947       Texture maskTexture = textureSet.GetTexture(1);
948       if(maskTexture)
949       {
950         mImageSize.SetWidth(std::min(static_cast<uint32_t>(mImageSize.GetWidth() * mMaskingData->mContentScaleFactor), maskTexture.GetWidth()));
951         mImageSize.SetHeight(std::min(static_cast<uint32_t>(mImageSize.GetHeight() * mMaskingData->mContentScaleFactor), maskTexture.GetHeight()));
952
953         float   textureWidth  = std::max(static_cast<float>(texture.GetWidth() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1);
954         float   textureHeight = std::max(static_cast<float>(texture.GetHeight() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1);
955         Vector2 textureRatio(std::min(static_cast<float>(maskTexture.GetWidth()), textureWidth) / textureWidth,
956                              std::min(static_cast<float>(maskTexture.GetHeight()), textureHeight) / textureHeight);
957         mImpl->mRenderer.RegisterProperty(MASK_TEXTURE_RATIO_NAME, textureRatio);
958       }
959     }
960   }
961 }
962
963 void AnimatedImageVisual::FrameReady(TextureSet textureSet, uint32_t interval, bool preMultiplied)
964 {
965   EnablePreMultipliedAlpha(preMultiplied);
966
967   // When image visual requested to load new frame to mImageCache and it is failed.
968   if(!mImageCache || !textureSet)
969   {
970     textureSet = SetLoadingFailed();
971   }
972   SetImageSize(textureSet);
973
974   if(mStartFirstFrame)
975   {
976     mFrameCount = mImageCache->GetTotalFrameCount();
977     StartFirstFrame(textureSet, interval);
978   }
979   else
980   {
981     if(mImpl->mRenderer)
982     {
983       if(mFrameDelayTimer && interval > 0u)
984       {
985         mFrameDelayTimer.SetInterval(interval);
986       }
987       mImpl->mRenderer.SetTextures(textureSet);
988       CheckMaskTexture();
989     }
990   }
991 }
992
993 bool AnimatedImageVisual::DisplayNextFrame()
994 {
995   TextureSet textureSet;
996   bool       continueTimer = false;
997
998   if(mImageCache)
999   {
1000     uint32_t frameIndex = mImageCache->GetCurrentFrameIndex();
1001
1002     if(mIsJumpTo)
1003     {
1004       mIsJumpTo  = false;
1005       frameIndex = mFrameIndexForJumpTo;
1006     }
1007     else if(mActionStatus == DevelAnimatedImageVisual::Action::PAUSE)
1008     {
1009       return false;
1010     }
1011     else if(mActionStatus == DevelAnimatedImageVisual::Action::STOP)
1012     {
1013       mCurrentLoopIndex = FIRST_LOOP;
1014       if(mStopBehavior == DevelImageVisual::StopBehavior::FIRST_FRAME)
1015       {
1016         frameIndex = FIRST_FRAME_INDEX;
1017       }
1018       else if(mStopBehavior == DevelImageVisual::StopBehavior::LAST_FRAME)
1019       {
1020         frameIndex = mFrameCount - 1;
1021       }
1022       else
1023       {
1024         return false; // Do not draw already rendered scene twice.
1025       }
1026     }
1027     else
1028     {
1029       if(mFrameCount > SINGLE_IMAGE_COUNT)
1030       {
1031         frameIndex++;
1032         if(frameIndex >= mFrameCount)
1033         {
1034           frameIndex = FIRST_FRAME_INDEX;
1035           ++mCurrentLoopIndex;
1036         }
1037
1038         if(mLoopCount >= 0 && mCurrentLoopIndex >= mLoopCount)
1039         {
1040           // This will stop timer
1041           mActionStatus = DevelAnimatedImageVisual::Action::STOP;
1042           return DisplayNextFrame();
1043         }
1044       }
1045     }
1046
1047     DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "AnimatedImageVisual::DisplayNextFrame(this:%p) CurrentFrameIndex:%d\n", this, frameIndex);
1048
1049     textureSet = mImageCache->Frame(frameIndex);
1050
1051     if(textureSet)
1052     {
1053       SetImageSize(textureSet);
1054       if(mImpl->mRenderer)
1055       {
1056         mImpl->mRenderer.SetTextures(textureSet);
1057         CheckMaskTexture();
1058       }
1059       mFrameDelayTimer.SetInterval(mImageCache->GetFrameInterval(frameIndex));
1060     }
1061
1062     mCurrentFrameIndex = frameIndex;
1063     continueTimer      = (mActionStatus == DevelAnimatedImageVisual::Action::PLAY && textureSet) ? true : false;
1064   }
1065
1066   return continueTimer;
1067 }
1068
1069 TextureSet AnimatedImageVisual::SetLoadingFailed()
1070 {
1071   DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "ResourceReady(ResourceStatus::FAILED)\n");
1072   ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
1073
1074   Actor   actor     = mPlacementActor.GetHandle();
1075   Vector2 imageSize = Vector2::ZERO;
1076   if(actor)
1077   {
1078     imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
1079   }
1080   mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
1081   TextureSet textureSet = mImpl->mRenderer.GetTextures();
1082
1083   if(mFrameDelayTimer)
1084   {
1085     mFrameDelayTimer.Stop();
1086     mFrameDelayTimer.Reset();
1087   }
1088
1089   SetImageSize(textureSet);
1090
1091   return textureSet;
1092 }
1093
1094 void AnimatedImageVisual::AllocateMaskData()
1095 {
1096   if(!mMaskingData)
1097   {
1098     mMaskingData.reset(new TextureManager::MaskingData());
1099   }
1100 }
1101
1102 void AnimatedImageVisual::CheckMaskTexture()
1103 {
1104   if(mMaskingData && !mMaskingData->mPreappliedMasking)
1105   {
1106     bool       maskLoadFailed = true;
1107     TextureSet textures       = mImpl->mRenderer.GetTextures();
1108     if(textures && textures.GetTextureCount() >= TEXTURE_COUNT_FOR_GPU_ALPHA_MASK)
1109     {
1110       maskLoadFailed = false;
1111     }
1112     if(mMaskingData->mMaskImageLoadingFailed != maskLoadFailed)
1113     {
1114       mMaskingData->mMaskImageLoadingFailed = maskLoadFailed;
1115       UpdateShader();
1116     }
1117   }
1118 }
1119
1120 void AnimatedImageVisual::OnControlVisibilityChanged(Actor actor, bool visible, DevelActor::VisibilityChange::Type type)
1121 {
1122   if(!visible && mActionStatus != DevelAnimatedImageVisual::Action::STOP)
1123   {
1124     mActionStatus = DevelAnimatedImageVisual::Action::STOP;
1125     DisplayNextFrame();
1126     DALI_LOG_INFO(gAnimImgLogFilter, Debug::Verbose, "AnimatedImageVisual::OnControlVisibilityChanged: invisibile. Pause animation [%p]\n", this);
1127   }
1128 }
1129
1130 void AnimatedImageVisual::OnWindowVisibilityChanged(Window window, bool visible)
1131 {
1132   if(!visible && mActionStatus != DevelAnimatedImageVisual::Action::STOP)
1133   {
1134     mActionStatus = DevelAnimatedImageVisual::Action::STOP;
1135     DisplayNextFrame();
1136     DALI_LOG_INFO(gAnimImgLogFilter, Debug::Verbose, "AnimatedImageVisual::OnWindowVisibilityChanged: invisibile. Pause animation [%p]\n", this);
1137   }
1138 }
1139
1140 } // namespace Internal
1141
1142 } // namespace Toolkit
1143
1144 } // namespace Dali