#include <dali/internal/text/text-abstraction/font-client-impl.h>
// EXTERNAL INCLUDES
+#include <condition_variable>
+#include <mutex>
#include <thread>
#if defined(VCONF_ENABLED)
#include <vconf.h>
#endif
// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/thread-settings.h>
#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/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;
+std::condition_variable gPreCacheCond;
+std::condition_variable gPreLoadCond;
+bool gPreCacheThreadReady;
+bool gPreLoadThreadReady;
+
/* 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)
+void FontClient::PreCacheRun(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily, bool syncCreation)
{
- if(gFontPreCacheAvailable)
+ SetThreadName("FontThread-fc");
+
+ if(syncCreation)
{
- 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");
+ std::unique_lock<std::mutex> lock(gMutex);
+ gPreCacheThreadReady = true;
+ gPreCacheCond.notify_one();
+ lock.unlock();
}
- else
+
+ 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, bool syncCreation)
+{
+ SetThreadName("FontThread-ft");
+
+ if(syncCreation)
{
- FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "FontClient pre-cache run failed, as a pre-cached font client already exists.\n");
+ std::unique_lock<std::mutex> lock(gMutex);
+ gPreLoadThreadReady = true;
+ gPreLoadCond.notify_one();
+ lock.unlock();
}
+
+ 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)
+void FontClient::PreCache(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily, bool useThread, bool syncCreation)
{
if(!gFontPreCacheAvailable)
{
- 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 pre-cache run failed, as a pre-cached 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(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)
+ {
+ if(syncCreation)
+ {
+ // The main thread wakes up upon receiving a notification from the pre-cache thread.
+ // If it doesn't receive a notification within the specified time, it wakes up due to a timeout.
+ const std::chrono::milliseconds timeout(1000);
+ gPreCacheThreadReady = false;
+ std::unique_lock<std::mutex> lock(gMutex);
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "BEGIN: DALI_TEXT_PRECACHE_THREAD_SYNC_CREATION\n");
+ gPreCacheThread = std::thread(PreCacheRun, fallbackFamilyList, extraFamilyList, localeFamily, syncCreation);
+ gPreCacheCond.wait_for(lock, timeout, []{return gPreCacheThreadReady;});
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "END: DALI_TEXT_PRECACHE_THREAD_SYNC_CREATION\n");
+ }
+ else
+ {
+ gPreCacheThread = std::thread(PreCacheRun, fallbackFamilyList, extraFamilyList, localeFamily, syncCreation);
+ }
+ }
else
{
- if(useThread)
+ GetImplementation(gPreCreatedFontClient).FontPreCache(fallbackFamilyList, extraFamilyList, localeFamily);
+ }
+}
+
+void FontClient::PreLoad(const FontPathList& fontPathList, const FontPathList& memoryFontPathList, bool useThread, bool syncCreation)
+{
+ if(!gFontPreLoadAvailable)
+ {
+ FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "FontClient font pre-load run failed, as a pre-loaded font client already exists.\n");
+ return;
+ }
+
+ if(gPreLoadThread.joinable())
+ {
+ FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "FontClient font pre-load thread already running.\n");
+ return;
+ }
+
+ if(!gPreCreatedFontClient)
+ {
+ 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)
+ {
+ if(syncCreation)
{
- gPreCacheThread = std::thread(PreCacheRun, fallbackFamilyList, extraFamilyList, localeFamily);
+ // The main thread wakes up upon receiving a notification from the pre-load thread.
+ // If it doesn't receive a notification within the specified time, it wakes up due to a timeout.
+ const std::chrono::milliseconds timeout(1000);
+ gPreLoadThreadReady = false;
+ std::unique_lock<std::mutex> lock(gMutex);
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "BEGIN: DALI_TEXT_FONT_PRELOAD_THREAD_SYNC_CREATION\n");
+ gPreLoadThread = std::thread(PreLoadRun, fontPathList, memoryFontPathList, syncCreation);
+ gPreLoadCond.wait_for(lock, timeout, []{return gPreLoadThreadReady;});
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "END: DALI_TEXT_FONT_PRELOAD_THREAD_SYNC_CREATION\n");
}
else
{
- PreCacheRun(fallbackFamilyList, extraFamilyList, localeFamily);
+ gPreLoadThread = std::thread(PreLoadRun, fontPathList, memoryFontPathList, syncCreation);
}
}
+ else
+ {
+ GetImplementation(gPreCreatedFontClient).FontPreLoad(fontPathList, memoryFontPathList);
+ }
}
void FontClient::ClearCache()
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);