Merge "Set http response body in binary format." into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / rendering / atlas / text-atlas-renderer.cpp
1 /*
2  * Copyright (c) 2022 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-metrics-helper.h>
32 #include <dali-toolkit/internal/text/glyph-run.h>
33 #include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
34 #include <dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h>
35 #include <dali-toolkit/internal/text/text-view.h>
36
37 using namespace Dali;
38 using namespace Dali::Toolkit;
39 using namespace Dali::Toolkit::Text;
40
41 namespace
42 {
43 #if defined(DEBUG_ENABLED)
44 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_RENDERING");
45 #endif
46
47 const float    ZERO(0.0f);
48 const float    HALF(0.5f);
49 const float    ONE(1.0f);
50 const float    ONE_AND_A_HALF(1.5f);
51 const uint32_t DOUBLE_PIXEL_PADDING = 4u; //Padding will be added twice to Atlas
52 const uint16_t NO_OUTLINE           = 0u;
53 } // namespace
54
55 struct AtlasRenderer::Impl
56 {
57   enum Style
58   {
59     STYLE_NORMAL,
60     STYLE_DROP_SHADOW
61   };
62
63   struct MeshRecord
64   {
65     MeshRecord()
66     : mAtlasId(0u)
67     {
68     }
69
70     uint32_t             mAtlasId;
71     AtlasManager::Mesh2D mMesh;
72   };
73
74   /**
75    * brief Struct used to generate the underline/striketthrough mesh.
76    * There is one Extent per line of text.
77    */
78   struct Extent
79   {
80     Extent()
81     : mBaseLine(0.0f),
82       mLeft(0.0f),
83       mRight(0.0f),
84       mUnderlinePosition(0.0f),
85       mLineThickness(0.0f),
86       mMeshRecordIndex(0u),
87       mUnderlineChunkId(0u),
88       mStrikethroughPosition(0.0f),
89       mStrikethroughChunkId(0u)
90     {
91     }
92
93     float    mBaseLine;
94     float    mLeft;
95     float    mRight;
96     float    mUnderlinePosition;
97     float    mLineThickness;
98     uint32_t mMeshRecordIndex;
99     uint32_t mUnderlineChunkId;
100     float    mStrikethroughPosition;
101     uint32_t mStrikethroughChunkId;
102   };
103
104   struct MaxBlockSize
105   {
106     MaxBlockSize()
107     : mFontId(0),
108       mNeededBlockWidth(0),
109       mNeededBlockHeight(0)
110     {
111     }
112
113     FontId   mFontId;
114     uint32_t mNeededBlockWidth;
115     uint32_t mNeededBlockHeight;
116   };
117
118   struct CheckEntry
119   {
120     CheckEntry()
121     : mFontId(0),
122       mIndex(0)
123     {
124     }
125
126     FontId           mFontId;
127     Text::GlyphIndex mIndex;
128   };
129
130   struct TextCacheEntry
131   {
132     TextCacheEntry()
133     : mFontId{0u},
134       mIndex{0u},
135       mImageId{0u},
136       mOutlineWidth{0u},
137       isItalic{false},
138       isBold{false}
139     {
140     }
141
142     FontId           mFontId;
143     Text::GlyphIndex mIndex;
144     uint32_t         mImageId;
145     uint16_t         mOutlineWidth;
146     bool             isItalic : 1;
147     bool             isBold : 1;
148   };
149
150   Impl()
151   : mDepth(0)
152   {
153     mGlyphManager = AtlasGlyphManager::Get();
154     mFontClient   = TextAbstraction::FontClient::Get();
155
156     mQuadVertexFormat["aPosition"] = Property::VECTOR2;
157     mQuadVertexFormat["aTexCoord"] = Property::VECTOR2;
158     mQuadVertexFormat["aColor"]    = Property::VECTOR4;
159   }
160
161   bool IsGlyphUnderlined(GlyphIndex              index,
162                          const Vector<GlyphRun>& underlineRuns)
163   {
164     for(Vector<GlyphRun>::ConstIterator it    = underlineRuns.Begin(),
165                                         endIt = underlineRuns.End();
166         it != endIt;
167         ++it)
168     {
169       const GlyphRun& run = *it;
170
171       if((run.glyphIndex <= index) && (index < run.glyphIndex + run.numberOfGlyphs))
172       {
173         return true;
174       }
175     }
176
177     return false;
178   }
179
180   bool doGlyphHaveStrikethrough(GlyphIndex                           index,
181                                 const Vector<StrikethroughGlyphRun>& strikethroughRuns,
182                                 Vector4&                             strikethroughColor)
183   {
184     for(Vector<StrikethroughGlyphRun>::ConstIterator it    = strikethroughRuns.Begin(),
185                                                      endIt = strikethroughRuns.End();
186         it != endIt;
187         ++it)
188     {
189       const StrikethroughGlyphRun& run = *it;
190
191       if((run.glyphRun.glyphIndex <= index) && (index < run.glyphRun.glyphIndex + run.glyphRun.numberOfGlyphs))
192       {
193         if(run.isColorSet)
194         {
195           strikethroughColor = run.color;
196         }
197
198         return true;
199       }
200     }
201
202     return false;
203   }
204   void CacheGlyph(const GlyphInfo& glyph, FontId lastFontId, const AtlasGlyphManager::GlyphStyle& style, AtlasManager::AtlasSlot& slot)
205   {
206     const Size& defaultTextAtlasSize = mFontClient.GetDefaultTextAtlasSize(); //Retrieve default size of text-atlas-block from font-client.
207     const Size& maximumTextAtlasSize = mFontClient.GetMaximumTextAtlasSize(); //Retrieve maximum size of text-atlas-block from font-client.
208
209     const bool glyphNotCached = !mGlyphManager.IsCached(glyph.fontId, glyph.index, style, slot); // Check FontGlyphRecord vector for entry with glyph index and fontId
210
211     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "AddGlyphs fontID[%u] glyphIndex[%u] [%s]\n", glyph.fontId, glyph.index, (glyphNotCached) ? "not cached" : "cached");
212
213     if(glyphNotCached)
214     {
215       MaxBlockSize& blockSize = mBlockSizes[0u];
216
217       if(lastFontId != glyph.fontId)
218       {
219         uint32_t index = 0u;
220         // 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.
221         // CalculateBlocksSize() above ensures a block size entry exists.
222         for(std::vector<MaxBlockSize>::const_iterator it    = mBlockSizes.begin(),
223                                                       endIt = mBlockSizes.end();
224             it != endIt;
225             ++it, ++index)
226         {
227           const MaxBlockSize& blockSizeEntry = *it;
228           if(blockSizeEntry.mFontId == glyph.fontId)
229           {
230             blockSize = mBlockSizes[index];
231           }
232         }
233       }
234
235       // Create a new image for the glyph
236       PixelData bitmap;
237
238       // Whether the glyph is an outline.
239       const bool isOutline = 0u != style.outline;
240
241       // Whether the current glyph is a color one.
242       const bool isColorGlyph = mFontClient.IsColorGlyph(glyph.fontId, glyph.index);
243
244       if(!isOutline || (isOutline && !isColorGlyph))
245       {
246         // Retrieve the emoji's bitmap.
247         TextAbstraction::FontClient::GlyphBufferData glyphBufferData;
248         glyphBufferData.width  = isColorGlyph ? glyph.width : 0; // Desired width and height.
249         glyphBufferData.height = isColorGlyph ? glyph.height : 0;
250
251         mFontClient.CreateBitmap(glyph.fontId,
252                                  glyph.index,
253                                  glyph.isItalicRequired,
254                                  glyph.isBoldRequired,
255                                  glyphBufferData,
256                                  style.outline);
257
258         // Create the pixel data.
259         bitmap = PixelData::New(glyphBufferData.buffer,
260                                 glyphBufferData.width * glyphBufferData.height * GetBytesPerPixel(glyphBufferData.format),
261                                 glyphBufferData.width,
262                                 glyphBufferData.height,
263                                 glyphBufferData.format,
264                                 PixelData::DELETE_ARRAY);
265
266         if(bitmap)
267         {
268           // Ensure that the next image will fit into the current block size
269           if(bitmap.GetWidth() > blockSize.mNeededBlockWidth)
270           {
271             blockSize.mNeededBlockWidth = bitmap.GetWidth();
272           }
273
274           if(bitmap.GetHeight() > blockSize.mNeededBlockHeight)
275           {
276             blockSize.mNeededBlockHeight = bitmap.GetHeight();
277           }
278
279           // If CheckAtlas in AtlasManager::Add can't fit the bitmap in the current atlas it will create a new atlas
280
281           // Setting the block size and size of new atlas does not mean a new one will be created. An existing atlas may still surffice.
282           uint32_t default_width  = defaultTextAtlasSize.width;
283           uint32_t default_height = defaultTextAtlasSize.height;
284
285           while(
286             (blockSize.mNeededBlockWidth >= (default_width - (DOUBLE_PIXEL_PADDING + 1u)) ||
287              blockSize.mNeededBlockHeight >= (default_height - (DOUBLE_PIXEL_PADDING + 1u))) &&
288             (default_width < maximumTextAtlasSize.width &&
289              default_height < maximumTextAtlasSize.height))
290           {
291             default_width <<= 1u;
292             default_height <<= 1u;
293           }
294           mGlyphManager.SetNewAtlasSize(default_width,
295                                         default_height,
296                                         blockSize.mNeededBlockWidth,
297                                         blockSize.mNeededBlockHeight);
298
299           // Locate a new slot for our glyph
300           mGlyphManager.Add(glyph, style, bitmap, slot); // slot will be 0 is glyph not added
301         }
302       }
303     }
304     else
305     {
306       // We have 2+ copies of the same glyph
307       mGlyphManager.AdjustReferenceCount(glyph.fontId, glyph.index, style, 1); //increment
308     }
309   }
310
311   void GenerateMesh(const GlyphInfo&         glyph,
312                     const Vector2&           position,
313                     const Vector4&           color,
314                     uint16_t                 outline,
315                     AtlasManager::AtlasSlot& slot,
316                     bool                     decorationlineGlyph,
317                     float                    currentUnderlinePosition,
318                     float                    currentlineThickness,
319                     std::vector<MeshRecord>& meshContainer,
320                     Vector<TextCacheEntry>&  newTextCache,
321                     Vector<Extent>&          extents,
322                     uint32_t                 underlineChunkId,
323                     bool                     isGlyphCached,
324                     uint32_t                 strikethroughChunkId)
325   {
326     // Generate mesh data for this quad, plugging in our supplied position
327     AtlasManager::Mesh2D newMesh;
328     mGlyphManager.GenerateMeshData(slot.mImageId, position, newMesh);
329
330     if(!isGlyphCached)
331     {
332       TextCacheEntry textCacheEntry;
333       textCacheEntry.mFontId       = glyph.fontId;
334       textCacheEntry.mImageId      = slot.mImageId;
335       textCacheEntry.mIndex        = glyph.index;
336       textCacheEntry.mOutlineWidth = outline;
337       textCacheEntry.isItalic      = glyph.isItalicRequired;
338       textCacheEntry.isBold        = glyph.isBoldRequired;
339
340       newTextCache.PushBack(textCacheEntry);
341     }
342
343     AtlasManager::Vertex2D* verticesBuffer = newMesh.mVertices.Begin();
344
345     for(unsigned int index = 0u, size = newMesh.mVertices.Count();
346         index < size;
347         ++index)
348     {
349       AtlasManager::Vertex2D& vertex = *(verticesBuffer + index);
350
351       // Set the color of the vertex.
352       vertex.mColor = color;
353     }
354
355     // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
356     StitchTextMesh(meshContainer,
357                    newMesh,
358                    extents,
359                    position.y + glyph.yBearing,
360                    decorationlineGlyph,
361                    currentUnderlinePosition,
362                    currentlineThickness,
363                    slot,
364                    underlineChunkId,
365                    position.y + (glyph.height * HALF),
366                    strikethroughChunkId);
367   }
368
369   void CreateActors(const std::vector<MeshRecord>& meshContainer,
370                     const Size&                    textSize,
371                     const Vector4&                 color,
372                     const Vector4&                 shadowColor,
373                     const Vector2&                 shadowOffset,
374                     Actor                          textControl,
375                     Property::Index                animatablePropertyIndex,
376                     bool                           drawShadow)
377   {
378     if(!mActor)
379     {
380       // Create a container actor to act as a common parent for text and shadow, to avoid color inheritence issues.
381       mActor = Actor::New();
382       mActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
383       mActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
384       mActor.SetProperty(Actor::Property::SIZE, textSize);
385       mActor.SetProperty(Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR);
386     }
387
388     for(std::vector<MeshRecord>::const_iterator it    = meshContainer.begin(),
389                                                 endIt = meshContainer.end();
390         it != endIt;
391         ++it)
392     {
393       const MeshRecord& meshRecord = *it;
394
395       Actor actor = CreateMeshActor(textControl, animatablePropertyIndex, color, meshRecord, textSize, STYLE_NORMAL);
396
397       // Whether the actor has renderers.
398       const bool hasRenderer = actor.GetRendererCount() > 0u;
399
400       // Create an effect if necessary
401       if(hasRenderer &&
402          drawShadow)
403       {
404         // Change the color of the vertices.
405         for(Vector<AtlasManager::Vertex2D>::Iterator vIt    = meshRecord.mMesh.mVertices.Begin(),
406                                                      vEndIt = meshRecord.mMesh.mVertices.End();
407             vIt != vEndIt;
408             ++vIt)
409         {
410           AtlasManager::Vertex2D& vertex = *vIt;
411
412           vertex.mColor = shadowColor;
413         }
414
415         Actor shadowActor = CreateMeshActor(textControl, animatablePropertyIndex, color, meshRecord, textSize, STYLE_DROP_SHADOW);
416 #if defined(DEBUG_ENABLED)
417         shadowActor.SetProperty(Dali::Actor::Property::NAME, "Text Shadow renderable actor");
418 #endif
419         // Offset shadow in x and y
420         shadowActor.RegisterProperty("uOffset", shadowOffset);
421         Dali::Renderer renderer(shadowActor.GetRendererAt(0));
422         int            depthIndex = renderer.GetProperty<int>(Dali::Renderer::Property::DEPTH_INDEX);
423         renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, depthIndex - 1);
424         mActor.Add(shadowActor);
425       }
426
427       if(hasRenderer)
428       {
429         mActor.Add(actor);
430       }
431     }
432   }
433
434   void AddGlyphs(Text::ViewInterface&     view,
435                  Actor                    textControl,
436                  Property::Index          animatablePropertyIndex,
437                  const Vector<Vector2>&   positions,
438                  const Vector<GlyphInfo>& glyphs,
439                  const Vector4&           defaultColor,
440                  const Vector4* const     colorsBuffer,
441                  const ColorIndex* const  colorIndicesBuffer,
442                  int                      depth,
443                  float                    minLineOffset)
444   {
445     AtlasManager::AtlasSlot slot;
446     slot.mImageId = 0u;
447     slot.mAtlasId = 0u;
448
449     AtlasManager::AtlasSlot slotOutline;
450     slotOutline.mImageId = 0u;
451     slotOutline.mAtlasId = 0u;
452
453     std::vector<MeshRecord> meshContainer;
454     std::vector<MeshRecord> meshContainerOutline;
455     Vector<Extent>          extents;
456     Vector<Extent>          strikethroughExtents;
457     mDepth = depth;
458
459     const Vector2&              textSize(view.GetLayoutSize());
460     const Vector2               halfTextSize(textSize * 0.5f);
461     const Vector2&              shadowOffset(view.GetShadowOffset());
462     const Vector4&              shadowColor(view.GetShadowColor());
463     const bool                  underlineEnabled = view.IsUnderlineEnabled();
464     const Vector4&              underlineColor(view.GetUnderlineColor());
465     const float                 underlineHeight      = view.GetUnderlineHeight();
466     const Text::Underline::Type underlineType        = view.GetUnderlineType();
467     const float                 dashedUnderlineWidth = view.GetDashedUnderlineWidth();
468     const float                 dashedUnderlineGap   = view.GetDashedUnderlineGap();
469     const uint16_t              outlineWidth         = view.GetOutlineWidth();
470     const Vector4&              outlineColor(view.GetOutlineColor());
471     const bool                  isOutline            = 0u != outlineWidth;
472     const GlyphInfo*            hyphens              = view.GetHyphens();
473     const Length*               hyphenIndices        = view.GetHyphenIndices();
474     const Length                hyphensCount         = view.GetHyphensCount();
475     const bool                  strikethroughEnabled = view.IsStrikethroughEnabled();
476     const Vector4&              strikethroughColor(view.GetStrikethroughColor());
477     const float                 strikethroughHeight = view.GetStrikethroughHeight();
478     Vector4                     currentStrikethroughColor;
479     const float                 characterSpacing(view.GetCharacterSpacing());
480
481     // Elided text info. Indices according to elided text.
482     const auto startIndexOfGlyphs              = view.GetStartIndexOfElidedGlyphs();
483     const auto firstMiddleIndexOfElidedGlyphs  = view.GetFirstMiddleIndexOfElidedGlyphs();
484     const auto secondMiddleIndexOfElidedGlyphs = view.GetSecondMiddleIndexOfElidedGlyphs();
485
486     const bool useDefaultColor = (NULL == colorsBuffer);
487
488     // Get the underline runs.
489     const Length     numberOfUnderlineRuns = view.GetNumberOfUnderlineRuns();
490     Vector<GlyphRun> underlineRuns;
491     underlineRuns.Resize(numberOfUnderlineRuns);
492     view.GetUnderlineRuns(underlineRuns.Begin(),
493                           0u,
494                           numberOfUnderlineRuns);
495
496     // Get the strikethrough runs.
497     const Length                  numberOfStrikethroughRuns = view.GetNumberOfStrikethroughRuns();
498     Vector<StrikethroughGlyphRun> strikethroughRuns;
499     strikethroughRuns.Resize(numberOfStrikethroughRuns);
500     view.GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
501
502     bool thereAreUnderlinedGlyphs = false;
503     bool strikethroughGlyphsExist = false;
504
505     float  currentUnderlinePosition      = ZERO;
506     float  currentUnderlineThickness     = underlineHeight;
507     float  currentStrikethroughThickness = strikethroughHeight;
508     FontId lastFontId                    = 0;
509     FontId lastUnderlinedFontId          = 0;
510     Style  style                         = STYLE_NORMAL;
511
512     if(fabsf(shadowOffset.x) > Math::MACHINE_EPSILON_1 || fabsf(shadowOffset.y) > Math::MACHINE_EPSILON_1)
513     {
514       style = STYLE_DROP_SHADOW;
515     }
516
517     CalculateBlocksSize(glyphs);
518
519     // Avoid emptying mTextCache (& removing references) until after incremented references for the new text
520     Vector<TextCacheEntry> newTextCache;
521     const GlyphInfo* const glyphsBuffer    = glyphs.Begin();
522     const Vector2* const   positionsBuffer = positions.Begin();
523     const Vector2          lineOffsetPosition(minLineOffset, 0.f);
524     uint32_t               hyphenIndex = 0;
525
526     //For septated underlined chunks. (this is for Markup case)
527     uint32_t underlineChunkId = 0u;    // give id for each chunk.
528     bool     isPreUnderlined  = false; // status of underlined for previous glyph.
529
530     uint32_t                      strikethroughChunkId      = 0u;    // give id for each chunk.
531     bool                          isPrevGlyphStrikethrough  = false; // status of strikethrough for previous glyph.
532     const Character*              textBuffer                = view.GetTextBuffer();
533     float                         calculatedAdvance         = 0.f;
534     const Vector<CharacterIndex>& glyphToCharacterMap       = view.GetGlyphsToCharacters();
535     const CharacterIndex*         glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
536
537     //Skip hyphenIndices less than startIndexOfGlyphs or between two middle of elided text
538     if(hyphenIndices)
539     {
540       while((hyphenIndex < hyphensCount) && (hyphenIndices[hyphenIndex] < startIndexOfGlyphs ||
541                                              (hyphenIndices[hyphenIndex] > firstMiddleIndexOfElidedGlyphs && hyphenIndices[hyphenIndex] < secondMiddleIndexOfElidedGlyphs)))
542       {
543         ++hyphenIndex;
544       }
545     }
546
547     for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i)
548     {
549       GlyphInfo glyph;
550       bool      addHyphen = ((hyphenIndex < hyphensCount) && hyphenIndices && ((i + startIndexOfGlyphs) == hyphenIndices[hyphenIndex]));
551       if(addHyphen && hyphens)
552       {
553         glyph = hyphens[hyphenIndex];
554         i--;
555       }
556       else
557       {
558         glyph = *(glyphsBuffer + i);
559       }
560
561       const bool isGlyphUnderlined = underlineEnabled || IsGlyphUnderlined(i, underlineRuns);
562       thereAreUnderlinedGlyphs     = thereAreUnderlinedGlyphs || isGlyphUnderlined;
563
564       currentStrikethroughColor       = strikethroughColor;
565       const bool isStrikethroughGlyph = strikethroughEnabled || doGlyphHaveStrikethrough(i, strikethroughRuns, currentStrikethroughColor);
566       strikethroughGlyphsExist        = strikethroughGlyphsExist || isStrikethroughGlyph;
567
568       // No operation for white space
569       if(glyph.width && glyph.height)
570       {
571         // Are we still using the same fontId as previous
572         if((isGlyphUnderlined || isStrikethroughGlyph) && (glyph.fontId != lastUnderlinedFontId))
573         {
574           // We need to fetch fresh font underline metrics
575           FontMetrics fontMetrics;
576           mFontClient.GetFontMetrics(glyph.fontId, fontMetrics);
577           currentUnderlinePosition = ceil(fabsf(fontMetrics.underlinePosition));
578           const float descender    = ceil(fabsf(fontMetrics.descender));
579
580           if(fabsf(underlineHeight) < Math::MACHINE_EPSILON_1000)
581           {
582             currentUnderlineThickness = fontMetrics.underlineThickness;
583
584             // Ensure underline will be at least a pixel high
585             if(currentUnderlineThickness < ONE)
586             {
587               currentUnderlineThickness = ONE;
588             }
589             else
590             {
591               currentUnderlineThickness = ceil(currentUnderlineThickness);
592             }
593           }
594
595           if(fabsf(strikethroughHeight) < Math::MACHINE_EPSILON_1000)
596           {
597             // Ensure strikethrough will be at least a pixel high
598             if(currentStrikethroughThickness < ONE)
599             {
600               currentStrikethroughThickness = ONE;
601             }
602             else
603             {
604               currentStrikethroughThickness = ceil(currentStrikethroughThickness);
605             }
606           }
607
608           // Clamp the underline position at the font descender and check for ( as EFL describes it ) a broken font
609           if(currentUnderlinePosition > descender)
610           {
611             currentUnderlinePosition = descender;
612           }
613
614           if(fabsf(currentUnderlinePosition) < Math::MACHINE_EPSILON_1000)
615           {
616             // Move offset down by one ( EFL behavior )
617             currentUnderlinePosition = ONE;
618           }
619
620           lastUnderlinedFontId = glyph.fontId;
621
622         } // underline
623
624         AtlasGlyphManager::GlyphStyle style;
625         style.isItalic = glyph.isItalicRequired;
626         style.isBold   = glyph.isBoldRequired;
627
628         // Retrieves and caches the glyph's bitmap.
629         CacheGlyph(glyph, lastFontId, style, slot);
630
631         // Retrieves and caches the outline glyph's bitmap.
632         if(isOutline)
633         {
634           style.outline = outlineWidth;
635           CacheGlyph(glyph, lastFontId, style, slotOutline);
636         }
637
638         // Move the origin (0,0) of the mesh to the center of the actor
639         Vector2 position = *(positionsBuffer + i);
640
641         if(addHyphen)
642         {
643           GlyphInfo tempInfo = *(glyphsBuffer + i);
644           calculatedAdvance  = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + i))), characterSpacing, tempInfo.advance);
645           position.x         = position.x + calculatedAdvance - tempInfo.xBearing + glyph.xBearing;
646           position.y += tempInfo.yBearing - glyph.yBearing;
647         }
648
649         position = Vector2(roundf(position.x), position.y) - halfTextSize - lineOffsetPosition; // roundf() avoids pixel alignment issues.
650
651         if(0u != slot.mImageId) // invalid slot id, glyph has failed to be added to atlas
652         {
653           Vector2 positionPlusOutlineOffset = position;
654           if(isOutline)
655           {
656             // Add an offset to the text.
657             const float outlineWidthOffset = static_cast<float>(outlineWidth);
658             positionPlusOutlineOffset += Vector2(outlineWidthOffset, outlineWidthOffset);
659           }
660
661           // Get the color of the character.
662           const ColorIndex colorIndex = useDefaultColor ? 0u : *(colorIndicesBuffer + i);
663           const Vector4&   color      = (useDefaultColor || (0u == colorIndex)) ? defaultColor : *(colorsBuffer + colorIndex - 1u);
664
665           GenerateMesh(glyph,
666                        positionPlusOutlineOffset,
667                        color,
668                        NO_OUTLINE,
669                        slot,
670                        isGlyphUnderlined,
671                        currentUnderlinePosition,
672                        currentUnderlineThickness,
673                        meshContainer,
674                        newTextCache,
675                        extents,
676                        underlineChunkId,
677                        false,
678                        0u);
679
680           if(isStrikethroughGlyph)
681           {
682             GenerateMesh(glyph,
683                          positionPlusOutlineOffset,
684                          color,
685                          NO_OUTLINE,
686                          slot,
687                          strikethroughGlyphsExist,
688                          0.0f,
689                          currentStrikethroughThickness,
690                          meshContainer,
691                          newTextCache,
692                          strikethroughExtents,
693                          0u,
694                          true,
695                          strikethroughChunkId);
696           }
697
698           lastFontId = glyph.fontId; // Prevents searching for existing blocksizes when string of the same fontId.
699         }
700
701         if(isOutline && (0u != slotOutline.mImageId)) // invalid slot id, glyph has failed to be added to atlas
702         {
703           GenerateMesh(glyph,
704                        position,
705                        outlineColor,
706                        outlineWidth,
707                        slotOutline,
708                        false,
709                        currentUnderlinePosition,
710                        currentUnderlineThickness,
711                        meshContainerOutline,
712                        newTextCache,
713                        extents,
714                        0u,
715                        false,
716                        0u);
717         }
718
719         //The new underlined chunk. Add new id if they are not consecutive indices (this is for Markup case)
720         // Examples: "Hello <u>World</u> Hello <u>World</u>", "<u>World</u> Hello <u>World</u>", "<u>   World</u> Hello <u>World</u>"
721         if(isPreUnderlined && (isPreUnderlined != isGlyphUnderlined))
722         {
723           underlineChunkId++;
724         }
725         //Keep status of underlined for previous glyph to check consecutive indices
726         isPreUnderlined = isGlyphUnderlined;
727
728         if(isPrevGlyphStrikethrough && !isStrikethroughGlyph)
729         {
730           strikethroughChunkId++;
731         }
732
733         isPrevGlyphStrikethrough = isStrikethroughGlyph;
734       }
735
736       if(addHyphen)
737       {
738         hyphenIndex++;
739       }
740     } // glyphs
741
742     // Now remove references for the old text
743     RemoveText();
744     mTextCache.Swap(newTextCache);
745
746     if(thereAreUnderlinedGlyphs)
747     {
748       // Check to see if any of the text needs an underline
749       GenerateUnderlines(meshContainer, extents, underlineColor, underlineType, dashedUnderlineWidth, dashedUnderlineGap);
750     }
751
752     if(strikethroughGlyphsExist)
753     {
754       // Check to see if any of the text needs a strikethrough
755       GenerateStrikethrough(meshContainer, strikethroughExtents, currentStrikethroughColor);
756     }
757
758     // For each MeshData object, create a mesh actor and add to the renderable actor
759     bool isShadowDrawn = false;
760     if(!meshContainerOutline.empty())
761     {
762       const bool drawShadow = STYLE_DROP_SHADOW == style;
763       CreateActors(meshContainerOutline,
764                    textSize,
765                    outlineColor,
766                    shadowColor,
767                    shadowOffset,
768                    textControl,
769                    animatablePropertyIndex,
770                    drawShadow);
771
772       isShadowDrawn = drawShadow;
773     }
774
775     // For each MeshData object, create a mesh actor and add to the renderable actor
776     if(!meshContainer.empty())
777     {
778       const bool drawShadow = !isShadowDrawn && (STYLE_DROP_SHADOW == style);
779       CreateActors(meshContainer,
780                    textSize,
781                    defaultColor,
782                    shadowColor,
783                    shadowOffset,
784                    textControl,
785                    animatablePropertyIndex,
786                    drawShadow);
787     }
788
789 #if defined(DEBUG_ENABLED)
790     Toolkit::AtlasGlyphManager::Metrics metrics = mGlyphManager.GetMetrics();
791     DALI_LOG_INFO(gLogFilter, Debug::General, "TextAtlasRenderer::GlyphManager::GlyphCount: %i, AtlasCount: %i, TextureMemoryUse: %iK\n", metrics.mGlyphCount, metrics.mAtlasMetrics.mAtlasCount, metrics.mAtlasMetrics.mTextureMemoryUsed / 1024);
792
793     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "%s\n", metrics.mVerboseGlyphCounts.c_str());
794
795     for(uint32_t i = 0; i < metrics.mAtlasMetrics.mAtlasCount; ++i)
796     {
797       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);
798     }
799 #endif
800   }
801
802   void RemoveText()
803   {
804     for(Vector<TextCacheEntry>::Iterator oldTextIter = mTextCache.Begin(); oldTextIter != mTextCache.End(); ++oldTextIter)
805     {
806       AtlasGlyphManager::GlyphStyle style;
807       style.outline  = oldTextIter->mOutlineWidth;
808       style.isItalic = oldTextIter->isItalic;
809       style.isBold   = oldTextIter->isBold;
810       mGlyphManager.AdjustReferenceCount(oldTextIter->mFontId, oldTextIter->mIndex, style, -1 /*decrement*/);
811     }
812     mTextCache.Resize(0);
813   }
814
815   Actor CreateMeshActor(Actor textControl, Property::Index animatablePropertyIndex, const Vector4& defaultColor, const MeshRecord& meshRecord, const Vector2& actorSize, Style style)
816   {
817     VertexBuffer quadVertices = VertexBuffer::New(mQuadVertexFormat);
818     quadVertices.SetData(const_cast<AtlasManager::Vertex2D*>(&meshRecord.mMesh.mVertices[0]), meshRecord.mMesh.mVertices.Size());
819
820     Geometry quadGeometry = Geometry::New();
821     quadGeometry.AddVertexBuffer(quadVertices);
822     quadGeometry.SetIndexBuffer(&meshRecord.mMesh.mIndices[0], meshRecord.mMesh.mIndices.Size());
823
824     TextureSet textureSet(mGlyphManager.GetTextures(meshRecord.mAtlasId));
825
826     // Choose the shader to use.
827     const bool isColorShader = (STYLE_DROP_SHADOW != style) && (Pixel::BGRA8888 == mGlyphManager.GetPixelFormat(meshRecord.mAtlasId));
828     Shader     shader;
829     if(isColorShader)
830     {
831       // The glyph is an emoji and is not a shadow.
832       if(!mShaderRgba)
833       {
834         mShaderRgba = Shader::New(SHADER_TEXT_ATLAS_SHADER_VERT, SHADER_TEXT_ATLAS_RGBA_SHADER_FRAG);
835       }
836       shader = mShaderRgba;
837     }
838     else
839     {
840       // The glyph is text or a shadow.
841       if(!mShaderL8)
842       {
843         mShaderL8 = Shader::New(SHADER_TEXT_ATLAS_SHADER_VERT, SHADER_TEXT_ATLAS_L8_SHADER_FRAG);
844       }
845       shader = mShaderL8;
846     }
847
848     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "defaultColor[%f, %f, %f, %f ]\n", defaultColor.r, defaultColor.g, defaultColor.b, defaultColor.a);
849
850     Dali::Property::Index shaderTextColorIndex = shader.RegisterProperty("textColorAnimatable", defaultColor);
851
852     if(animatablePropertyIndex != Property::INVALID_INDEX)
853     {
854       // create constraint for the animatable text's color Property with textColorAnimatable in the shader.
855       if(shaderTextColorIndex)
856       {
857         Constraint constraint = Constraint::New<Vector4>(shader, shaderTextColorIndex, EqualToConstraint());
858         constraint.AddSource(Source(textControl, animatablePropertyIndex));
859         constraint.Apply();
860       }
861     }
862     else
863     {
864       // If not animating the text colour then set to 1's so shader uses the current vertex color
865       shader.RegisterProperty("textColorAnimatable", Vector4(1.0, 1.0, 1.0, 1.0));
866     }
867
868     Dali::Renderer renderer = Dali::Renderer::New(quadGeometry, shader);
869     renderer.SetTextures(textureSet);
870     renderer.SetProperty(Dali::Renderer::Property::BLEND_MODE, BlendMode::ON);
871     renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT + mDepth);
872
873     Actor actor = Actor::New();
874 #if defined(DEBUG_ENABLED)
875     actor.SetProperty(Dali::Actor::Property::NAME, "Text renderable actor");
876 #endif
877     actor.AddRenderer(renderer);
878     // Keep all of the origins aligned
879     actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
880     actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
881     actor.SetProperty(Actor::Property::SIZE, actorSize);
882     actor.RegisterProperty("uOffset", Vector2::ZERO);
883     actor.SetProperty(Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR);
884
885     return actor;
886   }
887
888   void StitchTextMesh(std::vector<MeshRecord>& meshContainer,
889                       AtlasManager::Mesh2D&    newMesh,
890                       Vector<Extent>&          extents,
891                       float                    baseLine,
892                       bool                     decorationlineGlyph,
893                       float                    underlinePosition,
894                       float                    lineThickness,
895                       AtlasManager::AtlasSlot& slot,
896                       uint32_t                 underlineChunkId,
897                       float                    strikethroughPosition,
898                       uint32_t                 strikethroughChunkId)
899   {
900     if(slot.mImageId)
901     {
902       float left  = newMesh.mVertices[0].mPosition.x;
903       float right = newMesh.mVertices[1].mPosition.x;
904
905       // Check to see if there's a mesh data object that references the same atlas ?
906       uint32_t index = 0;
907       for(std::vector<MeshRecord>::iterator mIt    = meshContainer.begin(),
908                                             mEndIt = meshContainer.end();
909           mIt != mEndIt;
910           ++mIt, ++index)
911       {
912         if(slot.mAtlasId == mIt->mAtlasId)
913         {
914           // Append the mesh to the existing mesh and adjust any extents
915           Toolkit::Internal::AtlasMeshFactory::AppendMesh(mIt->mMesh, newMesh);
916
917           if(decorationlineGlyph)
918           {
919             AdjustExtents(extents,
920                           meshContainer,
921                           index,
922                           left,
923                           right,
924                           baseLine,
925                           underlinePosition,
926                           lineThickness,
927                           underlineChunkId,
928                           strikethroughPosition,
929                           strikethroughChunkId);
930           }
931
932           return;
933         }
934       }
935
936       // No mesh data object currently exists that references this atlas, so create a new one
937       MeshRecord meshRecord;
938       meshRecord.mAtlasId = slot.mAtlasId;
939       meshRecord.mMesh    = newMesh;
940       meshContainer.push_back(meshRecord);
941
942       if(decorationlineGlyph)
943       {
944         // Adjust extents for this new meshrecord
945         AdjustExtents(extents,
946                       meshContainer,
947                       meshContainer.size() - 1u,
948                       left,
949                       right,
950                       baseLine,
951                       underlinePosition,
952                       lineThickness,
953                       underlineChunkId,
954                       strikethroughPosition,
955                       strikethroughChunkId);
956       }
957     }
958   }
959
960   void AdjustExtents(Vector<Extent>&          extents,
961                      std::vector<MeshRecord>& meshRecords,
962                      uint32_t                 index,
963                      float                    left,
964                      float                    right,
965                      float                    baseLine,
966                      float                    underlinePosition,
967                      float                    lineThickness,
968                      uint32_t                 underlineChunkId,
969                      float                    strikethroughPosition,
970                      uint32_t                 strikethroughChunkId)
971   {
972     bool foundExtent = false;
973     for(Vector<Extent>::Iterator eIt    = extents.Begin(),
974                                  eEndIt = extents.End();
975         eIt != eEndIt;
976         ++eIt)
977     {
978       if(Equals(baseLine, eIt->mBaseLine) && underlineChunkId == eIt->mUnderlineChunkId && strikethroughChunkId == eIt->mStrikethroughChunkId)
979       {
980         foundExtent = true;
981         if(left < eIt->mLeft)
982         {
983           eIt->mLeft = left;
984         }
985         if(right > eIt->mRight)
986         {
987           eIt->mRight = right;
988         }
989
990         if(underlinePosition > eIt->mUnderlinePosition)
991         {
992           eIt->mUnderlinePosition = underlinePosition;
993         }
994         if(lineThickness > eIt->mLineThickness)
995         {
996           eIt->mLineThickness = lineThickness;
997         }
998       }
999     }
1000     if(!foundExtent)
1001     {
1002       Extent extent;
1003       extent.mLeft                  = left;
1004       extent.mRight                 = right;
1005       extent.mBaseLine              = baseLine;
1006       extent.mUnderlinePosition     = underlinePosition;
1007       extent.mMeshRecordIndex       = index;
1008       extent.mUnderlineChunkId      = underlineChunkId;
1009       extent.mLineThickness         = lineThickness;
1010       extent.mStrikethroughPosition = strikethroughPosition;
1011       extent.mStrikethroughChunkId  = strikethroughChunkId;
1012       extents.PushBack(extent);
1013     }
1014   }
1015
1016   void CalculateBlocksSize(const Vector<GlyphInfo>& glyphs)
1017   {
1018     for(Vector<GlyphInfo>::ConstIterator glyphIt    = glyphs.Begin(),
1019                                          glyphEndIt = glyphs.End();
1020         glyphIt != glyphEndIt;
1021         ++glyphIt)
1022     {
1023       const FontId fontId    = (*glyphIt).fontId;
1024       bool         foundFont = false;
1025
1026       for(std::vector<MaxBlockSize>::const_iterator blockIt    = mBlockSizes.begin(),
1027                                                     blockEndIt = mBlockSizes.end();
1028           blockIt != blockEndIt;
1029           ++blockIt)
1030       {
1031         if((*blockIt).mFontId == fontId) // Different size fonts will have a different fontId
1032         {
1033           DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Text::AtlasRenderer::CalculateBlocksSize match found fontID(%u) glyphIndex(%u)\n", fontId, (*glyphIt).index);
1034           foundFont = true;
1035           break;
1036         }
1037       }
1038
1039       if(!foundFont)
1040       {
1041         FontMetrics fontMetrics;
1042         mFontClient.GetFontMetrics(fontId, fontMetrics);
1043
1044         MaxBlockSize maxBlockSize;
1045         maxBlockSize.mNeededBlockWidth  = static_cast<uint32_t>(fontMetrics.height);
1046         maxBlockSize.mNeededBlockHeight = maxBlockSize.mNeededBlockWidth;
1047         maxBlockSize.mFontId            = fontId;
1048         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Text::AtlasRenderer::CalculateBlocksSize New font with no matched blocksize, setting blocksize[%u]\n", maxBlockSize.mNeededBlockWidth);
1049         mBlockSizes.push_back(maxBlockSize);
1050       }
1051     }
1052   }
1053
1054   void GenerateUnderlines(std::vector<MeshRecord>&     meshRecords,
1055                           Vector<Extent>&              extents,
1056                           const Vector4&               underlineColor,
1057                           const Text::Underline::Type& underlineType,
1058                           const float&                 dashedUnderlineWidth,
1059                           const float&                 dashedUnderlineGap)
1060   {
1061     AtlasManager::Mesh2D newMesh;
1062     unsigned short       faceIndex = 0;
1063     for(Vector<Extent>::ConstIterator eIt    = extents.Begin(),
1064                                       eEndIt = extents.End();
1065         eIt != eEndIt;
1066         ++eIt)
1067     {
1068       AtlasManager::Vertex2D vert;
1069       uint32_t               index = eIt->mMeshRecordIndex;
1070       Vector2                uv    = mGlyphManager.GetAtlasSize(meshRecords[index].mAtlasId);
1071
1072       // Make sure we don't hit texture edge for single pixel texture ( filled pixel is in top left of every atlas )
1073       float u           = HALF / uv.x;
1074       float v           = HALF / uv.y;
1075       float thickness   = eIt->mLineThickness;
1076       float ShiftLineBy = (underlineType == Text::Underline::Type::DOUBLE) ? (thickness * ONE_AND_A_HALF) : (thickness * HALF);
1077       float baseLine    = eIt->mBaseLine + eIt->mUnderlinePosition - ShiftLineBy;
1078       float tlx         = eIt->mLeft;
1079       float brx         = eIt->mRight;
1080
1081       if(underlineType == Text::Underline::Type::DASHED)
1082       {
1083         float dashTlx = tlx;
1084         float dashBrx = tlx;
1085         faceIndex     = 0;
1086
1087         AtlasManager::Mesh2D newMesh;
1088         while((dashTlx >= tlx) && (dashTlx < brx) && ((dashTlx + dashedUnderlineWidth) <= brx))
1089         {
1090           dashBrx = dashTlx + dashedUnderlineWidth;
1091
1092           //The top left edge of the underline
1093           vert.mPosition.x  = dashTlx;
1094           vert.mPosition.y  = baseLine;
1095           vert.mTexCoords.x = ZERO;
1096           vert.mTexCoords.y = ZERO;
1097           vert.mColor       = underlineColor;
1098           newMesh.mVertices.PushBack(vert);
1099
1100           //The top right edge of the underline
1101           vert.mPosition.x  = dashBrx;
1102           vert.mPosition.y  = baseLine;
1103           vert.mTexCoords.x = u;
1104           vert.mColor       = underlineColor;
1105           newMesh.mVertices.PushBack(vert);
1106
1107           //The bottom left edge of the underline
1108           vert.mPosition.x  = dashTlx;
1109           vert.mPosition.y  = baseLine + thickness;
1110           vert.mTexCoords.x = ZERO;
1111           vert.mTexCoords.y = v;
1112           vert.mColor       = underlineColor;
1113           newMesh.mVertices.PushBack(vert);
1114
1115           //The bottom right edge of the underline
1116           vert.mPosition.x  = dashBrx;
1117           vert.mPosition.y  = baseLine + thickness;
1118           vert.mTexCoords.x = u;
1119           vert.mColor       = underlineColor;
1120           newMesh.mVertices.PushBack(vert);
1121
1122           dashTlx = dashBrx + dashedUnderlineGap; // The next dash will start at the right of the current dash plus the gap
1123
1124           // Six indices in counter clockwise winding
1125           newMesh.mIndices.PushBack(faceIndex + 1u);
1126           newMesh.mIndices.PushBack(faceIndex);
1127           newMesh.mIndices.PushBack(faceIndex + 2u);
1128           newMesh.mIndices.PushBack(faceIndex + 2u);
1129           newMesh.mIndices.PushBack(faceIndex + 3u);
1130           newMesh.mIndices.PushBack(faceIndex + 1u);
1131
1132           faceIndex += 4;
1133
1134           Toolkit::Internal::AtlasMeshFactory::AppendMesh(meshRecords[index].mMesh, newMesh);
1135         }
1136       }
1137       else
1138       {
1139         // It's either SOLID or DOUBLE so we need to generate the first solid underline anyway.
1140         vert.mPosition.x  = tlx;
1141         vert.mPosition.y  = baseLine;
1142         vert.mTexCoords.x = ZERO;
1143         vert.mTexCoords.y = ZERO;
1144         vert.mColor       = underlineColor;
1145         newMesh.mVertices.PushBack(vert);
1146
1147         vert.mPosition.x  = brx;
1148         vert.mPosition.y  = baseLine;
1149         vert.mTexCoords.x = u;
1150         vert.mColor       = underlineColor;
1151         newMesh.mVertices.PushBack(vert);
1152
1153         vert.mPosition.x  = tlx;
1154         vert.mPosition.y  = baseLine + thickness;
1155         vert.mTexCoords.x = ZERO;
1156         vert.mTexCoords.y = v;
1157         vert.mColor       = underlineColor;
1158         newMesh.mVertices.PushBack(vert);
1159
1160         vert.mPosition.x  = brx;
1161         vert.mPosition.y  = baseLine + thickness;
1162         vert.mTexCoords.x = u;
1163         vert.mColor       = underlineColor;
1164         newMesh.mVertices.PushBack(vert);
1165
1166         // Six indices in counter clockwise winding
1167         newMesh.mIndices.PushBack(faceIndex + 1u);
1168         newMesh.mIndices.PushBack(faceIndex);
1169         newMesh.mIndices.PushBack(faceIndex + 2u);
1170         newMesh.mIndices.PushBack(faceIndex + 2u);
1171         newMesh.mIndices.PushBack(faceIndex + 3u);
1172         newMesh.mIndices.PushBack(faceIndex + 1u);
1173         faceIndex += 4;
1174
1175         Toolkit::Internal::AtlasMeshFactory::AppendMesh(meshRecords[index].mMesh, newMesh);
1176
1177         if(underlineType == Text::Underline::Type::DOUBLE)
1178         {
1179           baseLine += 2 * thickness;
1180
1181           //The top left edge of the underline
1182           vert.mPosition.x  = tlx;
1183           vert.mPosition.y  = baseLine; // Vertical start of the second underline
1184           vert.mTexCoords.x = ZERO;
1185           vert.mTexCoords.y = ZERO;
1186           vert.mColor       = underlineColor;
1187           newMesh.mVertices.PushBack(vert);
1188
1189           //The top right edge of the underline
1190           vert.mPosition.x  = brx;
1191           vert.mPosition.y  = baseLine;
1192           vert.mTexCoords.x = u;
1193           vert.mColor       = underlineColor;
1194           newMesh.mVertices.PushBack(vert);
1195
1196           //The bottom left edge of the underline
1197           vert.mPosition.x  = tlx;
1198           vert.mPosition.y  = baseLine + thickness; // Vertical End of the second underline
1199           vert.mTexCoords.x = ZERO;
1200           vert.mTexCoords.y = v;
1201           vert.mColor       = underlineColor;
1202           newMesh.mVertices.PushBack(vert);
1203
1204           //The bottom right edge of the underline
1205           vert.mPosition.x  = brx;
1206           vert.mPosition.y  = baseLine + thickness;
1207           vert.mTexCoords.x = u;
1208           vert.mColor       = underlineColor;
1209           newMesh.mVertices.PushBack(vert);
1210
1211           // Six indices in counter clockwise winding
1212           newMesh.mIndices.PushBack(faceIndex + 1u);
1213           newMesh.mIndices.PushBack(faceIndex);
1214           newMesh.mIndices.PushBack(faceIndex + 2u);
1215           newMesh.mIndices.PushBack(faceIndex + 2u);
1216           newMesh.mIndices.PushBack(faceIndex + 3u);
1217           newMesh.mIndices.PushBack(faceIndex + 1u);
1218
1219           faceIndex += 4;
1220
1221           Toolkit::Internal::AtlasMeshFactory::AppendMesh(meshRecords[index].mMesh, newMesh);
1222         }
1223       }
1224     }
1225   }
1226
1227   void GenerateStrikethrough(std::vector<MeshRecord>& meshRecords,
1228                              Vector<Extent>&          extents,
1229                              const Vector4&           strikethroughColor)
1230   {
1231     AtlasManager::Mesh2D newMesh;
1232     unsigned short       faceIndex = 0;
1233     for(Vector<Extent>::ConstIterator eIt    = extents.Begin(),
1234                                       eEndIt = extents.End();
1235         eIt != eEndIt;
1236         ++eIt)
1237     {
1238       AtlasManager::Vertex2D vert;
1239       uint32_t               index = eIt->mMeshRecordIndex;
1240       Vector2                uv    = mGlyphManager.GetAtlasSize(meshRecords[index].mAtlasId);
1241
1242       // Make sure we don't hit texture edge for single pixel texture ( filled pixel is in top left of every atlas )
1243       float u                     = HALF / uv.x;
1244       float v                     = HALF / uv.y;
1245       float thickness             = eIt->mLineThickness;
1246       float tlx                   = eIt->mLeft;
1247       float brx                   = eIt->mRight;
1248       float strikethroughPosition = eIt->mStrikethroughPosition;
1249
1250       vert.mPosition.x  = tlx;
1251       vert.mPosition.y  = strikethroughPosition;
1252       vert.mTexCoords.x = ZERO;
1253       vert.mTexCoords.y = ZERO;
1254       vert.mColor       = strikethroughColor;
1255       newMesh.mVertices.PushBack(vert);
1256
1257       vert.mPosition.x  = brx;
1258       vert.mPosition.y  = strikethroughPosition;
1259       vert.mTexCoords.x = u;
1260       vert.mColor       = strikethroughColor;
1261       newMesh.mVertices.PushBack(vert);
1262
1263       vert.mPosition.x  = tlx;
1264       vert.mPosition.y  = strikethroughPosition + thickness;
1265       vert.mTexCoords.x = ZERO;
1266       vert.mTexCoords.y = v;
1267       vert.mColor       = strikethroughColor;
1268       newMesh.mVertices.PushBack(vert);
1269
1270       vert.mPosition.x  = brx;
1271       vert.mPosition.y  = strikethroughPosition + thickness;
1272       vert.mTexCoords.x = u;
1273       vert.mColor       = strikethroughColor;
1274       newMesh.mVertices.PushBack(vert);
1275
1276       // Six indices in counter clockwise winding
1277       newMesh.mIndices.PushBack(faceIndex + 1u);
1278       newMesh.mIndices.PushBack(faceIndex);
1279       newMesh.mIndices.PushBack(faceIndex + 2u);
1280       newMesh.mIndices.PushBack(faceIndex + 2u);
1281       newMesh.mIndices.PushBack(faceIndex + 3u);
1282       newMesh.mIndices.PushBack(faceIndex + 1u);
1283       faceIndex += 4;
1284
1285       Toolkit::Internal::AtlasMeshFactory::AppendMesh(meshRecords[index].mMesh, newMesh);
1286     }
1287   }
1288
1289   Actor                       mActor;            ///< The actor parent which renders the text
1290   AtlasGlyphManager           mGlyphManager;     ///< Glyph Manager to handle upload and caching
1291   TextAbstraction::FontClient mFontClient;       ///< The font client used to supply glyph information
1292   Shader                      mShaderL8;         ///< The shader for glyphs and emoji's shadows.
1293   Shader                      mShaderRgba;       ///< The shader for emojis.
1294   std::vector<MaxBlockSize>   mBlockSizes;       ///< Maximum size needed to contain a glyph in a block within a new atlas
1295   Vector<TextCacheEntry>      mTextCache;        ///< Caches data from previous render
1296   Property::Map               mQuadVertexFormat; ///< Describes the vertex format for text
1297   int                         mDepth;            ///< DepthIndex passed by control when connect to stage
1298 };
1299
1300 Text::RendererPtr AtlasRenderer::New()
1301 {
1302   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Text::AtlasRenderer::New()\n");
1303
1304   return Text::RendererPtr(new AtlasRenderer());
1305 }
1306
1307 Actor AtlasRenderer::Render(Text::ViewInterface& view,
1308                             Actor                textControl,
1309                             Property::Index      animatablePropertyIndex,
1310                             float&               alignmentOffset,
1311                             int                  depth)
1312 {
1313   DALI_LOG_INFO(gLogFilter, Debug::General, "Text::AtlasRenderer::Render()\n");
1314
1315   UnparentAndReset(mImpl->mActor);
1316
1317   Length numberOfGlyphs = view.GetNumberOfGlyphs();
1318
1319   if(numberOfGlyphs > 0u)
1320   {
1321     Vector<GlyphInfo> glyphs;
1322     glyphs.Resize(numberOfGlyphs);
1323
1324     Vector<Vector2> positions;
1325     positions.Resize(numberOfGlyphs);
1326
1327     numberOfGlyphs = view.GetGlyphs(glyphs.Begin(),
1328                                     positions.Begin(),
1329                                     alignmentOffset,
1330                                     0u,
1331                                     numberOfGlyphs);
1332
1333     glyphs.Resize(numberOfGlyphs);
1334     positions.Resize(numberOfGlyphs);
1335
1336     const Vector4* const    colorsBuffer       = view.GetColors();
1337     const ColorIndex* const colorIndicesBuffer = view.GetColorIndices();
1338     const Vector4&          defaultColor       = view.GetTextColor();
1339
1340     mImpl->AddGlyphs(view,
1341                      textControl,
1342                      animatablePropertyIndex,
1343                      positions,
1344                      glyphs,
1345                      defaultColor,
1346                      colorsBuffer,
1347                      colorIndicesBuffer,
1348                      depth,
1349                      alignmentOffset);
1350
1351     /* In the case where AddGlyphs does not create a renderable Actor for example when glyphs are all whitespace create a new Actor. */
1352     /* 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. */
1353     if(!mImpl->mActor)
1354     {
1355       mImpl->mActor = Actor::New();
1356     }
1357   }
1358
1359   return mImpl->mActor;
1360 }
1361
1362 AtlasRenderer::AtlasRenderer()
1363 {
1364   mImpl = new Impl();
1365 }
1366
1367 AtlasRenderer::~AtlasRenderer()
1368 {
1369   mImpl->RemoveText();
1370   delete mImpl;
1371 }