2 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <dali/integration-api/debug.h>
18 #include <dali/internal/text/text-abstraction/plugin/font-client-utils.h>
19 #include <dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.h>
22 #if defined(DEBUG_ENABLED)
23 extern Dali::Integration::Log::Filter* gFontClientLogFilter;
26 namespace Dali::TextAbstraction::Internal
32 GlyphCacheManager::GlyphCacheManager(FT_Face ftFace, std::size_t maxNumberOfGlyphCache)
33 : mFreeTypeFace(ftFace),
34 mGlyphCacheMaxSize(maxNumberOfGlyphCache),
35 mLRUGlyphCache(mGlyphCacheMaxSize)
37 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager Create with maximum size : %d\n", static_cast<int>(mGlyphCacheMaxSize));
39 GlyphCacheManager::~GlyphCacheManager()
41 while(!mLRUGlyphCache.IsEmpty())
43 auto removedData = mLRUGlyphCache.Pop();
45 // Release Glyph data resource
46 removedData.ReleaseGlyphData();
48 mLRUGlyphCache.Clear();
51 bool GlyphCacheManager::GetGlyphCacheDataFromIndex(
52 const GlyphIndex& index,
54 const bool& isBoldRequired,
55 GlyphCacheData& glyphData,
58 // Append some error value here instead of FT_Err_Ok.
59 error = static_cast<FT_Error>(-1);
61 const GlyphCacheKey key = GlyphCacheKey(index, flag, isBoldRequired);
62 auto iter = mLRUGlyphCache.Find(key);
64 if(iter == mLRUGlyphCache.End())
66 // If cache size is full, remove oldest glyph.
67 if(mLRUGlyphCache.IsFull())
69 auto removedData = mLRUGlyphCache.Pop();
71 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Remove oldest cache for glyph : %p\n", removedData.mGlyph);
73 // Release Glyph data resource
74 removedData.ReleaseGlyphData();
77 const bool loadSuccess = LoadGlyphDataFromIndex(index, flag, isBoldRequired, glyphData, error);
80 // Copy and cached data.
81 mLRUGlyphCache.Push(key, glyphData);
83 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Create cache for index : %u flag : %d isBold : %d isBitmap : %d, glyph : %p\n", index, static_cast<int>(flag), isBoldRequired, glyphData.mIsBitmap, glyphData.mGlyph);
92 // We already notify that we use this glyph. And now, copy cached data.
93 glyphData = iter->element;
95 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Find cache for index : %u flag : %d isBold : %d isBitmap : %d, glyph : %p\n", index, static_cast<int>(flag), isBoldRequired, glyphData.mIsBitmap, glyphData.mGlyph);
100 bool GlyphCacheManager::LoadGlyphDataFromIndex(
101 const GlyphIndex& index,
102 const FT_Int32& flag,
103 const bool& isBoldRequired,
104 GlyphCacheData& glyphData,
107 error = FT_Load_Glyph(mFreeTypeFace, index, flag);
108 if(FT_Err_Ok == error)
110 glyphData.mStyleFlags = mFreeTypeFace->style_flags;
112 const bool isEmboldeningRequired = isBoldRequired && !(glyphData.mStyleFlags & FT_STYLE_FLAG_BOLD);
113 if(isEmboldeningRequired)
115 // Does the software bold.
116 FT_GlyphSlot_Embolden(mFreeTypeFace->glyph);
119 glyphData.mGlyphMetrics = mFreeTypeFace->glyph->metrics;
120 glyphData.mIsBitmap = false;
122 error = FT_Get_Glyph(mFreeTypeFace->glyph, &glyphData.mGlyph);
124 if(glyphData.mGlyph->format == FT_GLYPH_FORMAT_BITMAP)
126 // Copy original glyph infomation. Due to we use union, we should keep original handle.
127 FT_Glyph bitmapGlyph = glyphData.mGlyph;
129 // Copy rendered bitmap
130 // TODO : Is there any way to keep bitmap buffer without copy?
131 glyphData.mBitmap = new FT_Bitmap();
132 *glyphData.mBitmap = mFreeTypeFace->glyph->bitmap;
134 // New allocate buffer
135 size_t bufferSize = 0;
136 switch(glyphData.mBitmap->pixel_mode)
138 case FT_PIXEL_MODE_GRAY:
140 if(glyphData.mBitmap->pitch == static_cast<int>(glyphData.mBitmap->width))
142 bufferSize = static_cast<size_t>(glyphData.mBitmap->width) * static_cast<size_t>(glyphData.mBitmap->rows);
146 #ifdef FREETYPE_BITMAP_SUPPORT
147 case FT_PIXEL_MODE_BGRA:
149 if(glyphData.mBitmap->pitch == static_cast<int>(glyphData.mBitmap->width << 2u))
151 bufferSize = (static_cast<size_t>(glyphData.mBitmap->width) * static_cast<size_t>(glyphData.mBitmap->rows)) << 2u;
158 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::GlyphCacheManager::LoadGlyphDataFromIndex. FontClient Unable to create Bitmap of this PixelType\n");
165 glyphData.mIsBitmap = true;
166 glyphData.mBitmap->buffer = new uint8_t[bufferSize];
167 memcpy(glyphData.mBitmap->buffer, mFreeTypeFace->glyph->bitmap.buffer, bufferSize);
171 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::GlyphCacheManager::LoadGlyphDataFromIndex. Bitmap glyph buffer size is zero\n");
172 delete glyphData.mBitmap;
173 glyphData.mBitmap = nullptr;
174 error = static_cast<FT_Error>(-1);
177 // Release glyph data.
178 FT_Done_Glyph(bitmapGlyph);
181 if(FT_Err_Ok == error)
189 void GlyphCacheManager::GlyphCacheData::ReleaseGlyphData()
191 if(mIsBitmap && mBitmap)
193 // Created FT_Bitmap object must be released with FT_Bitmap_Done
194 delete[] mBitmap->buffer;
200 // Created FT_Glyph object must be released with FT_Done_Glyph
201 FT_Done_Glyph(mGlyph);
206 } // namespace Dali::TextAbstraction::Internal