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