[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 && (mWrapModeU != Dali::WrapMode::DEFAULT || mWrapModeV != Dali::WrapMode::DEFAULT))
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) &&
748          mTextures &&
749          (mWrapModeU != Dali::WrapMode::DEFAULT || mWrapModeV != Dali::WrapMode::DEFAULT))
750       {
751         Sampler sampler = Sampler::New();
752         sampler.SetWrapMode(mWrapModeU, mWrapModeV);
753         mTextures.SetSampler(0u, sampler);
754       }
755     }
756   }
757
758   if(mTextures)
759   {
760     mImpl->mRenderer.SetTextures(mTextures);
761     ComputeTextureSize();
762     CheckMaskTexture();
763
764     bool needToUpdateShader = DevelTexture::IsNative(mTextures.GetTexture(0)) || mUseBrokenImageRenderer;
765
766     if(mTextures.GetTextureCount() == 3)
767     {
768       if(mTextures.GetTexture(0).GetPixelFormat() == Pixel::L8 && mTextures.GetTexture(1).GetPixelFormat() == Pixel::CHROMINANCE_U && mTextures.GetTexture(2).GetPixelFormat() == Pixel::CHROMINANCE_V)
769       {
770         mNeedYuvToRgb      = true;
771         needToUpdateShader = true;
772       }
773     }
774
775     if(needToUpdateShader)
776     {
777       UpdateShader();
778     }
779     mTextures.Reset(); // Visual should not keep a handle to the texture after this point.
780
781     if(DALI_UNLIKELY(mUseBrokenImageRenderer))
782     {
783       // We need to re-generate geometry only if it was broken image before, and result changed after Reload.
784       auto geometry = GenerateGeometry(mTextureId, true);
785
786       // Update geometry only if we need.
787       if(geometry)
788       {
789         mImpl->mRenderer.SetGeometry(geometry);
790       }
791     }
792
793     // We don't use broken image anymore.
794     mUseBrokenImageRenderer = false;
795   }
796
797   if(attemptAtlasing) // the texture is packed inside atlas
798   {
799     mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, mAtlasRect);
800
801     bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
802
803     if(!defaultWrapMode) // custom wrap mode
804     {
805       Vector2 wrapMode(mWrapModeU - WrapMode::CLAMP_TO_EDGE, mWrapModeV - WrapMode::CLAMP_TO_EDGE);
806       wrapMode.Clamp(Vector2::ZERO, Vector2(2.f, 2.f));
807       mImpl->mRenderer.RegisterProperty(WRAP_MODE_UNIFORM_NAME, wrapMode);
808     }
809   }
810 }
811
812 void ImageVisual::DoSetOnScene(Actor& actor)
813 {
814   if(mImageUrl.IsValid())
815   {
816     InitializeRenderer();
817   }
818
819   if(!mImpl->mRenderer)
820   {
821     return;
822   }
823
824   mPlacementActor = actor;
825
826   if(mPixelArea != FULL_TEXTURE_RECT)
827   {
828     mPixelAreaIndex = mImpl->mRenderer.RegisterProperty(mPixelAreaIndex, PIXEL_AREA_UNIFORM_NAME, mPixelArea);
829   }
830
831   if(mLoadState == TextureManager::LoadState::LOAD_FINISHED)
832   {
833     actor.AddRenderer(mImpl->mRenderer);
834     mRendererAdded = true;
835     mPlacementActor.Reset();
836
837     // Image loaded and ready to display
838     ResourceReady(Toolkit::Visual::ResourceStatus::READY);
839   }
840   else if(mLoadState == TextureManager::LoadState::LOAD_FAILED)
841   {
842     ShowBrokenImage();
843     ResourceReady(Toolkit::Visual::ResourceStatus::FAILED);
844   }
845   else
846   {
847     if(mFastTrackLoadingTask)
848     {
849       actor.AddRenderer(mImpl->mRenderer);
850       mRendererAdded = true;
851     }
852   }
853 }
854
855 void ImageVisual::DoSetOffScene(Actor& actor)
856 {
857   // Visual::Base::SetOffScene only calls DoSetOffScene if mRenderer exists (is on onstage)
858
859   // Image release is dependent on the ReleasePolicy, renderer is removed.
860   actor.RemoveRenderer(mImpl->mRenderer);
861   mRendererAdded = false;
862
863   if(mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED)
864   {
865     ResetRenderer();
866   }
867
868   mPlacementActor.Reset();
869 }
870
871 void ImageVisual::DoCreatePropertyMap(Property::Map& map) const
872 {
873   map.Clear();
874   map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
875
876   bool sync = IsSynchronousLoadingRequired();
877   map.Insert(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, sync);
878   if(mImageUrl.IsValid())
879   {
880     map.Insert(Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl());
881     map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
882     map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
883   }
884
885   map.Insert(Toolkit::ImageVisual::Property::FITTING_MODE, mFittingMode);
886   map.Insert(Toolkit::ImageVisual::Property::SAMPLING_MODE, mSamplingMode);
887
888   if(mImpl->mRenderer && mPixelAreaIndex != Property::INVALID_INDEX)
889   {
890     // Update values from Renderer
891     Vector4 pixelArea = mImpl->mRenderer.GetProperty<Vector4>(mPixelAreaIndex);
892     map.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, pixelArea);
893   }
894   else
895   {
896     map.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, mPixelArea);
897   }
898
899   map.Insert(Toolkit::ImageVisual::Property::WRAP_MODE_U, mWrapModeU);
900   map.Insert(Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV);
901
902   map.Insert(Toolkit::ImageVisual::Property::ATLASING, mAttemptAtlasing);
903
904   if(mMaskingData != NULL)
905   {
906     map.Insert(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mMaskingData->mAlphaMaskUrl.GetUrl());
907     map.Insert(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskingData->mContentScaleFactor);
908     map.Insert(Toolkit::ImageVisual::Property::CROP_TO_MASK, mMaskingData->mCropToMask);
909     map.Insert(Toolkit::DevelImageVisual::Property::MASKING_TYPE, mMaskingData->mPreappliedMasking ? DevelImageVisual::MaskingType::MASKING_ON_LOADING : DevelImageVisual::MaskingType::MASKING_ON_RENDERING);
910   }
911
912   map.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, mLoadPolicy);
913   map.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy);
914   map.Insert(Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION, mOrientationCorrection);
915
916   map.Insert(Toolkit::DevelImageVisual::Property::FAST_TRACK_UPLOADING, mUseFastTrackUploading);
917 }
918
919 void ImageVisual::DoCreateInstancePropertyMap(Property::Map& map) const
920 {
921   map.Clear();
922   map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
923   if(mImageUrl.IsValid())
924   {
925     map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
926     map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
927   }
928 }
929
930 void ImageVisual::OnDoAction(const Dali::Property::Index actionId, const Dali::Property::Value& attributes)
931 {
932   // Check if action is valid for this visual type and perform action if possible
933
934   switch(actionId)
935   {
936     case DevelImageVisual::Action::RELOAD:
937     {
938       auto attemptAtlasing = AttemptAtlasing();
939
940       // Reset resource ready status when we call reload.
941       ResourceReady(Toolkit::Visual::ResourceStatus::PREPARING);
942       mLoadState = TextureManager::LoadState::NOT_STARTED;
943
944       LoadTexture(attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection, TextureManager::ReloadPolicy::FORCED);
945       break;
946     }
947   }
948 }
949
950 void ImageVisual::OnSetTransform()
951 {
952   if(mImpl->mRenderer)
953   {
954     mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
955   }
956 }
957
958 void ImageVisual::UpdateShader()
959 {
960   if(mImpl->mRenderer)
961   {
962     Shader shader = GenerateShader();
963     mImpl->mRenderer.SetShader(shader);
964   }
965 }
966
967 // From existing atlas manager
968 void ImageVisual::UploadCompleted()
969 {
970   // Texture has been uploaded. If weak handle is holding a placement actor,
971   // it is the time to add the renderer to actor.
972   Actor actor = mPlacementActor.GetHandle();
973   if(actor)
974   {
975     mImpl->mRenderer.RegisterProperty(ATLAS_RECT_UNIFORM_NAME, mAtlasRect);
976     actor.AddRenderer(mImpl->mRenderer);
977     mRendererAdded = true;
978     // reset the weak handle so that the renderer only get added to actor once
979     mPlacementActor.Reset();
980   }
981
982   // Image loaded
983   ResourceReady(Toolkit::Visual::ResourceStatus::READY);
984   mLoadState = TextureManager::LoadState::LOAD_FINISHED;
985 }
986
987 // From FastTrackLoadingTask
988 void ImageVisual::FastLoadComplete(FastTrackLoadingTaskPtr task)
989 {
990   Toolkit::Visual::ResourceStatus resourceStatus;
991
992   DALI_ASSERT_ALWAYS(mFastTrackLoadingTask == task && "Task was not canceled successfully!");
993   DALI_ASSERT_ALWAYS(mRendererAdded && "Some FastTrack logic missed!");
994
995   Actor actor = mPlacementActor.GetHandle();
996
997   if(mFastTrackLoadingTask && mFastTrackLoadingTask->mLoadSuccess)
998   {
999     resourceStatus = Toolkit::Visual::ResourceStatus::READY;
1000     mLoadState     = TextureManager::LoadState::LOAD_FINISHED;
1001
1002     // Change premultiplied alpha flag after change renderer.
1003     EnablePreMultipliedAlpha(mFastTrackLoadingTask->mPremultiplied);
1004
1005     if(mFastTrackLoadingTask->mLoadPlanesAvaliable)
1006     {
1007       if(mFastTrackLoadingTask->mPlanesLoaded)
1008       {
1009         // Let we use regular yuv cases.
1010         mNeedYuvToRgb = true;
1011       }
1012       else
1013       {
1014         // Let we use regular image cases.
1015         mNeedYuvToRgb = false;
1016
1017         auto textureSet = mImpl->mRenderer.GetTextures();
1018         DALI_ASSERT_ALWAYS(textureSet && textureSet.GetTextureCount() > 0u && "Previous texture set must exist!");
1019
1020         Dali::TextureSet newTextureSet = TextureSet::New();
1021         newTextureSet.SetTexture(0u, textureSet.GetTexture(0u));
1022         mImpl->mRenderer.SetTextures(newTextureSet);
1023       }
1024
1025       // We can specify what kind of shader we need to use now. Update shader.
1026       mNeedUnifiedYuvAndRgb = false;
1027       UpdateShader();
1028     }
1029   }
1030   else
1031   {
1032     resourceStatus = Toolkit::Visual::ResourceStatus::FAILED;
1033     mLoadState     = TextureManager::LoadState::LOAD_FAILED;
1034
1035     // Change renderer as broken.
1036     ShowBrokenImage();
1037   }
1038
1039   mFastTrackLoadingTask.Reset();
1040
1041   // Signal to observers ( control ) that resources are ready. Must be all resources.
1042   ResourceReady(resourceStatus);
1043 }
1044
1045 // From Texture Manager
1046 void ImageVisual::LoadComplete(bool loadingSuccess, TextureInformation textureInformation)
1047 {
1048   Toolkit::Visual::ResourceStatus resourceStatus;
1049
1050   if(mImpl->mRenderer)
1051   {
1052     EnablePreMultipliedAlpha(textureInformation.preMultiplied);
1053
1054     Actor actor = mPlacementActor.GetHandle();
1055     if(!loadingSuccess)
1056     {
1057       ShowBrokenImage();
1058       textureInformation.textureSet = mImpl->mRenderer.GetTextures();
1059     }
1060     else
1061     {
1062       if(mWrapModeU != Dali::WrapMode::DEFAULT || mWrapModeV != Dali::WrapMode::DEFAULT)
1063       {
1064         Sampler sampler = Sampler::New();
1065         sampler.SetWrapMode(mWrapModeU, mWrapModeV);
1066         textureInformation.textureSet.SetSampler(0u, sampler);
1067       }
1068
1069       mImpl->mRenderer.SetTextures(textureInformation.textureSet);
1070       ComputeTextureSize();
1071       CheckMaskTexture();
1072
1073       bool needToUpdateShader = mUseBrokenImageRenderer;
1074
1075       if(textureInformation.textureSet.GetTextureCount() == 3)
1076       {
1077         if(textureInformation.textureSet.GetTexture(0).GetPixelFormat() == Pixel::L8 && textureInformation.textureSet.GetTexture(1).GetPixelFormat() == Pixel::CHROMINANCE_U && textureInformation.textureSet.GetTexture(2).GetPixelFormat() == Pixel::CHROMINANCE_V)
1078         {
1079           mNeedYuvToRgb      = true;
1080           needToUpdateShader = true;
1081         }
1082       }
1083
1084       if(needToUpdateShader)
1085       {
1086         UpdateShader();
1087       }
1088
1089       if(actor)
1090       {
1091         actor.AddRenderer(mImpl->mRenderer);
1092         mRendererAdded = true;
1093         // reset the weak handle so that the renderer only get added to actor once
1094         mPlacementActor.Reset();
1095       }
1096
1097       auto geometry = GenerateGeometry(textureInformation.textureId, mUseBrokenImageRenderer);
1098
1099       if(DALI_UNLIKELY(geometry))
1100       {
1101         // Rare cases. If load successed image don't use quad geometry (i.e. Show some n-patch broken image, and call Reload(), and success)
1102         // or If given texture use AddOn,
1103         // then we need to make to use quad geometry and update shader agian.
1104         mImpl->mRenderer.SetGeometry(geometry);
1105       }
1106
1107       // We don't use broken image anymore.
1108       mUseBrokenImageRenderer = false;
1109     }
1110   }
1111
1112   // Storing TextureSet needed when renderer staged.
1113   if(!mImpl->mRenderer)
1114   {
1115     mTextures = textureInformation.textureSet;
1116   }
1117
1118   // Image loaded, set status regardless of staged status.
1119   if(loadingSuccess)
1120   {
1121     resourceStatus = Toolkit::Visual::ResourceStatus::READY;
1122     mLoadState     = TextureManager::LoadState::LOAD_FINISHED;
1123   }
1124   else
1125   {
1126     resourceStatus = Toolkit::Visual::ResourceStatus::FAILED;
1127     mLoadState     = TextureManager::LoadState::LOAD_FAILED;
1128   }
1129
1130   // Signal to observers ( control ) that resources are ready. Must be all resources.
1131   ResourceReady(resourceStatus);
1132 }
1133
1134 void ImageVisual::RemoveTexture()
1135 {
1136   if(mTextureId != TextureManager::INVALID_TEXTURE_ID)
1137   {
1138     mFactoryCache.GetTextureManager().RequestRemove(mTextureId, this);
1139     mTextureId = TextureManager::INVALID_TEXTURE_ID;
1140   }
1141   else
1142   {
1143     ResetFastTrackLoadingTask();
1144
1145     Vector4         atlasRect(0.f, 0.f, 1.f, 1.f);
1146     Property::Index index = mImpl->mRenderer.GetPropertyIndex(ATLAS_RECT_UNIFORM_NAME);
1147     if(index != Property::INVALID_INDEX)
1148     {
1149       Property::Value atlasRectValue = mImpl->mRenderer.GetProperty(index);
1150       atlasRectValue.Get(atlasRect);
1151     }
1152
1153     TextureSet textureSet = mImpl->mRenderer.GetTextures();
1154
1155     if(index != Property::INVALID_INDEX)
1156     {
1157       mFactoryCache.GetAtlasManager()->Remove(textureSet, atlasRect);
1158     }
1159   }
1160 }
1161
1162 void ImageVisual::ComputeTextureSize()
1163 {
1164   if(mImpl->mRenderer)
1165   {
1166     auto textureSet = mImpl->mRenderer.GetTextures();
1167     if(textureSet && textureSet.GetTextureCount())
1168     {
1169       auto texture = textureSet.GetTexture(0);
1170       if(texture)
1171       {
1172         mTextureSize.x = texture.GetWidth();
1173         mTextureSize.y = texture.GetHeight();
1174         if(textureSet.GetTextureCount() > 1u && mMaskingData && !mMaskingData->mPreappliedMasking && mMaskingData->mCropToMask)
1175         {
1176           Texture maskTexture = textureSet.GetTexture(1);
1177           if(maskTexture)
1178           {
1179             mTextureSize.x = std::min(static_cast<uint32_t>(mTextureSize.x * mMaskingData->mContentScaleFactor), maskTexture.GetWidth());
1180             mTextureSize.y = std::min(static_cast<uint32_t>(mTextureSize.y * mMaskingData->mContentScaleFactor), maskTexture.GetHeight());
1181           }
1182         }
1183       }
1184     }
1185   }
1186 }
1187
1188 Vector2 ImageVisual::ComputeMaskTextureRatio()
1189 {
1190   Vector2 maskTextureRatio;
1191   if(mImpl->mRenderer)
1192   {
1193     auto textureSet = mImpl->mRenderer.GetTextures();
1194     if(textureSet && textureSet.GetTextureCount())
1195     {
1196       auto texture = textureSet.GetTexture(0);
1197       if(texture)
1198       {
1199         if(textureSet.GetTextureCount() > 1u && mMaskingData && !mMaskingData->mPreappliedMasking && mMaskingData->mCropToMask)
1200         {
1201           Texture maskTexture = textureSet.GetTexture(1);
1202           if(maskTexture)
1203           {
1204             float textureWidth  = std::max(static_cast<float>(texture.GetWidth() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1);
1205             float textureHeight = std::max(static_cast<float>(texture.GetHeight() * mMaskingData->mContentScaleFactor), Dali::Math::MACHINE_EPSILON_1);
1206             maskTextureRatio    = Vector2(std::min(static_cast<float>(maskTexture.GetWidth()), textureWidth) / textureWidth,
1207                                        std::min(static_cast<float>(maskTexture.GetHeight()), textureHeight) / textureHeight);
1208           }
1209         }
1210       }
1211     }
1212   }
1213   return maskTextureRatio;
1214 }
1215
1216 Shader ImageVisual::GenerateShader() const
1217 {
1218   Shader shader;
1219
1220   const bool useStandardShader = !mImpl->mCustomShader;
1221   const bool useNativeImage    = (mTextures && DevelTexture::IsNative(mTextures.GetTexture(0)));
1222
1223   if(useStandardShader)
1224   {
1225     bool requiredAlphaMaskingOnRendering = (mMaskingData && !mMaskingData->mMaskImageLoadingFailed) ? !mMaskingData->mPreappliedMasking : false;
1226     // Create and cache the standard shader
1227     shader = mImageVisualShaderFactory.GetShader(
1228       mFactoryCache,
1229       ImageVisualShaderFeatureBuilder()
1230         .EnableTextureAtlas(mImpl->mFlags & Visual::Base::Impl::IS_ATLASING_APPLIED && !useNativeImage)
1231         .ApplyDefaultTextureWrapMode(mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE)
1232         .EnableRoundedCorner(IsRoundedCornerRequired())
1233         .EnableBorderline(IsBorderlineRequired())
1234         .SetTextureForFragmentShaderCheck(useNativeImage ? mTextures.GetTexture(0) : Dali::Texture())
1235         .EnableAlphaMaskingOnRendering(requiredAlphaMaskingOnRendering)
1236         .EnableYuvToRgb(mNeedYuvToRgb, mNeedUnifiedYuvAndRgb));
1237   }
1238   else
1239   {
1240     bool             usesWholeTexture = true;
1241     std::string_view vertexShaderView;
1242     std::string_view fragmentShaderView;
1243
1244     if(mImpl->mCustomShader && !mImpl->mCustomShader->mVertexShader.empty())
1245     {
1246       vertexShaderView = mImpl->mCustomShader->mVertexShader;
1247       usesWholeTexture = false; // Impossible to tell.
1248     }
1249     else
1250     {
1251       vertexShaderView = mImageVisualShaderFactory.GetVertexShaderSource();
1252     }
1253
1254     if(mImpl->mCustomShader && !mImpl->mCustomShader->mFragmentShader.empty())
1255     {
1256       fragmentShaderView = mImpl->mCustomShader->mFragmentShader;
1257     }
1258     else
1259     {
1260       fragmentShaderView = mImageVisualShaderFactory.GetFragmentShaderSource();
1261     }
1262
1263     // If the texture is native, we may need to change prefix and sampler in
1264     // the fragment shader
1265     if(useNativeImage)
1266     {
1267       bool        modifiedFragmentShader = false;
1268       Texture     nativeTexture          = mTextures.GetTexture(0);
1269       std::string fragmentShaderString   = std::string(fragmentShaderView);
1270
1271       modifiedFragmentShader = DevelTexture::ApplyNativeFragmentShader(nativeTexture, fragmentShaderString);
1272       if(modifiedFragmentShader)
1273       {
1274         fragmentShaderView = fragmentShaderString;
1275       }
1276
1277       // Create shader here cause fragmentShaderString scope issue
1278       shader = Shader::New(vertexShaderView, fragmentShaderView, mImpl->mCustomShader->mHints);
1279     }
1280     else
1281     {
1282       shader = Shader::New(vertexShaderView, fragmentShaderView, mImpl->mCustomShader->mHints);
1283     }
1284
1285     if(usesWholeTexture)
1286     {
1287       shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
1288     }
1289   }
1290
1291   return shader;
1292 }
1293
1294 Dali::Property ImageVisual::OnGetPropertyObject(Dali::Property::Key key)
1295 {
1296   if((key.type == Property::Key::INDEX && key.indexKey == Toolkit::ImageVisual::Property::PIXEL_AREA) || (key.type == Property::Key::STRING && key.stringKey == PIXEL_AREA_UNIFORM_NAME))
1297   {
1298     if(DALI_LIKELY(mImpl->mRenderer))
1299     {
1300       if(mPixelAreaIndex == Property::INVALID_INDEX)
1301       {
1302         mPixelAreaIndex = mImpl->mRenderer.RegisterProperty(mPixelAreaIndex, PIXEL_AREA_UNIFORM_NAME, mPixelArea);
1303       }
1304       return Dali::Property(mImpl->mRenderer, mPixelAreaIndex);
1305     }
1306   }
1307
1308   Handle handle;
1309   return Dali::Property(handle, Property::INVALID_INDEX);
1310 }
1311
1312 void ImageVisual::CheckMaskTexture()
1313 {
1314   if(mMaskingData && !mMaskingData->mPreappliedMasking)
1315   {
1316     bool       maskLoadFailed = true;
1317     TextureSet textures       = mImpl->mRenderer.GetTextures();
1318     if(textures && textures.GetTextureCount() >= TEXTURE_COUNT_FOR_GPU_ALPHA_MASK)
1319     {
1320       if(mMaskingData->mCropToMask)
1321       {
1322         mImpl->mRenderer.RegisterProperty(MASK_TEXTURE_RATIO_NAME, ComputeMaskTextureRatio());
1323       }
1324       else
1325       {
1326         mImpl->mRenderer.RegisterProperty(MASK_TEXTURE_RATIO_NAME, Vector2::ONE);
1327       }
1328       maskLoadFailed = false;
1329     }
1330
1331     if(mMaskingData->mMaskImageLoadingFailed != maskLoadFailed)
1332     {
1333       mMaskingData->mMaskImageLoadingFailed = maskLoadFailed;
1334       UpdateShader();
1335     }
1336   }
1337 }
1338
1339 void ImageVisual::ResetRenderer()
1340 {
1341   RemoveTexture(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas
1342   mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING;
1343
1344   TextureSet textureSet = TextureSet::New();
1345   mImpl->mRenderer.SetTextures(textureSet);
1346   ComputeTextureSize();
1347
1348   mLoadState = TextureManager::LoadState::NOT_STARTED;
1349 }
1350
1351 void ImageVisual::ShowBrokenImage()
1352 {
1353   if(mEnableBrokenImage)
1354   {
1355     Actor actor = mPlacementActor.GetHandle();
1356
1357     Vector2 imageSize = Vector2::ZERO;
1358     if(actor)
1359     {
1360       imageSize           = actor.GetProperty(Actor::Property::SIZE).Get<Vector2>();
1361       mPlacementActorSize = imageSize;
1362
1363       if(mRendererAdded)
1364       {
1365         actor.RemoveRenderer(mImpl->mRenderer);
1366         mRendererAdded = false;
1367       }
1368     }
1369
1370     mUseBrokenImageRenderer = true;
1371     mFactoryCache.UpdateBrokenImageRenderer(mImpl->mRenderer, imageSize);
1372     if(actor)
1373     {
1374       actor.AddRenderer(mImpl->mRenderer);
1375       mRendererAdded = true;
1376       mPlacementActor.Reset();
1377     }
1378   }
1379   else
1380   {
1381     if(mRendererAdded)
1382     {
1383       Actor actor = mPlacementActor.GetHandle();
1384       if(actor)
1385       {
1386         actor.RemoveRenderer(mImpl->mRenderer);
1387         mRendererAdded = false;
1388       }
1389     }
1390     ResetRenderer();
1391   }
1392 }
1393
1394 void ImageVisual::ResetFastTrackLoadingTask()
1395 {
1396   if(mFastTrackLoadingTask)
1397   {
1398     Dali::AsyncTaskManager::Get().RemoveTask(mFastTrackLoadingTask);
1399     mFastTrackLoadingTask.Reset();
1400   }
1401 }
1402
1403 Geometry ImageVisual::GenerateGeometry(TextureManager::TextureId textureId, bool createForce)
1404 {
1405   Geometry geometry;
1406   if(Stage::IsInstalled())
1407   {
1408     if(mImpl->mCustomShader)
1409     {
1410       if(createForce)
1411       {
1412         geometry = CreateGeometry(mFactoryCache, mImpl->mCustomShader->mGridSize);
1413       }
1414     }
1415     else
1416     {
1417       uint32_t firstElementCount{0u};
1418       uint32_t secondElementCount{0u};
1419
1420       geometry = mFactoryCache.GetTextureManager().GetRenderGeometry(textureId, firstElementCount, secondElementCount);
1421       if(geometry)
1422       {
1423         if(mImpl->mRenderer)
1424         {
1425           Dali::DevelRenderer::DrawCommand drawCommand{};
1426           drawCommand.drawType = DevelRenderer::DrawType::INDEXED;
1427
1428           if(firstElementCount)
1429           {
1430             drawCommand.firstIndex   = 0;
1431             drawCommand.elementCount = firstElementCount;
1432             drawCommand.queue        = DevelRenderer::RENDER_QUEUE_OPAQUE;
1433             DevelRenderer::AddDrawCommand(mImpl->mRenderer, drawCommand);
1434           }
1435
1436           if(secondElementCount)
1437           {
1438             drawCommand.firstIndex   = firstElementCount;
1439             drawCommand.elementCount = secondElementCount;
1440             drawCommand.queue        = DevelRenderer::RENDER_QUEUE_TRANSPARENT;
1441             DevelRenderer::AddDrawCommand(mImpl->mRenderer, drawCommand);
1442           }
1443         }
1444       }
1445       else if(createForce)
1446       {
1447         // Create default quad geometry now
1448         geometry = CreateGeometry(mFactoryCache, ImageDimensions(1, 1));
1449       }
1450     }
1451   }
1452
1453   return geometry;
1454 }
1455
1456 } // namespace Internal
1457
1458 } // namespace Toolkit
1459
1460 } // namespace Dali