Fix for PLACEHOLDER_TEXT_FOCUSED feature
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / rendering / atlas / text-atlas-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 <dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/dali.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/public-api/text-abstraction/text-abstraction.h>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/internal/atlas-manager/atlas-manager.h>
28 #include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
29 #include <dali-toolkit/internal/text/rendering/shaders/text-basic-shader.h>
30 #include <dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h>
31 #include <dali-toolkit/internal/text/rendering/shaders/text-basic-shadow-shader.h>
32 #if defined(DEBUG_ENABLED)
33 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_ATLAS_RENDERER");
34 #endif
35
36 using namespace Dali;
37 using namespace Dali::Toolkit;
38 using namespace Dali::Toolkit::Text;
39
40 namespace
41 {
42   const float ZERO( 0.0f );
43   const float HALF( 0.5f );
44   const float ONE( 1.0f );
45   const float TWO( 2.0f );
46   const uint32_t DEFAULT_ATLAS_WIDTH = 512u;
47   const uint32_t DEFAULT_ATLAS_HEIGHT = 512u;
48 }
49
50 struct AtlasRenderer::Impl : public ConnectionTracker
51 {
52
53   enum Style
54   {
55     STYLE_NORMAL,
56     STYLE_DROP_SHADOW
57   };
58
59   struct MeshRecord
60   {
61     Vector4 mColor;
62     uint32_t mAtlasId;
63     MeshData mMeshData;
64     FrameBufferImage mBuffer;
65     bool mIsUnderline;
66   };
67
68   struct Extent
69   {
70     float mBaseLine;
71     float mLeft;
72     float mRight;
73     float mUnderlinePosition;
74     float mUnderlineThickness;
75     uint32_t mMeshRecordIndex;
76   };
77
78   struct AtlasRecord
79   {
80     uint32_t mImageId;
81     Text::GlyphIndex mIndex;
82   };
83
84   struct MaxBlockSize
85   {
86     FontId mFontId;
87     uint32_t mNeededBlockWidth;
88     uint32_t mNeededBlockHeight;
89   };
90
91   Impl()
92   {
93     mGlyphManager = AtlasGlyphManager::Get();
94     mFontClient = TextAbstraction::FontClient::Get();
95     mBasicShader = BasicShader::New();
96     mBgraShader = BgraShader::New();
97     mBasicShadowShader = BasicShadowShader::New();
98
99     mFace.reserve( 6u );
100     mFace.push_back( 0 ); mFace.push_back( 2u ); mFace.push_back( 1u );
101     mFace.push_back( 1u ); mFace.push_back( 2u ); mFace.push_back( 3u );
102   }
103
104   void AddGlyphs( const std::vector<Vector2>& positions,
105                   const Vector<GlyphInfo>& glyphs,
106                   const Vector4& textColor,
107                   const Vector2& shadowOffset,
108                   const Vector4& shadowColor,
109                   bool underlineEnabled,
110                   const Vector4& underlineColor,
111                   float underlineHeight )
112   {
113     AtlasManager::AtlasSlot slot;
114     std::vector< MeshRecord > meshContainer;
115     Vector< Extent > extents;
116
117     float currentUnderlinePosition = ZERO;
118     float currentUnderlineThickness = underlineHeight;
119     uint32_t currentBlockSize = 0;
120     FontId lastFontId = 0;
121     Style style = STYLE_NORMAL;
122
123     if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 )
124     {
125       style = STYLE_DROP_SHADOW;
126     }
127
128     if ( mImageIds.Size() )
129     {
130       // Unreference any currently used glyphs
131       RemoveText();
132     }
133
134     CalculateBlocksSize( glyphs );
135
136     for ( uint32_t i = 0; i < glyphs.Size(); ++i )
137     {
138       GlyphInfo glyph = glyphs[ i ];
139
140       // No operation for white space
141       if ( glyph.width && glyph.height )
142       {
143         // Are we still using the same fontId as previous
144         if ( glyph.fontId != lastFontId )
145         {
146           // We need to fetch fresh font underline metrics
147           FontMetrics fontMetrics;
148           mFontClient.GetFontMetrics( glyph.fontId, fontMetrics );
149           currentUnderlinePosition = ceil( fabsf( fontMetrics.underlinePosition ) );
150           float descender = ceil( fabsf( fontMetrics.descender ) );
151
152           if ( underlineHeight == ZERO )
153           {
154             currentUnderlineThickness = fontMetrics.underlineThickness;
155
156             // Ensure underline will be at least a pixel high
157             if ( currentUnderlineThickness < ONE )
158             {
159               currentUnderlineThickness = ONE;
160             }
161             else
162             {
163               currentUnderlineThickness = ceil( currentUnderlineThickness );
164             }
165           }
166
167           // Clamp the underline position at the font descender and check for ( as EFL describes it ) a broken font
168           if ( currentUnderlinePosition > descender )
169           {
170             currentUnderlinePosition = descender;
171           }
172           if ( ZERO == currentUnderlinePosition )
173           {
174             // Move offset down by one ( EFL behavior )
175             currentUnderlinePosition = ONE;
176           }
177         }
178
179         Vector2 position = positions[ i ];
180         MeshData newMeshData;
181         mGlyphManager.Cached( glyph.fontId, glyph.index, slot );
182
183         if ( slot.mImageId )
184         {
185           // This glyph already exists so generate mesh data plugging in our supplied position
186           mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
187           mImageIds.PushBack( slot.mImageId );
188         }
189         else
190         {
191
192           // Select correct size for new atlas if needed....?
193           if ( lastFontId != glyph.fontId )
194           {
195             for ( uint32_t j = 0; j < mBlockSizes.size(); ++j )
196             {
197               if ( mBlockSizes[ j ].mFontId == glyph.fontId )
198               {
199                 currentBlockSize = j;
200                 mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_WIDTH,
201                                                DEFAULT_ATLAS_HEIGHT,
202                                                mBlockSizes[ j ].mNeededBlockWidth,
203                                                mBlockSizes[ j ].mNeededBlockHeight );
204               }
205             }
206           }
207
208           // Create a new image for the glyph
209           BufferImage bitmap = mFontClient.CreateBitmap( glyph.fontId, glyph.index );
210           if ( bitmap )
211           {
212             // Ensure that the next image will fit into the current block size
213             bool setSize = false;
214             if ( bitmap.GetWidth() > mBlockSizes[ currentBlockSize ].mNeededBlockWidth )
215             {
216               setSize = true;
217               mBlockSizes[ currentBlockSize ].mNeededBlockWidth = bitmap.GetWidth();
218             }
219             if ( bitmap.GetHeight() > mBlockSizes[ currentBlockSize ].mNeededBlockHeight )
220             {
221               setSize = true;
222               mBlockSizes[ currentBlockSize ].mNeededBlockHeight = bitmap.GetHeight();
223             }
224
225             if ( setSize )
226             {
227               mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_WIDTH,
228                                              DEFAULT_ATLAS_HEIGHT,
229                                              mBlockSizes[ currentBlockSize ].mNeededBlockWidth,
230                                              mBlockSizes[ currentBlockSize ].mNeededBlockHeight );
231             }
232
233             // Locate a new slot for our glyph
234             mGlyphManager.Add( glyph, bitmap, slot );
235
236             // Generate mesh data for this quad, plugging in our supplied position
237             if ( slot.mImageId )
238             {
239               mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
240               mImageIds.PushBack( slot.mImageId );
241             }
242           }
243         }
244         // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
245         StitchTextMesh( meshContainer,
246                         newMeshData,
247                         extents,
248                         textColor,
249                         position.y + glyph.yBearing,
250                         currentUnderlinePosition,
251                         currentUnderlineThickness,
252                         slot );
253         lastFontId = glyph.fontId;
254       }
255     }
256
257     if ( underlineEnabled )
258     {
259       // Check to see if any of the text needs an underline
260       GenerateUnderlines( meshContainer, extents, underlineColor, textColor );
261     }
262
263     // For each MeshData object, create a mesh actor and add to the renderable actor
264     if ( meshContainer.size() )
265     {
266       for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt )
267       {
268         MeshActor actor = MeshActor::New( Mesh::New( mIt->mMeshData ) );
269         actor.SetColor( mIt->mColor );
270
271         // Ensure that text rendering is unfiltered
272         actor.SetFilterMode( FilterMode::NEAREST, FilterMode::NEAREST );
273         if ( mIt->mIsUnderline )
274         {
275           actor.SetColorMode( USE_OWN_COLOR );
276         }
277         else
278         {
279           actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
280         }
281
282         // Check to see what pixel format the shader should be
283         if ( mGlyphManager.GetPixelFormat( mIt->mAtlasId ) == Pixel::L8 )
284         {
285           // Create an effect if necessary
286           if ( style == STYLE_DROP_SHADOW )
287           {
288             actor.Add( GenerateShadow( *mIt, shadowOffset, shadowColor ) );
289           }
290           actor.SetShaderEffect( mBasicShader );
291         }
292         else
293         {
294           actor.SetShaderEffect( mBgraShader );
295         }
296
297         if ( mActor )
298         {
299           mActor.Add( actor );
300         }
301         else
302         {
303           mActor = actor;
304         }
305       }
306       mActor.OffStageSignal().Connect( this, &AtlasRenderer::Impl::OffStageDisconnect );
307     }
308 #if defined(DEBUG_ENABLED)
309     Toolkit::AtlasGlyphManager::Metrics metrics = mGlyphManager.GetMetrics();
310     DALI_LOG_INFO( gLogFilter, Debug::General, "TextAtlasRenderer::GlyphManager::GlyphCount: %i, AtlasCount: %i, TextureMemoryUse: %iK\n",
311                                                 metrics.mGlyphCount,
312                                                 metrics.mAtlasMetrics.mAtlasCount,
313                                                 metrics.mAtlasMetrics.mTextureMemoryUsed / 1024 );
314     for ( uint32_t i = 0; i < metrics.mAtlasMetrics.mAtlasCount; ++i )
315     {
316       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Atlas [%i] %sPixels: %s Size: %ix%i, BlockSize: %ix%i, BlocksUsed: %i/%i\n",
317                                                  i + 1, i > 8 ? "" : " ",
318                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mPixelFormat == Pixel::L8 ? "L8  " : "BGRA",
319                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mWidth,
320                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mHeight,
321                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mBlockWidth,
322                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mBlockHeight,
323                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mBlocksUsed,
324                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mTotalBlocks );
325     }
326 #endif
327   }
328
329   void StitchTextMesh( std::vector< MeshRecord >& meshContainer,
330                        MeshData& newMeshData,
331                        Vector< Extent >& extents,
332                        const Vector4& color,
333                        float baseLine,
334                        float underlinePosition,
335                        float underlineThickness,
336                        AtlasManager::AtlasSlot& slot )
337   {
338     if ( slot.mImageId )
339     {
340       MeshData::VertexContainer verts = newMeshData.GetVertices();
341       float left = verts[ 0 ].x;
342       float right = verts[ 1 ].x;
343
344       // Check to see if there's a mesh data object that references the same atlas ?
345       uint32_t index = 0;
346       for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt, ++index )
347       {
348         if ( slot.mAtlasId == mIt->mAtlasId && color == mIt->mColor )
349         {
350           // Stitch the mesh to the existing mesh and adjust any extents
351           mGlyphManager.StitchMesh( mIt->mMeshData, newMeshData );
352           AdjustExtents( extents,
353                          meshContainer,
354                          index,
355                          left,
356                          right,
357                          baseLine,
358                          underlinePosition,
359                          underlineThickness );
360           return;
361         }
362       }
363
364       // No mesh data object currently exists that references this atlas, so create a new one
365       MeshRecord meshRecord;
366       meshRecord.mAtlasId = slot.mAtlasId;
367       meshRecord.mMeshData = newMeshData;
368       meshRecord.mColor = color;
369       meshRecord.mIsUnderline = false;
370       meshContainer.push_back( meshRecord );
371
372       // Adjust extents for this new meshrecord
373       AdjustExtents( extents,
374                      meshContainer,
375                      meshContainer.size() - 1u,
376                      left,
377                      right,
378                      baseLine,
379                      underlinePosition,
380                      underlineThickness );
381
382     }
383   }
384
385   void AdjustExtents( Vector< Extent >& extents,
386                       std::vector< MeshRecord>& meshRecords,
387                       uint32_t index,
388                       float left,
389                       float right,
390                       float baseLine,
391                       float underlinePosition,
392                       float underlineThickness )
393   {
394     bool foundExtent = false;
395     for ( Vector< Extent >::Iterator eIt = extents.Begin(); eIt != extents.End(); ++eIt )
396     {
397       if ( Equals( baseLine, eIt->mBaseLine ) )
398       {
399         foundExtent = true;
400         if ( left < eIt->mLeft )
401         {
402           eIt->mLeft = left;
403         }
404         if ( right > eIt->mRight  )
405         {
406           eIt->mRight = right;
407         }
408
409         if ( underlinePosition > eIt->mUnderlinePosition )
410         {
411           eIt->mUnderlinePosition = underlinePosition;
412         }
413         if ( underlineThickness > eIt->mUnderlineThickness )
414         {
415           eIt->mUnderlineThickness = underlineThickness;
416         }
417       }
418     }
419     if ( !foundExtent )
420     {
421       Extent extent;
422       extent.mLeft = left;
423       extent.mRight = right;
424       extent.mBaseLine = baseLine;
425       extent.mUnderlinePosition = underlinePosition;
426       extent.mUnderlineThickness = underlineThickness;
427       extent.mMeshRecordIndex = index;
428       extents.PushBack( extent );
429     }
430   }
431
432   // Unreference any glyphs that were used with this actor
433   void OffStageDisconnect( Dali::Actor actor )
434   {
435     RemoveText();
436   }
437
438   void RemoveText()
439   {
440     for ( uint32_t i = 0; i < mImageIds.Size(); ++i )
441     {
442       mGlyphManager.Remove( mImageIds[ i ] );
443     }
444     mImageIds.Resize( 0 );
445   }
446
447   void CalculateBlocksSize( const Vector<GlyphInfo>& glyphs )
448   {
449     MaxBlockSize maxBlockSize;
450     for ( uint32_t i = 0; i < glyphs.Size(); ++i )
451     {
452       FontId fontId = glyphs[ i ].fontId;
453       bool foundFont = false;
454       for ( uint32_t j = 0; j < mBlockSizes.size(); ++j )
455       {
456         if ( mBlockSizes[ j ].mFontId == fontId )
457         {
458           foundFont = true;
459         }
460       }
461       if ( !foundFont )
462       {
463         FontMetrics fontMetrics;
464         mFontClient.GetFontMetrics( fontId, fontMetrics );
465         maxBlockSize.mNeededBlockWidth = static_cast< uint32_t >( fontMetrics.height );
466         maxBlockSize.mNeededBlockHeight = static_cast< uint32_t >( fontMetrics.height );
467         maxBlockSize.mFontId = fontId;
468         mBlockSizes.push_back( maxBlockSize );
469       }
470     }
471   }
472
473   void GenerateUnderlines( std::vector< MeshRecord>& meshRecords,
474                            Vector< Extent >& extents,
475                            const Vector4& underlineColor,
476                            const Vector4& textColor )
477   {
478     MeshData newMeshData;
479     for ( Vector< Extent >::ConstIterator eIt = extents.Begin(); eIt != extents.End(); ++eIt )
480     {
481       MeshData::VertexContainer newVerts;
482       newVerts.reserve( 4u );
483       uint32_t index = eIt->mMeshRecordIndex;
484       Vector2 uv = mGlyphManager.GetAtlasSize( meshRecords[ index ].mAtlasId );
485
486       // Make sure we don't hit texture edge for single pixel texture ( filled pixel is in top left of every atlas )
487       float u = HALF / uv.x;
488       float v = HALF / uv.y;
489       float thickness = eIt->mUnderlineThickness;
490       float baseLine = eIt->mBaseLine + eIt->mUnderlinePosition - ( thickness * HALF );
491       float tlx = eIt->mLeft;
492       float brx = eIt->mRight;
493
494       newVerts.push_back( MeshData::Vertex( Vector3( tlx, baseLine, ZERO ),
495                                             Vector2::ZERO,
496                                             Vector3::ZERO ) );
497
498       newVerts.push_back( MeshData::Vertex( Vector3( brx, baseLine, ZERO ),
499                                             Vector2( u, ZERO ),
500                                             Vector3::ZERO ) );
501
502       newVerts.push_back( MeshData::Vertex( Vector3( tlx, baseLine + thickness, ZERO ),
503                                             Vector2( ZERO, v ),
504                                             Vector3::ZERO ) );
505
506       newVerts.push_back( MeshData::Vertex( Vector3( brx, baseLine + thickness, ZERO ),
507                                             Vector2( u, v ),
508                                             Vector3::ZERO ) );
509
510       newMeshData.SetVertices( newVerts );
511       newMeshData.SetFaceIndices( mFace );
512
513       if ( underlineColor == textColor )
514       {
515         mGlyphManager.StitchMesh( meshRecords[ index ].mMeshData, newMeshData );
516       }
517       else
518       {
519         MeshRecord record;
520         newMeshData.SetMaterial( meshRecords[ index ].mMeshData.GetMaterial() );
521         newMeshData.SetHasNormals( true );
522         newMeshData.SetHasColor( false );
523         newMeshData.SetHasTextureCoords( true );
524         record.mMeshData = newMeshData;
525         record.mAtlasId = meshRecords[ index ].mAtlasId;
526         record.mColor = underlineColor;
527         record.mIsUnderline = true;
528         meshRecords.push_back( record );
529       }
530     }
531   }
532
533   MeshActor GenerateShadow( MeshRecord& meshRecord,
534                             const Vector2& shadowOffset,
535                             const Vector4& shadowColor )
536   {
537     // Scan vertex buffer to determine width and height of effect buffer needed
538     MeshData::VertexContainer verts = meshRecord.mMeshData.GetVertices();
539     float tlx = verts[ 0 ].x;
540     float tly = verts[ 0 ].y;
541     float brx = ZERO;
542     float bry = ZERO;
543
544     for ( uint32_t i = 0; i < verts.size(); ++i )
545     {
546       if ( verts[ i ].x < tlx )
547       {
548         tlx = verts[ i ].x;
549       }
550       if ( verts[ i ].y < tly )
551       {
552         tly = verts[ i ].y;
553       }
554       if ( verts[ i ].x > brx )
555       {
556         brx = verts[ i ].x;
557       }
558       if ( verts[ i ].y > bry )
559       {
560         bry = verts[ i ].y;
561       }
562     }
563
564     float width = brx - tlx;
565     float height = bry - tly;
566     float divWidth = TWO / width;
567     float divHeight = TWO / height;
568
569     // Create a buffer to render to
570     meshRecord.mBuffer = FrameBufferImage::New( width, height );
571
572     // Create a mesh actor to contain the post-effect render
573     MeshData::VertexContainer vertices;
574     MeshData::FaceIndices face;
575
576     vertices.push_back( MeshData::Vertex( Vector3( tlx + shadowOffset.x, tly + shadowOffset.y, ZERO ),
577                                           Vector2::ZERO,
578                                           Vector3::ZERO ) );
579
580     vertices.push_back( MeshData::Vertex( Vector3( brx + shadowOffset.x, tly + shadowOffset.y, ZERO ),
581                                           Vector2( ONE, ZERO ),
582                                           Vector3::ZERO ) );
583
584     vertices.push_back( MeshData::Vertex( Vector3( tlx + shadowOffset.x, bry + shadowOffset.y, ZERO ),
585                                           Vector2( ZERO, ONE ),
586                                           Vector3::ZERO ) );
587
588     vertices.push_back( MeshData::Vertex( Vector3( brx + shadowOffset.x, bry + shadowOffset.y, ZERO ),
589                                           Vector2::ONE,
590                                           Vector3::ZERO ) );
591
592     MeshData meshData;
593     Material newMaterial = Material::New("effect buffer");
594     newMaterial.SetDiffuseTexture( meshRecord.mBuffer );
595     meshData.SetMaterial( newMaterial );
596     meshData.SetVertices( vertices );
597     meshData.SetFaceIndices( mFace );
598     meshData.SetHasNormals( true );
599     meshData.SetHasColor( false );
600     meshData.SetHasTextureCoords( true );
601     MeshActor actor = MeshActor::New( Mesh::New( meshData ) );
602     actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
603     actor.SetShaderEffect( mBgraShader );
604     actor.SetFilterMode( FilterMode::LINEAR, FilterMode::LINEAR );
605     actor.SetSortModifier( 0.1f ); // force behind main text
606
607     // Create a sub actor to render once with normalized vertex positions
608     MeshData newMeshData;
609     MeshData::VertexContainer newVerts;
610     MeshData::FaceIndices newFaces;
611     MeshData::FaceIndices faces = meshRecord.mMeshData.GetFaces();
612     for ( uint32_t i = 0; i < verts.size(); ++i )
613     {
614       MeshData::Vertex vertex = verts[ i ];
615       vertex.x = ( ( vertex.x - tlx ) * divWidth ) - ONE;
616       vertex.y = ( ( vertex.y - tly ) * divHeight ) - ONE;
617       newVerts.push_back( vertex );
618     }
619
620     // Reverse triangle winding order
621     uint32_t faceCount = faces.size() / 3;
622     for ( uint32_t i = 0; i < faceCount; ++i )
623     {
624       uint32_t index = i * 3;
625       newFaces.push_back( faces[ index + 2 ] );
626       newFaces.push_back( faces[ index + 1 ] );
627       newFaces.push_back( faces[ index ] );
628     }
629
630     newMeshData.SetMaterial( meshRecord.mMeshData.GetMaterial() );
631     newMeshData.SetVertices( newVerts );
632     newMeshData.SetFaceIndices( newFaces );
633     newMeshData.SetHasNormals( true );
634     newMeshData.SetHasColor( false );
635     newMeshData.SetHasTextureCoords( true );
636
637     MeshActor subActor = MeshActor::New( Mesh::New( newMeshData ) );
638     subActor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
639     subActor.SetColor( shadowColor );
640     subActor.SetShaderEffect( mBasicShadowShader );
641     subActor.SetFilterMode( FilterMode::NEAREST, FilterMode::NEAREST );
642
643     // Create a render task to render the effect
644     RenderTask task = Stage::GetCurrent().GetRenderTaskList().CreateTask();
645     task.SetTargetFrameBuffer( meshRecord.mBuffer );
646     task.SetSourceActor( subActor );
647     task.SetClearEnabled( true );
648     task.SetClearColor( Vector4::ZERO );
649     task.SetExclusive( true );
650     task.SetRefreshRate( RenderTask::REFRESH_ONCE );
651     task.FinishedSignal().Connect( this, &AtlasRenderer::Impl::RenderComplete );
652     actor.Add( subActor );
653     return actor;
654   }
655
656   void RenderComplete( RenderTask& renderTask )
657   {
658     // Disconnect and remove this single shot render task
659     renderTask.FinishedSignal().Disconnect( this, &AtlasRenderer::Impl::RenderComplete );
660     Stage::GetCurrent().GetRenderTaskList().RemoveTask( renderTask );
661
662     // Get the actor used for render to buffer and remove it from the parent
663     Actor renderActor = renderTask.GetSourceActor();
664     if ( renderActor )
665     {
666       Actor parent = renderActor.GetParent();
667       if ( parent )
668       {
669         parent.Remove( renderActor );
670       }
671     }
672   }
673
674   RenderableActor mActor;                             ///< The actor parent which renders the text
675   AtlasGlyphManager mGlyphManager;                    ///< Glyph Manager to handle upload and caching
676   Vector< uint32_t > mImageIds;                       ///< A list of imageIDs used by the renderer
677   TextAbstraction::FontClient mFontClient;            ///> The font client used to supply glyph information
678   ShaderEffect mBasicShader;                          ///> Shader used to render L8 glyphs
679   ShaderEffect mBgraShader;                           ///> Shader used to render BGRA glyphs
680   ShaderEffect mBasicShadowShader;                    ///> Shader used to render drop shadow into buffer
681   std::vector< MaxBlockSize > mBlockSizes;            ///> Maximum size needed to contain a glyph in a block within a new atlas
682   std::vector< MeshData::FaceIndex > mFace;           ///> Face indices for a quad
683 };
684
685 Text::RendererPtr AtlasRenderer::New()
686 {
687   return Text::RendererPtr( new AtlasRenderer() );
688 }
689
690 RenderableActor AtlasRenderer::Render( Text::ViewInterface& view )
691 {
692
693   UnparentAndReset( mImpl->mActor );
694
695   Text::Length numberOfGlyphs = view.GetNumberOfGlyphs();
696
697   if( numberOfGlyphs > 0 )
698   {
699     Vector<GlyphInfo> glyphs;
700     glyphs.Resize( numberOfGlyphs );
701
702     view.GetGlyphs( &glyphs[0], 0, numberOfGlyphs );
703
704     std::vector<Vector2> positions;
705     positions.resize( numberOfGlyphs );
706     view.GetGlyphPositions( &positions[0], 0, numberOfGlyphs );
707     mImpl->AddGlyphs( positions,
708                       glyphs,
709                       view.GetTextColor(),
710                       view.GetShadowOffset(),
711                       view.GetShadowColor(),
712                       view.IsUnderlineEnabled(),
713                       view.GetUnderlineColor(),
714                       view.GetUnderlineHeight() );
715   }
716   return mImpl->mActor;
717 }
718
719 AtlasRenderer::AtlasRenderer()
720 {
721   mImpl = new Impl();
722
723 }
724
725 AtlasRenderer::~AtlasRenderer()
726 {
727   delete mImpl;
728 }