Merge "Moves shader creation from Text Atlas Renderer to GlyphManager" into devel...
[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/devel-api/text-abstraction/font-client.h>
25
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/public-api/controls/control-depth-index-ranges.h>
29 #include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
30
31 using namespace Dali;
32 using namespace Dali::Toolkit;
33 using namespace Dali::Toolkit::Text;
34
35 namespace
36 {
37 #if defined(DEBUG_ENABLED)
38   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_RENDERING");
39 #endif
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 struct AtlasRenderer::Impl : public ConnectionTracker
49 {
50
51   enum Style
52   {
53     STYLE_NORMAL,
54     STYLE_DROP_SHADOW
55   };
56
57   struct MeshRecord
58   {
59     Vector4 mColor;
60     uint32_t mAtlasId;
61     AtlasManager::Mesh2D mMesh;
62     FrameBufferImage mBuffer;
63     bool mIsUnderline;
64   };
65
66   struct Extent
67   {
68     float mBaseLine;
69     float mLeft;
70     float mRight;
71     float mUnderlinePosition;
72     float mUnderlineThickness;
73     uint32_t mMeshRecordIndex;
74   };
75
76   struct AtlasRecord
77   {
78     uint32_t mImageId;
79     Text::GlyphIndex mIndex;
80   };
81
82   struct MaxBlockSize
83   {
84     FontId mFontId;
85     uint32_t mNeededBlockWidth;
86     uint32_t mNeededBlockHeight;
87   };
88
89   Impl()
90   {
91     mGlyphManager = AtlasGlyphManager::Get();
92     mFontClient = TextAbstraction::FontClient::Get();
93
94     mQuadVertexFormat[ "aPosition" ] = Property::VECTOR2;
95     mQuadVertexFormat[ "aTexCoord" ] = Property::VECTOR2;
96     mQuadIndexFormat[ "indices" ] = Property::UNSIGNED_INTEGER;
97   }
98
99   void AddGlyphs( const std::vector<Vector2>& positions,
100                   const Vector<GlyphInfo>& glyphs,
101                   const Vector4& textColor,
102                   const Vector2& shadowOffset,
103                   const Vector4& shadowColor,
104                   bool underlineEnabled,
105                   const Vector4& underlineColor,
106                   float underlineHeight )
107   {
108     AtlasManager::AtlasSlot slot;
109     std::vector< MeshRecord > meshContainer;
110     Vector< Extent > extents;
111
112     float currentUnderlinePosition = ZERO;
113     float currentUnderlineThickness = underlineHeight;
114     uint32_t currentBlockSize = 0;
115     FontId lastFontId = 0;
116     Style style = STYLE_NORMAL;
117
118     if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 )
119     {
120       style = STYLE_DROP_SHADOW;
121     }
122
123     if ( mImageIds.Size() )
124     {
125       // Unreference any currently used glyphs
126       RemoveText();
127     }
128
129     CalculateBlocksSize( glyphs );
130
131     for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
132     {
133       const GlyphInfo& glyph = glyphs[ i ];
134
135       // No operation for white space
136       if ( glyph.width && glyph.height )
137       {
138         // Are we still using the same fontId as previous
139         if ( glyph.fontId != lastFontId )
140         {
141           // We need to fetch fresh font underline metrics
142           FontMetrics fontMetrics;
143           mFontClient.GetFontMetrics( glyph.fontId, fontMetrics );
144           currentUnderlinePosition = ceil( fabsf( fontMetrics.underlinePosition ) );
145           float descender = ceil( fabsf( fontMetrics.descender ) );
146
147           if ( underlineHeight == ZERO )
148           {
149             currentUnderlineThickness = fontMetrics.underlineThickness;
150
151             // Ensure underline will be at least a pixel high
152             if ( currentUnderlineThickness < ONE )
153             {
154               currentUnderlineThickness = ONE;
155             }
156             else
157             {
158               currentUnderlineThickness = ceil( currentUnderlineThickness );
159             }
160           }
161
162           // Clamp the underline position at the font descender and check for ( as EFL describes it ) a broken font
163           if ( currentUnderlinePosition > descender )
164           {
165             currentUnderlinePosition = descender;
166           }
167           if ( ZERO == currentUnderlinePosition )
168           {
169             // Move offset down by one ( EFL behavior )
170             currentUnderlinePosition = ONE;
171           }
172         }
173
174         const Vector2& position = positions[ i ];
175         AtlasManager::Mesh2D newMesh;
176         mGlyphManager.Cached( glyph.fontId, glyph.index, slot );
177
178         if ( slot.mImageId )
179         {
180           // This glyph already exists so generate mesh data plugging in our supplied position
181           mGlyphManager.GenerateMeshData( slot.mImageId, position, newMesh );
182           mImageIds.PushBack( slot.mImageId );
183         }
184         else
185         {
186
187           // Select correct size for new atlas if needed....?
188           if ( lastFontId != glyph.fontId )
189           {
190             for ( uint32_t j = 0; j < mBlockSizes.size(); ++j )
191             {
192               if ( mBlockSizes[ j ].mFontId == glyph.fontId )
193               {
194                 currentBlockSize = j;
195                 mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_WIDTH,
196                                                DEFAULT_ATLAS_HEIGHT,
197                                                mBlockSizes[ j ].mNeededBlockWidth,
198                                                mBlockSizes[ j ].mNeededBlockHeight );
199               }
200             }
201           }
202
203           // Create a new image for the glyph
204           BufferImage bitmap = mFontClient.CreateBitmap( glyph.fontId, glyph.index );
205           if ( bitmap )
206           {
207             // Ensure that the next image will fit into the current block size
208             bool setSize = false;
209             if ( bitmap.GetWidth() > mBlockSizes[ currentBlockSize ].mNeededBlockWidth )
210             {
211               setSize = true;
212               mBlockSizes[ currentBlockSize ].mNeededBlockWidth = bitmap.GetWidth();
213             }
214             if ( bitmap.GetHeight() > mBlockSizes[ currentBlockSize ].mNeededBlockHeight )
215             {
216               setSize = true;
217               mBlockSizes[ currentBlockSize ].mNeededBlockHeight = bitmap.GetHeight();
218             }
219
220             if ( setSize )
221             {
222               mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_WIDTH,
223                                              DEFAULT_ATLAS_HEIGHT,
224                                              mBlockSizes[ currentBlockSize ].mNeededBlockWidth,
225                                              mBlockSizes[ currentBlockSize ].mNeededBlockHeight );
226             }
227
228             // Locate a new slot for our glyph
229             mGlyphManager.Add( glyph, bitmap, slot );
230
231             // Generate mesh data for this quad, plugging in our supplied position
232             if ( slot.mImageId )
233             {
234               mGlyphManager.GenerateMeshData( slot.mImageId, position, newMesh );
235               mImageIds.PushBack( slot.mImageId );
236             }
237           }
238         }
239         // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
240         StitchTextMesh( meshContainer,
241                         newMesh,
242                         extents,
243                         textColor,
244                         position.y + glyph.yBearing,
245                         currentUnderlinePosition,
246                         currentUnderlineThickness,
247                         slot );
248        lastFontId = glyph.fontId;
249       }
250     }
251
252     if ( underlineEnabled )
253     {
254       // Check to see if any of the text needs an underline
255       GenerateUnderlines( meshContainer, extents, underlineColor, textColor );
256     }
257
258     // For each MeshData object, create a mesh actor and add to the renderable actor
259     if ( meshContainer.size() )
260     {
261       for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt )
262       {
263         Actor actor = CreateMeshActor( *mIt );
264
265         // Create an effect if necessary
266         if ( style == STYLE_DROP_SHADOW )
267         {
268           actor.Add( GenerateShadow( *mIt, shadowOffset, shadowColor ) );
269         }
270
271         if ( mActor )
272         {
273           mActor.Add( actor );
274         }
275         else
276         {
277           mActor = actor;
278         }
279       }
280       mActor.OffStageSignal().Connect( this, &AtlasRenderer::Impl::OffStageDisconnect );
281     }
282 #if defined(DEBUG_ENABLED)
283     Toolkit::AtlasGlyphManager::Metrics metrics = mGlyphManager.GetMetrics();
284     DALI_LOG_INFO( gLogFilter, Debug::General, "TextAtlasRenderer::GlyphManager::GlyphCount: %i, AtlasCount: %i, TextureMemoryUse: %iK\n",
285                                                 metrics.mGlyphCount,
286                                                 metrics.mAtlasMetrics.mAtlasCount,
287                                                 metrics.mAtlasMetrics.mTextureMemoryUsed / 1024 );
288     for ( uint32_t i = 0; i < metrics.mAtlasMetrics.mAtlasCount; ++i )
289     {
290       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Atlas [%i] %sPixels: %s Size: %ix%i, BlockSize: %ix%i, BlocksUsed: %i/%i\n",
291                                                  i + 1, i > 8 ? "" : " ",
292                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mPixelFormat == Pixel::L8 ? "L8  " : "BGRA",
293                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mWidth,
294                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mHeight,
295                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mBlockWidth,
296                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mBlockHeight,
297                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mBlocksUsed,
298                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mTotalBlocks );
299     }
300 #endif
301   }
302
303   Actor CreateMeshActor( const MeshRecord& meshRecord )
304   {
305     PropertyBuffer quadVertices = PropertyBuffer::New( mQuadVertexFormat, meshRecord.mMesh.mVertices.Size() );
306     PropertyBuffer quadIndices = PropertyBuffer::New( mQuadIndexFormat, meshRecord.mMesh.mIndices.Size() );
307     quadVertices.SetData( const_cast< AtlasManager::Vertex2D* >( &meshRecord.mMesh.mVertices[ 0 ] ) );
308     quadIndices.SetData( const_cast< unsigned int* >( &meshRecord.mMesh.mIndices[ 0 ] ) );
309
310     Geometry quadGeometry = Geometry::New();
311     quadGeometry.AddVertexBuffer( quadVertices );
312     quadGeometry.SetIndexBuffer( quadIndices );
313
314     Material material = mGlyphManager.GetMaterial( meshRecord.mAtlasId );
315     Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, material );
316     Actor actor = Actor::New();
317     actor.AddRenderer( renderer );
318     actor.SetSize( 1.0f, 1.0f );
319     actor.SetColor( meshRecord.mColor );
320
321     if ( meshRecord.mIsUnderline )
322     {
323       actor.SetColorMode( USE_OWN_COLOR );
324     }
325     else
326     {
327       actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
328     }
329     return actor;
330   }
331
332   void StitchTextMesh( std::vector< MeshRecord >& meshContainer,
333                        AtlasManager::Mesh2D& newMesh,
334                        Vector< Extent >& extents,
335                        const Vector4& color,
336                        float baseLine,
337                        float underlinePosition,
338                        float underlineThickness,
339                        AtlasManager::AtlasSlot& slot )
340   {
341     if ( slot.mImageId )
342     {
343       float left = newMesh.mVertices[ 0 ].mPosition.x;
344       float right = newMesh.mVertices[ 1 ].mPosition.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->mMesh, newMesh );
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.mMesh = newMesh;
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     AtlasManager::Mesh2D newMesh;
481     unsigned short faceIndex = 0;
482     for ( Vector< Extent >::ConstIterator eIt = extents.Begin(); eIt != extents.End(); ++eIt )
483     {
484       AtlasManager::Vertex2D vert;
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       vert.mPosition.x = tlx;
497       vert.mPosition.y = baseLine;
498       vert.mTexCoords.x = ZERO;
499       vert.mTexCoords.y = ZERO;
500       newMesh.mVertices.PushBack( vert );
501
502       vert.mPosition.x = brx;
503       vert.mPosition.y = baseLine;
504       vert.mTexCoords.x = u;
505       newMesh.mVertices.PushBack( vert );
506
507       vert.mPosition.x = tlx;
508       vert.mPosition.y = baseLine + thickness;
509       vert.mTexCoords.x = ZERO;
510       vert.mTexCoords.y = v;
511       newMesh.mVertices.PushBack( vert );
512
513       vert.mPosition.x = brx;
514       vert.mPosition.y = baseLine + thickness;
515       vert.mTexCoords.x = u;
516       newMesh.mVertices.PushBack( vert );
517
518       // Six indices in counter clockwise winding
519       newMesh.mIndices.PushBack( faceIndex + 1u );
520       newMesh.mIndices.PushBack( faceIndex );
521       newMesh.mIndices.PushBack( faceIndex + 2u );
522       newMesh.mIndices.PushBack( faceIndex + 2u );
523       newMesh.mIndices.PushBack( faceIndex + 3u );
524       newMesh.mIndices.PushBack( faceIndex + 1u );
525       faceIndex += 4;
526
527       if ( underlineColor == textColor )
528       {
529         mGlyphManager.StitchMesh( meshRecords[ index ].mMesh, newMesh );
530       }
531       else
532       {
533         MeshRecord record;
534         record.mMesh = newMesh;
535         record.mAtlasId = meshRecords[ index ].mAtlasId;
536         record.mColor = underlineColor;
537         record.mIsUnderline = true;
538         meshRecords.push_back( record );
539       }
540     }
541   }
542
543   Actor GenerateShadow( MeshRecord& meshRecord,
544                         const Vector2& shadowOffset,
545                         const Vector4& shadowColor )
546   {
547     // Scan vertex buffer to determine width and height of effect buffer needed
548     const Vector< AtlasManager::Vertex2D >& verts = meshRecord.mMesh.mVertices;
549     float tlx = verts[ 0 ].mPosition.x;
550     float tly = verts[ 0 ].mPosition.y;
551     float brx = ZERO;
552     float bry = ZERO;
553
554     for ( uint32_t i = 0; i < verts.Size(); ++i )
555     {
556       if ( verts[ i ].mPosition.x < tlx )
557       {
558         tlx = verts[ i ].mPosition.x;
559       }
560       if ( verts[ i ].mPosition.y < tly )
561       {
562         tly = verts[ i ].mPosition.y;
563       }
564       if ( verts[ i ].mPosition.x > brx )
565       {
566         brx = verts[ i ].mPosition.x;
567       }
568       if ( verts[ i ].mPosition.y > bry )
569       {
570         bry = verts[ i ].mPosition.y;
571       }
572     }
573
574     float width = brx - tlx;
575     float height = bry - tly;
576     float divWidth = TWO / width;
577     float divHeight = TWO / height;
578
579     // Create a buffer to render to
580     meshRecord.mBuffer = FrameBufferImage::New( width, height );
581
582     // We will render a quad into this buffer
583     unsigned int indices[ 6 ] = { 1, 0, 2, 2, 3, 1 };
584     PropertyBuffer quadVertices = PropertyBuffer::New( mQuadVertexFormat, 4u );
585     PropertyBuffer quadIndices = PropertyBuffer::New( mQuadIndexFormat, sizeof(indices)/sizeof(indices[0]) );
586
587     AtlasManager::Vertex2D vertices[ 4 ] = {
588     { Vector2( tlx + shadowOffset.x, tly + shadowOffset.y ), Vector2( ZERO, ZERO ) },
589     { Vector2( brx + shadowOffset.x, tly + shadowOffset.y ), Vector2( ONE, ZERO ) },
590     { Vector2( tlx + shadowOffset.x, bry + shadowOffset.y ), Vector2( ZERO, ONE ) },
591     { Vector2( brx + shadowOffset.x, bry + shadowOffset.y ), Vector2( ONE, ONE ) } };
592
593     quadVertices.SetData( vertices );
594     quadIndices.SetData( indices );
595
596     Geometry quadGeometry = Geometry::New();
597     quadGeometry.AddVertexBuffer( quadVertices );
598     quadGeometry.SetIndexBuffer( quadIndices );
599
600     Sampler sampler = Sampler::New( meshRecord.mBuffer, "sTexture" );
601     Material material = Material::New( mGlyphManager.GetEffectBufferShader() );
602     material.AddSampler( sampler );
603
604     Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, material );
605
606     // Ensure shadow is behind the text...
607     renderer.SetDepthIndex( CONTENT_DEPTH_INDEX - 1 );
608     Actor actor = Actor::New();
609     actor.AddRenderer( renderer );
610     actor.SetSize( 1.0f, 1.0f );
611
612     // Create a sub actor to render the source with normalized vertex positions
613     Vector< AtlasManager::Vertex2D > normVertexList;
614     for ( uint32_t i = 0; i < verts.Size(); ++i )
615     {
616       AtlasManager::Vertex2D vertex = verts[ i ];
617       vertex.mPosition.x = ( ( vertex.mPosition.x - tlx ) * divWidth ) - ONE;
618       vertex.mPosition.y = ( ( vertex.mPosition.y - tly ) * divHeight ) - ONE;
619       normVertexList.PushBack( vertex );
620     }
621
622     PropertyBuffer normVertices = PropertyBuffer::New( mQuadVertexFormat, normVertexList.Size() );
623     PropertyBuffer normIndices = PropertyBuffer::New( mQuadIndexFormat, meshRecord.mMesh.mIndices.Size() );
624     normVertices.SetData( const_cast< AtlasManager::Vertex2D* >( &normVertexList[ 0 ] ) );
625     normIndices.SetData( const_cast< unsigned int* >( &meshRecord.mMesh.mIndices[ 0 ] ) );
626
627     Geometry normGeometry = Geometry::New();
628     normGeometry.AddVertexBuffer( normVertices );
629     normGeometry.SetIndexBuffer( normIndices );
630
631     Material normMaterial = Material::New( mGlyphManager.GetGlyphShadowShader() );
632     Sampler normSampler =  mGlyphManager.GetSampler( meshRecord.mAtlasId );
633     normMaterial.AddSampler( normSampler );
634     Dali::Renderer normRenderer = Dali::Renderer::New( normGeometry, normMaterial );
635     Actor subActor = Actor::New();
636     subActor.AddRenderer( normRenderer );
637     subActor.SetSize( 1.0f, 1.0f );
638     subActor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
639     subActor.SetColor( shadowColor );
640
641     // Create a render task to render the effect
642     RenderTask task = Stage::GetCurrent().GetRenderTaskList().CreateTask();
643     task.SetTargetFrameBuffer( meshRecord.mBuffer );
644     task.SetSourceActor( subActor );
645     task.SetClearEnabled( true );
646     task.SetClearColor( Vector4::ZERO );
647     task.SetExclusive( true );
648     task.SetRefreshRate( RenderTask::REFRESH_ONCE );
649     task.FinishedSignal().Connect( this, &AtlasRenderer::Impl::RenderComplete );
650     actor.Add( subActor );
651
652     return actor;
653   }
654
655   void RenderComplete( RenderTask& renderTask )
656   {
657     // Disconnect and remove this single shot render task
658     renderTask.FinishedSignal().Disconnect( this, &AtlasRenderer::Impl::RenderComplete );
659     Stage::GetCurrent().GetRenderTaskList().RemoveTask( renderTask );
660
661     // Get the actor used for render to buffer and remove it from the parent
662     Actor renderActor = renderTask.GetSourceActor();
663     if ( renderActor )
664     {
665       Actor parent = renderActor.GetParent();
666       if ( parent )
667       {
668         parent.Remove( renderActor );
669       }
670     }
671   }
672
673   Actor mActor;                                       ///< The actor parent which renders the text
674   AtlasGlyphManager mGlyphManager;                    ///< Glyph Manager to handle upload and caching
675   Vector< uint32_t > mImageIds;                       ///< A list of imageIDs used by the renderer
676   TextAbstraction::FontClient mFontClient;            ///> The font client used to supply glyph information
677   std::vector< MaxBlockSize > mBlockSizes;            ///> Maximum size needed to contain a glyph in a block within a new atlas
678   std::vector< uint32_t > mFace;                      ///> Face indices for a quad
679   Property::Map mQuadVertexFormat;
680   Property::Map mQuadIndexFormat;
681 };
682
683 Text::RendererPtr AtlasRenderer::New()
684 {
685   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Text::AtlasRenderer::New()\n" );
686
687   return Text::RendererPtr( new AtlasRenderer() );
688 }
689
690 Actor AtlasRenderer::Render( Text::ViewInterface& view )
691 {
692   UnparentAndReset( mImpl->mActor );
693
694   Length numberOfGlyphs = view.GetNumberOfGlyphs();
695
696   if( numberOfGlyphs > 0u )
697   {
698     Vector<GlyphInfo> glyphs;
699     glyphs.Resize( numberOfGlyphs );
700
701     std::vector<Vector2> positions;
702     positions.resize( numberOfGlyphs );
703
704     numberOfGlyphs = view.GetGlyphs( glyphs.Begin(),
705                                      &positions[0],
706                                      0u,
707                                      numberOfGlyphs );
708     glyphs.Resize( numberOfGlyphs );
709     positions.resize( numberOfGlyphs );
710
711     mImpl->AddGlyphs( positions,
712                       glyphs,
713                       view.GetTextColor(),
714                       view.GetShadowOffset(),
715                       view.GetShadowColor(),
716                       view.IsUnderlineEnabled(),
717                       view.GetUnderlineColor(),
718                       view.GetUnderlineHeight() );
719   }
720
721   return mImpl->mActor;
722 }
723
724 AtlasRenderer::AtlasRenderer()
725 {
726   mImpl = new Impl();
727
728 }
729
730 AtlasRenderer::~AtlasRenderer()
731 {
732   delete mImpl;
733 }