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