This patch adds a new FontClientFontPreLoad API that preloads font faces.
this can prevents delays on main thread during the inital call of FT_New_Face.
using memoryFontPathList involves loading font buffers into memory.
And using FT_New_Memory_Face at runtime, which uses more memory
but can lead to greater performance improvements.
Change-Id: Id4ea04c23e2e63354e818b5ba74783508c43c8b7
Signed-off-by: Bowon Ryu <bowon.ryu@samsung.com>
int ReadFile(const std::string& filename, std::streampos& fileSize, Dali::Vector<char>& memblock, FileLoader::FileType fileType)
{
return Dali::Internal::Adaptor::ReadFile(filename, fileSize, memblock, fileType);
- ;
+}
+
+int ReadFile(const std::string& filename, std::streampos& fileSize, Dali::Vector<uint8_t>& memblock, FileLoader::FileType fileType)
+{
+ return Dali::Internal::Adaptor::ReadFile(filename, fileSize, memblock, fileType);
}
std::streampos GetFileSize(const std::string& filename)
#define DALI_FILE_LOADER_H
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
DALI_ADAPTOR_API int ReadFile(const std::string& filename, std::streampos& fileSize, Dali::Vector<char>& memblock, FileLoader::FileType fileType = BINARY);
/**
+ * @brief Load the file. It will load it either as a binary or as a text
+ *
+ * @param[in] filename Filename of the file to load.
+ * @param[in] fileSize Size of the loaded file
+ * @param[in] memblock Dali::Vector containing the buffer loaded
+ * @param[in] fileType How we want to load the file. Binary or Text. Binary default
+ * @return error code. 0 - Error, 1 - Ok
+ *
+ */
+DALI_ADAPTOR_API int ReadFile(const std::string& filename, std::streampos& fileSize, Dali::Vector<uint8_t>& memblock, FileLoader::FileType fileType = BINARY);
+
+/**
* @brief Get the file size of a file
*
* @param[in] filename Filename of the file to load.
GetImplementation(*this).GetDefaultFonts(defaultFonts);
}
+void FontClient::InitDefaultFontDescription()
+{
+ GetImplementation(*this).InitDefaultFontDescription();
+}
+
void FontClient::GetDefaultPlatformFontDescription(FontDescription& fontDescription)
{
GetImplementation(*this).GetDefaultPlatformFontDescription(fontDescription);
Internal::FontClient::PreCache(fallbackFamilyList, extraFamilyList, localeFamily, useThread);
}
+void FontClientFontPreLoad(const FontPathList& fontPathList, const FontPathList& memoryFontPathList, bool useThread)
+{
+ Internal::FontClient::PreLoad(fontPathList, memoryFontPathList, useThread);
+}
+
} // namespace TextAbstraction
} // namespace Dali
void GetDefaultFonts(FontList& defaultFonts);
/**
+ * @brief Initializes and caches default font from the system.
+ */
+ void InitDefaultFontDescription();
+
+ /**
* @brief Retrieve the active default font from the system.
*
* @param[out] fontDescription font structure describing the default font.
DALI_ADAPTOR_API FontClient FontClientPreInitialize();
/**
- * @brief This is used to pre-cache fonts in order to improve the runtime performance of the application.
+ * @brief This is used to pre-cache FontConfig in order to improve the runtime performance of the application.
*
* @param[in] fallbackFamilyList A list of fallback font families to be pre-cached.
* @param[in] extraFamilyList A list of additional font families to be pre-cached.
*/
DALI_ADAPTOR_API void FontClientPreCache(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily, bool useThread);
+/**
+ * @brief This is used to pre-load FreeType font face in order to improve the runtime performance of the application.
+ *
+ * @param[in] fontPathList A list of font paths to be pre-loaded.
+ * @param[in] memoryFontPathList A list of memory font paths to be pre-loaded.
+ * @param[in] useThread True if the font client should create thread and perform font pre-loading, false otherwise.
+ *
+ * @note
+ * The fonts in the fontPathList perform FT_New_Face during pre-loading,
+ * which can provide some performace benefits.
+ *
+ * The fonts in the memoryFontPathList read the font file and cache the buffer in memory during pre-load.
+ * This enables the use of FT_New_Memory_Face during runtime and provides a performance boost.
+ * It requires memory equivalent to the size of each font file.
+ */
+DALI_ADAPTOR_API void FontClientFontPreLoad(const FontPathList& fontPathList, const FontPathList& memoryFontPathList, bool useThread);
+
} // namespace TextAbstraction
} // namespace Dali
typedef std::string FontFamily;
typedef std::string FontStyle;
typedef std::vector<FontFamily> FontFamilyList;
+typedef std::vector<FontPath> FontPathList;
namespace FontWidth
{
#include <dali/internal/text/text-abstraction/font-client-impl.h>
// EXTERNAL INCLUDES
+#include <mutex>
#include <thread>
#if defined(VCONF_ENABLED)
#include <vconf.h>
#include <dali/devel-api/text-abstraction/glyph-info.h>
+// Use this macro only if need to log messages before the log function is set.
#define FONT_LOG_MESSAGE(level, format, ...) \
do \
{ \
{
Dali::TextAbstraction::FontClient FontClient::gPreCreatedFontClient(NULL);
std::thread gPreCacheThread;
+std::thread gPreLoadThread;
+std::mutex gMutex;
+
/* TODO: This is to prevent duplicate calls of font pre-cache.
* We may support this later, but currently we can't guarantee the behaviour
* if there is a pre-cache call from the user after the font client has been created. */
bool gFontPreCacheAvailable = true;
+bool gFontPreLoadAvailable = true;
FontClient::FontClient()
: mPlugin(nullptr),
FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient PreCache thread join\n");
}
+ if(gPreLoadThread.joinable())
+ {
+ gPreLoadThread.join();
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient PreLoad thread join\n");
+ }
+
if(gPreCreatedFontClient)
{
fontClientHandle = gPreCreatedFontClient;
else
{
fontClientHandle = Dali::TextAbstraction::FontClient(new FontClient);
-
- // Make DefaultFontDescription cached
- Dali::TextAbstraction::FontDescription defaultFontDescription;
- fontClientHandle.GetDefaultPlatformFontDescription(defaultFontDescription);
}
+ fontClientHandle.InitDefaultFontDescription();
+
gFontPreCacheAvailable = false;
+ gFontPreLoadAvailable = false;
uint32_t horizontalDpi, verticalDpi;
fontClientHandle.GetDpi(horizontalDpi, verticalDpi);
{
// Pre-cached font client already exists or pre-cache thread already running.
// Font client pre-cache includes caching of the default font description.
- if((gPreCreatedFontClient && !gFontPreCacheAvailable) ||
- (gPreCacheThread.joinable()))
+ if(gPreCreatedFontClient && !gFontPreCacheAvailable)
{
return gPreCreatedFontClient;
}
- gPreCreatedFontClient = Dali::TextAbstraction::FontClient(new FontClient);
+ if(!gPreCreatedFontClient)
+ {
+ gPreCreatedFontClient = Dali::TextAbstraction::FontClient(new FontClient);
+ }
- // Make DefaultFontDescription cached
- Dali::TextAbstraction::FontDescription defaultFontDescription;
- gPreCreatedFontClient.GetDefaultPlatformFontDescription(defaultFontDescription);
+ gPreCreatedFontClient.InitDefaultFontDescription();
return gPreCreatedFontClient;
}
void FontClient::PreCacheRun(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily)
{
- if(gFontPreCacheAvailable)
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "BEGIN: DALI_TEXT_PRECACHE_RUN\n");
+ GetImplementation(gPreCreatedFontClient).FontPreCache(fallbackFamilyList, extraFamilyList, localeFamily);
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "END: DALI_TEXT_PRECACHE_RUN\n");
+}
+
+void FontClient::PreLoadRun(const FontPathList& fontPathList, const FontPathList& memoryFontPathList)
+{
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "BEGIN: DALI_TEXT_FONT_PRELOAD_RUN\n");
+ GetImplementation(gPreCreatedFontClient).FontPreLoad(fontPathList, memoryFontPathList);
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "END: DALI_TEXT_FONT_PRELOAD_RUN\n");
+}
+
+void FontClient::PreCache(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily, bool useThread)
+{
+ if(!gFontPreCacheAvailable)
{
- gFontPreCacheAvailable = false;
- FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "BEGIN: DALI_TEXT_PRECACHE_RUN\n");
- if(!gPreCreatedFontClient)
- {
- gPreCreatedFontClient = Dali::TextAbstraction::FontClient(new FontClient);
- }
- GetImplementation(gPreCreatedFontClient).FontPreCache(fallbackFamilyList, extraFamilyList, localeFamily);
- FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "END: DALI_TEXT_PRECACHE_RUN\n");
+ FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "FontClient pre-cache run failed, as a pre-cached font client already exists.\n");
+ return;
+ }
+
+ if(gPreCacheThread.joinable())
+ {
+ FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "FontClient pre-cache thread already running.\n");
+ }
+
+ if(!gPreCreatedFontClient)
+ {
+ gPreCreatedFontClient = Dali::TextAbstraction::FontClient(new FontClient);
+ }
+
+ gFontPreCacheAvailable = false;
+
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient FontConfig PreCache fallbackFamilyList : %zu\n", fallbackFamilyList.size());
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient FontConfig PreCache extraFamilyList : %zu\n", extraFamilyList.size());
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient FontConfig PreCache localeFamily : %s\n", localeFamily.c_str());
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient FontConfig PreCache useThread : %d\n", useThread);
+
+ if(useThread)
+ {
+ gPreCacheThread = std::thread(PreCacheRun, fallbackFamilyList, extraFamilyList, localeFamily);
}
else
{
- FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "FontClient pre-cache run failed, as a pre-cached font client already exists.\n");
+ PreCacheRun(fallbackFamilyList, extraFamilyList, localeFamily);
}
}
-void FontClient::PreCache(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily, bool useThread)
+void FontClient::PreLoad(const FontPathList& fontPathList, const FontPathList& memoryFontPathList, bool useThread)
{
- if(!gFontPreCacheAvailable)
+ if(!gFontPreLoadAvailable)
{
- FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "FontClient pre-cache has been completed or the font client has already been created.\n");
+ FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "FontClient font pre-load run failed, as a pre-loaded font client already exists.\n");
return;
}
- FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient PreCache fallbackFamilyList : %zu\n", fallbackFamilyList.size());
- FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient PreCache extraFamilyList : %zu\n", extraFamilyList.size());
- FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient PreCache localeFamily : %s\n", localeFamily.c_str());
- FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient PreCache useThread : %d\n", useThread);
+ if(gPreLoadThread.joinable())
+ {
+ FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "FontClient font pre-load thread already running.\n");
+ return;
+ }
- if(gPreCacheThread.joinable())
+ if(!gPreCreatedFontClient)
{
- FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "FontClient pre-cache thread already running.\n");
+ gPreCreatedFontClient = Dali::TextAbstraction::FontClient(new FontClient);
+ }
+
+ gFontPreLoadAvailable = false;
+
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient Font PreLoad fontPathList : %zu\n", fontPathList.size());
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient Font PreLoad memoryFontPathList : %zu\n", memoryFontPathList.size());
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient Font PreLoad useThread : %d\n", useThread);
+
+ if(useThread)
+ {
+ gPreLoadThread = std::thread(PreLoadRun, fontPathList, memoryFontPathList);
}
else
{
- if(useThread)
- {
- gPreCacheThread = std::thread(PreCacheRun, fallbackFamilyList, extraFamilyList, localeFamily);
- }
- else
- {
- PreCacheRun(fallbackFamilyList, extraFamilyList, localeFamily);
- }
+ PreLoadRun(fontPathList, memoryFontPathList);
}
}
mPlugin->FontPreCache(fallbackFamilyList, extraFamilyList, localeFamily);
}
+void FontClient::FontPreLoad(const FontPathList& fontPathList, const FontPathList& memoryFontPathList)
+{
+ CreatePlugin();
+
+ mPlugin->FontPreLoad(fontPathList, memoryFontPathList);
+}
+
+void FontClient::InitDefaultFontDescription()
+{
+ CreatePlugin();
+
+ mPlugin->InitDefaultFontDescription();
+}
+
void FontClient::GetDefaultPlatformFontDescription(FontDescription& fontDescription)
{
CreatePlugin();
void FontClient::CreatePlugin()
{
+ std::scoped_lock lock(gMutex);
if(!mPlugin)
{
mPlugin = new Plugin(mDpiHorizontal, mDpiVertical);
#define DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_IMPL_H
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
static Dali::TextAbstraction::FontClient PreInitialize();
/**
- * @brief This is used to pre-cache fonts in order to improve the runtime performance of the application.
+ * @brief This is used to pre-cache FontConfig in order to improve the runtime performance of the application.
*
* @see Dali::TextAbstraction::FontClientPreCache(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily, bool useThread);
*/
- static void PreCache(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily, bool useUiThread);
+ static void PreCache(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily, bool useThread);
/**
- * @brief This is used to creates a global font client and pre-caches the fonts.
+ * @brief This is used to creates a global font client and pre-caches the FontConfig.
*/
static void PreCacheRun(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily);
/**
+ * @brief This is used to pre-load FreeType font face in order to improve the runtime performance of the application.
+ *
+ * @see Dali::TextAbstraction:FontClientFontPreLoad(const FontPathList& fontPathList, const FontPathList& memoryFontPathList, bool useThread);
+ */
+ static void PreLoad(const FontPathList& fontPathList, const FontPathList& memoryFontPathList, bool useThread);
+
+ /**
+ * @brief This is used to creates a global font client and pre-loads the FreeType font face.
+ */
+ static void PreLoadRun(const FontPathList& fontPathList, const FontPathList& memoryFontPathList);
+
+ /**
* @copydoc Dali::TextAbstraction::FontClient::ClearCache()
*/
void ClearCache();
void GetDefaultFonts(FontList& defaultFonts);
/**
+ * @copydoc Dali::TextAbstraction::FontClient::InitDefaultFontDescription()
+ */
+ void InitDefaultFontDescription();
+
+ /**
* @copydoc Dali::TextAbstraction::FontClient::GetDefaultPlatformFontDescription()
*/
void GetDefaultPlatformFontDescription(FontDescription& fontDescription);
*/
void FontPreCache(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily);
+ /**
+ * @brief This is used to pre-load FreeType font face in order to improve the runtime performance of the application.
+ *
+ * @param[in] fontPathList A list of font paths to be pre-loaded.
+ * @param[in] memoryFontPathList A list of memory font paths to be pre-loaded.
+ * @param[in] useThread True if the font client should create thread and perform font pre-loading, false otherwise.
+ */
+ void FontPreLoad(const FontPathList& fontPathList, const FontPathList& memoryFontPathList);
+
+
private:
/**
* Helper for lazy initialization.
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// INTERNAL INCLUDES
#include <dali/devel-api/adaptor-framework/environment-variable.h>
+#include <dali/devel-api/adaptor-framework/file-loader.h>
#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/internal/system/common/logging.h>
#include <dali/internal/text/text-abstraction/font-client-impl.h>
#include <dali/internal/text/text-abstraction/plugin/font-client-plugin-impl.h>
#include <dali/internal/text/text-abstraction/plugin/font-client-utils.h>
+// Use this macro only if need to log messages before the log function is set.
+#define FONT_LOG_MESSAGE(level, format, ...) \
+ do \
+ { \
+ char buffer[256]; \
+ int result = std::snprintf(buffer, sizeof(buffer), format, ##__VA_ARGS__); \
+ if(result >= static_cast<int>(sizeof(buffer))) \
+ { \
+ std::string log("Font log message is too long to fit in the buffer.\n"); \
+ Dali::TizenPlatform::LogMessage(Dali::Integration::Log::ERROR, log); \
+ break; \
+ } \
+ std::string log(buffer); \
+ Dali::TizenPlatform::LogMessage(level, log); \
+ } while(0)
+
#if defined(DEBUG_ENABLED)
extern Dali::Integration::Log::Filter* gFontClientLogFilter;
mFontDescriptionCache(),
mCharacterSetCache(),
mFontDescriptionSizeCache(),
+ mFontDataCache(),
+ mFontFTFaceCache(),
mEllipsisCache(),
mEmbeddedItemCache(),
mGlyphCacheManager(new GlyphCacheManager(GetMaxNumberOfGlyphCache())),
mFontDescriptionSizeCache.clear();
mFontDescriptionSizeCache.rehash(0); // Note : unordered_map.clear() didn't deallocate memory
+ mFontDataCache.clear();
+ mFontDataCache.rehash(0);
+
+ ClearFTFaceFromFontFTFaceCache();
+ mFontFTFaceCache.clear();
+ mFontFTFaceCache.rehash(0);
+
mEllipsisCache.clear();
mPixelBufferCache.clear();
mEmbeddedItemCache.clear();
}
}
+void FontClient::Plugin::CacheHandler::ClearFTFaceFromFontFTFaceCache()
+{
+ for(auto& item : mFontFTFaceCache)
+ {
+ FT_Done_Face(item.second);
+ }
+}
+
// System / Default
void FontClient::Plugin::CacheHandler::InitSystemFonts()
{
if(!mDefaultFontDescriptionCached)
{
+ mDefaultFontDescriptionCached = true;
+
// Clear any font config stored info in the caches.
ClearCharacterSet();
// Create again the character sets as they are not valid after FcInitReinitialize()
CreateCharacterSet();
+ }
+}
- mDefaultFontDescriptionCached = true;
+// Font
+
+bool FontClient::Plugin::CacheHandler::FindFontData(const std::string& fontPath) const
+{
+ auto it = mFontDataCache.find(fontPath);
+ if(it != mFontDataCache.end())
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool FontClient::Plugin::CacheHandler::FindFontData(const std::string& fontPath, uint8_t*& fontDataPtr, std::streampos& dataSize) const
+{
+ auto it = mFontDataCache.find(fontPath);
+ if(it != mFontDataCache.end())
+ {
+ fontDataPtr = it->second.first.Begin();
+ dataSize = it->second.second;
+ return true;
}
+
+ return false;
+}
+
+bool FontClient::Plugin::CacheHandler::LoadFontDataFromFile(const std::string& fontPath, Dali::Vector<uint8_t>& fontDataBuffer, std::streampos& dataSize) const
+{
+ if(Dali::FileLoader::ReadFile(fontPath, dataSize, fontDataBuffer, Dali::FileLoader::BINARY))
+ {
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "PreLoad font file buffer : %lu, size : %ld, path : %s\n", fontDataBuffer.Size(), static_cast<long>(dataSize), fontPath.c_str());
+ return true;
+ }
+
+ return false;
+}
+
+void FontClient::Plugin::CacheHandler::CacheFontData(const std::string& fontPath, Dali::Vector<uint8_t>& fontDataBuffer, std::streampos& dataSize)
+{
+ mFontDataCache[fontPath] = std::make_pair(std::move(fontDataBuffer), dataSize);
+}
+
+bool FontClient::Plugin::CacheHandler::FindFontFace(const std::string& fontPath) const
+{
+ auto it = mFontFTFaceCache.find(fontPath);
+ if(it != mFontFTFaceCache.end())
+ {
+ return true;
+ }
+
+ return false;
+}
+
+void FontClient::Plugin::CacheHandler::CacheFontFace(const std::string& fontPath, FT_Face ftFace)
+{
+ mFontFTFaceCache[fontPath] = std::move(ftFace);
}
// Validate
#define DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_PLUGIN_CACHE_HANDLER_H
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*/
void ClearCharacterSet();
+ /**
+ * @brief Free the resources allocated in FreeType face cache.
+ */
+ void ClearFTFaceFromFontFTFaceCache();
+
private:
/**
* @brief Crate the charset resouces by default font and Fallback caches.
*/
void InitDefaultFontDescription();
+ // Font
+
+ /**
+ * @brief Checks if font data for the specified font path is cached.
+ *
+ * @param[in] fontPath The font path to check for cached data.
+ *
+ * @return @e true if the font data is cached, otherwise false.
+ */
+ bool FindFontData(const std::string& fontPath) const;
+
+ /**
+ * @brief Retrieves font data for the specified font path if it is cached.
+ *
+ * @param[in] fontPath The font path to retrieve the cached data for.
+ * @param[out] fontDataPtr A pointer to the cached font data.
+ * @param[out] dataSize The size of the cached font data.
+ *
+ * @return @e true if the font data is cached and retrieved successfully, otherwise false.
+ */
+ bool FindFontData(const std::string& fontPath, uint8_t*& fontDataPtr, std::streampos& dataSize) const;
+
+ /**
+ * @brief Loads font data from the specified file path.
+ *
+ * @param[in] fontPath The file path to load the font data from.
+ * @param[out] fontDataBuffer A vector containing the loaded font data.
+ * @param[out] dataSize The size of the loaded font data.
+ *
+ * @return @e true if the font data was loaded successfully, otherwise false.
+ */
+ bool LoadFontDataFromFile(const std::string& fontPath, Dali::Vector<uint8_t>& fontDataBuffer, std::streampos& dataSize) const;
+
+ /**
+ * @brief Caches font data for the specified font path.
+ *
+ * @param[in] fontPath The font path to cache the data for.
+ * @param[in] fontDataBuffer A vector containing the font data to cache.
+ * @param[in] dataSize The size of the font data to cache.
+ */
+ void CacheFontData(const std::string& fontPath, Dali::Vector<uint8_t>& fontDataBuffer, std::streampos& dataSize);
+
+ /**
+ * @brief Checks if FreeType face for the specified font path is cached.
+ *
+ * @param[in] fontPath The font path to check for cached face.
+ *
+ * @return @e true if the font face is cached, otherwise false.
+ */
+ bool FindFontFace(const std::string& fontPath) const;
+
+ /**
+ * @brief Caches FreeType face for the specified font path.
+ *
+ * @param[in] fontPath The font path to cache the face for.
+ * @param[in] ftFace The freetype font face to cache.
+ */
+ void CacheFontFace(const std::string& fontPath, FT_Face ftFace);
+
// Validate
/**
FontDescriptionSizeCacheContainer mFontDescriptionSizeCache; ///< Caches font identifiers for the pairs of font point size and the index to the vector with font descriptions of the validated fonts.
+ std::unordered_map<std::string, std::pair<Dali::Vector<uint8_t>, std::streampos>> mFontDataCache; ///< Caches font data with each font path as the key, allowing faster loading of fonts later on.
+ std::unordered_map<std::string, FT_Face> mFontFTFaceCache; ///< Caches freetype font face for font pre-load.
+
std::vector<EllipsisItem> mEllipsisCache; ///< Caches ellipsis glyphs for a particular point size.
std::vector<BitmapFontCacheItem> mBitmapFontCache; ///< Stores bitmap fonts.
std::vector<PixelBufferCacheItem> mPixelBufferCache; ///< Caches the pixel buffer of a url.
#include <dali/integration-api/trace.h>
#include <dali/internal/adaptor/common/adaptor-impl.h>
#include <dali/internal/imaging/common/image-operations.h>
+#include <dali/internal/system/common/logging.h>
#include <dali/internal/text/text-abstraction/plugin/bitmap-font-cache-item.h>
#include <dali/internal/text/text-abstraction/plugin/embedded-item.h>
#include <dali/internal/text/text-abstraction/plugin/font-client-plugin-cache-handler.h>
#include <algorithm>
#include <iterator>
+// Use this macro only if need to log messages before the log function is set.
+#define FONT_LOG_MESSAGE(level, format, ...) \
+ do \
+ { \
+ char buffer[256]; \
+ int result = std::snprintf(buffer, sizeof(buffer), format, ##__VA_ARGS__); \
+ if(result >= static_cast<int>(sizeof(buffer))) \
+ { \
+ std::string log("Font log message is too long to fit in the buffer.\n"); \
+ Dali::TizenPlatform::LogMessage(Dali::Integration::Log::ERROR, log); \
+ break; \
+ } \
+ std::string log(buffer); \
+ Dali::TizenPlatform::LogMessage(level, log); \
+ } while(0)
+
#if defined(DEBUG_ENABLED)
// Note, to turn on trace and verbose logging, use "export LOG_FONT_CLIENT=3,true"
mCacheHandler->ResetSystemDefaults();
}
+void FontClient::Plugin::CacheFontDataFromFile(const std::string& fontPath) const
+{
+ if(fontPath.empty())
+ {
+ return;
+ }
+
+ if(mCacheHandler->FindFontData(fontPath))
+ {
+ // Font data is already cached, no need to reload
+ return;
+ }
+
+ Dali::Vector<uint8_t> fontDataBuffer;
+ std::streampos dataSize = 0;
+ if(!mCacheHandler->LoadFontDataFromFile(fontPath, fontDataBuffer, dataSize))
+ {
+ fontDataBuffer.Clear();
+ FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "Failed to load font data : %s\n", fontPath.c_str());
+ return;
+ }
+
+ // Cache font data
+ mCacheHandler->CacheFontData(fontPath, fontDataBuffer, dataSize);
+}
+
+void FontClient::Plugin::CacheFontFaceFromFile(const std::string& fontPath) const
+{
+ if(fontPath.empty())
+ {
+ return;
+ }
+
+ if(mCacheHandler->FindFontFace(fontPath))
+ {
+ // Font face is already cached, no need to reload
+ return;
+ }
+
+ FT_Face ftFace;
+ int error = FT_New_Face(mFreeTypeLibrary, fontPath.c_str(), 0, &ftFace);
+ if(FT_Err_Ok != error)
+ {
+ FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "Failed to load font face : %s\n", fontPath.c_str());
+ return;
+ }
+
+ // Cache font face
+ mCacheHandler->CacheFontFace(fontPath, ftFace);
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "PreLoad font new face : %s\n", fontPath.c_str());
+}
+
+void FontClient::Plugin::FontPreLoad(const FontPathList& fontPathList, const FontPathList& memoryFontPathList) const
+{
+ for(const auto& fontPath : fontPathList)
+ {
+ CacheFontFaceFromFile(fontPath);
+ }
+
+ for(const auto& memoryFontPath : memoryFontPathList)
+ {
+ CacheFontDataFromFile(memoryFontPath);
+ }
+}
+
void FontClient::Plugin::FontPreCache(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily) const
{
mCacheHandler->InitDefaultFontDescription();
}
}
+void FontClient::Plugin::InitDefaultFontDescription() const
+{
+ mCacheHandler->InitDefaultFontDescription();
+}
+
void FontClient::Plugin::GetDefaultPlatformFontDescription(FontDescription& fontDescription) const
{
DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
uint32_t FontClient::Plugin::GetNumberOfPointsPerOneUnitOfPointSize() const
{
return TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
- ;
}
FontId FontClient::Plugin::CreateFont(const FontPath& path,
DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_CREATE_FONT");
- FontId fontId = 0u;
-#if defined(TRACE_ENABLED)
- if(gTraceFilter && gTraceFilter->IsTraceEnabled())
+ FontId fontId = 0u;
+ FT_Face ftFace;
+ FT_Error error;
+
+ uint8_t* fontDataPtr = nullptr;
+ std::streampos dataSize = 0;
+ bool fontDataFound = mCacheHandler->FindFontData(path, fontDataPtr, dataSize);
+
+ if(fontDataFound)
{
- DALI_LOG_DEBUG_INFO("DALI_TEXT_CREATE_FONT : FT_New_Face : %s\n", path.c_str());
+ // Create & cache new font face from pre-loaded font
+ error = FT_New_Memory_Face(mFreeTypeLibrary, reinterpret_cast<FT_Byte*>(fontDataPtr), static_cast<FT_Long>(dataSize), 0, &ftFace);
+#if defined(TRACE_ENABLED)
+ if(gTraceFilter && gTraceFilter->IsTraceEnabled())
+ {
+ DALI_LOG_DEBUG_INFO("DALI_TEXT_CREATE_FONT : FT_New_Memory_Face : %s\n", path.c_str());
+ }
+#endif
}
+ else
+ {
+ // Create & cache new font face
+ error = FT_New_Face(mFreeTypeLibrary, path.c_str(), 0, &ftFace);
+#if defined(TRACE_ENABLED)
+ if(gTraceFilter && gTraceFilter->IsTraceEnabled())
+ {
+ DALI_LOG_DEBUG_INFO("DALI_TEXT_CREATE_FONT : FT_New_Face : %s\n", path.c_str());
+ }
#endif
-
- // Create & cache new font face
- FT_Face ftFace;
- int error = FT_New_Face(mFreeTypeLibrary,
- path.c_str(),
- 0,
- &ftFace);
+ }
if(FT_Err_Ok == error)
{
#define DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_PLUGIN_IMPL_H
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
void ResetSystemDefaults() const;
/**
+ * @copydoc Dali::TextAbstraction::FontClient::InitDefaultFontDescription()
+ */
+ void InitDefaultFontDescription() const;
+
+ /**
* @copydoc Dali::TextAbstraction::FontClient::GetDefaultPlatformFontDescription()
*/
void GetDefaultPlatformFontDescription(FontDescription& fontDescription) const;
*/
void FontPreCache(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily) const;
+ /**
+ * @copydoc Dali::TextAbstraction::Internal::FontClient::FontPreLoad()
+ */
+ void FontPreLoad(const FontPathList& fontPathList, const FontPathList& memoryFontPathList) const;
+
private:
/**
* Get the cached font item for the given font
FaceIndex faceIndex,
bool cacheDescription) const;
+
+ /**
+ * @brief Caches font data for the specified font path if it is not already cached.
+ *
+ * If the font data is not already cached, this function will load the font file
+ * from disk and cache the data for future use.
+ *
+ * @param[in] fontPath The font path to cache the data for.
+ */
+ void CacheFontDataFromFile(const std::string& fontPath) const;
+
+ /**
+ * @brief Caches FreeType face for the specified font path if it is not already cached.
+ *
+ * If the font face is not already cached, this function will perform the new face
+ * from font file and cache the face for future use.
+ *
+ * @param[in] fontPath The font path to cache the face for.
+ */
+ void CacheFontFaceFromFile(const std::string& fontPath) const;
+
private:
Plugin(const Plugin&) = delete;
Plugin& operator=(const Plugin&) = delete;