Create glyph bitmap without copy if single color
[platform/core/uifw/dali-adaptor.git] / dali / internal / text / text-abstraction / plugin / font-client-plugin-impl.cpp
index 40d3f32..6c0c264 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
@@ -248,12 +248,10 @@ FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem(FontDescr
 {
 }
 
-FontClient::Plugin::FontDescriptionSizeCacheItem::FontDescriptionSizeCacheItem(FontDescriptionId validatedFontId,
-                                                                               PointSize26Dot6   requestedPointSize,
-                                                                               FontId            fontId)
-: validatedFontId(validatedFontId),
-  requestedPointSize(requestedPointSize),
-  fontId(fontId)
+FontClient::Plugin::FontDescriptionSizeCacheKey::FontDescriptionSizeCacheKey(FontDescriptionId fontDescriptionId,
+                                                                             PointSize26Dot6   requestedPointSize)
+: fontDescriptionId(fontDescriptionId),
+  requestedPointSize(requestedPointSize)
 {
 }
 
@@ -299,6 +297,9 @@ FontClient::Plugin::~Plugin()
   DestroyCharacterSets(mCharacterSetCache);
   ClearCharacterSetFromFontFaceCache();
 
+  // Clear FontFaceCache here. Due to we sould deallocate FT_Faces before done freetype library
+  mFontFaceCache.clear();
+
 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
   delete mVectorFontCache;
 #endif
@@ -330,6 +331,7 @@ void FontClient::Plugin::ClearCache()
   mCharacterSetCache.Clear();
 
   mFontDescriptionSizeCache.clear();
+  mFontDescriptionSizeCache.rehash(0); // Note : unordered_map.clear() didn't deallocate memory
 
   mEllipsisCache.Clear();
   mPixelBufferCache.clear();
@@ -478,8 +480,39 @@ void FontClient::Plugin::GetDefaultPlatformFontDescription(FontDescription& font
       FcDefaultSubstitute(matchPattern);
 
       FcCharSet* characterSet = nullptr;
-      MatchFontDescriptionToPattern(matchPattern, mDefaultFontDescription, &characterSet);
+      bool       matched      = MatchFontDescriptionToPattern(matchPattern, mDefaultFontDescription, &characterSet);
+
+      // Caching the default font description
+      if(matched)
+      {
+        // Copy default font description info.
+        // Due to the type changed, we need to make some temperal font description.
+        FontDescription tempFontDescription = mDefaultFontDescription;
+
+        // Add the path to the cache.
+        tempFontDescription.type = FontDescription::FACE_FONT;
+        mFontDescriptionCache.push_back(tempFontDescription);
+
+        // Set the index to the vector of paths to font file names.
+        const FontDescriptionId fontDescriptionId = mFontDescriptionCache.size();
+
+        FONT_LOG_DESCRIPTION(tempFontDescription, "default platform font");
+        DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  default font fontDescriptionId : %d\n", fontDescriptionId);
+
+        // Cache the index and the matched font's description.
+        FontDescriptionCacheItem item(tempFontDescription,
+                                      fontDescriptionId);
+
+        mValidatedFontCache.push_back(std::move(item));
+      }
+      else
+      {
+        DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  default font validation failed for font [%s]\n", mDefaultFontDescription.family.c_str());
+      }
+
       // Decrease the reference counter of the character set as it's not stored.
+      // Note. the cached default font description will increase reference counter by
+      // mFontDescriptionCache. So we can decrease reference counter here.
       FcCharSetDestroy(characterSet);
 
       // Destroys the pattern created.
@@ -555,9 +588,9 @@ void FontClient::Plugin::GetDescription(FontId           id,
       {
         for(const auto& item : mFontDescriptionSizeCache)
         {
-          if(item.fontId == fontIdCacheItem.id)
+          if(item.second == fontIdCacheItem.index)
           {
-            fontDescription = *(mFontDescriptionCache.begin() + item.validatedFontId - 1u);
+            fontDescription = *(mFontDescriptionCache.begin() + item.first.fontDescriptionId - 1u);
 
             FONT_LOG_DESCRIPTION(fontDescription, "");
             return;
@@ -568,7 +601,7 @@ void FontClient::Plugin::GetDescription(FontId           id,
       case FontDescription::BITMAP_FONT:
       {
         fontDescription.type   = FontDescription::BITMAP_FONT;
-        fontDescription.family = mBitmapFontCache[fontIdCacheItem.id].font.name;
+        fontDescription.family = mBitmapFontCache[fontIdCacheItem.index].font.name;
         break;
       }
       default:
@@ -618,7 +651,7 @@ bool FontClient::Plugin::IsCharacterSupportedByFont(FontId fontId, Character cha
 
 const FontCacheItemInterface* FontClient::Plugin::GetCachedFontItem(FontId id) const
 {
-  const FontId index = id - 1u;
+  const FontCacheIndex index = id - 1u;
   if((id > 0u) && (index < mFontIdCache.Count()))
   {
     const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
@@ -626,11 +659,11 @@ const FontCacheItemInterface* FontClient::Plugin::GetCachedFontItem(FontId id) c
     {
       case FontDescription::FACE_FONT:
       {
-        return &mFontFaceCache[fontIdCacheItem.id];
+        return &mFontFaceCache[fontIdCacheItem.index];
       }
       case FontDescription::BITMAP_FONT:
       {
-        return &mBitmapFontCache[fontIdCacheItem.id];
+        return &mBitmapFontCache[fontIdCacheItem.index];
       }
       default:
       {
@@ -684,7 +717,7 @@ FontId FontClient::Plugin::FindFontForCharacter(const FontList&         fontList
         if((fontId > 0) &&
            (fontId - 1u < mFontIdCache.Count()))
         {
-          const FontFaceCacheItem& item = mFontFaceCache[mFontIdCache[fontId - 1u].id];
+          const FontFaceCacheItem& item = mFontFaceCache[mFontIdCache[fontId - 1u].index];
 
           foundColor = item.mHasColorTables;
         }
@@ -832,6 +865,18 @@ FontId FontClient::Plugin::GetFontId(const FontDescription& fontDescription,
 {
   DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
   FONT_LOG_DESCRIPTION(fontDescription, "");
+
+  // Special case when font Description don't have family information.
+  // In this case, we just use default description family and path.
+  const FontDescription& realFontDescription = fontDescription.family.empty() ? FontDescription(mDefaultFontDescription.path,
+                                                                                                mDefaultFontDescription.family,
+                                                                                                fontDescription.width,
+                                                                                                fontDescription.weight,
+                                                                                                fontDescription.slant,
+                                                                                                fontDescription.type)
+                                                                              : fontDescription;
+
+  FONT_LOG_DESCRIPTION(realFontDescription, "");
   DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "   requestedPointSize : %d\n", requestedPointSize);
 
   // This method uses three vectors which caches:
@@ -856,28 +901,28 @@ FontId FontClient::Plugin::GetFontId(const FontDescription& fontDescription,
   FontId fontId = 0u;
 
   // Check first if the font description matches with a previously loaded bitmap font.
-  if(FindBitmapFont(fontDescription.family, fontId))
+  if(FindBitmapFont(realFontDescription.family, fontId))
   {
     return fontId;
   }
 
   // Check if the font's description have been validated before.
-  FontDescriptionId validatedFontId = 0u;
+  FontDescriptionId fontDescriptionId = 0u;
 
-  if(!FindValidatedFont(fontDescription,
-                        validatedFontId))
+  if(!FindValidatedFont(realFontDescription,
+                        fontDescriptionId))
   {
     // Use font config to validate the font's description.
-    ValidateFont(fontDescription,
-                 validatedFontId);
+    ValidateFont(realFontDescription,
+                 fontDescriptionId);
   }
 
-  FontId fontFaceId = 0u;
-  // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
-  if(!FindFont(validatedFontId, requestedPointSize, fontFaceId))
+  FontCacheIndex fontCacheIndex = 0u;
+  // Check if exists a pair 'fontDescriptionId, requestedPointSize' in the cache.
+  if(!FindFont(fontDescriptionId, requestedPointSize, fontCacheIndex))
   {
     // Retrieve the font file name path.
-    const FontDescription& description = *(mFontDescriptionCache.begin() + validatedFontId - 1u);
+    const FontDescription& description = *(mFontDescriptionCache.begin() + fontDescriptionId - 1u);
 
     // Retrieve the font id. Do not cache the description as it has been already cached.
     fontId = GetFontId(description.path,
@@ -885,17 +930,15 @@ FontId FontClient::Plugin::GetFontId(const FontDescription& fontDescription,
                        faceIndex,
                        false);
 
-    fontFaceId                               = mFontIdCache[fontId - 1u].id;
-    mFontFaceCache[fontFaceId].mCharacterSet = FcCharSetCopy(mCharacterSetCache[validatedFontId - 1u]);
+    fontCacheIndex                               = mFontIdCache[fontId - 1u].index;
+    mFontFaceCache[fontCacheIndex].mCharacterSet = FcCharSetCopy(mCharacterSetCache[fontDescriptionId - 1u]);
 
-    // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
-    mFontDescriptionSizeCache.push_back(FontDescriptionSizeCacheItem(validatedFontId,
-                                                                     requestedPointSize,
-                                                                     fontFaceId));
+    // Cache the pair 'fontDescriptionId, requestedPointSize' to improve the following queries.
+    mFontDescriptionSizeCache.emplace(FontDescriptionSizeCacheKey(fontDescriptionId, requestedPointSize), fontCacheIndex);
   }
   else
   {
-    fontId = mFontFaceCache[fontFaceId].mFontId + 1u;
+    fontId = mFontFaceCache[fontCacheIndex].mFontId + 1u;
   }
 
   DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  font id : %d\n", fontId);
@@ -915,8 +958,8 @@ FontId FontClient::Plugin::GetFontId(const BitmapFont& bitmapFont)
   BitmapFontCacheItem bitmapFontCacheItem(bitmapFont, mFontIdCache.Count());
 
   FontIdCacheItem fontIdCacheItem;
-  fontIdCacheItem.type = FontDescription::BITMAP_FONT;
-  fontIdCacheItem.id   = mBitmapFontCache.size();
+  fontIdCacheItem.type  = FontDescription::BITMAP_FONT;
+  fontIdCacheItem.index = mBitmapFontCache.size();
 
   mBitmapFontCache.push_back(std::move(bitmapFontCacheItem));
   mFontIdCache.PushBack(fontIdCacheItem);
@@ -925,7 +968,7 @@ FontId FontClient::Plugin::GetFontId(const BitmapFont& bitmapFont)
 }
 
 void FontClient::Plugin::ValidateFont(const FontDescription& fontDescription,
-                                      FontDescriptionId&     validatedFontId)
+                                      FontDescriptionId&     fontDescriptionId)
 {
   DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
   FONT_LOG_DESCRIPTION(fontDescription, "");
@@ -946,17 +989,17 @@ void FontClient::Plugin::ValidateFont(const FontDescription& fontDescription,
     mFontDescriptionCache.push_back(description);
 
     // Set the index to the vector of paths to font file names.
-    validatedFontId = mFontDescriptionCache.size();
+    fontDescriptionId = mFontDescriptionCache.size();
 
     FONT_LOG_DESCRIPTION(description, "matched");
-    DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  validatedFontId : %d\n", validatedFontId);
+    DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  fontDescriptionId : %d\n", fontDescriptionId);
 
     // The reference counter of the character set has already been increased in MatchFontDescriptionToPattern.
     mCharacterSetCache.PushBack(characterSet);
 
     // Cache the index and the matched font's description.
     FontDescriptionCacheItem item(description,
-                                  validatedFontId);
+                                  fontDescriptionId);
 
     mValidatedFontCache.push_back(std::move(item));
 
@@ -967,7 +1010,7 @@ void FontClient::Plugin::ValidateFont(const FontDescription& fontDescription,
     {
       // Cache the given font's description if it's different than the matched.
       FontDescriptionCacheItem item(fontDescription,
-                                    validatedFontId);
+                                    fontDescriptionId);
 
       mValidatedFontCache.push_back(std::move(item));
     }
@@ -1066,7 +1109,7 @@ bool FontClient::Plugin::GetVectorMetrics(GlyphInfo* array,
     if((fontId > 0u) &&
        (fontId - 1u) < mFontIdCache.Count())
     {
-      FontFaceCacheItem& font = mFontFaceCache[mFontIdCache[fontId - 1u].id];
+      FontFaceCacheItem& font = mFontFaceCache[mFontIdCache[fontId - 1u].index];
 
       if(!font.mVectorFontId)
       {
@@ -1122,7 +1165,7 @@ PixelData FontClient::Plugin::CreateBitmap(FontId fontId, GlyphIndex glyphIndex,
                         data.width,
                         data.height,
                         data.format,
-                        PixelData::DELETE_ARRAY);
+                        PixelData::FREE);
 }
 
 void FontClient::Plugin::CreateVectorBlob(FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight)
@@ -1134,8 +1177,8 @@ void FontClient::Plugin::CreateVectorBlob(FontId fontId, GlyphIndex glyphIndex,
   if((fontId > 0u) &&
      (fontId - 1u < mFontIdCache.Count()))
   {
-    const FontId       fontFaceId = mFontIdCache[fontId - 1u].id;
-    FontFaceCacheItem& font       = mFontFaceCache[fontFaceId];
+    const FontCacheIndex fontFaceId = mFontIdCache[fontId - 1u].index;
+    FontFaceCacheItem&   font       = mFontFaceCache[fontFaceId];
 
     if(!font.mVectorFontId)
     {
@@ -1176,7 +1219,7 @@ const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph(PointSize26Dot6 requestedP
                                       false);
 
   // Set the character index to access the glyph inside the font.
-  item.glyph.index = FT_Get_Char_Index(mFontFaceCache[mFontIdCache[item.glyph.fontId - 1u].id].mFreeTypeFace,
+  item.glyph.index = FT_Get_Char_Index(mFontFaceCache[mFontIdCache[item.glyph.fontId - 1u].index].mFreeTypeFace,
                                        ELLIPSIS_CHARACTER);
 
   GetBitmapMetrics(&item.glyph, 1u, true);
@@ -1567,16 +1610,17 @@ FontId FontClient::Plugin::CreateFont(const FontPath& path,
       }
       else
       {
+        FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
+
+        FontMetrics metrics(static_cast<float>(ftMetrics.ascender) * FROM_266,
+                            static_cast<float>(ftMetrics.descender) * FROM_266,
+                            static_cast<float>(ftMetrics.height) * FROM_266,
+                            static_cast<float>(ftFace->underline_position) * FROM_266,
+                            static_cast<float>(ftFace->underline_thickness) * FROM_266);
+
         const float fixedWidth  = static_cast<float>(ftFace->available_sizes[fixedSizeIndex].width);
         const float fixedHeight = static_cast<float>(ftFace->available_sizes[fixedSizeIndex].height);
 
-        // Indicate that the font is a fixed sized bitmap
-        FontMetrics metrics(fixedHeight, // The ascender in pixels.
-                            0.0f,
-                            fixedHeight, // The height in pixels.
-                            0.0f,
-                            0.0f);
-
         // Create the FreeType font face item to cache.
         FontFaceCacheItem fontFaceCacheItem(mFreeTypeLibrary, ftFace, path, requestedPointSize, faceIndex, metrics, fixedSizeIndex, fixedWidth, fixedHeight, hasColorTables);
 
@@ -1588,11 +1632,11 @@ FontId FontClient::Plugin::CreateFont(const FontPath& path,
         fontIdCacheItem.type = FontDescription::FACE_FONT;
 
         // Set the index to the FreeType font face cache.
-        fontIdCacheItem.id = mFontFaceCache.size();
-        fontFaceId         = fontIdCacheItem.id + 1u;
+        fontIdCacheItem.index = mFontFaceCache.size();
+        fontFaceId            = fontIdCacheItem.index + 1u;
 
         // Cache the items.
-        mFontFaceCache.push_back(fontFaceCacheItem);
+        mFontFaceCache.emplace_back(std::move(fontFaceCacheItem));
         mFontIdCache.PushBack(fontIdCacheItem);
 
         // Set the font id to be returned.
@@ -1646,11 +1690,11 @@ FontId FontClient::Plugin::CreateFont(const FontPath& path,
         fontIdCacheItem.type = FontDescription::FACE_FONT;
 
         // Set the index to the FreeType font face cache.
-        fontIdCacheItem.id = mFontFaceCache.size();
-        fontFaceId         = fontIdCacheItem.id + 1u;
+        fontIdCacheItem.index = mFontFaceCache.size();
+        fontFaceId            = fontIdCacheItem.index + 1u;
 
         // Cache the items.
-        mFontFaceCache.push_back(fontFaceCacheItem);
+        mFontFaceCache.emplace_back(std::move(fontFaceCacheItem));
         mFontIdCache.PushBack(fontIdCacheItem);
 
         // Set the font id to be returned.
@@ -1708,13 +1752,13 @@ bool FontClient::Plugin::FindFont(const FontPath& path,
 }
 
 bool FontClient::Plugin::FindValidatedFont(const FontDescription& fontDescription,
-                                           FontDescriptionId&     validatedFontId)
+                                           FontDescriptionId&     fontDescriptionId)
 {
   DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
   FONT_LOG_DESCRIPTION(fontDescription, "");
   DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "  number of validated fonts in the cache : %d\n", mValidatedFontCache.size());
 
-  validatedFontId = 0u;
+  fontDescriptionId = 0u;
 
   for(const auto& item : mValidatedFontCache)
   {
@@ -1724,14 +1768,14 @@ bool FontClient::Plugin::FindValidatedFont(const FontDescription& fontDescriptio
        (fontDescription.weight == item.fontDescription.weight) &&
        (fontDescription.slant == item.fontDescription.slant))
     {
-      validatedFontId = item.index;
+      fontDescriptionId = item.index;
 
-      DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  validated font found, id : %d\n", validatedFontId);
+      DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  validated font description found, id : %d\n", fontDescriptionId);
       return true;
     }
   }
 
-  DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  validated font not found\n");
+  DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  validated font description not found\n");
   return false;
 }
 
@@ -1765,26 +1809,25 @@ bool FontClient::Plugin::FindFallbackFontList(const FontDescription& fontDescrip
   return false;
 }
 
-bool FontClient::Plugin::FindFont(FontDescriptionId validatedFontId,
+bool FontClient::Plugin::FindFont(FontDescriptionId fontDescriptionId,
                                   PointSize26Dot6   requestedPointSize,
-                                  FontId&           fontId)
+                                  FontCacheIndex&   fontCacheIndex)
 {
   DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
-  DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "    validatedFontId  : %d\n", validatedFontId);
+  DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "   fontDescriptionId : %d\n", fontDescriptionId);
   DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize);
 
-  fontId = 0u;
+  fontCacheIndex = 0u;
 
-  for(const auto& item : mFontDescriptionSizeCache)
+  FontDescriptionSizeCacheKey key(fontDescriptionId, requestedPointSize);
+
+  const auto& iter = mFontDescriptionSizeCache.find(key);
+  if(iter != mFontDescriptionSizeCache.cend())
   {
-    if((validatedFontId == item.validatedFontId) &&
-       (requestedPointSize == item.requestedPointSize))
-    {
-      fontId = item.fontId;
+    fontCacheIndex = iter->second;
 
-      DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  font found, id : %d\n", fontId);
-      return true;
-    }
+    DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  font found, index of font cache : %d\n", fontCacheIndex);
+    return true;
   }
 
   DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  font not found.\n");
@@ -1940,9 +1983,9 @@ void FontClient::Plugin::CacheFontPath(FT_Face ftFace, FontId id, PointSize26Dot
     description.weight = FontWeight::BOLD;
   }
 
-  FontDescriptionId validatedFontId = 0u;
+  FontDescriptionId fontDescriptionId = 0u;
   if(!FindValidatedFont(description,
-                        validatedFontId))
+                        fontDescriptionId))
   {
     FcPattern* pattern = CreateFontFamilyPattern(description); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
 
@@ -1964,19 +2007,17 @@ void FontClient::Plugin::CacheFontPath(FT_Face ftFace, FontId id, PointSize26Dot
     mFontDescriptionCache.push_back(description);
 
     // Set the index to the vector of paths to font file names.
-    validatedFontId = mFontDescriptionCache.size();
+    fontDescriptionId = mFontDescriptionCache.size();
 
     // Increase the reference counter and add the character set to the cache.
     mCharacterSetCache.PushBack(FcCharSetCopy(characterSet));
 
     // Cache the index and the font's description.
     mValidatedFontCache.push_back(std::move(FontDescriptionCacheItem(std::move(description),
-                                                                     validatedFontId)));
+                                                                     fontDescriptionId)));
 
-    // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
-    mFontDescriptionSizeCache.push_back(FontDescriptionSizeCacheItem(validatedFontId,
-                                                                     requestedPointSize,
-                                                                     fontFaceId));
+    // Cache the pair 'fontDescriptionId, requestedPointSize' to improve the following queries.
+    mFontDescriptionSizeCache.emplace(FontDescriptionSizeCacheKey(fontDescriptionId, requestedPointSize), fontFaceId);
   }
 }