Added UNDERLINE_HEIGHT Property to override font metrics
[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
25 // INTERNAL INCLUDES
26 #include <dali-toolkit/internal/atlas-manager/atlas-manager.h>
27 #include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
28 #include <dali-toolkit/internal/text/rendering/shaders/text-basic-shader.h>
29 #include <dali-toolkit/internal/text/rendering/shaders/text-bgra-shader.h>
30 #include <dali-toolkit/internal/text/rendering/shaders/text-basic-shadow-shader.h>
31 #if defined(DEBUG_ENABLED)
32 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_ATLAS_RENDERER");
33 #endif
34
35 using namespace Dali;
36 using namespace Dali::Toolkit;
37 using namespace Dali::Toolkit::Text;
38
39 namespace
40 {
41   const Vector2 DEFAULT_ATLAS_SIZE( 512.0f, 512.0f );
42   const Vector2 DEFAULT_BLOCK_SIZE( 16.0f, 16.0f );
43   const Vector2 PADDING( 4.0f, 4.0f ); // Allow for variation in font glyphs
44   const float ZERO( 0.0f );
45   const float HALF( 0.5f );
46   const float ONE( 1.0f );
47   const float TWO( 2.0f );
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     Vector2 mNeededBlockSize;
88   };
89
90   Impl()
91   {
92     mGlyphManager = AtlasGlyphManager::Get();
93     mFontClient = TextAbstraction::FontClient::Get();
94     mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_SIZE, DEFAULT_BLOCK_SIZE );
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
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                 mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_SIZE, mBlockSizes[ j ].mNeededBlockSize );
200               }
201             }
202             lastFontId = glyph.fontId;
203           }
204
205           // Glyph doesn't currently exist in atlas so upload
206           BufferImage bitmap = mFontClient.CreateBitmap( glyph.fontId, glyph.index );
207
208           // Locate a new slot for our glyph
209           mGlyphManager.Add( glyph, bitmap, slot );
210
211           // Generate mesh data for this quad, plugging in our supplied position
212           if ( slot.mImageId )
213           {
214             mGlyphManager.GenerateMeshData( slot.mImageId, position, newMeshData );
215             mImageIds.PushBack( slot.mImageId );
216           }
217         }
218         // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
219         StitchTextMesh( meshContainer,
220                         newMeshData,
221                         extents,
222                         textColor,
223                         position.y + glyph.yBearing,
224                         currentUnderlinePosition,
225                         currentUnderlineThickness,
226                         slot );
227       }
228     }
229
230     if ( underlineEnabled )
231     {
232       // Check to see if any of the text needs an underline
233       GenerateUnderlines( meshContainer, extents, underlineColor, textColor );
234     }
235
236     // For each MeshData object, create a mesh actor and add to the renderable actor
237     if ( meshContainer.size() )
238     {
239       for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt )
240       {
241         MeshActor actor = MeshActor::New( Mesh::New( mIt->mMeshData ) );
242         actor.SetColor( mIt->mColor );
243         if ( mIt->mIsUnderline )
244         {
245           actor.SetColorMode( USE_OWN_COLOR );
246         }
247         else
248         {
249           actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
250         }
251
252         // Check to see what pixel format the shader should be
253         if ( mGlyphManager.GetPixelFormat( mIt->mAtlasId ) == Pixel::L8 )
254         {
255           // Create an effect if necessary
256           if ( style == STYLE_DROP_SHADOW )
257           {
258             actor.Add( GenerateShadow( *mIt, shadowOffset, shadowColor ) );
259           }
260           actor.SetShaderEffect( mBasicShader );
261         }
262         else
263         {
264           actor.SetShaderEffect( mBgraShader );
265         }
266
267         if ( mActor )
268         {
269           mActor.Add( actor );
270         }
271         else
272         {
273           mActor = actor;
274         }
275       }
276       mActor.OffStageSignal().Connect( this, &AtlasRenderer::Impl::OffStageDisconnect );
277     }
278 #if defined(DEBUG_ENABLED)
279     Toolkit::AtlasGlyphManager::Metrics metrics = mGlyphManager.GetMetrics();
280     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TextAtlasRenderer::GlyphManager::GlyphCount: %i, AtlasCount: %i, TextureMemoryUse: %iK\n",
281                                                 metrics.mGlyphCount,
282                                                 metrics.mAtlasMetrics.mAtlasCount,
283                                                 metrics.mAtlasMetrics.mTextureMemoryUsed / 1024 );
284     for ( uint32_t i = 0; i < metrics.mAtlasMetrics.mAtlasCount; ++i )
285     {
286       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Atlas [%i] %sPixels: %s Size: %ix%i, BlockSize: %ix%i, BlocksUsed: %i/%i\n",
287                                                  i + 1, i > 8 ? "" : " ",
288                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mPixelFormat == Pixel::L8 ? "L8  " : "BGRA",
289                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mWidth,
290                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mHeight,
291                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mBlockWidth,
292                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mBlockHeight,
293                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mBlocksUsed,
294                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mTotalBlocks );
295     }
296 #endif
297   }
298
299   void StitchTextMesh( std::vector< MeshRecord >& meshContainer,
300                        MeshData& newMeshData,
301                        Vector< Extent >& extents,
302                        const Vector4& color,
303                        float baseLine,
304                        float underlinePosition,
305                        float underlineThickness,
306                        AtlasManager::AtlasSlot& slot )
307   {
308     if ( slot.mImageId )
309     {
310       MeshData::VertexContainer verts = newMeshData.GetVertices();
311       float left = verts[ 0 ].x;
312       float right = verts[ 1 ].x;
313
314       // Check to see if there's a mesh data object that references the same atlas ?
315       uint32_t index = 0;
316       for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt, ++index )
317       {
318         if ( slot.mAtlasId == mIt->mAtlasId && color == mIt->mColor )
319         {
320           // Stitch the mesh to the existing mesh and adjust any extents
321           mGlyphManager.StitchMesh( mIt->mMeshData, newMeshData );
322           AdjustExtents( extents,
323                          meshContainer,
324                          index,
325                          left,
326                          right,
327                          baseLine,
328                          underlinePosition,
329                          underlineThickness );
330           return;
331         }
332       }
333
334       // No mesh data object currently exists that references this atlas, so create a new one
335       MeshRecord meshRecord;
336       meshRecord.mAtlasId = slot.mAtlasId;
337       meshRecord.mMeshData = newMeshData;
338       meshRecord.mColor = color;
339       meshRecord.mIsUnderline = false;
340       meshContainer.push_back( meshRecord );
341
342       // Adjust extents for this new meshrecord
343       AdjustExtents( extents,
344                      meshContainer,
345                      meshContainer.size() - 1u,
346                      left,
347                      right,
348                      baseLine,
349                      underlinePosition,
350                      underlineThickness );
351
352     }
353   }
354
355   void AdjustExtents( Vector< Extent >& extents,
356                       std::vector< MeshRecord>& meshRecords,
357                       uint32_t index,
358                       float left,
359                       float right,
360                       float baseLine,
361                       float underlinePosition,
362                       float underlineThickness )
363   {
364     bool foundExtent = false;
365     for ( Vector< Extent >::Iterator eIt = extents.Begin(); eIt != extents.End(); ++eIt )
366     {
367       if ( Equals( baseLine, eIt->mBaseLine ) )
368       {
369         foundExtent = true;
370         if ( left < eIt->mLeft )
371         {
372           eIt->mLeft = left;
373         }
374         if ( right > eIt->mRight  )
375         {
376           eIt->mRight = right;
377         }
378
379         if ( underlinePosition > eIt->mUnderlinePosition )
380         {
381           eIt->mUnderlinePosition = underlinePosition;
382         }
383         if ( underlineThickness > eIt->mUnderlineThickness )
384         {
385           eIt->mUnderlineThickness = underlineThickness;
386         }
387       }
388     }
389     if ( !foundExtent )
390     {
391       Extent extent;
392       extent.mLeft = left;
393       extent.mRight = right;
394       extent.mBaseLine = baseLine;
395       extent.mUnderlinePosition = underlinePosition;
396       extent.mUnderlineThickness = underlineThickness;
397       extent.mMeshRecordIndex = index;
398       extents.PushBack( extent );
399     }
400   }
401
402   // Unreference any glyphs that were used with this actor
403   void OffStageDisconnect( Dali::Actor actor )
404   {
405     RemoveText();
406   }
407
408   void RemoveText()
409   {
410     for ( uint32_t i = 0; i < mImageIds.Size(); ++i )
411     {
412       mGlyphManager.Remove( mImageIds[ i ] );
413     }
414     mImageIds.Resize( 0 );
415   }
416
417   void CalculateBlocksSize( const Vector<GlyphInfo>& glyphs )
418   {
419     MaxBlockSize maxBlockSize;
420     for ( uint32_t i = 0; i < glyphs.Size(); ++i )
421     {
422       // Get the fontId of this glyph and check to see if a max size exists?
423       FontId fontId = glyphs[ i ].fontId;
424       float paddedWidth = glyphs[ i ].width + PADDING.x;
425       float paddedHeight = glyphs[ i ].height + PADDING.y;
426       bool foundFont = false;
427
428       for ( uint32_t j = 0; j < mBlockSizes.size(); ++j )
429       {
430         if ( mBlockSizes[ j ].mFontId == fontId )
431         {
432           foundFont = true;
433           if ( mBlockSizes[ j ].mNeededBlockSize.x < paddedWidth )
434           {
435             mBlockSizes[ j ].mNeededBlockSize.x = paddedWidth;
436           }
437           if ( mBlockSizes[ j ].mNeededBlockSize.y < paddedHeight )
438           {
439             mBlockSizes[ j ].mNeededBlockSize.y = paddedHeight;
440           }
441         }
442       }
443
444       if ( !foundFont )
445       {
446         maxBlockSize.mNeededBlockSize = Vector2( paddedWidth, paddedHeight );
447         maxBlockSize.mFontId = fontId;
448         mBlockSizes.push_back( maxBlockSize );
449       }
450     }
451   }
452
453   void GenerateUnderlines( std::vector< MeshRecord>& meshRecords,
454                            Vector< Extent >& extents,
455                            const Vector4& underlineColor,
456                            const Vector4& textColor )
457   {
458     MeshData newMeshData;
459     for ( Vector< Extent >::ConstIterator eIt = extents.Begin(); eIt != extents.End(); ++eIt )
460     {
461       MeshData::VertexContainer newVerts;
462       newVerts.reserve( 4u );
463       uint32_t index = eIt->mMeshRecordIndex;
464       Vector2 uv = mGlyphManager.GetAtlasSize( meshRecords[ index ].mAtlasId );
465
466       // Make sure we don't hit texture edge for single pixel texture ( filled pixel is in top left of every atlas )
467       float u = HALF / uv.x;
468       float v = HALF / uv.y;
469       float thickness = eIt->mUnderlineThickness;
470       float baseLine = eIt->mBaseLine + eIt->mUnderlinePosition - ( thickness * HALF );
471       float tlx = eIt->mLeft;
472       float brx = eIt->mRight;
473
474       newVerts.push_back( MeshData::Vertex( Vector3( tlx, baseLine, ZERO ),
475                                             Vector2::ZERO,
476                                             Vector3::ZERO ) );
477
478       newVerts.push_back( MeshData::Vertex( Vector3( brx, baseLine, ZERO ),
479                                             Vector2( u, ZERO ),
480                                             Vector3::ZERO ) );
481
482       newVerts.push_back( MeshData::Vertex( Vector3( tlx, baseLine + thickness, ZERO ),
483                                             Vector2( ZERO, v ),
484                                             Vector3::ZERO ) );
485
486       newVerts.push_back( MeshData::Vertex( Vector3( brx, baseLine + thickness, ZERO ),
487                                             Vector2( u, v ),
488                                             Vector3::ZERO ) );
489
490       newMeshData.SetVertices( newVerts );
491       newMeshData.SetFaceIndices( mFace );
492
493       if ( underlineColor == textColor )
494       {
495         mGlyphManager.StitchMesh( meshRecords[ index ].mMeshData, newMeshData );
496       }
497       else
498       {
499         MeshRecord record;
500         newMeshData.SetMaterial( meshRecords[ index ].mMeshData.GetMaterial() );
501         newMeshData.SetHasNormals( true );
502         newMeshData.SetHasColor( false );
503         newMeshData.SetHasTextureCoords( true );
504         record.mMeshData = newMeshData;
505         record.mAtlasId = meshRecords[ index ].mAtlasId;
506         record.mColor = underlineColor;
507         record.mIsUnderline = true;
508         meshRecords.push_back( record );
509       }
510     }
511   }
512
513   MeshActor GenerateShadow( MeshRecord& meshRecord,
514                             const Vector2& shadowOffset,
515                             const Vector4& shadowColor )
516   {
517     // Scan vertex buffer to determine width and height of effect buffer needed
518     MeshData::VertexContainer verts = meshRecord.mMeshData.GetVertices();
519     float tlx = verts[ 0 ].x;
520     float tly = verts[ 0 ].y;
521     float brx = ZERO;
522     float bry = ZERO;
523
524     for ( uint32_t i = 0; i < verts.size(); ++i )
525     {
526       if ( verts[ i ].x < tlx )
527       {
528         tlx = verts[ i ].x;
529       }
530       if ( verts[ i ].y < tly )
531       {
532         tly = verts[ i ].y;
533       }
534       if ( verts[ i ].x > brx )
535       {
536         brx = verts[ i ].x;
537       }
538       if ( verts[ i ].y > bry )
539       {
540         bry = verts[ i ].y;
541       }
542     }
543
544     float width = brx - tlx;
545     float height = bry - tly;
546     float divWidth = TWO / width;
547     float divHeight = TWO / height;
548
549     // Create a buffer to render to
550     meshRecord.mBuffer = FrameBufferImage::New( width, height );
551
552     // Create a mesh actor to contain the post-effect render
553     MeshData::VertexContainer vertices;
554     MeshData::FaceIndices face;
555
556     vertices.push_back( MeshData::Vertex( Vector3( tlx + shadowOffset.x, tly + shadowOffset.y, ZERO ),
557                                           Vector2::ZERO,
558                                           Vector3::ZERO ) );
559
560     vertices.push_back( MeshData::Vertex( Vector3( brx + shadowOffset.x, tly + shadowOffset.y, ZERO ),
561                                           Vector2( ONE, ZERO ),
562                                           Vector3::ZERO ) );
563
564     vertices.push_back( MeshData::Vertex( Vector3( tlx + shadowOffset.x, bry + shadowOffset.y, ZERO ),
565                                           Vector2( ZERO, ONE ),
566                                           Vector3::ZERO ) );
567
568     vertices.push_back( MeshData::Vertex( Vector3( brx + shadowOffset.x, bry + shadowOffset.y, ZERO ),
569                                           Vector2::ONE,
570                                           Vector3::ZERO ) );
571
572     MeshData meshData;
573     Material newMaterial = Material::New("effect buffer");
574     newMaterial.SetDiffuseTexture( meshRecord.mBuffer );
575     meshData.SetMaterial( newMaterial );
576     meshData.SetVertices( vertices );
577     meshData.SetFaceIndices( mFace );
578     meshData.SetHasNormals( true );
579     meshData.SetHasColor( false );
580     meshData.SetHasTextureCoords( true );
581     MeshActor actor = MeshActor::New( Mesh::New( meshData ) );
582     actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
583     actor.SetShaderEffect( mBgraShader );
584     actor.SetFilterMode( FilterMode::LINEAR, FilterMode::LINEAR );
585     actor.SetSortModifier( 0.1f ); // force behind main text
586
587     // Create a sub actor to render once with normalized vertex positions
588     MeshData newMeshData;
589     MeshData::VertexContainer newVerts;
590     MeshData::FaceIndices newFaces;
591     MeshData::FaceIndices faces = meshRecord.mMeshData.GetFaces();
592     for ( uint32_t i = 0; i < verts.size(); ++i )
593     {
594       MeshData::Vertex vertex = verts[ i ];
595       vertex.x = ( ( vertex.x - tlx ) * divWidth ) - ONE;
596       vertex.y = ( ( vertex.y - tly ) * divHeight ) - ONE;
597       newVerts.push_back( vertex );
598     }
599
600     // Reverse triangle winding order
601     uint32_t faceCount = faces.size() / 3;
602     for ( uint32_t i = 0; i < faceCount; ++i )
603     {
604       uint32_t index = i * 3;
605       newFaces.push_back( faces[ index + 2 ] );
606       newFaces.push_back( faces[ index + 1 ] );
607       newFaces.push_back( faces[ index ] );
608     }
609
610     newMeshData.SetMaterial( meshRecord.mMeshData.GetMaterial() );
611     newMeshData.SetVertices( newVerts );
612     newMeshData.SetFaceIndices( newFaces );
613     newMeshData.SetHasNormals( true );
614     newMeshData.SetHasColor( false );
615     newMeshData.SetHasTextureCoords( true );
616
617     MeshActor subActor = MeshActor::New( Mesh::New( newMeshData ) );
618     subActor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
619     subActor.SetColor( shadowColor );
620     subActor.SetShaderEffect( mBasicShadowShader );
621     subActor.SetFilterMode( FilterMode::NEAREST, FilterMode::NEAREST );
622
623     // Create a render task to render the effect
624     RenderTask task = Stage::GetCurrent().GetRenderTaskList().CreateTask();
625     task.SetTargetFrameBuffer( meshRecord.mBuffer );
626     task.SetSourceActor( subActor );
627     task.SetClearEnabled( true );
628     task.SetClearColor( Vector4::ZERO );
629     task.SetExclusive( true );
630     task.SetRefreshRate( RenderTask::REFRESH_ONCE );
631     task.FinishedSignal().Connect( this, &AtlasRenderer::Impl::RenderComplete );
632     actor.Add( subActor );
633     return actor;
634   }
635
636   void RenderComplete( RenderTask& renderTask )
637   {
638     // Disconnect and remove this single shot render task
639     renderTask.FinishedSignal().Disconnect( this, &AtlasRenderer::Impl::RenderComplete );
640     Stage::GetCurrent().GetRenderTaskList().RemoveTask( renderTask );
641
642     // Get the actor used for render to buffer and remove it from the parent
643     Actor renderActor = renderTask.GetSourceActor();
644     if ( renderActor )
645     {
646       Actor parent = renderActor.GetParent();
647       if ( parent )
648       {
649         parent.Remove( renderActor );
650       }
651     }
652   }
653
654   RenderableActor mActor;                             ///< The actor parent which renders the text
655   AtlasGlyphManager mGlyphManager;                    ///< Glyph Manager to handle upload and caching
656   Vector< uint32_t > mImageIds;                       ///< A list of imageIDs used by the renderer
657   TextAbstraction::FontClient mFontClient;            ///> The font client used to supply glyph information
658   ShaderEffect mBasicShader;                          ///> Shader used to render L8 glyphs
659   ShaderEffect mBgraShader;                           ///> Shader used to render BGRA glyphs
660   ShaderEffect mBasicShadowShader;                    ///> Shader used to render drop shadow into buffer
661   std::vector< MaxBlockSize > mBlockSizes;            ///> Maximum size needed to contain a glyph in a block within a new atlas
662   std::vector< MeshData::FaceIndex > mFace;           ///> Face indices for a quad
663 };
664
665 Text::RendererPtr AtlasRenderer::New()
666 {
667   return Text::RendererPtr( new AtlasRenderer() );
668 }
669
670 RenderableActor AtlasRenderer::Render( Text::ViewInterface& view )
671 {
672
673   UnparentAndReset( mImpl->mActor );
674
675   Text::Length numberOfGlyphs = view.GetNumberOfGlyphs();
676
677   if( numberOfGlyphs > 0 )
678   {
679     Vector<GlyphInfo> glyphs;
680     glyphs.Resize( numberOfGlyphs );
681
682     view.GetGlyphs( &glyphs[0], 0, numberOfGlyphs );
683
684     std::vector<Vector2> positions;
685     positions.resize( numberOfGlyphs );
686     view.GetGlyphPositions( &positions[0], 0, numberOfGlyphs );
687     mImpl->AddGlyphs( positions,
688                       glyphs,
689                       view.GetTextColor(),
690                       view.GetShadowOffset(),
691                       view.GetShadowColor(),
692                       view.IsUnderlineEnabled(),
693                       view.GetUnderlineColor(),
694                       view.GetUnderlineHeight() );
695   }
696   return mImpl->mActor;
697 }
698
699 AtlasRenderer::AtlasRenderer()
700 {
701   mImpl = new Impl();
702
703 }
704
705 AtlasRenderer::~AtlasRenderer()
706 {
707   delete mImpl;
708 }