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