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