+ mFontClient = TextAbstraction::FontClient::Get();
+
+ mQuadVertexFormat["aPosition"] = Property::VECTOR2;
+ mQuadVertexFormat["aTexCoord"] = Property::VECTOR2;
+ mQuadVertexFormat["aColor"] = Property::VECTOR4;
+ }
+
+ void CacheGlyph(const GlyphInfo& glyph, FontId lastFontId, const AtlasGlyphManager::GlyphStyle& style, AtlasManager::AtlasSlot& slot)
+ {
+ const Size& defaultTextAtlasSize = mFontClient.GetDefaultTextAtlasSize(); //Retrieve default size of text-atlas-block from font-client.
+ const Size& maximumTextAtlasSize = mFontClient.GetMaximumTextAtlasSize(); //Retrieve maximum size of text-atlas-block from font-client.
+
+ const bool glyphNotCached = !mGlyphManager.IsCached(glyph.fontId, glyph.index, style, slot); // Check FontGlyphRecord vector for entry with glyph index and fontId
+
+ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "AddGlyphs fontID[%u] glyphIndex[%u] [%s]\n", glyph.fontId, glyph.index, (glyphNotCached) ? "not cached" : "cached");
+
+ if(glyphNotCached)
+ {
+ MaxBlockSize& blockSize = mBlockSizes[0u];
+
+ if(lastFontId != glyph.fontId)
+ {
+ uint32_t index = 0u;
+ // 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.
+ // CalculateBlocksSize() above ensures a block size entry exists.
+ for(std::vector<MaxBlockSize>::const_iterator it = mBlockSizes.begin(),
+ endIt = mBlockSizes.end();
+ it != endIt;
+ ++it, ++index)
+ {
+ const MaxBlockSize& blockSizeEntry = *it;
+ if(blockSizeEntry.mFontId == glyph.fontId)
+ {
+ blockSize = mBlockSizes[index];
+ }
+ }
+ }
+
+ // Create a new image for the glyph
+ PixelData bitmap;
+
+ // Whether the glyph is an outline.
+ const bool isOutline = 0u != style.outline;
+
+ // Whether the current glyph is a color one.
+ const bool isColorGlyph = mFontClient.IsColorGlyph(glyph.fontId, glyph.index);
+
+ if(!isOutline || (isOutline && !isColorGlyph))
+ {
+ // Retrieve the emoji's bitmap.
+ TextAbstraction::FontClient::GlyphBufferData glyphBufferData;
+ glyphBufferData.width = isColorGlyph ? glyph.width : 0; // Desired width and height.
+ glyphBufferData.height = isColorGlyph ? glyph.height : 0;
+
+ mFontClient.CreateBitmap(glyph.fontId,
+ glyph.index,
+ glyph.isItalicRequired,
+ glyph.isBoldRequired,
+ glyphBufferData,
+ style.outline);
+
+ uint32_t glyphBufferSize = glyphBufferData.width * glyphBufferData.height * Pixel::GetBytesPerPixel(glyphBufferData.format);
+ // If glyph buffer data don't have ownership, Or if we need to decompress, create new memory and replace ownership.
+ if(!glyphBufferData.isBufferOwned || glyphBufferData.compressionType != TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION)
+ {
+ uint8_t* newBuffer = (uint8_t*)malloc(glyphBufferSize);
+ if(DALI_LIKELY(newBuffer != nullptr))
+ {
+ TextAbstraction::FontClient::GlyphBufferData::Decompress(glyphBufferData, newBuffer);
+ if(glyphBufferData.isBufferOwned)
+ {
+ // Release previous buffer
+ free(glyphBufferData.buffer);
+ }
+ glyphBufferData.isBufferOwned = true;
+ glyphBufferData.buffer = newBuffer;
+ glyphBufferData.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+ }
+ }
+
+ // Create the pixel data.
+ bitmap = PixelData::New(glyphBufferData.buffer,
+ glyphBufferSize,
+ glyphBufferData.width,
+ glyphBufferData.height,
+ glyphBufferData.format,
+ PixelData::FREE);
+
+ // Change buffer ownership.
+ glyphBufferData.isBufferOwned = false;
+
+ if(bitmap)
+ {
+ // Ensure that the next image will fit into the current block size
+ if(bitmap.GetWidth() > blockSize.mNeededBlockWidth)
+ {
+ blockSize.mNeededBlockWidth = bitmap.GetWidth();
+ }
+
+ if(bitmap.GetHeight() > blockSize.mNeededBlockHeight)
+ {
+ blockSize.mNeededBlockHeight = bitmap.GetHeight();
+ }
+
+ // If CheckAtlas in AtlasManager::Add can't fit the bitmap in the current atlas it will create a new atlas
+
+ // Setting the block size and size of new atlas does not mean a new one will be created. An existing atlas may still surffice.
+ uint32_t default_width = defaultTextAtlasSize.width;
+ uint32_t default_height = defaultTextAtlasSize.height;
+
+ while(
+ (blockSize.mNeededBlockWidth >= (default_width - (DOUBLE_PIXEL_PADDING + 1u)) ||
+ blockSize.mNeededBlockHeight >= (default_height - (DOUBLE_PIXEL_PADDING + 1u))) &&
+ (default_width < maximumTextAtlasSize.width &&
+ default_height < maximumTextAtlasSize.height))
+ {
+ default_width <<= 1u;
+ default_height <<= 1u;
+ }
+ mGlyphManager.SetNewAtlasSize(default_width,
+ default_height,
+ blockSize.mNeededBlockWidth,
+ blockSize.mNeededBlockHeight);
+
+ // Locate a new slot for our glyph
+ mGlyphManager.Add(glyph, style, bitmap, slot); // slot will be 0 is glyph not added
+ }
+ }
+ }
+ else
+ {
+ // We have 2+ copies of the same glyph
+ mGlyphManager.AdjustReferenceCount(glyph.fontId, glyph.index, style, 1); //increment
+ }
+ }
+
+ void GenerateMesh(const GlyphInfo& glyph,
+ const Vector2& position,
+ const Vector4& color,
+ uint16_t outline,
+ AtlasManager::AtlasSlot& slot,
+ bool decorationlineGlyph,
+ float currentUnderlinePosition,
+ float currentlineThickness,
+ std::vector<MeshRecord>& meshContainer,
+ Vector<TextCacheEntry>& newTextCache,
+ Vector<Extent>& extents,
+ uint32_t underlineChunkId,
+ bool isGlyphCached,
+ uint32_t strikethroughChunkId)
+ {
+ // Generate mesh data for this quad, plugging in our supplied position
+ AtlasManager::Mesh2D newMesh;
+ mGlyphManager.GenerateMeshData(slot.mImageId, position, newMesh);
+
+ if(!isGlyphCached)
+ {
+ TextCacheEntry textCacheEntry;
+ textCacheEntry.mFontId = glyph.fontId;
+ textCacheEntry.mImageId = slot.mImageId;
+ textCacheEntry.mIndex = glyph.index;
+ textCacheEntry.mOutlineWidth = outline;
+ textCacheEntry.isItalic = glyph.isItalicRequired;
+ textCacheEntry.isBold = glyph.isBoldRequired;
+
+ newTextCache.PushBack(textCacheEntry);
+ }
+
+ AtlasManager::Vertex2D* verticesBuffer = newMesh.mVertices.Begin();
+
+ for(unsigned int index = 0u, size = newMesh.mVertices.Count();
+ index < size;
+ ++index)
+ {
+ AtlasManager::Vertex2D& vertex = *(verticesBuffer + index);
+
+ // Set the color of the vertex.
+ vertex.mColor = color;
+ }