[Tizen] Add support for FontClientFontPreLoad API
[platform/core/uifw/dali-adaptor.git] / dali / internal / text / text-abstraction / plugin / font-client-plugin-impl.cpp
index f119b5e..78448d9 100644 (file)
 // INTERNAL INCLUDES
 #include <dali/devel-api/text-abstraction/font-list.h>
 #include <dali/integration-api/debug.h>
+#include <dali/integration-api/trace.h>
 #include <dali/integration-api/platform-abstraction.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"
@@ -75,6 +93,9 @@ Dali::Integration::Log::Filter* gFontClientLogFilter = Dali::Integration::Log::F
 
 namespace
 {
+
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_FONT_PERFORMANCE_MARKER, false);
+
 /**
  * Conversion from Fractional26.6 to float
  */
@@ -261,6 +282,131 @@ void FontClient::Plugin::ResetSystemDefaults() const
   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();
+
+  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))
+    {
+      FontDescription copiedFontDescription = fontDescription;
+      mCacheHandler->CacheFallbackFontList(std::move(copiedFontDescription), 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::InitDefaultFontDescription() const
+{
+  mCacheHandler->InitDefaultFontDescription();
+}
+
 void FontClient::Plugin::GetDefaultPlatformFontDescription(FontDescription& fontDescription) const
 {
   DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
@@ -482,6 +628,8 @@ FontId FontClient::Plugin::FindFallbackFont(Character              charcode,
   DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
   FONT_LOG_REQUEST(charcode, requestedPointSize, preferColor);
 
+  DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_FIND_FALLBACKFONT");
+
   // The font id to be returned.
   FontId fontId = 0u;
 
@@ -499,6 +647,13 @@ FontId FontClient::Plugin::FindFallbackFont(Character              charcode,
   DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "  [%s] --> [%s]\n", FontWidth::Name[preferredFontDescription.width], FontWidth::Name[fontDescription.width]);
   DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "  [%s] --> [%s]\n", FontSlant::Name[preferredFontDescription.slant], FontSlant::Name[fontDescription.slant]);
 
+  #if defined(TRACE_ENABLED)
+  if(gTraceFilter && gTraceFilter->IsTraceEnabled())
+  {
+    DALI_LOG_DEBUG_INFO("DALI_TEXT_FIND_FALLBACKFONT : %s -> %s\n", preferredFontDescription.family.c_str(), fontDescription.family.c_str());
+  }
+  #endif
+
   // Check first if the font's description has been queried before.
   FontList*         fontList         = nullptr;
   CharacterSetList* characterSetList = nullptr;
@@ -614,11 +769,14 @@ FontId FontClient::Plugin::GetFontId(const FontDescription& fontDescription,
     // So set cacheDescription=false, that we don't call CacheFontPath().
     fontId = GetFontIdByPath(description.path, requestedPointSize, faceIndex, false);
 
-    fontCacheIndex                                              = mCacheHandler->mFontIdCache[fontId - 1u].index;
-    mCacheHandler->mFontFaceCache[fontCacheIndex].mCharacterSet = FcCharSetCopy(mCacheHandler->mCharacterSetCache[fontDescriptionId - 1u]);
+    if((fontId > 0u) && (fontId - 1u < mCacheHandler->mFontIdCache.size()))
+    {
+      fontCacheIndex                                              = mCacheHandler->mFontIdCache[fontId - 1u].index;
+      mCacheHandler->mFontFaceCache[fontCacheIndex].mCharacterSet = FcCharSetCopy(mCacheHandler->mCharacterSetCache[fontDescriptionId - 1u]);
 
-    // Cache the pair 'fontDescriptionId, requestedPointSize' to improve the following queries.
-    mCacheHandler->CacheFontDescriptionSize(fontDescriptionId, requestedPointSize, fontCacheIndex);
+      // Cache the pair 'fontDescriptionId, requestedPointSize' to improve the following queries.
+      mCacheHandler->CacheFontDescriptionSize(fontDescriptionId, requestedPointSize, fontCacheIndex);
+    }
   }
   else
   {
@@ -1001,7 +1159,6 @@ bool FontClient::Plugin::SetCurrentMaximumBlockSizeFitInAtlas(const Size& curren
 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,
@@ -1013,14 +1170,38 @@ FontId FontClient::Plugin::CreateFont(const FontPath& path,
   DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "                path : [%s]\n", path.c_str());
   DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize);
 
-  FontId fontId = 0u;
+  DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_CREATE_FONT");
 
-  // Create & cache new font face
-  FT_Face ftFace;
-  int     error = FT_New_Face(mFreeTypeLibrary,
-                          path.c_str(),
-                          0,
-                          &ftFace);
+  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)
+  {
+    // 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
+  }
 
   if(FT_Err_Ok == error)
   {
@@ -1040,7 +1221,7 @@ FontId FontClient::Plugin::CreateFont(const FontPath& path,
       int             fixedSizeIndex  = 0;
       for(; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex)
       {
-        const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
+        const PointSize26Dot6 fixedSize = static_cast<PointSize26Dot6>(ftFace->available_sizes[fixedSizeIndex].size);
         DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "  size index : %d, size : %d\n", fixedSizeIndex, fixedSize);
 
         if(fixedSize >= requestedPointSize)
@@ -1054,7 +1235,7 @@ FontId FontClient::Plugin::CreateFont(const FontPath& path,
       {
         // The requested point size is bigger than the bigest fixed size.
         fixedSizeIndex  = ftFace->num_fixed_sizes - 1;
-        actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
+        actualPointSize = static_cast<PointSize26Dot6>(ftFace->available_sizes[fixedSizeIndex].size);
       }
 
       DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "  size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize);
@@ -1079,7 +1260,7 @@ FontId FontClient::Plugin::CreateFont(const FontPath& path,
         const float fixedHeight = static_cast<float>(ftFace->available_sizes[fixedSizeIndex].height);
 
         // Create the FreeType font face item to cache.
-        FontFaceCacheItem fontFaceCacheItem(mFreeTypeLibrary, ftFace, path, requestedPointSize, faceIndex, metrics, fixedSizeIndex, fixedWidth, fixedHeight, hasColorTables);
+        FontFaceCacheItem fontFaceCacheItem(mFreeTypeLibrary, ftFace, mCacheHandler->GetGlyphCacheManager(), path, requestedPointSize, faceIndex, metrics, fixedSizeIndex, fixedWidth, fixedHeight, hasColorTables);
 
         fontId = mCacheHandler->CacheFontFaceCacheItem(std::move(fontFaceCacheItem));
       }
@@ -1121,7 +1302,7 @@ FontId FontClient::Plugin::CreateFont(const FontPath& path,
                             static_cast<float>(ftFace->underline_thickness) * FROM_266);
 
         // Create the FreeType font face item to cache.
-        FontFaceCacheItem fontFaceCacheItem(mFreeTypeLibrary, ftFace, path, requestedPointSize, faceIndex, metrics);
+        FontFaceCacheItem fontFaceCacheItem(mFreeTypeLibrary, ftFace, mCacheHandler->GetGlyphCacheManager(), path, requestedPointSize, faceIndex, metrics);
 
         fontId = mCacheHandler->CacheFontFaceCacheItem(std::move(fontFaceCacheItem));
       }