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