Merge branch 'devel/master' into tizen
authortscholb <scholb.kim@samsung.com>
Tue, 21 Jun 2022 06:36:16 +0000 (15:36 +0900)
committertscholb <scholb.kim@samsung.com>
Tue, 21 Jun 2022 06:36:16 +0000 (15:36 +0900)
23 files changed:
dali/devel-api/adaptor-framework/vector-image-renderer-plugin.h [deleted file]
dali/devel-api/file.list
dali/internal/adaptor/common/combined-update-render-controller.cpp
dali/internal/adaptor/tizen-wayland/framework-tizen.cpp
dali/internal/imaging/common/image-operations.cpp
dali/internal/imaging/common/loader-wbmp.cpp
dali/internal/imaging/common/webp-loading.cpp
dali/internal/text/file.list
dali/internal/text/text-abstraction/font-client-impl.cpp
dali/internal/text/text-abstraction/font-client-impl.h
dali/internal/text/text-abstraction/plugin/bitmap-font-cache-item.h
dali/internal/text/text-abstraction/plugin/font-cache-item-interface.h
dali/internal/text/text-abstraction/plugin/font-client-plugin-impl.cpp
dali/internal/text/text-abstraction/plugin/font-client-plugin-impl.h
dali/internal/text/text-abstraction/plugin/font-face-cache-item.cpp
dali/internal/text/text-abstraction/plugin/font-face-cache-item.h
dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.cpp [new file with mode: 0644]
dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.h [new file with mode: 0644]
dali/internal/text/text-abstraction/shaping-impl.cpp
dali/internal/window-system/common/window-impl.cpp
dali/internal/window-system/common/window-impl.h
dali/public-api/dali-adaptor-version.cpp
packaging/dali-adaptor.spec

diff --git a/dali/devel-api/adaptor-framework/vector-image-renderer-plugin.h b/dali/devel-api/adaptor-framework/vector-image-renderer-plugin.h
deleted file mode 100644 (file)
index 76d78f7..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-#ifndef DALI_VECTOR_IMAGE_RENDERER_PLUGIN_H
-#define DALI_VECTOR_IMAGE_RENDERER_PLUGIN_H
-
-/*
- * Copyright (c) 2021 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
-
-namespace Dali
-{
-/**
- * VectorImageRendererPlugin is an abstract interface, used by dali-adaptor to render a vector image(SVG).
- * A concrete implementation must be created for each platform and provided as a dynamic library which
- * will be loaded at run time by the adaptor.
- */
-class VectorImageRendererPlugin
-{
-public:
-  /**
-   * @brief Constructor
-   */
-  VectorImageRendererPlugin()
-  {
-  }
-
-  /**
-   * @brief Destructor
-   */
-  virtual ~VectorImageRendererPlugin()
-  {
-  }
-
-  /**
-   * @brief Load vector image data directly.
-   *
-   * @param[in] data The memory data of vector image
-   * @return True if the load success, false otherwise.
-   */
-  virtual bool Load(const Vector<uint8_t>& data) = 0;
-
-  /**
-   * @brief Rasterizes the content to the target buffer synchronously.
-   *
-   * @param[in] buffer The target buffer
-   * @return True if the rendering succeeds, false otherwise.
-   */
-  virtual bool Rasterize(Dali::Devel::PixelBuffer& buffer) = 0;
-
-  /**
-   * @brief Gets the default size of the file.
-   *
-   * @param[out] width The default width of the file
-   * @param[out] height The default height of the file
-   */
-  virtual void GetDefaultSize(uint32_t& width, uint32_t& height) const = 0;
-
-  /**
-   * @brief Function pointer called in adaptor to create a plugin instance.
-   */
-  using CreateVectorImageRendererFunction = VectorImageRendererPlugin* (*)();
-};
-
-} // namespace Dali
-
-#endif // DALI_VECTOR_IMAGE_RENDERER_PLUGIN_H
index edef100..89cb0a9 100755 (executable)
@@ -103,7 +103,6 @@ SET( devel_api_adaptor_framework_header_files
   ${adaptor_devel_api_dir}/adaptor-framework/vector-animation-renderer.h
   ${adaptor_devel_api_dir}/adaptor-framework/vector-animation-renderer-plugin.h
   ${adaptor_devel_api_dir}/adaptor-framework/vector-image-renderer.h
-  ${adaptor_devel_api_dir}/adaptor-framework/vector-image-renderer-plugin.h
   ${adaptor_devel_api_dir}/adaptor-framework/video-player.h
   ${adaptor_devel_api_dir}/adaptor-framework/video-player-plugin.h
   ${adaptor_devel_api_dir}/adaptor-framework/web-engine.h
index 0f1f71b..350ab2a 100644 (file)
@@ -545,7 +545,8 @@ void CombinedUpdateRenderController::UpdateRenderThread()
     LOG_UPDATE_RENDER_TRACE;
 
     // For thread safe
-    bool uploadOnly = mUploadWithoutRendering;
+    bool         uploadOnly     = mUploadWithoutRendering;
+    unsigned int surfaceResized = mSurfaceResized;
 
     // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
     AddPerformanceMarker(PerformanceInterface::VSYNC);
@@ -676,7 +677,7 @@ void CombinedUpdateRenderController::UpdateRenderThread()
     // Upload shared resources
     mCore.PreRender(renderStatus, mForceClear);
 
-    if(!uploadOnly)
+    if(!uploadOnly || surfaceResized)
     {
       // Go through each window
       WindowContainer windows;
index b4efe3d..8198a80 100644 (file)
@@ -195,23 +195,6 @@ struct Framework::Impl
 #endif
     mApplicationType = type;
     mCallbackManager = CallbackManager::New();
-
-    char* region   = nullptr;
-    char* language = nullptr;
-    system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_COUNTRY, &region);
-    system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &language);
-
-    if(region != nullptr)
-    {
-      mRegion = std::string(region);
-      free(region);
-    }
-
-    if(language != nullptr)
-    {
-      mLanguage = std::string(language);
-      free(language);
-    }
   }
 
   ~Impl()
@@ -294,13 +277,35 @@ struct Framework::Impl
     mRegion = region;
   }
 
-  std::string GetLanguage() const
+  std::string GetLanguage()
   {
+    if(mLanguage.empty())
+    {
+      char* language = nullptr;
+      system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &language);
+
+      if(language != nullptr)
+      {
+        mLanguage = std::string(language);
+        free(language);
+      }
+    }
     return mLanguage;
   }
 
-  std::string GetRegion() const
+  std::string GetRegion()
   {
+    if(mRegion.empty())
+    {
+      char* region = nullptr;
+      system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_COUNTRY, &region);
+
+      if(region != nullptr)
+      {
+        mRegion = std::string(region);
+        free(region);
+      }
+    }
     return mRegion;
   }
 
@@ -308,8 +313,8 @@ struct Framework::Impl
   Type             mApplicationType;
   CallbackBase*    mAbortCallBack;
   CallbackManager* mCallbackManager;
-  std::string      mLanguage;
-  std::string      mRegion;
+  std::string      mLanguage{};
+  std::string      mRegion{};
 
   Framework*                  mFramework;
   AppCore::AppEventHandlerPtr handlers[5];
