[Tizen] Add support for FontClientFontPreLoad API
[platform/core/uifw/dali-adaptor.git] / dali / internal / text / text-abstraction / plugin / font-client-plugin-cache-handler.cpp
index acaec1d..c248787 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.
 
 // EXTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
+#include <dali/integration-api/trace.h>
 #include <fontconfig/fontconfig.h>
 
 // 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;
 
@@ -61,6 +81,31 @@ extern Dali::Integration::Log::Filter* gFontClientLogFilter;
 
 namespace
 {
+
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_FONT_PERFORMANCE_MARKER, false);
+
+/**
+ * @brief Maximum size of glyph cache per each font face.
+ */
+constexpr std::size_t DEFAULT_GLYPH_CACHE_MAX         = 128;
+constexpr std::size_t MINIMUM_SIZE_OF_GLYPH_CACHE_MAX = 3u;
+
+constexpr auto MAX_NUMBER_OF_GLYPH_CACHE_ENV = "DALI_GLYPH_CACHE_MAX";
+
+/**
+ * @brief Get maximum size of glyph cache size from environment.
+ * If not settuped, default as 128.
+ * @note This value fixed when we call it first time.
+ * @return The max size of glyph cache.
+ */
+inline size_t GetMaxNumberOfGlyphCache()
+{
+  using Dali::EnvironmentVariable::GetEnvironmentVariable;
+  static auto numberString = GetEnvironmentVariable(MAX_NUMBER_OF_GLYPH_CACHE_ENV);
+  static auto number       = numberString ? std::strtoul(numberString, nullptr, 10) : DEFAULT_GLYPH_CACHE_MAX;
+  return (number < MINIMUM_SIZE_OF_GLYPH_CACHE_MAX) ? MINIMUM_SIZE_OF_GLYPH_CACHE_MAX : number;
+}
+
 } // namespace
 
 namespace Dali::TextAbstraction::Internal
@@ -247,8 +292,11 @@ FontClient::Plugin::CacheHandler::CacheHandler()
   mFontDescriptionCache(),
   mCharacterSetCache(),
   mFontDescriptionSizeCache(),
+  mFontDataCache(),
+  mFontFTFaceCache(),
   mEllipsisCache(),
   mEmbeddedItemCache(),
+  mGlyphCacheManager(new GlyphCacheManager(GetMaxNumberOfGlyphCache())),
   mLatestFoundFontDescription(),
   mLatestFoundFontDescriptionId(0u),
   mLatestFoundCacheKey(0, 0),
@@ -264,6 +312,9 @@ FontClient::Plugin::CacheHandler::~CacheHandler()
 
 void FontClient::Plugin::CacheHandler::ClearCache()
 {
+  // delete cached glyph informations before clear mFontFaceCache.
+  mGlyphCacheManager->ClearCache();
+
   mDefaultFontDescription = FontDescription();
 
   mSystemFonts.clear();
@@ -289,6 +340,13 @@ void FontClient::Plugin::CacheHandler::ClearCache()
   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();
@@ -384,6 +442,14 @@ void FontClient::Plugin::CacheHandler::CreateCharacterSet()
   }
 }
 
+void FontClient::Plugin::CacheHandler::ClearFTFaceFromFontFTFaceCache()
+{
+  for(auto& item : mFontFTFaceCache)
+  {
+    FT_Done_Face(item.second);
+  }
+}
+
 // System / Default
 
 void FontClient::Plugin::CacheHandler::InitSystemFonts()
