/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
}
bool GlyphCacheManager::GetGlyphCacheDataFromIndex(
- const FT_Face freeTypeFace,
- const GlyphIndex index,
- const FT_Int32 flag,
- const bool isBoldRequired,
- GlyphCacheData& glyphData,
- FT_Error& error)
+ const FT_Face freeTypeFace,
+ const GlyphIndex index,
+ const FT_Int32 flag,
+ const bool isBoldRequired,
+ GlyphCacheDataPtr& glyphDataPtr,
+ FT_Error& error)
{
// Append some error value here instead of FT_Err_Ok.
error = static_cast<FT_Error>(-1);
{
auto removedData = mLRUGlyphCache.Pop();
- DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Remove oldest cache for glyph : %p\n", removedData.mGlyph);
-
- // Release Glyph data resource
- removedData.ReleaseGlyphData();
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Remove oldest cache for glyph : %p\n", removedData->mGlyph);
}
+ // Create new GlyphCacheData.
+ glyphDataPtr = std::make_shared<GlyphCacheData>();
+
+ GlyphCacheData& glyphData = *glyphDataPtr.get();
+
const bool loadSuccess = LoadGlyphDataFromIndex(freeTypeFace, index, flag, isBoldRequired, glyphData, error);
if(loadSuccess)
{
// Copy and cached data.
- mLRUGlyphCache.Push(key, glyphData);
+ mLRUGlyphCache.Push(key, glyphDataPtr);
DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Create cache for face : %p, index : %u flag : %d isBold : %d isBitmap : %d, glyph : %p\n", freeTypeFace, index, static_cast<int>(flag), isBoldRequired, glyphData.mIsBitmap, glyphData.mGlyph);
}
error = FT_Err_Ok;
// We already notify that we use this glyph. And now, copy cached data.
- glyphData = mLRUGlyphCache.GetElement(iter);
+ glyphDataPtr = mLRUGlyphCache.GetElement(iter);
- DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Find cache for face : %p, index : %u flag : %d isBold : %d isBitmap : %d, glyph : %p\n", freeTypeFace, index, static_cast<int>(flag), isBoldRequired, glyphData.mIsBitmap, glyphData.mGlyph);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, "FontClient::Plugin::GlyphCacheManager::GetGlyphCacheDataFromIndex. Find cache for face : %p, index : %u flag : %d isBold : %d isBitmap : %d, glyph : %p\n", freeTypeFace, index, static_cast<int>(flag), isBoldRequired, glyphDataPtr->mIsBitmap, glyphDataPtr->mGlyph);
return true;
}
}
{
glyphData.mIsBitmap = true;
glyphData.mBitmap->buffer = (uint8_t*)malloc(bufferSize * sizeof(uint8_t)); // @note The caller is responsible for deallocating the bitmap data using free.
- memcpy(glyphData.mBitmap->buffer, freeTypeFace->glyph->bitmap.buffer, bufferSize);
+ if(DALI_UNLIKELY(!glyphData.mBitmap->buffer))
+ {
+ DALI_LOG_ERROR("malloc is failed. request malloc size : %zu\n", bufferSize * sizeof(uint8_t));
+ delete glyphData.mBitmap;
+ glyphData.mIsBitmap = false;
+ glyphData.mBitmap = nullptr;
+ error = static_cast<FT_Error>(-1);
+ }
+ else
+ {
+ memcpy(glyphData.mBitmap->buffer, freeTypeFace->glyph->bitmap.buffer, bufferSize);
+ }
}
else
{
// Skip this API if desired size is zero
return;
}
- FT_Error error;
- GlyphCacheData originGlyphData;
- if(GetGlyphCacheDataFromIndex(freeTypeFace, index, flag, isBoldRequired, originGlyphData, error))
+ FT_Error error;
+ GlyphCacheDataPtr glyphDataPtr;
+ if(GetGlyphCacheDataFromIndex(freeTypeFace, index, flag, isBoldRequired, glyphDataPtr, error))
{
- if(DALI_LIKELY(originGlyphData.mIsBitmap && originGlyphData.mBitmap))
+ GlyphCacheData& glyphData = *glyphDataPtr.get();
+ if(DALI_LIKELY(glyphData.mIsBitmap && glyphData.mBitmap))
{
- const bool requiredResize = (originGlyphData.mBitmap->rows != desiredHeight) || (originGlyphData.mBitmap->width != desiredWidth);
+ const bool requiredResize = (glyphData.mBitmap->rows != desiredHeight) || (glyphData.mBitmap->width != desiredWidth);
if(requiredResize)
{
- // originalGlyphData is copy data. For change cached information, we should access as iterator.
- const GlyphCacheKey key = GlyphCacheKey(freeTypeFace, index, flag, isBoldRequired);
- auto iter = mLRUGlyphCache.Find(key);
-
- GlyphCacheData& destinationGlpyhData = mLRUGlyphCache.GetElement(iter);
-
- const ImageDimensions inputDimensions(destinationGlpyhData.mBitmap->width, destinationGlpyhData.mBitmap->rows);
+ const ImageDimensions inputDimensions(glyphData.mBitmap->width, glyphData.mBitmap->rows);
const ImageDimensions desiredDimensions(desiredWidth, desiredHeight);
uint8_t* desiredBuffer = nullptr;
- switch(destinationGlpyhData.mBitmap->pixel_mode)
+ switch(glyphData.mBitmap->pixel_mode)
{
case FT_PIXEL_MODE_GRAY:
{
- if(destinationGlpyhData.mBitmap->pitch == static_cast<int>(destinationGlpyhData.mBitmap->width))
+ if(glyphData.mBitmap->pitch == static_cast<int>(glyphData.mBitmap->width))
{
desiredBuffer = (uint8_t*)malloc(desiredWidth * desiredHeight * sizeof(uint8_t)); // @note The caller is responsible for deallocating the bitmap data using free.
- // Resize bitmap here.
- Dali::Internal::Platform::LanczosSample1BPP(destinationGlpyhData.mBitmap->buffer,
- inputDimensions,
- destinationGlpyhData.mBitmap->width,
- desiredBuffer,
- desiredDimensions);
+
+ if(DALI_UNLIKELY(!desiredBuffer))
+ {
+ DALI_LOG_ERROR("malloc is failed. request malloc size : %u x %u x 1\n", desiredWidth, desiredHeight);
+ }
+ else
+ {
+ // Resize bitmap here.
+ Dali::Internal::Platform::LanczosSample1BPP(glyphData.mBitmap->buffer,
+ inputDimensions,
+ glyphData.mBitmap->width,
+ desiredBuffer,
+ desiredDimensions);
+ }
}
break;
}
#ifdef FREETYPE_BITMAP_SUPPORT
case FT_PIXEL_MODE_BGRA:
{
- if(destinationGlpyhData.mBitmap->pitch == static_cast<int>(destinationGlpyhData.mBitmap->width << 2u))
+ if(glyphData.mBitmap->pitch == static_cast<int>(glyphData.mBitmap->width << 2u))
{
desiredBuffer = (uint8_t*)malloc((desiredWidth * desiredHeight * sizeof(uint8_t)) << 2u); // @note The caller is responsible for deallocating the bitmap data using free.
- // Resize bitmap here.
- Dali::Internal::Platform::LanczosSample4BPP(destinationGlpyhData.mBitmap->buffer,
- inputDimensions,
- destinationGlpyhData.mBitmap->width,
- desiredBuffer,
- desiredDimensions);
+
+ if(DALI_UNLIKELY(!desiredBuffer))
+ {
+ DALI_LOG_ERROR("malloc is failed. request malloc size : %u x %u x 4\n", desiredWidth, desiredHeight);
+ }
+ else
+ {
+ // Resize bitmap here.
+ Dali::Internal::Platform::LanczosSample4BPP(glyphData.mBitmap->buffer,
+ inputDimensions,
+ glyphData.mBitmap->width,
+ desiredBuffer,
+ desiredDimensions);
+ }
}
break;
}
{
// 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
// 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;
{
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;
{
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;
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;
}
}
{
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();
}
{
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;
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