index 360c9ad..2bdac51 100644 (file)
@@ -1333,7 +1333,7 @@ void HalveScanlineInPlaceRGB565(unsigned char* pixels, unsigned int width)
 
   for(unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel)
   {
-    const uint32_t averaged = AveragePixelRGB565(alignedPixels[pixel], alignedPixels[pixel + 1]);
+    const uint16_t averaged = AveragePixelRGB565(alignedPixels[pixel], alignedPixels[pixel + 1]);
     alignedPixels[outPixel] = averaged;
   }
 }
@@ -1395,6 +1395,7 @@ namespace
 /**
  * @copydoc AverageScanlines1
  * @note This API average eight components in one operation.
+ * @note Only possible if each scanline pointer's address aligned
  * It will give performance benifit.
  */
 inline void AverageScanlinesWithEightComponents(
@@ -1406,20 +1407,27 @@ inline void AverageScanlinesWithEightComponents(
   unsigned int component = 0;
   if(DALI_LIKELY(totalComponentCount >= 8))
   {
-    // Jump 8 components in one step
-    const std::uint64_t* const scanline18Step = reinterpret_cast<const std::uint64_t* const>(scanline1);
-    const std::uint64_t* const scanline28Step = reinterpret_cast<const std::uint64_t* const>(scanline2);
-    std::uint64_t* const       output8step    = reinterpret_cast<std::uint64_t* const>(outputScanline);
+    // Note reinsterpret_cast from uint8_t to uint64_t and read/write only allowed
+    // If pointer of data is aligned well.
+    if(((reinterpret_cast<std::ptrdiff_t>(scanline1) & (sizeof(std::uint64_t) - 1)) == 0) &&
+       ((reinterpret_cast<std::ptrdiff_t>(scanline2) & (sizeof(std::uint64_t) - 1)) == 0) &&
+       ((reinterpret_cast<std::ptrdiff_t>(outputScanline) & (sizeof(std::uint64_t) - 1)) == 0))
+    {
+      // Jump 8 components in one step
+      const std::uint64_t* const scanline18Step = reinterpret_cast<const std::uint64_t* const>(scanline1);
+      const std::uint64_t* const scanline28Step = reinterpret_cast<const std::uint64_t* const>(scanline2);
+      std::uint64_t* const       output8step    = reinterpret_cast<std::uint64_t* const>(outputScanline);
 
-    const std::uint32_t totalStepCount = (totalComponentCount) >> 3;
-    component                          = totalStepCount << 3;
+      const std::uint32_t totalStepCount = (totalComponentCount) >> 3;
+      component                          = totalStepCount << 3;
 
-    // and for each step, calculate average of 8 bytes.
-    for(std::uint32_t i = 0; i < totalStepCount; ++i)
-    {
-      const auto& c1     = *(scanline18Step + i);
-      const auto& c2     = *(scanline28Step + i);
-      *(output8step + i) = static_cast<std::uint64_t>((((c1 ^ c2) & 0xfefefefefefefefeull) >> 1) + (c1 & c2));
+      // and for each step, calculate average of 8 bytes.
+      for(std::uint32_t i = 0; i < totalStepCount; ++i)
+      {
+        const auto& c1     = *(scanline18Step + i);
+        const auto& c2     = *(scanline28Step + i);
+        *(output8step + i) = static_cast<std::uint64_t>((((c1 ^ c2) & 0xfefefefefefefefeull) >> 1) + (c1 & c2));
+      }
     }
   }
   // remaining components calculate
@@ -1968,7 +1976,7 @@ inline void LinearSampleGeneric(const unsigned char* __restrict__ inPixels,
 
     // Find the two scanlines to blend and the weight to blend with:
     const unsigned int integerY1    = inY >> 16u;
-    const unsigned int integerY2    = integerY1 >= inputHeight ? integerY1 : integerY1 + 1;
+    const unsigned int integerY2    = integerY1 + 1 >= inputHeight ? integerY1 : integerY1 + 1;
     const unsigned int inputYWeight = inY & 65535u;
 
     DALI_ASSERT_DEBUG(integerY1 < inputHeight);
@@ -1982,7 +1990,7 @@ inline void LinearSampleGeneric(const unsigned char* __restrict__ inPixels,
     {
       // Work out the two pixel scanline offsets for this cluster of four samples:
       const unsigned int integerX1 = inX >> 16u;
-      const unsigned int integerX2 = integerX1 >= inputWidth ? integerX1 : integerX1 + 1;
+      const unsigned int integerX2 = integerX1 + 1 >= inputWidth ? integerX1 : integerX1 + 1;
 
       // Execute the loads:
       const PIXEL pixel1 = inScanline1[integerX1];
index 0fd3773..40fe8f1 100644 (file)
@@ -240,32 +240,37 @@ bool LoadBitmapFromWbmp(const Dali::ImageLoader::Input& input, Dali::Devel::Pixe
    * @endcode
    */
 
-  const std::uint8_t* inputPixels                  = inputBufferPtr + position;
-  const std::uint32_t lineByteLengthWithoutPadding = w >> 3;
-  const std::uint8_t  linePadding                  = w & 0x07;
+  const std::uint8_t* inputPixels                 = inputBufferPtr + position;
+  const std::uint32_t lineBitLengthWithoutPadding = (w >> 3) << 3;
 
   for(std::uint32_t y = 0; y < h; ++y)
   {
-    for(std::uint32_t x = 0; x < lineByteLengthWithoutPadding; ++x)
+    std::uint32_t x = 0;
+    if((reinterpret_cast<std::ptrdiff_t>(outputPixels) & (sizeof(std::uint32_t) - 1)) == 0)
     {
-      // memset whole 8 bits
-      // outputPixels filled 4 bytes in one operation.
-      // cachedCalculation4BitTo4ByteTable calculated in compile-time.
-      *(reinterpret_cast<std::uint32_t*>(outputPixels + 0)) = cachedCalculation4BitTo4ByteTable[((*inputPixels) >> 4) & 0x0f];
-      *(reinterpret_cast<std::uint32_t*>(outputPixels + 4)) = cachedCalculation4BitTo4ByteTable[(*inputPixels) & 0x0f];
-      outputPixels += 8;
-      ++inputPixels;
+      for(; x < lineBitLengthWithoutPadding; x += 8)
+      {
+        // memset whole 8 bits
+        // outputPixels filled 4 bytes in one operation.
+        // cachedCalculation4BitTo4ByteTable calculated in compile-time.
+        *(reinterpret_cast<std::uint32_t*>(outputPixels + 0)) = cachedCalculation4BitTo4ByteTable[((*inputPixels) >> 4) & 0x0f];
+        *(reinterpret_cast<std::uint32_t*>(outputPixels + 4)) = cachedCalculation4BitTo4ByteTable[(*inputPixels) & 0x0f];
+        outputPixels += 8;
+        ++inputPixels;
+      }
     }
-    if(linePadding > 0)
     {
       // memset linePadding bits naive.
-      for(std::uint8_t x = 0; x < linePadding; ++x)
+      for(; x < w; ++x)
       {
         const std::uint8_t offset = (0x07 - (x & 0x07));
         *outputPixels             = ((*inputPixels) >> offset) & 1 ? 0xff : 0x00;
         ++outputPixels;
+        if(offset == 0)
+        {
+          ++inputPixels;
+        }
       }
-      ++inputPixels;
     }
   }
 
index 61baf2a..7790c66 100644 (file)
@@ -119,7 +119,7 @@ public:
       mWebPData.bytes = mBuffer;
 
       WebPDemuxer* demuxer = WebPDemux(&mWebPData);
-      uint32_t flags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS);
+      uint32_t     flags   = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS);
       if(flags & ANIMATION_FLAG)
       {
         mIsAnimatedImage = true;
@@ -268,7 +268,7 @@ public:
   bool            mIsLocalResource;
 
 #ifdef DALI_WEBP_AVAILABLE
-  WebPData                 mWebPData{0};
+  WebPData mWebPData{0};
 #endif
 
 #ifdef DALI_ANIMATED_WEBP_ENABLED
@@ -397,7 +397,7 @@ Dali::Devel::PixelBuffer WebPLoading::DecodeFrame(uint32_t frameIndex)
 {
   Dali::Devel::PixelBuffer pixelBuffer;
 #ifdef DALI_ANIMATED_WEBP_ENABLED
-  if(mImpl->mLatestLoadedFrame > static_cast<int32_t>(frameIndex))
+  if(mImpl->mLatestLoadedFrame >= static_cast<int32_t>(frameIndex))
   {
     mImpl->mLatestLoadedFrame = INITIAL_INDEX;
     WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
index 1444e79..867fb26 100644 (file)
@@ -14,4 +14,5 @@ SET( adaptor_text_common_src_files
     ${adaptor_text_dir}/text-abstraction/plugin/font-client-plugin-impl.cpp
     ${adaptor_text_dir}/text-abstraction/plugin/font-face-cache-item.cpp
     ${adaptor_text_dir}/text-abstraction/plugin/font-face-glyph-cache-manager.cpp
+    ${adaptor_text_dir}/text-abstraction/plugin/harfbuzz-proxy-font.cpp
 )
index 2b5c40a..0656765 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.
@@ -419,6 +419,13 @@ bool FontClient::AddCustomFontDirectory(const FontPath& path)
   return mPlugin->AddCustomFontDirectory(path);
 }
 
+HarfBuzzFontHandle FontClient::GetHarfBuzzFont(FontId fontId)
+{
+  CreatePlugin();
+
+  return mPlugin->GetHarfBuzzFont(fontId);
+}
+
 void FontClient::CreatePlugin()
 {
   if(!mPlugin)
index ffa070a..7b158ef 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_IMPL_H
 
 /*
- * 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.
@@ -32,6 +32,8 @@ namespace TextAbstraction
 {
 namespace Internal
 {
+using HarfBuzzFontHandle = void*; ///< @note We don't want to make other class include harfbuzz header. So we will keep harfbuzz font data as HarfBuzzFontHandle.
+
 /**
  * Implementation of the FontClient
  */
@@ -48,6 +50,7 @@ public:
    */
   ~FontClient();
 
+public: // API for Dali::TextAbstraction::FontClient used.
   /**
    * @copydoc Dali::TextAbstraction::FontClient::Get()
    */
@@ -259,6 +262,12 @@ public:
   uint32_t GetNumberOfPointsPerOneUnitOfPointSize() const;
 
   /**
+   * @copydoc Dali::TextAbstraction::FontClient::AddCustomFontDirectory()
+   */
+  bool AddCustomFontDirectory(const FontPath& path);
+
+public: // API for Dali::TextAbstraction::Internal::FontClient used.
+  /**
    * @brief Retrieves the pointer to the FreeType Font Face for the given @p fontId.
    *
    * @param[in] fontId The font id.
@@ -277,9 +286,12 @@ public:
   FontDescription::Type GetFontType(FontId fontId);
 
   /**
-   * @copydoc Dali::TextAbstraction::FontClient::AddCustomFontDirectory()
+   * @brief Get the harfbuzz font data of font.
+   *
+   * @param fontId The font id.
+   * @return The harfbuzz font data, or nullptr if failed.
    */
-  bool AddCustomFontDirectory(const FontPath& path);
+  HarfBuzzFontHandle GetHarfBuzzFont(FontId fontId);
 
 private:
   /**
index 39e0cfb..1799eb2 100644 (file)
@@ -107,6 +107,14 @@ struct BitmapFontCacheItem : public FontCacheItemInterface
   }
 
   /**
+   * @copydoc FontCacheItemInterface::GetHarfBuzzFont()
+   */
+  HarfBuzzFontHandle GetHarfBuzzFont(const uint32_t& horizontalDpi, const uint32_t& verticalDpi) override
+  {
+    return nullptr;
+  }
+
+  /**
    * @copydoc FontCacheItemInterface::HasItalicStyle()
    */
   bool HasItalicStyle() const override
index 1d042d5..c5cce86 100644 (file)
  * limitations under the License.
  */
 
+// INTERNAL INCLUDES
 #include <dali/devel-api/text-abstraction/font-client.h>
 #include <dali/devel-api/text-abstraction/font-metrics.h>
 #include <dali/devel-api/text-abstraction/glyph-info.h>
+#include <dali/internal/text/text-abstraction/font-client-impl.h> // for HarfBuzzFontHandle
 
+// EXTERNAL INCLUDES
 #include <ft2build.h>
 #include FT_FREETYPE_H
 
@@ -96,6 +99,15 @@ struct FontCacheItemInterface
   virtual FT_Face GetTypeface() const = 0;
 
   /**
+   * Get the harfbuzz font struct for this font.
+   *
+   * @param[in] horizontalDpi Horizontal DPI for this harfbuzz font.
+   * @param[in] verticalDpi Vertical DPI for this harfbuzz font.
+   * @return the harfbuzz font data, or nullptr if failed.
+   */
+  virtual HarfBuzzFontHandle GetHarfBuzzFont(const uint32_t& horizontalDpi, const uint32_t& verticalDpi) = 0;
+
+  /**
    * @return true if this font has an italic style
    */
   virtual bool HasItalicStyle() const = 0;
index 6c0c264..4ac6bd0 100644 (file)
@@ -272,6 +272,10 @@ FontClient::Plugin::Plugin(unsigned int horizontalDpi,
   mVectorFontCache(nullptr),
   mEllipsisCache(),
   mEmbeddedItemCache(),
+  mLatestFoundFontDescription(),
+  mLatestFoundFontDescriptionId(0u),
+  mLatestFoundCacheKey(0, 0),
+  mLatestFoundCacheIndex(0u),
   mDefaultFontDescriptionCached(false),
   mIsAtlasLimitationEnabled(TextAbstraction::FontClient::DEFAULT_ATLAS_LIMITATION_ENABLED),
   mCurrentMaximumBlockSizeFitInAtlas(TextAbstraction::FontClient::MAX_SIZE_FIT_IN_ATLAS)
@@ -338,6 +342,9 @@ void FontClient::Plugin::ClearCache()
   mEmbeddedItemCache.Clear();
   mBitmapFontCache.clear();
 
+  mLatestFoundFontDescription.family.clear();
+  mLatestFoundCacheKey = FontDescriptionSizeCacheKey(0, 0);
+
   mDefaultFontDescriptionCached = false;
 }
 
@@ -1262,6 +1269,16 @@ bool FontClient::Plugin::AddCustomFontDirectory(const FontPath& path)
   return FcConfigAppFontAddDir(nullptr, reinterpret_cast<const FcChar8*>(path.c_str()));
 }
 
+HarfBuzzFontHandle FontClient::Plugin::GetHarfBuzzFont(FontId fontId)
+{
+  FontCacheItemInterface* fontCacheItem = const_cast<FontCacheItemInterface*>(GetCachedFontItem(fontId));
+  if(fontCacheItem != nullptr)
+  {
+    return fontCacheItem->GetHarfBuzzFont(mDpiHorizontal, mDpiVertical); // May cache
+  }
+  return nullptr;
+}
+
 GlyphIndex FontClient::Plugin::CreateEmbeddedItem(const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat)
 {
   EmbeddedItem embeddedItem;
@@ -1760,16 +1777,37 @@ bool FontClient::Plugin::FindValidatedFont(const FontDescription& fontDescriptio
 
   fontDescriptionId = 0u;
 
+  // Fast cut if inputed family is empty.
+  if(DALI_UNLIKELY(fontDescription.family.empty()))
+  {
+    DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  validated font description not found / fontDescription.family is empty!\n");
+    return false;
+  }
+
+  // Heuristic optimize code : Compare with latest found item.
+  if((fontDescription.width == mLatestFoundFontDescription.width) &&
+     (fontDescription.weight == mLatestFoundFontDescription.weight) &&
+     (fontDescription.slant == mLatestFoundFontDescription.slant) &&
+     (fontDescription.family == mLatestFoundFontDescription.family))
+  {
+    fontDescriptionId = mLatestFoundFontDescriptionId;
+
+    DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  validated font description same as latest, id : %d\n", fontDescriptionId);
+    return true;
+  }
+
   for(const auto& item : mValidatedFontCache)
   {
-    if(!fontDescription.family.empty() &&
-       (fontDescription.family == item.fontDescription.family) &&
-       (fontDescription.width == item.fontDescription.width) &&
+    if((fontDescription.width == item.fontDescription.width) &&
        (fontDescription.weight == item.fontDescription.weight) &&
-       (fontDescription.slant == item.fontDescription.slant))
+       (fontDescription.slant == item.fontDescription.slant) &&
+       (fontDescription.family == item.fontDescription.family))
     {
       fontDescriptionId = item.index;
 
+      mLatestFoundFontDescription   = fontDescription;
+      mLatestFoundFontDescriptionId = fontDescriptionId;
+
       DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  validated font description found, id : %d\n", fontDescriptionId);
       return true;
     }
@@ -1819,13 +1857,25 @@ bool FontClient::Plugin::FindFont(FontDescriptionId fontDescriptionId,
 
   fontCacheIndex = 0u;
 
-  FontDescriptionSizeCacheKey key(fontDescriptionId, requestedPointSize);
+  const FontDescriptionSizeCacheKey key(fontDescriptionId, requestedPointSize);
+
+  // Heuristic optimize code : Compare with latest found item.
+  if(key == mLatestFoundCacheKey)
+  {
+    fontCacheIndex = mLatestFoundCacheIndex;
+
+    DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  font same as latest, index of font cache : %d\n", fontCacheIndex);
+    return true;
+  }
 
   const auto& iter = mFontDescriptionSizeCache.find(key);
   if(iter != mFontDescriptionSizeCache.cend())
   {
     fontCacheIndex = iter->second;
 
+    mLatestFoundCacheKey   = key;
+    mLatestFoundCacheIndex = fontCacheIndex;
+
     DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "  font found, index of font cache : %d\n", fontCacheIndex);
     return true;
   }
index 97bd754..bef0f89 100644 (file)
@@ -414,6 +414,11 @@ public:
    */
   bool AddCustomFontDirectory(const FontPath& path);
 
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetHarfBuzzFont()
+   */
+  HarfBuzzFontHandle GetHarfBuzzFont(FontId fontId);
+
 private:
   /**
    * @brief Caches the fonts present in the platform.
@@ -615,6 +620,12 @@ private:
   Vector<EmbeddedItem>              mEmbeddedItemCache; ///< Cache embedded items.
   std::vector<BitmapFontCacheItem>  mBitmapFontCache;   ///< Stores bitmap fonts.
 
+  FontDescription   mLatestFoundFontDescription; ///< Latest found font description and id in FindValidatedFont()
+  FontDescriptionId mLatestFoundFontDescriptionId;
+
+  FontDescriptionSizeCacheKey mLatestFoundCacheKey; ///< Latest found font description and id in FindFont()
+  FontCacheIndex              mLatestFoundCacheIndex;
+
   bool mDefaultFontDescriptionCached : 1; ///< Whether the default font is cached or not
 
   bool    mIsAtlasLimitationEnabled : 1;      ///< Whether the validation on maximum atlas block size, then reduce block size to fit into it is enabled or not.
index dcde3e7..dd45035 100644 (file)
@@ -72,6 +72,7 @@ FontFaceCacheItem::FontFaceCacheItem(FT_Library&        freeTypeLibrary,
 : mFreeTypeLibrary(freeTypeLibrary),
   mFreeTypeFace(ftFace),
   mGlyphCacheManager(new GlyphCacheManager(mFreeTypeFace, GetMaxNumberOfGlyphCache())),
+  mHarfBuzzProxyFont(),
   mPath(path),
   mRequestedPointSize(requestedPointSize),
   mFaceIndex(face),
@@ -100,6 +101,7 @@ FontFaceCacheItem::FontFaceCacheItem(FT_Library&        freeTypeLibrary,
 : mFreeTypeLibrary(freeTypeLibrary),
   mFreeTypeFace(ftFace),
   mGlyphCacheManager(new GlyphCacheManager(mFreeTypeFace, GetMaxNumberOfGlyphCache())),
+  mHarfBuzzProxyFont(),
   mPath(path),
   mRequestedPointSize(requestedPointSize),
   mFaceIndex(face),
@@ -121,7 +123,8 @@ FontFaceCacheItem::FontFaceCacheItem(FontFaceCacheItem&& rhs)
 : mFreeTypeLibrary(rhs.mFreeTypeLibrary)
 {
   mFreeTypeFace       = rhs.mFreeTypeFace;
-  mGlyphCacheManager  = rhs.mGlyphCacheManager;
+  mGlyphCacheManager  = std::move(rhs.mGlyphCacheManager);
+  mHarfBuzzProxyFont  = std::move(rhs.mHarfBuzzProxyFont);
   mPath               = std::move(rhs.mPath);
   mRequestedPointSize = rhs.mRequestedPointSize;
   mFaceIndex          = rhs.mFaceIndex;
@@ -135,8 +138,7 @@ FontFaceCacheItem::FontFaceCacheItem(FontFaceCacheItem&& rhs)
   mIsFixedSizeBitmap  = rhs.mIsFixedSizeBitmap;
   mHasColorTables     = rhs.mHasColorTables;
 
-  rhs.mGlyphCacheManager = nullptr;
-  rhs.mFreeTypeFace      = nullptr;
+  rhs.mFreeTypeFace = nullptr;
 }
 
 FontFaceCacheItem::~FontFaceCacheItem()
@@ -144,7 +146,12 @@ FontFaceCacheItem::~FontFaceCacheItem()
   // delete glyph cache manager before free face.
   if(mGlyphCacheManager)
   {
-    delete mGlyphCacheManager;
+    mGlyphCacheManager.reset();
+  }
+
+  if(mHarfBuzzProxyFont)
+  {
+    mHarfBuzzProxyFont.reset();
   }
 
   // Free face.
@@ -507,4 +514,14 @@ GlyphIndex FontFaceCacheItem::GetGlyphIndex(Character character, Character varia
   return FT_Face_GetCharVariantIndex(mFreeTypeFace, character, variantSelector);
 }
 
+HarfBuzzFontHandle FontFaceCacheItem::GetHarfBuzzFont(const uint32_t& horizontalDpi, const uint32_t& verticalDpi)
+{
+  // Create new harfbuzz font only first time or DPI changed.
+  if(DALI_UNLIKELY(!mHarfBuzzProxyFont || mHarfBuzzProxyFont->mHorizontalDpi != horizontalDpi || mHarfBuzzProxyFont->mVerticalDpi != verticalDpi))
+  {
+    mHarfBuzzProxyFont.reset(new HarfBuzzProxyFont(mFreeTypeFace, mRequestedPointSize, horizontalDpi, verticalDpi, mGlyphCacheManager.get()));
+  }
+  return mHarfBuzzProxyFont->GetHarfBuzzFont();
+}
+
 } // namespace Dali::TextAbstraction::Internal
index e1e0c6e..08baff7 100644 (file)
 // INTERNAL INCLUDES
 #include <dali/internal/text/text-abstraction/plugin/font-cache-item-interface.h>
 #include <dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.h>
+#include <dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.h>
 
 // EXTERNAL INCLUDES
 #include <fontconfig/fontconfig.h>
+#include <memory> // for std::unique_ptr
 
 // EXTERNAL INCLUDES
 #include <ft2build.h>
@@ -114,6 +116,11 @@ struct FontFaceCacheItem : public FontCacheItemInterface
   }
 
   /**
+   * @copydoc FontCacheItemInterface::GetHarfBuzzFont()
+   */
+  HarfBuzzFontHandle GetHarfBuzzFont(const uint32_t& horizontalDpi, const uint32_t& verticalDpi) override;
+
+  /**
    * @copydoc FontCacheItemInterface::HasItalicStyle()
    */
   bool HasItalicStyle() const override
@@ -121,21 +128,25 @@ struct FontFaceCacheItem : public FontCacheItemInterface
     return (0u != (mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC));
   }
 
-  FT_Library&        mFreeTypeLibrary;       ///< A handle to a FreeType library instance.
-  FT_Face            mFreeTypeFace;          ///< The FreeType face.
-  GlyphCacheManager* mGlyphCacheManager;     ///< The glyph cache manager. It will cache this face's glyphs.
-  FontPath           mPath;                  ///< The path to the font file name.
-  PointSize26Dot6    mRequestedPointSize;    ///< The font point size.
-  FaceIndex          mFaceIndex;             ///< The face index.
-  FontMetrics        mMetrics;               ///< The font metrics.
-  _FcCharSet*        mCharacterSet;          ///< Pointer with the range of characters.
-  int                mFixedSizeIndex;        ///< Index to the fixed size table for the requested size.
-  float              mFixedWidthPixels;      ///< The height in pixels (fixed size bitmaps only)
-  float              mFixedHeightPixels;     ///< The height in pixels (fixed size bitmaps only)
-  unsigned int       mVectorFontId;          ///< The ID of the equivalent vector-based font
-  FontId             mFontId;                ///< Index to the vector with the cache of font's ids.
-  bool               mIsFixedSizeBitmap : 1; ///< Whether the font has fixed size bitmaps.
-  bool               mHasColorTables : 1;    ///< Whether the font has color tables.
+public:
+  FT_Library& mFreeTypeLibrary; ///< A handle to a FreeType library instance.
+  FT_Face     mFreeTypeFace;    ///< The FreeType face.
+
+  std::unique_ptr<GlyphCacheManager> mGlyphCacheManager; ///< The glyph cache manager. It will cache this face's glyphs.
+  std::unique_ptr<HarfBuzzProxyFont> mHarfBuzzProxyFont; ///< The harfbuzz font. It will store harfbuzz relate data.
+
+  FontPath        mPath;                  ///< The path to the font file name.
+  PointSize26Dot6 mRequestedPointSize;    ///< The font point size.
+  FaceIndex       mFaceIndex;             ///< The face index.
+  FontMetrics     mMetrics;               ///< The font metrics.
+  _FcCharSet*     mCharacterSet;          ///< Pointer with the range of characters.
+  int             mFixedSizeIndex;        ///< Index to the fixed size table for the requested size.
+  float           mFixedWidthPixels;      ///< The height in pixels (fixed size bitmaps only)
+  float           mFixedHeightPixels;     ///< The height in pixels (fixed size bitmaps only)
+  unsigned int    mVectorFontId;          ///< The ID of the equivalent vector-based font
+  FontId          mFontId;                ///< Index to the vector with the cache of font's ids.
+  bool            mIsFixedSizeBitmap : 1; ///< Whether the font has fixed size bitmaps.
+  bool            mHasColorTables : 1;    ///< Whether the font has color tables.
 };
 
 } // namespace Dali::TextAbstraction::Internal
diff --git a/dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.cpp b/dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.cpp
new file mode 100644 (file)
index 0000000..5d62a95
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.h>
+
+// EXTERNAL INCLUDES
+#include FT_GLYPH_H
+#include <harfbuzz/hb-ft.h>
+#include <harfbuzz/hb.h>
+
+#if defined(DEBUG_ENABLED)
+extern Dali::Integration::Log::Filter* gFontClientLogFilter;
+#endif
+
+namespace Dali::TextAbstraction::Internal
+{
+/**
+ * @brief Helper class to create and destroy harfbuzz font, and hold data in harfbuzz callback
+ * It also cache informations what harfbuzz font need to be created.
+ */
+struct HarfBuzzProxyFont::Impl
+{
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] freeTypeFace The FreeType face.
+   * @param[in] glyphCacheManager Glyph caching system for this harfbuzz font. It will be used as harfbuzz callback data.
+   */
+  Impl(FT_Face freeTypeFace, GlyphCacheManager* glyphCacheManager)
+  : mFreeTypeFace(freeTypeFace),
+    mGlyphCacheManager(glyphCacheManager),
+    mHarfBuzzFont(nullptr)
+  {
+  }
+
+  // Destructor
+  ~Impl()
+  {
+    if(mHarfBuzzFont)
+    {
+      // It will reduce reference of freetype face automatically.
+      hb_font_destroy(mHarfBuzzFont);
+    }
+  }
+
+public:
+  /**
+   * @brief Create new harfbuzz font.
+   *
+   * @param[in] requestedPointSize The requiested point size of font.
+   * @param[in] horizontalDpi Horizontal DPI.
+   * @param[in] verticalDpi Vertical DPI.
+   */
+  void CreateHarfBuzzFont(const PointSize26Dot6& requestedPointSize, const uint32_t& horizontalDpi, const uint32_t& verticalDpi);
+
+private:
+  /**
+   * @brief Register harfbuzz callback functions into current harfbuzz font.
+   */
+  void SetHarfBuzzFunctions();
+
+public:
+  FT_Face            mFreeTypeFace;      ///< The FreeType face. Owned from font-face-cache-item.
+  GlyphCacheManager* mGlyphCacheManager; ///< Glyph caching system for this harfbuzz font. Owned from font-face-cache-item.
+
+  hb_font_t* mHarfBuzzFont; ///< Harfbuzz font handle integrated with FT_Face.
+};
+
+HarfBuzzProxyFont::HarfBuzzProxyFont(FT_Face freeTypeFace, const PointSize26Dot6& requestedPointSize, const uint32_t& horizontalDpi, const uint32_t& verticalDpi, GlyphCacheManager* glyphCacheManager)
+: mHorizontalDpi(horizontalDpi),
+  mVerticalDpi(verticalDpi),
+  mImpl(new Impl(freeTypeFace, glyphCacheManager))
+{
+  mImpl->CreateHarfBuzzFont(requestedPointSize, mHorizontalDpi, mVerticalDpi);
+}
+
+HarfBuzzProxyFont::~HarfBuzzProxyFont()
+{
+  if(mImpl)
+  {
+    delete mImpl;
+  }
+}
+
+HarfBuzzFontHandle HarfBuzzProxyFont::GetHarfBuzzFont() const
+{
+  if(mImpl)
+  {
+    return static_cast<HarfBuzzFontHandle>(mImpl->mHarfBuzzFont);
+  }
+  return nullptr;
+}
+
+// Collection of harfbuzz custom callback functions.
+// Reference : https://github.com/harfbuzz/harfbuzz/blob/main/src/hb-ft.cc
+namespace
+{
+/**
+ * @brief Get glyph informations by dali glyph cache system.
+ *
+ * @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.
+ * @return True if we success to get some glyph data. False otherwise.
+ */
+static bool GetGlyphCacheData(void* font_data, const GlyphIndex& glyphIndex, GlyphCacheManager::GlyphCacheData& glyphData)
+{
+  HarfBuzzProxyFont::Impl* impl = reinterpret_cast<HarfBuzzProxyFont::Impl*>(font_data);
+
+  // Note : HarfBuzz used only FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING internally.
+  if(DALI_LIKELY(impl && impl->mGlyphCacheManager))
+  {
+    FT_Error error;
+    return impl->mGlyphCacheManager->GetGlyphCacheDataFromIndex(glyphIndex, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING, false, glyphData, error);
+  }
+  return false;
+}
+
+/**
+ * @brief Calculate font extents value both in vertical and horizontal.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[out] extents Extents value of font. (scale as 26.6)
+ * @param[in] user_data Registered user data.
+ * @return True if we success to get font extents. False otherwise.
+ */
+static hb_bool_t FontExtentsFunc(hb_font_t* font, void* font_data, hb_font_extents_t* extents, void* user_data)
+{
+  HarfBuzzProxyFont::Impl* impl = reinterpret_cast<HarfBuzzProxyFont::Impl*>(font_data);
+
+  if(DALI_LIKELY(impl && impl->mFreeTypeFace))
+  {
+    FT_Size_Metrics& ftMetrics = impl->mFreeTypeFace->size->metrics;
+
+    extents->ascender  = ftMetrics.ascender;
+    extents->descender = ftMetrics.descender;
+    extents->line_gap  = ftMetrics.height - (extents->ascender - extents->descender);
+
+    return true;
+  }
+  return false;
+}
+
+/**
+ * @brief Convert from character into index of glyph.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[in] character The value of character what we want to get index.
+ * @param[out] glyphIndex Index of glyph that current font face used.
+ * @param[in] user_data Registered user data.
+ * @return True if we success to convert.
+ */
+static hb_bool_t GlyphNormalIndexConvertFunc(hb_font_t* font, void* font_data, hb_codepoint_t character, hb_codepoint_t* glyphIndex, void* user_data)
+{
+  HarfBuzzProxyFont::Impl* impl = reinterpret_cast<HarfBuzzProxyFont::Impl*>(font_data);
+
+  if(DALI_LIKELY(impl && impl->mFreeTypeFace))
+  {
+    *glyphIndex = FT_Get_Char_Index(impl->mFreeTypeFace, character);
+    return *glyphIndex != 0;
+  }
+  return false;
+}
+
+/**
+ * @brief Convert from character and variant selector into index of glyph.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[in] character The value of character what we want to get index.
+ * @param[in] variantSelector Variant selector.
+ * @param[out] glyphIndex Index of glyph that current font face used.
+ * @param[in] user_data Registered user data.
+ * @return True if we success to convert.
+ */
+static hb_bool_t GlyphVariantIndexConvertFunc(hb_font_t* font, void* font_data, hb_codepoint_t character, hb_codepoint_t variantSelector, hb_codepoint_t* glyphIndex, void* user_data)
+{
+  HarfBuzzProxyFont::Impl* impl = reinterpret_cast<HarfBuzzProxyFont::Impl*>(font_data);
+
+  if(DALI_LIKELY(impl && impl->mFreeTypeFace))
+  {
+    *glyphIndex = FT_Face_GetCharVariantIndex(impl->mFreeTypeFace, character, variantSelector);
+    return *glyphIndex != 0;
+  }
+  return false;
+}
+
+/**
+ * @brief Calculate glyph advance value in horizontal.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[in] glyphIndex Index of glyph.
+ * @param[in] user_data Registered user data.
+ * @return Horizontal advance value of glyphIndex. (scale as 26.6)
+ */
+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))
+  {
+    // 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.
+    return static_cast<hb_position_t>(glyphData.mGlyphMetrics.horiAdvance);
+  }
+  return 0;
+}
+/**
+ * @brief Calculate glyph advance value in vertical.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[in] glyphIndex Index of glyph.
+ * @param[in] user_data Registered user data.
+ * @return Vertical advance value of glyphIndex. (scale as 26.6)
+ */
+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))
+  {
+    // 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.
+    return static_cast<hb_position_t>(glyphData.mGlyphMetrics.vertAdvance);
+  }
+  return 0;
+}
+
+/**
+ * @brief Calculate glyph origin position value in horizontal.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl that register this callback as void* type.
+ * @param[in] glyphIndex Index of glyph.
+ * @param[out] x Origin position x (scale as 26.6)
+ * @param[out] y Origin position y (scale as 26.6)
+ * @param[in] user_data Registered user data.
+ * @return True if we get data successfully. False if some error occured.
+ */
+static hb_bool_t GlyphHorizontalOriginFunc(hb_font_t* font, void* font_data, hb_codepoint_t glyphIndex, hb_position_t* x, hb_position_t* y, void* user_data)
+{
+  // Nothing to do
+  return true;
+}
+/**
+ * @brief Calculate glyph origin position value in vertical.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[in] glyphIndex Index of glyph.
+ * @param[out] x Origin position x (scale as 26.6)
+ * @param[out] y Origin position y (scale as 26.6)
+ * @param[in] user_data Registered user data.
+ * @return True if we get data successfully. False if some error occured.
+ */
+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))
+  {
+    *x = glyphData.mGlyphMetrics.horiBearingX - glyphData.mGlyphMetrics.vertBearingX;
+    *y = glyphData.mGlyphMetrics.horiBearingY + glyphData.mGlyphMetrics.vertBearingY;
+    return true;
+  }
+  return false;
+}
+
+/**
+ * @brief Calculate glyph kerning value in horizontal.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[in] glyphIndex1 First index of glyph to get kerning.
+ * @param[in] glyphIndex2 Second index of glyph to get kerning.
+ * @param[in] user_data Registered user data.
+ * @return Horizontal kerning position. (scale as 26.6)
+ */
+static hb_position_t GlyphHorizontalKerningFunc(hb_font_t* font, void* font_data, hb_codepoint_t glyphIndex1, hb_codepoint_t glyphIndex2, void* user_data)
+{
+  HarfBuzzProxyFont::Impl* impl = reinterpret_cast<HarfBuzzProxyFont::Impl*>(font_data);
+
+  if(DALI_LIKELY(impl && impl->mFreeTypeFace))
+  {
+    FT_Error  error;
+    FT_Vector kerning;
+
+    error = FT_Get_Kerning(impl->mFreeTypeFace, glyphIndex1, glyphIndex2, FT_KERNING_UNSCALED, &kerning);
+    if(error == FT_Err_Ok)
+    {
+      return kerning.x;
+    }
+  }
+  return 0;
+}
+/**
+ * @brief Calculate glyph kerning value in vertical.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[in] glyphIndex1 First index of glyph to get kerning.
+ * @param[in] glyphIndex2 Second index of glyph to get kerning.
+ * @param[in] user_data Registered user data.
+ * @return Vertical kerning position. (scale as 26.6)
+ */
+static hb_position_t GlyphVerticalKerningFunc(hb_font_t* font, void* font_data, hb_codepoint_t glyphIndex1, hb_codepoint_t glyphIndex2, void* user_data)
+{
+  // FreeType doesn't support vertical kerning
+  return 0;
+}
+
+/**
+ * @brief Calculate glyph extents.
+ *
+ * @param[in] font Current harfbuzz font data.
+ * @param[in] font_data HarfBuzzProxyFont::Impl pointer that register this callback as void* type.
+ * @param[in] glyphIndex Index of glyph.
+ * @param[out] extents Extents value of glyph. (scale as 26.6)
+ * @param[in] user_data Registered user data.
+ * @return True if we get data successfully. False if some error occured.
+ */
+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))
+  {
+    extents->x_bearing = glyphData.mGlyphMetrics.horiBearingX;
+    extents->y_bearing = glyphData.mGlyphMetrics.horiBearingY;
+    extents->width     = glyphData.mGlyphMetrics.width;
+    extents->height    = glyphData.mGlyphMetrics.height;
+    return true;
+  }
+  return false;
+}
+
+} // namespace
+
+void HarfBuzzProxyFont::Impl::CreateHarfBuzzFont(const PointSize26Dot6& requestedPointSize, const uint32_t& horizontalDpi, const uint32_t& verticalDpi)
+{
+  // Destroy previous hb_font_t if exist.
+  if(mHarfBuzzFont)
+  {
+    // It will reduce reference of freetype face automatically.
+    hb_font_destroy(mHarfBuzzFont);
+    mHarfBuzzFont = nullptr;
+  }
+
+  if(mFreeTypeFace)
+  {
+    // Before create hb_font_t, we must set FT_Char_Size
+    FT_Set_Char_Size(mFreeTypeFace,
+                     0u,
+                     requestedPointSize,
+                     horizontalDpi,
+                     verticalDpi);
+
+    // Create font face with increase font face's reference.
+    mHarfBuzzFont = hb_ft_font_create_referenced(mFreeTypeFace);
+
+    SetHarfBuzzFunctions();
+
+    if(mHarfBuzzFont)
+    {
+      DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::HarfBuzzManager::GetHarfBuzzFont. Create new harfbuzz font : %p freetype face : %p. Requested point size : %u, dpi : horizon %u vertial %u\n", mHarfBuzzFont, mFreeTypeFace, requestedPointSize, horizontalDpi, verticalDpi);
+    }
+    else
+    {
+      DALI_LOG_ERROR("ERROR! failed to create harfbuzz font.");
+    }
+  }
+  else
+  {
+    DALI_LOG_ERROR("ERROR! freetype face is null! something unknown problem occured.");
+  }
+}
+
+void HarfBuzzProxyFont::Impl::SetHarfBuzzFunctions()
+{
+  if(mHarfBuzzFont)
+  {
+    hb_font_funcs_t* customFunctions = hb_font_funcs_create();
+
+    if(customFunctions)
+    {
+      // Bind custom functions here
+      hb_font_funcs_set_font_h_extents_func(customFunctions, FontExtentsFunc, 0, 0);
+      hb_font_funcs_set_font_v_extents_func(customFunctions, FontExtentsFunc, 0, 0);
+
+      hb_font_funcs_set_nominal_glyph_func(customFunctions, GlyphNormalIndexConvertFunc, 0, 0);
+      hb_font_funcs_set_variation_glyph_func(customFunctions, GlyphVariantIndexConvertFunc, 0, 0);
+
+      hb_font_funcs_set_glyph_h_advance_func(customFunctions, GlyphHorizontalAdvanceFunc, 0, 0);
+      hb_font_funcs_set_glyph_v_advance_func(customFunctions, GlyphVerticalAdvanceFunc, 0, 0);
+      hb_font_funcs_set_glyph_extents_func(customFunctions, GlyphExtentsFunc, 0, 0);
+
+      hb_font_funcs_set_glyph_h_origin_func(customFunctions, GlyphHorizontalOriginFunc, 0, 0);
+      hb_font_funcs_set_glyph_v_origin_func(customFunctions, GlyphVerticalOriginFunc, 0, 0);
+      hb_font_funcs_set_glyph_h_kerning_func(customFunctions, GlyphHorizontalKerningFunc, 0, 0);
+      hb_font_funcs_set_glyph_v_kerning_func(customFunctions, GlyphVerticalKerningFunc, 0, 0);
+
+      // Set custom functions into our own harfbuzz font
+      hb_font_set_funcs(mHarfBuzzFont, customFunctions, this, 0);
+
+      // We must release functions type what we create.
+      hb_font_funcs_destroy(customFunctions);
+    }
+    else
+    {
+      DALI_LOG_ERROR("ERROR! Fail to create custom harfbuzz functions.");
+
+      // Something wrong while create harfbuzz font. Destory it.
+      // It will reduce reference of freetype face automatically.
+      hb_font_destroy(mHarfBuzzFont);
+      mHarfBuzzFont = nullptr;
+    }
+  }
+}
+
+} // namespace Dali::TextAbstraction::Internal
diff --git a/dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.h b/dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.h
new file mode 100644 (file)
index 0000000..a14f2f7
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef DALI_TEXT_ABSTRACTION_INTERNAL_HARFBUZZ_PROXY_FONT_H
+#define DALI_TEXT_ABSTRACTION_INTERNAL_HARFBUZZ_PROXY_FONT_H
+
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+#include <dali/internal/text/text-abstraction/font-client-impl.h> // for HarfBuzzFontHandle
+#include <dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.h>
+
+// EXTERNAL INCLUDES
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+namespace Dali::TextAbstraction::Internal
+{
+/**
+ * @brief Helper class to shape of FT_Face by harfbuzz library.
+ * @note Current class only be used for font face cache item.
+ */
+class HarfBuzzProxyFont
+{
+public:
+  /**
+   * @brief Constructor harfbuzz font data integrated with FreeType face and our font face cache item.
+   *
+   * @param[in] freeTypeFace The FreeType face.
+   * @param[in] requestedPointSize The requiested point size of font.
+   * @param[in] horizontalDpi Horizontal DPI.
+   * @param[in] verticalDpi Vertical DPI.
+   * @param[in] glyphCacheManager Glyph caching system for this harfbuzz font. It will be used as harfbuzz callback data.
+   */
+  HarfBuzzProxyFont(FT_Face freeTypeFace, const PointSize26Dot6& requestedPointSize, const uint32_t& horizontalDpi, const uint32_t& verticalDpi, GlyphCacheManager* glyphCacheManager);
+
+  // Destructor
+  ~HarfBuzzProxyFont();
+
+public:
+  // Public API area.
+
+  /**
+   * @brief Get the created harfbuzz font data integrated with FreeType face and our font face cache item.
+   *
+   * @return Created harfbuzz font data. or nullptr if there is something error.
+   */
+  HarfBuzzFontHandle GetHarfBuzzFont() const;
+
+private:
+  // Private API area.
+  HarfBuzzProxyFont()                             = delete; // Do not use default construct
+  HarfBuzzProxyFont(const HarfBuzzProxyFont& rhs) = delete; // Do not use copy construct
+  HarfBuzzProxyFont(HarfBuzzProxyFont&& rhs)      = delete; // Do not use move construct
+public:
+  struct Impl;             // Harfbuzz callback can access this struct.
+  uint32_t mHorizontalDpi; ///< Horizontal DPI.
+  uint32_t mVerticalDpi;   ///< VerticalDPI.
+
+private:
+  // Private member value area.
+  Impl* mImpl;
+};
+
+} // namespace Dali::TextAbstraction::Internal
+
+#endif //DALI_TEXT_ABSTRACTION_INTERNAL_HARFBUZZ_PROXY_FONT_H
index 89d6498..f966fd6 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.
@@ -151,6 +151,14 @@ struct Shaping::Plugin
     {
       case FontDescription::FACE_FONT:
       {
+        // Get our harfbuzz font struct
+        hb_font_t* harfBuzzFont = reinterpret_cast<hb_font_t*>(fontClientImpl.GetHarfBuzzFont(fontId));
+        if(nullptr == harfBuzzFont)
+        {
+          // Nothing to do if the harfBuzzFont is null.
+          return 0u;
+        }
+
         // Reserve some space to avoid reallocations.
         const Length numberOfGlyphs = static_cast<Length>(1.3f * static_cast<float>(numberOfCharacters));
         mIndices.Reserve(numberOfGlyphs);
@@ -158,28 +166,6 @@ struct Shaping::Plugin
         mCharacterMap.Reserve(numberOfGlyphs);
         mOffset.Reserve(2u * numberOfGlyphs);
 
-        // Retrieve a FreeType font's face.
-        FT_Face face = fontClientImpl.GetFreetypeFace(fontId);
-        if(nullptr == face)
-        {
-          // Nothing to do if the face is null.
-          return 0u;
-        }
-
-        unsigned int horizontalDpi = 0u;
-        unsigned int verticalDpi   = 0u;
-        fontClient.GetDpi(horizontalDpi, verticalDpi);
-
-        FT_Set_Char_Size(face,
-                         0u,
-                         fontClient.GetPointSize(fontId),
-                         horizontalDpi,
-                         verticalDpi);
-
-        /* Get our harfbuzz font struct */
-        hb_font_t* harfBuzzFont;
-        harfBuzzFont = hb_ft_font_create(face, NULL);
-
         /* Create a buffer for harfbuzz to use */
         hb_buffer_t* harfBuzzBuffer = hb_buffer_create();
 
@@ -276,7 +262,6 @@ struct Shaping::Plugin
 
         /* Cleanup */
         hb_buffer_destroy(harfBuzzBuffer);
-        hb_font_destroy(harfBuzzFont);
         break;
       }
       case FontDescription::BITMAP_FONT:
index b4aca26..8b0f1f0 100644 (file)
@@ -92,8 +92,8 @@ Window::Window()
   mTransitionEffectEventSignal(),
   mKeyboardRepeatSettingsChangedSignal(),
   mAuxiliaryMessageSignal(),
-  mLastKeyEevent(),
-  mLastTouchEevent(),
+  mLastKeyEvent(),
+  mLastTouchEvent(),
   mIsTransparent(false),
   mIsFocusAcceptable(true),
   mIconified(false),
@@ -891,7 +891,7 @@ void Window::OnUpdatePositionSize(Dali::PositionSize& positionSize)
 
 void Window::OnTouchPoint(Dali::Integration::Point& point, int timeStamp)
 {
-  mLastTouchEevent = Dali::Integration::NewTouchEvent(timeStamp, point);
+  mLastTouchEvent = Dali::Integration::NewTouchEvent(timeStamp, point);
   FeedTouchPoint(point, timeStamp);
 }
 
@@ -902,7 +902,7 @@ void Window::OnWheelEvent(Dali::Integration::WheelEvent& wheelEvent)
 
 void Window::OnKeyEvent(Dali::Integration::KeyEvent& keyEvent)
 {
-  mLastKeyEevent = Dali::DevelKeyEvent::New(keyEvent.keyName, keyEvent.logicalKey, keyEvent.keyString, keyEvent.keyCode, keyEvent.keyModifier, keyEvent.time, static_cast<Dali::KeyEvent::State>(keyEvent.state), keyEvent.compose, keyEvent.deviceName, keyEvent.deviceClass, keyEvent.deviceSubclass);
+  mLastKeyEvent = Dali::DevelKeyEvent::New(keyEvent.keyName, keyEvent.logicalKey, keyEvent.keyString, keyEvent.keyCode, keyEvent.keyModifier, keyEvent.time, static_cast<Dali::KeyEvent::State>(keyEvent.state), keyEvent.compose, keyEvent.deviceName, keyEvent.deviceClass, keyEvent.deviceSubclass);
   FeedKeyEvent(keyEvent);
 }
 
@@ -1217,12 +1217,12 @@ bool Window::IsWindowRotating() const
 
 const Dali::KeyEvent& Window::GetLastKeyEvent() const
 {
-  return mLastKeyEevent;
+  return mLastKeyEvent;
 }
 
 const Dali::TouchEvent& Window::GetLastTouchEvent() const
 {
-  return mLastTouchEevent;
+  return mLastTouchEvent;
 }
 
 } // namespace Adaptor