@@ -451,6 +517,8 @@ void FontClient::Plugin::CacheHandler::InitDefaultFontDescription()
 {
   if(!mDefaultFontDescriptionCached)
   {
+    mDefaultFontDescriptionCached = true;
+
     // Clear any font config stored info in the caches.
     ClearCharacterSet();
 
@@ -479,7 +547,7 @@ void FontClient::Plugin::CacheHandler::InitDefaultFontDescription()
         mFontDescriptionCache.push_back(tempFontDescription);
 
         // Set the index to the vector of paths to font file names.
-        const FontDescriptionId fontDescriptionId = mFontDescriptionCache.size();
+        const FontDescriptionId fontDescriptionId = static_cast<FontDescriptionId>(mFontDescriptionCache.size());
 
         FONT_LOG_DESCRIPTION(tempFontDescription, "default platform font");
         DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  default font fontDescriptionId : %d\n", fontDescriptionId);
@@ -503,9 +571,65 @@ void FontClient::Plugin::CacheHandler::InitDefaultFontDescription()
 
     // 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
@@ -514,7 +638,7 @@ bool FontClient::Plugin::CacheHandler::FindValidatedFont(const FontDescription&
                                                          FontDescriptionId&     fontDescriptionId)
 {
   DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
-  DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "  number of validated fonts in the cache : %d\n", mValidatedFontCache.size());
+  DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "  number of validated fonts in the cache : %zu\n", mValidatedFontCache.size());
 
   fontDescriptionId = 0u;
 
@@ -564,6 +688,8 @@ void FontClient::Plugin::CacheHandler::ValidateFont(const FontDescription& fontD
   DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
   FONT_LOG_DESCRIPTION(fontDescription, "");
 
+  DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_VALIDATE_FONT");
+
   // Create a font pattern.
   FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription);
 
@@ -575,12 +701,19 @@ void FontClient::Plugin::CacheHandler::ValidateFont(const FontDescription& fontD
 
   if(matched && (nullptr != characterSet))
   {
+    #if defined(TRACE_ENABLED)
+    if(gTraceFilter && gTraceFilter->IsTraceEnabled())
+    {
+      DALI_LOG_DEBUG_INFO("DALI_TEXT_VALIDATE_FONT : FcFontMatch : %s, style : %s, %s, %s\n", fontDescription.family.c_str(), FontWidth::Name[fontDescription.width], FontWeight::Name[fontDescription.weight], FontSlant::Name[fontDescription.slant]);
+    }
+    #endif
+
     // Add the path to the cache.
     description.type = FontDescription::FACE_FONT;
     mFontDescriptionCache.push_back(description);
 
     // Set the index to the vector of paths to font file names.
-    fontDescriptionId = mFontDescriptionCache.size();
+    fontDescriptionId = static_cast<FontDescriptionId>(mFontDescriptionCache.size());
 
     FONT_LOG_DESCRIPTION(description, "matched");
     DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  fontDescriptionId : %d\n", fontDescriptionId);
@@ -619,7 +752,7 @@ bool FontClient::Plugin::CacheHandler::FindFallbackFontList(const FontDescriptio
                                                             CharacterSetList*&     characterSetList) const
 {
   DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
-  DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "  number of fallback font lists in the cache : %d\n", mFallbackCache.size());
+  DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "  number of fallback font lists in the cache : %zu\n", mFallbackCache.size());
 
   fontList = nullptr;
 
@@ -649,6 +782,15 @@ void FontClient::Plugin::CacheHandler::CacheFallbackFontList(FontDescription&&
 {
   DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
 
+  DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_FALLBACK_FONTLIST");
+
+  #if defined(TRACE_ENABLED)
+  if(gTraceFilter && gTraceFilter->IsTraceEnabled())
+  {
+    DALI_LOG_DEBUG_INFO("DALI_TEXT_FALLBACK_FONTLIST : FcFontSort : %s\n", fontDescription.family.c_str());
+  }
+  #endif
+
   fontList         = new FontList;
   characterSetList = new CharacterSetList;
 
@@ -683,7 +825,7 @@ bool FontClient::Plugin::CacheHandler::FindFontByPath(const FontPath& path,
   DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
   DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "                path : [%s]\n", path.c_str());
   DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize);
-  DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "  number of fonts in the cache : %d\n", mFontFaceCache.size());
+  DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "  number of fonts in the cache : %zu\n", mFontFaceCache.size());
 
   fontId = 0u;
   for(const auto& cacheItem : mFontFaceCache)
@@ -800,7 +942,7 @@ void FontClient::Plugin::CacheHandler::CacheFontPath(FT_Face ftFace, FontId font
     mFontDescriptionCache.push_back(description);
 
     // Set the index to the vector of paths to font file names.
-    fontDescriptionId = mFontDescriptionCache.size();
+    fontDescriptionId = static_cast<FontDescriptionId>(mFontDescriptionCache.size());
 
     // Increase the reference counter and add the character set to the cache.
     mCharacterSetCache.PushBack(FcCharSetCopy(characterSet));
@@ -816,21 +958,21 @@ void FontClient::Plugin::CacheHandler::CacheFontPath(FT_Face ftFace, FontId font
 FontId FontClient::Plugin::CacheHandler::CacheFontFaceCacheItem(FontFaceCacheItem&& fontFaceCacheItem)
 {
   // Set the index to the font's id cache.
-  fontFaceCacheItem.mFontId = mFontIdCache.size();
+  fontFaceCacheItem.mFontId = static_cast<FontId>(mFontIdCache.size());
 
   // Create the font id item to cache.
   FontIdCacheItem fontIdCacheItem;
   fontIdCacheItem.type = FontDescription::FACE_FONT;
 
   // Set the index to the FreeType font face cache.
-  fontIdCacheItem.index = mFontFaceCache.size();
+  fontIdCacheItem.index = static_cast<FontCacheIndex>(mFontFaceCache.size());
 
   // Cache the items.
   mFontFaceCache.emplace_back(std::move(fontFaceCacheItem));
   mFontIdCache.emplace_back(std::move(fontIdCacheItem));
 
   // Set the font id to be returned.
-  FontId fontId = mFontIdCache.size();
+  FontId fontId = static_cast<FontId>(mFontIdCache.size());
 
   return fontId;
 }
@@ -861,7 +1003,7 @@ bool FontClient::Plugin::CacheHandler::FindEllipsis(PointSize26Dot6 requestedPoi
 
 FontClient::Plugin::CacheHandler::EllipsisCacheIndex FontClient::Plugin::CacheHandler::CacheEllipsis(EllipsisItem&& ellipsisItem)
 {
-  EllipsisCacheIndex ellipsisCacheIndex = mEllipsisCache.size();
+  EllipsisCacheIndex ellipsisCacheIndex = static_cast<EllipsisCacheIndex>(mEllipsisCache.size());
 
   mEllipsisCache.emplace_back(std::move(ellipsisItem));
 
@@ -889,21 +1031,21 @@ bool FontClient::Plugin::CacheHandler::FindBitmapFont(const FontFamily& bitmapFo
 FontId FontClient::Plugin::CacheHandler::CacheBitmapFontCacheItem(BitmapFontCacheItem&& bitmapFontCacheItem)
 {
   // Set the index to the font's id cache.
-  bitmapFontCacheItem.id = mFontIdCache.size();
+  bitmapFontCacheItem.id = static_cast<FontId>(mFontIdCache.size());
 
   // Create the font id item to cache.
   CacheHandler::FontIdCacheItem fontIdCacheItem;
   fontIdCacheItem.type = FontDescription::BITMAP_FONT;
 
   // Set the index to the Bitmap font face cache.
-  fontIdCacheItem.index = mBitmapFontCache.size();
+  fontIdCacheItem.index = static_cast<FontCacheIndex>(mBitmapFontCache.size());
 
   // Cache the items.
   mBitmapFontCache.emplace_back(std::move(bitmapFontCacheItem));
   mFontIdCache.emplace_back(std::move(fontIdCacheItem));
 
   // Set the font id to be returned.
-  FontId fontId = mFontIdCache.size();
+  FontId fontId = static_cast<FontId>(mFontIdCache.size());
 
   return fontId;
 }
@@ -939,13 +1081,13 @@ PixelBufferId FontClient::Plugin::CacheHandler::CacheEmbeddedPixelBuffer(const s
     PixelBufferCacheItem pixelBufferCacheItem;
     pixelBufferCacheItem.pixelBuffer = pixelBuffer;
     pixelBufferCacheItem.url         = url;
-    pixelBufferCacheItem.id          = mPixelBufferCache.size() + 1u;
+    pixelBufferCacheItem.id          = static_cast<PixelBufferId>(mPixelBufferCache.size() + 1u);
 
     // Store the cache item in the cache.
     mPixelBufferCache.emplace_back(std::move(pixelBufferCacheItem));
 
     // Set the pixel buffer id to be returned.
-    pixelBufferId = mPixelBufferCache.size();
+    pixelBufferId = static_cast<PixelBufferId>(mPixelBufferCache.size());
   }
   return pixelBufferId;
 }
@@ -970,13 +1112,13 @@ bool FontClient::Plugin::CacheHandler::FindEmbeddedItem(PixelBufferId pixelBuffe
 
 GlyphIndex FontClient::Plugin::CacheHandler::CacheEmbeddedItem(EmbeddedItem&& embeddedItem)
 {
-  embeddedItem.index = mEmbeddedItemCache.size() + 1u;
+  embeddedItem.index = static_cast<GlyphIndex>(mEmbeddedItemCache.size() + 1u);
 
   // Cache the embedded item.
   mEmbeddedItemCache.emplace_back(std::move(embeddedItem));
 
   // Set the font id to be returned.
-  GlyphIndex index = mEmbeddedItemCache.size();
+  GlyphIndex index = static_cast<GlyphIndex>(mEmbeddedItemCache.size());
 
   return index;
 }