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