Select the renderer type based on the image url
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / renderers / image / image-renderer.cpp
1 /*
2  * Copyright (c) 2015 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 "image-renderer.h"
20
21 // EXTERNAL HEADER
22 #include <cstring> // for strncasecmp
23 #include <dali/public-api/images/resource-image.h>
24 #include <dali/public-api/images/native-image.h>
25 #include <dali/integration-api/debug.h>
26
27 // INTERNAL HEADER
28 #include <dali-toolkit/internal/controls/renderers/renderer-string-constants.h>
29 #include <dali-toolkit/internal/controls/renderers/renderer-factory-impl.h>
30 #include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
31 #include <dali-toolkit/internal/controls/renderers/control-renderer-impl.h>
32 #include <dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h>
33 #include <dali-toolkit/internal/controls/renderers/image-atlas-manager.h>
34
35 namespace Dali
36 {
37
38 namespace Toolkit
39 {
40
41 namespace Internal
42 {
43
44 namespace
45 {
46 const char HTTP_URL[] = "http://";
47 const char HTTPS_URL[] = "https://";
48
49 // property names
50 const char * const IMAGE_FITTING_MODE( "fittingMode" );
51 const char * const IMAGE_SAMPLING_MODE( "samplingMode" );
52 const char * const IMAGE_DESIRED_WIDTH( "desiredWidth" );
53 const char * const IMAGE_DESIRED_HEIGHT( "desiredHeight" );
54
55 // fitting modes
56 const char * const SHRINK_TO_FIT("SHRINK_TO_FIT");
57 const char * const SCALE_TO_FILL("SCALE_TO_FILL");
58 const char * const FIT_WIDTH("FIT_WIDTH");
59 const char * const FIT_HEIGHT("FIT_HEIGHT");
60 const char * const DEFAULT("DEFAULT");
61
62 // sampling modes
63 const char * const BOX("BOX");
64 const char * const NEAREST("NEAREST");
65 const char * const LINEAR("LINEAR");
66 const char * const BOX_THEN_NEAREST("BOX_THEN_NEAREST");
67 const char * const BOX_THEN_LINEAR("BOX_THEN_LINEAR");
68 const char * const NO_FILTER("NO_FILTER");
69 const char * const DONT_CARE("DONT_CARE");
70
71 const std::string PIXEL_AREA_UNIFORM_NAME = "pixelArea";
72
73 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
74
75 const char* DEFAULT_SAMPLER_TYPENAME = "sampler2D";
76
77 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
78   attribute mediump vec2 aPosition;\n
79   uniform mediump mat4 uMvpMatrix;\n
80   uniform mediump vec3 uSize;\n
81   uniform mediump vec4 uAtlasRect;\n
82   uniform mediump vec4 pixelArea;
83   varying mediump vec2 vTexCoord;\n
84   \n
85   void main()\n
86   {\n
87     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
88     vertexPosition.xyz *= uSize;\n
89     vertexPosition = uMvpMatrix * vertexPosition;\n
90     \n
91     vTexCoord = mix( uAtlasRect.xy, uAtlasRect.zw, pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5) ) );\n
92     gl_Position = vertexPosition;\n
93   }\n
94 );
95
96 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
97   varying mediump vec2 vTexCoord;\n
98   uniform sampler2D sTexture;\n
99   uniform lowp vec4 uColor;\n
100   \n
101   void main()\n
102   {\n
103     gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
104   }\n
105 );
106
107 Geometry CreateGeometry( RendererFactoryCache& factoryCache, ImageDimensions gridSize )
108 {
109   Geometry geometry;
110
111   if( gridSize == ImageDimensions( 1, 1 ) )
112   {
113     geometry = factoryCache.GetGeometry( RendererFactoryCache::QUAD_GEOMETRY );
114     if( !geometry )
115     {
116       geometry =  RendererFactoryCache::CreateQuadGeometry();
117       factoryCache.SaveGeometry( RendererFactoryCache::QUAD_GEOMETRY, geometry );
118     }
119   }
120   else
121   {
122     geometry = RendererFactoryCache::CreateGridGeometry( gridSize );
123   }
124
125   return geometry;
126 }
127
128 } //unnamed namespace
129
130 ImageRenderer::ImageRenderer( RendererFactoryCache& factoryCache, ImageAtlasManager& atlasManager )
131 : ControlRenderer( factoryCache ),
132   mAtlasManager( atlasManager ),
133   mDesiredSize(),
134   mFittingMode( FittingMode::DEFAULT ),
135   mSamplingMode( SamplingMode::DEFAULT ),
136   mNativeFragmentShaderCode( ),
137   mNativeImageFlag( false )
138 {
139 }
140
141 ImageRenderer::~ImageRenderer()
142 {
143 }
144
145 void ImageRenderer::DoInitialize( Actor& actor, const Property::Map& propertyMap )
146 {
147   std::string oldImageUrl = mImageUrl;
148
149   Property::Value* imageURLValue = propertyMap.Find( IMAGE_URL_NAME );
150   if( imageURLValue )
151   {
152     imageURLValue->Get( mImageUrl );
153     if( !mImageUrl.empty() )
154     {
155       mImage.Reset();
156     }
157
158     Property::Value* fittingValue = propertyMap.Find( IMAGE_FITTING_MODE );
159     if( fittingValue )
160     {
161       std::string fitting;
162       fittingValue->Get( fitting );
163
164       mFittingMode = FittingMode::DEFAULT;
165       if( fitting == SHRINK_TO_FIT )
166       {
167         mFittingMode = FittingMode::SHRINK_TO_FIT;
168       }
169       else if( fitting == SCALE_TO_FILL )
170       {
171         mFittingMode = FittingMode::SCALE_TO_FILL;
172       }
173       else if( fitting == FIT_WIDTH )
174       {
175         mFittingMode = FittingMode::FIT_WIDTH;
176       }
177       else if( fitting == FIT_HEIGHT )
178       {
179         mFittingMode = FittingMode::FIT_HEIGHT;
180       }
181       else if( fitting == DEFAULT )
182       {
183         mFittingMode = FittingMode::DEFAULT;
184       }
185       else
186       {
187         DALI_ASSERT_ALWAYS("Unknown fitting mode");
188       }
189     }
190
191     Property::Value* samplingValue = propertyMap.Find( IMAGE_SAMPLING_MODE );
192     if( samplingValue )
193     {
194       std::string sampling;
195       samplingValue->Get( sampling );
196
197       mSamplingMode = SamplingMode::DEFAULT;
198       if( sampling == BOX )
199       {
200         mSamplingMode = SamplingMode::BOX;
201       }
202       else if( sampling == NEAREST )
203       {
204         mSamplingMode = SamplingMode::NEAREST;
205       }
206       else if( sampling == LINEAR )
207       {
208         mSamplingMode = SamplingMode::LINEAR;
209       }
210       else if( sampling == BOX_THEN_NEAREST )
211       {
212         mSamplingMode = SamplingMode::BOX_THEN_NEAREST;
213       }
214       else if( sampling == BOX_THEN_LINEAR )
215       {
216         mSamplingMode = SamplingMode::BOX_THEN_LINEAR;
217       }
218       else if( sampling == NO_FILTER )
219       {
220         mSamplingMode = SamplingMode::NO_FILTER;
221       }
222       else if( sampling == DONT_CARE )
223       {
224         mSamplingMode = SamplingMode::DONT_CARE;
225       }
226       else if( sampling == DEFAULT )
227       {
228         mSamplingMode = SamplingMode::DEFAULT;
229       }
230       else
231       {
232         DALI_ASSERT_ALWAYS("Unknown sampling mode");
233       }
234     }
235
236     int desiredWidth = 0;
237     Property::Value* desiredWidthValue = propertyMap.Find( IMAGE_DESIRED_WIDTH );
238     if( desiredWidthValue )
239     {
240       desiredWidthValue->Get( desiredWidth );
241     }
242
243     int desiredHeight = 0;
244     Property::Value* desiredHeightValue = propertyMap.Find( IMAGE_DESIRED_HEIGHT );
245     if( desiredHeightValue )
246     {
247       desiredHeightValue->Get( desiredHeight );
248     }
249
250     mDesiredSize = ImageDimensions( desiredWidth, desiredHeight );
251   }
252
253   // remove old renderer if exit
254   if( mImpl->mRenderer )
255   {
256     if( actor ) //remove old renderer from actor
257     {
258       actor.RemoveRenderer( mImpl->mRenderer );
259     }
260     if( !oldImageUrl.empty() ) //clean old renderer from cache
261     {
262       CleanCache( oldImageUrl );
263     }
264   }
265
266   NativeImage nativeImage = NativeImage::DownCast( mImage );
267
268   if( nativeImage )
269   {
270     SetNativeFragmentShaderCode( nativeImage );
271   }
272
273   // if actor is on stage, create new renderer and apply to actor
274   if( actor && actor.OnStage() )
275   {
276     SetOnStage( actor );
277   }
278 }
279
280 void ImageRenderer::SetSize( const Vector2& size )
281 {
282   ControlRenderer::SetSize( size );
283 }
284
285 void ImageRenderer::GetNaturalSize( Vector2& naturalSize ) const
286 {
287   if(mImage)
288   {
289     naturalSize.x = mImage.GetWidth();
290     naturalSize.y = mImage.GetHeight();
291     return;
292   }
293   else if( mDesiredSize.GetWidth()>0 && mDesiredSize.GetHeight()>0)
294   {
295     naturalSize.x = mDesiredSize.GetWidth();
296     naturalSize.y = mDesiredSize.GetHeight();
297     return;
298   }
299   else if( !mImageUrl.empty() )
300   {
301     ImageDimensions dimentions = ResourceImage::GetImageSize( mImageUrl );
302     naturalSize.x = dimentions.GetWidth();
303     naturalSize.y = dimentions.GetHeight();
304     return;
305   }
306
307   naturalSize = Vector2::ZERO;
308 }
309
310 void ImageRenderer::SetClipRect( const Rect<int>& clipRect )
311 {
312   ControlRenderer::SetClipRect( clipRect );
313 }
314
315 void ImageRenderer::SetOffset( const Vector2& offset )
316 {
317 }
318
319 Renderer ImageRenderer::CreateRenderer() const
320 {
321   Geometry geometry;
322   Shader shader;
323
324   // If mImage is nativeImage with custom sampler or prefix, mNativeFragmentShaderCode will be applied.
325   // Renderer can't be shared between NativeImage and other image types.
326   if( !mNativeFragmentShaderCode.empty() )
327   {
328     return CreateNativeImageRenderer();
329   }
330
331   if( !mImpl->mCustomShader )
332   {
333     geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
334
335     shader = GetImageShader(mFactoryCache);
336   }
337   else
338   {
339     geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
340     if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
341     {
342       shader = GetImageShader(mFactoryCache);
343     }
344     else
345     {
346       shader  = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
347                              mImpl->mCustomShader->mFragmentShader.empty() ? FRAGMENT_SHADER : mImpl->mCustomShader->mFragmentShader,
348                              mImpl->mCustomShader->mHints );
349       if( mImpl->mCustomShader->mVertexShader.empty() )
350       {
351         shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
352         shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
353       }
354     }
355   }
356
357   TextureSet textureSet = TextureSet::New();
358
359   Renderer renderer = Renderer::New( geometry, shader );
360   renderer.SetTextures( textureSet );
361
362   return renderer;
363 }
364
365 Renderer ImageRenderer::CreateNativeImageRenderer() const
366 {
367   Geometry geometry;
368   Shader shader;
369
370   if( !mImpl->mCustomShader )
371   {
372     geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
373
374     shader  = Shader::New( VERTEX_SHADER, mNativeFragmentShaderCode );
375     shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
376     shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
377   }
378   else
379   {
380     geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
381     if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
382     {
383       shader  = Shader::New( VERTEX_SHADER, mNativeFragmentShaderCode );
384     }
385     else
386     {
387       shader  = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? VERTEX_SHADER : mImpl->mCustomShader->mVertexShader,
388                              mNativeFragmentShaderCode,
389                              mImpl->mCustomShader->mHints );
390       if( mImpl->mCustomShader->mVertexShader.empty() )
391       {
392         shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
393         shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
394       }
395     }
396   }
397
398   TextureSet textureSet = TextureSet::New();
399   Renderer renderer = Renderer::New( geometry, shader );
400   renderer.SetTextures( textureSet );
401
402   return renderer;
403 }
404
405 void ImageRenderer::InitializeRenderer( const std::string& imageUrl )
406 {
407   if( imageUrl.empty() )
408   {
409     return;
410   }
411
412   mImageUrl = imageUrl;
413   mImpl->mRenderer.Reset();
414
415   if( !mImpl->mCustomShader &&
416       ( strncasecmp( imageUrl.c_str(), HTTP_URL,  sizeof(HTTP_URL)  -1 ) != 0 ) && // ignore remote images
417       ( strncasecmp( imageUrl.c_str(), HTTPS_URL, sizeof(HTTPS_URL) -1 ) != 0 ) )
418   {
419     mImpl->mRenderer = mFactoryCache.GetRenderer( imageUrl );
420     if( !mImpl->mRenderer )
421     {
422       Vector4 atlasRect;
423       TextureSet textureSet = mAtlasManager.Add(atlasRect, imageUrl, mDesiredSize, mFittingMode, mSamplingMode );
424       if( textureSet )
425       {
426         Geometry geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
427         Shader shader( GetImageShader(mFactoryCache) );
428         mImpl->mRenderer = Renderer::New( geometry, shader );
429         mImpl->mRenderer.SetTextures( textureSet );
430         mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect );
431       }
432       else // big image, atlasing is not applied
433       {
434         mImpl->mRenderer = CreateRenderer();
435
436         ResourceImage image = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode );
437         image.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
438         TextureSet textureSet = mImpl->mRenderer.GetTextures();
439         textureSet.SetImage( 0u, image );
440       }
441
442       mFactoryCache.SaveRenderer( imageUrl, mImpl->mRenderer );
443     }
444
445     mImpl->mFlags |= Impl::IS_FROM_CACHE;
446   }
447   else
448   {
449     // for custom shader or remote image, renderer is not cached and atlas is not applied
450
451     mImpl->mFlags &= ~Impl::IS_FROM_CACHE;
452     mImpl->mRenderer = CreateRenderer();
453     ResourceImage resourceImage = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode );
454     resourceImage.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
455     ApplyImageToSampler( resourceImage );
456   }
457 }
458
459 void ImageRenderer::InitializeRenderer( const Image& image )
460 {
461   mImpl->mFlags &= ~Impl::IS_FROM_CACHE;
462
463   mImpl->mRenderer = CreateRenderer();
464
465   if( image )
466   {
467     ApplyImageToSampler( image );
468   }
469 }
470
471
472 void ImageRenderer::DoSetOnStage( Actor& actor )
473 {
474   if( !mImageUrl.empty() )
475   {
476     InitializeRenderer( mImageUrl );
477   }
478   else
479   {
480     InitializeRenderer( mImage );
481   }
482
483 }
484
485 void ImageRenderer::DoSetOffStage( Actor& actor )
486 {
487   //If we own the image then make sure we release it when we go off stage
488   if( !mImageUrl.empty() )
489   {
490     actor.RemoveRenderer( mImpl->mRenderer );
491     CleanCache(mImageUrl);
492     mImage.Reset();
493   }
494   else
495   {
496     actor.RemoveRenderer( mImpl->mRenderer );
497     mImpl->mRenderer.Reset();
498   }
499 }
500
501 void ImageRenderer::DoCreatePropertyMap( Property::Map& map ) const
502 {
503   map.Clear();
504   map.Insert( RENDERER_TYPE, IMAGE_RENDERER );
505   if( !mImageUrl.empty() )
506   {
507     map.Insert( IMAGE_URL_NAME, mImageUrl );
508     map.Insert( IMAGE_DESIRED_WIDTH, mDesiredSize.GetWidth() );
509     map.Insert( IMAGE_DESIRED_HEIGHT, mDesiredSize.GetHeight() );
510   }
511   else if( mImage )
512   {
513     map.Insert( IMAGE_DESIRED_WIDTH, static_cast<int>(mImage.GetWidth()) );
514     map.Insert( IMAGE_DESIRED_HEIGHT, static_cast<int>(mImage.GetHeight()) );
515
516     ResourceImage resourceImage = ResourceImage::DownCast(mImage);
517     if( resourceImage )
518     {
519       map.Insert( IMAGE_URL_NAME, resourceImage.GetUrl() );
520     }
521   }
522
523   switch( mFittingMode )
524   {
525     case Dali::FittingMode::FIT_HEIGHT:
526     {
527       map.Insert( IMAGE_FITTING_MODE, FIT_HEIGHT );
528       break;
529     }
530     case Dali::FittingMode::FIT_WIDTH:
531     {
532       map.Insert( IMAGE_FITTING_MODE, FIT_WIDTH );
533       break;
534     }
535     case Dali::FittingMode::SCALE_TO_FILL:
536     {
537       map.Insert( IMAGE_FITTING_MODE, SCALE_TO_FILL );
538       break;
539     }
540     case Dali::FittingMode::SHRINK_TO_FIT:
541     {
542       map.Insert( IMAGE_FITTING_MODE, SHRINK_TO_FIT );
543       break;
544     }
545     default:
546     {
547       map.Insert( IMAGE_FITTING_MODE, DEFAULT );
548       break;
549     }
550   }
551
552   switch( mSamplingMode )
553   {
554     case Dali::SamplingMode::BOX:
555     {
556       map.Insert( IMAGE_SAMPLING_MODE, BOX );
557       break;
558     }
559     case Dali::SamplingMode::NEAREST:
560     {
561       map.Insert( IMAGE_SAMPLING_MODE, NEAREST );
562       break;
563     }
564     case Dali::SamplingMode::LINEAR:
565     {
566       map.Insert( IMAGE_SAMPLING_MODE, LINEAR );
567       break;
568     }
569     case Dali::SamplingMode::BOX_THEN_LINEAR:
570     {
571       map.Insert( IMAGE_SAMPLING_MODE, BOX_THEN_LINEAR );
572       break;
573     }
574     case Dali::SamplingMode::BOX_THEN_NEAREST:
575     {
576       map.Insert( IMAGE_SAMPLING_MODE, BOX_THEN_NEAREST );
577       break;
578     }
579     case Dali::SamplingMode::NO_FILTER:
580     {
581       map.Insert( IMAGE_SAMPLING_MODE, NO_FILTER );
582       break;
583     }
584     case Dali::SamplingMode::DONT_CARE:
585     {
586       map.Insert( IMAGE_SAMPLING_MODE, DONT_CARE );
587       break;
588     }
589     default:
590     {
591       map.Insert( IMAGE_SAMPLING_MODE, DEFAULT );
592       break;
593     }
594   }
595 }
596
597 Shader ImageRenderer::GetImageShader( RendererFactoryCache& factoryCache )
598 {
599   Shader shader = factoryCache.GetShader( RendererFactoryCache::IMAGE_SHADER );
600   if( !shader )
601   {
602     shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
603     factoryCache.SaveShader( RendererFactoryCache::IMAGE_SHADER, shader );
604     shader.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
605     shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
606   }
607   return shader;
608 }
609
610 void ImageRenderer::SetImage( Actor& actor, const std::string& imageUrl, ImageDimensions size, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode )
611 {
612   if( mImageUrl != imageUrl )
613   {
614     std::string oldImageUrl = mImageUrl;
615     mImageUrl = imageUrl;
616     mDesiredSize = size;
617     mFittingMode = fittingMode;
618     mSamplingMode = samplingMode;
619     mImage.Reset();
620
621     if( mImpl->mRenderer )
622     {
623       if( GetIsFromCache() ) // if renderer is from cache, remove the old one
624       {
625         //remove old renderer
626         if( actor )
627         {
628           actor.RemoveRenderer( mImpl->mRenderer );
629         }
630
631         //clean the cache
632         if( !oldImageUrl.empty() )
633         {
634           CleanCache(oldImageUrl);
635         }
636
637         if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
638         {
639           SetOnStage(actor);
640         }
641       }
642       else // if renderer is not from cache, reuse the same renderer and only change the texture
643       {
644         ResourceImage image = Dali::ResourceImage::New( imageUrl, mDesiredSize, mFittingMode, mSamplingMode );
645         image.LoadingFinishedSignal().Connect( this, &ImageRenderer::OnImageLoaded );
646         ApplyImageToSampler( image );
647       }
648     }
649   }
650 }
651
652 void ImageRenderer::SetImage( Actor& actor, const Image& image )
653 {
654   if( mImage != image )
655   {
656     NativeImage newNativeImage = NativeImage::DownCast( image );
657     bool newRendererFlag = true;
658
659     if( newNativeImage && !mNativeImageFlag )
660     {
661       SetNativeFragmentShaderCode( newNativeImage );
662     }
663
664     if( ( newNativeImage && mNativeImageFlag ) || ( !newNativeImage && !mNativeImageFlag ) )
665     {
666       newRendererFlag = false;
667     }
668
669     if( newNativeImage )
670     {
671       mNativeImageFlag = true;
672     }
673     else
674     {
675       mNativeFragmentShaderCode.clear();
676       mNativeImageFlag = false;
677     }
678
679     mImage = image;
680
681     if( mImpl->mRenderer )
682     {
683       // if renderer is from cache, remove the old one, and create new renderer
684       if( GetIsFromCache() )
685       {
686         //remove old renderer
687         if( actor )
688         {
689           actor.RemoveRenderer( mImpl->mRenderer );
690         }
691
692         //clean the cache
693         if( !mImageUrl.empty() )
694         {
695           CleanCache(mImageUrl);
696         }
697         mImageUrl.clear();
698
699         if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
700         {
701           SetOnStage(actor);
702         }
703       }
704       // if input image is nativeImage and mImage is regular image or the reverse, remove the old one, and create new renderer
705       else if( newRendererFlag )
706       {
707         //remove old renderer
708         if( actor )
709         {
710           actor.RemoveRenderer( mImpl->mRenderer );
711         }
712
713         if( actor && actor.OnStage() ) // if actor on stage, create a new renderer and apply to actor
714         {
715           SetOnStage(actor);
716         }
717       }
718       else // if renderer is not from cache, reuse the same renderer and only change the texture
719       {
720         ApplyImageToSampler( image );
721       }
722     }
723
724     mImageUrl.clear();
725     mDesiredSize = ImageDimensions();
726     mFittingMode = FittingMode::DEFAULT;
727     mSamplingMode = SamplingMode::DEFAULT;
728   }
729 }
730
731 void ImageRenderer::ApplyImageToSampler( const Image& image )
732 {
733   if( image )
734   {
735     TextureSet textureSet = mImpl->mRenderer.GetTextures();
736     if( textureSet )
737     {
738       textureSet.SetImage( 0u, image );
739     }
740   }
741 }
742
743 void ImageRenderer::OnImageLoaded( ResourceImage image )
744 {
745   if( image.GetLoadingState() == Dali::ResourceLoadingFailed )
746   {
747     Image brokenImage = RendererFactory::GetBrokenRendererImage();
748     if( mImpl->mRenderer )
749     {
750       ApplyImageToSampler( brokenImage );
751     }
752   }
753 }
754
755 void ImageRenderer::CleanCache(const std::string& url)
756 {
757   TextureSet textureSet = mImpl->mRenderer.GetTextures();
758
759   Vector4 atlasRect( 0.f, 0.f, 1.f, 1.f );
760   Property::Index index = mImpl->mRenderer.GetPropertyIndex( ATLAS_RECT_UNIFORM_NAME );
761   if( index != Property::INVALID_INDEX )
762   {
763     Property::Value atlasRectValue = mImpl->mRenderer.GetProperty( index );
764     atlasRectValue.Get( atlasRect );
765   }
766
767   mImpl->mRenderer.Reset();
768   if( mFactoryCache.CleanRendererCache( url ) && index != Property::INVALID_INDEX )
769   {
770     mAtlasManager.Remove( textureSet, atlasRect );
771   }
772 }
773
774 void ImageRenderer::SetNativeFragmentShaderCode( Dali::NativeImage& nativeImage )
775 {
776   const char* fragmentPreFix = nativeImage.GetCustomFragmentPreFix();
777   const char* customSamplerTypename = nativeImage.GetCustomSamplerTypename();
778
779   if( fragmentPreFix )
780   {
781     mNativeFragmentShaderCode = fragmentPreFix;
782     mNativeFragmentShaderCode += "\n";
783   }
784
785   if( mImpl->mCustomShader && !mImpl->mCustomShader->mFragmentShader.empty() )
786   {
787     mNativeFragmentShaderCode += mImpl->mCustomShader->mFragmentShader;
788   }
789   else
790   {
791     mNativeFragmentShaderCode += FRAGMENT_SHADER;
792   }
793
794   if( customSamplerTypename )
795   {
796     mNativeFragmentShaderCode.replace( mNativeFragmentShaderCode.find( DEFAULT_SAMPLER_TYPENAME ), strlen( DEFAULT_SAMPLER_TYPENAME ), customSamplerTypename );
797   }
798
799 }
800
801 } // namespace Internal
802
803 } // namespace Toolkit
804
805 } // namespace Dali