From 87fedb101d54c95bc6afb3bcfc3b10cf01db5715 Mon Sep 17 00:00:00 2001 From: "Eunki, Hong" Date: Thu, 23 Mar 2023 23:03:58 +0900 Subject: [PATCH] Make GlyphCacheManager cache shared_ptr of GlyphCacheData Previously, font-face-glyph-cache-manager release GlyphCacheData by manager side. Now, let we keep cache data by shared_ptr, 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 --- .../plugin/font-face-cache-item.cpp | 56 ++--- .../plugin/font-face-glyph-cache-manager.cpp | 196 +++++++++++------- .../plugin/font-face-glyph-cache-manager.h | 45 ++-- .../plugin/harfbuzz-proxy-font.cpp | 32 +-- 4 files changed, 203 insertions(+), 126 deletions(-) diff --git a/dali/internal/text/text-abstraction/plugin/font-face-cache-item.cpp b/dali/internal/text/text-abstraction/plugin/font-face-cache-item.cpp index b0087f280..7c7041161 100644 --- a/dali/internal/text/text-abstraction/plugin/font-face-cache-item.cpp +++ b/dali/internal/text/text-abstraction/plugin/font-face-cache-item.cpp @@ -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(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(dummyData.mGlyphMetrics.width) * FROM_266; + const float width = static_cast(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; diff --git a/dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.cpp b/dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.cpp index 097e9cddc..96817dbfc 100644 --- a/dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.cpp +++ b/dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.cpp @@ -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(-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& 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(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(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(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(destinationGlpyhData.mBitmap->width)) + if(glyphData.mBitmap->pitch == static_cast(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(destinationGlpyhData.mBitmap->width << 2u)) + if(glyphData.mBitmap->pitch == static_cast(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 diff --git a/dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.h b/dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.h index dc19c7660..521c37340 100644 --- a/dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.h +++ b/dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.h @@ -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 // EXTERNAL INCLUDES +#include // for std::shared_ptr + #include #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; + // 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; + using CacheContainer = LRUCacheContainer; CacheContainer mLRUGlyphCache; ///< LRU Cache container of glyph }; diff --git a/dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.cpp b/dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.cpp index 53d3d0fc2..13e4b1bb3 100644 --- a/dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.cpp +++ b/dali/internal/text/text-abstraction/plugin/harfbuzz-proxy-font.cpp @@ -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(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), glyphData)) + GlyphCacheManager::GlyphCacheDataPtr glyphDataPtr; + if(GetGlyphCacheData(font_data, static_cast(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), glyphData)) + GlyphCacheManager::GlyphCacheDataPtr glyphDataPtr; + if(GetGlyphCacheData(font_data, static_cast(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), glyphData)) + GlyphCacheManager::GlyphCacheDataPtr glyphDataPtr; + if(GetGlyphCacheData(font_data, static_cast(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), glyphData)) + GlyphCacheManager::GlyphCacheDataPtr glyphDataPtr; + if(!GetGlyphCacheData(font_data, static_cast(glyphIndex), glyphDataPtr)) { + GlyphCacheManager::GlyphCacheData& glyphData = *glyphDataPtr.get(); + extents->x_bearing = glyphData.mGlyphMetrics.horiBearingX; extents->y_bearing = glyphData.mGlyphMetrics.horiBearingY; extents->width = glyphData.mGlyphMetrics.width; -- 2.34.1