Merge "Changes in Particle System for NUI" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / image / 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/image/image-visual.h>
20
21 // EXTERNAL HEADERS
22 #include <dali/devel-api/adaptor-framework/image-loading.h>
23 #include <dali/devel-api/common/stage.h>
24 #include <dali/devel-api/rendering/renderer-devel.h>
25 #include <dali/devel-api/rendering/texture-devel.h>
26 #include <dali/devel-api/scripting/enum-helper.h>
27 #include <dali/devel-api/scripting/scripting.h>
28 #include <dali/integration-api/debug.h>
29 #include <dali/public-api/actors/layer.h>
30 #include <dali/public-api/adaptor-framework/async-task-manager.h>
31 #include <dali/public-api/rendering/decorated-visual-renderer.h>
32 #include <cstring> // for strlen()
33
34 // INTERNAL HEADERS
35 #include <dali-toolkit/devel-api/visuals/image-visual-actions-devel.h>
36 #include <dali-toolkit/internal/texture-manager/texture-manager-impl.h>
37 #include <dali-toolkit/internal/visuals/image-atlas-manager.h>
38 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
39 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
40 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
41 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
42 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
43 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
44 #include <dali-toolkit/internal/visuals/visual-url.h>
45 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
46 #include <dali-toolkit/public-api/visuals/visual-properties.h>
47
48 namespace Dali
49 {
50 namespace Toolkit
51 {
52 namespace Internal
53 {
54 namespace
55 {
56 const int CUSTOM_PROPERTY_COUNT(7); // ltr, wrap, pixel area, atlas, pixalign, crop to mask, mask texture ratio
57
58 // fitting modes
59 DALI_ENUM_TO_STRING_TABLE_BEGIN(FITTING_MODE)
60   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, SHRINK_TO_FIT)
61   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, SCALE_TO_FILL)
62   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, FIT_WIDTH)
63   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, FIT_HEIGHT)
64   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, DEFAULT)
65 DALI_ENUM_TO_STRING_TABLE_END(FITTING_MODE)
66
67 // sampling modes
68 DALI_ENUM_TO_STRING_TABLE_BEGIN(SAMPLING_MODE)
69   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX)
70   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, NEAREST)
71   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, LINEAR)
72   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX_THEN_NEAREST)
73   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX_THEN_LINEAR)
74   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, NO_FILTER)
75   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, DONT_CARE)
76 DALI_ENUM_TO_STRING_TABLE_END(SAMPLING_MODE)
77
78 // wrap modes
79 DALI_ENUM_TO_STRING_TABLE_BEGIN(WRAP_MODE)
80   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, DEFAULT)
81   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, CLAMP_TO_EDGE)
82   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, REPEAT)
83   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::WrapMode, MIRRORED_REPEAT)
84 DALI_ENUM_TO_STRING_TABLE_END(WRAP_MODE)
85
86 // load policies
87 DALI_ENUM_TO_STRING_TABLE_BEGIN(LOAD_POLICY)
88   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::LoadPolicy, IMMEDIATE)
89   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::LoadPolicy, ATTACHED)
90 DALI_ENUM_TO_STRING_TABLE_END(LOAD_POLICY)
91
92 // release policies
93 DALI_ENUM_TO_STRING_TABLE_BEGIN(RELEASE_POLICY)
94   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, DETACHED)
95   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, DESTROYED)
96   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::ImageVisual::ReleasePolicy, NEVER)
97 DALI_ENUM_TO_STRING_TABLE_END(RELEASE_POLICY)
98
99 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
100
101 constexpr uint32_t TEXTURE_COUNT_FOR_GPU_ALPHA_MASK = 2u;
102
103 Geometry CreateGeometry(VisualFactoryCache& factoryCache, ImageDimensions gridSize)
104 {
105   Geometry geometry;
106
107   if(gridSize == ImageDimensions(1, 1))
108   {
109     geometry = factoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY);
110   }
111   else
112   {
113     geometry = VisualFactoryCache::CreateGridGeometry(gridSize);
114   }
115
116   return geometry;
117 }
118
119 } // unnamed namespace
120
121 ImageVisualPtr ImageVisual::New(VisualFactoryCache&       factoryCache,
122                                 ImageVisualShaderFactory& shaderFactory,
123                                 const VisualUrl&          imageUrl,
124                                 const Property::Map&      properties,
125                                 ImageDimensions           size,
126                                 FittingMode::Type         fittingMode,
127                                 Dali::SamplingMode::Type  samplingMode)
128 {
129   ImageVisualPtr imageVisualPtr(new ImageVisual(factoryCache, shaderFactory, imageUrl, size, fittingMode, samplingMode));
130   imageVisualPtr->SetProperties(properties);
131   imageVisualPtr->Initialize();
132   return imageVisualPtr;
133 }
134
135 ImageVisualPtr ImageVisual::New(VisualFactoryCache&       factoryCache,
136                                 ImageVisualShaderFactory& shaderFactory,
137                                 const VisualUrl&          imageUrl,
138                                 ImageDimensions           size,
139                                 FittingMode::Type         fittingMode,
140                                 Dali::SamplingMode::Type  samplingMode)
141 {
142   ImageVisualPtr imageVisualPtr(new ImageVisual(factoryCache, shaderFactory, imageUrl, size, fittingMode, samplingMode));
143   imageVisualPtr->Initialize();
144   return imageVisualPtr;
145 }
146
147 ImageVisual::ImageVisual(VisualFactoryCache&       factoryCache,
148                          ImageVisualShaderFactory& shaderFactory,
149                          const VisualUrl&          imageUrl,
150                          ImageDimensions           size,
151                          FittingMode::Type         fittingMode,
152                          Dali::SamplingMode::Type  samplingMode)
153 : Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::IMAGE),
154   mPixelArea(FULL_TEXTURE_RECT),
155   mPlacementActor(),
156   mImageUrl(imageUrl),
157   mMaskingData(),
158   mDesiredSize(size),
159   mTextureId(TextureManager::INVALID_TEXTURE_ID),
160   mTextures(),
161   mImageVisualShaderFactory(shaderFactory),
162   mFittingMode(fittingMode),
163   mSamplingMode(samplingMode),
164   mWrapModeU(WrapMode::DEFAULT),
165   mWrapModeV(WrapMode::DEFAULT),
166   mLoadPolicy(Toolkit::ImageVisual::LoadPolicy::ATTACHED),
167   mReleasePolicy(Toolkit::ImageVisual::ReleasePolicy::DETACHED),
168   mAtlasRect(0.0f, 0.0f, 0.0f, 0.0f),
169   mAtlasRectSize(0, 0),
170   mLoadState(TextureManager::LoadState::NOT_STARTED),
171   mAttemptAtlasing(false),
172   mOrientationCorrection(true),
173   mEnableBrokenImage(true)
174 {
175   EnablePreMultipliedAlpha(mFactoryCache.GetPreMultiplyOnLoad());
176 }
177
178 ImageVisual::~ImageVisual()
179 {
180   if(Stage::IsInstalled())
181   {
182     if(mImageUrl.IsValid())
183     {
184       // Decrease reference count of External Resources :
185       // EncodedImageBuffer or ExternalTextures.
186       // Ensure the stage is still valid before accessing texture manager.
187       if(mImageUrl.GetProtocolType() == VisualUrl::TEXTURE)
188       {
189         TextureManager& textureManager = mFactoryCache.GetTextureManager();
190         textureManager.RemoveExternalTexture(mImageUrl.GetUrl());
191       }
192       else if(mImageUrl.IsBufferResource())
193       {
194         TextureManager& textureManager = mFactoryCache.GetTextureManager();
195         textureManager.RemoveEncodedImageBuffer(mImageUrl.GetUrl());
196       }
197     }
198
199     // ImageVisual destroyed so remove texture unless ReleasePolicy is set to never release
200     if((mTextureId != TextureManager::INVALID_TEXTURE_ID) && (mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER))
201     {
202       RemoveTexture();
203     }
204
205     ResetFastTrackLoadingTask();
206   }
207 }
208
209 void ImageVisual::DoSetProperties(const Property::Map& propertyMap)
210 {
211   // Url is already received in constructor
212   for(Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter)
213   {
214     KeyValuePair keyValue = propertyMap.GetKeyValue(iter);
215     if(keyValue.first.type == Property::Key::INDEX)
216     {
217       DoSetProperty(keyValue.first.indexKey, keyValue.second);
218     }
219     else
220     {
221       if(keyValue.first == IMAGE_FITTING_MODE)
222       {
223         DoSetProperty(Toolkit::ImageVisual::Property::FITTING_MODE, keyValue.second);
224       }
225       else if(keyValue.first == IMAGE_SAMPLING_MODE)
226       {
227         DoSetProperty(Toolkit::ImageVisual::Property::SAMPLING_MODE, keyValue.second);
228       }
229       else if(keyValue.first == IMAGE_DESIRED_WIDTH)
230       {
231         DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_WIDTH, keyValue.second);
232       }
233       else if(keyValue.first == IMAGE_DESIRED_HEIGHT)
234       {
235         DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, keyValue.second);
236       }
237       else if(keyValue.first == PIXEL_AREA_UNIFORM_NAME)
238       {
239         DoSetProperty(Toolkit::ImageVisual::Property::PIXEL_AREA, keyValue.second);
240       }
241       else if(keyValue.first == IMAGE_WRAP_MODE_U)
242       {
243         DoSetProperty(Toolkit::ImageVisual::Property::WRAP_MODE_U, keyValue.second);
244       }
245       else if(keyValue.first == IMAGE_WRAP_MODE_V)
246       {
247         DoSetProperty(Toolkit::ImageVisual::Property::WRAP_MODE_V, keyValue.second);
248       }
249       else if(keyValue.first == SYNCHRONOUS_LOADING)
250       {
251         DoSetProperty(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second);
252       }
253       else if(keyValue.first == IMAGE_ATLASING)
254       {
255         DoSetProperty(Toolkit::ImageVisual::Property::ATLASING, keyValue.second);
256       }
257       else if(keyValue.first == ALPHA_MASK_URL)
258       {
259         DoSetProperty(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, keyValue.second);
260       }
261       else if(keyValue.first == MASK_CONTENT_SCALE_NAME)
262       {
263         DoSetProperty(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, keyValue.second);
264       }
265       else if(keyValue.first == CROP_TO_MASK_NAME)
266       {
267         DoSetProperty(Toolkit::ImageVisual::Property::CROP_TO_MASK, keyValue.second);
268       }
269       else if(keyValue.first == MASKING_TYPE_NAME)
270       {
271         DoSetProperty(Toolkit::DevelImageVisual::Property::MASKING_TYPE, keyValue.second);
272       }
273       else if(keyValue.first == ENABLE_BROKEN_IMAGE)
274       {
275         DoSetProperty(Toolkit::DevelImageVisual::Property::ENABLE_BROKEN_IMAGE, keyValue.second);
276       }
277       else if(keyValue.first == LOAD_POLICY_NAME)
278       {
279         DoSetProperty(Toolkit::ImageVisual::Property::LOAD_POLICY, keyValue.second);
280       }
281       else if(keyValue.first == RELEASE_POLICY_NAME)
282       {
283         DoSetProperty(Toolkit::ImageVisual::Property::RELEASE_POLICY, keyValue.second);
284       }
285       else if(keyValue.first == ORIENTATION_CORRECTION_NAME)
286       {
287         DoSetProperty(Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION, keyValue.second);
288       }
289       else if(keyValue.first == FAST_TRACK_UPLOADING_NAME)
290       {
291         DoSetProperty(Toolkit::DevelImageVisual::Property::FAST_TRACK_UPLOADING, keyValue.second);
292       }
293     }
294   }
295   // Load image immediately if LOAD_POLICY requires it
296   if(mLoadPolicy == Toolkit::ImageVisual::LoadPolicy::IMMEDIATE)
297   {
298     auto attemptAtlasing = AttemptAtlasing();
299     LoadTexture(attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection, TextureManager::ReloadPolicy::CACHED);
300   }
301 }
302
303 void ImageVisual::DoSetProperty(Property::Index index, const Property::Value& value)
304 {
305   switch(index)
306   {
307     case Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING:
308     {
309       bool sync = false;
310       if(value.Get(sync))
311       {
312         if(sync)
313         {
314           mImpl->mFlags |= Visual::Base::Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
315         }
316         else
317         {
318           mImpl->mFlags &= ~Visual::Base::Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
319         }
320       }
321       else
322       {
323         DALI_LOG_ERROR("ImageVisual: synchronousLoading property has incorrect type\n");
324       }
325       break;
326     }
327
328     case Toolkit::ImageVisual::Property::DESIRED_WIDTH:
329     {
330       int32_t desiredWidth = 0;
331       if(value.Get(desiredWidth))
332       {
333         mDesiredSize.SetWidth(desiredWidth);
334       }
335       else
336       {
337         DALI_LOG_ERROR("ImageVisual: desiredWidth property has incorrect type\n");
338       }
339       break;
340     }
341
342     case Toolkit::ImageVisual::Property::DESIRED_HEIGHT:
343     {
344       int32_t desiredHeight = 0;
345       if(value.Get(desiredHeight))
346       {
347         mDesiredSize.SetHeight(desiredHeight);
348       }
349       else
350       {
351         DALI_LOG_ERROR("ImageVisual: desiredHeight property has incorrect type\n");
352       }
353       break;
354     }
355
356     case Toolkit::ImageVisual::Property::FITTING_MODE:
357     {
358       int fittingMode = 0;
359       Scripting::GetEnumerationProperty(value, FITTING_MODE_TABLE, FITTING_MODE_TABLE_COUNT, fittingMode);
360       mFittingMode = Dali::FittingMode::Type(fittingMode);
361       break;
362     }
363
364     case Toolkit::ImageVisual::Property::SAMPLING_MODE:
365     {
366       int samplingMode = 0;
367       Scripting::GetEnumerationProperty(value, SAMPLING_MODE_TABLE, SAMPLING_MODE_TABLE_COUNT, samplingMode);
368       mSamplingMode = Dali::SamplingMode::Type(samplingMode);
369       break;
370     }
371
372     case Toolkit::ImageVisual::Property::PIXEL_AREA:
373     {
374       value.Get(mPixelArea);
375       break;
376     }
377
378     case Toolkit::ImageVisual::Property::WRAP_MODE_U:
379     {
380       int wrapMode = 0;
381       Scripting::GetEnumerationProperty(value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode);
382       mWrapModeU = Dali::WrapMode::Type(wrapMode);
383       break;
384     }
385
386     case Toolkit::ImageVisual::Property::WRAP_MODE_V:
387     {
388       int wrapMode = 0;
389       Scripting::GetEnumerationProperty(value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode);
390       mWrapModeV = Dali::WrapMode::Type(wrapMode);
391       break;
392     }
393
394     case Toolkit::ImageVisual::Property::ATLASING:
395     {
396       value.Get(mAttemptAtlasing);
397       break;
398     }
399
400     case Toolkit::ImageVisual::Property::ALPHA_MASK_URL:
401     {
402       std::string alphaUrl = "";
403       if(value.Get(alphaUrl))
404       {
405         AllocateMaskData();
406         mMaskingData->mAlphaMaskUrl = alphaUrl;
407       }
408       break;
409     }
410
411     case Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE:
412     {
413       float scale = 1.0f;
414       if(value.Get(scale))
415       {
416         AllocateMaskData();
417         mMaskingData->mContentScaleFactor = scale;
418       }
419       break;
420     }
421
422     case Toolkit::ImageVisual::Property::CROP_TO_MASK:
423     {
424       bool crop = false;
425       if(value.Get(crop))
426       {
427         AllocateMaskData();
428         mMaskingData->mCropToMask = crop;
429       }
430       break;
431     }
432
433     case Toolkit::DevelImageVisual::Property::MASKING_TYPE:
434     {
435       int maskingType = 0;
436       if(value.Get(maskingType))
437       {
438         AllocateMaskData();
439         if(mImageUrl.IsValid() && mImageUrl.GetProtocolType() == VisualUrl::TEXTURE)
440         {
441           // For external textures, only gpu masking is available.
442           // Therefore, MASKING_TYPE is set to MASKING_ON_RENDERING forcelly.
443           mMaskingData->mPreappliedMasking = false;
444         }
445         else
446         {
447           mMaskingData->mPreappliedMasking = Toolkit::DevelImageVisual::MaskingType::Type(maskingType) == Toolkit::DevelImageVisual::MaskingType::MASKING_ON_LOADING ? true : false;
448         }
449       }
450       break;
451     }
452
453     case Toolkit::DevelImageVisual::Property::ENABLE_BROKEN_IMAGE:
454     {
455       bool enableBrokenImage(mEnableBrokenImage);
456       if(value.Get(enableBrokenImage))
457       {
458         mEnableBrokenImage = enableBrokenImage;
459       }
460       break;
461     }
462
463     case Toolkit::ImageVisual::Property::RELEASE_POLICY:
464     {
465       int releasePolicy = 0;
466       Scripting::GetEnumerationProperty(value, RELEASE_POLICY_TABLE, RELEASE_POLICY_TABLE_COUNT, releasePolicy);
467       mReleasePolicy = Toolkit::ImageVisual::ReleasePolicy::Type(releasePolicy);
468       break;
469     }
470
471     case Toolkit::ImageVisual::Property::LOAD_POLICY:
472     {
473       int loadPolicy = 0;
474       Scripting::GetEnumerationProperty(value, LOAD_POLICY_TABLE, LOAD_POLICY_TABLE_COUNT, loadPolicy);
475       mLoadPolicy = Toolkit::ImageVisual::LoadPolicy::Type(loadPolicy);
476       break;
477     }
478     case Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION:
479     {
480       bool orientationCorrection(mOrientationCorrection);
481       if(value.Get(orientationCorrection))
482       {
483         mOrientationCorrection = orientationCorrection;
484       }
485       break;
486     }
487
488     case Toolkit::DevelImageVisual::Property::FAST_TRACK_UPLOADING:
489     {
490       bool fastTrackUploading = false;
491       if(value.Get(fastTrackUploading))
492       {
493         mUseFastTrackUploading = fastTrackUploading;
494       }
495       break;
496     }
497   }
498 }
499
500 void ImageVisual::AllocateMaskData()
501 {
502   if(!mMaskingData)
503   {
504     mMaskingData.reset(new TextureManager::MaskingData());
505     if(mImageUrl.IsValid() && mImageUrl.GetProtocolType() == VisualUrl::TEXTURE)
506     {
507       mMaskingData->mPreappliedMasking = false;
508     }
509   }
510 }
511
512 void ImageVisual::GetNaturalSize(Vector2& naturalSize)
513 {
514   if(mDesiredSize.GetWidth() > 0 && mDesiredSize.GetHeight() > 0)
515   {
516     naturalSize.x = mDesiredSize.GetWidth();
517     naturalSize.y = mDesiredSize.GetHeight();
518     return;
519   }
520   else if(mImpl->mRenderer) // Check if we have a loaded image
521   {
522     if(mImpl->mFlags & Visual::Base::Impl::IS_ATLASING_APPLIED)
523     {
524       naturalSize.x = mAtlasRectSize.GetWidth();
525       naturalSize.y = mAtlasRectSize.GetHeight();
526       return;
527     }
528
529     auto textureSet = mImpl->mRenderer.GetTextures();
530     if(textureSet && textureSet.GetTextureCount())
531     {
532       if(mTextureSize != Vector2::ZERO)
533       {
534         naturalSize = mTextureSize;
535         return;
536       }
537     }
538   }
539
540   if(mMaskingData != NULL && mMaskingData->mAlphaMaskUrl.IsValid() &&
541      mMaskingData->mCropToMask)
542   {
543     ImageDimensions dimensions = Dali::GetClosestImageSize(mMaskingData->mAlphaMaskUrl.GetUrl());
544     if(dimensions != ImageDimensions(0, 0))
545     {
546       naturalSize.x = dimensions.GetWidth();
547       naturalSize.y = dimensions.GetHeight();
548     }
549     return;
550   }
551   else if(mImageUrl.IsValid())
552   {
553     if(mImageUrl.GetProtocolType() == VisualUrl::LOCAL)
554     {
555       ImageDimensions dimensions = Dali::GetClosestImageSize(mImageUrl.GetUrl());
556
557       if(dimensions != ImageDimensions(0, 0))
558       {
559         naturalSize.x = dimensions.GetWidth();
560         naturalSize.y = dimensions.GetHeight();
561       }
562       else
563       {
564         Actor   actor     = mPlacementActor.GetHandle();
565         Vector2 imageSize = Vector2::ZERO;
566         if(actor)
567         {
568           imageSize = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
569         }
570         else
571         {
572           imageSize = mPlacementActorSize;
573         }
574
575         mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
576         Texture brokenImage = mImpl->mRenderer.GetTextures().GetTexture(0);
577         naturalSize.x       = brokenImage.GetWidth();
578         naturalSize.y       = brokenImage.GetWidth();
579       }
580       return;
581     }
582   }
583   naturalSize = Vector2::ZERO;
584 }
585
586 void ImageVisual::OnInitialize()
587 {
588   Geometry geometry;
589
590   // Get the geometry
591   if(mImpl->mCustomShader)
592   {
593     geometry = CreateGeometry(mFactoryCache, mImpl->mCustomShader->mGridSize);
594   }
595   else // Get any geometry associated with the texture
596   {
597     TextureManager& textureManager = mFactoryCache.GetTextureManager();
598
599     uint32_t firstElementCount{0u};
600     uint32_t secondElementCount{0u};
601     geometry = textureManager.GetRenderGeometry(mTextureId, firstElementCount, secondElementCount);
602
603     if(!firstElementCount && !secondElementCount) // Otherwise use quad
604     {
605       geometry = CreateGeometry(mFactoryCache, ImageDimensions(1, 1));
606     }
607   }
608
609   // Increase reference count of External Resources :
610   // EncodedImageBuffer or ExternalTextures.
611   // Reference count will be decreased at destructor of the visual.
612   if(mImageUrl.IsValid() && (mImageUrl.IsBufferResource() || mImageUrl.GetProtocolType() == VisualUrl::TEXTURE))
613   {
614     TextureManager& textureManager = mFactoryCache.GetTextureManager();
615     textureManager.UseExternalResource(mImageUrl.GetUrl());
616   }
617
618   Shader shader = GenerateShader();
619
620   // Create the renderer
621   mImpl->mRenderer = DecoratedVisualRenderer::New(geometry, shader);
622   mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
623
624   //Register transform properties
625   mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
626
627   EnablePreMultipliedAlpha(IsPreMultipliedAlphaEnabled());
628
629   if(mMaskingData)
630   {
631     mImpl->mRenderer.RegisterProperty(CROP_TO_MASK_NAME, static_cast<float>(mMaskingData->mCropToMask));
632   }
633 }
634
635 void ImageVisual::LoadTexture(bool& atlasing, Vector4& atlasRect, TextureSet& textures, bool orientationCorrection, TextureManager::ReloadPolicy forceReload)
636 {
637   TextureManager& textureManager = mFactoryCache.GetTextureManager();
638
639   ImageAtlasManagerPtr atlasManager        = nullptr;
640   AtlasUploadObserver* atlasUploadObserver = nullptr;
641   auto                 textureObserver     = this;
642
643   if(atlasing)
644   {
645     atlasManager        = mFactoryCache.GetAtlasManager();
646     atlasUploadObserver = this;
647   }
648
649   auto preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader
650                              ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD
651                              : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
652
653   bool synchronousLoading = IsSynchronousLoadingRequired();
654   bool loadingStatus      = false;
655
656   // Remove previous loading task.
657   ResetFastTrackLoadingTask();
658
659   // Rare case. If someone call LoadTexture during fast track loading task running, (Ex : Action::RELOAD)
660   // we should remove previously added renderer now.
661   if(mRendererAdded)
662   {
663     Actor actor = mPlacementActor.GetHandle();
664     if(actor)
665     {
666       actor.RemoveRenderer(mImpl->mRenderer);
667       mRendererAdded = false;
668     }
669   }
670
671   /**
672    * @brief Check whether FastTrackUploading is avaliable or not.
673    * @return True if we can use fast track uploading feature. False otherwise.
674    */
675   auto IsFastTrackUploadingAvailable = [&]() {
676     if(mUseFastTrackUploading &&
677        mLoadPolicy == Toolkit::ImageVisual::LoadPolicy::ATTACHED &&
678        mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED &&
679        forceReload == TextureManager::ReloadPolicy::CACHED &&
680        (mImageUrl.GetProtocolType() == VisualUrl::LOCAL || mImageUrl.GetProtocolType() == VisualUrl::REMOTE) &&
681        !synchronousLoading &&
682        !atlasing &&
683        !mImpl->mCustomShader &&
684        !(mMaskingData && mMaskingData->mAlphaMaskUrl.IsValid()))
685     {
686       return true;
687     }
688     else if(mUseFastTrackUploading)
689     {
690       DALI_LOG_DEBUG_INFO("FastTrack : Fail to load fast track. mUrl : [%s]%s%s%s%s%s%s%s%s\n",
691                           mImageUrl.GetUrl().c_str(),
692                           (mLoadPolicy != Toolkit::ImageVisual::LoadPolicy::ATTACHED) ? "/ mLoadPolicy != ATTACHED" : "",
693                           (mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::DETACHED) ? "/ mReleasePolicy != DETACHED" : "",
694                           (forceReload != TextureManager::ReloadPolicy::CACHED) ? "/ forceReload != CACHED" : "",
695                           (!(mImageUrl.GetProtocolType() == VisualUrl::LOCAL || mImageUrl.GetProtocolType() == VisualUrl::REMOTE)) ? "/ url is not image" : "",
696                           (synchronousLoading) ? "/ synchronousLoading" : "",
697                           (atlasing) ? "/ atlasing" : "",
698                           (mImpl->mCustomShader) ? "/ use customs shader" : "",
699                           (mMaskingData && mMaskingData->mAlphaMaskUrl.IsValid()) ? "/ use masking url" : "");
700     }
701     return false;
702   };
703
704   if(IsFastTrackUploadingAvailable())
705   {
706     // Enable PremultipliedAlpha first.
707     EnablePreMultipliedAlpha(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
708
709     // Set new TextureSet with fast track loading task
710     mFastTrackLoadingTask = new FastTrackLoadingTask(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mOrientationCorrection, preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF, MakeCallback(this, &ImageVisual::FastLoadComplete));
711
712     TextureSet textureSet = TextureSet::New();
713     textureSet.SetTexture(0u, mFastTrackLoadingTask->mTexture);
714     mImpl->mRenderer.SetTextures(textureSet);
715
716     Dali::AsyncTaskManager::Get().AddTask(mFastTrackLoadingTask);
717
718     mLoadState = TextureManager::LoadState::LOADING;
719   }
720   else
721   {
722     textures = textureManager.LoadTexture(mImageUrl, mDesiredSize, mFittingMode, mSamplingMode, mMaskingData, synchronousLoading, mTextureId, atlasRect, mAtlasRectSize, atlasing, loadingStatus, textureObserver, atlasUploadObserver, atlasManager, mOrientationCorrection, forceReload, preMultiplyOnLoad);
723   }
724
725   if(textures)
726   {
727     if(loadingStatus)
728     {
729       mLoadState = TextureManager::LoadState::LOADING;
730     }
731     else
732     {
733       mLoadState = TextureManager::LoadState::LOAD_FINISHED;
734     }
735
736     EnablePreMultipliedAlpha(preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD);
737     if(!atlasing)
738     {
739       Sampler sampler = Sampler::New();
740       sampler.SetWrapMode(mWrapModeU, mWrapModeV);
741       textures.SetSampler(0u, sampler);
742     }
743   }
744   else if(synchronousLoading)
745   {
746     // Synchronous loading is failed
747     mLoadState = TextureManager::LoadState::LOAD_FAILED;
748   }
749
750   if(atlasing) // Flag needs to be set before creating renderer
751   {
752     mImpl->mFlags |= Visual::Base::Impl::IS_ATLASING_APPLIED;
753   }
754   else
755   {
756     mImpl->mFlags &= ~Visual::Base::Impl::IS_ATLASING_APPLIED;
757   }
758 }
759
760 bool ImageVisual::AttemptAtlasing()
761 {
762   return (!mImpl->mCustomShader && (mImageUrl.IsLocalResource() || mImageUrl.IsBufferResource()) && mAttemptAtlasing);
763 }
764
765 void ImageVisual::InitializeRenderer()
766 {
767   auto attemptAtlasing = AttemptAtlasing();
768
769   // Load Texture if mTextures is empty.
770   // mTextures is already set, the mTexture can be used to create Renderer.
771   // There are two cases mTextures is empty.
772   // 1. mTextureId == TextureManager::INVALID_TEXTURE_ID
773   //  - Visual is on stage with LoadPolicy::ATTACHED
774   // 2. mTextureId != TextureManager::INVALID_TEXTURE_ID
775   //  - If ReleasePolicy is DESTROYED, InitializeRenderer called every on stage called.
776   //  - Then every resources those contained in Visual are Reset but mTextureId is remained when the Off stage time,
777   //  - So, mTextures needed to be get from texture manager to created resources like mImpl->mRenderer.
778   if(!mTextures)
779   {
780     if(mTextureId == TextureManager::INVALID_TEXTURE_ID)
781     {
782       LoadTexture(attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection, TextureManager::ReloadPolicy::CACHED);
783     }
784     else
785     {
786       mTextures = mFactoryCache.GetTextureManager().GetTextureSet(mTextureId);
787       if(!(mImpl->mFlags & Visual::Base::Impl::IS_ATLASING_APPLIED) && mTextures)
788       {
789         Sampler sampler = Sampler::New();
790         sampler.SetWrapMode(mWrapModeU, mWrapModeV);
791         mTextures.SetSampler(0u, sampler);
792       }
793     }
794   }
795
796   if(mTextures)
797   {
798     mImpl->mRenderer.SetTextures(mTextures);
799     ComputeTextureSize();
800     CheckMaskTexture();
801
802     bool needToUpdateShader = DevelTexture::IsNative(mTextures.GetTexture(0));
803
804     if(mTextures.GetTextureCount() == 3)
805     {
806       if(mTextures.GetTexture(0).GetPixelFormat() == Pixel::L8 && mTextures.GetTexture(1).GetPixelFormat() == Pixel::CHROMINANCE_U && mTextures.GetTexture(2).GetPixelFormat() == Pixel::CHROMINANCE_V)
807       {
808         mNeedYuvToRgb      = true;
809         needToUpdateShader = true;
810       }
811     }
812
813     if(needToUpdateShader)
814     {
815       UpdateShader();
816     }
817     mTextures.Reset(); // Visual should not keep a handle to the texture after this point.
818   }
819
820   if(attemptAtlasing) // the texture is packed inside atlas
821   {
822     mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, mAtlasRect);
823
824     bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
825
826     if(!defaultWrapMode) // custom wrap mode
827     {
828       Vector2 wrapMode(mWrapModeU - WrapMode::CLAMP_TO_EDGE, mWrapModeV - WrapMode::CLAMP_TO_EDGE);
829       wrapMode.Clamp(Vector2::ZERO, Vector2(2.f, 2.f));
830       mImpl->mRenderer.RegisterProperty(WRAP_MODE_UNIFORM_NAME, wrapMode);
831     }
832   }
833 }
834
835 void ImageVisual::DoSetOnScene(Actor& actor)
836 {
837   if(mImageUrl.IsValid())
838   {
839     InitializeRenderer();
840   }
841
842   if(!mImpl->mRenderer)
843   {
844     return;
845   }
846
847   mPlacementActor = actor;
848
849   if(mPixelArea != FULL_TEXTURE_RECT)
850   {
851     mImpl->mRenderer.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, mPixelArea);
852   }
853
854   if(mLoadState == TextureManager::LoadState::LOAD_FINISHED)
855   {
856     actor.AddRenderer(mImpl->mRenderer);
857     mRendererAdded = true;
858     mPlacementActor.Reset();
859
860     // Image loaded and ready to display
861     ResourceReady(Toolkit::Visual::ResourceStatus::READY);
862   }
863   else if(mLoadState == TextureManager::LoadState::LOAD_FAILED)
864   {
865     ShowBrokenImage();
866     ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
867   }
868   else
869   {
870     if(mFastTrackLoadingTask)
871     {
872       actor.AddRenderer(mImpl->mRenderer);
873       mRendererAdded = true;
874     }
875   }
876 }
877
878 void ImageVisual::DoSetOffScene(Actor& actor)
879 {
880   // Visual::Base::SetOffScene only calls DoSetOffScene if mRenderer exists (is on onstage)
881
882   // Image release is dependent on the ReleasePolicy, renderer is removed.
883   actor.RemoveRenderer(mImpl->mRenderer);
884   mRendererAdded = false;
885
886   if(mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED)
887   {
888     ResetRenderer();
889   }
890
891   mPlacementActor.Reset();
892 }
893
894 void ImageVisual::DoCreatePropertyMap(Property::Map& map) const
895 {
896   map.Clear();
897   map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
898
899   bool sync = IsSynchronousLoadingRequired();
900   map.Insert(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, sync);
901   if(mImageUrl.IsValid())
902   {
903     map.Insert(Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl());
904     map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
905     map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
906   }
907
908   map.Insert(Toolkit::ImageVisual::Property::FITTING_MODE, mFittingMode);
909   map.Insert(Toolkit::ImageVisual::Property::SAMPLING_MODE, mSamplingMode);
910
911   map.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, mPixelArea);
912   map.Insert(Toolkit::ImageVisual::Property::WRAP_MODE_U, mWrapModeU);
913   map.Insert(Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV);
914
915   map.Insert(Toolkit::ImageVisual::Property::ATLASING, mAttemptAtlasing);
916
917   if(mMaskingData != NULL)
918   {
919     map.Insert(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mMaskingData->mAlphaMaskUrl.GetUrl());
920     map.Insert(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskingData->mContentScaleFactor);
921     map.Insert(Toolkit::ImageVisual::Property::CROP_TO_MASK, mMaskingData->mCropToMask);
922     map.Insert(Toolkit::DevelImageVisual::Property::MASKING_TYPE, mMaskingData->mPreappliedMasking ? DevelImageVisual::MaskingType::MASKING_ON_LOADING : DevelImageVisual::MaskingType::MASKING_ON_RENDERING);
923   }
924
925   map.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, mLoadPolicy);
926   map.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy);
927   map.Insert(Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION, mOrientationCorrection);
928
929   map.Insert(Toolkit::DevelImageVisual::Property::FAST_TRACK_UPLOADING, mUseFastTrackUploading);
930 }
931
932 void ImageVisual::DoCreateInstancePropertyMap(Property::Map& map) const
933 {
934   map.Clear();
935   map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
936   if(mImageUrl.IsValid())
937   {
938     map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
939     map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
940   }
941 }
942
943 void ImageVisual::OnDoAction(const Dali::Property::Index actionId, const Dali::Property::Value& attributes)
944 {
945   // Check if action is valid for this visual type and perform action if possible
946
947   switch(actionId)
948   {
949     case DevelImageVisual::Action::RELOAD:
950     {
951       auto attemptAtlasing = AttemptAtlasing();
952       LoadTexture(attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection, TextureManager::ReloadPolicy::FORCED);
953       break;
954     }
955   }
956 }
957
958 void ImageVisual::OnSetTransform()
959 {
960   if(mImpl->mRenderer)
961   {
962     mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
963   }
964 }
965
966 void ImageVisual::UpdateShader()
967 {
968   if(mImpl->mRenderer)
969   {
970     Shader shader = GenerateShader();
971     mImpl->mRenderer.SetShader(shader);
972   }
973 }
974
975 // From existing atlas manager
976 void ImageVisual::UploadCompleted()
977 {
978   // Texture has been uploaded. If weak handle is holding a placement actor,
979   // it is the time to add the renderer to actor.
980   Actor actor = mPlacementActor.GetHandle();
981   if(actor)
982   {
983     mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, mAtlasRect);
984     actor.AddRenderer(mImpl->mRenderer);
985     mRendererAdded = true;
986     // reset the weak handle so that the renderer only get added to actor once
987     mPlacementActor.Reset();
988   }
989
990   // Image loaded
991   ResourceReady(Toolkit::Visual::ResourceStatus::READY);
992   mLoadState = TextureManager::LoadState::LOAD_FINISHED;
993 }
994
995 // From FastTrackLoadingTask
996 void ImageVisual::FastLoadComplete(FastTrackLoadingTaskPtr task)
997 {
998   Toolkit::Visual::ResourceStatus resourceStatus;
999
1000   DALI_ASSERT_ALWAYS(mFastTrackLoadingTask == task && "Task was not canceled successfully!");
1001   DALI_ASSERT_ALWAYS(mRendererAdded && "Some FastTrack logic missed!");
1002
1003   Actor actor = mPlacementActor.GetHandle();
1004
1005   if(mFastTrackLoadingTask && mFastTrackLoadingTask->mLoadSuccess)
1006   {
1007     resourceStatus = Toolkit::Visual::ResourceStatus::READY;
1008     mLoadState     = TextureManager::LoadState::LOAD_FINISHED;
1009
1010     // Change premultiplied alpha flag after change renderer.
1011     EnablePreMultipliedAlpha(mFastTrackLoadingTask->mPremultiplied);
1012   }
1013   else
1014   {
1015     resourceStatus    = Toolkit::Visual::ResourceStatus::FAILED;
1016     mLoadState        = TextureManager::LoadState::LOAD_FAILED;
1017
1018     // Change renderer as broken.
1019     ShowBrokenImage();
1020   }
1021
1022   mFastTrackLoadingTask.Reset();
1023
1024   // Signal to observers ( control ) that resources are ready. Must be all resources.
1025   ResourceReady(resourceStatus);
1026 }
1027
1028 // From Texture Manager
1029 void ImageVisual::LoadComplete(bool loadingSuccess, TextureInformation textureInformation)
1030 {
1031   Toolkit::Visual::ResourceStatus resourceStatus;
1032   if(mImpl->mRenderer)
1033   {
1034     if(textureInformation.useAtlasing)
1035     {
1036       mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, mAtlasRect);
1037     }
1038
1039     EnablePreMultipliedAlpha(textureInformation.preMultiplied);
1040
1041     Actor actor = mPlacementActor.GetHandle();
1042     if(!loadingSuccess)
1043     {
1044       ShowBrokenImage();
1045       textureInformation.textureSet = mImpl->mRenderer.GetTextures();
1046     }
1047     else
1048     {
1049       if(!textureInformation.useAtlasing)
1050       {
1051         Sampler sampler = Sampler::New();
1052         sampler.SetWrapMode(mWrapModeU, mWrapModeV);
1053         textureInformation.textureSet.SetSampler(0u, sampler);
1054       }
1055
1056       mImpl->mRenderer.SetTextures(textureInformation.textureSet);
1057       ComputeTextureSize();
1058       CheckMaskTexture();
1059
1060       if(textureInformation.textureSet.GetTextureCount() == 3)
1061       {
1062         if(textureInformation.textureSet.GetTexture(0).GetPixelFormat() == Pixel::L8 && textureInformation.textureSet.GetTexture(1).GetPixelFormat() == Pixel::CHROMINANCE_U && textureInformation.textureSet.GetTexture(2).GetPixelFormat() == Pixel::CHROMINANCE_V)
1063         {
1064           mNeedYuvToRgb = true;
1065           UpdateShader();
1066         }
1067       }
1068
1069       if(actor)
1070       {
1071         actor.AddRenderer(mImpl->mRenderer);
1072         mRendererAdded = true;
1073         // reset the weak handle so that the renderer only get added to actor once
1074         mPlacementActor.Reset();
1075       }
1076     }
1077   }
1078
1079   // Storing TextureSet needed when renderer staged.
1080   if(!mImpl->mRenderer)
1081   {
1082     mTextures = textureInformation.textureSet;
1083   }
1084
1085   // Image loaded, set status regardless of staged status.
1086   if(loadingSuccess)
1087   {
1088     resourceStatus = Toolkit::Visual::ResourceStatus::READY;
1089     mLoadState     = TextureManager::LoadState::LOAD_FINISHED;
1090   }
1091   else
1092   {
1093     resourceStatus = Toolkit::Visual::ResourceStatus::FAILED;
1094     mLoadState     = TextureManager::LoadState::LOAD_FAILED;
1095   }
1096
1097   // use geometry if needed
1098   if(loadingSuccess)
1099   {
1100     uint32_t firstElementCount{0u};
1101     uint32_t secondElementCount{0u};
1102     auto     geometry = mFactoryCache.GetTextureManager().GetRenderGeometry(mTextureId, firstElementCount, secondElementCount);
1103     if(mImpl->mRenderer && geometry)
1104     {
1105       mImpl->mRenderer.SetGeometry(geometry);
1106       Dali::DevelRenderer::DrawCommand drawCommand{};
1107       drawCommand.drawType = DevelRenderer::DrawType::INDEXED;
1108
1109       if(firstElementCount)
1110       {
1111         drawCommand.firstIndex   = 0;
1112         drawCommand.elementCount = firstElementCount;
1113         drawCommand.queue        = DevelRenderer::RENDER_QUEUE_OPAQUE;
1114         DevelRenderer::AddDrawCommand(mImpl->mRenderer, drawCommand);
1115       }
1116
1117       if(secondElementCount)
1118       {
1119         drawCommand.firstIndex   = firstElementCount;
1120         drawCommand.elementCount = secondElementCount;
1121         drawCommand.queue        = DevelRenderer::RENDER_QUEUE_TRANSPARENT;
1122         DevelRenderer::AddDrawCommand(mImpl->mRenderer, drawCommand);
1123       }
1124     }
1125   }
1126
1127   // Signal to observers ( control ) that resources are ready. Must be all resources.
1128   ResourceReady(resourceStatus);
1129 }
1130
1131 void ImageVisual::RemoveTexture()
1132 {
1133   if(mTextureId != TextureManager::INVALID_TEXTURE_ID)
1134   {
1135     mFactoryCache.GetTextureManager().RequestRemove(mTextureId, this);
1136     mTextureId = TextureManager::INVALID_TEXTURE_ID;
1137   }
1138   else
1139   {
1140     ResetFastTrackLoadingTask();
1141
1142     Vector4         atlasRect(0.f, 0.f, 1.f, 1.f);
1143     Property::Index index = mImpl->mRenderer.GetPropertyIndex(ATLAS_RECT_UNIFORM_NAME);
1144     if(index != Property::INVALID_INDEX)
1145     {
1146       Property::Value atlasRectValue = mImpl->mRenderer.GetProperty(index);
1147       atlasRectValue.Get(atlasRect);
1148     }
1149
1150     TextureSet textureSet = mImpl->mRenderer.GetTextures();
1151
1152     if(index != Property::INVALID_INDEX)
1153     {
1154       mFactoryCache.GetAtlasManager()->Remove(textureSet, atlasRect);
1155     }
1156   }
1157 }
1158
1159 void ImageVisual::ComputeTextureSize()
1160 {
1161   if(mImpl->mRenderer)
1162   {
1163     auto textureSet = mImpl->mRenderer.GetTextures();
1164     if(textureSet && textureSet.GetTextureCount())
1165     {
1166       auto texture = textureSet.GetTexture(0);
1167       if(texture)
1168       {
1169         mTextureSize.x = texture.GetWidth();
1170         mTextureSize.y = texture.GetHeight();
1171         if(textureSet.GetTextureCount() > 1u && mMaskingData && !mMaskingData->mPreappliedMasking && mMaskingData->mCropToMask)
1172         {
1173           Texture maskTexture = textureSet.GetTexture(1);
1174           if(maskTexture)
1175           {
1176             mTextureSize.x = std::min(static_cast<uint32_t>(mTextureSize.x * mMaskingData->mContentScaleFactor), maskTexture.GetWidth());
1177             mTextureSize.y = std::min(static_cast<uint32_t>(mTextureSize.y * mMaskingData->mContentScaleFactor), maskTexture.GetHeight());
1178           }
1179         }
1180       }
1181     }
1182   }
1183 }
1184
1185 Vector2 ImageVisual::ComputeMaskTextureRatio()
1186 {
1187   Vector2 maskTextureRatio;
1188   if(mImpl->mRenderer)
1189   {
1190     auto textureSet = mImpl->mRenderer.GetTextures();
1191     if(textureSet && textureSet.GetTextureCount())
1192     {
1193       auto texture = textureSet.GetTexture(0);
1194       if(texture)
1195       {
1196         if(textureSet.GetTextureCount() > 1u && mMaskingData && !mMaskingData->mPreappliedMasking && mMaskingData->mCropToMask)
1197         {
1198           Texture maskTexture = textureSet.GetTexture(1);
1199           if(maskTexture)
1200           {
1201             float textureWidth  = std::max(static_cast<float>(texture.GetWidth() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1);
1202             float textureHeight = std::max(static_cast<float>(texture.GetHeight() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1);
1203             maskTextureRatio    = Vector2(std::min(static_cast<float>(maskTexture.GetWidth()), textureWidth) / textureWidth,
1204                                        std::min(static_cast<float>(maskTexture.GetHeight()), textureHeight) / textureHeight);
1205           }
1206         }
1207       }
1208     }
1209   }
1210   return maskTextureRatio;
1211 }
1212
1213 Shader ImageVisual::GenerateShader() const
1214 {
1215   Shader shader;
1216
1217   bool       usesWholeTexture  = true;
1218   const bool useStandardShader = !mImpl->mCustomShader;
1219   const bool useNativeImage    = (mTextures && DevelTexture::IsNative(mTextures.GetTexture(0)));
1220
1221   if(useStandardShader)
1222   {
1223     bool requiredAlphaMaskingOnRendering = (mMaskingData && !mMaskingData->mMaskImageLoadingFailed) ? !mMaskingData->mPreappliedMasking : false;
1224     // Create and cache the standard shader
1225     shader = mImageVisualShaderFactory.GetShader(
1226       mFactoryCache,
1227       ImageVisualShaderFeature::FeatureBuilder()
1228         .EnableTextureAtlas(mImpl->mFlags & Visual::Base::Impl::IS_ATLASING_APPLIED && !useNativeImage)
1229         .ApplyDefaultTextureWrapMode(mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE)
1230         .EnableRoundedCorner(IsRoundedCornerRequired())
1231         .EnableBorderline(IsBorderlineRequired())
1232         .SetTextureForFragmentShaderCheck(useNativeImage ? mTextures.GetTexture(0) : Dali::Texture())
1233         .EnableAlphaMaskingOnRendering(requiredAlphaMaskingOnRendering)
1234         .EnableYuvToRgb(mNeedYuvToRgb));
1235   }
1236   else
1237   {
1238     std::string_view vertexShaderView;
1239     std::string_view fragmentShaderView;
1240
1241     if(mImpl->mCustomShader && !mImpl->mCustomShader->mVertexShader.empty())
1242     {
1243       vertexShaderView = mImpl->mCustomShader->mVertexShader;
1244       usesWholeTexture = false; // Impossible to tell.
1245     }
1246     else
1247     {
1248       vertexShaderView = mImageVisualShaderFactory.GetVertexShaderSource();
1249     }
1250
1251     if(mImpl->mCustomShader && !mImpl->mCustomShader->mFragmentShader.empty())
1252     {
1253       fragmentShaderView = mImpl->mCustomShader->mFragmentShader;
1254     }
1255     else
1256     {
1257       fragmentShaderView = mImageVisualShaderFactory.GetFragmentShaderSource();
1258     }
1259
1260     // If the texture is native, we may need to change prefix and sampler in
1261     // the fragment shader
1262     if(useNativeImage)
1263     {
1264       bool        modifiedFragmentShader = false;
1265       Texture     nativeTexture          = mTextures.GetTexture(0);
1266       std::string fragmentShaderString   = std::string(fragmentShaderView);
1267
1268       modifiedFragmentShader = DevelTexture::ApplyNativeFragmentShader(nativeTexture, fragmentShaderString);
1269       if(modifiedFragmentShader)
1270       {
1271         fragmentShaderView = fragmentShaderString;
1272       }
1273
1274       // Create shader here cause fragmentShaderString scope issue
1275       shader = Shader::New(vertexShaderView, fragmentShaderView, mImpl->mCustomShader->mHints);
1276     }
1277     else
1278     {
1279       shader = Shader::New(vertexShaderView, fragmentShaderView, mImpl->mCustomShader->mHints);
1280     }
1281   }
1282
1283   if(usesWholeTexture)
1284   {
1285     shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
1286   }
1287
1288   return shader;
1289 }
1290
1291 void ImageVisual::CheckMaskTexture()
1292 {
1293   if(mMaskingData && !mMaskingData->mPreappliedMasking)
1294   {
1295     bool       maskLoadFailed = true;
1296     TextureSet textures       = mImpl->mRenderer.GetTextures();
1297     if(textures && textures.GetTextureCount() >= TEXTURE_COUNT_FOR_GPU_ALPHA_MASK)
1298     {
1299       if(mMaskingData->mCropToMask)
1300       {
1301         mImpl->mRenderer.RegisterProperty(MASK_TEXTURE_RATIO_NAME, ComputeMaskTextureRatio());
1302       }
1303       maskLoadFailed = false;
1304     }
1305
1306     if(mMaskingData->mMaskImageLoadingFailed != maskLoadFailed)
1307     {
1308       mMaskingData->mMaskImageLoadingFailed = maskLoadFailed;
1309       UpdateShader();
1310     }
1311   }
1312 }
1313
1314 void ImageVisual::ResetRenderer()
1315 {
1316   RemoveTexture(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas
1317   mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING;
1318
1319   TextureSet textureSet = TextureSet::New();
1320   mImpl->mRenderer.SetTextures(textureSet);
1321   ComputeTextureSize();
1322
1323   mLoadState = TextureManager::LoadState::NOT_STARTED;
1324 }
1325
1326 void ImageVisual::ShowBrokenImage()
1327 {
1328   if(mEnableBrokenImage)
1329   {
1330     Actor actor = mPlacementActor.GetHandle();
1331
1332     Vector2 imageSize = Vector2::ZERO;
1333     if(actor)
1334     {
1335       imageSize           = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
1336       mPlacementActorSize = imageSize;
1337
1338       if(mRendererAdded)
1339       {
1340         actor.RemoveRenderer(mImpl->mRenderer);
1341         mRendererAdded = false;
1342       }
1343     }
1344
1345     mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
1346     if(actor)
1347     {
1348       actor.AddRenderer(mImpl->mRenderer);
1349       mRendererAdded = true;
1350       mPlacementActor.Reset();
1351     }
1352   }
1353   else
1354   {
1355     if(mRendererAdded)
1356     {
1357       Actor actor = mPlacementActor.GetHandle();
1358       if(actor)
1359       {
1360         actor.RemoveRenderer(mImpl->mRenderer);
1361         mRendererAdded = false;
1362       }
1363     }
1364     ResetRenderer();
1365   }
1366 }
1367
1368 void ImageVisual::ResetFastTrackLoadingTask()
1369 {
1370   if(mFastTrackLoadingTask)
1371   {
1372     Dali::AsyncTaskManager::Get().RemoveTask(mFastTrackLoadingTask);
1373     mFastTrackLoadingTask.Reset();
1374   }
1375 }
1376
1377 } // namespace Internal
1378
1379 } // namespace Toolkit
1380
1381 } // namespace Dali