Reduce the number of resize for emoji 61/275961/3
authorEunki, Hong <eunkiki.hong@samsung.com>
Tue, 7 Jun 2022 10:44:31 +0000 (19:44 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Tue, 7 Jun 2022 11:40:24 +0000 (20:40 +0900)
When we use fixed size glyph, It did resize for
every glyph creation.

This patch make we store resized bitmap glyph
so reduce the time of text rendering.

Resized glyph will be cached. Due to the memory issue,
we only convert the size when glyph become smaller enough.

Change-Id: I4303f76dc8d3e52d809c4744a9878ee731d8493f
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
dali/internal/text/text-abstraction/plugin/font-client-utils.cpp
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

index 869609c..bb79eb3 100644 (file)
@@ -143,7 +143,7 @@ void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, unsigned
 
   // Creates the output buffer
   const unsigned int bufferSize = data.width * data.height * 4u;
-  data.buffer                   = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
+  data.buffer                   = new uint8_t[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
 
   if(inputDimensions == desiredDimensions)
   {
index df8c735..34e2b48 100644 (file)
@@ -34,6 +34,13 @@ const float FROM_266        = 1.0f / 64.0f;
 const float POINTS_PER_INCH = 72.f;
 
 /**
+ * @brief Maximum rate of bitmap glyph resize.
+ * If scale factor is bigger than this value, we will not cache resized glyph.
+ * Else, resize bitmap glyph itself and cache it.
+ */
+constexpr float MAXIMUM_RATE_OF_BITMAP_GLYPH_CACHE_RESIZE = 1.5f;
+
+/**
  * @brief Maximum size of glyph cache per each font face.
  */
 constexpr std::size_t DEFAULT_GLYPH_CACHE_MAX         = 128;
@@ -181,7 +188,7 @@ bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVe
   if(mIsFixedSizeBitmap)
   {
     FT_Select_Size(mFreeTypeFace, mFixedSizeIndex); ///< @todo: needs to be investigated why it's needed to select the size again.
-    mGlyphCacheManager->GetGlyphCacheDataFromIndex(glyphInfo.index, FT_LOAD_COLOR, false, glyphData, error);
+    mGlyphCacheManager->GetGlyphCacheDataFromIndex(glyphInfo.index, FT_LOAD_COLOR, glyphInfo.isBoldRequired, glyphData, error);
 
     if(FT_Err_Ok == error)
     {
@@ -214,6 +221,17 @@ bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVe
         glyphInfo.yBearing      = round(glyphInfo.yBearing * scaleFactor);
 
         glyphInfo.scaleFactor = scaleFactor;
+
+        if(scaleFactor < MAXIMUM_RATE_OF_BITMAP_GLYPH_CACHE_RESIZE)
+        {
+          // Resize bitmap glyph and cache it due to the performance issue.
+          // If scaleFactor is too big, cached bitmap may hold too big memory.
+          // So, we only hold small enough case.
+
+          // TODO : If dpiVertical value changed, this resize feature will be break down.
+          // Otherwise, this glyph will be resized only one times.
+          mGlyphCacheManager->ResizeBitmapGlyph(glyphInfo.index, FT_LOAD_COLOR, glyphInfo.isBoldRequired, static_cast<uint32_t>(glyphInfo.width), static_cast<uint32_t>(glyphInfo.height));
+        }
       }
     }
     else
index 23f0bbd..daf0bf9 100644 (file)
  * limitations under the License.
  */
 
+// INTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
+#include <dali/internal/imaging/common/image-operations.h>
 #include <dali/internal/text/text-abstraction/plugin/font-client-utils.h>
 #include <dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.h>
+
+// EXTERNAL INCLUDES
 #include FT_BITMAP_H
 
 #if defined(DEBUG_ENABLED)
@@ -186,6 +190,102 @@ bool GlyphCacheManager::LoadGlyphDataFromIndex(
   return false;
 }
 
+void GlyphCacheManager::ResizeBitmapGlyph(
+  const GlyphIndex& index,
+  const FT_Int32&   flag,
+  const bool&       isBoldRequired,
+  const uint32_t&   desiredWidth,
+  const uint32_t&   desiredHeight)
+{
+  FT_Error       error;
+  GlyphCacheData originGlyphData;
+  if(GetGlyphCacheDataFromIndex(index, flag, isBoldRequired, originGlyphData, error))
+  {
+    if(DALI_LIKELY(originGlyphData.mIsBitmap && originGlyphData.mBitmap))
+    {
+      const bool requiredResize = (originGlyphData.mBitmap->rows != desiredHeight) || (originGlyphData.mBitmap->width != desiredWidth);
+      if(requiredResize)
+      {
+        const GlyphCacheKey key  = GlyphCacheKey(index, flag, isBoldRequired);
+        auto                iter = mLRUGlyphCache.Find(key);
+
+        GlyphCacheData& destinationGlpyhData = iter->element;
+
+        const ImageDimensions inputDimensions(destinationGlpyhData.mBitmap->width, destinationGlpyhData.mBitmap->rows);
+        const ImageDimensions desiredDimensions(desiredWidth, desiredHeight);
+
+        uint8_t* desiredBuffer = nullptr;
+
+        switch(destinationGlpyhData.mBitmap->pixel_mode)
+        {
+          case FT_PIXEL_MODE_GRAY:
+          {
+            if(destinationGlpyhData.mBitmap->pitch == static_cast<int>(destinationGlpyhData.mBitmap->width))
+            {
+              desiredBuffer = new uint8_t[desiredWidth * desiredHeight];
+              // Resize bitmap here.
+              Dali::Internal::Platform::LanczosSample1BPP(destinationGlpyhData.mBitmap->buffer,
+                                                          inputDimensions,
+                                                          destinationGlpyhData.mBitmap->width,
+                                                          desiredBuffer,
+                                                          desiredDimensions);
+            }
+            break;
+          }
+#ifdef FREETYPE_BITMAP_SUPPORT
+          case FT_PIXEL_MODE_BGRA:
+          {
+            if(destinationGlpyhData.mBitmap->pitch == static_cast<int>(destinationGlpyhData.mBitmap->width << 2u))
+            {
+              desiredBuffer = new uint8_t[(desiredWidth * desiredHeight) << 2u];
+              // Resize bitmap here.
+              Dali::Internal::Platform::LanczosSample4BPP(destinationGlpyhData.mBitmap->buffer,
+                                                          inputDimensions,
+                                                          destinationGlpyhData.mBitmap->width,
+                                                          desiredBuffer,
+                                                          desiredDimensions);
+            }
+            break;
+          }
+#endif
+          default:
+          {
+            DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::GlyphCacheManager::ResizeBitmapGlyph. FontClient Unable to create Bitmap of this PixelType\n");
+            break;
+          }
+        }
+
+        if(desiredBuffer)
+        {
+          // Success to resize bitmap glyph.
+          // Release origin bitmap buffer.
+          delete[] destinationGlpyhData.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)
+          {
+            case FT_PIXEL_MODE_GRAY:
+            {
+              destinationGlpyhData.mBitmap->pitch = desiredWidth;
+              break;
+            }
+#ifdef FREETYPE_BITMAP_SUPPORT
+            case FT_PIXEL_MODE_BGRA:
+            {
+              destinationGlpyhData.mBitmap->pitch = desiredWidth << 2u;
+              break;
+            }
+#endif
+          }
+        }
+      }
+    }
+  }
+}
+
 void GlyphCacheManager::GlyphCacheData::ReleaseGlyphData()
 {
   if(mIsBitmap && mBitmap)
index beba02f..5b8d135 100644 (file)
@@ -93,7 +93,7 @@ public:
     FT_Error&         error);
 
   /**
-   * @brief Load GlyphCacheData from face. The result will be cached.
+   * @brief Load GlyphCacheData from face. The result will not be cached.
    * @note If we call this API, We should release GlyphCacheData manually.
    *
    * @param[in] index Index of glyph in this face.
@@ -110,6 +110,23 @@ public:
     GlyphCacheData&   data,
     FT_Error&         error);
 
+  /**
+   * @brief Resize bitmap glyph. The result will change cached glyph bitmap information.
+   * If glyph is not bitmap glyph, nothing happened.
+   *
+   * @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[in] desiredWidth Desired width of bitmap.
+   * @param[in] desiredHeight Desired height of bitmap.
+   */
+  void ResizeBitmapGlyph(
+    const GlyphIndex& index,
+    const FT_Int32&   flag,
+    const bool&       isBoldRequired,
+    const uint32_t&   desiredWidth,
+    const uint32_t&   desiredHeight);
+
 private:
   // Private struct area.
   /**