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