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.
19 #include <dali/internal/text/text-abstraction/plugin/font-client-plugin-cache-handler.h>
22 #include <dali/integration-api/debug.h>
23 #include <dali/integration-api/trace.h>
24 #include <fontconfig/fontconfig.h>
27 #include <dali/devel-api/adaptor-framework/environment-variable.h>
28 #include <dali/devel-api/adaptor-framework/image-loading.h>
29 #include <dali/internal/text/text-abstraction/font-client-impl.h>
30 #include <dali/internal/text/text-abstraction/plugin/font-client-plugin-impl.h>
31 #include <dali/internal/text/text-abstraction/plugin/font-client-utils.h>
33 #if defined(DEBUG_ENABLED)
34 extern Dali::Integration::Log::Filter* gFontClientLogFilter;
36 #define FONT_LOG_DESCRIPTION(fontDescription, prefix) \
37 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, #prefix " description; family : [%s]\n", fontDescription.family.c_str()); \
38 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, \
42 " slant : [%s]\n\n", \
43 fontDescription.path.c_str(), \
44 FontWidth::Name[fontDescription.width], \
45 FontWeight::Name[fontDescription.weight], \
46 FontSlant::Name[fontDescription.slant])
48 #define FONT_LOG_REQUEST(charcode, requestedPointSize, preferColor) \
49 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, \
51 " requestedPointSize : %d\n" \
52 " preferColor : %s\n", \
55 (preferColor ? "true" : "false"))
59 #define FONT_LOG_DESCRIPTION(fontDescription, prefix)
60 #define FONT_LOG_REQUEST(charcode, requestedPointSize, preferColor)
67 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_FONT_PERFORMANCE_MARKER, false);
70 * @brief Maximum size of glyph cache per each font face.
72 constexpr std::size_t DEFAULT_GLYPH_CACHE_MAX = 128;
73 constexpr std::size_t MINIMUM_SIZE_OF_GLYPH_CACHE_MAX = 3u;
75 constexpr auto MAX_NUMBER_OF_GLYPH_CACHE_ENV = "DALI_GLYPH_CACHE_MAX";
78 * @brief Get maximum size of glyph cache size from environment.
79 * If not settuped, default as 128.
80 * @note This value fixed when we call it first time.
81 * @return The max size of glyph cache.
83 inline size_t GetMaxNumberOfGlyphCache()
85 using Dali::EnvironmentVariable::GetEnvironmentVariable;
86 static auto numberString = GetEnvironmentVariable(MAX_NUMBER_OF_GLYPH_CACHE_ENV);
87 static auto number = numberString ? std::strtoul(numberString, nullptr, 10) : DEFAULT_GLYPH_CACHE_MAX;
88 return (number < MINIMUM_SIZE_OF_GLYPH_CACHE_MAX) ? MINIMUM_SIZE_OF_GLYPH_CACHE_MAX : number;
93 namespace Dali::TextAbstraction::Internal
98 * @brief Free the resources allocated by the FcCharSet objects.
100 * @param[in] characterSets The vector of character sets.
102 void DestroyCharacterSets(CharacterSetList& characterSets)
104 for(auto& item : characterSets)
108 FcCharSetDestroy(item);
114 * @brief Retrieves the fonts present in the platform.
116 * @note Need to call FcFontSetDestroy to free the allocated resources.
118 * @return A font fonfig data structure with the platform's fonts.
120 _FcFontSet* GetFcFontSet()
122 FcFontSet* fontset = nullptr;
124 // create a new pattern.
125 // a pattern holds a set of names, each name refers to a property of the font
126 FcPattern* pattern = FcPatternCreate();
128 if(nullptr != pattern)
130 // create an object set used to define which properties are to be returned in the patterns from FcFontList.
131 FcObjectSet* objectSet = FcObjectSetCreate();
133 if(nullptr != objectSet)
135 // build an object set from a list of property names
136 FcObjectSetAdd(objectSet, FC_FILE);
137 FcObjectSetAdd(objectSet, FC_FAMILY);
138 FcObjectSetAdd(objectSet, FC_WIDTH);
139 FcObjectSetAdd(objectSet, FC_WEIGHT);
140 FcObjectSetAdd(objectSet, FC_SLANT);
142 // get a list of fonts
143 // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
144 fontset = FcFontList(nullptr /* the default configuration is checked to be up to date, and used */, pattern, objectSet); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
146 // clear up the object set
147 FcObjectSetDestroy(objectSet);
150 // clear up the pattern
151 FcPatternDestroy(pattern);
158 * @brief Helper for GetDefaultFonts etc.
160 * @note CharacterSetList is a vector of FcCharSet that are reference counted. It's needed to call FcCharSetDestroy to decrease the reference counter.
162 * @param[in] fontDescription A font description.
163 * @param[out] fontList A list of the fonts which are a close match for fontDescription.
164 * @param[out] characterSetList A list of character sets which are a close match for fontDescription.
166 void SetFontList(const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList)
168 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
171 FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
173 FcResult result = FcResultMatch;
175 // Match the pattern.
176 FcFontSet* fontSet = FcFontSort(nullptr /* use default configure */,
178 false /* don't trim */,
180 &result); // FcFontSort creates a font set that needs to be destroyed by calling FcFontSetDestroy.
182 if(nullptr != fontSet)
184 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " number of fonts found : [%d]\n", fontSet->nfont);
185 // Reserve some space to avoid reallocations.
186 fontList.reserve(fontSet->nfont);
188 for(int i = 0u; i < fontSet->nfont; ++i)
190 FcPattern* fontPattern = fontSet->fonts[i];
194 // Skip fonts with no path
195 if(GetFcString(fontPattern, FC_FILE, path))
197 // Retrieve the character set. Need to call FcCharSetDestroy to free the resources.
198 FcCharSet* characterSet = nullptr;
199 FcPatternGetCharSet(fontPattern, FC_CHARSET, 0u, &characterSet);
201 // Increase the reference counter of the character set.
202 characterSetList.PushBack(FcCharSetCopy(characterSet));
204 fontList.push_back(FontDescription());
205 FontDescription& newFontDescription = fontList.back();
207 newFontDescription.path = std::move(path);
212 GetFcString(fontPattern, FC_FAMILY, newFontDescription.family);
213 GetFcInt(fontPattern, FC_WIDTH, width);
214 GetFcInt(fontPattern, FC_WEIGHT, weight);
215 GetFcInt(fontPattern, FC_SLANT, slant);
216 newFontDescription.width = IntToWidthType(width);
217 newFontDescription.weight = IntToWeightType(weight);
218 newFontDescription.slant = IntToSlantType(slant);
220 FONT_LOG_DESCRIPTION(newFontDescription, "new font");
224 // Destroys the font set created by FcFontSort.
225 FcFontSetDestroy(fontSet);
229 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " No fonts found.\n");
232 // Destroys the pattern created by FcPatternCreate in CreateFontFamilyPattern.
233 FcPatternDestroy(fontFamilyPattern);
238 FontClient::Plugin::CacheHandler::FallbackCacheItem::FallbackCacheItem(FontDescription&& font, FontList* fallbackFonts, CharacterSetList* characterSets)
239 : fontDescription{std::move(font)},
240 fallbackFonts{fallbackFonts},
241 characterSets{characterSets}
245 FontClient::Plugin::CacheHandler::FontDescriptionCacheItem::FontDescriptionCacheItem(const FontDescription& fontDescription,
246 FontDescriptionId index)
247 : fontDescription{fontDescription},
252 FontClient::Plugin::CacheHandler::FontDescriptionCacheItem::FontDescriptionCacheItem(FontDescription&& fontDescription,
253 FontDescriptionId index)
254 : fontDescription{std::move(fontDescription)},
259 FontClient::Plugin::CacheHandler::FontDescriptionSizeCacheKey::FontDescriptionSizeCacheKey(FontDescriptionId fontDescriptionId,
260 PointSize26Dot6 requestedPointSize)
261 : fontDescriptionId(fontDescriptionId),
262 requestedPointSize(requestedPointSize)
267 FontClient::Plugin::CacheHandler::CacheHandler()
268 : mDefaultFontDescription(),
273 mValidatedFontCache(),
274 mFontDescriptionCache(),
275 mCharacterSetCache(),
276 mFontDescriptionSizeCache(),
278 mEmbeddedItemCache(),
279 mGlyphCacheManager(new GlyphCacheManager(GetMaxNumberOfGlyphCache())),
280 mLatestFoundFontDescription(),
281 mLatestFoundFontDescriptionId(0u),
282 mLatestFoundCacheKey(0, 0),
283 mLatestFoundCacheIndex(0u),
284 mDefaultFontDescriptionCached(false)
288 FontClient::Plugin::CacheHandler::~CacheHandler()
293 void FontClient::Plugin::CacheHandler::ClearCache()
295 // delete cached glyph informations before clear mFontFaceCache.
296 mGlyphCacheManager->ClearCache();
298 mDefaultFontDescription = FontDescription();
300 mSystemFonts.clear();
301 mDefaultFonts.clear();
303 DestroyCharacterSets(mDefaultFontCharacterSets);
304 mDefaultFontCharacterSets.Clear();
306 ClearFallbackCache();
307 mFallbackCache.clear();
309 mFontIdCache.clear();
311 ClearCharacterSetFromFontFaceCache();
312 mFontFaceCache.clear();
314 mValidatedFontCache.clear();
315 mFontDescriptionCache.clear();
317 DestroyCharacterSets(mCharacterSetCache);
318 mCharacterSetCache.Clear();
320 mFontDescriptionSizeCache.clear();
321 mFontDescriptionSizeCache.rehash(0); // Note : unordered_map.clear() didn't deallocate memory
323 mEllipsisCache.clear();
324 mPixelBufferCache.clear();
325 mEmbeddedItemCache.clear();
326 mBitmapFontCache.clear();
328 mLatestFoundFontDescription.family.clear();
329 mLatestFoundCacheKey = FontDescriptionSizeCacheKey(0, 0);
331 mDefaultFontDescriptionCached = false;
334 void FontClient::Plugin::CacheHandler::ResetSystemDefaults()
336 mDefaultFontDescriptionCached = false;
341 void FontClient::Plugin::CacheHandler::ClearFallbackCache()
343 for(auto& item : mFallbackCache)
345 if(nullptr != item.fallbackFonts)
347 delete item.fallbackFonts;
350 if(nullptr != item.characterSets)
352 // Free the resources allocated by the FcCharSet objects in the 'characterSets' vector.
353 DestroyCharacterSets(*item.characterSets);
354 delete item.characterSets;
359 void FontClient::Plugin::CacheHandler::ClearCharacterSetFromFontFaceCache()
361 for(auto& item : mFontFaceCache)
363 FcCharSetDestroy(item.mCharacterSet);
364 item.mCharacterSet = nullptr;
368 void FontClient::Plugin::CacheHandler::ClearCharacterSet()
370 // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
371 DestroyCharacterSets(mDefaultFontCharacterSets);
372 DestroyCharacterSets(mCharacterSetCache);
373 mDefaultFontCharacterSets.Clear();
374 mCharacterSetCache.Clear();
376 for(auto& item : mFallbackCache)
378 // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
379 DestroyCharacterSets(*item.characterSets);
381 delete item.characterSets;
382 item.characterSets = nullptr;
385 // Set the character set pointer as null. Will be created again the next time IsCharacterSupportedByFont()
386 ClearCharacterSetFromFontFaceCache();
389 void FontClient::Plugin::CacheHandler::CreateCharacterSet()
391 for(const auto& description : mDefaultFonts)
393 mDefaultFontCharacterSets.PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
396 for(const auto& description : mFontDescriptionCache)
398 mCharacterSetCache.PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
401 for(auto& item : mFallbackCache)
403 if(nullptr != item.fallbackFonts)
405 if(nullptr == item.characterSets)
407 item.characterSets = new CharacterSetList;
410 for(const auto& description : *(item.fallbackFonts))
412 item.characterSets->PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
420 void FontClient::Plugin::CacheHandler::InitSystemFonts()
422 if(mSystemFonts.empty())
424 FcFontSet* fontSet = GetFcFontSet(); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
428 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " number of system fonts : %d\n", fontSet->nfont);
430 // Reserve some space to avoid reallocations.
431 mSystemFonts.reserve(fontSet->nfont);
433 for(int i = 0u; i < fontSet->nfont; ++i)
435 FcPattern* fontPattern = fontSet->fonts[i];
439 // Skip fonts with no path
440 if(GetFcString(fontPattern, FC_FILE, path))
442 mSystemFonts.push_back(FontDescription());
443 FontDescription& fontDescription = mSystemFonts.back();
445 fontDescription.path = std::move(path);
450 GetFcString(fontPattern, FC_FAMILY, fontDescription.family);
451 GetFcInt(fontPattern, FC_WIDTH, width);
452 GetFcInt(fontPattern, FC_WEIGHT, weight);
453 GetFcInt(fontPattern, FC_SLANT, slant);
454 fontDescription.width = IntToWidthType(width);
455 fontDescription.weight = IntToWeightType(weight);
456 fontDescription.slant = IntToSlantType(slant);
458 FONT_LOG_DESCRIPTION(fontDescription, "system fonts");
462 // Destroys the font set created.
463 FcFontSetDestroy(fontSet);
468 void FontClient::Plugin::CacheHandler::InitDefaultFonts()
470 if(mDefaultFonts.empty())
472 FontDescription fontDescription;
473 fontDescription.family = DefaultFontFamily(); // todo This could be set to the Platform font
474 fontDescription.width = DefaultFontWidth();
475 fontDescription.weight = DefaultFontWeight();
476 fontDescription.slant = DefaultFontSlant();
477 SetFontList(fontDescription, mDefaultFonts, mDefaultFontCharacterSets);
481 void FontClient::Plugin::CacheHandler::InitDefaultFontDescription()
483 if(!mDefaultFontDescriptionCached)
485 // Clear any font config stored info in the caches.
488 // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
489 FcInitReinitialize();
491 FcPattern* matchPattern = FcPatternCreate(); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
493 if(nullptr != matchPattern)
495 FcConfigSubstitute(nullptr, matchPattern, FcMatchPattern);
496 FcDefaultSubstitute(matchPattern);
498 FcCharSet* characterSet = nullptr;
499 bool matched = MatchFontDescriptionToPattern(matchPattern, mDefaultFontDescription, &characterSet);
501 // Caching the default font description
504 // Copy default font description info.
505 // Due to the type changed, we need to make some temperal font description.
506 FontDescription tempFontDescription = mDefaultFontDescription;
508 // Add the path to the cache.
509 tempFontDescription.type = FontDescription::FACE_FONT;
510 mFontDescriptionCache.push_back(tempFontDescription);
512 // Set the index to the vector of paths to font file names.
513 const FontDescriptionId fontDescriptionId = static_cast<FontDescriptionId>(mFontDescriptionCache.size());
515 FONT_LOG_DESCRIPTION(tempFontDescription, "default platform font");
516 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " default font fontDescriptionId : %d\n", fontDescriptionId);
518 // Cache the index and the matched font's description.
519 CacheValidateFont(std::move(tempFontDescription), fontDescriptionId);
523 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " default font validation failed for font [%s]\n", mDefaultFontDescription.family.c_str());
526 // Decrease the reference counter of the character set as it's not stored.
527 // Note. the cached default font description will increase reference counter by
528 // mFontDescriptionCache in CreateCharacterSet(). So we can decrease reference counter here.
529 FcCharSetDestroy(characterSet);
531 // Destroys the pattern created.
532 FcPatternDestroy(matchPattern);
535 // Create again the character sets as they are not valid after FcInitReinitialize()
536 CreateCharacterSet();
538 mDefaultFontDescriptionCached = true;
544 bool FontClient::Plugin::CacheHandler::FindValidatedFont(const FontDescription& fontDescription,
545 FontDescriptionId& fontDescriptionId)
547 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
548 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " number of validated fonts in the cache : %zu\n", mValidatedFontCache.size());
550 fontDescriptionId = 0u;
552 // Fast cut if inputed family is empty.
553 if(DALI_UNLIKELY(fontDescription.family.empty()))
555 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " validated font description not found / fontDescription.family is empty!\n");
559 // Heuristic optimize code : Compare with latest found item.
560 if((fontDescription.width == mLatestFoundFontDescription.width) &&
561 (fontDescription.weight == mLatestFoundFontDescription.weight) &&
562 (fontDescription.slant == mLatestFoundFontDescription.slant) &&
563 (fontDescription.family == mLatestFoundFontDescription.family))
565 fontDescriptionId = mLatestFoundFontDescriptionId;
567 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " validated font description same as latest, id : %d\n", fontDescriptionId);
571 for(const auto& item : mValidatedFontCache)
573 if((fontDescription.width == item.fontDescription.width) &&
574 (fontDescription.weight == item.fontDescription.weight) &&
575 (fontDescription.slant == item.fontDescription.slant) &&
576 (fontDescription.family == item.fontDescription.family))
578 fontDescriptionId = item.index;
580 mLatestFoundFontDescription = fontDescription;
581 mLatestFoundFontDescriptionId = fontDescriptionId;
583 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " validated font description found, id : %d\n", fontDescriptionId);
588 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " validated font description not found\n");
592 void FontClient::Plugin::CacheHandler::ValidateFont(const FontDescription& fontDescription,
593 FontDescriptionId& fontDescriptionId)
595 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
596 FONT_LOG_DESCRIPTION(fontDescription, "");
598 DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_VALIDATE_FONT");
600 // Create a font pattern.
601 FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription);
603 FontDescription description;
605 FcCharSet* characterSet = nullptr;
606 bool matched = MatchFontDescriptionToPattern(fontFamilyPattern, description, &characterSet);
607 FcPatternDestroy(fontFamilyPattern);
609 if(matched && (nullptr != characterSet))
611 #if defined(TRACE_ENABLED)
612 if(gTraceFilter && gTraceFilter->IsTraceEnabled())
614 DALI_LOG_DEBUG_INFO("DALI_TEXT_VALIDATE_FONT : FcFontMatch : %s, style : %s, %s, %s\n", fontDescription.family.c_str(), FontWidth::Name[fontDescription.width], FontWeight::Name[fontDescription.weight], FontSlant::Name[fontDescription.slant]);
618 // Add the path to the cache.
619 description.type = FontDescription::FACE_FONT;
620 mFontDescriptionCache.push_back(description);
622 // Set the index to the vector of paths to font file names.
623 fontDescriptionId = static_cast<FontDescriptionId>(mFontDescriptionCache.size());
625 FONT_LOG_DESCRIPTION(description, "matched");
626 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " fontDescriptionId : %d\n", fontDescriptionId);
628 // The reference counter of the character set has already been increased in MatchFontDescriptionToPattern.
629 mCharacterSetCache.PushBack(characterSet);
631 if((fontDescription.family != description.family) ||
632 (fontDescription.width != description.width) ||
633 (fontDescription.weight != description.weight) ||
634 (fontDescription.slant != description.slant))
636 // Cache the given font's description if it's different than the matched.
637 CacheValidateFont(std::move(FontDescription(fontDescription)), fontDescriptionId);
640 // Cache the index and the matched font's description.
641 CacheValidateFont(std::move(description), fontDescriptionId);
645 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font validation failed for font [%s]\n", fontDescription.family.c_str());
649 void FontClient::Plugin::CacheHandler::CacheValidateFont(FontDescription&& fontDescription,
650 FontDescriptionId validatedFontId)
652 mValidatedFontCache.emplace_back(std::move(FontDescriptionCacheItem(fontDescription, validatedFontId)));
657 bool FontClient::Plugin::CacheHandler::FindFallbackFontList(const FontDescription& fontDescription,
659 CharacterSetList*& characterSetList) const
661 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
662 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " number of fallback font lists in the cache : %zu\n", mFallbackCache.size());
666 for(const auto& item : mFallbackCache)
668 if(!fontDescription.family.empty() &&
669 (fontDescription.family == item.fontDescription.family) &&
670 (fontDescription.width == item.fontDescription.width) &&
671 (fontDescription.weight == item.fontDescription.weight) &&
672 (fontDescription.slant == item.fontDescription.slant))
674 fontList = item.fallbackFonts;
675 characterSetList = item.characterSets;
677 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " fallback font list found.\n");
682 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " fallback font list not found.\n");
686 void FontClient::Plugin::CacheHandler::CacheFallbackFontList(FontDescription&& fontDescription,
688 CharacterSetList*& characterSetList)
690 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
692 DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_FALLBACK_FONTLIST");
694 #if defined(TRACE_ENABLED)
695 if(gTraceFilter && gTraceFilter->IsTraceEnabled())
697 DALI_LOG_DEBUG_INFO("DALI_TEXT_FALLBACK_FONTLIST : FcFontSort : %s\n", fontDescription.family.c_str());
701 fontList = new FontList;
702 characterSetList = new CharacterSetList;
704 SetFontList(fontDescription, *fontList, *characterSetList);
706 FontDescription appleColorEmoji;
707 appleColorEmoji.family = "Apple Color Emoji";
708 appleColorEmoji.width = fontDescription.width;
709 appleColorEmoji.weight = fontDescription.weight;
710 appleColorEmoji.slant = fontDescription.slant;
711 FontList emojiFontList;
712 CharacterSetList emojiCharSetList;
713 SetFontList(appleColorEmoji, emojiFontList, emojiCharSetList);
715 std::move(fontList->begin(), fontList->end(), std::back_inserter(emojiFontList));
716 emojiCharSetList.Insert(emojiCharSetList.End(), characterSetList->Begin(), characterSetList->End());
717 *fontList = std::move(emojiFontList);
718 *characterSetList = std::move(emojiCharSetList);
721 // Add the font-list to the cache.
722 mFallbackCache.push_back(std::move(CacheHandler::FallbackCacheItem(std::move(fontDescription), fontList, characterSetList)));
727 bool FontClient::Plugin::CacheHandler::FindFontByPath(const FontPath& path,
728 PointSize26Dot6 requestedPointSize,
730 FontId& fontId) const
732 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
733 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " path : [%s]\n", path.c_str());
734 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
735 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " number of fonts in the cache : %zu\n", mFontFaceCache.size());
738 for(const auto& cacheItem : mFontFaceCache)
740 if(cacheItem.mRequestedPointSize == requestedPointSize &&
741 cacheItem.mFaceIndex == faceIndex &&
742 cacheItem.mPath == path)
744 fontId = cacheItem.mFontId + 1u;
746 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font found, id : %d\n", fontId);
751 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font not found\n");
755 bool FontClient::Plugin::CacheHandler::FindFont(FontDescriptionId fontDescriptionId,
756 PointSize26Dot6 requestedPointSize,
757 FontCacheIndex& fontCacheIndex)
759 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
760 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " fontDescriptionId : %d\n", fontDescriptionId);
761 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
765 const FontDescriptionSizeCacheKey key(fontDescriptionId, requestedPointSize);
767 // Heuristic optimize code : Compare with latest found item.
768 if(key == mLatestFoundCacheKey)
770 fontCacheIndex = mLatestFoundCacheIndex;
772 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font same as latest, index of font cache : %d\n", fontCacheIndex);
776 const auto& iter = mFontDescriptionSizeCache.find(key);
777 if(iter != mFontDescriptionSizeCache.cend())
779 fontCacheIndex = iter->second;
781 mLatestFoundCacheKey = key;
782 mLatestFoundCacheIndex = fontCacheIndex;
784 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font found, index of font cache : %d\n", fontCacheIndex);
788 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font not found.\n");
792 void FontClient::Plugin::CacheHandler::CacheFontDescriptionSize(FontDescriptionId fontDescriptionId, PointSize26Dot6 requestedPointSize, FontCacheIndex fontCacheIndex)
794 mFontDescriptionSizeCache.emplace(FontDescriptionSizeCacheKey(fontDescriptionId, requestedPointSize), fontCacheIndex);
797 void FontClient::Plugin::CacheHandler::CacheFontPath(FT_Face ftFace, FontId fontId, PointSize26Dot6 requestedPointSize, const FontPath& path)
799 FontDescription description;
800 description.path = path;
801 description.family = std::move(FontFamily(ftFace->family_name));
802 description.weight = FontWeight::NONE;
803 description.width = FontWidth::NONE;
804 description.slant = FontSlant::NONE;
806 // Note FreeType doesn't give too much info to build a proper font style.
807 if(ftFace->style_flags & FT_STYLE_FLAG_ITALIC)
809 description.slant = FontSlant::ITALIC;
811 if(ftFace->style_flags & FT_STYLE_FLAG_BOLD)
813 description.weight = FontWeight::BOLD;
816 FontDescriptionId fontDescriptionId = 0u;
817 if(!FindValidatedFont(description, fontDescriptionId))
819 // TODO : Due to the FontClient pattern match process, we cannot pass dali-toolkit UTC.
820 // Can't we use ValidateFont here?
822 // Use font config to validate the font's description.
823 ValidateFont(description, fontDescriptionId);
825 const FontCacheIndex fontCacheIndex = mFontIdCache[fontId - 1u].index;
826 mFontFaceCache[fontCacheIndex].mCharacterSet = FcCharSetCopy(mCharacterSetCache[fontDescriptionId - 1u]); // Increases the reference counter.
828 // Cache the pair 'fontDescriptionId, requestedPointSize' to improve the following queries.
829 mFontDescriptionSizeCache.emplace(CacheHandler::FontDescriptionSizeCacheKey(fontDescriptionId, requestedPointSize), fontCacheIndex);
832 FcPattern* pattern = CreateFontFamilyPattern(description); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
834 FcResult result = FcResultMatch;
835 FcPattern* match = FcFontMatch(nullptr, pattern, &result); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
837 FcCharSet* characterSet = nullptr;
838 FcPatternGetCharSet(match, FC_CHARSET, 0u, &characterSet);
840 const FontCacheIndex fontCacheIndex = mFontIdCache[fontId - 1u].index;
841 mFontFaceCache[fontCacheIndex].mCharacterSet = FcCharSetCopy(characterSet); // Increases the reference counter.
843 // Destroys the created patterns.
844 FcPatternDestroy(match);
845 FcPatternDestroy(pattern);
847 // Add the path to the cache.
848 description.type = FontDescription::FACE_FONT;
849 mFontDescriptionCache.push_back(description);
851 // Set the index to the vector of paths to font file names.
852 fontDescriptionId = static_cast<FontDescriptionId>(mFontDescriptionCache.size());
854 // Increase the reference counter and add the character set to the cache.
855 mCharacterSetCache.PushBack(FcCharSetCopy(characterSet));
857 // Cache the index and the font's description.
858 CacheValidateFont(std::move(description), fontDescriptionId);
860 // Cache the pair 'fontDescriptionId, requestedPointSize' to improve the following queries.
861 CacheFontDescriptionSize(fontDescriptionId, requestedPointSize, fontCacheIndex);
865 FontId FontClient::Plugin::CacheHandler::CacheFontFaceCacheItem(FontFaceCacheItem&& fontFaceCacheItem)
867 // Set the index to the font's id cache.
868 fontFaceCacheItem.mFontId = static_cast<FontId>(mFontIdCache.size());
870 // Create the font id item to cache.
871 FontIdCacheItem fontIdCacheItem;
872 fontIdCacheItem.type = FontDescription::FACE_FONT;
874 // Set the index to the FreeType font face cache.
875 fontIdCacheItem.index = static_cast<FontCacheIndex>(mFontFaceCache.size());
878 mFontFaceCache.emplace_back(std::move(fontFaceCacheItem));
879 mFontIdCache.emplace_back(std::move(fontIdCacheItem));
881 // Set the font id to be returned.
882 FontId fontId = static_cast<FontId>(mFontIdCache.size());
889 bool FontClient::Plugin::CacheHandler::FindEllipsis(PointSize26Dot6 requestedPointSize, EllipsisCacheIndex& ellipsisCacheIndex) const
891 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
892 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize %d.\n", requestedPointSize);
894 ellipsisCacheIndex = 0u;
896 // First look into the cache if there is an ellipsis glyph for the requested point size.
897 for(const auto& item : mEllipsisCache)
899 if(item.requestedPointSize == requestedPointSize)
901 // Use the glyph in the cache.
902 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index);
903 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font %d.\n", item.glyph.fontId);
904 ellipsisCacheIndex = item.index;
911 FontClient::Plugin::CacheHandler::EllipsisCacheIndex FontClient::Plugin::CacheHandler::CacheEllipsis(EllipsisItem&& ellipsisItem)
913 EllipsisCacheIndex ellipsisCacheIndex = static_cast<EllipsisCacheIndex>(mEllipsisCache.size());
915 mEllipsisCache.emplace_back(std::move(ellipsisItem));
917 return ellipsisCacheIndex;
922 bool FontClient::Plugin::CacheHandler::FindBitmapFont(const FontFamily& bitmapFontFamily, FontId& fontId) const
926 for(const auto& item : mBitmapFontCache)
928 if(bitmapFontFamily == item.font.name)
930 fontId = item.id + 1u;
938 FontId FontClient::Plugin::CacheHandler::CacheBitmapFontCacheItem(BitmapFontCacheItem&& bitmapFontCacheItem)
940 // Set the index to the font's id cache.
941 bitmapFontCacheItem.id = static_cast<FontId>(mFontIdCache.size());
943 // Create the font id item to cache.
944 CacheHandler::FontIdCacheItem fontIdCacheItem;
945 fontIdCacheItem.type = FontDescription::BITMAP_FONT;
947 // Set the index to the Bitmap font face cache.
948 fontIdCacheItem.index = static_cast<FontCacheIndex>(mBitmapFontCache.size());
951 mBitmapFontCache.emplace_back(std::move(bitmapFontCacheItem));
952 mFontIdCache.emplace_back(std::move(fontIdCacheItem));
954 // Set the font id to be returned.
955 FontId fontId = static_cast<FontId>(mFontIdCache.size());
962 bool FontClient::Plugin::CacheHandler::FindEmbeddedPixelBufferId(const std::string& url, PixelBufferId& pixelBufferId) const
966 for(const auto& cacheItem : mPixelBufferCache)
968 if(cacheItem.url == url)
970 // The url is in the pixel buffer cache.
971 pixelBufferId = cacheItem.id;
979 PixelBufferId FontClient::Plugin::CacheHandler::CacheEmbeddedPixelBuffer(const std::string& url)
981 PixelBufferId pixelBufferId = 0u;
983 // Load the image from the url.
984 Devel::PixelBuffer pixelBuffer = LoadImageFromFile(url);
987 // Create the cache item.
988 PixelBufferCacheItem pixelBufferCacheItem;
989 pixelBufferCacheItem.pixelBuffer = pixelBuffer;
990 pixelBufferCacheItem.url = url;
991 pixelBufferCacheItem.id = static_cast<PixelBufferId>(mPixelBufferCache.size() + 1u);
993 // Store the cache item in the cache.
994 mPixelBufferCache.emplace_back(std::move(pixelBufferCacheItem));
996 // Set the pixel buffer id to be returned.
997 pixelBufferId = static_cast<PixelBufferId>(mPixelBufferCache.size());
999 return pixelBufferId;
1002 bool FontClient::Plugin::CacheHandler::FindEmbeddedItem(PixelBufferId pixelBufferId, uint32_t width, uint32_t height, GlyphIndex& index) const
1006 for(const auto& cacheItem : mEmbeddedItemCache)
1008 if((cacheItem.pixelBufferId == pixelBufferId) &&
1009 (cacheItem.width == width) &&
1010 (cacheItem.height == height))
1012 index = cacheItem.index;
1020 GlyphIndex FontClient::Plugin::CacheHandler::CacheEmbeddedItem(EmbeddedItem&& embeddedItem)
1022 embeddedItem.index = static_cast<GlyphIndex>(mEmbeddedItemCache.size() + 1u);
1024 // Cache the embedded item.
1025 mEmbeddedItemCache.emplace_back(std::move(embeddedItem));
1027 // Set the font id to be returned.
1028 GlyphIndex index = static_cast<GlyphIndex>(mEmbeddedItemCache.size());
1033 } // namespace Dali::TextAbstraction::Internal