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