/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
#include <dali/internal/text-abstraction/font-client-plugin-impl.h>
// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-list.h>
#include <dali/public-api/common/dali-vector.h>
#include <dali/public-api/common/vector-wrapper.h>
-#include <dali/public-api/text-abstraction/glyph-info.h>
#include <dali/integration-api/debug.h>
+#include <dali/integration-api/platform-abstraction.h>
+#include <dali/internal/text-abstraction/font-client-helper.h>
+#include <platform-abstractions/portable/image-operations.h>
+#include <adaptor-impl.h>
// EXTERNAL INCLUDES
#include <fontconfig/fontconfig.h>
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
+#endif
+
/**
* Conversion from Fractional26.6 to float
*/
-namespace
-{
const float FROM_266 = 1.0f / 64.0f;
+const float POINTS_PER_INCH = 72.f;
const std::string FONT_FORMAT( "TrueType" );
const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
-const std::string DEFAULT_FONT_STYLE( "Regular" );
-}
+const int DEFAULT_FONT_WIDTH = 100; // normal
+const int DEFAULT_FONT_WEIGHT = 80; // normal
+const int DEFAULT_FONT_SLANT = 0; // normal
+
+const uint32_t ELLIPSIS_CHARACTER = 0x2026;
+
+// http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
+
+// NONE -1 --> DEFAULT_FONT_WIDTH (NORMAL) will be used.
+// ULTRA_CONDENSED 50
+// EXTRA_CONDENSED 63
+// CONDENSED 75
+// SEMI_CONDENSED 87
+// NORMAL 100
+// SEMI_EXPANDED 113
+// EXPANDED 125
+// EXTRA_EXPANDED 150
+// ULTRA_EXPANDED 200
+const int FONT_WIDTH_TYPE_TO_INT[] = { -1, 50, 63, 75, 87, 100, 113, 125, 150, 200 };
+const unsigned int NUM_FONT_WIDTH_TYPE = sizeof( FONT_WIDTH_TYPE_TO_INT ) / sizeof( int );
+
+// NONE -1 --> DEFAULT_FONT_WEIGHT (NORMAL) will be used.
+// THIN 0
+// ULTRA_LIGHT, EXTRA_LIGHT 40
+// LIGHT 50
+// DEMI_LIGHT, SEMI_LIGHT 55
+// BOOK 75
+// NORMAL, REGULAR 80
+// MEDIUM 100
+// DEMI_BOLD, SEMI_BOLD 180
+// BOLD 200
+// ULTRA_BOLD, EXTRA_BOLD 205
+// BLACK, HEAVY, EXTRA_BLACK 210
+const int FONT_WEIGHT_TYPE_TO_INT[] = { -1, 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210 };
+const unsigned int NUM_FONT_WEIGHT_TYPE = sizeof( FONT_WEIGHT_TYPE_TO_INT ) / sizeof( int );
+
+// NONE -1 --> DEFAULT_FONT_SLANT (NORMAL) will be used.
+// NORMAL, ROMAN 0
+// ITALIC 100
+// OBLIQUE 110
+const int FONT_SLANT_TYPE_TO_INT[] = { -1, 0, 100, 110 };
+const unsigned int NUM_FONT_SLANT_TYPE = sizeof( FONT_SLANT_TYPE_TO_INT ) / sizeof( int );
+
+} // namespace
using Dali::Vector;
namespace Internal
{
-const bool FONT_FIXED_SIZE_BITMAP( true );
+/**
+ * @brief Returns the FontWidth's enum index for the given width value.
+ *
+ * @param[in] width The width value.
+ *
+ * @return The FontWidth's enum index.
+ */
+FontWidth::Type IntToWidthType( int width )
+{
+ return static_cast<FontWidth::Type>( ValueToIndex( width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u ) );
+}
-FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontFamily& fontFamily,
- const FontStyle& fontStyle,
+/**
+ * @brief Returns the FontWeight's enum index for the given weight value.
+ *
+ * @param[in] weight The weight value.
+ *
+ * @return The FontWeight's enum index.
+ */
+FontWeight::Type IntToWeightType( int weight )
+{
+ return static_cast<FontWeight::Type>( ValueToIndex( weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u ) );
+}
+
+/**
+ * @brief Returns the FontSlant's enum index for the given slant value.
+ *
+ * @param[in] slant The slant value.
+ *
+ * @return The FontSlant's enum index.
+ */
+FontSlant::Type IntToSlantType( int slant )
+{
+ return static_cast<FontSlant::Type>( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) );
+}
+
+ FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( const FontDescription& font, FontList* fallbackFonts, CharacterSetList* characterSets )
+: fontDescription( font ),
+ fallbackFonts( fallbackFonts ),
+ characterSets( characterSets )
+{
+}
+
+FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
FontDescriptionId index )
-: fontFamily( fontFamily ),
- fontStyle( fontStyle ),
+: fontDescription( fontDescription ),
index( index )
{
}
FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId,
- PointSize26Dot6 pointSize,
+ PointSize26Dot6 requestedPointSize,
FontId fontId )
: validatedFontId( validatedFontId ),
- pointSize( pointSize ),
+ requestedPointSize( requestedPointSize ),
fontId( fontId )
{
}
-FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
- const FontPath& path,
- PointSize26Dot6 pointSize,
- FaceIndex face,
- const FontMetrics& metrics )
+FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
+ const FontPath& path,
+ PointSize26Dot6 requestedPointSize,
+ FaceIndex face,
+ const FontMetrics& metrics )
: mFreeTypeFace( ftFace ),
mPath( path ),
- mPointSize( pointSize ),
+ mRequestedPointSize( requestedPointSize ),
mFaceIndex( face ),
mMetrics( metrics ),
+ mCharacterSet( NULL ),
mFixedWidthPixels( 0.0f ),
mFixedHeightPixels( 0.0f ),
- mIsFixedSizeBitmap( false )
+ mVectorFontId( 0 ),
+ mIsFixedSizeBitmap( false ),
+ mHasColorTables( false )
{
}
-FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
- const FontPath& path,
- PointSize26Dot6 pointSize,
- FaceIndex face,
- const FontMetrics& metrics,
- float fixedWidth,
- float fixedHeight )
+FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
+ const FontPath& path,
+ PointSize26Dot6 requestedPointSize,
+ FaceIndex face,
+ const FontMetrics& metrics,
+ float fixedWidth,
+ float fixedHeight,
+ bool hasColorTables )
: mFreeTypeFace( ftFace ),
mPath( path ),
- mPointSize( pointSize ),
+ mRequestedPointSize( requestedPointSize ),
mFaceIndex( face ),
mMetrics( metrics ),
+ mCharacterSet( NULL ),
mFixedWidthPixels( fixedWidth ),
mFixedHeightPixels( fixedHeight ),
- mIsFixedSizeBitmap( true )
+ mVectorFontId( 0 ),
+ mIsFixedSizeBitmap( true ),
+ mHasColorTables( hasColorTables )
{
}
: mFreeTypeLibrary( NULL ),
mDpiHorizontal( horizontalDpi ),
mDpiVertical( verticalDpi ),
+ mDefaultFontDescription(),
mSystemFonts(),
mDefaultFonts(),
mFontCache(),
mValidatedFontCache(),
mFontDescriptionCache( 1u ),
- mFontIdCache()
+ mCharacterSetCache(),
+ mFontIdCache(),
+ mVectorFontCache( NULL ),
+ 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<FallbackCacheItem>::iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
+ it != endIt;
+ ++it )
+ {
+ FallbackCacheItem& item = *it;
+
+ if( item.fallbackFonts )
+ {
+ delete item.fallbackFonts;
+ delete item.characterSets;
+ item.fallbackFonts = NULL;
+ item.characterSets = NULL;
+ }
+ }
+
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+ delete mVectorFontCache;
+#endif
+
FT_Done_FreeType( mFreeTypeLibrary );
}
mDpiVertical = verticalDpi;
}
-void FontClient::Plugin::SetDefaultFontFamily( const FontFamily& fontFamilyName,
- const FontStyle& fontStyle )
+void FontClient::Plugin::ResetSystemDefaults()
+{
+ mDefaultFontDescriptionCached = false;
+}
+
+ void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList )
{
- mDefaultFonts.clear();
+ 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] );
- FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamilyName,
- fontStyle );
+ fontList.clear();
+
+ FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
FcResult result = FcResultMatch;
if( NULL != fontSet )
{
+ DALI_LOG_INFO( gLogFilter, Debug::General, " number of fonts found : [%d]\n", fontSet->nfont );
// Reserve some space to avoid reallocations.
- mDefaultFonts.reserve( fontSet->nfont );
+ fontList.reserve( fontSet->nfont );
for( int i = 0u; i < fontSet->nfont; ++i )
{
// Skip fonts with no path
if( GetFcString( fontPattern, FC_FILE, path ) )
{
- mDefaultFonts.push_back( FontDescription() );
- FontDescription& fontDescription = mDefaultFonts.back();
-
- fontDescription.path = path;
-
- GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
- GetFcString( fontPattern, FC_STYLE, fontDescription.style );
+ FcCharSet* characterSet = NULL;
+ FcPatternGetCharSet( fontPattern, FC_CHARSET, 0u, &characterSet );
+
+ characterSetList.PushBack( characterSet );
+ fontList.push_back( FontDescription() );
+ FontDescription& newFontDescription = fontList.back();
+
+ newFontDescription.path = path;
+
+ int width = 0;
+ int weight = 0;
+ int slant = 0;
+ GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
+ GetFcInt( fontPattern, FC_WIDTH, width );
+ GetFcInt( fontPattern, FC_WEIGHT, weight );
+ GetFcInt( fontPattern, FC_SLANT, slant );
+ 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::General, "-->FontClient::Plugin::GetDefaultFonts\n" );
+
if( mDefaultFonts.empty() )
{
- SetDefaultFontFamily( DEFAULT_FONT_FAMILY_NAME,
- DEFAULT_FONT_STYLE );
+ FontDescription fontDescription;
+ fontDescription.family = DEFAULT_FONT_FAMILY_NAME; // todo This could be set to the Platform font
+ fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
+ fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
+ fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
+ 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::General, "-->FontClient::Plugin::GetDefaultPlatformFontDescription\n");
+
+ if( !mDefaultFontDescriptionCached )
+ {
+ FcInitReinitialize(); // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
+
+ FcPattern* matchPattern = FcPatternCreate();
+
+ if( matchPattern )
+ {
+ FcConfigSubstitute( NULL, matchPattern, FcMatchPattern );
+ FcDefaultSubstitute( matchPattern );
+
+ FcCharSet* characterSet = NULL;
+ MatchFontDescriptionToPattern( matchPattern, mDefaultFontDescription, &characterSet );
+ FcPatternDestroy( matchPattern );
+ }
+
+ mDefaultFontDescriptionCached = true;
+ }
+
+ fontDescription.path = mDefaultFontDescription.path;
+ fontDescription.family = mDefaultFontDescription.family;
+ 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::General, "-->FontClient::Plugin::GetSystemFonts\n");
+
if( mSystemFonts.empty() )
{
InitSystemFonts();
}
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
{
+ DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDescription\n");
+ DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
+
for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
endIt = mFontIdCache.end();
it != endIt;
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 < mFontCache.size() ) )
{
- return ( *( mFontCache.begin() + index ) ).mPointSize;
+ DALI_LOG_INFO( gLogFilter, Debug::General, " point size : %d\n", ( *( mFontCache.begin() + index ) ).mRequestedPointSize );
+ DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
+ return ( *( mFontCache.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;
}
-FontId FontClient::Plugin::FindDefaultFont( Character charcode,
- PointSize26Dot6 requestedSize,
- bool preferColor )
+bool FontClient::Plugin::IsCharacterSupportedByFont( FontId fontId, Character character )
{
- FontId fontId(0);
- bool foundColor(false);
+ 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 );
- // Create the list of default fonts if it has not been created.
- if( mDefaultFonts.empty() )
+ if( ( fontId < 1u ) || ( fontId > mFontCache.size() ) )
{
- SetDefaultFontFamily( DEFAULT_FONT_FAMILY_NAME,
- DEFAULT_FONT_STYLE );
+ DALI_LOG_INFO( gLogFilter, Debug::General, " Invalid font id. Number of items in the cache: %d\n",mFontCache.size());
+ DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
+ return false;
}
- // Traverse the list of default fonts.
- // Check for each default font if supports the character.
+ --fontId;
- for( FontList::const_iterator it = mDefaultFonts.begin(), endIt = mDefaultFonts.end();
- it != endIt;
- ++it )
- {
- const FontDescription& description = *it;
+ bool isSupported = false;
- FcPattern* pattern = CreateFontFamilyPattern( description.family,
- description.style );
+ const FontFaceCacheItem& cacheItem = mFontCache[fontId];
- FcResult result = FcResultMatch;
- FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
+ isSupported = FcCharSetHasChar( cacheItem.mCharacterSet, character );
- FcCharSet* charSet = NULL;
- FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet );
+ 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;
+}
- if( FcCharSetHasChar( charSet, charcode ) )
- {
- Vector< PointSize26Dot6 > fixedSizes;
- GetFixedSizes( description.family,
- description.style,
- fixedSizes );
+FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
+ const CharacterSetList& characterSetList,
+ Character character,
+ PointSize26Dot6 requestedPointSize,
+ bool preferColor )
+{
+ DALI_ASSERT_DEBUG( ( fontList.size() == characterSetList.Count() ) && "FontClient::Plugin::FindFontForCharacter. Different number of fonts and character sets." );
- const Vector< PointSize26Dot6 >::SizeType count = fixedSizes.Count();
- if( 0 != count )
- {
- // If the font is not scalable, pick the largest size <= requestedSize
- PointSize26Dot6 size = fixedSizes[0];
- for( unsigned int i=1; i<count; ++i )
- {
- if( fixedSizes[i] <= requestedSize &&
- fixedSizes[i] > size )
- {
- size = fixedSizes[i];
- }
- }
- requestedSize = size;
- }
+ 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( unsigned int index = 0u, numberOfFonts = fontList.size(); index < numberOfFonts; ++index )
+ {
+ const FontDescription& description = fontList[index];
+ const FcCharSet* const characterSet = characterSetList[index];
+
+ 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] );
- fontId = GetFontId( description.family,
- description.style,
- requestedSize,
+ bool foundInRanges = false;
+ if( NULL != characterSet )
+ {
+ foundInRanges = FcCharSetHasChar( characterSet, character );
+ }
+
+ if( foundInRanges )
+ {
+ fontId = GetFontId( description,
+ requestedPointSize,
0u );
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, " font id : %d\n", fontId );
+
if( preferColor )
{
- BufferImage bitmap = CreateBitmap( fontId, GetGlyphIndex(fontId,charcode) );
- if( bitmap &&
- Pixel::BGRA8888 == bitmap.GetPixelFormat() )
+ if( ( fontId > 0 ) &&
+ ( fontId - 1u < mFontCache.size() ) )
{
- foundColor = true;
+ const FontFaceCacheItem& item = mFontCache[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
+ // Keep going unless we prefer a different (color) font.
if( !preferColor || foundColor )
{
break;
}
}
+ DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
+ DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFontForCharacter\n" );
+ return fontId;
+}
+
+FontId FontClient::Plugin::FindDefaultFont( Character charcode,
+ PointSize26Dot6 requestedPointSize,
+ bool preferColor )
+{
+ 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);
+
+ // Create the list of default fonts if it has not been created.
+ if( mDefaultFonts.empty() )
+ {
+ FontDescription fontDescription;
+ fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
+ fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
+ fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
+ fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
+
+ 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, 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;
+}
+
+FontId FontClient::Plugin::FindFallbackFont( Character charcode,
+ const FontDescription& preferredFontDescription,
+ 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;
+
+ FontDescription fontDescription;
+
+ // Fill the font description with the preferred font description and complete with the defaults.
+ fontDescription.family = preferredFontDescription.family.empty() ? DEFAULT_FONT_FAMILY_NAME : preferredFontDescription.family;
+ fontDescription.weight = ( ( FontWeight::NONE == preferredFontDescription.weight ) ? IntToWeightType( DEFAULT_FONT_WEIGHT ) : preferredFontDescription.weight );
+ 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;
+ CharacterSetList* characterSetList = NULL;
+
+ if( !FindFallbackFontList( fontDescription, fontList, characterSetList ) )
+ {
+ fontList = new FontList;
+ characterSetList = new CharacterSetList;
+
+ SetFontList( fontDescription, *fontList, *characterSetList );
+
+ // Add the font-list to the cache.
+ mFallbackCache.push_back( FallbackCacheItem( fontDescription, fontList, characterSetList ) );
+ }
+
+ if( fontList && characterSetList )
+ {
+ 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 pointSize,
+ PointSize26Dot6 requestedPointSize,
FaceIndex faceIndex,
bool cacheDescription )
{
+ 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 )
{
FontId foundId(0);
- if( FindFont( path, pointSize, faceIndex, foundId ) )
+ if( FindFont( path, requestedPointSize, faceIndex, foundId ) )
{
id = foundId;
}
else
{
- id = CreateFont( path, pointSize, 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 FontFamily& fontFamily,
- const FontStyle& fontStyle,
- PointSize26Dot6 pointSize,
+FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
+ PointSize26Dot6 requestedPointSize,
FaceIndex faceIndex )
{
+ 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 'fontFamily, fontStyle' and an index to a vector with paths to font file names.
+ // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
// * The path to font file names.
// * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
- // 1) Checks in the cache if the pair 'fontFamily, fontStyle' has been validated before.
+ // 1) Checks in the cache if the font's description has been validated before.
// If it was it gets an index to the vector with paths to font file names. Otherwise,
- // retrieves using font config a path to a font file name which matches with the pair
- // 'fontFamily, fontStyle'. The path is stored in the chache.
+ // retrieves using font config a path to a font file name which matches with the
+ // font's description. The path is stored in the cache.
//
// 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
- // fon file names' exists. If exists, it gets the font id. If it doesn't it calls
+ // font file names' exists. If exists, it gets the font id. If it doesn't it calls
// the GetFontId() method with the path to the font file name and the point size to
// get the font id.
// The font id to be returned.
FontId fontId = 0u;
- // Check first if the pair font family and style have been validated before.
+ // Check first if the font's description have been validated before.
FontDescriptionId validatedFontId = 0u;
- if( !FindValidatedFont( fontFamily,
- fontStyle,
+ if( !FindValidatedFont( fontDescription,
validatedFontId ) )
{
- // Use font config to validate the font family name and font style.
- ValidateFont( fontFamily, fontStyle, validatedFontId );
+ // Use font config to validate the font's description.
+ ValidateFont( fontDescription,
+ validatedFontId );
}
- // Check if exists a pair 'validatedFontId, pointSize' in the cache.
- if( !FindFont( validatedFontId, pointSize, fontId ) )
+ // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
+ if( !FindFont( validatedFontId, requestedPointSize, fontId ) )
{
// Retrieve the font file name path.
const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
// Retrieve the font id. Do not cache the description as it has been already cached.
fontId = GetFontId( description.path,
- pointSize,
+ requestedPointSize,
faceIndex,
false );
- // Cache the pair 'validatedFontId, pointSize' to improve the following queries.
+ mFontCache[fontId-1u].mCharacterSet = mCharacterSetCache[validatedFontId];
+
+ // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
- pointSize,
+ 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 FontFamily& fontFamily,
- const FontStyle& fontStyle,
+void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
FontDescriptionId& validatedFontId )
{
+ 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( fontFamily,
- fontStyle );
+ FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
- FcResult result = FcResultMatch;
+ FontDescription description;
- // match the pattern
- FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
+ FcCharSet* characterSet = NULL;
+ bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description, &characterSet );
+ FcPatternDestroy( fontFamilyPattern );
- if( match )
+ if( matched && ( NULL != characterSet ) )
{
- // Get the path to the font file name.
- FontDescription description;
- GetFcString( match, FC_FILE, description.path );
- GetFcString( match, FC_FAMILY, description.family );
- GetFcString( match, FC_STYLE, description.style );
-
// 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 );
- // Cache the index and the pair font family name, font style.
- FontDescriptionCacheItem item( fontFamily, fontStyle, validatedFontId );
mValidatedFontCache.push_back( item );
- // destroyed the matched pattern
- FcPatternDestroy( match );
+ if( ( fontDescription.family != description.family ) ||
+ ( fontDescription.width != description.width ) ||
+ ( fontDescription.weight != description.weight ) ||
+ ( fontDescription.slant != description.slant ) )
+ {
+ // Cache the given font's description if it's different than the matched.
+ FontDescriptionCacheItem item( fontDescription,
+ validatedFontId );
+
+ mValidatedFontCache.push_back( item );
+ }
}
else
{
- DALI_LOG_ERROR( "FontClient::Plugin::ValidateFont failed for font %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
+ DALI_LOG_INFO( gLogFilter, Debug::General, " font validation failed for font [%s]\n", fontDescription.family.c_str() );
}
- // destroy the pattern
- FcPatternDestroy( fontFamilyPattern );
+ DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::ValidateFont\n" );
}
-
-
void FontClient::Plugin::GetFontMetrics( FontId fontId,
FontMetrics& metrics )
{
- if( fontId > 0 &&
- fontId-1 < mFontCache.size() )
+ if( ( fontId > 0 ) &&
+ ( fontId - 1u < mFontCache.size() ) )
{
- metrics = mFontCache[fontId-1].mMetrics;
+ const FontFaceCacheItem& font = mFontCache[fontId-1];
+
+ metrics = font.mMetrics;
+
+ // Adjust the metrics if the fixed-size font should be down-scaled
+ if( font.mIsFixedSizeBitmap )
+ {
+ const float desiredFixedSize = static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
+
+ if( desiredFixedSize > 0.f )
+ {
+ const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
+
+ metrics.ascender = floorf( metrics.ascender * scaleFactor );
+ metrics.descender = floorf( metrics.descender * scaleFactor );
+ metrics.height = floorf( metrics.height * scaleFactor );
+ metrics.underlinePosition = floorf( metrics.underlinePosition * scaleFactor );
+ metrics.underlineThickness = floorf( metrics.underlineThickness * scaleFactor );
+ }
+ }
}
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 < mFontCache.size() ) )
{
- FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
+ FT_Face ftFace = mFontCache[fontId-1u].mFreeTypeFace;
index = FT_Get_Char_Index( ftFace, charcode );
}
bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
uint32_t size,
+ GlyphType type,
bool horizontal )
{
+ if( VECTOR_GLYPH == type )
+ {
+ return GetVectorMetrics( array, size, horizontal );
+ }
+
+ return GetBitmapMetrics( array, size, horizontal );
+}
+
+bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array,
+ uint32_t size,
+ bool horizontal )
+{
bool success( true );
for( unsigned int i=0; i<size; ++i )
{
- FontId fontId = array[i].fontId;
+ GlyphInfo& glyph = array[i];
+
+ FontId fontId = glyph.fontId;
if( fontId > 0 &&
fontId-1 < mFontCache.size() )
{
- FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
+ const FontFaceCacheItem& font = mFontCache[fontId-1];
+
+ FT_Face ftFace = font.mFreeTypeFace;
#ifdef FREETYPE_BITMAP_SUPPORT
// Check to see if we should be loading a Fixed Size bitmap?
- if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
+ if ( font.mIsFixedSizeBitmap )
{
- int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_COLOR );
+ int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_COLOR );
if ( FT_Err_Ok == error )
{
- array[i].width = mFontCache[ fontId -1 ].mFixedWidthPixels;
- array[i].height = mFontCache[ fontId -1 ].mFixedHeightPixels;
- array[i].advance = mFontCache[ fontId -1 ].mFixedWidthPixels;
- array[i].xBearing = 0.0f;
- array[i].yBearing = mFontCache[ fontId -1 ].mFixedHeightPixels;
+ glyph.width = font.mFixedWidthPixels;
+ glyph.height = font.mFixedHeightPixels;
+ glyph.advance = font.mFixedWidthPixels;
+ glyph.xBearing = 0.0f;
+ glyph.yBearing = font.mFixedHeightPixels;
+
+ // Adjust the metrics if the fixed-size font should be down-scaled
+ const float desiredFixedSize = static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
+
+ if( desiredFixedSize > 0.f )
+ {
+ const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
+
+ glyph.width = floorf( glyph.width * scaleFactor );
+ glyph.height = floorf( glyph.height * scaleFactor );
+ glyph.advance = floorf( glyph.advance * scaleFactor );
+ glyph.xBearing = floorf( glyph.xBearing * scaleFactor );
+ glyph.yBearing = floorf( glyph.yBearing * scaleFactor );
+
+ glyph.scaleFactor = scaleFactor;
+ }
}
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, array[i].index, FT_LOAD_DEFAULT );
+ int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_DEFAULT );
if( FT_Err_Ok == error )
{
- array[i].width = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
- array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
+ glyph.width = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
+ glyph.height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
if( horizontal )
{
- array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
- array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
- array[i].advance = static_cast< float >( ftFace->glyph->metrics.horiAdvance ) * FROM_266;
+ glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
+ glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
}
else
{
- array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
- array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
- array[i].advance = static_cast< float >( ftFace->glyph->metrics.vertAdvance ) * FROM_266;
+ glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
+ glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
}
}
else
return success;
}
-BufferImage FontClient::Plugin::CreateBitmap( FontId fontId,
- GlyphIndex glyphIndex )
+bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array,
+ uint32_t size,
+ bool horizontal )
{
- BufferImage bitmap;
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+ bool success( true );
- if( fontId > 0 &&
- fontId-1 < mFontCache.size() )
+ for( unsigned int i=0; i<size; ++i )
{
- FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
+ FontId fontId = array[i].fontId;
+
+ if( fontId > 0 &&
+ fontId-1 < mFontCache.size() )
+ {
+ FontFaceCacheItem& font = mFontCache[fontId-1];
+
+ if( ! font.mVectorFontId )
+ {
+ font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
+ }
+
+ mVectorFontCache->GetGlyphMetrics( font.mVectorFontId, array[i] );
+
+ // Vector metrics are in EMs, convert to pixels
+ const float scale = ( static_cast<float>( font.mRequestedPointSize ) * FROM_266 ) * static_cast<float>( mDpiVertical ) / POINTS_PER_INCH;
+ array[i].width *= scale;
+ array[i].height *= scale;
+ array[i].xBearing *= scale;
+ array[i].yBearing *= scale;
+ array[i].advance *= scale;
+ }
+ else
+ {
+ success = false;
+ }
+ }
+
+ return success;
+#else
+ return false;
+#endif
+}
+
+void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data )
+{
+ if( ( fontId > 0 ) &&
+ ( fontId - 1u < mFontCache.size() ) )
+ {
+ FT_Face ftFace = mFontCache[fontId - 1u].mFreeTypeFace;
FT_Error error;
#ifdef FREETYPE_BITMAP_SUPPORT
// Check to see if this is fixed size bitmap
- if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
+ if ( mFontCache[fontId - 1u].mIsFixedSizeBitmap )
{
error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
}
error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
if ( FT_Err_Ok == error )
{
- FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
- ConvertBitmap( bitmap, bitmapGlyph->bitmap );
+ 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
{
- ConvertBitmap( bitmap, ftFace->glyph->bitmap );
+ ConvertBitmap( data, ftFace->glyph->bitmap );
}
// Created FT_Glyph object must be released with FT_Done_Glyph
}
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 )
+{
+ TextAbstraction::FontClient::GlyphBufferData data;
+
+ CreateBitmap( fontId, glyphIndex, data );
+
+ return PixelData::New( data.buffer,
+ data.width * data.height * Pixel::GetBytesPerPixel( data.format ),
+ data.width,
+ data.height,
+ data.format,
+ PixelData::DELETE_ARRAY );
+}
+
+void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
+{
+ blob = NULL;
+ blobLength = 0;
+
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+ if( fontId > 0 &&
+ fontId-1 < mFontCache.size() )
+ {
+ FontFaceCacheItem& font = mFontCache[fontId-1];
+
+ if( ! font.mVectorFontId )
+ {
+ font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
+ }
+
+ mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
+ }
+#endif
+}
+
+const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
+{
+ // First look into the cache if there is an ellipsis glyph for the requested point size.
+ for( Vector<EllipsisItem>::ConstIterator it = mEllipsisCache.Begin(),
+ endIt = mEllipsisCache.End();
+ it != endIt;
+ ++it )
+ {
+ const EllipsisItem& item = *it;
+
+ if( fabsf( item.requestedPointSize - requestedPointSize ) < Math::MACHINE_EPSILON_1000 )
+ {
+ // Use the glyph in the cache.
+ return item.glyph;
+ }
+ }
+
+ // No glyph has been found. Create one.
+ mEllipsisCache.PushBack( EllipsisItem() );
+ EllipsisItem& item = *( mEllipsisCache.End() - 1u );
+
+ item.requestedPointSize = requestedPointSize;
+
+ // Find a font for the ellipsis glyph.
+ item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
+ requestedPointSize,
+ 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,
+ ELLIPSIS_CHARACTER );
+
+ GetBitmapMetrics( &item.glyph, 1u, true );
+
+ return item.glyph;
+}
+
+bool FontClient::Plugin::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
+{
+ FT_Error error = -1;
+
+#ifdef FREETYPE_BITMAP_SUPPORT
+ if( ( fontId > 0 ) &&
+ ( fontId - 1u < mFontCache.size() ) )
+ {
+ const FontFaceCacheItem& item = mFontCache[fontId - 1u];
+ FT_Face ftFace = item.mFreeTypeFace;
+
+ // Check to see if this is fixed size bitmap
+ if( item.mHasColorTables )
+ {
+ error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
}
}
+#endif
- return bitmap;
+ return FT_Err_Ok == error;
}
void FontClient::Plugin::InitSystemFonts()
{
+ 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 );
// Skip fonts with no path
if( GetFcString( fontPattern, FC_FILE, path ) )
{
+ FcCharSet* characterSet = NULL;
+ FcPatternGetCharSet( fontPattern, FC_CHARSET, 0u, &characterSet );
+
+ mSystemFontCharacterSets.PushBack( characterSet );
+
mSystemFonts.push_back( FontDescription() );
FontDescription& fontDescription = mSystemFonts.back();
fontDescription.path = path;
+ int width = 0;
+ int weight = 0;
+ int slant = 0;
GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
- GetFcString( fontPattern, FC_STYLE, fontDescription.style );
+ GetFcInt( fontPattern, FC_WIDTH, width );
+ GetFcInt( fontPattern, FC_WEIGHT, weight );
+ GetFcInt( fontPattern, FC_SLANT, slant );
+ fontDescription.width = IntToWidthType( width );
+ fontDescription.weight = IntToWeightType( weight );
+ fontDescription.slant = IntToSlantType( slant );
+
+ 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, FcCharSet** characterSet )
+{
+ DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::MatchFontDescriptionToPattern\n" );
+
+ FcResult result = FcResultMatch;
+ FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
+
+ const bool matched = NULL != match;
+ DALI_LOG_INFO( gLogFilter, Debug::General, " pattern matched : %s\n", ( matched ? "true" : "false" ) );
+
+ if( matched )
+ {
+ int width = 0;
+ int weight = 0;
+ int slant = 0;
+ GetFcString( match, FC_FILE, fontDescription.path );
+ GetFcString( match, FC_FAMILY, fontDescription.family );
+ GetFcInt( match, FC_WIDTH, width );
+ GetFcInt( match, FC_WEIGHT, weight );
+ GetFcInt( match, FC_SLANT, slant );
+ fontDescription.width = IntToWidthType( width );
+ fontDescription.weight = IntToWeightType( weight );
+ fontDescription.slant = IntToSlantType( slant );
+
+ // Cache the character ranges.
+ FcPatternGetCharSet( match, FC_CHARSET, 0u, characterSet );
+
+ // destroyed the matched pattern
+ FcPatternDestroy( match );
+
+ 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::MatchFontDescriptionToPattern\n" );
+ return matched;
}
-FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontFamily& fontFamily,
- const FontStyle& fontStyle )
+FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription )
{
// create the cached font family lookup pattern
// a pattern holds a set of names, each name refers to a property of the font
FcPattern* fontFamilyPattern = FcPatternCreate();
- // add a property to the pattern for the font family
- FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontFamily.c_str() ) );
+ if( !fontFamilyPattern )
+ {
+ return NULL;
+ }
// add a property to the pattern for the font family
- FcPatternAddString( fontFamilyPattern, FC_STYLE, reinterpret_cast<const FcChar8*>( fontStyle.c_str() ) );
+ FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
+
+ int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
+ if( width < 0 )
+ {
+ // Use default.
+ width = DEFAULT_FONT_WIDTH;
+ }
+
+ int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
+ if( weight < 0 )
+ {
+ // Use default.
+ weight = DEFAULT_FONT_WEIGHT;
+ }
+
+ int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
+ if( slant < 0 )
+ {
+ // Use default.
+ slant = DEFAULT_FONT_SLANT;
+ }
+
+ FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
+ FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
+ FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
// Add a property of the pattern, to say we want to match TrueType fonts
FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
// build an object set from a list of property names
FcObjectSetAdd( objectSet, FC_FILE );
FcObjectSetAdd( objectSet, FC_FAMILY );
- FcObjectSetAdd( objectSet, FC_STYLE );
+ FcObjectSetAdd( objectSet, FC_WIDTH );
+ FcObjectSetAdd( objectSet, FC_WEIGHT );
+ FcObjectSetAdd( objectSet, FC_SLANT );
// get a list of fonts
// creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
return false;
}
+bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
+{
+ const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
+
+ if( FcResultMatch == retVal )
+ {
+ return true;
+ }
+
+ return false;
+}
+
FontId FontClient::Plugin::CreateFont( const FontPath& path,
- PointSize26Dot6 pointSize,
+ PointSize26Dot6 requestedPointSize,
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;
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<FT_Pos>(pointSize) == ftFace->available_sizes[ i ].size )
+ const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, " size index : %d, size : %d\n", fixedSizeIndex, fixedSize );
+
+ if( fixedSize >= requestedPointSize )
{
- // 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 );
-
- // Indicate that the font is a fixed sized bitmap
- FontMetrics metrics( fixedHeight,
- 0.0f,
- fixedHeight,
- 0.0f,
- 0.0f );
-
- mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics, fixedWidth, fixedHeight ) );
- id = mFontCache.size();
-
- if( cacheDescription )
- {
- FontDescription description;
- description.path = path;
- description.family = FontFamily( ftFace->family_name );
- description.style = FontStyle( ftFace->style_name );
-
- mFontDescriptionCache.push_back( description );
- }
- return id;
- }
+ actualPointSize = fixedSize;
+ break;
}
}
- // Can't find this size
- std::stringstream sizes;
- for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
+ if( 0u == actualPointSize )
{
- if ( i )
- {
- sizes << ", ";
- }
- sizes << ftFace->available_sizes[ i ].size;
+ // The requested point size is bigger than the bigest fixed size.
+ fixedSizeIndex = ftFace->num_fixed_sizes - 1;
+ actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
+ }
+
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, " size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize );
+
+ // 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 );
+ }
+ else
+ {
+ 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 );
+
+ mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight, hasColorTables ) );
+ id = mFontCache.size();
}
- DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
- path.c_str(), pointSize, sizes.str().c_str() );
}
else
{
error = FT_Set_Char_Size( ftFace,
- 0,
- pointSize,
- mDpiHorizontal,
- mDpiVertical );
+ 0,
+ requestedPointSize,
+ mDpiHorizontal,
+ mDpiVertical );
if( FT_Err_Ok == error )
{
static_cast< float >( ftFace->underline_position ) * FROM_266,
static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
- mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics ) );
+ mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) );
id = mFontCache.size();
-
- if( cacheDescription )
- {
- FontDescription description;
- description.path = path;
- description.family = FontFamily( ftFace->family_name );
- description.style = FontStyle( ftFace->style_name );
-
- mFontDescriptionCache.push_back( description );
- }
}
else
{
- DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, pointSize );
+ 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;
}
-void FontClient::Plugin::ConvertBitmap( BufferImage& destBitmap,
- FT_Bitmap srcBitmap )
+void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap )
{
if( srcBitmap.width*srcBitmap.rows > 0 )
{
{
case FT_PIXEL_MODE_GRAY:
{
- if( srcBitmap.pitch == static_cast< int >( srcBitmap.width ) )
+ if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
{
- destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
-
- PixelBuffer* destBuffer = destBitmap.GetBuffer();
- memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
+ const unsigned int bufferSize = srcBitmap.width * srcBitmap.rows;
+ 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;
+ memcpy( data.buffer, srcBitmap.buffer, bufferSize );
}
break;
}
#ifdef FREETYPE_BITMAP_SUPPORT
case FT_PIXEL_MODE_BGRA:
{
- if ( srcBitmap.pitch == static_cast< int >( srcBitmap.width << 2 ) )
+ if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
{
- destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::BGRA8888 );
+ // Set the input dimensions.
+ const ImageDimensions inputDimensions( srcBitmap.width, srcBitmap.rows );
+
+ // Set the output dimensions.
+ // If the output dimension is not given, the input dimension is set
+ // and won't be downscaling.
+ data.width = ( data.width == 0 ) ? srcBitmap.width : data.width;
+ data.height = ( data.height == 0 ) ? srcBitmap.rows : data.height;
+ const ImageDimensions desiredDimensions( data.width, data.height );
+
+ // Creates the output buffer
+ const unsigned int bufferSize = data.width * data.height * 4u;
+ data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
- PixelBuffer* destBuffer = destBitmap.GetBuffer();
- memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows*4 );
+ if( inputDimensions == desiredDimensions )
+ {
+ // There isn't downscaling.
+ memcpy( data.buffer, srcBitmap.buffer, bufferSize );
+ }
+ else
+ {
+ Dali::Internal::Platform::LanczosSample4BPP( srcBitmap.buffer,
+ inputDimensions,
+ data.buffer,
+ desiredDimensions );
+ }
+ data.format = Pixel::BGRA8888;
}
break;
}
#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;
}
}
}
bool FontClient::Plugin::FindFont( const FontPath& path,
- PointSize26Dot6 pointSize,
+ PointSize26Dot6 requestedPointSize,
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", mFontCache.size() );
+
fontId = 0u;
- for( std::vector<CacheItem>::const_iterator it = mFontCache.begin(),
+ for( std::vector<FontFaceCacheItem>::const_iterator it = mFontCache.begin(),
endIt = mFontCache.end();
it != endIt;
++it, ++fontId )
{
- const CacheItem& cacheItem = *it;
+ const FontFaceCacheItem& cacheItem = *it;
- if( cacheItem.mPointSize == pointSize &&
+ 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" );
+
return false;
}
-bool FontClient::Plugin::FindValidatedFont( const FontFamily& fontFamily,
- const FontStyle& fontStyle,
+bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
FontDescriptionId& validatedFontId )
{
+ 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<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
{
const FontDescriptionCacheItem& item = *it;
- if( ( fontFamily == item.fontFamily ) &&
- ( fontStyle == item.fontStyle ) )
+ if( !fontDescription.family.empty() &&
+ ( fontDescription.family == item.fontDescription.family ) &&
+ ( fontDescription.width == item.fontDescription.width ) &&
+ ( fontDescription.weight == item.fontDescription.weight ) &&
+ ( fontDescription.slant == item.fontDescription.slant ) )
{
validatedFontId = item.index;
+ 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::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,
+ CharacterSetList*& characterSetList )
+{
+ 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;
+
+ for( std::vector<FallbackCacheItem>::const_iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
+ it != endIt;
+ ++it )
+ {
+ const FallbackCacheItem& item = *it;
+
+ if( !fontDescription.family.empty() &&
+ ( fontDescription.family == item.fontDescription.family ) &&
+ ( fontDescription.width == item.fontDescription.width ) &&
+ ( fontDescription.weight == item.fontDescription.weight ) &&
+ ( fontDescription.slant == item.fontDescription.slant ) )
+ {
+ fontList = item.fallbackFonts;
+ characterSetList = item.characterSets;
+
+ 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::General, " fallback font list not found.\n" );
+ DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
return false;
}
bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
- PointSize26Dot6 pointSize,
+ 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<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
const FontIdCacheItem& item = *it;
if( ( validatedFontId == item.validatedFontId ) &&
- ( pointSize == item.pointSize ) )
+ ( 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(),
&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() );
+ }
+ else
+ {
+ isScalable = ftFace->face_flags & FT_FACE_FLAG_SCALABLE;
}
- return ( ftFace->num_fixed_sizes == 0 );
+
+ return isScalable;
}
-bool FontClient::Plugin::IsScalable( const FontFamily& fontFamily, const FontStyle& fontStyle )
+bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
{
// Create a font pattern.
- FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
- fontStyle );
+ FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
FcResult result = FcResultMatch;
// match the pattern
FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
+ bool isScalable = false;
if( match )
{
// Get the path to the font file name.
FontPath path;
GetFcString( match, FC_FILE, path );
- return IsScalable( path );
+ isScalable = IsScalable( path );
+ }
+ else
+ {
+ DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
}
- DALI_LOG_ERROR( "FreeType Cannot check font: %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
- return true;
+ FcPatternDestroy( fontFamilyPattern );
+ FcPatternDestroy( match );
+ return isScalable;
}
void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
&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
}
}
-void FontClient::Plugin::GetFixedSizes( const FontFamily& fontFamily,
- const FontStyle& fontStyle,
+void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
Vector< PointSize26Dot6 >& sizes )
{
// Create a font pattern.
- FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
- fontStyle );
+ FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
FcResult result = FcResultMatch;
// Get the path to the font file name.
FontPath path;
GetFcString( match, FC_FILE, path );
- return GetFixedSizes( path, sizes );
+ GetFixedSizes( path, sizes );
+ }
+ else
+ {
+ DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
+ }
+ FcPatternDestroy( match );
+ FcPatternDestroy( fontFamilyPattern );
+}
+
+void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize, const FontPath& path )
+{
+ FontDescription description;
+ description.path = path;
+ description.family = FontFamily( ftFace->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( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
+ {
+ description.slant = FontSlant::ITALIC;
+ }
+ if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
+ {
+ description.weight = FontWeight::BOLD;
+ }
+
+ FontDescriptionId validatedFontId = 0u;
+ if( !FindValidatedFont( description,
+ validatedFontId ) )
+ {
+ // 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( NULL, pattern, &result );
+
+ FcCharSet* characterSet = NULL;
+ FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
+
+ FcPatternDestroy( match );
+ FcPatternDestroy( pattern );
+
+ mFontCache[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 );
+
+ // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
+ mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
+ requestedPointSize,
+ id ) );
}
- DALI_LOG_ERROR( "FreeType Cannot check font: %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
}
} // namespace Internal