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