e79edd71cd60bdc854ee6d679a6141da630222b2
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / image / image-visual.cpp
1 /*
2  * Copyright (c) 2020 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 <cstring> // for strlen()
23 #include <dali/public-api/actors/layer.h>
24 #include <dali/public-api/common/stage.h>
25 #include <dali/public-api/images/resource-image.h>
26 #include <dali/public-api/images/native-image.h>
27 #include <dali/devel-api/images/texture-set-image.h>
28 #include <dali/devel-api/adaptor-framework/image-loading.h>
29 #include <dali/devel-api/scripting/enum-helper.h>
30 #include <dali/devel-api/scripting/scripting.h>
31 #include <dali/integration-api/debug.h>
32
33 // INTERNAL HEADERS
34 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
35 #include <dali-toolkit/public-api/visuals/visual-properties.h>
36 #include <dali-toolkit/devel-api/visuals/image-visual-actions-devel.h>
37 #include <dali-toolkit/internal/visuals/texture-manager-impl.h>
38 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
39 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
40 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
41 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
42 #include <dali-toolkit/internal/visuals/image-atlas-manager.h>
43 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
44 #include <dali-toolkit/internal/visuals/visual-url.h>
45 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
46
47 namespace Dali
48 {
49
50 namespace Toolkit
51 {
52
53 namespace Internal
54 {
55
56 namespace
57 {
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 const char* DEFAULT_SAMPLER_TYPENAME = "sampler2D";
103
104 const float PIXEL_ALIGN_ON = 1.0f;
105 const float PIXEL_ALIGN_OFF = 0.0f;
106
107 Geometry CreateGeometry( VisualFactoryCache& factoryCache, ImageDimensions gridSize )
108 {
109   Geometry geometry;
110
111   if( gridSize == ImageDimensions( 1, 1 ) )
112   {
113     geometry = factoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
114   }
115   else
116   {
117     geometry = VisualFactoryCache::CreateGridGeometry( gridSize );
118   }
119
120   return geometry;
121 }
122
123 } // unnamed namespace
124
125 ImageVisualPtr ImageVisual::New( VisualFactoryCache& factoryCache,
126                                  ImageVisualShaderFactory& shaderFactory,
127                                  const VisualUrl& imageUrl,
128                                  const Property::Map& properties,
129                                  ImageDimensions size,
130                                  FittingMode::Type fittingMode,
131                                  Dali::SamplingMode::Type samplingMode )
132 {
133   ImageVisualPtr imageVisualPtr( new ImageVisual( factoryCache, shaderFactory, imageUrl, size, fittingMode, samplingMode ) );
134   imageVisualPtr->SetProperties( properties );
135   return imageVisualPtr;
136 }
137
138 ImageVisualPtr ImageVisual::New( VisualFactoryCache& factoryCache,
139                                  ImageVisualShaderFactory& shaderFactory,
140                                  const VisualUrl& imageUrl,
141                                  ImageDimensions size,
142                                  FittingMode::Type fittingMode,
143                                  Dali::SamplingMode::Type samplingMode )
144 {
145   return new ImageVisual( factoryCache, shaderFactory, imageUrl, size, fittingMode, samplingMode );
146 }
147
148 ImageVisualPtr ImageVisual::New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const Image& image )
149 {
150   return new ImageVisual( factoryCache, shaderFactory, image );
151 }
152
153 ImageVisual::ImageVisual( VisualFactoryCache& factoryCache,
154                           ImageVisualShaderFactory& shaderFactory,
155                           const VisualUrl& imageUrl,
156                           ImageDimensions size,
157                           FittingMode::Type fittingMode,
158                           Dali::SamplingMode::Type samplingMode )
159 : Visual::Base( factoryCache, Visual::FittingMode::FILL ),
160   mImage(),
161   mPixelArea( FULL_TEXTURE_RECT ),
162   mPlacementActor(),
163   mImageUrl( imageUrl ),
164   mMaskingData( ),
165   mDesiredSize( size ),
166   mTextureId( TextureManager::INVALID_TEXTURE_ID ),
167   mTextures(),
168   mImageVisualShaderFactory( shaderFactory ),
169   mFittingMode( fittingMode ),
170   mSamplingMode( samplingMode ),
171   mWrapModeU( WrapMode::DEFAULT ),
172   mWrapModeV( WrapMode::DEFAULT ),
173   mLoadPolicy( Toolkit::ImageVisual::LoadPolicy::ATTACHED ),
174   mReleasePolicy( Toolkit::ImageVisual::ReleasePolicy::DETACHED ),
175   mAtlasRect( 0.0f, 0.0f, 0.0f, 0.0f ),
176   mAtlasRectSize( 0, 0 ),
177   mAttemptAtlasing( false ),
178   mLoading( false ),
179   mOrientationCorrection( true )
180 {
181   EnablePreMultipliedAlpha( mFactoryCache.GetPreMultiplyOnLoad() );
182 }
183
184 ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const Image& image )
185 : Visual::Base( factoryCache, Visual::FittingMode::FIT_KEEP_ASPECT_RATIO ),
186   mImage( image ),
187   mPixelArea( FULL_TEXTURE_RECT ),
188   mPlacementActor(),
189   mImageUrl(),
190   mMaskingData( ),
191   mDesiredSize(),
192   mTextureId( TextureManager::INVALID_TEXTURE_ID ),
193   mTextures(),
194   mImageVisualShaderFactory( shaderFactory ),
195   mFittingMode( FittingMode::DEFAULT ),
196   mSamplingMode( SamplingMode::DEFAULT ),
197   mWrapModeU( WrapMode::DEFAULT ),
198   mWrapModeV( WrapMode::DEFAULT ),
199   mLoadPolicy( Toolkit::ImageVisual::LoadPolicy::ATTACHED ),
200   mReleasePolicy( Toolkit::ImageVisual::ReleasePolicy::DESTROYED ),
201   mAtlasRect( 0.0f, 0.0f, 0.0f, 0.0f ),
202   mAttemptAtlasing( false ),
203   mLoading( false ),
204   mOrientationCorrection( true )
205 {
206   EnablePreMultipliedAlpha( mFactoryCache.GetPreMultiplyOnLoad() );
207 }
208
209 ImageVisual::~ImageVisual()
210 {
211   if( Stage::IsInstalled() )
212   {
213     if( mMaskingData )
214     {
215       // TextureManager could have been deleted before the actor that contains this
216       // ImageVisual is destroyed (e.g. due to stage shutdown). Ensure the stage
217       // is still valid before accessing texture manager.
218       if( mMaskingData->mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID )
219       {
220         TextureManager& textureManager = mFactoryCache.GetTextureManager();
221         textureManager.Remove( mMaskingData->mAlphaMaskId, this );
222       }
223     }
224
225     // ImageVisual destroyed so remove texture unless ReleasePolicy is set to never release
226     if( ( mTextureId != TextureManager::INVALID_TEXTURE_ID  ) && ( mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER ) )
227     {
228       RemoveTexture();
229     }
230   }
231 }
232
233 void ImageVisual::DoSetProperties( const Property::Map& propertyMap )
234 {
235   // Url is already received in constructor
236   for( Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter )
237   {
238     KeyValuePair keyValue = propertyMap.GetKeyValue( iter );
239     if( keyValue.first.type == Property::Key::INDEX )
240     {
241       DoSetProperty( keyValue.first.indexKey, keyValue.second );
242     }
243     else
244     {
245       if( keyValue.first == IMAGE_FITTING_MODE )
246       {
247         DoSetProperty( Toolkit::ImageVisual::Property::FITTING_MODE, keyValue.second );
248       }
249       else if( keyValue.first == IMAGE_SAMPLING_MODE )
250       {
251         DoSetProperty( Toolkit::ImageVisual::Property::SAMPLING_MODE, keyValue.second );
252       }
253       else if( keyValue.first == IMAGE_DESIRED_WIDTH )
254       {
255         DoSetProperty( Toolkit::ImageVisual::Property::DESIRED_WIDTH, keyValue.second );
256       }
257       else if( keyValue.first == IMAGE_DESIRED_HEIGHT )
258       {
259         DoSetProperty( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, keyValue.second );
260       }
261       else if( keyValue.first == PIXEL_AREA_UNIFORM_NAME )
262       {
263         DoSetProperty( Toolkit::ImageVisual::Property::PIXEL_AREA, keyValue.second );
264       }
265       else if( keyValue.first == IMAGE_WRAP_MODE_U )
266       {
267         DoSetProperty( Toolkit::ImageVisual::Property::WRAP_MODE_U, keyValue.second );
268       }
269       else if( keyValue.first == IMAGE_WRAP_MODE_V )
270       {
271         DoSetProperty( Toolkit::ImageVisual::Property::WRAP_MODE_V, keyValue.second );
272       }
273       else if( keyValue.first == SYNCHRONOUS_LOADING )
274       {
275         DoSetProperty( Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second );
276       }
277       else if( keyValue.first == IMAGE_ATLASING )
278       {
279         DoSetProperty( Toolkit::ImageVisual::Property::ATLASING, keyValue.second );
280       }
281       else if( keyValue.first == ALPHA_MASK_URL )
282       {
283         DoSetProperty( Toolkit::ImageVisual::Property::ALPHA_MASK_URL, keyValue.second );
284       }
285       else if( keyValue.first == MASK_CONTENT_SCALE_NAME )
286       {
287         DoSetProperty( Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, keyValue.second );
288       }
289       else if( keyValue.first == CROP_TO_MASK_NAME )
290       {
291         DoSetProperty( Toolkit::ImageVisual::Property::CROP_TO_MASK, keyValue.second );
292       }
293       else if ( keyValue.first == LOAD_POLICY_NAME )
294       {
295         DoSetProperty( Toolkit::ImageVisual::Property::LOAD_POLICY, keyValue.second );
296       }
297       else if( keyValue.first == RELEASE_POLICY_NAME )
298       {
299         DoSetProperty( Toolkit::ImageVisual::Property::RELEASE_POLICY, keyValue.second );
300       }
301       else if( keyValue.first == ORIENTATION_CORRECTION_NAME )
302       {
303         DoSetProperty( Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION, keyValue.second );
304       }
305     }
306   }
307   // Load image immediately if LOAD_POLICY requires it
308   if ( mLoadPolicy == Toolkit::ImageVisual::LoadPolicy::IMMEDIATE )
309   {
310     auto attemptAtlasing = AttemptAtlasing();
311     LoadTexture( attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection,
312                  TextureManager::ReloadPolicy::CACHED  );
313   }
314 }
315
316 void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& value )
317 {
318   switch( index )
319   {
320     case Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING:
321     {
322       bool sync = false;
323       if( value.Get( sync ) )
324       {
325         if( sync )
326         {
327           mImpl->mFlags |= Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
328         }
329         else
330         {
331           mImpl->mFlags &= ~Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
332         }
333       }
334       else
335       {
336         DALI_LOG_ERROR("ImageVisual: synchronousLoading property has incorrect type\n");
337       }
338       break;
339     }
340
341     case Toolkit::ImageVisual::Property::DESIRED_WIDTH:
342     {
343       float desiredWidth = 0.0f;
344       if( value.Get( desiredWidth ) )
345       {
346         mDesiredSize.SetWidth( desiredWidth );
347       }
348       else
349       {
350         DALI_LOG_ERROR("ImageVisual: desiredWidth property has incorrect type\n");
351       }
352       break;
353     }
354
355     case Toolkit::ImageVisual::Property::DESIRED_HEIGHT:
356     {
357       float desiredHeight = 0.0f;
358       if( value.Get( desiredHeight ) )
359       {
360         mDesiredSize.SetHeight( desiredHeight );
361       }
362       else
363       {
364         DALI_LOG_ERROR("ImageVisual: desiredHeight property has incorrect type\n");
365       }
366       break;
367     }
368
369     case Toolkit::ImageVisual::Property::FITTING_MODE:
370     {
371       int fittingMode = 0;
372       Scripting::GetEnumerationProperty( value, FITTING_MODE_TABLE, FITTING_MODE_TABLE_COUNT, fittingMode );
373       mFittingMode = Dali::FittingMode::Type( fittingMode );
374       break;
375     }
376
377     case Toolkit::ImageVisual::Property::SAMPLING_MODE:
378     {
379       int samplingMode = 0;
380       Scripting::GetEnumerationProperty( value, SAMPLING_MODE_TABLE, SAMPLING_MODE_TABLE_COUNT, samplingMode );
381       mSamplingMode = Dali::SamplingMode::Type( samplingMode );
382       break;
383     }
384
385     case Toolkit::ImageVisual::Property::PIXEL_AREA:
386     {
387       value.Get( mPixelArea );
388       break;
389     }
390
391     case Toolkit::ImageVisual::Property::WRAP_MODE_U:
392     {
393       int wrapMode = 0;
394       Scripting::GetEnumerationProperty( value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode );
395       mWrapModeU = Dali::WrapMode::Type( wrapMode );
396       break;
397     }
398
399     case Toolkit::ImageVisual::Property::WRAP_MODE_V:
400     {
401       int wrapMode = 0;
402       Scripting::GetEnumerationProperty( value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode );
403       mWrapModeV = Dali::WrapMode::Type( wrapMode );
404       break;
405     }
406
407     case Toolkit::ImageVisual::Property::ATLASING:
408     {
409       value.Get( mAttemptAtlasing );
410       break;
411     }
412
413     case Toolkit::ImageVisual::Property::ALPHA_MASK_URL:
414     {
415       std::string alphaUrl = "";
416       if( value.Get( alphaUrl ) )
417       {
418         AllocateMaskData();
419         mMaskingData->mAlphaMaskUrl = alphaUrl;
420       }
421       break;
422     }
423
424     case Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE:
425     {
426       float scale = 1.0f;
427       if( value.Get( scale ) )
428       {
429         AllocateMaskData();
430         mMaskingData->mContentScaleFactor = scale;
431       }
432       break;
433     }
434
435     case Toolkit::ImageVisual::Property::CROP_TO_MASK:
436     {
437       bool crop=false;
438       if( value.Get( crop ) )
439       {
440         AllocateMaskData();
441         mMaskingData->mCropToMask = crop;
442       }
443       break;
444     }
445
446     case Toolkit::ImageVisual::Property::RELEASE_POLICY:
447     {
448       int releasePolicy = 0;
449       Scripting::GetEnumerationProperty( value, RELEASE_POLICY_TABLE, RELEASE_POLICY_TABLE_COUNT, releasePolicy );
450       mReleasePolicy = Toolkit::ImageVisual::ReleasePolicy::Type( releasePolicy );
451       break;
452     }
453
454     case Toolkit::ImageVisual::Property::LOAD_POLICY:
455     {
456       int loadPolicy = 0;
457       Scripting::GetEnumerationProperty( value, LOAD_POLICY_TABLE, LOAD_POLICY_TABLE_COUNT, loadPolicy );
458       mLoadPolicy = Toolkit::ImageVisual::LoadPolicy::Type( loadPolicy );
459       break;
460     }
461     case Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION:
462     {
463       bool orientationCorrection( mOrientationCorrection );
464       if( value.Get( orientationCorrection ) )
465       {
466         mOrientationCorrection = orientationCorrection;
467       }
468       break;
469     }
470   }
471 }
472
473 void ImageVisual::AllocateMaskData()
474 {
475   if( !mMaskingData )
476   {
477     mMaskingData.reset(new TextureManager::MaskingData());
478   }
479 }
480
481 void ImageVisual::GetNaturalSize( Vector2& naturalSize )
482 {
483   if(mImage)
484   {
485     naturalSize.x = mImage.GetWidth();
486     naturalSize.y = mImage.GetHeight();
487     return;
488   }
489   else if( mDesiredSize.GetWidth()>0 && mDesiredSize.GetHeight()>0)
490   {
491     naturalSize.x = mDesiredSize.GetWidth();
492     naturalSize.y = mDesiredSize.GetHeight();
493     return;
494   }
495   else if( mImpl->mRenderer ) // Check if we have a loaded image
496   {
497     if( mImpl->mFlags & Impl::IS_ATLASING_APPLIED )
498     {
499       naturalSize.x = mAtlasRectSize.GetWidth();
500       naturalSize.y = mAtlasRectSize.GetHeight();
501       return;
502     }
503
504     auto textureSet = mImpl->mRenderer.GetTextures();
505     if( textureSet )
506     {
507       auto texture = textureSet.GetTexture(0);
508       naturalSize.x = texture.GetWidth();
509       naturalSize.y = texture.GetHeight();
510       return;
511     }
512   }
513
514   if( mMaskingData != NULL && mMaskingData->mAlphaMaskUrl.IsValid() &&
515            mMaskingData->mCropToMask )
516   {
517     ImageDimensions dimensions = Dali::GetClosestImageSize( mMaskingData->mAlphaMaskUrl.GetUrl() );
518     if( dimensions != ImageDimensions( 0, 0 ) )
519     {
520       naturalSize.x = dimensions.GetWidth();
521       naturalSize.y = dimensions.GetHeight();
522     }
523     return;
524   }
525   else if( mImageUrl.IsValid() )
526   {
527     if( mImageUrl.GetProtocolType() == VisualUrl::LOCAL )
528     {
529       ImageDimensions dimensions = Dali::GetClosestImageSize( mImageUrl.GetUrl() );
530
531       if( dimensions != ImageDimensions( 0, 0 ) )
532       {
533         naturalSize.x = dimensions.GetWidth();
534         naturalSize.y = dimensions.GetHeight();
535       }
536       else
537       {
538         Image brokenImage = mFactoryCache.GetBrokenVisualImage();
539
540         naturalSize.x = brokenImage.GetWidth();
541         naturalSize.y = brokenImage.GetWidth();
542       }
543       return;
544     }
545   }
546
547   naturalSize = Vector2::ZERO;
548 }
549
550 void ImageVisual::CreateRenderer( TextureSet& textureSet )
551 {
552   Geometry geometry;
553   Shader shader;
554
555   if( !mImpl->mCustomShader )
556   {
557     geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
558
559     shader = mImageVisualShaderFactory.GetShader( mFactoryCache,
560                              mImpl->mFlags & Impl::IS_ATLASING_APPLIED,
561                              mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE,
562                              IsRoundedCornerRequired() );
563   }
564   else
565   {
566     geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
567     if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
568     {
569       // Use custom hints
570       shader = Shader::New( mImageVisualShaderFactory.GetVertexShaderSource(), mImageVisualShaderFactory.GetFragmentShaderSource(), mImpl->mCustomShader->mHints );
571       shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
572     }
573     else
574     {
575       shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? mImageVisualShaderFactory.GetVertexShaderSource() : mImpl->mCustomShader->mVertexShader,
576                             mImpl->mCustomShader->mFragmentShader.empty() ? mImageVisualShaderFactory.GetFragmentShaderSource() : mImpl->mCustomShader->mFragmentShader,
577                             mImpl->mCustomShader->mHints );
578       if( mImpl->mCustomShader->mVertexShader.empty() )
579       {
580         shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
581       }
582     }
583   }
584
585   // Set pixel align off as default.
586   // ToDo: Pixel align causes issues such as rattling image animation.
587   // We should trun it off until issues are resolved
588   shader.RegisterProperty( PIXEL_ALIGNED_UNIFORM_NAME, PIXEL_ALIGN_OFF );
589
590   mImpl->mRenderer = Renderer::New( geometry, shader );
591   if( textureSet )
592   {
593     mImpl->mRenderer.SetTextures( textureSet );
594   }
595   // else still waiting for texture load to finish.
596
597   //Register transform properties
598   mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
599
600   EnablePreMultipliedAlpha( IsPreMultipliedAlphaEnabled() );
601 }
602
603 void ImageVisual::CreateNativeImageRenderer( NativeImage& nativeImage )
604 {
605   Geometry geometry;
606   Shader shader;
607
608   std::string fragmentShader;
609   const char* fragmentPreFix = nativeImage.GetCustomFragmentPreFix();
610   const char* customSamplerTypename = nativeImage.GetCustomSamplerTypename();
611
612   if( fragmentPreFix )
613   {
614     fragmentShader = fragmentPreFix;
615     fragmentShader += "\n";
616   }
617
618   if( mImpl->mCustomShader && !mImpl->mCustomShader->mFragmentShader.empty() )
619   {
620     fragmentShader += mImpl->mCustomShader->mFragmentShader;
621   }
622   else
623   {
624     fragmentShader += mImageVisualShaderFactory.GetFragmentShaderSource();
625   }
626
627   if( customSamplerTypename )
628   {
629     fragmentShader.replace( fragmentShader.find( DEFAULT_SAMPLER_TYPENAME ), strlen( DEFAULT_SAMPLER_TYPENAME ), customSamplerTypename );
630   }
631
632   if( !mImpl->mCustomShader )
633   {
634     geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
635
636     shader  = Shader::New( mImageVisualShaderFactory.GetVertexShaderSource(), fragmentShader );
637     shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
638   }
639   else
640   {
641     geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
642     shader  = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? mImageVisualShaderFactory.GetVertexShaderSource() : mImpl->mCustomShader->mVertexShader,
643                            fragmentShader,
644                            mImpl->mCustomShader->mHints );
645     if( mImpl->mCustomShader->mVertexShader.empty() )
646     {
647       shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
648     }
649   }
650
651   mImpl->mRenderer = Renderer::New( geometry, shader );
652
653   //Register transform properties
654   mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
655 }
656
657 void ImageVisual::LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& textures, bool orientationCorrection,
658                                TextureManager::ReloadPolicy forceReload )
659 {
660   TextureManager& textureManager = mFactoryCache.GetTextureManager();
661
662   ImageAtlasManagerPtr atlasManager = nullptr;
663   AtlasUploadObserver* atlasUploadObserver = nullptr;
664   auto textureObserver = this;
665
666   if( atlasing )
667   {
668     atlasManager = mFactoryCache.GetAtlasManager();
669     atlasUploadObserver = this;
670   }
671
672   auto preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader
673     ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD
674     : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
675
676   textures = textureManager.LoadTexture( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode,
677                                          mMaskingData, IsSynchronousLoadingRequired(), mTextureId,
678                                          atlasRect, mAtlasRectSize, atlasing, mLoading, mWrapModeU,
679                                          mWrapModeV, textureObserver, atlasUploadObserver, atlasManager,
680                                          mOrientationCorrection, forceReload, preMultiplyOnLoad);
681
682   if( textures )
683   {
684     EnablePreMultipliedAlpha( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD );
685   }
686
687   if( atlasing ) // Flag needs to be set before creating renderer
688   {
689     mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
690   }
691   else
692   {
693     mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
694   }
695 }
696
697 bool ImageVisual::AttemptAtlasing()
698 {
699   return ( ! mImpl->mCustomShader && mImageUrl.GetProtocolType() == VisualUrl::LOCAL && mAttemptAtlasing );
700 }
701
702 void ImageVisual::InitializeRenderer()
703 {
704   auto attemptAtlasing = AttemptAtlasing();
705   // texture set has to be created first as we need to know if atlasing succeeded or not
706   // when selecting the shader
707
708   if( mTextureId == TextureManager::INVALID_TEXTURE_ID && ! mTextures ) // Only load the texture once
709   {
710     LoadTexture( attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection,
711                  TextureManager::ReloadPolicy::CACHED );
712   }
713
714   CreateRenderer( mTextures );
715   mTextures.Reset(); // Visual should not keep a handle to the texture after this point.
716
717   if( attemptAtlasing ) // the texture is packed inside atlas
718   {
719     mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mAtlasRect );
720
721     bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
722
723     if( !defaultWrapMode ) // custom wrap mode
724     {
725       Vector2 wrapMode(mWrapModeU-WrapMode::CLAMP_TO_EDGE, mWrapModeV-WrapMode::CLAMP_TO_EDGE);
726       wrapMode.Clamp( Vector2::ZERO, Vector2( 2.f, 2.f ) );
727       mImpl->mRenderer.RegisterProperty( WRAP_MODE_UNIFORM_NAME, wrapMode );
728     }
729   }
730 }
731
732 void ImageVisual::InitializeRenderer( const Image& image )
733 {
734   TextureSet textures = TextureSet::New();
735
736   NativeImage nativeImage = NativeImage::DownCast( image );
737   if( nativeImage )
738   {
739     CreateNativeImageRenderer( nativeImage );
740     DALI_ASSERT_DEBUG( textures );
741     mImpl->mRenderer.SetTextures( textures );
742   }
743   else
744   {
745     // reuse existing code for regular images
746     CreateRenderer( textures ); // Textures will be retreived from Image
747   }
748   ApplyImageToSampler( image );
749 }
750
751 void ImageVisual::DoSetOnStage( Actor& actor )
752 {
753   if( mImageUrl.IsValid() )
754   {
755     InitializeRenderer();
756   }
757   else if( mImage )
758   {
759     InitializeRenderer( mImage );
760   }
761
762   if( !mImpl->mRenderer )
763   {
764     return;
765   }
766
767   mPlacementActor = actor;
768   // Search the Actor tree to find if Layer UI behaviour set.
769   Layer layer = actor.GetLayer();
770   if( layer && layer.GetBehavior() == Layer::LAYER_3D )
771   {
772      // Layer 3D set, do not align pixels
773      mImpl->mRenderer.RegisterProperty( PIXEL_ALIGNED_UNIFORM_NAME, PIXEL_ALIGN_OFF );
774   }
775
776   if( mPixelArea != FULL_TEXTURE_RECT )
777   {
778     mImpl->mRenderer.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, mPixelArea );
779   }
780
781   if( mLoading == false )
782   {
783     actor.AddRenderer( mImpl->mRenderer );
784     mPlacementActor.Reset();
785
786     // Image loaded and ready to display
787     ResourceReady( Toolkit::Visual::ResourceStatus::READY );
788   }
789 }
790
791 void ImageVisual::DoSetOffStage( Actor& actor )
792 {
793   // Visual::Base::SetOffStage only calls DoSetOffStage if mRenderer exists (is on onstage)
794
795   // Image release is dependent on the ReleasePolicy, renderer is destroyed.
796   actor.RemoveRenderer( mImpl->mRenderer);
797   if( mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED )
798   {
799     RemoveTexture(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas
800     mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING;
801   }
802
803   if( mImageUrl.IsValid() )
804   {
805     // Legacy support for deprecated Dali::Image
806     mImage.Reset();
807   }
808   mLoading = false;
809   mImpl->mRenderer.Reset();
810   mPlacementActor.Reset();
811 }
812
813 void ImageVisual::DoCreatePropertyMap( Property::Map& map ) const
814 {
815   map.Clear();
816   map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE );
817
818   bool sync = IsSynchronousLoadingRequired();
819   map.Insert( SYNCHRONOUS_LOADING, sync );
820   if( mImageUrl.IsValid() )
821   {
822     map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl() );
823     map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth() );
824     map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight() );
825   }
826   else if( mImage )
827   {
828     map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, static_cast<int>(mImage.GetWidth()) );
829     map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, static_cast<int>(mImage.GetHeight()) );
830
831     ResourceImage resourceImage = ResourceImage::DownCast(mImage);
832     if( resourceImage )
833     {
834       map.Insert( Toolkit::ImageVisual::Property::URL, resourceImage.GetUrl() );
835     }
836   }
837
838   map.Insert( Toolkit::ImageVisual::Property::FITTING_MODE, mFittingMode );
839   map.Insert( Toolkit::ImageVisual::Property::SAMPLING_MODE, mSamplingMode );
840
841   map.Insert( Toolkit::ImageVisual::Property::PIXEL_AREA, mPixelArea );
842   map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_U, mWrapModeU );
843   map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV );
844
845   map.Insert( Toolkit::ImageVisual::Property::ATLASING, mAttemptAtlasing );
846
847   if( mMaskingData != NULL )
848   {
849     map.Insert( Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mMaskingData->mAlphaMaskUrl.GetUrl() );
850     map.Insert( Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskingData->mContentScaleFactor );
851     map.Insert( Toolkit::ImageVisual::Property::CROP_TO_MASK, mMaskingData->mCropToMask );
852   }
853
854   map.Insert( Toolkit::ImageVisual::Property::LOAD_POLICY, mLoadPolicy );
855   map.Insert( Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy );
856   map.Insert( Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION, mOrientationCorrection );
857 }
858
859 void ImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
860 {
861   map.Clear();
862   map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE );
863   if( mImageUrl.IsValid() )
864   {
865     map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth() );
866     map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight() );
867   }
868   else if( mImage )
869   {
870     map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, static_cast<int>(mImage.GetWidth()) );
871     map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, static_cast<int>(mImage.GetHeight()) );
872   }
873 }
874
875 void ImageVisual::OnDoAction( const Dali::Property::Index actionName, const Dali::Property::Value& attributes )
876 {
877   // Check if action is valid for this visual type and perform action if possible
878
879   switch ( actionName )
880   {
881     case DevelImageVisual::Action::RELOAD:
882     {
883       auto attemptAtlasing = AttemptAtlasing();
884       LoadTexture( attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection,
885                    TextureManager::ReloadPolicy::FORCED );
886       break;
887     }
888   }
889 }
890
891 void ImageVisual::OnSetTransform()
892 {
893   if( mImpl->mRenderer )
894   {
895     mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
896   }
897 }
898
899 bool ImageVisual::IsResourceReady() const
900 {
901   return ( mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY ||
902            mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::FAILED );
903 }
904
905 void ImageVisual::ApplyImageToSampler( const Image& image )
906 {
907   if( image )
908   {
909     TextureSet textureSet = mImpl->mRenderer.GetTextures();
910     DALI_ASSERT_DEBUG( textureSet ); // texture set should always exist by this time
911
912     TextureSetImage( textureSet, 0u, image );
913     Sampler sampler = Sampler::New();
914     sampler.SetWrapMode(  mWrapModeU, mWrapModeV  );
915     textureSet.SetSampler( 0u, sampler );
916   }
917 }
918
919 // From existing atlas manager
920 void ImageVisual::UploadCompleted()
921 {
922   // Texture has been uploaded. If weak handle is holding a placement actor,
923   // it is the time to add the renderer to actor.
924   Actor actor = mPlacementActor.GetHandle();
925   if( actor )
926   {
927     mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mAtlasRect );
928     actor.AddRenderer( mImpl->mRenderer );
929     // reset the weak handle so that the renderer only get added to actor once
930     mPlacementActor.Reset();
931   }
932   // Image loaded
933   ResourceReady( Toolkit::Visual::ResourceStatus::READY );
934   mLoading = false;
935 }
936
937 // From Texture Manager
938 void ImageVisual::UploadComplete( bool loadingSuccess, int32_t textureId, TextureSet textureSet, bool usingAtlas,
939                                   const Vector4& atlasRectangle, bool preMultiplied )
940 {
941   Toolkit::Visual::ResourceStatus resourceStatus;
942   if( mImpl->mRenderer )
943   {
944     if( usingAtlas )
945     {
946       mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mAtlasRect );
947     }
948
949     EnablePreMultipliedAlpha( preMultiplied );
950
951     Actor actor = mPlacementActor.GetHandle();
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     if( loadingSuccess )
960     {
961       Sampler sampler = Sampler::New();
962       sampler.SetWrapMode(  mWrapModeU, mWrapModeV  );
963       textureSet.SetSampler( 0u, sampler );
964       mImpl->mRenderer.SetTextures(textureSet);
965     }
966     else
967     {
968       Image brokenImage = mFactoryCache.GetBrokenVisualImage();
969
970       textureSet = TextureSet::New();
971       mImpl->mRenderer.SetTextures( textureSet );
972
973       ApplyImageToSampler( brokenImage );
974     }
975   }
976
977   // Storing TextureSet needed when renderer staged.
978   if( ! mImpl->mRenderer )
979   {
980     mTextures = textureSet;
981   }
982
983   // Image loaded, set status regardless of staged status.
984   if( loadingSuccess )
985   {
986     resourceStatus = Toolkit::Visual::ResourceStatus::READY;
987   }
988   else
989   {
990     resourceStatus = Toolkit::Visual::ResourceStatus::FAILED;
991   }
992   // Signal to observers ( control ) that resources are ready. Must be all resources.
993   ResourceReady( resourceStatus );
994   mLoading = false;
995 }
996
997 void ImageVisual::RemoveTexture()
998 {
999   if( mTextureId != TextureManager::INVALID_TEXTURE_ID )
1000   {
1001     mFactoryCache.GetTextureManager().Remove( mTextureId, this );
1002     mTextureId = TextureManager::INVALID_TEXTURE_ID;
1003   }
1004   else
1005   {
1006     Vector4 atlasRect( 0.f, 0.f, 1.f, 1.f );
1007     Property::Index index = mImpl->mRenderer.GetPropertyIndex( ATLAS_RECT_UNIFORM_NAME );
1008     if( index != Property::INVALID_INDEX )
1009     {
1010       Property::Value atlasRectValue = mImpl->mRenderer.GetProperty( index );
1011       atlasRectValue.Get( atlasRect );
1012     }
1013
1014     TextureSet textureSet = mImpl->mRenderer.GetTextures();
1015     mImpl->mRenderer.Reset();
1016
1017     if( index != Property::INVALID_INDEX )
1018     {
1019       mFactoryCache.GetAtlasManager()->Remove( textureSet, atlasRect );
1020     }
1021   }
1022 }
1023
1024 } // namespace Internal
1025
1026 } // namespace Toolkit
1027
1028 } // namespace Dali