#include <dali/internal/text/text-abstraction/font-client-impl.h>
// EXTERNAL INCLUDES
+#include <thread>
#if defined(VCONF_ENABLED)
#include <vconf.h>
#endif
// INTERNAL INCLUDES
#include <dali/devel-api/common/singleton-service.h>
+#include <dali/internal/system/common/logging.h>
#include <dali/internal/text/text-abstraction/plugin/font-client-plugin-impl.h>
#include <dali/internal/window-system/common/window-system.h>
#include <dali/devel-api/text-abstraction/glyph-info.h>
+#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)
+
namespace Dali
{
namespace TextAbstraction
namespace Internal
{
Dali::TextAbstraction::FontClient FontClient::gPreInitializedFontClient(NULL);
+Dali::TextAbstraction::FontClient FontClient::gPreCachedFontClient(NULL);
+std::thread gPreCacheThread;
+/* 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;
FontClient::FontClient()
: mPlugin(nullptr),
}
else // create and register the object
{
+ if(gPreCacheThread.joinable())
+ {
+ gPreCacheThread.join();
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient PreCache thread join\n");
+ }
+
if(gPreInitializedFontClient)
{
fontClientHandle = gPreInitializedFontClient;
gPreInitializedFontClient.Reset(); // No longer needed
}
+ else if(gPreCachedFontClient)
+ {
+ // TODO: Currently font pre-caching is not available in the candidate process.
+ fontClientHandle = gPreCachedFontClient;
+ gPreCachedFontClient.Reset(); // No longer needed
+ }
else
{
fontClientHandle = Dali::TextAbstraction::FontClient(new FontClient);
}
+ gFontPreCacheAvailable = false;
+
uint32_t horizontalDpi, verticalDpi;
fontClientHandle.GetDpi(horizontalDpi, verticalDpi);
if(horizontalDpi == 0u || verticalDpi == 0u)
return gPreInitializedFontClient;
}
+void FontClient::PreCacheRun(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily)
+{
+ if(!gPreCachedFontClient)
+ {
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "BEGIN: DALI_TEXT_PRECACHE_RUN\n");
+ Dali::TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient(new FontClient);
+ GetImplementation(fontClient).FontPreCache(fallbackFamilyList, extraFamilyList, localeFamily);
+ gPreCachedFontClient = fontClient;
+ gFontPreCacheAvailable = false;
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "END: DALI_TEXT_PRECACHE_RUN\n");
+ }
+ else
+ {
+ FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "FontClient pre-cache run failed, as a pre-cached font client already exists.\n");
+ }
+}
+
+void FontClient::PreCache(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily, bool useThread)
+{
+ if(!gFontPreCacheAvailable)
+ {
+ FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "FontClient pre-cache has been completed or the font client has already been created.\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(gPreCacheThread.joinable())
+ {
+ FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "FontClient pre-cache thread already running.\n");
+ }
+ else
+ {
+ if(useThread)
+ {
+ gPreCacheThread = std::thread(PreCacheRun, fallbackFamilyList, extraFamilyList, localeFamily);
+ }
+ else
+ {
+ PreCacheRun(fallbackFamilyList, extraFamilyList, localeFamily);
+ }
+ }
+}
+
void FontClient::ClearCache()
{
if(mPlugin)
mPlugin->GetDefaultFonts(defaultFonts);
}
+void FontClient::FontPreCache(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily)
+{
+ CreatePlugin();
+
+ mPlugin->FontPreCache(fallbackFamilyList, extraFamilyList, localeFamily);
+}
+
void FontClient::GetDefaultPlatformFontDescription(FontDescription& fontDescription)
{
CreatePlugin();
static Dali::TextAbstraction::FontClient PreInitialize();
/**
+ * @brief This is used to pre-cache fonts 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);
+
+ /**
+ * @brief This is used to creates a global font client and pre-caches the fonts.
+ */
+ static void PreCacheRun(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily);
+
+ /**
* @copydoc Dali::TextAbstraction::FontClient::ClearCache()
*/
void ClearCache();
*/
HarfBuzzFontHandle GetHarfBuzzFont(FontId fontId);
+ /**
+ * @brief This is used to pre-cache fonts 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.
+ * @param[in] localeFamily A locale font family to be pre-cached.
+ */
+ void FontPreCache(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily);
+
private:
/**
* Helper for lazy initialization.
unsigned int mDpiVertical;
static Dali::TextAbstraction::FontClient gPreInitializedFontClient;
+ static Dali::TextAbstraction::FontClient gPreCachedFontClient;
}; // class FontClient
mCacheHandler->ResetSystemDefaults();
}
+void FontClient::Plugin::FontPreCache(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily) const
+{
+ mCacheHandler->InitDefaultFontDescription();
+
+ FontFamilyList familyList;
+ familyList.reserve(extraFamilyList.size() + 1);
+
+ for (const auto& fallbackFont : fallbackFamilyList)
+ {
+ FontList* fontList = nullptr;
+ CharacterSetList* characterSetList = nullptr;
+ FontDescriptionId fontDescriptionId = 0u;
+ FontDescription fontDescription;
+ fontDescription.family = FontFamily(fallbackFont);
+ fontDescription.weight = DefaultFontWeight();
+ fontDescription.width = DefaultFontWidth();
+ fontDescription.slant = DefaultFontSlant();
+
+ if(!mCacheHandler->FindFallbackFontList(fontDescription, fontList, characterSetList))
+ {
+ mCacheHandler->CacheFallbackFontList(std::move(fontDescription), fontList, characterSetList);
+ }
+ if(!mCacheHandler->FindValidatedFont(fontDescription, fontDescriptionId))
+ {
+ mCacheHandler->ValidateFont(fontDescription, fontDescriptionId);
+ }
+
+ if(extraFamilyList.empty() && localeFamily.empty())
+ {
+ continue;
+ }
+
+ familyList.clear();
+ familyList.insert(familyList.end(), extraFamilyList.begin(), extraFamilyList.end());
+ if(!localeFamily.empty())
+ {
+ familyList.push_back(localeFamily);
+ }
+
+ for(const auto& font : *fontList)
+ {
+ auto it = std::find(familyList.begin(), familyList.end(), font.family);
+ if(it != familyList.end())
+ {
+ if(!mCacheHandler->FindValidatedFont(font, fontDescriptionId))
+ {
+ mCacheHandler->ValidateFont(font, fontDescriptionId);
+ }
+ familyList.erase(it);
+ }
+ }
+ }
+}
+
void FontClient::Plugin::GetDefaultPlatformFontDescription(FontDescription& fontDescription) const
{
DALI_LOG_TRACE_METHOD(gFontClientLogFilter);