Atlas manager using old block size for new atlas creation
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / rendering / atlas / text-atlas-renderer.cpp
1 /*
2  * Copyright (c) 2016 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/public-api/rendering/geometry.h>
23 #include <dali/public-api/rendering/renderer.h>
24 #include <dali/public-api/images/frame-buffer-image.h>
25 #include <dali/devel-api/text-abstraction/font-client.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/public-api/animation/constraints.h>
28
29 // INTERNAL INCLUDES
30 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
31 #include <dali-toolkit/internal/text/glyph-run.h>
32 #include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
33 #include <dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h>
34 #include <dali-toolkit/internal/text/text-view.h>
35
36 using namespace Dali;
37 using namespace Dali::Toolkit;
38 using namespace Dali::Toolkit::Text;
39
40 namespace
41 {
42 #if defined(DEBUG_ENABLED)
43   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_RENDERING");
44 #endif
45
46 #define MAKE_SHADER(A)#A
47
48 const char* VERTEX_SHADER = MAKE_SHADER(
49 attribute mediump vec2    aPosition;
50 attribute mediump vec2    aTexCoord;
51 attribute mediump vec4    aColor;
52 uniform   mediump vec2    uOffset;
53 uniform   mediump mat4    uMvpMatrix;
54 varying   mediump vec2    vTexCoord;
55 varying   mediump vec4    vColor;
56
57 void main()
58 {
59   mediump vec4 position = vec4( aPosition.xy + uOffset, 0.0, 1.0 );
60   gl_Position = uMvpMatrix * position;
61   vTexCoord = aTexCoord;
62   vColor = aColor;
63 }
64 );
65
66 const char* FRAGMENT_SHADER_L8 = MAKE_SHADER(
67 uniform lowp    vec4      uColor;
68 uniform lowp    vec4      textColorAnimatable;
69 uniform         sampler2D sTexture;
70 varying mediump vec2      vTexCoord;
71 varying mediump vec4      vColor;
72
73 void main()
74 {
75   mediump vec4 color = texture2D( sTexture, vTexCoord );
76   gl_FragColor = vec4( vColor.rgb * uColor.rgb * textColorAnimatable.rgb, uColor.a * vColor.a * textColorAnimatable.a * color.r );
77 }
78 );
79
80 const char* FRAGMENT_SHADER_RGBA = MAKE_SHADER(
81 uniform lowp    vec4      uColor;
82 uniform lowp    vec4      textColorAnimatable;
83 uniform         sampler2D sTexture;
84 varying mediump vec2      vTexCoord;
85
86 void main()
87 {
88   gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor * textColorAnimatable;
89 }
90 );
91
92 const float ZERO( 0.0f );
93 const float HALF( 0.5f );
94 const float ONE( 1.0f );
95 const uint32_t DEFAULT_ATLAS_WIDTH = 512u;
96 const uint32_t DEFAULT_ATLAS_HEIGHT = 512u;
97 }
98
99 struct AtlasRenderer::Impl
100 {
101   enum Style
102   {
103     STYLE_NORMAL,
104     STYLE_DROP_SHADOW
105   };
106
107   struct MeshRecord
108   {
109     MeshRecord()
110     : mAtlasId( 0u )
111     {
112     }
113
114     uint32_t mAtlasId;
115     AtlasManager::Mesh2D mMesh;
116     FrameBufferImage mBuffer;
117   };
118
119   /**
120    * brief Struct used to generate the underline mesh.
121    * There is one Extent per line of text.
122    */
123   struct Extent
124   {
125     Extent()
126     : mBaseLine( 0.0f ),
127       mLeft( 0.0f ),
128       mRight( 0.0f ),
129       mUnderlinePosition( 0.0f ),
130       mUnderlineThickness( 0.0f ),
131       mMeshRecordIndex( 0u )
132     {
133     }
134
135     float mBaseLine;
136     float mLeft;
137     float mRight;
138     float mUnderlinePosition;
139     float mUnderlineThickness;
140     uint32_t mMeshRecordIndex;
141   };
142
143   struct MaxBlockSize
144   {
145     MaxBlockSize()
146     : mFontId( 0 ),
147       mNeededBlockWidth( 0 ),
148       mNeededBlockHeight( 0 )
149     {
150     }
151
152     FontId mFontId;
153     uint32_t mNeededBlockWidth;
154     uint32_t mNeededBlockHeight;
155   };
156
157   struct CheckEntry
158   {
159     CheckEntry()
160     : mFontId( 0 ),
161       mIndex( 0 )
162     {
163     }
164
165     FontId mFontId;
166     Text::GlyphIndex mIndex;
167   };
168
169   struct TextCacheEntry
170   {
171     TextCacheEntry()
172     : mFontId( 0 ),
173       mIndex( 0 ),
174       mImageId( 0 )
175     {
176     }
177
178     FontId mFontId;
179     Text::GlyphIndex mIndex;
180     uint32_t mImageId;
181   };
182
183   Impl()
184   : mDepth( 0 )
185   {
186     mGlyphManager = AtlasGlyphManager::Get();
187     mFontClient = TextAbstraction::FontClient::Get();
188
189     mQuadVertexFormat[ "aPosition" ] = Property::VECTOR2;
190     mQuadVertexFormat[ "aTexCoord" ] = Property::VECTOR2;
191     mQuadVertexFormat[ "aColor" ] = Property::VECTOR4;
192   }
193
194   bool IsGlyphUnderlined( GlyphIndex index,
195                           const Vector<GlyphRun>& underlineRuns )
196   {
197     for( Vector<GlyphRun>::ConstIterator it = underlineRuns.Begin(),
198            endIt = underlineRuns.End();
199            it != endIt;
200          ++it )
201     {
202       const GlyphRun& run = *it;
203
204       if( ( run.glyphIndex <= index ) && ( index < run.glyphIndex + run.numberOfGlyphs ) )
205       {
206         return true;
207       }
208     }
209
210     return false;
211   }
212
213   void AddGlyphs( Text::ViewInterface& view,
214                   Actor textControl,
215                   Property::Index animatablePropertyIndex,
216                   const Vector<Vector2>& positions,
217                   const Vector<GlyphInfo>& glyphs,
218                   const Vector4& defaultColor,
219                   const Vector4* const colorsBuffer,
220                   const ColorIndex* const colorIndicesBuffer,
221                   int depth,
222                   float minLineOffset )
223   {
224     AtlasManager::AtlasSlot slot;
225     std::vector< MeshRecord > meshContainer;
226     Vector< Extent > extents;
227     TextCacheEntry textCacheEntry;
228     mDepth = depth;
229
230     const Vector2& textSize( view.GetLayoutSize() );
231     const Vector2 halfTextSize( textSize * 0.5f );
232     const Vector2& shadowOffset( view.GetShadowOffset() );
233     const Vector4& shadowColor( view.GetShadowColor() );
234     const bool underlineEnabled( view.IsUnderlineEnabled() );
235     const Vector4& underlineColor( view.GetUnderlineColor() );
236     const float underlineHeight( view.GetUnderlineHeight() );
237
238     const bool useDefaultColor = ( NULL == colorsBuffer );
239
240     // Get the underline runs.
241     const Length numberOfUnderlineRuns = view.GetNumberOfUnderlineRuns();
242     Vector<GlyphRun> underlineRuns;
243     underlineRuns.Resize( numberOfUnderlineRuns );
244     view.GetUnderlineRuns( underlineRuns.Begin(),
245                            0u,
246                            numberOfUnderlineRuns );
247
248     bool thereAreUnderlinedGlyphs = false;
249
250     float currentUnderlinePosition = ZERO;
251     float currentUnderlineThickness = underlineHeight;
252     uint32_t currentBlockSize = 0;
253     FontId lastFontId = 0;
254     FontId lastUnderlinedFontId = 0;
255     Style style = STYLE_NORMAL;
256
257     if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 )
258     {
259       style = STYLE_DROP_SHADOW;
260     }
261
262     CalculateBlocksSize( glyphs );
263
264     // Avoid emptying mTextCache (& removing references) until after incremented references for the new text
265     Vector< TextCacheEntry > newTextCache;
266     const GlyphInfo* const glyphsBuffer = glyphs.Begin();
267     const Vector2* const positionsBuffer = positions.Begin();
268     const Vector2 lineOffsetPosition( minLineOffset, 0.f );
269
270     for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
271     {
272       const GlyphInfo& glyph = *( glyphsBuffer + i );
273       const bool underlineGlyph = underlineEnabled || IsGlyphUnderlined( i, underlineRuns );
274       thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || underlineGlyph;
275
276       // No operation for white space
277       if( glyph.width && glyph.height )
278       {
279         // Are we still using the same fontId as previous
280         if( underlineGlyph && ( glyph.fontId != lastUnderlinedFontId ) )
281         {
282           // We need to fetch fresh font underline metrics
283           FontMetrics fontMetrics;
284           mFontClient.GetFontMetrics( glyph.fontId, fontMetrics );
285           currentUnderlinePosition = ceil( fabsf( fontMetrics.underlinePosition ) );
286           const float descender = ceil( fabsf( fontMetrics.descender ) );
287
288           if( fabsf( underlineHeight ) < Math::MACHINE_EPSILON_1000 )
289           {
290             currentUnderlineThickness = fontMetrics.underlineThickness;
291
292             // Ensure underline will be at least a pixel high
293             if ( currentUnderlineThickness < ONE )
294             {
295               currentUnderlineThickness = ONE;
296             }
297             else
298             {
299               currentUnderlineThickness = ceil( currentUnderlineThickness );
300             }
301           }
302
303           // Clamp the underline position at the font descender and check for ( as EFL describes it ) a broken font
304           if( currentUnderlinePosition > descender )
305           {
306             currentUnderlinePosition = descender;
307           }
308
309           if( fabsf( currentUnderlinePosition ) < Math::MACHINE_EPSILON_1000 )
310           {
311             // Move offset down by one ( EFL behavior )
312             currentUnderlinePosition = ONE;
313           }
314
315           lastUnderlinedFontId = glyph.fontId;
316         } // underline
317
318         bool glyphNotCached = !mGlyphManager.IsCached( glyph.fontId, glyph.index, slot );  // Check FontGlyphRecord vector for entry with glyph index and fontId
319
320         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "AddGlyphs fontID[%u] glyphIndex[%u] [%s]\n", glyph.fontId, glyph.index, (glyphNotCached)?"not cached":"cached" );
321
322         if( glyphNotCached )
323         {
324           MaxBlockSize& blockSize = mBlockSizes[currentBlockSize];
325
326           if ( lastFontId != glyph.fontId )
327           {
328             uint32_t index = 0u;
329             // Looks through all stored block sizes until finds the one which mataches required glyph font it.  Ensures new atlas block size will match existing for same font id.
330             // CalculateBlocksSize() above ensures a block size entry exists.
331             for( std::vector<MaxBlockSize>::const_iterator it = mBlockSizes.begin(),
332                    endIt = mBlockSizes.end();
333                  it != endIt;
334                  ++it, ++index )
335             {
336               const MaxBlockSize& blockSizeEntry = *it;
337               if( blockSizeEntry.mFontId == glyph.fontId )
338               {
339                 blockSize = mBlockSizes[index];
340               }
341             }
342           }
343
344           // Create a new image for the glyph
345           PixelData bitmap;
346
347           // Whether the current glyph is a color one.
348           const bool isColorGlyph = mFontClient.IsColorGlyph( glyph.fontId, glyph.index );
349
350           // Retrieve the emoji's bitmap.
351           TextAbstraction::FontClient::GlyphBufferData glyphBufferData;
352           glyphBufferData.width = isColorGlyph ? glyph.width : 0;   // Desired width and height.
353           glyphBufferData.height = isColorGlyph ? glyph.height : 0;
354
355           mFontClient.CreateBitmap( glyph.fontId,
356                                     glyph.index,
357                                     glyphBufferData );
358
359           // Create the pixel data.
360           bitmap = PixelData::New( glyphBufferData.buffer,
361                                    glyph.width * glyph.height * GetBytesPerPixel( glyphBufferData.format ),
362                                    glyph.width,
363                                    glyph.height,
364                                    glyphBufferData.format,
365                                    PixelData::DELETE_ARRAY );
366
367           if( bitmap )
368           {
369             // Ensure that the next image will fit into the current block size
370             if( bitmap.GetWidth() > blockSize.mNeededBlockWidth )
371             {
372               blockSize.mNeededBlockWidth = bitmap.GetWidth();
373             }
374
375             if( bitmap.GetHeight() > blockSize.mNeededBlockHeight )
376             {
377               blockSize.mNeededBlockHeight = bitmap.GetHeight();
378             }
379
380             // If CheckAtlas in AtlasManager::Add can't fit the bitmap in the current atlas it will create a new atlas
381
382             // Setting the block size and size of new atlas does not mean a new one will be created. An existing atlas may still surffice.
383             mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_WIDTH,
384                                            DEFAULT_ATLAS_HEIGHT,
385                                            blockSize.mNeededBlockWidth,
386                                            blockSize.mNeededBlockHeight );
387
388             // Locate a new slot for our glyph
389             mGlyphManager.Add( glyph, bitmap, slot ); // slot will be 0 is glyph not added
390           }
391         }
392         else
393         {
394           // We have 2+ copies of the same glyph
395           mGlyphManager.AdjustReferenceCount( glyph.fontId, glyph.index, 1/*increment*/ );
396         }
397
398         // Move the origin (0,0) of the mesh to the center of the actor
399         const Vector2 position = *( positionsBuffer + i ) - halfTextSize - lineOffsetPosition;
400
401         if ( 0u != slot.mImageId ) // invalid slot id, glyph has failed to be added to atlas
402         {
403           // Generate mesh data for this quad, plugging in our supplied position
404           AtlasManager::Mesh2D newMesh;
405           mGlyphManager.GenerateMeshData( slot.mImageId, position, newMesh );
406           textCacheEntry.mFontId = glyph.fontId;
407           textCacheEntry.mImageId = slot.mImageId;
408           textCacheEntry.mIndex = glyph.index;
409           newTextCache.PushBack( textCacheEntry );
410
411           AtlasManager::Vertex2D* verticesBuffer = newMesh.mVertices.Begin();
412
413           // Get the color of the character.
414           const ColorIndex colorIndex = useDefaultColor ? 0u : *( colorIndicesBuffer + i );
415           const Vector4& color = ( useDefaultColor || ( 0u == colorIndex ) ) ? defaultColor : *( colorsBuffer + colorIndex - 1u );
416
417           for( unsigned int index = 0u, size = newMesh.mVertices.Count();
418                index < size;
419                ++index )
420           {
421             AtlasManager::Vertex2D& vertex = *( verticesBuffer + index );
422
423             // Set the color of the vertex.
424             vertex.mColor = color;
425           }
426
427           // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
428           StitchTextMesh( meshContainer,
429                           newMesh,
430                           extents,
431                           position.y + glyph.yBearing,
432                           underlineGlyph,
433                           currentUnderlinePosition,
434                           currentUnderlineThickness,
435                           slot );
436
437           lastFontId = glyph.fontId; // Prevents searching for existing blocksizes when string of the same fontId.
438         }
439       }
440     } // glyphs
441
442     // Now remove references for the old text
443     RemoveText();
444     mTextCache.Swap( newTextCache );
445
446     if( thereAreUnderlinedGlyphs )
447     {
448       // Check to see if any of the text needs an underline
449       GenerateUnderlines( meshContainer, extents, underlineColor );
450     }
451
452     // For each MeshData object, create a mesh actor and add to the renderable actor
453     if( !meshContainer.empty() )
454     {
455       if( !mActor )
456       {
457         // Create a container actor to act as a common parent for text and shadow, to avoid color inheritence issues.
458         mActor = Actor::New();
459         mActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
460         mActor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
461         mActor.SetSize( textSize );
462         mActor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
463       }
464
465       for( std::vector< MeshRecord >::iterator it = meshContainer.begin(),
466               endIt = meshContainer.end();
467             it != endIt; ++it )
468       {
469         MeshRecord& meshRecord = *it;
470
471         Actor actor = CreateMeshActor( textControl, animatablePropertyIndex, defaultColor, meshRecord, textSize, STYLE_NORMAL );
472
473         // Whether the actor has renderers.
474         const bool hasRenderer = actor.GetRendererCount() > 0u;
475
476         // Create an effect if necessary
477         if( hasRenderer &&
478             ( style == STYLE_DROP_SHADOW ) )
479         {
480           // Change the color of the vertices.
481           for( Vector<AtlasManager::Vertex2D>::Iterator vIt =  meshRecord.mMesh.mVertices.Begin(),
482                  vEndIt = meshRecord.mMesh.mVertices.End();
483                vIt != vEndIt;
484                ++vIt )
485           {
486             AtlasManager::Vertex2D& vertex = *vIt;
487
488             vertex.mColor = shadowColor;
489           }
490
491           Actor shadowActor = CreateMeshActor(textControl, animatablePropertyIndex, defaultColor, meshRecord, textSize, STYLE_DROP_SHADOW );
492 #if defined(DEBUG_ENABLED)
493           shadowActor.SetName( "Text Shadow renderable actor" );
494 #endif
495           // Offset shadow in x and y
496           shadowActor.RegisterProperty("uOffset", shadowOffset );
497           Dali::Renderer renderer( shadowActor.GetRendererAt( 0 ) );
498           int depthIndex = renderer.GetProperty<int>(Dali::Renderer::Property::DEPTH_INDEX);
499           renderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, depthIndex - 1 );
500           mActor.Add( shadowActor );
501         }
502
503         if( hasRenderer )
504         {
505           mActor.Add( actor );
506         }
507       }
508     }
509 #if defined(DEBUG_ENABLED)
510     Toolkit::AtlasGlyphManager::Metrics metrics = mGlyphManager.GetMetrics();
511     DALI_LOG_INFO( gLogFilter, Debug::General, "TextAtlasRenderer::GlyphManager::GlyphCount: %i, AtlasCount: %i, TextureMemoryUse: %iK\n",
512                                                 metrics.mGlyphCount,
513                                                 metrics.mAtlasMetrics.mAtlasCount,
514                                                 metrics.mAtlasMetrics.mTextureMemoryUsed / 1024 );
515
516     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%s\n", metrics.mVerboseGlyphCounts.c_str() );
517
518     for( uint32_t i = 0; i < metrics.mAtlasMetrics.mAtlasCount; ++i )
519     {
520       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "   Atlas [%i] %sPixels: %s Size: %ix%i, BlockSize: %ix%i, BlocksUsed: %i/%i\n",
521                                                  i + 1, i > 8 ? "" : " ",
522                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mPixelFormat == Pixel::L8 ? "L8  " : "BGRA",
523                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mWidth,
524                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mHeight,
525                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mBlockWidth,
526                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mBlockHeight,
527                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mBlocksUsed,
528                                                  metrics.mAtlasMetrics.mAtlasMetrics[ i ].mTotalBlocks );
529     }
530 #endif
531   }
532
533   void RemoveText()
534   {
535     for( Vector< TextCacheEntry >::Iterator oldTextIter = mTextCache.Begin(); oldTextIter != mTextCache.End(); ++oldTextIter )
536     {
537       mGlyphManager.AdjustReferenceCount( oldTextIter->mFontId, oldTextIter->mIndex, -1/*decrement*/ );
538     }
539     mTextCache.Resize( 0 );
540   }
541
542   Actor CreateMeshActor( Actor textControl, Property::Index animatablePropertyIndex, const Vector4& defaultColor, const MeshRecord& meshRecord,
543                          const Vector2& actorSize, Style style )
544   {
545     PropertyBuffer quadVertices = PropertyBuffer::New( mQuadVertexFormat );
546     quadVertices.SetData( const_cast< AtlasManager::Vertex2D* >( &meshRecord.mMesh.mVertices[ 0 ] ), meshRecord.mMesh.mVertices.Size() );
547
548     Geometry quadGeometry = Geometry::New();
549     quadGeometry.AddVertexBuffer( quadVertices );
550     quadGeometry.SetIndexBuffer( &meshRecord.mMesh.mIndices[0],  meshRecord.mMesh.mIndices.Size() );
551
552     TextureSet textureSet( mGlyphManager.GetTextures( meshRecord.mAtlasId ) );
553
554     // Choose the shader to use.
555     const bool isColorShader = ( STYLE_DROP_SHADOW != style ) && ( Pixel::BGRA8888 == mGlyphManager.GetPixelFormat( meshRecord.mAtlasId ) );
556     Shader shader;
557     if( isColorShader )
558     {
559       // The glyph is an emoji and is not a shadow.
560       if( !mShaderRgba )
561       {
562         mShaderRgba = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RGBA );
563       }
564       shader = mShaderRgba;
565     }
566     else
567     {
568       // The glyph is text or a shadow.
569       if( !mShaderL8 )
570       {
571         mShaderL8 = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_L8 );
572       }
573       shader = mShaderL8;
574     }
575
576     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "defaultColor[%f, %f, %f, %f ]\n", defaultColor.r, defaultColor.g, defaultColor.b, defaultColor.a  );
577
578     Dali::Property::Index shaderTextColorIndex = shader.RegisterProperty( "textColorAnimatable", defaultColor );
579
580     if ( animatablePropertyIndex != Property::INVALID_INDEX )
581     {
582       // create constraint for the animatable text's color Property with textColorAnimatable in the shader.
583       if( shaderTextColorIndex  )
584       {
585         Constraint constraint = Constraint::New<Vector4>( shader, shaderTextColorIndex, EqualToConstraint() );
586         constraint.AddSource( Source( textControl, animatablePropertyIndex ) );
587         constraint.Apply();
588       }
589     }
590     else
591     {
592       // If not animating the text colour then set to 1's so shader uses the current vertex color
593       shader.RegisterProperty( "textColorAnimatable", Vector4(1.0, 1.0, 1.0, 1.0 ) );
594     }
595
596     Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, shader );
597     renderer.SetTextures( textureSet );
598     renderer.SetProperty( Dali::Renderer::Property::BLEND_MODE, BlendMode::ON );
599     renderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT + mDepth );
600
601     Actor actor = Actor::New();
602 #if defined(DEBUG_ENABLED)
603     actor.SetName( "Text renderable actor" );
604 #endif
605     actor.AddRenderer( renderer );
606     // Keep all of the origins aligned
607     actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
608     actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
609     actor.SetSize( actorSize );
610     actor.RegisterProperty("uOffset", Vector2::ZERO );
611     actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
612     return actor;
613   }
614
615   void StitchTextMesh( std::vector< MeshRecord >& meshContainer,
616                        AtlasManager::Mesh2D& newMesh,
617                        Vector< Extent >& extents,
618                        float baseLine,
619                        bool underlineGlyph,
620                        float underlinePosition,
621                        float underlineThickness,
622                        AtlasManager::AtlasSlot& slot )
623   {
624     if ( slot.mImageId )
625     {
626       float left = newMesh.mVertices[ 0 ].mPosition.x;
627       float right = newMesh.mVertices[ 1 ].mPosition.x;
628
629       // Check to see if there's a mesh data object that references the same atlas ?
630       uint32_t index = 0;
631       for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(),
632               mEndIt = meshContainer.end();
633             mIt != mEndIt;
634             ++mIt, ++index )
635       {
636         if( slot.mAtlasId == mIt->mAtlasId )
637         {
638           // Append the mesh to the existing mesh and adjust any extents
639           Toolkit::Internal::AtlasMeshFactory::AppendMesh( mIt->mMesh, newMesh );
640
641           if( underlineGlyph )
642           {
643             AdjustExtents( extents,
644                            meshContainer,
645                            index,
646                            left,
647                            right,
648                            baseLine,
649                            underlinePosition,
650                            underlineThickness );
651           }
652
653           return;
654         }
655       }
656
657       // No mesh data object currently exists that references this atlas, so create a new one
658       MeshRecord meshRecord;
659       meshRecord.mAtlasId = slot.mAtlasId;
660       meshRecord.mMesh = newMesh;
661       meshContainer.push_back( meshRecord );
662
663       if( underlineGlyph )
664       {
665         // Adjust extents for this new meshrecord
666         AdjustExtents( extents,
667                        meshContainer,
668                        meshContainer.size() - 1u,
669                        left,
670                        right,
671                        baseLine,
672                        underlinePosition,
673                        underlineThickness );
674       }
675     }
676   }
677
678   void AdjustExtents( Vector< Extent >& extents,
679                       std::vector< MeshRecord>& meshRecords,
680                       uint32_t index,
681                       float left,
682                       float right,
683                       float baseLine,
684                       float underlinePosition,
685                       float underlineThickness )
686   {
687     bool foundExtent = false;
688     for ( Vector< Extent >::Iterator eIt = extents.Begin(),
689             eEndIt = extents.End();
690           eIt != eEndIt;
691           ++eIt )
692     {
693       if ( Equals( baseLine, eIt->mBaseLine ) )
694       {
695         foundExtent = true;
696         if ( left < eIt->mLeft )
697         {
698           eIt->mLeft = left;
699         }
700         if ( right > eIt->mRight  )
701         {
702           eIt->mRight = right;
703         }
704
705         if ( underlinePosition > eIt->mUnderlinePosition )
706         {
707           eIt->mUnderlinePosition = underlinePosition;
708         }
709         if ( underlineThickness > eIt->mUnderlineThickness )
710         {
711           eIt->mUnderlineThickness = underlineThickness;
712         }
713       }
714     }
715     if ( !foundExtent )
716     {
717       Extent extent;
718       extent.mLeft = left;
719       extent.mRight = right;
720       extent.mBaseLine = baseLine;
721       extent.mUnderlinePosition = underlinePosition;
722       extent.mUnderlineThickness = underlineThickness;
723       extent.mMeshRecordIndex = index;
724       extents.PushBack( extent );
725     }
726   }
727
728   void CalculateBlocksSize( const Vector<GlyphInfo>& glyphs )
729   {
730     for( Vector<GlyphInfo>::ConstIterator glyphIt = glyphs.Begin(),
731            glyphEndIt = glyphs.End();
732          glyphIt != glyphEndIt;
733          ++glyphIt )
734     {
735       const FontId fontId = (*glyphIt).fontId;
736       bool foundFont = false;
737
738       for( std::vector< MaxBlockSize >::const_iterator blockIt = mBlockSizes.begin(),
739              blockEndIt = mBlockSizes.end();
740            blockIt != blockEndIt;
741            ++blockIt )
742       {
743         if( (*blockIt).mFontId == fontId )  // Different size fonts will have a different fontId
744         {
745           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Text::AtlasRenderer::CalculateBlocksSize match found fontID(%u) glyphIndex(%u)\n", fontId, (*glyphIt).index );
746           foundFont = true;
747           break;
748         }
749       }
750
751       if ( !foundFont )
752       {
753         FontMetrics fontMetrics;
754         mFontClient.GetFontMetrics( fontId, fontMetrics );
755
756         MaxBlockSize maxBlockSize;
757         maxBlockSize.mNeededBlockWidth = static_cast< uint32_t >( fontMetrics.height );
758         maxBlockSize.mNeededBlockHeight = maxBlockSize.mNeededBlockWidth;
759         maxBlockSize.mFontId = fontId;
760         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Text::AtlasRenderer::CalculateBlocksSize New font with no matched blocksize, setting blocksize[%u]\n", maxBlockSize.mNeededBlockWidth );
761         mBlockSizes.push_back( maxBlockSize );
762       }
763     }
764   }
765
766   void GenerateUnderlines( std::vector< MeshRecord >& meshRecords,
767                            Vector< Extent >& extents,
768                            const Vector4& underlineColor )
769   {
770     AtlasManager::Mesh2D newMesh;
771     unsigned short faceIndex = 0;
772     for ( Vector< Extent >::ConstIterator eIt = extents.Begin(),
773             eEndIt = extents.End();
774           eIt != eEndIt;
775           ++eIt )
776     {
777       AtlasManager::Vertex2D vert;
778       uint32_t index = eIt->mMeshRecordIndex;
779       Vector2 uv = mGlyphManager.GetAtlasSize( meshRecords[ index ].mAtlasId );
780
781       // Make sure we don't hit texture edge for single pixel texture ( filled pixel is in top left of every atlas )
782       float u = HALF / uv.x;
783       float v = HALF / uv.y;
784       float thickness = eIt->mUnderlineThickness;
785       float baseLine = eIt->mBaseLine + eIt->mUnderlinePosition - ( thickness * HALF );
786       float tlx = eIt->mLeft;
787       float brx = eIt->mRight;
788
789       vert.mPosition.x = tlx;
790       vert.mPosition.y = baseLine;
791       vert.mTexCoords.x = ZERO;
792       vert.mTexCoords.y = ZERO;
793       vert.mColor = underlineColor;
794       newMesh.mVertices.PushBack( vert );
795
796       vert.mPosition.x = brx;
797       vert.mPosition.y = baseLine;
798       vert.mTexCoords.x = u;
799       vert.mColor = underlineColor;
800       newMesh.mVertices.PushBack( vert );
801
802       vert.mPosition.x = tlx;
803       vert.mPosition.y = baseLine + thickness;
804       vert.mTexCoords.x = ZERO;
805       vert.mTexCoords.y = v;
806       vert.mColor = underlineColor;
807       newMesh.mVertices.PushBack( vert );
808
809       vert.mPosition.x = brx;
810       vert.mPosition.y = baseLine + thickness;
811       vert.mTexCoords.x = u;
812       vert.mColor = underlineColor;
813       newMesh.mVertices.PushBack( vert );
814
815       // Six indices in counter clockwise winding
816       newMesh.mIndices.PushBack( faceIndex + 1u );
817       newMesh.mIndices.PushBack( faceIndex );
818       newMesh.mIndices.PushBack( faceIndex + 2u );
819       newMesh.mIndices.PushBack( faceIndex + 2u );
820       newMesh.mIndices.PushBack( faceIndex + 3u );
821       newMesh.mIndices.PushBack( faceIndex + 1u );
822       faceIndex += 4;
823
824       Toolkit::Internal::AtlasMeshFactory::AppendMesh( meshRecords[ index ].mMesh, newMesh );
825     }
826   }
827
828   Actor mActor;                                       ///< The actor parent which renders the text
829   AtlasGlyphManager mGlyphManager;                    ///< Glyph Manager to handle upload and caching
830   TextAbstraction::FontClient mFontClient;            ///< The font client used to supply glyph information
831   Shader mShaderL8;                                   ///< The shader for glyphs and emoji's shadows.
832   Shader mShaderRgba;                                 ///< The shader for emojis.
833   std::vector< MaxBlockSize > mBlockSizes;            ///< Maximum size needed to contain a glyph in a block within a new atlas
834   Vector< TextCacheEntry > mTextCache;                ///< Caches data from previous render
835   Property::Map mQuadVertexFormat;                    ///< Describes the vertex format for text
836   int mDepth;                                         ///< DepthIndex passed by control when connect to stage
837 };
838
839 Text::RendererPtr AtlasRenderer::New()
840 {
841   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Text::AtlasRenderer::New()\n" );
842
843   return Text::RendererPtr( new AtlasRenderer() );
844 }
845
846 Actor AtlasRenderer::Render( Text::ViewInterface& view,
847                              Actor textControl,
848                              Property::Index animatablePropertyIndex,
849                              float& alignmentOffset,
850                              int depth )
851 {
852   DALI_LOG_INFO( gLogFilter, Debug::General, "Text::AtlasRenderer::Render()\n" );
853
854   UnparentAndReset( mImpl->mActor );
855
856   Length numberOfGlyphs = view.GetNumberOfGlyphs();
857
858   if( numberOfGlyphs > 0u )
859   {
860     Vector<GlyphInfo> glyphs;
861     glyphs.Resize( numberOfGlyphs );
862
863     Vector<Vector2> positions;
864     positions.Resize( numberOfGlyphs );
865
866     numberOfGlyphs = view.GetGlyphs( glyphs.Begin(),
867                                      positions.Begin(),
868                                      alignmentOffset,
869                                      0u,
870                                      numberOfGlyphs );
871
872     glyphs.Resize( numberOfGlyphs );
873     positions.Resize( numberOfGlyphs );
874
875     const Vector4* const colorsBuffer = view.GetColors();
876     const ColorIndex* const colorIndicesBuffer = view.GetColorIndices();
877     const Vector4& defaultColor = view.GetTextColor();
878
879     mImpl->AddGlyphs( view,
880                       textControl,
881                       animatablePropertyIndex,
882                       positions,
883                       glyphs,
884                       defaultColor,
885                       colorsBuffer,
886                       colorIndicesBuffer,
887                       depth,
888                       alignmentOffset );
889
890     /* In the case where AddGlyphs does not create a renderable Actor for example when glyphs are all whitespace create a new Actor. */
891     /* This renderable actor is used to position the text, other "decorations" can rely on there always being an Actor regardless of it is whitespace or regular text. */
892     if ( !mImpl->mActor )
893     {
894       mImpl->mActor = Actor::New();
895     }
896   }
897
898   return mImpl->mActor;
899 }
900
901 AtlasRenderer::AtlasRenderer()
902 {
903   mImpl = new Impl();
904
905 }
906
907 AtlasRenderer::~AtlasRenderer()
908 {
909   mImpl->RemoveText();
910   delete mImpl;
911 }