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/environment-variable.h>
27 #include <dali/devel-api/adaptor-framework/image-loading.h>
28 #include <dali/internal/text/text-abstraction/font-client-impl.h>
29 #include <dali/internal/text/text-abstraction/plugin/font-client-plugin-impl.h>
30 #include <dali/internal/text/text-abstraction/plugin/font-client-utils.h>
32 #if defined(DEBUG_ENABLED)
33 extern Dali::Integration::Log::Filter* gFontClientLogFilter;
35 #define FONT_LOG_DESCRIPTION(fontDescription, prefix) \
36 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, #prefix " description; family : [%s]\n", fontDescription.family.c_str()); \
37 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, \
41 " slant : [%s]\n\n", \
42 fontDescription.path.c_str(), \
43 FontWidth::Name[fontDescription.width], \
44 FontWeight::Name[fontDescription.weight], \
45 FontSlant::Name[fontDescription.slant])
47 #define FONT_LOG_REQUEST(charcode, requestedPointSize, preferColor) \
48 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, \
50 " requestedPointSize : %d\n" \
51 " preferColor : %s\n", \
54 (preferColor ? "true" : "false"))
58 #define FONT_LOG_DESCRIPTION(fontDescription, prefix)
59 #define FONT_LOG_REQUEST(charcode, requestedPointSize, preferColor)
66 * @brief Maximum size of glyph cache per each font face.
68 constexpr std::size_t DEFAULT_GLYPH_CACHE_MAX = 128;
69 constexpr std::size_t MINIMUM_SIZE_OF_GLYPH_CACHE_MAX = 3u;
71 constexpr auto MAX_NUMBER_OF_GLYPH_CACHE_ENV = "DALI_GLYPH_CACHE_MAX";
74 * @brief Get maximum size of glyph cache size from environment.
75 * If not settuped, default as 128.
76 * @note This value fixed when we call it first time.
77 * @return The max size of glyph cache.
79 inline size_t GetMaxNumberOfGlyphCache()
81 using Dali::EnvironmentVariable::GetEnvironmentVariable;
82 static auto numberString = GetEnvironmentVariable(MAX_NUMBER_OF_GLYPH_CACHE_ENV);
83 static auto number = numberString ? std::strtoul(numberString, nullptr, 10) : DEFAULT_GLYPH_CACHE_MAX;
84 return (number < MINIMUM_SIZE_OF_GLYPH_CACHE_MAX) ? MINIMUM_SIZE_OF_GLYPH_CACHE_MAX : number;
89 namespace Dali::TextAbstraction::Internal
94 * @brief Free the resources allocated by the FcCharSet objects.
96 * @param[in] characterSets The vector of character sets.
98 void DestroyCharacterSets(CharacterSetList& characterSets)
100 for(auto& item : characterSets)
104 FcCharSetDestroy(item);
110 * @brief Retrieves the fonts present in the platform.
112 * @note Need to call FcFontSetDestroy to free the allocated resources.
114 * @return A font fonfig data structure with the platform's fonts.
116 _FcFontSet* GetFcFontSet()
118 FcFontSet* fontset = nullptr;
120 // create a new pattern.
121 // a pattern holds a set of names, each name refers to a property of the font
122 FcPattern* pattern = FcPatternCreate();
124 if(nullptr != pattern)
126 // create an object set used to define which properties are to be returned in the patterns from FcFontList.
127 FcObjectSet* objectSet = FcObjectSetCreate();
129 if(nullptr != objectSet)
131 // build an object set from a list of property names
132 FcObjectSetAdd(objectSet, FC_FILE);
133 FcObjectSetAdd(objectSet, FC_FAMILY);
134 FcObjectSetAdd(objectSet, FC_WIDTH);
135 FcObjectSetAdd(objectSet, FC_WEIGHT);
136 FcObjectSetAdd(objectSet, FC_SLANT);
138 // get a list of fonts
139 // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
140 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.
142 // clear up the object set
143 FcObjectSetDestroy(objectSet);
146 // clear up the pattern
147 FcPatternDestroy(pattern);
154 * @brief Helper for GetDefaultFonts etc.
156 * @note CharacterSetList is a vector of FcCharSet that are reference counted. It's needed to call FcCharSetDestroy to decrease the reference counter.
158 * @param[in] fontDescription A font description.
159 * @param[out] fontList A list of the fonts which are a close match for fontDescription.
160 * @param[out] characterSetList A list of character sets which are a close match for fontDescription.
162 void SetFontList(const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList)
164 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
167 FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
169 FcResult result = FcResultMatch;
171 // Match the pattern.
172 FcFontSet* fontSet = FcFontSort(nullptr /* use default configure */,
174 false /* don't trim */,
176 &result); // FcFontSort creates a font set that needs to be destroyed by calling FcFontSetDestroy.
178 if(nullptr != fontSet)
180 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " number of fonts found : [%d]\n", fontSet->nfont);
181 // Reserve some space to avoid reallocations.
182 fontList.reserve(fontSet->nfont);
184 for(int i = 0u; i < fontSet->nfont; ++i)
186 FcPattern* fontPattern = fontSet->fonts[i];
190 // Skip fonts with no path
191 if(GetFcString(fontPattern, FC_FILE, path))
193 // Retrieve the character set. Need to call FcCharSetDestroy to free the resources.
194 FcCharSet* characterSet = nullptr;
195 FcPatternGetCharSet(fontPattern, FC_CHARSET, 0u, &characterSet);
197 // Increase the reference counter of the character set.
198 characterSetList.PushBack(FcCharSetCopy(characterSet));
200 fontList.push_back(FontDescription());
201 FontDescription& newFontDescription = fontList.back();
203 newFontDescription.path = std::move(path);
208 GetFcString(fontPattern, FC_FAMILY, newFontDescription.family);
209 GetFcInt(fontPattern, FC_WIDTH, width);
210 GetFcInt(fontPattern, FC_WEIGHT, weight);
211 GetFcInt(fontPattern, FC_SLANT, slant);
212 newFontDescription.width = IntToWidthType(width);
213 newFontDescription.weight = IntToWeightType(weight);
214 newFontDescription.slant = IntToSlantType(slant);
216 FONT_LOG_DESCRIPTION(newFontDescription, "new font");
220 // Destroys the font set created by FcFontSort.
221 FcFontSetDestroy(fontSet);
225 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " No fonts found.\n");
228 // Destroys the pattern created by FcPatternCreate in CreateFontFamilyPattern.
229 FcPatternDestroy(fontFamilyPattern);
234 FontClient::Plugin::CacheHandler::FallbackCacheItem::FallbackCacheItem(FontDescription&& font, FontList* fallbackFonts, CharacterSetList* characterSets)
235 : fontDescription{std::move(font)},
236 fallbackFonts{fallbackFonts},
237 characterSets{characterSets}
241 FontClient::Plugin::CacheHandler::FontDescriptionCacheItem::FontDescriptionCacheItem(const FontDescription& fontDescription,
242 FontDescriptionId index)
243 : fontDescription{fontDescription},
248 FontClient::Plugin::CacheHandler::FontDescriptionCacheItem::FontDescriptionCacheItem(FontDescription&& fontDescription,
249 FontDescriptionId index)
250 : fontDescription{std::move(fontDescription)},
255 FontClient::Plugin::CacheHandler::FontDescriptionSizeCacheKey::FontDescriptionSizeCacheKey(FontDescriptionId fontDescriptionId,
256 PointSize26Dot6 requestedPointSize)
257 : fontDescriptionId(fontDescriptionId),
258 requestedPointSize(requestedPointSize)
263 FontClient::Plugin::CacheHandler::CacheHandler()
264 : mDefaultFontDescription(),
269 mValidatedFontCache(),
270 mFontDescriptionCache(),
271 mCharacterSetCache(),
272 mFontDescriptionSizeCache(),
274 mEmbeddedItemCache(),
275 mGlyphCacheManager(new GlyphCacheManager(GetMaxNumberOfGlyphCache())),
276 mLatestFoundFontDescription(),
277 mLatestFoundFontDescriptionId(0u),
278 mLatestFoundCacheKey(0, 0),
279 mLatestFoundCacheIndex(0u),
280 mDefaultFontDescriptionCached(false)
284 FontClient::Plugin::CacheHandler::~CacheHandler()
289 void FontClient::Plugin::CacheHandler::ClearCache()
291 // delete cached glyph informations before clear mFontFaceCache.
292 mGlyphCacheManager->ClearCache();
294 mDefaultFontDescription = FontDescription();
296 mSystemFonts.clear();
297 mDefaultFonts.clear();
299 DestroyCharacterSets(mDefaultFontCharacterSets);
300 mDefaultFontCharacterSets.Clear();
302 ClearFallbackCache();
303 mFallbackCache.clear();
305 mFontIdCache.clear();
307 ClearCharacterSetFromFontFaceCache();
308 mFontFaceCache.clear();
310 mValidatedFontCache.clear();
311 mFontDescriptionCache.clear();
313 DestroyCharacterSets(mCharacterSetCache);
314 mCharacterSetCache.Clear();
316 mFontDescriptionSizeCache.clear();
317 mFontDescriptionSizeCache.rehash(0); // Note : unordered_map.clear() didn't deallocate memory
319 mEllipsisCache.clear();
320 mPixelBufferCache.clear();
321 mEmbeddedItemCache.clear();
322 mBitmapFontCache.clear();
324 mLatestFoundFontDescription.family.clear();
325 mLatestFoundCacheKey = FontDescriptionSizeCacheKey(0, 0);
327 mDefaultFontDescriptionCached = false;
330 void FontClient::Plugin::CacheHandler::ResetSystemDefaults()
332 mDefaultFontDescriptionCached = false;
337 void FontClient::Plugin::CacheHandler::ClearFallbackCache()
339 for(auto& item : mFallbackCache)
341 if(nullptr != item.fallbackFonts)
343 delete item.fallbackFonts;
346 if(nullptr != item.characterSets)
348 // Free the resources allocated by the FcCharSet objects in the 'characterSets' vector.
349 DestroyCharacterSets(*item.characterSets);
350 delete item.characterSets;
355 void FontClient::Plugin::CacheHandler::ClearCharacterSetFromFontFaceCache()
357 for(auto& item : mFontFaceCache)
359 FcCharSetDestroy(item.mCharacterSet);
360 item.mCharacterSet = nullptr;
364 void FontClient::Plugin::CacheHandler::ClearCharacterSet()
366 // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
367 DestroyCharacterSets(mDefaultFontCharacterSets);
368 DestroyCharacterSets(mCharacterSetCache);
369 mDefaultFontCharacterSets.Clear();
370 mCharacterSetCache.Clear();
372 for(auto& item : mFallbackCache)
374 // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
375 DestroyCharacterSets(*item.characterSets);
377 delete item.characterSets;
378 item.characterSets = nullptr;
381 // Set the character set pointer as null. Will be created again the next time IsCharacterSupportedByFont()
382 ClearCharacterSetFromFontFaceCache();
385 void FontClient::Plugin::CacheHandler::CreateCharacterSet()
387 for(const auto& description : mDefaultFonts)
389 mDefaultFontCharacterSets.PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
392 for(const auto& description : mFontDescriptionCache)
394 mCharacterSetCache.PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
397 for(auto& item : mFallbackCache)
399 if(nullptr != item.fallbackFonts)
401 if(nullptr == item.characterSets)
403 item.characterSets = new CharacterSetList;
406 for(const auto& description : *(item.fallbackFonts))
408 item.characterSets->PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
416 void FontClient::Plugin::CacheHandler::InitSystemFonts()
418 if(mSystemFonts.empty())
420 FcFontSet* fontSet = GetFcFontSet(); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
424 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " number of system fonts : %d\n", fontSet->nfont);
426 // Reserve some space to avoid reallocations.
427 mSystemFonts.reserve(fontSet->nfont);
429 for(int i = 0u; i < fontSet->nfont; ++i)
431 FcPattern* fontPattern = fontSet->fonts[i];
435 // Skip fonts with no path
436 if(GetFcString(fontPattern, FC_FILE, path))
438 mSystemFonts.push_back(FontDescription());
439 FontDescription& fontDescription = mSystemFonts.back();
441 fontDescription.path = std::move(path);
446 GetFcString(fontPattern, FC_FAMILY, fontDescription.family);
447 GetFcInt(fontPattern, FC_WIDTH, width);
448 GetFcInt(fontPattern, FC_WEIGHT, weight);
449 GetFcInt(fontPattern, FC_SLANT, slant);
450 fontDescription.width = IntToWidthType(width);
451 fontDescription.weight = IntToWeightType(weight);
452 fontDescription.slant = IntToSlantType(slant);
454 FONT_LOG_DESCRIPTION(fontDescription, "system fonts");
458 // Destroys the font set created.
459 FcFontSetDestroy(fontSet);
464 void FontClient::Plugin::CacheHandler::InitDefaultFonts()
466 if(mDefaultFonts.empty())
468 FontDescription fontDescription;
469 fontDescription.family = DefaultFontFamily(); // todo This could be set to the Platform font
470 fontDescription.width = DefaultFontWidth();
471 fontDescription.weight = DefaultFontWeight();
472 fontDescription.slant = DefaultFontSlant();
473 SetFontList(fontDescription, mDefaultFonts, mDefaultFontCharacterSets);
477 void FontClient::Plugin::CacheHandler::InitDefaultFontDescription()
479 if(!mDefaultFontDescriptionCached)
481 // Clear any font config stored info in the caches.
484 // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
485 FcInitReinitialize();
487 FcPattern* matchPattern = FcPatternCreate(); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
489 if(nullptr != matchPattern)
491 FcConfigSubstitute(nullptr, matchPattern, FcMatchPattern);
492 FcDefaultSubstitute(matchPattern);
494 FcCharSet* characterSet = nullptr;
495 bool matched = MatchFontDescriptionToPattern(matchPattern, mDefaultFontDescription, &characterSet);
497 // Caching the default font description
500 // Copy default font description info.
501 // Due to the type changed, we need to make some temperal font description.
502 FontDescription tempFontDescription = mDefaultFontDescription;
504 // Add the path to the cache.
505 tempFontDescription.type = FontDescription::FACE_FONT;
506 mFontDescriptionCache.push_back(tempFontDescription);
508 // Set the index to the vector of paths to font file names.
509 const FontDescriptionId fontDescriptionId = static_cast<FontDescriptionId>(mFontDescriptionCache.size());
511 FONT_LOG_DESCRIPTION(tempFontDescription, "default platform font");
512 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " default font fontDescriptionId : %d\n", fontDescriptionId);
514 // Cache the index and the matched font's description.
515 CacheValidateFont(std::move(tempFontDescription), fontDescriptionId);
519 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " default font validation failed for font [%s]\n", mDefaultFontDescription.family.c_str());
522 // Decrease the reference counter of the character set as it's not stored.
523 // Note. the cached default font description will increase reference counter by
524 // mFontDescriptionCache in CreateCharacterSet(). So we can decrease reference counter here.
525 FcCharSetDestroy(characterSet);
527 // Destroys the pattern created.
528 FcPatternDestroy(matchPattern);
531 // Create again the character sets as they are not valid after FcInitReinitialize()
532 CreateCharacterSet();
534 mDefaultFontDescriptionCached = true;
540 bool FontClient::Plugin::CacheHandler::FindValidatedFont(const FontDescription& fontDescription,
541 FontDescriptionId& fontDescriptionId)
543 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
544 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " number of validated fonts in the cache : %zu\n", mValidatedFontCache.size());
546 fontDescriptionId = 0u;
548 // Fast cut if inputed family is empty.
549 if(DALI_UNLIKELY(fontDescription.family.empty()))
551 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " validated font description not found / fontDescription.family is empty!\n");
555 // Heuristic optimize code : Compare with latest found item.
556 if((fontDescription.width == mLatestFoundFontDescription.width) &&
557 (fontDescription.weight == mLatestFoundFontDescription.weight) &&
558 (fontDescription.slant == mLatestFoundFontDescription.slant) &&
559 (fontDescription.family == mLatestFoundFontDescription.family))
561 fontDescriptionId = mLatestFoundFontDescriptionId;
563 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " validated font description same as latest, id : %d\n", fontDescriptionId);
567 for(const auto& item : mValidatedFontCache)
569 if((fontDescription.width == item.fontDescription.width) &&
570 (fontDescription.weight == item.fontDescription.weight) &&
571 (fontDescription.slant == item.fontDescription.slant) &&
572 (fontDescription.family == item.fontDescription.family))
574 fontDescriptionId = item.index;
576 mLatestFoundFontDescription = fontDescription;
577 mLatestFoundFontDescriptionId = fontDescriptionId;
579 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " validated font description found, id : %d\n", fontDescriptionId);
584 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " validated font description not found\n");
588 void FontClient::Plugin::CacheHandler::ValidateFont(const FontDescription& fontDescription,
589 FontDescriptionId& fontDescriptionId)
591 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
592 FONT_LOG_DESCRIPTION(fontDescription, "");
594 // Create a font pattern.
595 FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription);
597 FontDescription description;
599 FcCharSet* characterSet = nullptr;
600 bool matched = MatchFontDescriptionToPattern(fontFamilyPattern, description, &characterSet);
601 FcPatternDestroy(fontFamilyPattern);
603 if(matched && (nullptr != characterSet))
605 // Add the path to the cache.
606 description.type = FontDescription::FACE_FONT;
607 mFontDescriptionCache.push_back(description);
609 // Set the index to the vector of paths to font file names.
610 fontDescriptionId = static_cast<FontDescriptionId>(mFontDescriptionCache.size());
612 FONT_LOG_DESCRIPTION(description, "matched");
613 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " fontDescriptionId : %d\n", fontDescriptionId);
615 // The reference counter of the character set has already been increased in MatchFontDescriptionToPattern.
616 mCharacterSetCache.PushBack(characterSet);
618 if((fontDescription.family != description.family) ||
619 (fontDescription.width != description.width) ||
620 (fontDescription.weight != description.weight) ||
621 (fontDescription.slant != description.slant))
623 // Cache the given font's description if it's different than the matched.
624 CacheValidateFont(std::move(FontDescription(fontDescription)), fontDescriptionId);
627 // Cache the index and the matched font's description.
628 CacheValidateFont(std::move(description), fontDescriptionId);
632 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font validation failed for font [%s]\n", fontDescription.family.c_str());
636 void FontClient::Plugin::CacheHandler::CacheValidateFont(FontDescription&& fontDescription,
637 FontDescriptionId validatedFontId)
639 mValidatedFontCache.emplace_back(std::move(FontDescriptionCacheItem(fontDescription, validatedFontId)));
644 bool FontClient::Plugin::CacheHandler::FindFallbackFontList(const FontDescription& fontDescription,
646 CharacterSetList*& characterSetList) const
648 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
649 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " number of fallback font lists in the cache : %zu\n", mFallbackCache.size());
653 for(const auto& item : mFallbackCache)
655 if(!fontDescription.family.empty() &&
656 (fontDescription.family == item.fontDescription.family) &&
657 (fontDescription.width == item.fontDescription.width) &&
658 (fontDescription.weight == item.fontDescription.weight) &&
659 (fontDescription.slant == item.fontDescription.slant))
661 fontList = item.fallbackFonts;
662 characterSetList = item.characterSets;
664 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " fallback font list found.\n");
669 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " fallback font list not found.\n");
673 void FontClient::Plugin::CacheHandler::CacheFallbackFontList(FontDescription&& fontDescription,
675 CharacterSetList*& characterSetList)
677 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
679 fontList = new FontList;
680 characterSetList = new CharacterSetList;
682 SetFontList(fontDescription, *fontList, *characterSetList);
684 FontDescription appleColorEmoji;
685 appleColorEmoji.family = "Apple Color Emoji";
686 appleColorEmoji.width = fontDescription.width;
687 appleColorEmoji.weight = fontDescription.weight;
688 appleColorEmoji.slant = fontDescription.slant;
689 FontList emojiFontList;
690 CharacterSetList emojiCharSetList;
691 SetFontList(appleColorEmoji, emojiFontList, emojiCharSetList);
693 std::move(fontList->begin(), fontList->end(), std::back_inserter(emojiFontList));
694 emojiCharSetList.Insert(emojiCharSetList.End(), characterSetList->Begin(), characterSetList->End());
695 *fontList = std::move(emojiFontList);
696 *characterSetList = std::move(emojiCharSetList);
699 // Add the font-list to the cache.
700 mFallbackCache.push_back(std::move(CacheHandler::FallbackCacheItem(std::move(fontDescription), fontList, characterSetList)));
705 bool FontClient::Plugin::CacheHandler::FindFontByPath(const FontPath& path,
706 PointSize26Dot6 requestedPointSize,
708 FontId& fontId) const
710 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
711 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " path : [%s]\n", path.c_str());
712 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
713 DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " number of fonts in the cache : %zu\n", mFontFaceCache.size());
716 for(const auto& cacheItem : mFontFaceCache)
718 if(cacheItem.mRequestedPointSize == requestedPointSize &&
719 cacheItem.mFaceIndex == faceIndex &&
720 cacheItem.mPath == path)
722 fontId = cacheItem.mFontId + 1u;
724 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font found, id : %d\n", fontId);
729 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font not found\n");
733 bool FontClient::Plugin::CacheHandler::FindFont(FontDescriptionId fontDescriptionId,
734 PointSize26Dot6 requestedPointSize,
735 FontCacheIndex& fontCacheIndex)
737 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
738 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " fontDescriptionId : %d\n", fontDescriptionId);
739 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
743 const FontDescriptionSizeCacheKey key(fontDescriptionId, requestedPointSize);
745 // Heuristic optimize code : Compare with latest found item.
746 if(key == mLatestFoundCacheKey)
748 fontCacheIndex = mLatestFoundCacheIndex;
750 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font same as latest, index of font cache : %d\n", fontCacheIndex);
754 const auto& iter = mFontDescriptionSizeCache.find(key);
755 if(iter != mFontDescriptionSizeCache.cend())
757 fontCacheIndex = iter->second;
759 mLatestFoundCacheKey = key;
760 mLatestFoundCacheIndex = fontCacheIndex;
762 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font found, index of font cache : %d\n", fontCacheIndex);
766 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font not found.\n");
770 void FontClient::Plugin::CacheHandler::CacheFontDescriptionSize(FontDescriptionId fontDescriptionId, PointSize26Dot6 requestedPointSize, FontCacheIndex fontCacheIndex)
772 mFontDescriptionSizeCache.emplace(FontDescriptionSizeCacheKey(fontDescriptionId, requestedPointSize), fontCacheIndex);
775 void FontClient::Plugin::CacheHandler::CacheFontPath(FT_Face ftFace, FontId fontId, PointSize26Dot6 requestedPointSize, const FontPath& path)
777 FontDescription description;
778 description.path = path;
779 description.family = std::move(FontFamily(ftFace->family_name));
780 description.weight = FontWeight::NONE;
781 description.width = FontWidth::NONE;
782 description.slant = FontSlant::NONE;
784 // Note FreeType doesn't give too much info to build a proper font style.
785 if(ftFace->style_flags & FT_STYLE_FLAG_ITALIC)
787 description.slant = FontSlant::ITALIC;
789 if(ftFace->style_flags & FT_STYLE_FLAG_BOLD)
791 description.weight = FontWeight::BOLD;
794 FontDescriptionId fontDescriptionId = 0u;
795 if(!FindValidatedFont(description, fontDescriptionId))
797 // TODO : Due to the FontClient pattern match process, we cannot pass dali-toolkit UTC.
798 // Can't we use ValidateFont here?
800 // Use font config to validate the font's description.
801 ValidateFont(description, fontDescriptionId);
803 const FontCacheIndex fontCacheIndex = mFontIdCache[fontId - 1u].index;
804 mFontFaceCache[fontCacheIndex].mCharacterSet = FcCharSetCopy(mCharacterSetCache[fontDescriptionId - 1u]); // Increases the reference counter.
806 // Cache the pair 'fontDescriptionId, requestedPointSize' to improve the following queries.
807 mFontDescriptionSizeCache.emplace(CacheHandler::FontDescriptionSizeCacheKey(fontDescriptionId, requestedPointSize), fontCacheIndex);
810 FcPattern* pattern = CreateFontFamilyPattern(description); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
812 FcResult result = FcResultMatch;
813 FcPattern* match = FcFontMatch(nullptr, pattern, &result); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
815 FcCharSet* characterSet = nullptr;
816 FcPatternGetCharSet(match, FC_CHARSET, 0u, &characterSet);
818 const FontCacheIndex fontCacheIndex = mFontIdCache[fontId - 1u].index;
819 mFontFaceCache[fontCacheIndex].mCharacterSet = FcCharSetCopy(characterSet); // Increases the reference counter.
821 // Destroys the created patterns.
822 FcPatternDestroy(match);
823 FcPatternDestroy(pattern);
825 // Add the path to the cache.
826 description.type = FontDescription::FACE_FONT;
827 mFontDescriptionCache.push_back(description);
829 // Set the index to the vector of paths to font file names.
830 fontDescriptionId = static_cast<FontDescriptionId>(mFontDescriptionCache.size());
832 // Increase the reference counter and add the character set to the cache.
833 mCharacterSetCache.PushBack(FcCharSetCopy(characterSet));
835 // Cache the index and the font's description.
836 CacheValidateFont(std::move(description), fontDescriptionId);
838 // Cache the pair 'fontDescriptionId, requestedPointSize' to improve the following queries.
839 CacheFontDescriptionSize(fontDescriptionId, requestedPointSize, fontCacheIndex);
843 FontId FontClient::Plugin::CacheHandler::CacheFontFaceCacheItem(FontFaceCacheItem&& fontFaceCacheItem)
845 // Set the index to the font's id cache.
846 fontFaceCacheItem.mFontId = static_cast<FontId>(mFontIdCache.size());
848 // Create the font id item to cache.
849 FontIdCacheItem fontIdCacheItem;
850 fontIdCacheItem.type = FontDescription::FACE_FONT;
852 // Set the index to the FreeType font face cache.
853 fontIdCacheItem.index = static_cast<FontCacheIndex>(mFontFaceCache.size());
856 mFontFaceCache.emplace_back(std::move(fontFaceCacheItem));
857 mFontIdCache.emplace_back(std::move(fontIdCacheItem));
859 // Set the font id to be returned.
860 FontId fontId = static_cast<FontId>(mFontIdCache.size());
867 bool FontClient::Plugin::CacheHandler::FindEllipsis(PointSize26Dot6 requestedPointSize, EllipsisCacheIndex& ellipsisCacheIndex) const
869 DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
870 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize %d.\n", requestedPointSize);
872 ellipsisCacheIndex = 0u;
874 // First look into the cache if there is an ellipsis glyph for the requested point size.
875 for(const auto& item : mEllipsisCache)
877 if(item.requestedPointSize == requestedPointSize)
879 // Use the glyph in the cache.
880 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index);
881 DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font %d.\n", item.glyph.fontId);
882 ellipsisCacheIndex = item.index;
889 FontClient::Plugin::CacheHandler::EllipsisCacheIndex FontClient::Plugin::CacheHandler::CacheEllipsis(EllipsisItem&& ellipsisItem)
891 EllipsisCacheIndex ellipsisCacheIndex = static_cast<EllipsisCacheIndex>(mEllipsisCache.size());
893 mEllipsisCache.emplace_back(std::move(ellipsisItem));
895 return ellipsisCacheIndex;
900 bool FontClient::Plugin::CacheHandler::FindBitmapFont(const FontFamily& bitmapFontFamily, FontId& fontId) const
904 for(const auto& item : mBitmapFontCache)
906 if(bitmapFontFamily == item.font.name)
908 fontId = item.id + 1u;
916 FontId FontClient::Plugin::CacheHandler::CacheBitmapFontCacheItem(BitmapFontCacheItem&& bitmapFontCacheItem)
918 // Set the index to the font's id cache.
919 bitmapFontCacheItem.id = static_cast<FontId>(mFontIdCache.size());
921 // Create the font id item to cache.
922 CacheHandler::FontIdCacheItem fontIdCacheItem;
923 fontIdCacheItem.type = FontDescription::BITMAP_FONT;
925 // Set the index to the Bitmap font face cache.
926 fontIdCacheItem.index = static_cast<FontCacheIndex>(mBitmapFontCache.size());
929 mBitmapFontCache.emplace_back(std::move(bitmapFontCacheItem));
930 mFontIdCache.emplace_back(std::move(fontIdCacheItem));
932 // Set the font id to be returned.
933 FontId fontId = static_cast<FontId>(mFontIdCache.size());
940 bool FontClient::Plugin::CacheHandler::FindEmbeddedPixelBufferId(const std::string& url, PixelBufferId& pixelBufferId) const
944 for(const auto& cacheItem : mPixelBufferCache)
946 if(cacheItem.url == url)
948 // The url is in the pixel buffer cache.
949 pixelBufferId = cacheItem.id;
957 PixelBufferId FontClient::Plugin::CacheHandler::CacheEmbeddedPixelBuffer(const std::string& url)
959 PixelBufferId pixelBufferId = 0u;
961 // Load the image from the url.
962 Devel::PixelBuffer pixelBuffer = LoadImageFromFile(url);
965 // Create the cache item.
966 PixelBufferCacheItem pixelBufferCacheItem;
967 pixelBufferCacheItem.pixelBuffer = pixelBuffer;
968 pixelBufferCacheItem.url = url;
969 pixelBufferCacheItem.id = static_cast<PixelBufferId>(mPixelBufferCache.size() + 1u);
971 // Store the cache item in the cache.
972 mPixelBufferCache.emplace_back(std::move(pixelBufferCacheItem));
974 // Set the pixel buffer id to be returned.
975 pixelBufferId = static_cast<PixelBufferId>(mPixelBufferCache.size());
977 return pixelBufferId;
980 bool FontClient::Plugin::CacheHandler::FindEmbeddedItem(PixelBufferId pixelBufferId, uint32_t width, uint32_t height, GlyphIndex& index) const
984 for(const auto& cacheItem : mEmbeddedItemCache)
986 if((cacheItem.pixelBufferId == pixelBufferId) &&
987 (cacheItem.width == width) &&
988 (cacheItem.height == height))
990 index = cacheItem.index;
998 GlyphIndex FontClient::Plugin::CacheHandler::CacheEmbeddedItem(EmbeddedItem&& embeddedItem)
1000 embeddedItem.index = static_cast<GlyphIndex>(mEmbeddedItemCache.size() + 1u);
1002 // Cache the embedded item.
1003 mEmbeddedItemCache.emplace_back(std::move(embeddedItem));
1005 // Set the font id to be returned.
1006 GlyphIndex index = static_cast<GlyphIndex>(mEmbeddedItemCache.size());
1011 } // namespace Dali::TextAbstraction::Internal