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