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 <fontconfig/fontconfig.h>
26 #include <dali/devel-api/adaptor-framework/image-loading.h>
27 #include <dali/internal/text/text-abstraction/font-client-impl.h>
28 #include <dali/internal/text/text-abstraction/plugin/font-client-plugin-impl.h>
29 #include <dali/internal/text/text-abstraction/plugin/font-client-utils.h>
31 #if defined(DEBUG_ENABLED)
32 extern Dali::Integration::Log::Filter* gFontClientLogFilter;
34 #define FONT_LOG_DESCRIPTION(fontDescription, prefix) \
35 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, #prefix " description; family : [%s]\n", fontDescription.family.c_str()); \
36 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, \
40 " slant : [%s]\n\n", \
41 fontDescription.path.c_str(), \
42 FontWidth::Name[fontDescription.width], \
43 FontWeight::Name[fontDescription.weight], \
44 FontSlant::Name[fontDescription.slant])
46 #define FONT_LOG_REQUEST(charcode, requestedPointSize, preferColor) \
47 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, \
49 " requestedPointSize : %d\n" \
50 " preferColor : %s\n", \
53 (preferColor ? "true" : "false"))
57 #define FONT_LOG_DESCRIPTION(fontDescription, prefix)
58 #define FONT_LOG_REQUEST(charcode, requestedPointSize, preferColor)
66 namespace Dali::TextAbstraction::Internal
71 * @brief Free the resources allocated by the FcCharSet objects.
73 * @param[in] characterSets The vector of character sets.
75 void DestroyCharacterSets(CharacterSetList& characterSets)
77 for(auto& item : characterSets)
81 FcCharSetDestroy(item);
87 * @brief Retrieves the fonts present in the platform.
89 * @note Need to call FcFontSetDestroy to free the allocated resources.
91 * @return A font fonfig data structure with the platform's fonts.
93 _FcFontSet* GetFcFontSet()
95 FcFontSet* fontset = nullptr;
97 // create a new pattern.
98 // a pattern holds a set of names, each name refers to a property of the font
99 FcPattern* pattern = FcPatternCreate();
101 if(nullptr != pattern)
103 // create an object set used to define which properties are to be returned in the patterns from FcFontList.
104 FcObjectSet* objectSet = FcObjectSetCreate();
106 if(nullptr != objectSet)
108 // build an object set from a list of property names
109 FcObjectSetAdd(objectSet, FC_FILE);
110 FcObjectSetAdd(objectSet, FC_FAMILY);
111 FcObjectSetAdd(objectSet, FC_WIDTH);
112 FcObjectSetAdd(objectSet, FC_WEIGHT);
113 FcObjectSetAdd(objectSet, FC_SLANT);
115 // get a list of fonts
116 // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
117 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.
119 // clear up the object set
120 FcObjectSetDestroy(objectSet);
123 // clear up the pattern
124 FcPatternDestroy(pattern);
131 * @brief Helper for GetDefaultFonts etc.
133 * @note CharacterSetList is a vector of FcCharSet that are reference counted. It's needed to call FcCharSetDestroy to decrease the reference counter.
135 * @param[in] fontDescription A font description.
136 * @param[out] fontList A list of the fonts which are a close match for fontDescription.
137 * @param[out] characterSetList A list of character sets which are a close match for fontDescription.
139 void SetFontList(const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList)
141 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
144 FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
146 FcResult result = FcResultMatch;
148 // Match the pattern.
149 FcFontSet* fontSet = FcFontSort(nullptr /* use default configure */,
151 false /* don't trim */,
153 &result); // FcFontSort creates a font set that needs to be destroyed by calling FcFontSetDestroy.
155 if(nullptr != fontSet)
157 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " number of fonts found : [%d]\n", fontSet->nfont);
158 // Reserve some space to avoid reallocations.
159 fontList.reserve(fontSet->nfont);
161 for(int i = 0u; i < fontSet->nfont; ++i)
163 FcPattern* fontPattern = fontSet->fonts[i];
167 // Skip fonts with no path
168 if(GetFcString(fontPattern, FC_FILE, path))
170 // Retrieve the character set. Need to call FcCharSetDestroy to free the resources.
171 FcCharSet* characterSet = nullptr;
172 FcPatternGetCharSet(fontPattern, FC_CHARSET, 0u, &characterSet);
174 // Increase the reference counter of the character set.
175 characterSetList.PushBack(FcCharSetCopy(characterSet));
177 fontList.push_back(FontDescription());
178 FontDescription& newFontDescription = fontList.back();
180 newFontDescription.path = std::move(path);
185 GetFcString(fontPattern, FC_FAMILY, newFontDescription.family);
186 GetFcInt(fontPattern, FC_WIDTH, width);
187 GetFcInt(fontPattern, FC_WEIGHT, weight);
188 GetFcInt(fontPattern, FC_SLANT, slant);
189 newFontDescription.width = IntToWidthType(width);
190 newFontDescription.weight = IntToWeightType(weight);
191 newFontDescription.slant = IntToSlantType(slant);
193 FONT_LOG_DESCRIPTION(newFontDescription, "new font");
197 // Destroys the font set created by FcFontSort.
198 FcFontSetDestroy(fontSet);
202 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " No fonts found.\n");
205 // Destroys the pattern created by FcPatternCreate in CreateFontFamilyPattern.
206 FcPatternDestroy(fontFamilyPattern);
211 FontClient::Plugin::CacheHandler::FallbackCacheItem::FallbackCacheItem(FontDescription&& font, FontList* fallbackFonts, CharacterSetList* characterSets)
212 : fontDescription{std::move(font)},
213 fallbackFonts{fallbackFonts},
214 characterSets{characterSets}
218 FontClient::Plugin::CacheHandler::FontDescriptionCacheItem::FontDescriptionCacheItem(const FontDescription& fontDescription,
219 FontDescriptionId index)
220 : fontDescription{fontDescription},
225 FontClient::Plugin::CacheHandler::FontDescriptionCacheItem::FontDescriptionCacheItem(FontDescription&& fontDescription,
226 FontDescriptionId index)
227 : fontDescription{std::move(fontDescription)},
232 FontClient::Plugin::CacheHandler::FontDescriptionSizeCacheKey::FontDescriptionSizeCacheKey(FontDescriptionId fontDescriptionId,
233 PointSize26Dot6 requestedPointSize)
234 : fontDescriptionId(fontDescriptionId),
235 requestedPointSize(requestedPointSize)
240 FontClient::Plugin::CacheHandler::CacheHandler()
241 : mDefaultFontDescription(),
246 mValidatedFontCache(),
247 mFontDescriptionCache(),
248 mCharacterSetCache(),
249 mFontDescriptionSizeCache(),
251 mEmbeddedItemCache(),
252 mLatestFoundFontDescription(),
253 mLatestFoundFontDescriptionId(0u),
254 mLatestFoundCacheKey(0, 0),
255 mLatestFoundCacheIndex(0u),
256 mDefaultFontDescriptionCached(false)
260 FontClient::Plugin::CacheHandler::~CacheHandler()
265 void FontClient::Plugin::CacheHandler::ClearCache()
267 mDefaultFontDescription = FontDescription();
269 mSystemFonts.clear();
270 mDefaultFonts.clear();
272 DestroyCharacterSets(mDefaultFontCharacterSets);
273 mDefaultFontCharacterSets.Clear();
275 ClearFallbackCache();
276 mFallbackCache.clear();
278 mFontIdCache.clear();
280 ClearCharacterSetFromFontFaceCache();
281 mFontFaceCache.clear();
283 mValidatedFontCache.clear();
284 mFontDescriptionCache.clear();
286 DestroyCharacterSets(mCharacterSetCache);
287 mCharacterSetCache.Clear();
289 mFontDescriptionSizeCache.clear();
290 mFontDescriptionSizeCache.rehash(0); // Note : unordered_map.clear() didn't deallocate memory
292 mEllipsisCache.clear();
293 mPixelBufferCache.clear();
294 mEmbeddedItemCache.clear();
295 mBitmapFontCache.clear();
297 mLatestFoundFontDescription.family.clear();
298 mLatestFoundCacheKey = FontDescriptionSizeCacheKey(0, 0);
300 mDefaultFontDescriptionCached = false;
303 void FontClient::Plugin::CacheHandler::ResetSystemDefaults()
305 mDefaultFontDescriptionCached = false;
310 void FontClient::Plugin::CacheHandler::ClearFallbackCache()
312 for(auto& item : mFallbackCache)
314 if(nullptr != item.fallbackFonts)
316 delete item.fallbackFonts;
319 if(nullptr != item.characterSets)
321 // Free the resources allocated by the FcCharSet objects in the 'characterSets' vector.
322 DestroyCharacterSets(*item.characterSets);
323 delete item.characterSets;
328 void FontClient::Plugin::CacheHandler::ClearCharacterSetFromFontFaceCache()
330 for(auto& item : mFontFaceCache)
332 FcCharSetDestroy(item.mCharacterSet);
333 item.mCharacterSet = nullptr;
337 void FontClient::Plugin::CacheHandler::ClearCharacterSet()
339 // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
340 DestroyCharacterSets(mDefaultFontCharacterSets);
341 DestroyCharacterSets(mCharacterSetCache);
342 mDefaultFontCharacterSets.Clear();
343 mCharacterSetCache.Clear();
345 for(auto& item : mFallbackCache)
347 // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
348 DestroyCharacterSets(*item.characterSets);
350 delete item.characterSets;
351 item.characterSets = nullptr;
354 // Set the character set pointer as null. Will be created again the next time IsCharacterSupportedByFont()
355 ClearCharacterSetFromFontFaceCache();
358 void FontClient::Plugin::CacheHandler::CreateCharacterSet()
360 for(const auto& description : mDefaultFonts)
362 mDefaultFontCharacterSets.PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
365 for(const auto& description : mFontDescriptionCache)
367 mCharacterSetCache.PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
370 for(auto& item : mFallbackCache)
372 if(nullptr != item.fallbackFonts)
374 if(nullptr == item.characterSets)
376 item.characterSets = new CharacterSetList;
379 for(const auto& description : *(item.fallbackFonts))
381 item.characterSets->PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
389 void FontClient::Plugin::CacheHandler::InitSystemFonts()
391 if(mSystemFonts.empty())
393 FcFontSet* fontSet = GetFcFontSet(); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
397 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " number of system fonts : %d\n", fontSet->nfont);
399 // Reserve some space to avoid reallocations.
400 mSystemFonts.reserve(fontSet->nfont);
402 for(int i = 0u; i < fontSet->nfont; ++i)
404 FcPattern* fontPattern = fontSet->fonts[i];
408 // Skip fonts with no path
409 if(GetFcString(fontPattern, FC_FILE, path))
411 mSystemFonts.push_back(FontDescription());
412 FontDescription& fontDescription = mSystemFonts.back();
414 fontDescription.path = std::move(path);
419 GetFcString(fontPattern, FC_FAMILY, fontDescription.family);
420 GetFcInt(fontPattern, FC_WIDTH, width);
421 GetFcInt(fontPattern, FC_WEIGHT, weight);
422 GetFcInt(fontPattern, FC_SLANT, slant);
423 fontDescription.width = IntToWidthType(width);
424 fontDescription.weight = IntToWeightType(weight);
425 fontDescription.slant = IntToSlantType(slant);
427 FONT_LOG_DESCRIPTION(fontDescription, "system fonts");
431 // Destroys the font set created.
432 FcFontSetDestroy(fontSet);
437 void FontClient::Plugin::CacheHandler::InitDefaultFonts()
439 if(mDefaultFonts.empty())
441 FontDescription fontDescription;
442 fontDescription.family = DefaultFontFamily(); // todo This could be set to the Platform font
443 fontDescription.width = DefaultFontWidth();
444 fontDescription.weight = DefaultFontWeight();
445 fontDescription.slant = DefaultFontSlant();
446 SetFontList(fontDescription, mDefaultFonts, mDefaultFontCharacterSets);
450 void FontClient::Plugin::CacheHandler::InitDefaultFontDescription()
452 if(!mDefaultFontDescriptionCached)
454 // Clear any font config stored info in the caches.
457 // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
458 FcInitReinitialize();
460 FcPattern* matchPattern = FcPatternCreate(); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
462 if(nullptr != matchPattern)
464 FcConfigSubstitute(nullptr, matchPattern, FcMatchPattern);
465 FcDefaultSubstitute(matchPattern);
467 FcCharSet* characterSet = nullptr;
468 bool matched = MatchFontDescriptionToPattern(matchPattern, mDefaultFontDescription, &characterSet);
470 // Caching the default font description
473 // Copy default font description info.
474 // Due to the type changed, we need to make some temperal font description.
475 FontDescription tempFontDescription = mDefaultFontDescription;
477 // Add the path to the cache.
478 tempFontDescription.type = FontDescription::FACE_FONT;
479 mFontDescriptionCache.push_back(tempFontDescription);
481 // Set the index to the vector of paths to font file names.
482 const FontDescriptionId fontDescriptionId = static_cast<FontDescriptionId>(mFontDescriptionCache.size());
484 FONT_LOG_DESCRIPTION(tempFontDescription, "default platform font");
485 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " default font fontDescriptionId : %d\n", fontDescriptionId);
487 // Cache the index and the matched font's description.
488 CacheValidateFont(std::move(tempFontDescription), fontDescriptionId);
492 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " default font validation failed for font [%s]\n", mDefaultFontDescription.family.c_str());
495 // Decrease the reference counter of the character set as it's not stored.
496 // Note. the cached default font description will increase reference counter by
497 // mFontDescriptionCache in CreateCharacterSet(). So we can decrease reference counter here.
498 FcCharSetDestroy(characterSet);
500 // Destroys the pattern created.
501 FcPatternDestroy(matchPattern);
504 // Create again the character sets as they are not valid after FcInitReinitialize()
505 CreateCharacterSet();
507 mDefaultFontDescriptionCached = true;
513 bool FontClient::Plugin::CacheHandler::FindValidatedFont(const FontDescription& fontDescription,
514 FontDescriptionId& fontDescriptionId)
516 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
517 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " number of validated fonts in the cache : %zu\n", mValidatedFontCache.size());
519 fontDescriptionId = 0u;
521 // Fast cut if inputed family is empty.
522 if(DALI_UNLIKELY(fontDescription.family.empty()))
524 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " validated font description not found / fontDescription.family is empty!\n");
528 // Heuristic optimize code : Compare with latest found item.
529 if((fontDescription.width == mLatestFoundFontDescription.width) &&
530 (fontDescription.weight == mLatestFoundFontDescription.weight) &&
531 (fontDescription.slant == mLatestFoundFontDescription.slant) &&
532 (fontDescription.family == mLatestFoundFontDescription.family))
534 fontDescriptionId = mLatestFoundFontDescriptionId;
536 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " validated font description same as latest, id : %d\n", fontDescriptionId);
540 for(const auto& item : mValidatedFontCache)
542 if((fontDescription.width == item.fontDescription.width) &&
543 (fontDescription.weight == item.fontDescription.weight) &&
544 (fontDescription.slant == item.fontDescription.slant) &&
545 (fontDescription.family == item.fontDescription.family))
547 fontDescriptionId = item.index;
549 mLatestFoundFontDescription = fontDescription;
550 mLatestFoundFontDescriptionId = fontDescriptionId;
552 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " validated font description found, id : %d\n", fontDescriptionId);
557 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " validated font description not found\n");
561 void FontClient::Plugin::CacheHandler::ValidateFont(const FontDescription& fontDescription,
562 FontDescriptionId& fontDescriptionId)
564 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
565 FONT_LOG_DESCRIPTION(fontDescription, "");
567 // Create a font pattern.
568 FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription);
570 FontDescription description;
572 FcCharSet* characterSet = nullptr;
573 bool matched = MatchFontDescriptionToPattern(fontFamilyPattern, description, &characterSet);
574 FcPatternDestroy(fontFamilyPattern);
576 if(matched && (nullptr != characterSet))
578 // Add the path to the cache.
579 description.type = FontDescription::FACE_FONT;
580 mFontDescriptionCache.push_back(description);
582 // Set the index to the vector of paths to font file names.
583 fontDescriptionId = static_cast<FontDescriptionId>(mFontDescriptionCache.size());
585 FONT_LOG_DESCRIPTION(description, "matched");
586 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " fontDescriptionId : %d\n", fontDescriptionId);
588 // The reference counter of the character set has already been increased in MatchFontDescriptionToPattern.
589 mCharacterSetCache.PushBack(characterSet);
591 if((fontDescription.family != description.family) ||
592 (fontDescription.width != description.width) ||
593 (fontDescription.weight != description.weight) ||
594 (fontDescription.slant != description.slant))
596 // Cache the given font's description if it's different than the matched.
597 CacheValidateFont(std::move(FontDescription(fontDescription)), fontDescriptionId);
600 // Cache the index and the matched font's description.
601 CacheValidateFont(std::move(description), fontDescriptionId);
605 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font validation failed for font [%s]\n", fontDescription.family.c_str());
609 void FontClient::Plugin::CacheHandler::CacheValidateFont(FontDescription&& fontDescription,
610 FontDescriptionId validatedFontId)
612 mValidatedFontCache.emplace_back(std::move(FontDescriptionCacheItem(fontDescription, validatedFontId)));
617 bool FontClient::Plugin::CacheHandler::FindFallbackFontList(const FontDescription& fontDescription,
619 CharacterSetList*& characterSetList) const
621 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
622 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " number of fallback font lists in the cache : %zu\n", mFallbackCache.size());
626 for(const auto& item : mFallbackCache)
628 if(!fontDescription.family.empty() &&
629 (fontDescription.family == item.fontDescription.family) &&
630 (fontDescription.width == item.fontDescription.width) &&
631 (fontDescription.weight == item.fontDescription.weight) &&
632 (fontDescription.slant == item.fontDescription.slant))
634 fontList = item.fallbackFonts;
635 characterSetList = item.characterSets;
637 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " fallback font list found.\n");
642 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " fallback font list not found.\n");
646 void FontClient::Plugin::CacheHandler::CacheFallbackFontList(FontDescription&& fontDescription,
648 CharacterSetList*& characterSetList)
650 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
652 fontList = new FontList;
653 characterSetList = new CharacterSetList;
655 SetFontList(fontDescription, *fontList, *characterSetList);
657 FontDescription appleColorEmoji;
658 appleColorEmoji.family = "Apple Color Emoji";
659 appleColorEmoji.width = fontDescription.width;
660 appleColorEmoji.weight = fontDescription.weight;
661 appleColorEmoji.slant = fontDescription.slant;
662 FontList emojiFontList;
663 CharacterSetList emojiCharSetList;
664 SetFontList(appleColorEmoji, emojiFontList, emojiCharSetList);
666 std::move(fontList->begin(), fontList->end(), std::back_inserter(emojiFontList));
667 emojiCharSetList.Insert(emojiCharSetList.End(), characterSetList->Begin(), characterSetList->End());
668 *fontList = std::move(emojiFontList);
669 *characterSetList = std::move(emojiCharSetList);
672 // Add the font-list to the cache.
673 mFallbackCache.push_back(std::move(CacheHandler::FallbackCacheItem(std::move(fontDescription), fontList, characterSetList)));
678 bool FontClient::Plugin::CacheHandler::FindFontByPath(const FontPath& path,
679 PointSize26Dot6 requestedPointSize,
681 FontId& fontId) const
683 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
684 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " path : [%s]\n", path.c_str());
685 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
686 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " number of fonts in the cache : %zu\n", mFontFaceCache.size());
689 for(const auto& cacheItem : mFontFaceCache)
691 if(cacheItem.mRequestedPointSize == requestedPointSize &&
692 cacheItem.mFaceIndex == faceIndex &&
693 cacheItem.mPath == path)
695 fontId = cacheItem.mFontId + 1u;
697 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font found, id : %d\n", fontId);
702 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font not found\n");
706 bool FontClient::Plugin::CacheHandler::FindFont(FontDescriptionId fontDescriptionId,
707 PointSize26Dot6 requestedPointSize,
708 FontCacheIndex& fontCacheIndex)
710 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
711 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " fontDescriptionId : %d\n", fontDescriptionId);
712 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
716 const FontDescriptionSizeCacheKey key(fontDescriptionId, requestedPointSize);
718 // Heuristic optimize code : Compare with latest found item.
719 if(key == mLatestFoundCacheKey)
721 fontCacheIndex = mLatestFoundCacheIndex;
723 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font same as latest, index of font cache : %d\n", fontCacheIndex);
727 const auto& iter = mFontDescriptionSizeCache.find(key);
728 if(iter != mFontDescriptionSizeCache.cend())
730 fontCacheIndex = iter->second;
732 mLatestFoundCacheKey = key;
733 mLatestFoundCacheIndex = fontCacheIndex;
735 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font found, index of font cache : %d\n", fontCacheIndex);
739 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font not found.\n");
743 void FontClient::Plugin::CacheHandler::CacheFontDescriptionSize(FontDescriptionId fontDescriptionId, PointSize26Dot6 requestedPointSize, FontCacheIndex fontCacheIndex)
745 mFontDescriptionSizeCache.emplace(FontDescriptionSizeCacheKey(fontDescriptionId, requestedPointSize), fontCacheIndex);
748 void FontClient::Plugin::CacheHandler::CacheFontPath(FT_Face ftFace, FontId fontId, PointSize26Dot6 requestedPointSize, const FontPath& path)
750 FontDescription description;
751 description.path = path;
752 description.family = std::move(FontFamily(ftFace->family_name));
753 description.weight = FontWeight::NONE;
754 description.width = FontWidth::NONE;
755 description.slant = FontSlant::NONE;
757 // Note FreeType doesn't give too much info to build a proper font style.
758 if(ftFace->style_flags & FT_STYLE_FLAG_ITALIC)
760 description.slant = FontSlant::ITALIC;
762 if(ftFace->style_flags & FT_STYLE_FLAG_BOLD)
764 description.weight = FontWeight::BOLD;
767 FontDescriptionId fontDescriptionId = 0u;
768 if(!FindValidatedFont(description, fontDescriptionId))
770 // TODO : Due to the FontClient pattern match process, we cannot pass dali-toolkit UTC.
771 // Can't we use ValidateFont here?
773 // Use font config to validate the font's description.
774 ValidateFont(description, fontDescriptionId);
776 const FontCacheIndex fontCacheIndex = mFontIdCache[fontId - 1u].index;
777 mFontFaceCache[fontCacheIndex].mCharacterSet = FcCharSetCopy(mCharacterSetCache[fontDescriptionId - 1u]); // Increases the reference counter.
779 // Cache the pair 'fontDescriptionId, requestedPointSize' to improve the following queries.
780 mFontDescriptionSizeCache.emplace(CacheHandler::FontDescriptionSizeCacheKey(fontDescriptionId, requestedPointSize), fontCacheIndex);
783 FcPattern* pattern = CreateFontFamilyPattern(description); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
785 FcResult result = FcResultMatch;
786 FcPattern* match = FcFontMatch(nullptr, pattern, &result); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
788 FcCharSet* characterSet = nullptr;
789 FcPatternGetCharSet(match, FC_CHARSET, 0u, &characterSet);
791 const FontCacheIndex fontCacheIndex = mFontIdCache[fontId - 1u].index;
792 mFontFaceCache[fontCacheIndex].mCharacterSet = FcCharSetCopy(characterSet); // Increases the reference counter.
794 // Destroys the created patterns.
795 FcPatternDestroy(match);
796 FcPatternDestroy(pattern);
798 // Add the path to the cache.
799 description.type = FontDescription::FACE_FONT;
800 mFontDescriptionCache.push_back(description);
802 // Set the index to the vector of paths to font file names.
803 fontDescriptionId = static_cast<FontDescriptionId>(mFontDescriptionCache.size());
805 // Increase the reference counter and add the character set to the cache.
806 mCharacterSetCache.PushBack(FcCharSetCopy(characterSet));
808 // Cache the index and the font's description.
809 CacheValidateFont(std::move(description), fontDescriptionId);
811 // Cache the pair 'fontDescriptionId, requestedPointSize' to improve the following queries.
812 CacheFontDescriptionSize(fontDescriptionId, requestedPointSize, fontCacheIndex);
816 FontId FontClient::Plugin::CacheHandler::CacheFontFaceCacheItem(FontFaceCacheItem&& fontFaceCacheItem)
818 // Set the index to the font's id cache.
819 fontFaceCacheItem.mFontId = static_cast<FontId>(mFontIdCache.size());
821 // Create the font id item to cache.
822 FontIdCacheItem fontIdCacheItem;
823 fontIdCacheItem.type = FontDescription::FACE_FONT;
825 // Set the index to the FreeType font face cache.
826 fontIdCacheItem.index = static_cast<FontCacheIndex>(mFontFaceCache.size());
829 mFontFaceCache.emplace_back(std::move(fontFaceCacheItem));
830 mFontIdCache.emplace_back(std::move(fontIdCacheItem));
832 // Set the font id to be returned.
833 FontId fontId = static_cast<FontId>(mFontIdCache.size());
840 bool FontClient::Plugin::CacheHandler::FindEllipsis(PointSize26Dot6 requestedPointSize, EllipsisCacheIndex& ellipsisCacheIndex) const
842 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
843 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize %d.\n", requestedPointSize);
845 ellipsisCacheIndex = 0u;
847 // First look into the cache if there is an ellipsis glyph for the requested point size.
848 for(const auto& item : mEllipsisCache)
850 if(item.requestedPointSize == requestedPointSize)
852 // Use the glyph in the cache.
853 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index);
854 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font %d.\n", item.glyph.fontId);
855 ellipsisCacheIndex = item.index;
862 FontClient::Plugin::CacheHandler::EllipsisCacheIndex FontClient::Plugin::CacheHandler::CacheEllipsis(EllipsisItem&& ellipsisItem)
864 EllipsisCacheIndex ellipsisCacheIndex = static_cast<EllipsisCacheIndex>(mEllipsisCache.size());
866 mEllipsisCache.emplace_back(std::move(ellipsisItem));
868 return ellipsisCacheIndex;
873 bool FontClient::Plugin::CacheHandler::FindBitmapFont(const FontFamily& bitmapFontFamily, FontId& fontId) const
877 for(const auto& item : mBitmapFontCache)
879 if(bitmapFontFamily == item.font.name)
881 fontId = item.id + 1u;
889 FontId FontClient::Plugin::CacheHandler::CacheBitmapFontCacheItem(BitmapFontCacheItem&& bitmapFontCacheItem)
891 // Set the index to the font's id cache.
892 bitmapFontCacheItem.id = static_cast<FontId>(mFontIdCache.size());
894 // Create the font id item to cache.
895 CacheHandler::FontIdCacheItem fontIdCacheItem;
896 fontIdCacheItem.type = FontDescription::BITMAP_FONT;
898 // Set the index to the Bitmap font face cache.
899 fontIdCacheItem.index = static_cast<FontCacheIndex>(mBitmapFontCache.size());
902 mBitmapFontCache.emplace_back(std::move(bitmapFontCacheItem));
903 mFontIdCache.emplace_back(std::move(fontIdCacheItem));
905 // Set the font id to be returned.
906 FontId fontId = static_cast<FontId>(mFontIdCache.size());
913 bool FontClient::Plugin::CacheHandler::FindEmbeddedPixelBufferId(const std::string& url, PixelBufferId& pixelBufferId) const
917 for(const auto& cacheItem : mPixelBufferCache)
919 if(cacheItem.url == url)
921 // The url is in the pixel buffer cache.
922 pixelBufferId = cacheItem.id;
930 PixelBufferId FontClient::Plugin::CacheHandler::CacheEmbeddedPixelBuffer(const std::string& url)
932 PixelBufferId pixelBufferId = 0u;
934 // Load the image from the url.
935 Devel::PixelBuffer pixelBuffer = LoadImageFromFile(url);
938 // Create the cache item.
939 PixelBufferCacheItem pixelBufferCacheItem;
940 pixelBufferCacheItem.pixelBuffer = pixelBuffer;
941 pixelBufferCacheItem.url = url;
942 pixelBufferCacheItem.id = static_cast<PixelBufferId>(mPixelBufferCache.size() + 1u);
944 // Store the cache item in the cache.
945 mPixelBufferCache.emplace_back(std::move(pixelBufferCacheItem));
947 // Set the pixel buffer id to be returned.
948 pixelBufferId = static_cast<PixelBufferId>(mPixelBufferCache.size());
950 return pixelBufferId;
953 bool FontClient::Plugin::CacheHandler::FindEmbeddedItem(PixelBufferId pixelBufferId, uint32_t width, uint32_t height, GlyphIndex& index) const
957 for(const auto& cacheItem : mEmbeddedItemCache)
959 if((cacheItem.pixelBufferId == pixelBufferId) &&
960 (cacheItem.width == width) &&
961 (cacheItem.height == height))
963 index = cacheItem.index;
971 GlyphIndex FontClient::Plugin::CacheHandler::CacheEmbeddedItem(EmbeddedItem&& embeddedItem)
973 embeddedItem.index = static_cast<GlyphIndex>(mEmbeddedItemCache.size() + 1u);
975 // Cache the embedded item.
976 mEmbeddedItemCache.emplace_back(std::move(embeddedItem));
978 // Set the font id to be returned.
979 GlyphIndex index = static_cast<GlyphIndex>(mEmbeddedItemCache.size());
984 } // namespace Dali::TextAbstraction::Internal