This patch changes FontClient to create and use a handle to FontConfig.
Previously we always used FontConfig globally.
There was no problem because DALi had already recognized and developed this internally.
However, since FontConfig is a library open to the system,
FontConfig may be used by other libs that dali does not know about in the same process,
which may cause Thread safe problems.
Change-Id: Ie603016f08376f9c5ca389069b6c8da7a345d7a2
Signed-off-by: Bowon Ryu <bowon.ryu@samsung.com>
return GetImplementation(*this).AddCustomFontDirectory(path);
}
-void FontClient::ApplyCustomFontDirectories()
+const FontPathList& FontClient::GetCustomFontDirectories()
{
- GetImplementation(*this).ApplyCustomFontDirectories();
+ return GetImplementation(*this).GetCustomFontDirectories();
}
GlyphIndex FontClient::CreateEmbeddedItem(const EmbeddedItemDescription& description, Pixel::Format& pixelFormat)
bool AddCustomFontDirectory(const FontPath& path);
/**
- * @brief Apply custom fonts directories
+ * @brief Gets the custom fonts directories.
+ *
+ * @return list of the custom font paths.
*/
- void ApplyCustomFontDirectories();
+ const FontPathList& GetCustomFontDirectories();
/**
* @brief Creates and stores an embedded item and it's metrics.
return mPlugin->AddCustomFontDirectory(path);
}
-void FontClient::ApplyCustomFontDirectories()
+const FontPathList& FontClient::GetCustomFontDirectories()
{
CreatePlugin();
- return mPlugin->ApplyCustomFontDirectories();
+ return mPlugin->GetCustomFontDirectories();
}
HarfBuzzFontHandle FontClient::GetHarfBuzzFont(FontId fontId)
bool AddCustomFontDirectory(const FontPath& path);
/**
- * @copydoc Dali::TextAbstraction::FontClient::ApplyCustomFontDirectories()
+ * @copydoc Dali::TextAbstraction::FontClient::GetCustomFontDirectories()
*/
- void ApplyCustomFontDirectories();
+ const FontPathList& GetCustomFontDirectories();
public: // API for Dali::TextAbstraction::Internal::FontClient used.
/**
}
}
-bool BitmapFontCacheItem::IsCharacterSupported(Character character)
+bool BitmapFontCacheItem::IsCharacterSupported(FcConfig* fontConfig, Character character)
{
for(const auto& glyph : font.glyphs)
{
/**
* @copydoc FontCacheItemInterface::IsCharacterSupported()
*/
- bool IsCharacterSupported(Character character) override;
+ bool IsCharacterSupported(FcConfig* fontConfig, Character character) override;
/**
* @copydoc FontCacheItemInterface::GetPointSize()
#include <dali/internal/text/text-abstraction/font-client-impl.h> // for HarfBuzzFontHandle
// EXTERNAL INCLUDES
+#include <fontconfig/fontconfig.h>
#include <ft2build.h>
#include FT_FREETYPE_H
/**
* Check if the character is supported by this font
+ * @param[in] fontConfig A handle to a FontConfig library instance.
* @param[in] character The character to test
*/
- virtual bool IsCharacterSupported(Character character) = 0;
+ virtual bool IsCharacterSupported(FcConfig* fontConfig, Character character) = 0;
/**
* Get the point size of this font
* @brief Retrieves the fonts present in the platform.
*
* @note Need to call FcFontSetDestroy to free the allocated resources.
- *
+ * @param[in] fontConfig A handle to a FontConfig library instance.
* @return A font fonfig data structure with the platform's fonts.
*/
-_FcFontSet* GetFcFontSet()
+_FcFontSet* GetFcFontSet(FcConfig* fontConfig)
{
FcFontSet* fontset = nullptr;
// get a list of fonts
// creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
- 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.
+ fontset = FcFontList(fontConfig, pattern, objectSet); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
// clear up the object set
FcObjectSetDestroy(objectSet);
*
* @note CharacterSetList is a vector of FcCharSet that are reference counted. It's needed to call FcCharSetDestroy to decrease the reference counter.
*
+ * @param[in] fontConfig A handle to a FontConfig library instance.
* @param[in] fontDescription A font description.
* @param[out] fontList A list of the fonts which are a close match for fontDescription.
* @param[out] characterSetList A list of character sets which are a close match for fontDescription.
*/
-void SetFontList(const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList)
+void SetFontList(FcConfig* fontConfig, const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList)
{
DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
fontList.clear();
- FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
+ FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontConfig, fontDescription); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
FcResult result = FcResultMatch;
// Match the pattern.
- FcFontSet* fontSet = FcFontSort(nullptr /* use default configure */,
+ FcFontSet* fontSet = FcFontSort(fontConfig,
fontFamilyPattern,
false /* don't trim */,
nullptr,
// CacheHandler
FontClient::Plugin::CacheHandler::CacheHandler()
-: mDefaultFontDescription(),
+: mFontConfig(nullptr),
+ mDefaultFontDescription(),
mSystemFonts(),
mDefaultFonts(),
mFontIdCache(),
mFontFTFaceCache(),
mEllipsisCache(),
mEmbeddedItemCache(),
+ mCustomFontDirectories(),
mGlyphCacheManager(new GlyphCacheManager(GetMaxNumberOfGlyphCache())),
mLatestFoundFontDescription(),
mLatestFoundFontDescriptionId(0u),
FontClient::Plugin::CacheHandler::~CacheHandler()
{
ClearCache();
+ if(mFontConfig)
+ {
+ FcConfigDestroy(mFontConfig);
+ mFontConfig = nullptr;
+ }
}
void FontClient::Plugin::CacheHandler::ClearCache()
{
for(const auto& description : mDefaultFonts)
{
- mDefaultFontCharacterSets.PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
+ mDefaultFontCharacterSets.PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(mFontConfig, description)));
}
for(const auto& description : mFontDescriptionCache)
{
- mCharacterSetCache.PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
+ mCharacterSetCache.PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(mFontConfig, description)));
}
for(auto& item : mFallbackCache)
for(const auto& description : *(item.fallbackFonts))
{
- item.characterSets->PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
+ item.characterSets->PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(mFontConfig, description)));
}
}
}
{
if(mSystemFonts.empty())
{
- FcFontSet* fontSet = GetFcFontSet(); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
+ FcFontSet* fontSet = GetFcFontSet(mFontConfig); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
if(fontSet)
{
fontDescription.width = DefaultFontWidth();
fontDescription.weight = DefaultFontWeight();
fontDescription.slant = DefaultFontSlant();
- SetFontList(fontDescription, mDefaultFonts, mDefaultFontCharacterSets);
+ SetFontList(mFontConfig, fontDescription, mDefaultFonts, mDefaultFontCharacterSets);
}
}
// FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
// FcInitReinitialize resets global Fonconfig state and cache, which can cause race conditions or double free.
// FcInitLoadConfigAndFonts sets the current default configuration for the library, which is specific to the calling process.
+ if(mFontConfig)
+ {
+ FcConfigDestroy(mFontConfig);
+ }
+ mFontConfig = FcInitLoadConfigAndFonts();
- FcConfig* newConfig = FcInitLoadConfigAndFonts();
-
- if(newConfig)
+ if(mFontConfig)
{
for(auto &path: mCustomFontDirectories)
{
- FcConfigAppFontAddDir(newConfig, reinterpret_cast<const FcChar8*>(path.c_str()));
+ FcConfigAppFontAddDir(mFontConfig, reinterpret_cast<const FcChar8*>(path.c_str()));
}
-
- FcConfigBuildFonts(newConfig);
- FcConfigSetCurrent(newConfig);
- FcConfigDestroy(newConfig);
}
else
{
if(nullptr != matchPattern)
{
- FcConfigSubstitute(nullptr, matchPattern, FcMatchPattern);
+ FcConfigSubstitute(mFontConfig, matchPattern, FcMatchPattern);
FcDefaultSubstitute(matchPattern);
FcCharSet* characterSet = nullptr;
- bool matched = MatchFontDescriptionToPattern(matchPattern, mDefaultFontDescription, &characterSet);
+ bool matched = MatchFontDescriptionToPattern(mFontConfig, matchPattern, mDefaultFontDescription, &characterSet);
// Caching the default font description
if(matched)
DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_VALIDATE_FONT");
// Create a font pattern.
- FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription);
+ FcPattern* fontFamilyPattern = CreateFontFamilyPattern(mFontConfig, fontDescription);
FontDescription description;
FcCharSet* characterSet = nullptr;
- bool matched = MatchFontDescriptionToPattern(fontFamilyPattern, description, &characterSet);
+ bool matched = MatchFontDescriptionToPattern(mFontConfig, fontFamilyPattern, description, &characterSet);
FcPatternDestroy(fontFamilyPattern);
if(matched && (nullptr != characterSet))
fontList = new FontList;
characterSetList = new CharacterSetList;
- SetFontList(fontDescription, *fontList, *characterSetList);
+ SetFontList(mFontConfig, fontDescription, *fontList, *characterSetList);
#ifdef __APPLE__
FontDescription appleColorEmoji;
appleColorEmoji.family = "Apple Color Emoji";
appleColorEmoji.slant = fontDescription.slant;
FontList emojiFontList;
CharacterSetList emojiCharSetList;
- SetFontList(appleColorEmoji, emojiFontList, emojiCharSetList);
+ SetFontList(mFontConfig, appleColorEmoji, emojiFontList, emojiCharSetList);
std::move(fontList->begin(), fontList->end(), std::back_inserter(emojiFontList));
emojiCharSetList.Insert(emojiCharSetList.End(), characterSetList->Begin(), characterSetList->End());
mFontDescriptionSizeCache.emplace(CacheHandler::FontDescriptionSizeCacheKey(fontDescriptionId, requestedPointSize), fontCacheIndex);
*/
- FcPattern* pattern = CreateFontFamilyPattern(description); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
+ FcPattern* pattern = CreateFontFamilyPattern(mFontConfig, description); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
FcResult result = FcResultMatch;
- FcPattern* match = FcFontMatch(nullptr, pattern, &result); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
+ FcPattern* match = FcFontMatch(mFontConfig, pattern, &result); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
FcCharSet* characterSet = nullptr;
FcPatternGetCharSet(match, FC_CHARSET, 0u, &characterSet);
CacheHandler& operator=(const CacheHandler&) = delete;
public: // Cache container list
+ FcConfig* mFontConfig; ///< A handle to a FontConfig library instance.
FontDescription mDefaultFontDescription; ///< Cached default font from the system
FontList mSystemFonts; ///< Cached system fonts.
std::vector<PixelBufferCacheItem> mPixelBufferCache; ///< Caches the pixel buffer of a url.
std::vector<EmbeddedItem> mEmbeddedItemCache; ///< Cache embedded items.
- std::vector<std::string> mCustomFontDirectories; ///< Cache custom font directories to recovery upon reinitialization.
+ FontPathList mCustomFontDirectories; ///< Cache custom font directories to recovery upon reinitialization.
private: // Member value
std::unique_ptr<GlyphCacheManager> mGlyphCacheManager; ///< The glyph cache manager. It will cache this face's glyphs.
mIsAtlasLimitationEnabled(TextAbstraction::FontClient::DEFAULT_ATLAS_LIMITATION_ENABLED),
mCurrentMaximumBlockSizeFitInAtlas(TextAbstraction::FontClient::MAX_SIZE_FIT_IN_ATLAS),
mVectorFontCache(nullptr),
- mCacheHandler(new CacheHandler()),
- mCustomFonts(),
- mIsCustomFontsApplied(false)
+ mCacheHandler(new CacheHandler())
{
int error = FT_Init_FreeType(&mFreeTypeLibrary);
if(FT_Err_Ok != error)
auto fontCacheItem = const_cast<FontCacheItemInterface*>(GetCachedFontItem(fontId));
if(fontCacheItem != nullptr)
{
- isSupported = fontCacheItem->IsCharacterSupported(character); // May cache
+ isSupported = fontCacheItem->IsCharacterSupported(mCacheHandler->mFontConfig, character); // May cache
}
DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " is supported : %s\n", (isSupported ? "true" : "false"));
bool FontClient::Plugin::AddCustomFontDirectory(const FontPath& path)
{
- if(!mIsCustomFontsApplied)
- {
- if(mCustomFonts.size() > CUSTOM_FONTS_MAX_COUNT)
- {
- mCustomFonts.clear();
- }
- mCustomFonts.push_back(path);
-
- if(mCacheHandler)
- {
- mCacheHandler->mCustomFontDirectories.push_back(path);
- }
- }
- // nullptr as first parameter means the current configuration is used.
- return FcConfigAppFontAddDir(nullptr, reinterpret_cast<const FcChar8*>(path.c_str()));
+ mCacheHandler->mCustomFontDirectories.push_back(path);
+ return FcConfigAppFontAddDir(mCacheHandler->mFontConfig, reinterpret_cast<const FcChar8*>(path.c_str()));
}
-void FontClient::Plugin::ApplyCustomFontDirectories()
+const FontPathList& FontClient::Plugin::GetCustomFontDirectories()
{
- for(const auto& path : mCustomFonts)
- {
- FcConfigAppFontAddDir(nullptr, reinterpret_cast<const FcChar8*>(path.c_str()));
- }
- mCustomFonts.clear();
- mIsCustomFontsApplied = true;
+ return mCacheHandler->mCustomFontDirectories;
}
HarfBuzzFontHandle FontClient::Plugin::GetHarfBuzzFont(FontId fontId) const
bool FontClient::Plugin::IsScalable(const FontDescription& fontDescription) const
{
// Create a font pattern.
- FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
+ FcPattern* fontFamilyPattern = CreateFontFamilyPattern(mCacheHandler->mFontConfig, fontDescription); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
FcResult result = FcResultMatch;
// match the pattern
- FcPattern* match = FcFontMatch(nullptr /* use default configure */, fontFamilyPattern, &result); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
+ FcPattern* match = FcFontMatch(mCacheHandler->mFontConfig, fontFamilyPattern, &result); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
bool isScalable = false;
if(match)
Vector<PointSize26Dot6>& sizes) const
{
// Create a font pattern.
- FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
+ FcPattern* fontFamilyPattern = CreateFontFamilyPattern(mCacheHandler->mFontConfig, fontDescription); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
FcResult result = FcResultMatch;
// match the pattern
- FcPattern* match = FcFontMatch(nullptr /* use default configure */, fontFamilyPattern, &result); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
+ FcPattern* match = FcFontMatch(mCacheHandler->mFontConfig, fontFamilyPattern, &result); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
if(match)
{
bool AddCustomFontDirectory(const FontPath& path);
/**
- * @copydoc Dali::TextAbstraction::FontClient::ApplyCustomFontDirectories()
+ * @copydoc Dali::TextAbstraction::FontClient::GetCustomFontDirectories()
*/
- void ApplyCustomFontDirectories();
+ const FontPathList& GetCustomFontDirectories();
public: // Dali::TextAbstraction::Internal::FontClient
/**
struct CacheHandler;
CacheHandler* mCacheHandler; ///< Seperate cache for font data.
-
- FontPathList mCustomFonts;
- bool mIsCustomFontsApplied : 1;
};
} // namespace Internal
}
}
-FcPattern* CreateFontFamilyPattern(const FontDescription& fontDescription)
+FcPattern* CreateFontFamilyPattern(FcConfig* fontConfig, const FontDescription& fontDescription)
{
// create the cached font family lookup pattern
// a pattern holds a set of names, each name refers to a property of the font
FcPatternAddInteger(fontFamilyPattern, FC_SLANT, slant);
// modify the config, with the mFontFamilyPatterm
- FcConfigSubstitute(nullptr /* use default configure */, fontFamilyPattern, FcMatchPattern);
+ FcConfigSubstitute(fontConfig, fontFamilyPattern, FcMatchPattern);
// provide default values for unspecified properties in the font pattern
// e.g. patterns without a specified style or weight are set to Medium
return fontFamilyPattern;
}
-FcCharSet* CreateCharacterSetFromDescription(const FontDescription& description)
+FcCharSet* CreateCharacterSetFromDescription(FcConfig* fontConfig, const FontDescription& description)
{
FcCharSet* characterSet = nullptr;
- FcPattern* pattern = CreateFontFamilyPattern(description); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
+ FcPattern* pattern = CreateFontFamilyPattern(fontConfig, description); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
if(nullptr != pattern)
{
FcResult result = FcResultMatch;
- FcPattern* match = FcFontMatch(nullptr, pattern, &result); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
+ FcPattern* match = FcFontMatch(fontConfig, pattern, &result); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
FcPatternGetCharSet(match, FC_CHARSET, 0u, &characterSet);
return characterSet;
}
-bool MatchFontDescriptionToPattern(FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet)
+bool MatchFontDescriptionToPattern(FcConfig* fontConfig, FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet)
{
DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
FcResult result = FcResultMatch;
- FcPattern* match = FcFontMatch(nullptr /* use default configure */, pattern, &result); // Creates a new font pattern that needs to be destroyed by calling FcPatternDestroy.
+ FcPattern* match = FcFontMatch(fontConfig, pattern, &result); // Creates a new font pattern that needs to be destroyed by calling FcPatternDestroy.
const bool matched = nullptr != match;
DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " pattern matched : %s\n", (matched ? "true" : "false"));
*
* @note Need to call FcPatternDestroy to free the resources.
*
+ * @param[in] fontConfig A handle to a FontConfig library instance.
* @param[in] fontDescription The font to cache.
*
* @return The pattern.
*/
-FcPattern* CreateFontFamilyPattern(const FontDescription& fontDescription);
+FcPattern* CreateFontFamilyPattern(FcConfig* fontConfig, const FontDescription& fontDescription);
/**
* @brief Creates a character set from a given font's @p description.
*
* @note Need to call FcCharSetDestroy to free the resources.
*
+ * @param[in] fontConfig A handle to a FontConfig library instance.
* @param[in] description The font's description.
*
* @return A character set.
*/
-FcCharSet* CreateCharacterSetFromDescription(const FontDescription& description);
+FcCharSet* CreateCharacterSetFromDescription(FcConfig* fontConfig, const FontDescription& description);
/**
* @brief Gets the FontDescription which matches the given pattern.
*
* @note The reference counter of the @p characterSet has been increased. Call FcCharSetDestroy to decrease it.
*
+ * @param[in] fontConfig A handle to a FontConfig library instance.
* @param[in] pattern pattern to match against.
* @param[out] fontDescription the resultant fontDescription that matched.
* @param[out] characterSet The character set for that pattern.
* @return true if match found.
*/
-bool MatchFontDescriptionToPattern(FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet);
+bool MatchFontDescriptionToPattern(FcConfig* fontConfig, FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet);
/**
* @brief Retrieves a font config object's value from a pattern.
/**
* Check if the character is supported by this font
+ * @param[in] fontConfig A handle to a FontConfig library instance.
* @param[in] character The character to test
*/
-bool FontFaceCacheItem::IsCharacterSupported(Character character)
+bool FontFaceCacheItem::IsCharacterSupported(FcConfig* fontConfig, Character character)
{
if(nullptr == mCharacterSet)
{
description.weight = FontWeight::BOLD;
}
- mCharacterSet = FcCharSetCopy(CreateCharacterSetFromDescription(description));
+ mCharacterSet = FcCharSetCopy(CreateCharacterSetFromDescription(fontConfig, description));
}
return FcCharSetHasChar(mCharacterSet, character);
/**
* @copydoc FontCacheItemInterface::IsCharacterSupported()
*/
- bool IsCharacterSupported(Character character) override;
+ bool IsCharacterSupported(FcConfig* fontConfig, Character character) override;
/**
* @copydoc FontCacheItemInterface::GetPointSize()