/*
- * 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.
* limitations under the License.
*/
+// EXTERNAL HEADERS
#include <dali/integration-api/debug.h>
+
+// INTERNAL HEADERS
+#include <dali/devel-api/adaptor-framework/environment-variable.h>
#include <dali/internal/text/text-abstraction/plugin/font-client-utils.h>
#include <dali/internal/text/text-abstraction/plugin/font-face-cache-item.h>
namespace Dali::TextAbstraction::Internal
{
+namespace
+{
const float FROM_266 = 1.0f / 64.0f;
const float POINTS_PER_INCH = 72.f;
-FontFaceCacheItem::FontFaceCacheItem(FT_Library& freeTypeLibrary,
+/**
+ * @brief Maximum rate of bitmap glyph resize.
+ * If scale factor is bigger than this value, we will not cache resized glyph.
+ * Else, resize bitmap glyph itself and cache it.
+ */
+constexpr float MAXIMUM_RATE_OF_BITMAP_GLYPH_CACHE_RESIZE = 1.5f;
+
+/**
+ * @brief Behavior about cache the rendered glyph cache.
+ */
+constexpr bool DEFAULT_ENABLE_CACHE_RENDERED_GLYPH = true;
+constexpr auto ENABLE_CACHE_RENDERED_GLYPH_ENV = "DALI_ENABLE_CACHE_RENDERED_GLYPH";
+
+/**
+ * @brief Get whether we allow to cache rendered glyph from environment.
+ * If not settuped, default as true.
+ * @note This value fixed when we call it first time.
+ * @return True if we allow to cache rendered glyph.
+ */
+inline bool EnableCacheRenderedGlyph()
+{
+ using Dali::EnvironmentVariable::GetEnvironmentVariable;
+ static auto numberString = GetEnvironmentVariable(ENABLE_CACHE_RENDERED_GLYPH_ENV);
+ static auto number = numberString ? (std::strtoul(numberString, nullptr, 10) ? true : false) : DEFAULT_ENABLE_CACHE_RENDERED_GLYPH;
+ return number;
+}
+
+/**
+ * @brief Policy about compress the cached rendered glyph.
+ * It will be used only if CacheRenderedGlyph is enabled
+ */
+constexpr auto DEFAULT_RENDERED_GLYPH_COMPRESS_POLICY =
+#if !(defined(DALI_PROFILE_UBUNTU) || defined(ANDROID) || defined(WIN32) || defined(__APPLE__))
+ GlyphCacheManager::CompressionPolicyType::MEMORY; // If tizen target
+#else
+ GlyphCacheManager::CompressionPolicyType::SPEED; // If not tizen target
+#endif
+constexpr auto RENDERED_GLYPH_COMPRESS_POLICY_ENV = "DALI_RENDERED_GLYPH_COMPRESS_POLICY";
+
+/**
+ * @brief Get whether we allow to cache rendered glyph from environment.
+ * If not settuped, default value used, as defined above.
+ * @note This value fixed when we call it first time.
+ * @return SPEED if value start with 's' or 'S'. MEMORY if value start with 'm' or 'M'. otherwise, use default
+ */
+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
+ : DEFAULT_RENDERED_GLYPH_COMPRESS_POLICY;
+ return policy;
+}
+} // namespace
+
+FontFaceCacheItem::FontFaceCacheItem(const FT_Library& freeTypeLibrary,
FT_Face ftFace,
+ GlyphCacheManager* glyphCacheManager,
const FontPath& path,
PointSize26Dot6 requestedPointSize,
FaceIndex face,
const FontMetrics& metrics)
: mFreeTypeLibrary(freeTypeLibrary),
mFreeTypeFace(ftFace),
+ mGlyphCacheManager(glyphCacheManager),
+ mHarfBuzzProxyFont(),
mPath(path),
mRequestedPointSize(requestedPointSize),
mFaceIndex(face),
{
}
-FontFaceCacheItem::FontFaceCacheItem(FT_Library& freeTypeLibrary,
+FontFaceCacheItem::FontFaceCacheItem(const FT_Library& freeTypeLibrary,
FT_Face ftFace,
+ GlyphCacheManager* glyphCacheManager,
const FontPath& path,
PointSize26Dot6 requestedPointSize,
FaceIndex face,
bool hasColorTables)
: mFreeTypeLibrary(freeTypeLibrary),
mFreeTypeFace(ftFace),
+ mGlyphCacheManager(glyphCacheManager),
+ mHarfBuzzProxyFont(),
mPath(path),
mRequestedPointSize(requestedPointSize),
mFaceIndex(face),
{
}
+// Move constructor. font client plugin container may call this.
+// Note that we make nullptr of some reference sensitive values here.
+FontFaceCacheItem::FontFaceCacheItem(FontFaceCacheItem&& rhs)
+: mFreeTypeLibrary(rhs.mFreeTypeLibrary)
+{
+ mFreeTypeFace = rhs.mFreeTypeFace;
+ mGlyphCacheManager = rhs.mGlyphCacheManager;
+ mHarfBuzzProxyFont = std::move(rhs.mHarfBuzzProxyFont);
+ mPath = std::move(rhs.mPath);
+ mRequestedPointSize = rhs.mRequestedPointSize;
+ mFaceIndex = rhs.mFaceIndex;
+ mMetrics = rhs.mMetrics;
+ mCharacterSet = rhs.mCharacterSet;
+ mFixedSizeIndex = rhs.mFixedSizeIndex;
+ mFixedWidthPixels = rhs.mFixedWidthPixels;
+ mFixedHeightPixels = rhs.mFixedWidthPixels;
+ mVectorFontId = rhs.mVectorFontId;
+ mFontId = rhs.mFontId;
+ mIsFixedSizeBitmap = rhs.mIsFixedSizeBitmap;
+ mHasColorTables = rhs.mHasColorTables;
+
+ rhs.mFreeTypeFace = nullptr;
+ rhs.mGlyphCacheManager = nullptr;
+}
+
+FontFaceCacheItem::~FontFaceCacheItem()
+{
+ // delete cached glyph informations before free face.
+ if(mGlyphCacheManager)
+ {
+ mGlyphCacheManager->RemoveGlyphFromFace(mFreeTypeFace);
+ }
+
+ // delete harfbuzz proxy font before free face.
+ if(mHarfBuzzProxyFont)
+ {
+ mHarfBuzzProxyFont.reset();
+ }
+
+ // Free face.
+ if(mFreeTypeFace)
+ {
+ FT_Done_Face(mFreeTypeFace);
+ }
+}
+
void FontFaceCacheItem::GetFontMetrics(FontMetrics& metrics, unsigned int dpiVertical) const
{
metrics = mMetrics;
}
}
-bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyph, unsigned int dpiVertical, bool horizontal) const
+bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyphInfo, unsigned int dpiVertical, bool horizontal) const
{
bool success(true);
- FT_Face ftFace = mFreeTypeFace;
+ GlyphCacheManager::GlyphCacheData glyphData;
+ FT_Error error;
#ifdef FREETYPE_BITMAP_SUPPORT
// Check to see if we should be loading a Fixed Size bitmap?
if(mIsFixedSizeBitmap)
{
- FT_Select_Size(ftFace, mFixedSizeIndex); ///< @todo: needs to be investigated why it's needed to select the size again.
- int error = FT_Load_Glyph(ftFace, glyph.index, FT_LOAD_COLOR);
+ 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);
+
if(FT_Err_Ok == error)
{
- glyph.width = mFixedWidthPixels;
- glyph.height = mFixedHeightPixels;
- glyph.advance = mFixedWidthPixels;
- glyph.xBearing = 0.0f;
+ glyphInfo.width = mFixedWidthPixels;
+ glyphInfo.height = mFixedHeightPixels;
+ glyphInfo.advance = mFixedWidthPixels;
+ glyphInfo.xBearing = 0.0f;
+
+ const auto& metrics = glyphData.mGlyphMetrics;
if(horizontal)
{
- glyph.yBearing += static_cast<float>(ftFace->glyph->metrics.horiBearingY) * FROM_266;
+ glyphInfo.yBearing += static_cast<float>(metrics.horiBearingY) * FROM_266;
}
else
{
- glyph.yBearing += static_cast<float>(ftFace->glyph->metrics.vertBearingY) * FROM_266;
+ glyphInfo.yBearing += static_cast<float>(metrics.vertBearingY) * FROM_266;
}
// Adjust the metrics if the fixed-size font should be down-scaled
if(desiredFixedSize > 0.f)
{
const float scaleFactor = desiredFixedSize / mFixedHeightPixels;
- glyph.width = round(glyph.width * scaleFactor);
- glyph.height = round(glyph.height * scaleFactor);
- glyph.advance = round(glyph.advance * scaleFactor);
- glyph.xBearing = round(glyph.xBearing * scaleFactor);
- glyph.yBearing = round(glyph.yBearing * scaleFactor);
+ glyphInfo.width = round(glyphInfo.width * scaleFactor);
+ glyphInfo.height = round(glyphInfo.height * scaleFactor);
+ glyphInfo.advance = round(glyphInfo.advance * scaleFactor);
+ glyphInfo.xBearing = round(glyphInfo.xBearing * scaleFactor);
+ glyphInfo.yBearing = round(glyphInfo.yBearing * scaleFactor);
- glyph.scaleFactor = scaleFactor;
+ glyphInfo.scaleFactor = scaleFactor;
+
+ if(scaleFactor < MAXIMUM_RATE_OF_BITMAP_GLYPH_CACHE_RESIZE)
+ {
+ // Resize bitmap glyph and cache it due to the performance issue.
+ // If scaleFactor is too big, cached bitmap may hold too big memory.
+ // So, we only hold small enough case.
+
+ // TODO : If dpiVertical value changed, this resize feature will be break down.
+ // Otherwise, this glyph will be resized only one times.
+ mGlyphCacheManager->ResizeBitmapGlyph(mFreeTypeFace, glyphInfo.index, FT_LOAD_COLOR, glyphInfo.isBoldRequired, static_cast<uint32_t>(glyphInfo.width), static_cast<uint32_t>(glyphInfo.height));
+ }
}
}
else
// 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?
- int error = FT_Load_Glyph(ftFace, glyph.index, FT_LOAD_NO_AUTOHINT);
+ mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphInfo.index, FT_LOAD_NO_AUTOHINT, glyphInfo.isBoldRequired, glyphData, 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
// advance as Harfbuzz doesn't apply any SW emboldening to calculate
// the advance of the glyph.
- const float width = static_cast<float>(ftFace->glyph->metrics.width) * FROM_266;
if(FT_Err_Ok == error)
{
- const bool isEmboldeningRequired = glyph.isBoldRequired && !(ftFace->style_flags & FT_STYLE_FLAG_BOLD);
- if(isEmboldeningRequired)
- {
- // Does the software bold.
- FT_GlyphSlot_Embolden(ftFace->glyph);
- }
+ const auto& metrics = glyphData.mGlyphMetrics;
- glyph.width = static_cast<float>(ftFace->glyph->metrics.width) * FROM_266;
- glyph.height = static_cast<float>(ftFace->glyph->metrics.height) * FROM_266;
+ glyphInfo.width = static_cast<float>(metrics.width) * FROM_266;
+ glyphInfo.height = static_cast<float>(metrics.height) * FROM_266;
if(horizontal)
{
- glyph.xBearing += static_cast<float>(ftFace->glyph->metrics.horiBearingX) * FROM_266;
- glyph.yBearing += static_cast<float>(ftFace->glyph->metrics.horiBearingY) * FROM_266;
+ glyphInfo.xBearing += static_cast<float>(metrics.horiBearingX) * FROM_266;
+ glyphInfo.yBearing += static_cast<float>(metrics.horiBearingY) * FROM_266;
}
else
{
- glyph.xBearing += static_cast<float>(ftFace->glyph->metrics.vertBearingX) * FROM_266;
- glyph.yBearing += static_cast<float>(ftFace->glyph->metrics.vertBearingY) * FROM_266;
+ glyphInfo.xBearing += static_cast<float>(metrics.vertBearingX) * FROM_266;
+ glyphInfo.yBearing += static_cast<float>(metrics.vertBearingY) * FROM_266;
}
+ glyphInfo.advance = round(glyphInfo.advance);
- if(isEmboldeningRequired && !Dali::EqualsZero(width))
+ const bool isEmboldeningRequired = glyphInfo.isBoldRequired && !(glyphData.mStyleFlags & FT_STYLE_FLAG_BOLD);
+ if(isEmboldeningRequired)
{
- // If the glyph is emboldened by software, the advance is multiplied by a
- // scale factor to make it slightly bigger.
- glyph.advance *= (glyph.width / width);
+ // Get dummy glyph data without embolden.
+ GlyphCacheManager::GlyphCacheData dummyData;
+ if(mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphInfo.index, FT_LOAD_NO_AUTOHINT, false, dummyData, 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<float>(dummyData.mGlyphMetrics.width) * FROM_266;
+ if(!EqualsZero(width))
+ {
+ glyphInfo.advance *= (glyphInfo.width / width);
+ }
+ }
}
// Use the bounding box of the bitmap to correct the metrics.
// For some fonts i.e the SNum-3R the metrics need to be corrected,
// otherwise the glyphs 'dance' up and down depending on the
// font's point size.
-
- FT_Glyph ftGlyph;
- error = FT_Get_Glyph(ftFace->glyph, &ftGlyph);
+ FT_Glyph glyph = glyphData.mGlyph;
FT_BBox bbox;
- FT_Glyph_Get_CBox(ftGlyph, FT_GLYPH_BBOX_GRIDFIT, &bbox);
-
- const float descender = glyph.height - glyph.yBearing;
- glyph.height = (bbox.yMax - bbox.yMin) * FROM_266;
- glyph.yBearing = glyph.height - round(descender);
+ FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_GRIDFIT, &bbox);
- // Created FT_Glyph object must be released with FT_Done_Glyph
- FT_Done_Glyph(ftGlyph);
+ const float descender = glyphInfo.height - glyphInfo.yBearing;
+ glyphInfo.height = (bbox.yMax - bbox.yMin) * FROM_266;
+ glyphInfo.yBearing = glyphInfo.height - round(descender);
}
else
{
* @brief Create a bitmap representation of a glyph from a face font
*
* @param[in] glyphIndex The index of a glyph within the specified font.
- * @param[in] isItalicRequired Whether the glyph requires italic style.
- * @param[in] isBoldRequired Whether the glyph requires bold style.
* @param[out] data The bitmap data.
* @param[in] outlineWidth The width of the glyph outline in pixels.
+ * @param[in] isItalicRequired Whether the glyph requires italic style.
+ * @param[in] isBoldRequired Whether the glyph requires bold style.
*/
void FontFaceCacheItem::CreateBitmap(
GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const
{
- FT_Face ftFace = mFreeTypeFace;
- FT_Error error;
+ GlyphCacheManager::GlyphCacheData glyphData;
+ FT_Error error;
+ FT_Int32 loadFlag;
// For the software italics.
bool isShearRequired = false;
// Check to see if this is fixed size bitmap
if(mIsFixedSizeBitmap)
{
- error = FT_Load_Glyph(ftFace, glyphIndex, FT_LOAD_COLOR);
+ loadFlag = FT_LOAD_COLOR;
}
else
#endif
// 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?
- error = FT_Load_Glyph(ftFace, glyphIndex, FT_LOAD_NO_AUTOHINT);
+ loadFlag = FT_LOAD_NO_AUTOHINT;
}
+ mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphIndex, loadFlag, isBoldRequired, glyphData, error);
+
if(FT_Err_Ok == error)
{
- if(isBoldRequired && !(ftFace->style_flags & FT_STYLE_FLAG_BOLD))
- {
- // Does the software bold.
- FT_GlyphSlot_Embolden(ftFace->glyph);
- }
-
- if(isItalicRequired && !(ftFace->style_flags & FT_STYLE_FLAG_ITALIC))
+ if(isItalicRequired && !(glyphData.mStyleFlags & FT_STYLE_FLAG_ITALIC))
{
// Will do the software italic.
isShearRequired = true;
}
- FT_Glyph glyph;
- error = FT_Get_Glyph(ftFace->glyph, &glyph);
-
- // Convert to bitmap if necessary
- if(FT_Err_Ok == error)
+ if(!glyphData.mIsBitmap)
{
- if(glyph->format != FT_GLYPH_FORMAT_BITMAP)
- {
- int offsetX = 0, offsetY = 0;
- bool isOutlineGlyph = (glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0);
+ // Convert to bitmap if necessary
+ FT_Glyph glyph = glyphData.mGlyph;
- // Create a bitmap for the outline
- if(isOutlineGlyph)
+ DALI_ASSERT_ALWAYS(glyph->format != FT_GLYPH_FORMAT_BITMAP && "Something wrong with cashing. Some bitmap glyph cached failed.");
+
+ int offsetX = 0, offsetY = 0;
+ bool isOutlineGlyph = (glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0);
+ bool isStrokeGlyphSuccess = false;
+
+ // Create a bitmap for the outline
+ if(isOutlineGlyph)
+ {
+ // Retrieve the horizontal and vertical distance from the current pen position to the
+ // left and top border of the glyph bitmap for a normal glyph before applying the outline.
+ if(FT_Err_Ok == error)
{
- // Retrieve the horizontal and vertical distance from the current pen position to the
- // left and top border of the glyph bitmap for a normal glyph before applying the outline.
+ // Copy new glyph, and keep original cached glyph.
+ error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0);
if(FT_Err_Ok == error)
{
- FT_Glyph normalGlyph;
- error = FT_Get_Glyph(ftFace->glyph, &normalGlyph);
+ FT_BitmapGlyph bitmapGlyph = reinterpret_cast<FT_BitmapGlyph>(glyph);
- error = FT_Glyph_To_Bitmap(&normalGlyph, FT_RENDER_MODE_NORMAL, 0, 1);
- if(FT_Err_Ok == error)
- {
- FT_BitmapGlyph bitmapGlyph = reinterpret_cast<FT_BitmapGlyph>(normalGlyph);
-
- offsetX = bitmapGlyph->left;
- offsetY = bitmapGlyph->top;
- }
+ offsetX = bitmapGlyph->left;
+ offsetY = bitmapGlyph->top;
- // Created FT_Glyph object must be released with FT_Done_Glyph
- FT_Done_Glyph(normalGlyph);
+ // Copied FT_Glyph object must be released with FT_Done_Glyph
+ FT_Done_Glyph(glyph);
}
- // Now apply the outline
+ // Replace as original glyph
+ glyph = glyphData.mGlyph;
+ }
- // Set up a stroker
- FT_Stroker stroker;
- error = FT_Stroker_New(mFreeTypeLibrary, &stroker);
+ // Now apply the outline
+
+ // Set up a stroker
+ FT_Stroker stroker;
+ error = FT_Stroker_New(mFreeTypeLibrary, &stroker);
+
+ if(FT_Err_Ok == error)
+ {
+ // Copy glyph pointer for release memory.
+ FT_Stroker_Set(stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
+ error = FT_Glyph_StrokeBorder(&glyph, stroker, 0, 0);
if(FT_Err_Ok == error)
{
- FT_Stroker_Set(stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
- error = FT_Glyph_StrokeBorder(&glyph, stroker, 0, 1);
-
- if(FT_Err_Ok == error)
- {
- FT_Stroker_Done(stroker);
- }
- else
- {
- DALI_LOG_ERROR("FT_Glyph_StrokeBorder Failed with error: %d\n", error);
- }
+ FT_Stroker_Done(stroker);
+ isStrokeGlyphSuccess = true;
}
else
{
- DALI_LOG_ERROR("FT_Stroker_New Failed with error: %d\n", error);
+ DALI_LOG_ERROR("FT_Glyph_StrokeBorder Failed with error: %d\n", error);
}
}
+ else
+ {
+ DALI_LOG_ERROR("FT_Stroker_New Failed with error: %d\n", error);
+ }
+ }
- error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
+ const bool ableUseCachedRenderedGlyph = EnableCacheRenderedGlyph() && !isOutlineGlyph && !isShearRequired;
+
+ // If we cache rendered glyph, and if we can use it, use cached thing first.
+ if(ableUseCachedRenderedGlyph && glyphData.mRenderedBuffer)
+ {
+ data.buffer = glyphData.mRenderedBuffer->buffer;
+ data.width = glyphData.mRenderedBuffer->width;
+ data.height = glyphData.mRenderedBuffer->height;
+ data.format = glyphData.mRenderedBuffer->format;
+ data.compressionType = glyphData.mRenderedBuffer->compressionType;
+ data.isBufferOwned = false;
+ }
+ else
+ {
+ // Copy new glyph, and keep original cached glyph.
+ // If we already copy new glyph by stroke, just re-use that.
+ error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, isStrokeGlyphSuccess);
if(FT_Err_Ok == error)
{
FT_BitmapGlyph bitmapGlyph = reinterpret_cast<FT_BitmapGlyph>(glyph);
data.outlineOffsetY = bitmapGlyph->top - offsetY - outlineWidth;
}
- ConvertBitmap(data, bitmapGlyph->bitmap, isShearRequired);
+ // If we can cache this bitmapGlyph, store it.
+ // Note : We will call this API once per each glyph.
+ if(ableUseCachedRenderedGlyph)
+ {
+ mGlyphCacheManager->CacheRenderedGlyphBuffer(mFreeTypeFace, glyphIndex, loadFlag, isBoldRequired, bitmapGlyph->bitmap, GetRenderedGlyphCompressPolicy());
+
+ GlyphCacheManager::GlyphCacheData dummyData;
+ mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphIndex, loadFlag, isBoldRequired, dummyData, error);
+
+ if(DALI_LIKELY(FT_Err_Ok == error && dummyData.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.isBufferOwned = false;
+ }
+ else
+ {
+ // Something problem during cache or get rendered glyph buffer.
+ // Move bitmap buffer into data.buffer
+ ConvertBitmap(data, bitmapGlyph->bitmap, isShearRequired, true);
+ }
+ }
+ else
+ {
+ // Move bitmap buffer into data.buffer
+ ConvertBitmap(data, bitmapGlyph->bitmap, isShearRequired, true);
+ }
+
+ // Copied FT_Glyph object must be released with FT_Done_Glyph
+ FT_Done_Glyph(glyph);
}
else
{
DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Get_Glyph Failed with error: %d\n", error);
}
}
- else
- {
- ConvertBitmap(data, ftFace->glyph->bitmap, isShearRequired);
- }
-
- data.isColorEmoji = mIsFixedSizeBitmap;
-
- // Created FT_Glyph object must be released with FT_Done_Glyph
- FT_Done_Glyph(glyph);
}
+ else
+ {
+ ConvertBitmap(data, *glyphData.mBitmap, isShearRequired);
+ }
+
+ data.isColorEmoji = mIsFixedSizeBitmap;
}
else
{
// Check to see if this is fixed size bitmap
if(mHasColorTables)
{
- error = FT_Load_Glyph(mFreeTypeFace, glyphIndex, FT_LOAD_COLOR);
+ GlyphCacheManager::GlyphCacheData dummyData;
+ mGlyphCacheManager->GetGlyphCacheDataFromIndex(mFreeTypeFace, glyphIndex, FT_LOAD_COLOR, false, dummyData, error);
}
#endif
return FT_Err_Ok == error;
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));
+ }
+ return mHarfBuzzProxyFont->GetHarfBuzzFont();
+}
+
} // namespace Dali::TextAbstraction::Internal