index d2a9b77..b1fa39a 100644 (file)
@@ -747,8 +747,8 @@ private:
   AuxiliaryMessageSignalType              mAuxiliaryMessageSignal;
   AccessibilityHighlightSignalType        mAccessibilityHighlightSignal;
 
-  Dali::KeyEvent   mLastKeyEevent;
-  Dali::TouchEvent mLastTouchEevent;
+  Dali::KeyEvent   mLastKeyEvent;
+  Dali::TouchEvent mLastTouchEvent;
 
   bool mIsTransparent : 1;
   bool mIsFocusAcceptable : 1;
index 3cdcc90..839ffa4 100644 (file)
@@ -27,7 +27,7 @@ namespace Dali
 {
 const unsigned int ADAPTOR_MAJOR_VERSION = 2;
 const unsigned int ADAPTOR_MINOR_VERSION = 1;
-const unsigned int ADAPTOR_MICRO_VERSION = 25;
+const unsigned int ADAPTOR_MICRO_VERSION = 27;
 const char* const  ADAPTOR_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index a253a7a..144b9f6 100644 (file)
@@ -17,7 +17,7 @@
 
 Name:       dali2-adaptor
 Summary:    The DALi Tizen Adaptor
-Version:    2.1.25
+Version:    2.1.27
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT