X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=text%2Fdali%2Finternal%2Ftext-abstraction%2Ffont-client-plugin-impl.cpp;h=b11fd7284cf620342f75458a73db1ca71b60926c;hb=01a4891a7625e7bccef3e40fa5d7fe4115bfb73f;hp=970f0ffe8edd2d4a35e8f3f0fcaebb1e7e3afea8;hpb=0efbe95df09cccc17c211d1bbd2250d7f790f9dc;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git diff --git a/text/dali/internal/text-abstraction/font-client-plugin-impl.cpp b/text/dali/internal/text-abstraction/font-client-plugin-impl.cpp index 970f0ff..b11fd72 100644 --- a/text/dali/internal/text-abstraction/font-client-plugin-impl.cpp +++ b/text/dali/internal/text-abstraction/font-client-plugin-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 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. @@ -20,6 +20,7 @@ // INTERNAL INCLUDES #include + #include #include #include @@ -43,6 +44,7 @@ Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New */ const float FROM_266 = 1.0f / 64.0f; const float POINTS_PER_INCH = 72.f; +const FT_Fixed FONT_SLANT_TANGENT = 0.221694663 * 0x10000; // For support software italic const std::string FONT_FORMAT( "TrueType" ); const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" ); @@ -52,8 +54,6 @@ const int DEFAULT_FONT_SLANT = 0; // normal const uint32_t ELLIPSIS_CHARACTER = 0x2026; -const bool FONT_FIXED_SIZE_BITMAP( true ); - // http://www.freedesktop.org/software/fontconfig/fontconfig-user.html // NONE -1 --> DEFAULT_FONT_WIDTH (NORMAL) will be used. @@ -93,6 +93,8 @@ const unsigned int NUM_FONT_SLANT_TYPE = sizeof( FONT_SLANT_TYPE_TO_INT ) / size } // namespace + + using Dali::Vector; namespace Dali @@ -140,22 +142,30 @@ FontSlant::Type IntToSlantType( int slant ) return static_cast( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) ); } -FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( const FontDescription& font, FontList* list ) -: fontDescription( font ), - fallbackFonts( list ) +FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( FontDescription&& font, FontList* fallbackFonts, CharacterSetList* characterSets ) +: fontDescription{ std::move( font ) }, + fallbackFonts{ fallbackFonts }, + characterSets{ characterSets } { } FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription, FontDescriptionId index ) -: fontDescription( fontDescription ), - index( index ) +: fontDescription{ fontDescription }, + index{ index } +{ +} + +FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( FontDescription&& fontDescription, + FontDescriptionId index ) +: fontDescription{ std::move( fontDescription ) }, + index{ index } { } -FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId, - PointSize26Dot6 requestedPointSize, - FontId fontId ) +FontClient::Plugin::FontDescriptionSizeCacheItem::FontDescriptionSizeCacheItem( FontDescriptionId validatedFontId, + PointSize26Dot6 requestedPointSize, + FontId fontId ) : validatedFontId( validatedFontId ), requestedPointSize( requestedPointSize ), fontId( fontId ) @@ -172,10 +182,12 @@ FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace, mRequestedPointSize( requestedPointSize ), mFaceIndex( face ), mMetrics( metrics ), + mCharacterSet( nullptr ), mFixedWidthPixels( 0.0f ), mFixedHeightPixels( 0.0f ), mVectorFontId( 0 ), - mIsFixedSizeBitmap( false ) + mIsFixedSizeBitmap( false ), + mHasColorTables( false ) { } @@ -185,68 +197,95 @@ FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace, FaceIndex face, const FontMetrics& metrics, float fixedWidth, - float fixedHeight ) + float fixedHeight, + bool hasColorTables ) : mFreeTypeFace( ftFace ), mPath( path ), mRequestedPointSize( requestedPointSize ), mFaceIndex( face ), mMetrics( metrics ), + mCharacterSet( nullptr ), mFixedWidthPixels( fixedWidth ), mFixedHeightPixels( fixedHeight ), mVectorFontId( 0 ), - mIsFixedSizeBitmap( true ) + mIsFixedSizeBitmap( true ), + mHasColorTables( hasColorTables ) { } FontClient::Plugin::Plugin( unsigned int horizontalDpi, unsigned int verticalDpi ) -: mFreeTypeLibrary( NULL ), +: mFreeTypeLibrary( nullptr ), mDpiHorizontal( horizontalDpi ), mDpiVertical( verticalDpi ), mDefaultFontDescription(), mSystemFonts(), mDefaultFonts(), - mFontCache(), + mFontFaceCache(), mValidatedFontCache(), mFontDescriptionCache( 1u ), - mFontIdCache(), - mVectorFontCache( NULL ), + mCharacterSetCache(), + mFontDescriptionSizeCache(), + mVectorFontCache( nullptr ), mEllipsisCache(), mDefaultFontDescriptionCached( false ) { + mCharacterSetCache.Resize( 1u ); + int error = FT_Init_FreeType( &mFreeTypeLibrary ); if( FT_Err_Ok != error ) { - DALI_LOG_ERROR( "FreeType Init error: %d\n", error ); + DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Init error: %d\n", error ); } #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING mVectorFontCache = new VectorFontCache( mFreeTypeLibrary ); #endif + } FontClient::Plugin::~Plugin() { - for( std::vector::iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end(); - it != endIt; - ++it ) + for( auto& item : mFallbackCache ) { - FallbackCacheItem& item = *it; - if( item.fallbackFonts ) { delete item.fallbackFonts; - item.fallbackFonts = NULL; + delete item.characterSets; + item.fallbackFonts = nullptr; + item.characterSets = nullptr; } } #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING delete mVectorFontCache; #endif - + DestroyMatchedPatterns(); FT_Done_FreeType( mFreeTypeLibrary ); } +void FontClient::Plugin::ClearCache() +{ + mFontFaceCache.clear(); + mValidatedFontCache.clear(); + mFontDescriptionCache.clear(); + mFontDescriptionCache.resize( 1u ); + + mCharacterSetCache.Clear(); + mCharacterSetCache.Resize( 1u ); + + mFontDescriptionSizeCache.clear(); + mFallbackCache.clear(); + + mEllipsisCache.Clear(); + mSystemFonts.clear(); + mDefaultFonts.clear(); + mDefaultFontDescriptionCached = false; + mDefaultFontCharacterSets.Clear(); + mDefaultFontDescription = FontDescription(); + DestroyMatchedPatterns(); +} + void FontClient::Plugin::SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi ) { @@ -259,9 +298,13 @@ void FontClient::Plugin::ResetSystemDefaults() mDefaultFontDescriptionCached = false; } -void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList ) +void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::SetFontList family(%s)\n", fontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::SetFontList\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] ); fontList.clear(); @@ -270,14 +313,15 @@ void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, Fo FcResult result = FcResultMatch; // Match the pattern. - FcFontSet* fontSet = FcFontSort( NULL /* use default configure */, + FcFontSet* fontSet = FcFontSort( nullptr /* use default configure */, fontFamilyPattern, false /* don't trim */, - NULL, + nullptr, &result ); - if( NULL != fontSet ) + if( nullptr != fontSet ) { + DALI_LOG_INFO( gLogFilter, Debug::General, " number of fonts found : [%d]\n", fontSet->nfont ); // Reserve some space to avoid reallocations. fontList.reserve( fontSet->nfont ); @@ -290,10 +334,14 @@ void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, Fo // Skip fonts with no path if( GetFcString( fontPattern, FC_FILE, path ) ) { + FcCharSet* characterSet = nullptr; + FcPatternGetCharSet( fontPattern, FC_CHARSET, 0u, &characterSet ); + + characterSetList.PushBack( characterSet ); fontList.push_back( FontDescription() ); FontDescription& newFontDescription = fontList.back(); - newFontDescription.path = path; + newFontDescription.path = std::move( path ); int width = 0; int weight = 0; @@ -305,18 +353,29 @@ void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, Fo newFontDescription.width = IntToWidthType( width ); newFontDescription.weight = IntToWeightType( weight ); newFontDescription.slant = IntToSlantType( slant ); + + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", newFontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", newFontDescription.path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[newFontDescription.width] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[newFontDescription.weight] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[newFontDescription.slant] ); } } FcFontSetDestroy( fontSet ); } + else + { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " No fonts found.\n" ); + } FcPatternDestroy( fontFamilyPattern ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::SetFontList\n" ); } void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultFonts mDefaultFonts(%s)\n", ( mDefaultFonts.empty()?"empty":"valid" ) ); + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultFonts\n" ); if( mDefaultFonts.empty() ) { @@ -325,31 +384,79 @@ void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts ) fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH ); fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT ); fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT ); - SetFontList( fontDescription, mDefaultFonts ); + SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets ); } defaultFonts = mDefaultFonts; + + DALI_LOG_INFO( gLogFilter, Debug::General, " number of default fonts : [%d]\n", mDefaultFonts.size() ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultFonts\n" ); } void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultPlatformFontDescription\n"); + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultPlatformFontDescription\n"); if( !mDefaultFontDescriptionCached ) { - FcInitReinitialize(); // FcInitBringUptoDate did not seem to reload config file as was still getting old default font. + // Clear any font config stored info in the caches. + mDefaultFontCharacterSets.Clear(); + mCharacterSetCache.Clear(); + + for( auto& item : mFallbackCache ) + { + item.characterSets->Clear(); + } + + for( auto& item : mFontFaceCache ) + { + // Set the character set pointer as null. Will be created again the next time IsCharacterSupportedByFont() + item.mCharacterSet = nullptr; + } + + // FcInitBringUptoDate did not seem to reload config file as was still getting old default font. + FcInitReinitialize(); FcPattern* matchPattern = FcPatternCreate(); if( matchPattern ) { - FcConfigSubstitute( NULL, matchPattern, FcMatchPattern ); + FcConfigSubstitute( nullptr, matchPattern, FcMatchPattern ); FcDefaultSubstitute( matchPattern ); - MatchFontDescriptionToPattern( matchPattern, mDefaultFontDescription ); + FcCharSet* characterSet = nullptr; + MatchFontDescriptionToPattern( matchPattern, mDefaultFontDescription, &characterSet ); FcPatternDestroy( matchPattern ); } + // Create again the character sets as they are not valid after FcInitReinitialize() + + for( const auto& description : mDefaultFonts ) + { + mDefaultFontCharacterSets.PushBack( CreateCharacterSetFromDescription( description ) ); + } + + for( const auto& description : mFontDescriptionCache ) + { + mCharacterSetCache.PushBack( CreateCharacterSetFromDescription( description ) ); + } + + for( auto& item : mFallbackCache ) + { + if( nullptr != item.fallbackFonts ) + { + if( nullptr == item.characterSets ) + { + item.characterSets = new CharacterSetList; + } + + for( const auto& description : *( item.fallbackFonts ) ) + { + item.characterSets->PushBack( CreateCharacterSetFromDescription( description ) ); + } + } + } + mDefaultFontDescriptionCached = true; } @@ -358,11 +465,18 @@ void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fon fontDescription.width = mDefaultFontDescription.width; fontDescription.weight = mDefaultFontDescription.weight; fontDescription.slant = mDefaultFontDescription.slant; + + DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultPlatformFontDescription\n"); } void FontClient::Plugin::GetSystemFonts( FontList& systemFonts ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetSystemFonts\n"); + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetSystemFonts\n"); if( mSystemFonts.empty() ) { @@ -370,118 +484,178 @@ void FontClient::Plugin::GetSystemFonts( FontList& systemFonts ) } systemFonts = mSystemFonts; + DALI_LOG_INFO( gLogFilter, Debug::General, " number of system fonts : [%d]\n", mSystemFonts.size() ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetSystemFonts\n"); } void FontClient::Plugin::GetDescription( FontId id, FontDescription& fontDescription ) const { - for( std::vector::const_iterator it = mFontIdCache.begin(), - endIt = mFontIdCache.end(); - it != endIt; - ++it ) - { - const FontIdCacheItem& item = *it; + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDescription\n"); + DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id ); + for( const auto& item : mFontDescriptionSizeCache ) + { if( item.fontId == id ) { fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId ); + + DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n"); return; } } - DALI_LOG_ERROR( "FontClient::Plugin::GetDescription. No description found for the font ID %d\n", id ); + DALI_LOG_INFO( gLogFilter, Debug::General, " No description found for the font ID %d\n", id ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n"); } PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id ) { + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetPointSize\n"); + DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id ); const FontId index = id - 1u; - if( id > 0u && - index < mFontCache.size() ) + if( ( id > 0u ) && + ( index < mFontFaceCache.size() ) ) { - return ( *( mFontCache.begin() + index ) ).mRequestedPointSize; + DALI_LOG_INFO( gLogFilter, Debug::General, " point size : %d\n", ( *( mFontFaceCache.begin() + index ) ).mRequestedPointSize ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n"); + return ( *( mFontFaceCache.begin() + index ) ).mRequestedPointSize; } else { - DALI_LOG_ERROR( "FontClient::Plugin::GetPointSize. Invalid font ID %d\n", id ); + DALI_LOG_INFO( gLogFilter, Debug::General, " Invalid font ID %d\n", id ); } + DALI_LOG_INFO( gLogFilter, Debug::General, " default point size : %d\n", TextAbstraction::FontClient::DEFAULT_POINT_SIZE ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n"); return TextAbstraction::FontClient::DEFAULT_POINT_SIZE; } +bool FontClient::Plugin::IsCharacterSupportedByFont( FontId fontId, Character character ) +{ + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::IsCharacterSupportedByFont\n"); + DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId ); + DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", character ); + + if( ( fontId < 1u ) || ( fontId > mFontFaceCache.size() ) ) + { + DALI_LOG_INFO( gLogFilter, Debug::General, " Invalid font id. Number of items in the cache: %d\n",mFontFaceCache.size()); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n"); + return false; + } + + --fontId; + + bool isSupported = false; + + FontFaceCacheItem& cacheItem = mFontFaceCache[fontId]; + + if( nullptr == cacheItem.mCharacterSet ) + { + // Create again the character set. + // It can be null if the ResetSystemDefaults() method has been called. + + FontDescription description; + description.path = cacheItem.mPath; + description.family = std::move( FontFamily( cacheItem.mFreeTypeFace->family_name ) ); + description.weight = FontWeight::NONE; + description.width = FontWidth::NONE; + description.slant = FontSlant::NONE; + + // Note FreeType doesn't give too much info to build a proper font style. + if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC ) + { + description.slant = FontSlant::ITALIC; + } + if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_BOLD ) + { + description.weight = FontWeight::BOLD; + } + + cacheItem.mCharacterSet = CreateCharacterSetFromDescription( description ); + } + + isSupported = FcCharSetHasChar( cacheItem.mCharacterSet, character ); + + DALI_LOG_INFO( gLogFilter, Debug::General, " is supported : %s\n", (isSupported ? "true" : "false") ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n"); + return isSupported; +} + FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList, - Character charcode, + const CharacterSetList& characterSetList, + Character character, PointSize26Dot6 requestedPointSize, bool preferColor ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFontForCharacter\n"); + DALI_ASSERT_DEBUG( ( fontList.size() == characterSetList.Count() ) && "FontClient::Plugin::FindFontForCharacter. Different number of fonts and character sets." ); + + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFontForCharacter\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", character ); + DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize ); + DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) ); FontId fontId = 0u; bool foundColor = false; + DALI_LOG_INFO( gLogFilter, Debug::General, " number of fonts : %d\n", fontList.size() ); + // Traverse the list of fonts. // Check for each font if supports the character. - for( FontList::const_iterator it = fontList.begin(), endIt = fontList.end(); - it != endIt; - ++it ) + for( unsigned int index = 0u, numberOfFonts = fontList.size(); index < numberOfFonts; ++index ) { - const FontDescription& description = *it; - - FcPattern* pattern = CreateFontFamilyPattern( description ); - - FcResult result = FcResultMatch; - FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result ); + const FontDescription& description = fontList[index]; + const FcCharSet* const characterSet = characterSetList[index]; - FcCharSet* charSet = NULL; - FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", description.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", description.path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[description.width] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[description.weight] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[description.slant] ); - if( FcCharSetHasChar( charSet, charcode ) ) + bool foundInRanges = false; + if( nullptr != characterSet ) { - Vector< PointSize26Dot6 > fixedSizes; - GetFixedSizes( description, - fixedSizes ); - - PointSize26Dot6 actualPointSize = requestedPointSize; - - const Vector< PointSize26Dot6 >::SizeType count = fixedSizes.Count(); - - if( 0 != count ) - { - // If the font is not scalable, pick the largest size <= requestedPointSize - actualPointSize = fixedSizes[0]; - for( unsigned int i=1; i actualPointSize ) - { - actualPointSize = fixedSizes[i]; - } - } - } + foundInRanges = FcCharSetHasChar( characterSet, character ); + } + if( foundInRanges ) + { fontId = GetFontId( description, requestedPointSize, - actualPointSize, 0u ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " font id : %d\n", fontId ); + if( preferColor ) { - foundColor = IsColorGlyph( fontId, GetGlyphIndex( fontId, charcode ) ); + if( ( fontId > 0 ) && + ( fontId - 1u < mFontFaceCache.size() ) ) + { + const FontFaceCacheItem& item = mFontFaceCache[fontId - 1u]; + + foundColor = item.mHasColorTables; + } + + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " foundColor : %s\n", ( foundColor ? "true" : "false" ) ); } // Keep going unless we prefer a different (color) font. if( !preferColor || foundColor ) { - FcPatternDestroy( match ); - FcPatternDestroy( pattern ); break; } } - - FcPatternDestroy( match ); - FcPatternDestroy( pattern ); } + DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFontForCharacter\n" ); return fontId; } @@ -489,7 +663,10 @@ FontId FontClient::Plugin::FindDefaultFont( Character charcode, PointSize26Dot6 requestedPointSize, bool preferColor ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindDefaultFont DefaultFontsList(%s)\n", (mDefaultFonts.empty()?"empty":"created") ); + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindDefaultFont\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", charcode ); + DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize ); + DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) ); FontId fontId(0); @@ -502,12 +679,17 @@ FontId FontClient::Plugin::FindDefaultFont( Character charcode, fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT ); fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT ); - SetFontList( fontDescription, mDefaultFonts ); + SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets ); } + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of default fonts : %d\n", mDefaultFonts.size() ); + // Traverse the list of default fonts. // Check for each default font if supports the character. - fontId = FindFontForCharacter( mDefaultFonts, charcode, requestedPointSize, preferColor ); + fontId = FindFontForCharacter( mDefaultFonts, mDefaultFontCharacterSets, charcode, requestedPointSize, preferColor ); + + DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindDefaultFont\n" ); return fontId; } @@ -517,6 +699,11 @@ FontId FontClient::Plugin::FindFallbackFont( Character charcode, PointSize26Dot6 requestedPointSize, bool preferColor ) { + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFont\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", charcode ); + DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize ); + DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) ); + // The font id to be returned. FontId fontId = 0u; @@ -528,37 +715,49 @@ FontId FontClient::Plugin::FindFallbackFont( Character charcode, fontDescription.width = ( ( FontWidth::NONE == preferredFontDescription.width ) ? IntToWidthType( DEFAULT_FONT_WIDTH ) : preferredFontDescription.width ); fontDescription.slant = ( ( FontSlant::NONE == preferredFontDescription.slant ) ? IntToSlantType( DEFAULT_FONT_SLANT ) : preferredFontDescription.slant ); + DALI_LOG_INFO( gLogFilter, Debug::General, " preferredFontDescription --> fontDescription\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, " [%s] --> [%s]\n", preferredFontDescription.family.c_str(), fontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontWeight::Name[preferredFontDescription.weight], FontWeight::Name[fontDescription.weight] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontWidth::Name[preferredFontDescription.width], FontWidth::Name[fontDescription.width] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontSlant::Name[preferredFontDescription.slant], FontSlant::Name[fontDescription.slant] ); + // Check first if the font's description has been queried before. - FontList* fontList( NULL ); + FontList* fontList = nullptr; + CharacterSetList* characterSetList = nullptr; - if( !FindFallbackFontList( fontDescription, fontList ) ) + if( !FindFallbackFontList( fontDescription, fontList, characterSetList ) ) { fontList = new FontList; - SetFontList( fontDescription, *fontList ); + characterSetList = new CharacterSetList; + + SetFontList( fontDescription, *fontList, *characterSetList ); // Add the font-list to the cache. - mFallbackCache.push_back( FallbackCacheItem( fontDescription, fontList ) ); + mFallbackCache.push_back( std::move( FallbackCacheItem( std::move( fontDescription ), fontList, characterSetList ) ) ); } - if( fontList ) + if( fontList && characterSetList ) { - fontId = FindFontForCharacter( *fontList, charcode, requestedPointSize, preferColor ); + fontId = FindFontForCharacter( *fontList, *characterSetList, charcode, requestedPointSize, preferColor ); } + DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFont\n"); return fontId; } FontId FontClient::Plugin::GetFontId( const FontPath& path, PointSize26Dot6 requestedPointSize, - PointSize26Dot6 actualPointSize, FaceIndex faceIndex, bool cacheDescription ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId fontPatch:%s\n", path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize ); FontId id( 0 ); - if( NULL != mFreeTypeLibrary ) + if( nullptr != mFreeTypeLibrary ) { FontId foundId(0); if( FindFont( path, requestedPointSize, faceIndex, foundId ) ) @@ -567,19 +766,27 @@ FontId FontClient::Plugin::GetFontId( const FontPath& path, } else { - id = CreateFont( path, requestedPointSize, actualPointSize, faceIndex, cacheDescription ); + id = CreateFont( path, requestedPointSize, faceIndex, cacheDescription ); } } + DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" ); + return id; } FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription, PointSize26Dot6 requestedPointSize, - PointSize26Dot6 actualPointSize, FaceIndex faceIndex ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId font family(%s)\n", fontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] ); + DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize ); // This method uses three vectors which caches: // * Pairs of non validated font descriptions and an index to a vector with paths to font file names. @@ -605,8 +812,6 @@ FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription, if( !FindValidatedFont( fontDescription, validatedFontId ) ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId Validating Font\n"); - // Use font config to validate the font's description. ValidateFont( fontDescription, validatedFontId ); @@ -621,45 +826,63 @@ FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription, // Retrieve the font id. Do not cache the description as it has been already cached. fontId = GetFontId( description.path, requestedPointSize, - actualPointSize, faceIndex, false ); + mFontFaceCache[fontId-1u].mCharacterSet = mCharacterSetCache[validatedFontId]; + // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries. - mFontIdCache.push_back( FontIdCacheItem( validatedFontId, - requestedPointSize, - fontId ) ); + mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId, + requestedPointSize, + fontId ) ); } + DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" ); + return fontId; } void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription, FontDescriptionId& validatedFontId ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValidateFont Validating Font family(%s) \n", fontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::ValidateFont\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] ); // Create a font pattern. FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription ); FontDescription description; - bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description ); + FcCharSet* characterSet = nullptr; + bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description, &characterSet ); FcPatternDestroy( fontFamilyPattern ); - if( matched ) + if( matched && ( nullptr != characterSet ) ) { // Set the index to the vector of paths to font file names. validatedFontId = mFontDescriptionCache.size(); + DALI_LOG_INFO( gLogFilter, Debug::General, " matched description; family : [%s]\n", description.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", description.path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[description.width] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[description.weight] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[description.slant] ); + DALI_LOG_INFO( gLogFilter, Debug::General, " validatedFontId : %d\n", validatedFontId ); + // Add the path to the cache. mFontDescriptionCache.push_back( description ); + mCharacterSetCache.PushBack( characterSet ); // Cache the index and the matched font's description. FontDescriptionCacheItem item( description, validatedFontId ); - mValidatedFontCache.push_back( item ); + mValidatedFontCache.push_back( std::move( item ) ); if( ( fontDescription.family != description.family ) || ( fontDescription.width != description.width ) || @@ -670,28 +893,24 @@ void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription, FontDescriptionCacheItem item( fontDescription, validatedFontId ); - mValidatedFontCache.push_back( item ); + mValidatedFontCache.push_back( std::move( item ) ); } } else { - DALI_LOG_ERROR( "FontClient::Plugin::ValidateFont failed for font %s %d %d %d\n", - fontDescription.family.c_str(), - fontDescription.width, - fontDescription.weight, - fontDescription.slant ); + DALI_LOG_INFO( gLogFilter, Debug::General, " font validation failed for font [%s]\n", fontDescription.family.c_str() ); } - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValidateFont validatedFontId(%u) font family(%s)\n", validatedFontId, fontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::ValidateFont\n" ); } void FontClient::Plugin::GetFontMetrics( FontId fontId, FontMetrics& metrics ) { if( ( fontId > 0 ) && - ( fontId - 1u < mFontCache.size() ) ) + ( fontId - 1u < mFontFaceCache.size() ) ) { - const FontFaceCacheItem& font = mFontCache[fontId-1]; + const FontFaceCacheItem& font = mFontFaceCache[fontId-1]; metrics = font.mMetrics; @@ -714,19 +933,19 @@ void FontClient::Plugin::GetFontMetrics( FontId fontId, } else { - DALI_LOG_ERROR( "Invalid font ID %d\n", fontId ); + DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId ); } } GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId, Character charcode ) { - GlyphIndex index( 0 ); + GlyphIndex index = 0u; - if( fontId > 0 && - fontId-1 < mFontCache.size() ) + if( ( fontId > 0u ) && + ( fontId - 1u < mFontFaceCache.size() ) ) { - FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace; + FT_Face ftFace = mFontFaceCache[fontId-1u].mFreeTypeFace; index = FT_Get_Char_Index( ftFace, charcode ); } @@ -760,9 +979,9 @@ bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array, FontId fontId = glyph.fontId; if( fontId > 0 && - fontId-1 < mFontCache.size() ) + fontId-1 < mFontFaceCache.size() ) { - const FontFaceCacheItem& font = mFontCache[fontId-1]; + const FontFaceCacheItem& font = mFontFaceCache[fontId-1]; FT_Face ftFace = font.mFreeTypeFace; @@ -797,14 +1016,14 @@ bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array, } else { - DALI_LOG_ERROR( "FreeType Bitmap Load_Glyph error %d\n", error ); + DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetBitmapMetrics. FreeType Bitmap Load_Glyph error %d\n", error ); success = false; } } else #endif { - int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_DEFAULT ); + int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_NO_AUTOHINT ); if( FT_Err_Ok == error ) { @@ -848,9 +1067,9 @@ bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array, FontId fontId = array[i].fontId; if( fontId > 0 && - fontId-1 < mFontCache.size() ) + fontId-1 < mFontFaceCache.size() ) { - FontFaceCacheItem& font = mFontCache[fontId-1]; + FontFaceCacheItem& font = mFontFaceCache[fontId-1]; if( ! font.mVectorFontId ) { @@ -879,29 +1098,42 @@ bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array, #endif } -void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data ) +void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool softwareItalic, bool softwareBold, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth ) { if( ( fontId > 0 ) && - ( fontId - 1u < mFontCache.size() ) ) + ( fontId - 1u < mFontFaceCache.size() ) ) { - FT_Face ftFace = mFontCache[fontId - 1u].mFreeTypeFace; + FT_Face ftFace = mFontFaceCache[fontId - 1u].mFreeTypeFace; FT_Error error; #ifdef FREETYPE_BITMAP_SUPPORT // Check to see if this is fixed size bitmap - if ( mFontCache[fontId - 1u].mIsFixedSizeBitmap ) + if ( mFontFaceCache[fontId - 1u].mIsFixedSizeBitmap ) { error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR ); } else #endif { - error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT ); + error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_NO_AUTOHINT ); } if( FT_Err_Ok == error ) { FT_Glyph glyph; + + if( softwareBold ) + { + FT_GlyphSlot_Embolden(ftFace->glyph); + } + + if( softwareItalic ) + { + // FT Matrix uses 16.16 fixed-point format + FT_Matrix transform = {0x10000, FONT_SLANT_TANGENT, 0x00000, 0x10000}; + FT_Outline_Transform(&ftFace->glyph->outline, &transform); + } + error = FT_Get_Glyph( ftFace->glyph, &glyph ); // Convert to bitmap if necessary @@ -909,15 +1141,42 @@ void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, Dal { if( glyph->format != FT_GLYPH_FORMAT_BITMAP ) { + // Check whether we should create a bitmap for the outline + if( glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0 ) + { + // Set up a stroker + FT_Stroker stroker; + error = FT_Stroker_New(mFreeTypeLibrary, &stroker ); + + 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 ); + } + } + 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 ); if ( FT_Err_Ok == error ) { - FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph; + FT_BitmapGlyph bitmapGlyph = reinterpret_cast< FT_BitmapGlyph >( glyph ); ConvertBitmap( data, bitmapGlyph->bitmap ); } else { - DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error ); + DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Get_Glyph Failed with error: %d\n", error ); } } else @@ -931,17 +1190,16 @@ void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, Dal } else { - DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error ); + DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Load_Glyph Failed with error: %d\n", error ); } } } -PixelData FontClient::Plugin::CreateBitmap( FontId fontId, - GlyphIndex glyphIndex ) +PixelData FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth ) { TextAbstraction::FontClient::GlyphBufferData data; - CreateBitmap( fontId, glyphIndex, data ); + CreateBitmap( fontId, glyphIndex, false, false, data, outlineWidth ); return PixelData::New( data.buffer, data.width * data.height * Pixel::GetBytesPerPixel( data.format ), @@ -953,14 +1211,14 @@ PixelData FontClient::Plugin::CreateBitmap( FontId fontId, void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight ) { - blob = NULL; + blob = nullptr; blobLength = 0; #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING if( fontId > 0 && - fontId-1 < mFontCache.size() ) + fontId-1 < mFontFaceCache.size() ) { - FontFaceCacheItem& font = mFontCache[fontId-1]; + FontFaceCacheItem& font = mFontFaceCache[fontId-1]; if( ! font.mVectorFontId ) { @@ -974,17 +1232,20 @@ void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize ) { + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetEllipsisGlyph\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize %d.\n", requestedPointSize ); + // First look into the cache if there is an ellipsis glyph for the requested point size. - for( Vector::ConstIterator it = mEllipsisCache.Begin(), - endIt = mEllipsisCache.End(); - it != endIt; - ++it ) + for( const auto& item : mEllipsisCache ) { - const EllipsisItem& item = *it; - if( fabsf( item.requestedPointSize - requestedPointSize ) < Math::MACHINE_EPSILON_1000 ) { // Use the glyph in the cache. + + DALI_LOG_INFO( gLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index ); + DALI_LOG_INFO( gLogFilter, Debug::General, " font %d.\n", item.glyph.fontId ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" ); + return item.glyph; } } @@ -1001,11 +1262,15 @@ const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requested false ); // Set the character index to access the glyph inside the font. - item.glyph.index = FT_Get_Char_Index( mFontCache[item.glyph.fontId-1].mFreeTypeFace, + item.glyph.index = FT_Get_Char_Index( mFontFaceCache[item.glyph.fontId-1].mFreeTypeFace, ELLIPSIS_CHARACTER ); GetBitmapMetrics( &item.glyph, 1u, true ); + DALI_LOG_INFO( gLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index ); + DALI_LOG_INFO( gLogFilter, Debug::General, " font %d.\n", item.glyph.fontId ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" ); + return item.glyph; } @@ -1015,13 +1280,13 @@ bool FontClient::Plugin::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex ) #ifdef FREETYPE_BITMAP_SUPPORT if( ( fontId > 0 ) && - ( fontId - 1u < mFontCache.size() ) ) + ( fontId - 1u < mFontFaceCache.size() ) ) { - const FontFaceCacheItem& item = mFontCache[fontId - 1u]; + const FontFaceCacheItem& item = mFontFaceCache[fontId - 1u]; FT_Face ftFace = item.mFreeTypeFace; // Check to see if this is fixed size bitmap - if( item.mIsFixedSizeBitmap ) + if( item.mHasColorTables ) { error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR ); } @@ -1031,14 +1296,22 @@ bool FontClient::Plugin::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex ) return FT_Err_Ok == error; } +bool FontClient::Plugin::AddCustomFontDirectory( const FontPath& path ) +{ + // nullptr as first parameter means the current configuration is used. + return FcConfigAppFontAddDir( nullptr, reinterpret_cast( path.c_str() ) ); +} + void FontClient::Plugin::InitSystemFonts() { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts \n"); + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::InitSystemFonts\n" ); FcFontSet* fontSet = GetFcFontSet(); if( fontSet ) { + DALI_LOG_INFO( gLogFilter, Debug::General, " number of system fonts : %d\n", fontSet->nfont ); + // Reserve some space to avoid reallocations. mSystemFonts.reserve( fontSet->nfont ); @@ -1054,7 +1327,7 @@ void FontClient::Plugin::InitSystemFonts() mSystemFonts.push_back( FontDescription() ); FontDescription& fontDescription = mSystemFonts.back(); - fontDescription.path = path; + fontDescription.path = std::move( path ); int width = 0; int weight = 0; @@ -1066,30 +1339,37 @@ void FontClient::Plugin::InitSystemFonts() fontDescription.width = IntToWidthType( width ); fontDescription.weight = IntToWeightType( weight ); fontDescription.slant = IntToSlantType( slant ); - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts font family(%s)\n", fontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", fontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] ); } } FcFontSetDestroy( fontSet ); } + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::InitSystemFonts\n" ); } -bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription ) +bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet ) { + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::MatchFontDescriptionToPattern\n" ); + FcResult result = FcResultMatch; - FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result ); + FcPattern* match = FcFontMatch( nullptr /* use default configure */, pattern, &result ); - bool ret = false; + const bool matched = nullptr != match; + DALI_LOG_INFO( gLogFilter, Debug::General, " pattern matched : %s\n", ( matched ? "true" : "false" ) ); - if( match ) + if( matched ) { int width = 0; int weight = 0; int slant = 0; GetFcString( match, FC_FILE, fontDescription.path ); GetFcString( match, FC_FAMILY, fontDescription.family ); - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::MatchFontDescriptionToPattern matched:%s \n", fontDescription.family.c_str()); GetFcInt( match, FC_WIDTH, width ); GetFcInt( match, FC_WEIGHT, weight ); GetFcInt( match, FC_SLANT, slant ); @@ -1097,15 +1377,24 @@ bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali fontDescription.weight = IntToWeightType( weight ); fontDescription.slant = IntToSlantType( slant ); + // Cache the character ranges. + FcPatternGetCharSet( match, FC_CHARSET, 0u, characterSet ); + // destroyed the matched pattern FcPatternDestroy( match ); - ret = true; + + DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] ); } - return ret; -} + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::MatchFontDescriptionToPattern\n" ); + return matched; +} -FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription ) +FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription ) const { // create the cached font family lookup pattern // a pattern holds a set of names, each name refers to a property of the font @@ -1113,12 +1402,19 @@ FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& f if( !fontFamilyPattern ) { - return NULL; + return nullptr; } // add a property to the pattern for the font family FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast( fontDescription.family.c_str() ) ); + // add a property to the pattern for local setting. + const char* locale = setlocale( LC_MESSAGES, nullptr ); + if( locale != nullptr) + { + FcPatternAddString( fontFamilyPattern, FC_LANG, reinterpret_cast( locale ) ); + } + int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width]; if( width < 0 ) { @@ -1148,7 +1444,7 @@ FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& f FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast( FONT_FORMAT.c_str() ) ); // modify the config, with the mFontFamilyPatterm - FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern ); + FcConfigSubstitute( nullptr /* use default configure */, fontFamilyPattern, FcMatchPattern ); // provide default values for unspecified properties in the font pattern // e.g. patterns without a specified style or weight are set to Medium @@ -1175,7 +1471,7 @@ _FcFontSet* FontClient::Plugin::GetFcFontSet() const // get a list of fonts // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns - FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet ); + FcFontSet* fontset = FcFontList( nullptr /* the default configuration is checked to be up to date, and used */, pattern, objectSet ); // clear up the object set if( objectSet ) @@ -1195,7 +1491,7 @@ bool FontClient::Plugin::GetFcString( const FcPattern* const pattern, const char* const n, std::string& string ) { - FcChar8* file = NULL; + FcChar8* file = nullptr; const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file ); if( FcResultMatch == retVal ) @@ -1223,11 +1519,14 @@ bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* FontId FontClient::Plugin::CreateFont( const FontPath& path, PointSize26Dot6 requestedPointSize, - PointSize26Dot6 actualPointSize, FaceIndex faceIndex, bool cacheDescription ) { - FontId id( 0 ); + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::CreateFont\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize ); + + FontId id = 0u; // Create & cache new font face FT_Face ftFace; @@ -1238,63 +1537,68 @@ FontId FontClient::Plugin::CreateFont( const FontPath& path, if( FT_Err_Ok == error ) { + // Check if a font is scalable. + const bool isScalable = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_SCALABLE ) ); + const bool hasFixedSizedBitmaps = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) && ( 0 != ftFace->num_fixed_sizes ); + const bool hasColorTables = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_COLOR ) ); + + DALI_LOG_INFO( gLogFilter, Debug::General, " isScalable : [%s]\n", ( isScalable ? "true" : "false" ) ); + DALI_LOG_INFO( gLogFilter, Debug::General, " hasFixedSizedBitmaps : [%s]\n", ( hasFixedSizedBitmaps ? "true" : "false" ) ); + DALI_LOG_INFO( gLogFilter, Debug::General, " hasColorTables : [%s]\n", ( hasColorTables ? "true" : "false" ) ); + // Check to see if the font contains fixed sizes? - if ( ftFace->num_fixed_sizes && ftFace->available_sizes ) + if( !isScalable && hasFixedSizedBitmaps ) { - // Ensure this size is available - for ( int i = 0; i < ftFace->num_fixed_sizes; ++i ) + PointSize26Dot6 actualPointSize = 0u; + int fixedSizeIndex = 0; + for( ; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex ) { - if ( static_cast( actualPointSize ) == ftFace->available_sizes[ i ].size ) - { - // Tell Freetype to use this size - error = FT_Select_Size( ftFace, i ); - if ( FT_Err_Ok != error ) - { - DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error ); - } - else - { - float fixedWidth = static_cast< float >( ftFace->available_sizes[ i ].width ); - float fixedHeight = static_cast< float >( ftFace->available_sizes[ i ].height ); + const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size; + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " size index : %d, size : %d\n", fixedSizeIndex, fixedSize ); - // Indicate that the font is a fixed sized bitmap - FontMetrics metrics( fixedHeight, // The ascender in pixels. - 0.0f, - fixedHeight, // The height in pixels. - 0.0f, - 0.0f ); + if( fixedSize >= requestedPointSize ) + { + actualPointSize = fixedSize; + break; + } + } - mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight ) ); - id = mFontCache.size(); + if( 0u == actualPointSize ) + { + // The requested point size is bigger than the bigest fixed size. + fixedSizeIndex = ftFace->num_fixed_sizes - 1; + actualPointSize = ftFace->available_sizes[fixedSizeIndex].size; + } - if( cacheDescription ) - { - CacheFontPath( ftFace, id, requestedPointSize, path ); - } + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize ); - return id; - } - } + // Tell Freetype to use this size + error = FT_Select_Size( ftFace, fixedSizeIndex ); + if ( FT_Err_Ok != error ) + { + DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Select_Size error: %d\n", error ); } - - // Can't find this size - std::stringstream sizes; - for ( int i = 0; i < ftFace->num_fixed_sizes; ++i ) + else { - if ( i ) - { - sizes << ", "; - } - sizes << ftFace->available_sizes[ i ].size; + float fixedWidth = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].width ); + float fixedHeight = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].height ); + + // Indicate that the font is a fixed sized bitmap + FontMetrics metrics( fixedHeight, // The ascender in pixels. + 0.0f, + fixedHeight, // The height in pixels. + 0.0f, + 0.0f ); + + mFontFaceCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight, hasColorTables ) ); + id = mFontFaceCache.size(); } - DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n", - path.c_str(), actualPointSize, sizes.str().c_str() ); } else { error = FT_Set_Char_Size( ftFace, 0, - actualPointSize, + requestedPointSize, mDpiHorizontal, mDpiVertical ); @@ -1309,25 +1613,31 @@ FontId FontClient::Plugin::CreateFont( const FontPath& path, static_cast< float >( ftFace->underline_position ) * FROM_266, static_cast< float >( ftFace->underline_thickness ) * FROM_266 ); - mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) ); - id = mFontCache.size(); - - if( cacheDescription ) - { - CacheFontPath( ftFace, id, requestedPointSize, path ); - } + mFontFaceCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) ); + id = mFontFaceCache.size(); } else { - DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, actualPointSize ); + DALI_LOG_INFO( gLogFilter, Debug::General, " FreeType Set_Char_Size error: %d for pointSize %d\n", error, requestedPointSize ); + } + } + + if( 0u != id ) + { + if( cacheDescription ) + { + CacheFontPath( ftFace, id, requestedPointSize, path ); } } } else { - DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::General, " FreeType New_Face error: %d for [%s]\n", error, path.c_str() ); } + DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::CreateFont\n" ); + return id; } @@ -1342,7 +1652,7 @@ void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBuffer if( srcBitmap.pitch == static_cast( srcBitmap.width ) ) { const unsigned int bufferSize = srcBitmap.width * srcBitmap.rows; - data.buffer = new unsigned char[bufferSize]; + data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[]. data.width = srcBitmap.width; data.height = srcBitmap.rows; data.format = Pixel::L8; @@ -1389,7 +1699,7 @@ void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBuffer #endif default: { - DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::ConvertBitmap. FontClient Unable to create Bitmap of this PixelType\n" ); break; } } @@ -1401,40 +1711,48 @@ bool FontClient::Plugin::FindFont( const FontPath& path, FaceIndex faceIndex, FontId& fontId ) const { + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of fonts in the cache : %d\n", mFontFaceCache.size() ); + fontId = 0u; - for( std::vector::const_iterator it = mFontCache.begin(), - endIt = mFontCache.end(); - it != endIt; - ++it, ++fontId ) + for( const auto& cacheItem : mFontFaceCache ) { - const FontFaceCacheItem& cacheItem = *it; - + ++fontId; if( cacheItem.mRequestedPointSize == requestedPointSize && cacheItem.mFaceIndex == faceIndex && cacheItem.mPath == path ) { - ++fontId; + DALI_LOG_INFO( gLogFilter, Debug::General, " font found, id : %d\n", fontId ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" ); + return true; } } + DALI_LOG_INFO( gLogFilter, Debug::General, " font not found\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" ); + + fontId = 0u; return false; } bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription, FontDescriptionId& validatedFontId ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont fontDescription family(%s)\n", fontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindValidatedFont\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of validated fonts in the cache : %d\n", mValidatedFontCache.size() ); validatedFontId = 0u; - for( std::vector::const_iterator it = mValidatedFontCache.begin(), - endIt = mValidatedFontCache.end(); - it != endIt; - ++it ) + for( const auto& item : mValidatedFontCache ) { - const FontDescriptionCacheItem& item = *it; - if( !fontDescription.family.empty() && ( fontDescription.family == item.fontDescription.family ) && ( fontDescription.width == item.fontDescription.width ) && @@ -1443,30 +1761,33 @@ bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescripti { validatedFontId = item.index; - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont validated font family(%s) font id (%u) \n", fontDescription.family.c_str(), validatedFontId ); - + DALI_LOG_INFO( gLogFilter, Debug::General, " validated font found, id : %d\n", validatedFontId ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" ); return true; } } - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont NOT VALIDATED return false\n" ); - + DALI_LOG_INFO( gLogFilter, Debug::General, " validated font not found\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" ); return false; } bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription, - FontList*& fontList ) + FontList*& fontList, + CharacterSetList*& characterSetList ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList fontDescription family(%s)\n", fontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFontList\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of fallback font lists in the cache : %d\n", mFallbackCache.size() ); - fontList = NULL; + fontList = nullptr; - for( std::vector::const_iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end(); - it != endIt; - ++it ) + for( const auto& item : mFallbackCache ) { - const FallbackCacheItem& item = *it; - if( !fontDescription.family.empty() && ( fontDescription.family == item.fontDescription.family ) && ( fontDescription.width == item.fontDescription.width ) && @@ -1474,15 +1795,16 @@ bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescri ( fontDescription.slant == item.fontDescription.slant ) ) { fontList = item.fallbackFonts; + characterSetList = item.characterSets; - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList font family(%s) font-list (%p) \n", fontDescription.family.c_str(), fontList ); - + DALI_LOG_INFO( gLogFilter, Debug::General, " fallback font list found.\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" ); return true; } } - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList NOT FOUND return false\n" ); - + DALI_LOG_INFO( gLogFilter, Debug::General, " fallback font list not found.\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" ); return false; } @@ -1490,28 +1812,34 @@ bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId, PointSize26Dot6 requestedPointSize, FontId& fontId ) { + DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, " validatedFontId : %d\n", validatedFontId ); + DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize ); + fontId = 0u; - for( std::vector::const_iterator it = mFontIdCache.begin(), - endIt = mFontIdCache.end(); - it != endIt; - ++it ) + for( const auto& item : mFontDescriptionSizeCache ) { - const FontIdCacheItem& item = *it; - if( ( validatedFontId == item.validatedFontId ) && ( requestedPointSize == item.requestedPointSize ) ) { fontId = item.fontId; + + DALI_LOG_INFO( gLogFilter, Debug::General, " font found, id : %d\n", fontId ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" ); return true; } } + DALI_LOG_INFO( gLogFilter, Debug::General, " font not found.\n" ); + DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" ); return false; } bool FontClient::Plugin::IsScalable( const FontPath& path ) { + bool isScalable = false; + FT_Face ftFace; int error = FT_New_Face( mFreeTypeLibrary, path.c_str(), @@ -1519,9 +1847,14 @@ bool FontClient::Plugin::IsScalable( const FontPath& path ) &ftFace ); if( FT_Err_Ok != error ) { - DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: %s\n", path.c_str() ); } - return ( ftFace->num_fixed_sizes == 0 ); + else + { + isScalable = ftFace->face_flags & FT_FACE_FLAG_SCALABLE; + } + + return isScalable; } bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription ) @@ -1532,8 +1865,8 @@ bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription ) FcResult result = FcResultMatch; // match the pattern - FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result ); - bool isScalable = true; + FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result ); + bool isScalable = false; if( match ) { @@ -1544,11 +1877,7 @@ bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription ) } else { - DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n", - fontDescription.family.c_str(), - fontDescription.width, - fontDescription.weight, - fontDescription.slant ); + DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() ); } FcPatternDestroy( fontFamilyPattern ); FcPatternDestroy( match ); @@ -1567,7 +1896,7 @@ void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize2 &ftFace ); if( FT_Err_Ok != error ) { - DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() ); + DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font path : [%s]\n", path.c_str() ); } // Fetch the number of fixed sizes available @@ -1589,7 +1918,7 @@ void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription, FcResult result = FcResultMatch; // match the pattern - FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result ); + FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result ); if( match ) { @@ -1600,11 +1929,7 @@ void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription, } else { - DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n", - fontDescription.family.c_str(), - fontDescription.width, - fontDescription.weight, - fontDescription.slant ); + DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() ); } FcPatternDestroy( match ); FcPatternDestroy( fontFamilyPattern ); @@ -1614,7 +1939,7 @@ void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Do { FontDescription description; description.path = path; - description.family = FontFamily( ftFace->family_name ); + description.family = std::move( FontFamily( ftFace->family_name ) ); description.weight = FontWeight::NONE; description.width = FontWidth::NONE; description.slant = FontSlant::NONE; @@ -1636,20 +1961,63 @@ void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Do // Set the index to the vector of paths to font file names. validatedFontId = mFontDescriptionCache.size(); + FcPattern* pattern = CreateFontFamilyPattern( description ); + + FcResult result = FcResultMatch; + FcPattern* match = FcFontMatch( nullptr, pattern, &result ); + + FcCharSet* characterSet = nullptr; + FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet ); + + FcPatternDestroy( pattern ); + + mMatchedFcPatternCache.PushBack( match ); + + mFontFaceCache[id-1u].mCharacterSet = characterSet; + // Add the path to the cache. mFontDescriptionCache.push_back( description ); + mCharacterSetCache.PushBack( characterSet ); // Cache the index and the font's description. - FontDescriptionCacheItem item( description, - validatedFontId ); - - mValidatedFontCache.push_back( item ); + mValidatedFontCache.push_back( std::move( FontDescriptionCacheItem( std::move( description ), + validatedFontId) ) ); // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries. - mFontIdCache.push_back( FontIdCacheItem( validatedFontId, - requestedPointSize, - id ) ); + mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId, + requestedPointSize, + id ) ); + } +} + +FcCharSet* FontClient::Plugin::CreateCharacterSetFromDescription( const FontDescription& description ) +{ + FcCharSet* characterSet = nullptr; + + FcPattern* pattern = CreateFontFamilyPattern( description ); + + if( nullptr != pattern ) + { + FcResult result = FcResultMatch; + FcPattern* match = FcFontMatch( nullptr, pattern, &result ); + + FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet ); + + mMatchedFcPatternCache.PushBack( match ); + + FcPatternDestroy( pattern ); + } + + return characterSet; +} + +void FontClient::Plugin::DestroyMatchedPatterns() +{ + for (auto & object : mMatchedFcPatternCache) + { + FcPatternDestroy(reinterpret_cast(object)); } + mMatchedFcPatternCache.Clear(); } } // namespace Internal