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