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