Make GlyphCacheManager cache shared_ptr of GlyphCacheData 59/290359/2
authorEunki, Hong <eunkiki.hong@samsung.com>
Thu, 23 Mar 2023 14:03:58 +0000 (23:03 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Thu, 23 Mar 2023 14:38:31 +0000 (23:38 +0900)
Previously, font-face-glyph-cache-manager release GlyphCacheData by manager side.

Now, let we keep cache data by shared_ptr<GlyphCacheData>, and also get pointer,
not whole copy of data.

After this patch, we don't need to worry about glyph cache data's lifecycle.

Change-Id: Iceb58d78085f0415b679434cd5066ea93ab2859a
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
dali/internal/text/text-abstraction/plugin/font-face-cache-item.cpp
dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.cpp
dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.h
dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.cpp

index b0087f2..7c70411 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.
@@ -83,9 +83,9 @@ inline GlyphCacheManager::CompressionPolicyType GetRenderedGlyphCompressPolicy()
   using Dali::EnvironmentVariable::GetEnvironmentVariable;
   static auto policyString = GetEnvironmentVariable(RENDERED_GLYPH_COMPRESS_POLICY_ENV);
 
-  static auto policy = policyString ? policyString[0] == 's' || policyString[0] == 'S' ? GlyphCacheManager::CompressionPolicyType::SPEED
-                                                                                       : policyString[0] == 'm' || policyString[0] == 'M' ? GlyphCacheManager::CompressionPolicyType::MEMORY
-                                                                                                                                          : DEFAULT_RENDERED_GLYPH_COMPRESS_POLICY
+  static auto policy = policyString ? policyString[0] == 's' || policyString[0] == 'S'   ? GlyphCacheManager::CompressionPolicyType::SPEED
+                                      : policyString[0] == 'm' || policyString[0] == 'M' ? GlyphCacheManager::CompressionPolicyType::MEMORY
+                                                                                         : DEFAULT_RENDERED_GLYPH_COMPRESS_POLICY
                                     : DEFAULT_RENDERED_GLYPH_COMPRESS_POLICY;
   return policy;
 }
@@ -219,18 +219,20 @@ bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVe
 {
   bool success(true);
 
-  GlyphCacheManager::GlyphCacheData glyphData;
-  FT_Error                          error;
+  GlyphCacheManager::GlyphCacheDataPtr glyphDataPtr;
+  FT_Error                             error;
 
 #ifdef FREETYPE_BITMAP_SUPPORT
   // Check to see if we should be loading a Fixed Size bitmap?
   if(mIsFixedSizeBitmap)
   {
     FT_Select_Size(mFreeTypeFace, mFixedSizeIndex); ///< @todo: needs to be investigated why it's needed to select the size again.
-    mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphInfo.index, FT_LOAD_COLOR, glyphInfo.isBoldRequired, glyphData, error);
+    mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphInfo.index, FT_LOAD_COLOR, glyphInfo.isBoldRequired, glyphDataPtr, error);
 
     if(FT_Err_Ok == error)
     {
+      GlyphCacheManager::GlyphCacheData& glyphData = *glyphDataPtr.get();
+
       glyphInfo.width    = mFixedWidthPixels;
       glyphInfo.height   = mFixedHeightPixels;
       glyphInfo.advance  = mFixedWidthPixels;
@@ -285,7 +287,7 @@ bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVe
     // FT_LOAD_DEFAULT causes some issues in the alignment of the glyph inside the bitmap.
     // i.e. with the SNum-3R font.
     // @todo: add an option to use the FT_LOAD_DEFAULT if required?
-    mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphInfo.index, FT_LOAD_NO_AUTOHINT, glyphInfo.isBoldRequired, glyphData, error);
+    mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphInfo.index, FT_LOAD_NO_AUTOHINT, glyphInfo.isBoldRequired, glyphDataPtr, error);
 
     // Keep the width of the glyph before doing the software emboldening.
     // It will be used to calculate a scale factor to be applied to the
