// INTERNAL INCLUDES
#include <dali/devel-api/text-abstraction/font-list.h>
#include <dali/integration-api/debug.h>
+#include <dali/integration-api/trace.h>
#include <dali/integration-api/platform-abstraction.h>
#include <dali/internal/adaptor/common/adaptor-impl.h>
#include <dali/internal/imaging/common/image-operations.h>
+#include <dali/internal/system/common/logging.h>
#include <dali/internal/text/text-abstraction/plugin/bitmap-font-cache-item.h>
#include <dali/internal/text/text-abstraction/plugin/embedded-item.h>
#include <dali/internal/text/text-abstraction/plugin/font-client-plugin-cache-handler.h>
#include <algorithm>
#include <iterator>
+// Use this macro only if need to log messages before the log function is set.
+#define FONT_LOG_MESSAGE(level, format, ...) \
+ do \
+ { \
+ char buffer[256]; \
+ int result = std::snprintf(buffer, sizeof(buffer), format, ##__VA_ARGS__); \
+ if(result >= static_cast<int>(sizeof(buffer))) \
+ { \
+ std::string log("Font log message is too long to fit in the buffer.\n"); \
+ Dali::TizenPlatform::LogMessage(Dali::Integration::Log::ERROR, log); \
+ break; \
+ } \
+ std::string log(buffer); \
+ Dali::TizenPlatform::LogMessage(level, log); \
+ } while(0)
+
#if defined(DEBUG_ENABLED)
// Note, to turn on trace and verbose logging, use "export LOG_FONT_CLIENT=3,true"
namespace
{
+
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_FONT_PERFORMANCE_MARKER, false);
+
/**
* Conversion from Fractional26.6 to float
*/
mCacheHandler->ResetSystemDefaults();
}
+void FontClient::Plugin::CacheFontDataFromFile(const std::string& fontPath) const
+{
+ if(fontPath.empty())
+ {
+ return;
+ }
+
+ if(mCacheHandler->FindFontData(fontPath))
+ {
+ // Font data is already cached, no need to reload
+ return;
+ }
+
+ Dali::Vector<uint8_t> fontDataBuffer;
+ std::streampos dataSize = 0;
+ if(!mCacheHandler->LoadFontDataFromFile(fontPath, fontDataBuffer, dataSize))
+ {
+ fontDataBuffer.Clear();
+ FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "Failed to load font data : %s\n", fontPath.c_str());
+ return;
+ }
+
+ // Cache font data
+ mCacheHandler->CacheFontData(fontPath, fontDataBuffer, dataSize);
+}
+
+void FontClient::Plugin::CacheFontFaceFromFile(const std::string& fontPath) const
+{
+ if(fontPath.empty())
+ {
+ return;
+ }
+
+ if(mCacheHandler->FindFontFace(fontPath))
+ {
+ // Font face is already cached, no need to reload
+ return;
+ }
+
+ FT_Face ftFace;
+ int error = FT_New_Face(mFreeTypeLibrary, fontPath.c_str(), 0, &ftFace);
+ if(FT_Err_Ok != error)
+ {
+ FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "Failed to load font face : %s\n", fontPath.c_str());
+ return;
+ }
+
+ // Cache font face
+ mCacheHandler->CacheFontFace(fontPath, ftFace);
+ FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "PreLoad font new face : %s\n", fontPath.c_str());
+}
+
+void FontClient::Plugin::FontPreLoad(const FontPathList& fontPathList, const FontPathList& memoryFontPathList) const
+{
+ for(const auto& fontPath : fontPathList)
+ {
+ CacheFontFaceFromFile(fontPath);
+ }
+
+ for(const auto& memoryFontPath : memoryFontPathList)
+ {
+ CacheFontDataFromFile(memoryFontPath);
+ }
+}
+
+void FontClient::Plugin::FontPreCache(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily) const
+{
+ mCacheHandler->InitDefaultFontDescription();
+
+ FontFamilyList familyList;
+ familyList.reserve(extraFamilyList.size() + 1);
+
+ for (const auto& fallbackFont : fallbackFamilyList)
+ {
+ FontList* fontList = nullptr;
+ CharacterSetList* characterSetList = nullptr;
+ FontDescriptionId fontDescriptionId = 0u;
+ FontDescription fontDescription;
+ fontDescription.family = FontFamily(fallbackFont);
+ fontDescription.weight = DefaultFontWeight();
+ fontDescription.width = DefaultFontWidth();
+ fontDescription.slant = DefaultFontSlant();
+
+ if(!mCacheHandler->FindFallbackFontList(fontDescription, fontList, characterSetList))
+ {
+ FontDescription copiedFontDescription = fontDescription;
+ mCacheHandler->CacheFallbackFontList(std::move(copiedFontDescription), fontList, characterSetList);
+ }
+ if(!mCacheHandler->FindValidatedFont(fontDescription, fontDescriptionId))
+ {
+ mCacheHandler->ValidateFont(fontDescription, fontDescriptionId);
+ }
+
+ if(extraFamilyList.empty() && localeFamily.empty())
+ {
+ continue;
+ }
+
+ familyList.clear();
+ familyList.insert(familyList.end(), extraFamilyList.begin(), extraFamilyList.end());
+ if(!localeFamily.empty())
+ {
+ familyList.push_back(localeFamily);
+ }
+
+ for(const auto& font : *fontList)
+ {
+ auto it = std::find(familyList.begin(), familyList.end(), font.family);
+ if(it != familyList.end())
+ {
+ if(!mCacheHandler->FindValidatedFont(font, fontDescriptionId))
+ {
+ mCacheHandler->ValidateFont(font, fontDescriptionId);
+ }
+ familyList.erase(it);
+ }
+ }
+ }
+}
+
+void FontClient::Plugin::InitDefaultFontDescription() const
+{
+ mCacheHandler->InitDefaultFontDescription();
+}
+
void FontClient::Plugin::GetDefaultPlatformFontDescription(FontDescription& fontDescription) const
{
DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
FONT_LOG_REQUEST(charcode, requestedPointSize, preferColor);
+ DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_FIND_FALLBACKFONT");
+
// The font id to be returned.
FontId fontId = 0u;
DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontWidth::Name[preferredFontDescription.width], FontWidth::Name[fontDescription.width]);
DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontSlant::Name[preferredFontDescription.slant], FontSlant::Name[fontDescription.slant]);
+ #if defined(TRACE_ENABLED)
+ if(gTraceFilter && gTraceFilter->IsTraceEnabled())
+ {
+ DALI_LOG_DEBUG_INFO("DALI_TEXT_FIND_FALLBACKFONT : %s -> %s\n", preferredFontDescription.family.c_str(), fontDescription.family.c_str());
+ }
+ #endif
+
// Check first if the font's description has been queried before.
FontList* fontList = nullptr;
CharacterSetList* characterSetList = nullptr;
// So set cacheDescription=false, that we don't call CacheFontPath().
fontId = GetFontIdByPath(description.path, requestedPointSize, faceIndex, false);
- fontCacheIndex = mCacheHandler->mFontIdCache[fontId - 1u].index;
- mCacheHandler->mFontFaceCache[fontCacheIndex].mCharacterSet = FcCharSetCopy(mCacheHandler->mCharacterSetCache[fontDescriptionId - 1u]);
+ if((fontId > 0u) && (fontId - 1u < mCacheHandler->mFontIdCache.size()))
+ {
+ fontCacheIndex = mCacheHandler->mFontIdCache[fontId - 1u].index;
+ mCacheHandler->mFontFaceCache[fontCacheIndex].mCharacterSet = FcCharSetCopy(mCacheHandler->mCharacterSetCache[fontDescriptionId - 1u]);
- // Cache the pair 'fontDescriptionId, requestedPointSize' to improve the following queries.
- mCacheHandler->CacheFontDescriptionSize(fontDescriptionId, requestedPointSize, fontCacheIndex);
+ // Cache the pair 'fontDescriptionId, requestedPointSize' to improve the following queries.
+ mCacheHandler->CacheFontDescriptionSize(fontDescriptionId, requestedPointSize, fontCacheIndex);
+ }
}
else
{
uint32_t FontClient::Plugin::GetNumberOfPointsPerOneUnitOfPointSize() const
{
return TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
- ;
}
FontId FontClient::Plugin::CreateFont(const FontPath& path,
DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " path : [%s]\n", path.c_str());
DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
- FontId fontId = 0u;
+ DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_CREATE_FONT");
- // Create & cache new font face
- FT_Face ftFace;
- int error = FT_New_Face(mFreeTypeLibrary,
- path.c_str(),
- 0,
- &ftFace);
+ FontId fontId = 0u;
+ FT_Face ftFace;
+ FT_Error error;
+
+ uint8_t* fontDataPtr = nullptr;
+ std::streampos dataSize = 0;
+ bool fontDataFound = mCacheHandler->FindFontData(path, fontDataPtr, dataSize);
+
+ if(fontDataFound)
+ {
+ // Create & cache new font face from pre-loaded font
+ error = FT_New_Memory_Face(mFreeTypeLibrary, reinterpret_cast<FT_Byte*>(fontDataPtr), static_cast<FT_Long>(dataSize), 0, &ftFace);
+#if defined(TRACE_ENABLED)
+ if(gTraceFilter && gTraceFilter->IsTraceEnabled())
+ {
+ DALI_LOG_DEBUG_INFO("DALI_TEXT_CREATE_FONT : FT_New_Memory_Face : %s\n", path.c_str());
+ }
+#endif
+ }
+ else
+ {
+ // Create & cache new font face
+ error = FT_New_Face(mFreeTypeLibrary, path.c_str(), 0, &ftFace);
+#if defined(TRACE_ENABLED)
+ if(gTraceFilter && gTraceFilter->IsTraceEnabled())
+ {
+ DALI_LOG_DEBUG_INFO("DALI_TEXT_CREATE_FONT : FT_New_Face : %s\n", path.c_str());
+ }
+#endif
+ }
if(FT_Err_Ok == error)
{
int fixedSizeIndex = 0;
for(; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex)
{
- const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
+ const PointSize26Dot6 fixedSize = static_cast<PointSize26Dot6>(ftFace->available_sizes[fixedSizeIndex].size);
DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " size index : %d, size : %d\n", fixedSizeIndex, fixedSize);
if(fixedSize >= requestedPointSize)
{
// The requested point size is bigger than the bigest fixed size.
fixedSizeIndex = ftFace->num_fixed_sizes - 1;
- actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
+ actualPointSize = static_cast<PointSize26Dot6>(ftFace->available_sizes[fixedSizeIndex].size);
}
DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize);
const float fixedHeight = static_cast<float>(ftFace->available_sizes[fixedSizeIndex].height);
// Create the FreeType font face item to cache.
- FontFaceCacheItem fontFaceCacheItem(mFreeTypeLibrary, ftFace, path, requestedPointSize, faceIndex, metrics, fixedSizeIndex, fixedWidth, fixedHeight, hasColorTables);
+ FontFaceCacheItem fontFaceCacheItem(mFreeTypeLibrary, ftFace, mCacheHandler->GetGlyphCacheManager(), path, requestedPointSize, faceIndex, metrics, fixedSizeIndex, fixedWidth, fixedHeight, hasColorTables);
fontId = mCacheHandler->CacheFontFaceCacheItem(std::move(fontFaceCacheItem));
}
static_cast<float>(ftFace->underline_thickness) * FROM_266);
// Create the FreeType font face item to cache.
- FontFaceCacheItem fontFaceCacheItem(mFreeTypeLibrary, ftFace, path, requestedPointSize, faceIndex, metrics);
+ FontFaceCacheItem fontFaceCacheItem(mFreeTypeLibrary, ftFace, mCacheHandler->GetGlyphCacheManager(), path, requestedPointSize, faceIndex, metrics);
fontId = mCacheHandler->CacheFontFaceCacheItem(std::move(fontFaceCacheItem));
}