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