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