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