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