@@ -294,6 +296,8 @@ bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVe
 
     if(FT_Err_Ok == error)
     {
+      GlyphCacheManager::GlyphCacheData& glyphData = *glyphDataPtr.get();
+
       const auto& metrics = glyphData.mGlyphMetrics;
 
       glyphInfo.width  = static_cast<float>(metrics.width) * FROM_266;
@@ -313,12 +317,12 @@ bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVe
       if(isEmboldeningRequired)
       {
         // Get dummy glyph data without embolden.
-        GlyphCacheManager::GlyphCacheData dummyData;
-        if(mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphInfo.index, FT_LOAD_NO_AUTOHINT, false, dummyData, error))
+        GlyphCacheManager::GlyphCacheDataPtr dummyDataPtr;
+        if(mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphInfo.index, FT_LOAD_NO_AUTOHINT, false, dummyDataPtr, error))
         {
           // If the glyph is emboldened by software, the advance is multiplied by a
           // scale factor to make it slightly bigger.
-          const float width = static_cast<float>(dummyData.mGlyphMetrics.width) * FROM_266;
+          const float width = static_cast<float>(dummyDataPtr->mGlyphMetrics.width) * FROM_266;
           if(!EqualsZero(width))
           {
             glyphInfo.advance *= (glyphInfo.width / width);
@@ -359,9 +363,9 @@ bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVe
 void FontFaceCacheItem::CreateBitmap(
   GlyphIndex glyphIndex, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const
 {
-  GlyphCacheManager::GlyphCacheData glyphData;
-  FT_Error                          error;
-  FT_Int32                          loadFlag;
+  GlyphCacheManager::GlyphCacheDataPtr glyphDataPtr;
+  FT_Error                             error;
+  FT_Int32                             loadFlag;
   // For the software italics.
   bool isShearRequired = false;
 
@@ -379,10 +383,12 @@ void FontFaceCacheItem::CreateBitmap(
     // @todo: add an option to use the FT_LOAD_DEFAULT if required?
     loadFlag = FT_LOAD_NO_AUTOHINT;
   }
-  mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphIndex, loadFlag, isBoldRequired, glyphData, error);
+  mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphIndex, loadFlag, isBoldRequired, glyphDataPtr, error);
 
   if(FT_Err_Ok == error)
   {
+    GlyphCacheManager::GlyphCacheData& glyphData = *glyphDataPtr.get();
+
     if(isItalicRequired && !(glyphData.mStyleFlags & FT_STYLE_FLAG_ITALIC))
     {
       // Will do the software italic.
@@ -486,16 +492,16 @@ void FontFaceCacheItem::CreateBitmap(
           {
             mGlyphCacheManager->CacheRenderedGlyphBuffer(mFreeTypeFace, glyphIndex, loadFlag, isBoldRequired, bitmapGlyph->bitmap, GetRenderedGlyphCompressPolicy());
 
-            GlyphCacheManager::GlyphCacheData dummyData;
-            mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphIndex, loadFlag, isBoldRequired, dummyData, error);
+            GlyphCacheManager::GlyphCacheDataPtr dummyDataPtr;
+            mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphIndex, loadFlag, isBoldRequired, dummyDataPtr, error);
 
-            if(DALI_LIKELY(FT_Err_Ok == error && dummyData.mRenderedBuffer))
+            if(DALI_LIKELY(FT_Err_Ok == error && dummyDataPtr->mRenderedBuffer))
             {
-              data.buffer          = dummyData.mRenderedBuffer->buffer;
-              data.width           = dummyData.mRenderedBuffer->width;
-              data.height          = dummyData.mRenderedBuffer->height;
-              data.format          = dummyData.mRenderedBuffer->format;
-              data.compressionType = dummyData.mRenderedBuffer->compressionType;
+              data.buffer          = dummyDataPtr->mRenderedBuffer->buffer;
+              data.width           = dummyDataPtr->mRenderedBuffer->width;
+              data.height          = dummyDataPtr->mRenderedBuffer->height;
+              data.format          = dummyDataPtr->mRenderedBuffer->format;
+              data.compressionType = dummyDataPtr->mRenderedBuffer->compressionType;
               data.isBufferOwned   = false;
             }
             else
@@ -541,8 +547,8 @@ bool FontFaceCacheItem::IsColorGlyph(GlyphIndex glyphIndex) const
   // Check to see if this is fixed size bitmap
   if(mHasColorTables)
   {
-    GlyphCacheManager::GlyphCacheData dummyData;
-    mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphIndex, FT_LOAD_COLOR, false, dummyData, error);
+    GlyphCacheManager::GlyphCacheDataPtr dummyDataPtr;
+    mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphIndex, FT_LOAD_COLOR, false, dummyDataPtr, error);
   }
 #endif
   return FT_Err_Ok == error;
index 097e9cd..96817db 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.
@@ -49,12 +49,12 @@ GlyphCacheManager::~GlyphCacheManager()
 }
 
 bool GlyphCacheManager::GetGlyphCacheDataFromIndex(
-  const FT_Face    freeTypeFace,
-  const GlyphIndex index,
-  const FT_Int32   flag,
-  const bool       isBoldRequired,
-  GlyphCacheData&  glyphData,
-  FT_Error&        error)
+  const FT_Face      freeTypeFace,
+  const GlyphIndex   index,
+  const FT_Int32     flag,
+  const bool         isBoldRequired,
+  GlyphCacheDataPtr& glyphDataPtr,
+  FT_Error&          error)
 {
   // Append some error value here instead of FT_Err_Ok.
   error = static_cast<FT_Error>(-1);
@@ -69,17 +69,19 @@ bool GlyphCacheManager::GetGlyphCacheDataFromIndex(
     {
       auto removedData = mLRUGlyphCache.Pop();
 
-      DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Remove oldest cache for glyph : %p\n", removedData.mGlyph);
-
-      // Release Glyph data resource
-      removedData.ReleaseGlyphData();
+      DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Remove oldest cache for glyph : %p\n", removedData->mGlyph);
     }
 
+    // Create new GlyphCacheData.
+    glyphDataPtr = std::make_shared<GlyphCacheData>();
+
+    GlyphCacheData& glyphData = *glyphDataPtr.get();
+
     const bool loadSuccess = LoadGlyphDataFromIndex(freeTypeFace, index, flag, isBoldRequired, glyphData, error);
     if(loadSuccess)
     {
       // Copy and cached data.
-      mLRUGlyphCache.Push(key, glyphData);
+      mLRUGlyphCache.Push(key, glyphDataPtr);
 
       DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Create cache for face : %p, index : %u flag : %d isBold : %d isBitmap : %d, glyph : %p\n", freeTypeFace, index, static_cast<int>(flag), isBoldRequired, glyphData.mIsBitmap, glyphData.mGlyph);
     }
@@ -91,9 +93,9 @@ bool GlyphCacheManager::GetGlyphCacheDataFromIndex(
     error = FT_Err_Ok;
 
     // We already notify that we use this glyph. And now, copy cached data.
-    glyphData = mLRUGlyphCache.GetElement(iter);
+    glyphDataPtr = mLRUGlyphCache.GetElement(iter);
 
-    DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Find cache for face : %p, index : %u flag : %d isBold : %d isBitmap : %d, glyph : %p\n", freeTypeFace, index, static_cast<int>(flag), isBoldRequired, glyphData.mIsBitmap, glyphData.mGlyph);
+    DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Find cache for face : %p, index : %u flag : %d isBold : %d isBitmap : %d, glyph : %p\n", freeTypeFace, index, static_cast<int>(flag), isBoldRequired, glyphDataPtr->mIsBitmap, glyphDataPtr->mGlyph);
     return true;
   }
 }
@@ -201,37 +203,32 @@ void GlyphCacheManager::ResizeBitmapGlyph(
     // Skip this API if desired size is zero
     return;
   }
-  FT_Error       error;
-  GlyphCacheData originGlyphData;
-  if(GetGlyphCacheDataFromIndex(freeTypeFace, index, flag, isBoldRequired, originGlyphData, error))
+  FT_Error          error;
+  GlyphCacheDataPtr glyphDataPtr;
+  if(GetGlyphCacheDataFromIndex(freeTypeFace, index, flag, isBoldRequired, glyphDataPtr, error))
   {
-    if(DALI_LIKELY(originGlyphData.mIsBitmap && originGlyphData.mBitmap))
+    GlyphCacheData& glyphData = *glyphDataPtr.get();
+    if(DALI_LIKELY(glyphData.mIsBitmap && glyphData.mBitmap))
     {
-      const bool requiredResize = (originGlyphData.mBitmap->rows != desiredHeight) || (originGlyphData.mBitmap->width != desiredWidth);
+      const bool requiredResize = (glyphData.mBitmap->rows != desiredHeight) || (glyphData.mBitmap->width != desiredWidth);
       if(requiredResize)
       {
-        // originalGlyphData is copy data. For change cached information, we should access as iterator.
-        const GlyphCacheKey key  = GlyphCacheKey(freeTypeFace, index, flag, isBoldRequired);
-        auto                iter = mLRUGlyphCache.Find(key);
-
-        GlyphCacheData& destinationGlpyhData = mLRUGlyphCache.GetElement(iter);
-
-        const ImageDimensions inputDimensions(destinationGlpyhData.mBitmap->width, destinationGlpyhData.mBitmap->rows);
+        const ImageDimensions inputDimensions(glyphData.mBitmap->width, glyphData.mBitmap->rows);
         const ImageDimensions desiredDimensions(desiredWidth, desiredHeight);
 
         uint8_t* desiredBuffer = nullptr;
 
-        switch(destinationGlpyhData.mBitmap->pixel_mode)
+        switch(glyphData.mBitmap->pixel_mode)
         {
           case FT_PIXEL_MODE_GRAY:
           {
-            if(destinationGlpyhData.mBitmap->pitch == static_cast<int>(destinationGlpyhData.mBitmap->width))
+            if(glyphData.mBitmap->pitch == static_cast<int>(glyphData.mBitmap->width))
             {
               desiredBuffer = (uint8_t*)malloc(desiredWidth * desiredHeight * sizeof(uint8_t)); // @note The caller is responsible for deallocating the bitmap data using free.
               // Resize bitmap here.
-              Dali::Internal::Platform::LanczosSample1BPP(destinationGlpyhData.mBitmap->buffer,
+              Dali::Internal::Platform::LanczosSample1BPP(glyphData.mBitmap->buffer,
                                                           inputDimensions,
-                                                          destinationGlpyhData.mBitmap->width,
+                                                          glyphData.mBitmap->width,
                                                           desiredBuffer,
                                                           desiredDimensions);
             }
@@ -240,13 +237,13 @@ void GlyphCacheManager::ResizeBitmapGlyph(
 #ifdef FREETYPE_BITMAP_SUPPORT
           case FT_PIXEL_MODE_BGRA:
           {
-            if(destinationGlpyhData.mBitmap->pitch == static_cast<int>(destinationGlpyhData.mBitmap->width << 2u))
+            if(glyphData.mBitmap->pitch == static_cast<int>(glyphData.mBitmap->width << 2u))
             {
               desiredBuffer = (uint8_t*)malloc((desiredWidth * desiredHeight * sizeof(uint8_t)) << 2u); // @note The caller is responsible for deallocating the bitmap data using free.
               // Resize bitmap here.
-              Dali::Internal::Platform::LanczosSample4BPP(destinationGlpyhData.mBitmap->buffer,
+              Dali::Internal::Platform::LanczosSample4BPP(glyphData.mBitmap->buffer,
                                                           inputDimensions,
-                                                          destinationGlpyhData.mBitmap->width,
+                                                          glyphData.mBitmap->width,
                                                           desiredBuffer,
                                                           desiredDimensions);
             }
@@ -264,23 +261,23 @@ void GlyphCacheManager::ResizeBitmapGlyph(
         {
           // Success to resize bitmap glyph.
           // Release origin bitmap buffer.
-          free(destinationGlpyhData.mBitmap->buffer);
+          free(glyphData.mBitmap->buffer);
 
           // Replace as desired buffer and size.
-          destinationGlpyhData.mBitmap->buffer = desiredBuffer;
-          destinationGlpyhData.mBitmap->width  = desiredWidth;
-          destinationGlpyhData.mBitmap->rows   = desiredHeight;
-          switch(destinationGlpyhData.mBitmap->pixel_mode)
+          glyphData.mBitmap->buffer = desiredBuffer;
+          glyphData.mBitmap->width  = desiredWidth;
+          glyphData.mBitmap->rows   = desiredHeight;
+          switch(glyphData.mBitmap->pixel_mode)
           {
             case FT_PIXEL_MODE_GRAY:
             {
-              destinationGlpyhData.mBitmap->pitch = desiredWidth;
+              glyphData.mBitmap->pitch = desiredWidth;
               break;
             }
 #ifdef FREETYPE_BITMAP_SUPPORT
             case FT_PIXEL_MODE_BGRA:
             {
-              destinationGlpyhData.mBitmap->pitch = desiredWidth << 2u;
+              glyphData.mBitmap->pitch = desiredWidth << 2u;
               break;
             }
 #endif
@@ -304,26 +301,21 @@ void GlyphCacheManager::CacheRenderedGlyphBuffer(
     // Skip this API if rendered bitmap size is zero
     return;
   }
-  FT_Error       error;
-  GlyphCacheData originGlyphData;
-  if(GetGlyphCacheDataFromIndex(freeTypeFace, index, flag, isBoldRequired, originGlyphData, error))
+  FT_Error          error;
+  GlyphCacheDataPtr glyphDataPtr;
+  if(GetGlyphCacheDataFromIndex(freeTypeFace, index, flag, isBoldRequired, glyphDataPtr, error))
   {
-    if(DALI_LIKELY(!originGlyphData.mIsBitmap && originGlyphData.mRenderedBuffer == nullptr))
+    GlyphCacheData& glyphData = *glyphDataPtr.get();
+    if(DALI_LIKELY(!glyphData.mIsBitmap && glyphData.mRenderedBuffer == nullptr))
     {
-      // originalGlyphData is copy data. For change cached information, we should access as iterator.
-      const GlyphCacheKey key  = GlyphCacheKey(freeTypeFace, index, flag, isBoldRequired);
-      auto                iter = mLRUGlyphCache.Find(key);
-
-      GlyphCacheData& destinationGlpyhData = mLRUGlyphCache.GetElement(iter);
-
-      destinationGlpyhData.mRenderedBuffer = new TextAbstraction::GlyphBufferData();
-      if(DALI_UNLIKELY(!destinationGlpyhData.mRenderedBuffer))
+      glyphData.mRenderedBuffer = new TextAbstraction::GlyphBufferData();
+      if(DALI_UNLIKELY(!glyphData.mRenderedBuffer))
       {
         DALI_LOG_ERROR("Allocate GlyphBufferData failed\n");
         return;
       }
 
-      TextAbstraction::GlyphBufferData& renderBuffer = *destinationGlpyhData.mRenderedBuffer;
+      TextAbstraction::GlyphBufferData& renderBuffer = *glyphData.mRenderedBuffer;
 
       // Set basic informations.
       renderBuffer.width  = srcBitmap.width;
@@ -358,8 +350,8 @@ void GlyphCacheManager::CacheRenderedGlyphBuffer(
           {
             DALI_ASSERT_DEBUG(0 == "Compress failed at FT_PIXEL_MODE_GRAY");
             DALI_LOG_ERROR("Compress failed. Ignore cache\n");
-            delete destinationGlpyhData.mRenderedBuffer;
-            destinationGlpyhData.mRenderedBuffer = nullptr;
+            delete glyphData.mRenderedBuffer;
+            glyphData.mRenderedBuffer = nullptr;
             return;
           }
           break;
@@ -376,8 +368,8 @@ void GlyphCacheManager::CacheRenderedGlyphBuffer(
           {
             DALI_ASSERT_DEBUG(0 == "Compress failed at FT_PIXEL_MODE_BGRA");
             DALI_LOG_ERROR("Compress failed. Ignore cache\n");
-            delete destinationGlpyhData.mRenderedBuffer;
-            destinationGlpyhData.mRenderedBuffer = nullptr;
+            delete glyphData.mRenderedBuffer;
+            glyphData.mRenderedBuffer = nullptr;
             return;
           }
           break;
@@ -386,8 +378,8 @@ void GlyphCacheManager::CacheRenderedGlyphBuffer(
         default:
         {
           DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::GlyphCacheManager::CacheRenderedGlyphBuffer. FontClient Unable to create Bitmap of this PixelType\n");
-          delete destinationGlpyhData.mRenderedBuffer;
-          destinationGlpyhData.mRenderedBuffer = nullptr;
+          delete glyphData.mRenderedBuffer;
+          glyphData.mRenderedBuffer = nullptr;
           break;
         }
       }
@@ -422,15 +414,6 @@ void GlyphCacheManager::ClearCache(const std::size_t remainCount)
 {
   if(remainCount == 0u)
   {
-    // Release all data memory first.
-    auto endIter = mLRUGlyphCache.End();
-    for(auto iter = mLRUGlyphCache.Begin(); iter != endIter; ++iter)
-    {
-      // Get the reference of data. and release it.
-      auto& removedData = mLRUGlyphCache.GetElement(iter);
-      removedData.ReleaseGlyphData();
-    }
-
     // Clear all cache.
     mLRUGlyphCache.Clear();
   }
@@ -441,19 +424,19 @@ void GlyphCacheManager::ClearCache(const std::size_t remainCount)
     {
       auto removedData = mLRUGlyphCache.Pop();
 
-      DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::ClearCache[%zu / %zu]. Remove oldest cache for glyph : %p\n", mLRUGlyphCache.Count(), remainCount, removedData.mGlyph);
-
-      // Release Glyph data resource
-      removedData.ReleaseGlyphData();
+      DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::ClearCache[%zu / %zu]. Remove oldest cache for glyph : %p\n", mLRUGlyphCache.Count(), remainCount, removedData->mGlyph);
     }
   }
 }
 
+// GlyphCacheManager::GlyphCacheData
+
 void GlyphCacheManager::GlyphCacheData::ReleaseGlyphData()
 {
   if(mIsBitmap && mBitmap)
   {
     // Created FT_Bitmap object must be released with FT_Bitmap_Done
+    // But, this class's mBitmap it not an actual FT_Bitmap object. So free buffer is enough.
     free(mBitmap->buffer); // This buffer created by malloc
 
     delete mBitmap;
@@ -475,4 +458,73 @@ void GlyphCacheManager::GlyphCacheData::ReleaseGlyphData()
   mStyleFlags = 0;
 }
 
+GlyphCacheManager::GlyphCacheData::GlyphCacheData()
+: mGlyph{nullptr},
+  mGlyphMetrics{},
+  mStyleFlags{0},
+  mIsBitmap{false},
+  mRenderedBuffer{nullptr}
+{
+}
+
+GlyphCacheManager::GlyphCacheData::~GlyphCacheData()
+{
+  ReleaseGlyphData();
+}
+
+GlyphCacheManager::GlyphCacheData::GlyphCacheData(GlyphCacheData&& rhs) noexcept
+: mGlyph{nullptr},
+  mGlyphMetrics{},
+  mStyleFlags{0},
+  mIsBitmap{false},
+  mRenderedBuffer{nullptr}
+{
+  *this = std::move(rhs);
+}
+
+GlyphCacheManager::GlyphCacheData& GlyphCacheManager::GlyphCacheData::operator=(GlyphCacheData&& rhs) noexcept
+{
+  // Self-assignment detection
+  if(this == &rhs)
+  {
+    return *this;
+  }
+
+  // Delete self data first.
+  ReleaseGlyphData();
+
+  mIsBitmap = false;
+
+  if(rhs.mIsBitmap && rhs.mBitmap)
+  {
+    mIsBitmap = true;
+    mBitmap   = rhs.mBitmap;
+
+    rhs.mBitmap = nullptr;
+  }
+  else if(rhs.mGlyph)
+  {
+    mGlyph = rhs.mGlyph;
+
+    rhs.mGlyph = nullptr;
+  }
+  else
+  {
+    mGlyph = nullptr;
+  }
+
+  if(rhs.mRenderedBuffer)
+  {
+    mRenderedBuffer     = rhs.mRenderedBuffer;
+    rhs.mRenderedBuffer = nullptr;
+  }
+  else
+  {
+    mRenderedBuffer = nullptr;
+  }
+
+  mStyleFlags = rhs.mStyleFlags;
+  return *this;
+}
+
 } // namespace Dali::TextAbstraction::Internal
index dc19c76..521c373 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TEST_ABSTRACTION_INTERNAL_FONT_FACE_GLYPH_CACHE_MANAGER_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.
@@ -23,6 +23,8 @@
 #include <dali/internal/text/text-abstraction/plugin/lru-cache-container.h>
 
 // EXTERNAL INCLUDES
+#include <memory> // for std::shared_ptr
+
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #include FT_GLYPH_H
@@ -53,10 +55,12 @@ public:
    */
   struct GlyphCacheData
   {
-    GlyphCacheData()
-    : mGlyph{nullptr}
-    {
-    }
+    GlyphCacheData();
+    ~GlyphCacheData();
+
+    // Move operations
+    GlyphCacheData(GlyphCacheData&& rhs) noexcept;
+    GlyphCacheData& operator=(GlyphCacheData&& rhs) noexcept;
 
     union
     {
@@ -69,12 +73,19 @@ public:
 
     TextAbstraction::GlyphBufferData* mRenderedBuffer{nullptr}; // Rendered glyph buffer. Cached only if system allow to cache and we rendered it before. Otherwise, just nullptr
 
+  private:
+    // Delete copy operations
+    GlyphCacheData(const GlyphCacheData&) = delete;
+    GlyphCacheData& operator=(const GlyphCacheData&) = delete;
+
     /**
-     * @brief Release the memory of loaded mGlyph / mBitmap.
+     * @brief Release the memory of loaded mGlyph / mBitmap and mRenderedBuffer.
      */
     void ReleaseGlyphData();
   };
 
+  using GlyphCacheDataPtr = std::shared_ptr<GlyphCacheData>;
+
   // Compression priority of rendered glyph buffer.
   enum class CompressionPolicyType
   {
@@ -87,32 +98,32 @@ public:
 
   /**
    * @brief Load GlyphCacheData from face. The result will be cached.
+   * @note Inputed glyph data pointer will be overwrited.
    *
    * @param[in] freeTypeFace The freetype face handle.
    * @param[in] index Index of glyph in this face.
    * @param[in] flag Flag when we load the glyph.
    * @param[in] isBoldRequired True if we require some software bold.
-   * @param[out] data Result of glyph load.
+   * @param[out] glyphDataPtr Result of pointer of glyph load.
    * @param[out] error Error code during load glyph.
    * @return True if load successfully. False if something error occured.
    */
   bool GetGlyphCacheDataFromIndex(
-    const FT_Face    freeTypeFace,
-    const GlyphIndex index,
-    const FT_Int32   flag,
-    const bool       isBoldRequired,
-    GlyphCacheData&  data,
-    FT_Error&        error);
+    const FT_Face      freeTypeFace,
+    const GlyphIndex   index,
+    const FT_Int32     flag,
+    const bool         isBoldRequired,
+    GlyphCacheDataPtr& glyphDataPtr,
+    FT_Error&          error);
 
   /**
    * @brief Load GlyphCacheData from face. The result will not be cached.
-   * @note If we call this API, We should release GlyphCacheData manually.
    *
    * @param[in] freeTypeFace The freetype face handle.
    * @param[in] index Index of glyph in this face.
    * @param[in] flag Flag when we load the glyph.
    * @param[in] isBoldRequired True if we require some software bold.
-   * @param[out] data Result of glyph load.
+   * @param[in, out] glyphData Result of glyph load.
    * @param[out] error Error code during load glyph.
    * @return True if load successfully. False if something error occured.
    */
@@ -121,7 +132,7 @@ public:
     const GlyphIndex index,
     const FT_Int32   flag,
     const bool       isBoldRequired,
-    GlyphCacheData&  data,
+    GlyphCacheData&  glyphData,
     FT_Error&        error);
 
   /**
@@ -229,7 +240,7 @@ private:
   // Private member value area.
   std::size_t mGlyphCacheMaxSize; ///< The maximum capacity of glyph cache.
 
-  using CacheContainer = LRUCacheContainer<GlyphCacheKey, GlyphCacheData, GlyphCacheKeyHash>;
+  using CacheContainer = LRUCacheContainer<GlyphCacheKey, GlyphCacheDataPtr, GlyphCacheKeyHash>;
 
   CacheContainer mLRUGlyphCache; ///< LRU Cache container of glyph
 };
index 53d3d0f..13e4b1b 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.
@@ -115,10 +115,10 @@ namespace
  *
  * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
  * @param[in] glyphIndex Index of glyph.
- * @param[out] glyphData The result of cached glyph data.
+ * @param[out] glyphDataPtr The result of cached glyph data pointer.
  * @return True if we success to get some glyph data. False otherwise.
  */
-static bool GetGlyphCacheData(void* font_data, const GlyphIndex& glyphIndex, GlyphCacheManager::GlyphCacheData& glyphData)
+static bool GetGlyphCacheData(void* font_data, const GlyphIndex& glyphIndex, GlyphCacheManager::GlyphCacheDataPtr& glyphDataPtr)
 {
   HarfBuzzProxyFont::Impl* impl = reinterpret_cast<HarfBuzzProxyFont::Impl*>(font_data);
 
@@ -126,7 +126,7 @@ static bool GetGlyphCacheData(void* font_data, const GlyphIndex& glyphIndex, Gly
   if(DALI_LIKELY(impl && impl->mGlyphCacheManager))
   {
     FT_Error error;
-    return impl->mGlyphCacheManager->GetGlyphCacheDataFromIndex(impl->mFreeTypeFace, glyphIndex, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING, false, glyphData, error);
+    return impl->mGlyphCacheManager->GetGlyphCacheDataFromIndex(impl->mFreeTypeFace, glyphIndex, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING, false, glyphDataPtr, error);
   }
   return false;
 }
@@ -214,9 +214,11 @@ static hb_bool_t GlyphVariantIndexConvertFunc(hb_font_t* font, void* font_data,
 static hb_position_t GlyphHorizontalAdvanceFunc(hb_font_t* font, void* font_data, hb_codepoint_t glyphIndex, void* user_data)
 {
   // Output data stored here.
-  GlyphCacheManager::GlyphCacheData glyphData;
-  if(GetGlyphCacheData(font_data, static_cast<GlyphIndex>(glyphIndex), glyphData))
+  GlyphCacheManager::GlyphCacheDataPtr glyphDataPtr;
+  if(GetGlyphCacheData(font_data, static_cast<GlyphIndex>(glyphIndex), glyphDataPtr))
   {
+    GlyphCacheManager::GlyphCacheData& glyphData = *glyphDataPtr.get();
+
     // Note : It may return invalid value for fixed size bitmap glyph.
     // But, Harfbuzz library also return Undefined advanced value if it is fixed size font.
     // So we'll also ignore that case.
@@ -236,9 +238,11 @@ static hb_position_t GlyphHorizontalAdvanceFunc(hb_font_t* font, void* font_data
 static hb_position_t GlyphVerticalAdvanceFunc(hb_font_t* font, void* font_data, hb_codepoint_t glyphIndex, void* user_data)
 {
   // Output data stored here.
-  GlyphCacheManager::GlyphCacheData glyphData;
-  if(GetGlyphCacheData(font_data, static_cast<GlyphIndex>(glyphIndex), glyphData))
+  GlyphCacheManager::GlyphCacheDataPtr glyphDataPtr;
+  if(GetGlyphCacheData(font_data, static_cast<GlyphIndex>(glyphIndex), glyphDataPtr))
   {
+    GlyphCacheManager::GlyphCacheData& glyphData = *glyphDataPtr.get();
+
     // Note : It may return invalid value for fixed size bitmap glyph.
     // But, Harfbuzz library also return Undefined advanced value if it is fixed size font.
     // So we'll also ignore that case.
@@ -277,9 +281,11 @@ static hb_bool_t GlyphHorizontalOriginFunc(hb_font_t* font, void* font_data, hb_
 static hb_bool_t GlyphVerticalOriginFunc(hb_font_t* font, void* font_data, hb_codepoint_t glyphIndex, hb_position_t* x, hb_position_t* y, void* user_data)
 {
   // Output data stored here.
-  GlyphCacheManager::GlyphCacheData glyphData;
-  if(GetGlyphCacheData(font_data, static_cast<GlyphIndex>(glyphIndex), glyphData))
+  GlyphCacheManager::GlyphCacheDataPtr glyphDataPtr;
+  if(GetGlyphCacheData(font_data, static_cast<GlyphIndex>(glyphIndex), glyphDataPtr))
   {
+    GlyphCacheManager::GlyphCacheData& glyphData = *glyphDataPtr.get();
+
     *x = glyphData.mGlyphMetrics.horiBearingX - glyphData.mGlyphMetrics.vertBearingX;
     *y = glyphData.mGlyphMetrics.horiBearingY + glyphData.mGlyphMetrics.vertBearingY;
     return true;
@@ -343,9 +349,11 @@ static hb_position_t GlyphVerticalKerningFunc(hb_font_t* font, void* font_data,
 static hb_bool_t GlyphExtentsFunc(hb_font_t* font, void* font_data, hb_codepoint_t glyphIndex, hb_glyph_extents_t* extents, void* user_data)
 {
   // Output data stored here.
-  GlyphCacheManager::GlyphCacheData glyphData;
-  if(!GetGlyphCacheData(font_data, static_cast<GlyphIndex>(glyphIndex), glyphData))
+  GlyphCacheManager::GlyphCacheDataPtr glyphDataPtr;
+  if(!GetGlyphCacheData(font_data, static_cast<GlyphIndex>(glyphIndex), glyphDataPtr))
   {
+    GlyphCacheManager::GlyphCacheData& glyphData = *glyphDataPtr.get();
+
     extents->x_bearing = glyphData.mGlyphMetrics.horiBearingX;
     extents->y_bearing = glyphData.mGlyphMetrics.horiBearingY;
     extents->width     = glyphData.mGlyphMetrics.width;