2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/text-abstraction/font-client-plugin-impl.h>
22 #include <dali/devel-api/text-abstraction/font-list.h>
24 #include <dali/public-api/common/dali-vector.h>
25 #include <dali/public-api/common/vector-wrapper.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/integration-api/platform-abstraction.h>
28 #include <dali/internal/text-abstraction/font-client-helper.h>
29 #include <platform-abstractions/portable/image-operations.h>
30 #include <adaptor-impl.h>
33 #include <fontconfig/fontconfig.h>
38 #if defined(DEBUG_ENABLED)
39 Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
43 * Conversion from Fractional26.6 to float
45 const float FROM_266 = 1.0f / 64.0f;
46 const float POINTS_PER_INCH = 72.f;
48 const std::string FONT_FORMAT( "TrueType" );
49 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
50 const int DEFAULT_FONT_WIDTH = 100; // normal
51 const int DEFAULT_FONT_WEIGHT = 80; // normal
52 const int DEFAULT_FONT_SLANT = 0; // normal
54 const uint32_t ELLIPSIS_CHARACTER = 0x2026;
56 // http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
58 // NONE -1 --> DEFAULT_FONT_WIDTH (NORMAL) will be used.
68 const int FONT_WIDTH_TYPE_TO_INT[] = { -1, 50, 63, 75, 87, 100, 113, 125, 150, 200 };
69 const unsigned int NUM_FONT_WIDTH_TYPE = sizeof( FONT_WIDTH_TYPE_TO_INT ) / sizeof( int );
71 // NONE -1 --> DEFAULT_FONT_WEIGHT (NORMAL) will be used.
73 // ULTRA_LIGHT, EXTRA_LIGHT 40
75 // DEMI_LIGHT, SEMI_LIGHT 55
79 // DEMI_BOLD, SEMI_BOLD 180
81 // ULTRA_BOLD, EXTRA_BOLD 205
82 // BLACK, HEAVY, EXTRA_BLACK 210
83 const int FONT_WEIGHT_TYPE_TO_INT[] = { -1, 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210 };
84 const unsigned int NUM_FONT_WEIGHT_TYPE = sizeof( FONT_WEIGHT_TYPE_TO_INT ) / sizeof( int );
86 // NONE -1 --> DEFAULT_FONT_SLANT (NORMAL) will be used.
90 const int FONT_SLANT_TYPE_TO_INT[] = { -1, 0, 100, 110 };
91 const unsigned int NUM_FONT_SLANT_TYPE = sizeof( FONT_SLANT_TYPE_TO_INT ) / sizeof( int );
102 namespace TextAbstraction
109 * @brief Returns the FontWidth's enum index for the given width value.
111 * @param[in] width The width value.
113 * @return The FontWidth's enum index.
115 FontWidth::Type IntToWidthType( int width )
117 return static_cast<FontWidth::Type>( ValueToIndex( width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u ) );
121 * @brief Returns the FontWeight's enum index for the given weight value.
123 * @param[in] weight The weight value.
125 * @return The FontWeight's enum index.
127 FontWeight::Type IntToWeightType( int weight )
129 return static_cast<FontWeight::Type>( ValueToIndex( weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u ) );
133 * @brief Returns the FontSlant's enum index for the given slant value.
135 * @param[in] slant The slant value.
137 * @return The FontSlant's enum index.
139 FontSlant::Type IntToSlantType( int slant )
141 return static_cast<FontSlant::Type>( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) );
144 FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( const FontDescription& font, FontList* fallbackFonts, CharacterSetList* characterSets )
145 : fontDescription( font ),
146 fallbackFonts( fallbackFonts ),
147 characterSets( characterSets )
151 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
152 FontDescriptionId index )
153 : fontDescription( fontDescription ),
158 FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId,
159 PointSize26Dot6 requestedPointSize,
161 : validatedFontId( validatedFontId ),
162 requestedPointSize( requestedPointSize ),
167 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
168 const FontPath& path,
169 PointSize26Dot6 requestedPointSize,
171 const FontMetrics& metrics )
172 : mFreeTypeFace( ftFace ),
174 mRequestedPointSize( requestedPointSize ),
177 mCharacterSet( NULL ),
178 mFixedWidthPixels( 0.0f ),
179 mFixedHeightPixels( 0.0f ),
181 mIsFixedSizeBitmap( false ),
182 mHasColorTables( false )
186 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
187 const FontPath& path,
188 PointSize26Dot6 requestedPointSize,
190 const FontMetrics& metrics,
193 bool hasColorTables )
194 : mFreeTypeFace( ftFace ),
196 mRequestedPointSize( requestedPointSize ),
199 mCharacterSet( NULL ),
200 mFixedWidthPixels( fixedWidth ),
201 mFixedHeightPixels( fixedHeight ),
203 mIsFixedSizeBitmap( true ),
204 mHasColorTables( hasColorTables )
208 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
209 unsigned int verticalDpi )
210 : mFreeTypeLibrary( NULL ),
211 mDpiHorizontal( horizontalDpi ),
212 mDpiVertical( verticalDpi ),
213 mDefaultFontDescription(),
217 mValidatedFontCache(),
218 mFontDescriptionCache( 1u ),
219 mCharacterSetCache(),
221 mVectorFontCache( NULL ),
223 mDefaultFontDescriptionCached( false )
225 mCharacterSetCache.Resize( 1u );
227 int error = FT_Init_FreeType( &mFreeTypeLibrary );
228 if( FT_Err_Ok != error )
230 DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Init error: %d\n", error );
233 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
234 mVectorFontCache = new VectorFontCache( mFreeTypeLibrary );
239 FontClient::Plugin::~Plugin()
241 for( std::vector<FallbackCacheItem>::iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
245 FallbackCacheItem& item = *it;
247 if( item.fallbackFonts )
249 delete item.fallbackFonts;
250 delete item.characterSets;
251 item.fallbackFonts = NULL;
252 item.characterSets = NULL;
256 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
257 delete mVectorFontCache;
259 DestroyMatchedPatterns();
260 FT_Done_FreeType( mFreeTypeLibrary );
263 void FontClient::Plugin::ClearCache()
266 mValidatedFontCache.clear();
267 mFontDescriptionCache.clear();
268 mFontDescriptionCache.resize( 1u );
270 mCharacterSetCache.Clear();
271 mCharacterSetCache.Resize( 1u );
273 mFontIdCache.clear();
274 mFallbackCache.clear();
276 mEllipsisCache.Clear();
277 mSystemFonts.clear();
278 mDefaultFonts.clear();
279 mDefaultFontDescriptionCached = false;
280 mDefaultFontCharacterSets.Clear();
281 mDefaultFontDescription = FontDescription();
282 DestroyMatchedPatterns();
285 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
286 unsigned int verticalDpi )
288 mDpiHorizontal = horizontalDpi;
289 mDpiVertical = verticalDpi;
292 void FontClient::Plugin::ResetSystemDefaults()
294 mDefaultFontDescriptionCached = false;
297 void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList )
299 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::SetFontList\n" );
300 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
301 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
302 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
303 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
307 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
309 FcResult result = FcResultMatch;
311 // Match the pattern.
312 FcFontSet* fontSet = FcFontSort( NULL /* use default configure */,
314 false /* don't trim */,
318 if( NULL != fontSet )
320 DALI_LOG_INFO( gLogFilter, Debug::General, " number of fonts found : [%d]\n", fontSet->nfont );
321 // Reserve some space to avoid reallocations.
322 fontList.reserve( fontSet->nfont );
324 for( int i = 0u; i < fontSet->nfont; ++i )
326 FcPattern* fontPattern = fontSet->fonts[i];
330 // Skip fonts with no path
331 if( GetFcString( fontPattern, FC_FILE, path ) )
333 FcCharSet* characterSet = NULL;
334 FcPatternGetCharSet( fontPattern, FC_CHARSET, 0u, &characterSet );
336 characterSetList.PushBack( characterSet );
337 fontList.push_back( FontDescription() );
338 FontDescription& newFontDescription = fontList.back();
340 newFontDescription.path = path;
345 GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
346 GetFcInt( fontPattern, FC_WIDTH, width );
347 GetFcInt( fontPattern, FC_WEIGHT, weight );
348 GetFcInt( fontPattern, FC_SLANT, slant );
349 newFontDescription.width = IntToWidthType( width );
350 newFontDescription.weight = IntToWeightType( weight );
351 newFontDescription.slant = IntToSlantType( slant );
353 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", newFontDescription.family.c_str() );
354 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", newFontDescription.path.c_str() );
355 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[newFontDescription.width] );
356 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[newFontDescription.weight] );
357 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[newFontDescription.slant] );
361 FcFontSetDestroy( fontSet );
365 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " No fonts found.\n" );
368 FcPatternDestroy( fontFamilyPattern );
369 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::SetFontList\n" );
372 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
374 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultFonts\n" );
376 if( mDefaultFonts.empty() )
378 FontDescription fontDescription;
379 fontDescription.family = DEFAULT_FONT_FAMILY_NAME; // todo This could be set to the Platform font
380 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
381 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
382 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
383 SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
386 defaultFonts = mDefaultFonts;
388 DALI_LOG_INFO( gLogFilter, Debug::General, " number of default fonts : [%d]\n", mDefaultFonts.size() );
389 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultFonts\n" );
392 void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
394 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultPlatformFontDescription\n");
396 if( !mDefaultFontDescriptionCached )
398 // Clear any font config stored info in the caches.
399 mDefaultFontCharacterSets.Clear();
400 mCharacterSetCache.Clear();
402 for( std::vector<FallbackCacheItem>::iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end(); it != endIt; ++it )
404 FallbackCacheItem& item = *it;
406 item.characterSets->Clear();
409 for( std::vector<FontFaceCacheItem>::iterator it = mFontCache.begin(), endIt = mFontCache.end(); it != endIt; ++it )
411 FontFaceCacheItem& item = *it;
413 // Set the character set pointer as null. Will be created again the next time IsCharacterSupportedByFont()
414 item.mCharacterSet = NULL;
417 // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
418 FcInitReinitialize();
420 FcPattern* matchPattern = FcPatternCreate();
424 FcConfigSubstitute( NULL, matchPattern, FcMatchPattern );
425 FcDefaultSubstitute( matchPattern );
427 FcCharSet* characterSet = NULL;
428 MatchFontDescriptionToPattern( matchPattern, mDefaultFontDescription, &characterSet );
429 FcPatternDestroy( matchPattern );
432 // Create again the character sets as they are not valid after FcInitReinitialize()
434 for( FontList::const_iterator it = mDefaultFonts.begin(), endIt = mDefaultFonts.end(); it != endIt; ++it )
436 const FontDescription& description = *it;
438 mDefaultFontCharacterSets.PushBack( CreateCharacterSetFromDescription( description ) );
441 for( FontList::const_iterator it = mFontDescriptionCache.begin(), endIt = mFontDescriptionCache.end(); it != endIt; ++it )
443 const FontDescription& description = *it;
445 mCharacterSetCache.PushBack( CreateCharacterSetFromDescription( description ) );
448 for( std::vector<FallbackCacheItem>::iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end(); it != endIt; ++it )
450 FallbackCacheItem& item = *it;
452 if( NULL != item.fallbackFonts )
454 if( NULL == item.characterSets )
456 item.characterSets = new CharacterSetList;
459 for( FontList::const_iterator flIt = item.fallbackFonts->begin(), flEndIt = item.fallbackFonts->end(); flIt != flEndIt; ++flIt )
461 const FontDescription& description = *flIt;
462 item.characterSets->PushBack( CreateCharacterSetFromDescription( description ) );
467 mDefaultFontDescriptionCached = true;
470 fontDescription.path = mDefaultFontDescription.path;
471 fontDescription.family = mDefaultFontDescription.family;
472 fontDescription.width = mDefaultFontDescription.width;
473 fontDescription.weight = mDefaultFontDescription.weight;
474 fontDescription.slant = mDefaultFontDescription.slant;
476 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
477 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
478 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
479 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
480 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
481 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultPlatformFontDescription\n");
484 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
486 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetSystemFonts\n");
488 if( mSystemFonts.empty() )
493 systemFonts = mSystemFonts;
494 DALI_LOG_INFO( gLogFilter, Debug::General, " number of system fonts : [%d]\n", mSystemFonts.size() );
495 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetSystemFonts\n");
498 void FontClient::Plugin::GetDescription( FontId id,
499 FontDescription& fontDescription ) const
501 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDescription\n");
502 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
504 for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
505 endIt = mFontIdCache.end();
509 const FontIdCacheItem& item = *it;
511 if( item.fontId == id )
513 fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
515 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
516 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
517 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
518 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
519 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
520 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
525 DALI_LOG_INFO( gLogFilter, Debug::General, " No description found for the font ID %d\n", id );
526 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
529 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
531 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetPointSize\n");
532 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
533 const FontId index = id - 1u;
536 ( index < mFontCache.size() ) )
538 DALI_LOG_INFO( gLogFilter, Debug::General, " point size : %d\n", ( *( mFontCache.begin() + index ) ).mRequestedPointSize );
539 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
540 return ( *( mFontCache.begin() + index ) ).mRequestedPointSize;
544 DALI_LOG_INFO( gLogFilter, Debug::General, " Invalid font ID %d\n", id );
547 DALI_LOG_INFO( gLogFilter, Debug::General, " default point size : %d\n", TextAbstraction::FontClient::DEFAULT_POINT_SIZE );
548 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
549 return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
552 bool FontClient::Plugin::IsCharacterSupportedByFont( FontId fontId, Character character )
554 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::IsCharacterSupportedByFont\n");
555 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
556 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", character );
558 if( ( fontId < 1u ) || ( fontId > mFontCache.size() ) )
560 DALI_LOG_INFO( gLogFilter, Debug::General, " Invalid font id. Number of items in the cache: %d\n",mFontCache.size());
561 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
567 bool isSupported = false;
569 FontFaceCacheItem& cacheItem = mFontCache[fontId];
571 if( NULL == cacheItem.mCharacterSet )
573 // Create again the character set.
574 // It can be null if the ResetSystemDefaults() method has been called.
576 FontDescription description;
577 description.path = cacheItem.mPath;
578 description.family = FontFamily( cacheItem.mFreeTypeFace->family_name );
579 description.weight = FontWeight::NONE;
580 description.width = FontWidth::NONE;
581 description.slant = FontSlant::NONE;
583 // Note FreeType doesn't give too much info to build a proper font style.
584 if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC )
586 description.slant = FontSlant::ITALIC;
588 if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_BOLD )
590 description.weight = FontWeight::BOLD;
593 cacheItem.mCharacterSet = CreateCharacterSetFromDescription( description );
596 isSupported = FcCharSetHasChar( cacheItem.mCharacterSet, character );
598 DALI_LOG_INFO( gLogFilter, Debug::General, " is supported : %s\n", (isSupported ? "true" : "false") );
599 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
603 FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
604 const CharacterSetList& characterSetList,
606 PointSize26Dot6 requestedPointSize,
609 DALI_ASSERT_DEBUG( ( fontList.size() == characterSetList.Count() ) && "FontClient::Plugin::FindFontForCharacter. Different number of fonts and character sets." );
611 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFontForCharacter\n" );
612 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", character );
613 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
614 DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) );
617 bool foundColor = false;
619 DALI_LOG_INFO( gLogFilter, Debug::General, " number of fonts : %d\n", fontList.size() );
621 // Traverse the list of fonts.
622 // Check for each font if supports the character.
623 for( unsigned int index = 0u, numberOfFonts = fontList.size(); index < numberOfFonts; ++index )
625 const FontDescription& description = fontList[index];
626 const FcCharSet* const characterSet = characterSetList[index];
628 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", description.family.c_str() );
629 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", description.path.c_str() );
630 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[description.width] );
631 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[description.weight] );
632 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[description.slant] );
634 bool foundInRanges = false;
635 if( NULL != characterSet )
637 foundInRanges = FcCharSetHasChar( characterSet, character );
642 fontId = GetFontId( description,
646 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " font id : %d\n", fontId );
650 if( ( fontId > 0 ) &&
651 ( fontId - 1u < mFontCache.size() ) )
653 const FontFaceCacheItem& item = mFontCache[fontId - 1u];
655 foundColor = item.mHasColorTables;
658 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " foundColor : %s\n", ( foundColor ? "true" : "false" ) );
661 // Keep going unless we prefer a different (color) font.
662 if( !preferColor || foundColor )
669 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
670 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFontForCharacter\n" );
674 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
675 PointSize26Dot6 requestedPointSize,
678 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindDefaultFont\n" );
679 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", charcode );
680 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
681 DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) );
685 // Create the list of default fonts if it has not been created.
686 if( mDefaultFonts.empty() )
688 FontDescription fontDescription;
689 fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
690 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
691 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
692 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
694 SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
696 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of default fonts : %d\n", mDefaultFonts.size() );
699 // Traverse the list of default fonts.
700 // Check for each default font if supports the character.
701 fontId = FindFontForCharacter( mDefaultFonts, mDefaultFontCharacterSets, charcode, requestedPointSize, preferColor );
703 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
704 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindDefaultFont\n" );
709 FontId FontClient::Plugin::FindFallbackFont( Character charcode,
710 const FontDescription& preferredFontDescription,
711 PointSize26Dot6 requestedPointSize,
714 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFont\n" );
715 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", charcode );
716 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
717 DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) );
719 // The font id to be returned.
722 FontDescription fontDescription;
724 // Fill the font description with the preferred font description and complete with the defaults.
725 fontDescription.family = preferredFontDescription.family.empty() ? DEFAULT_FONT_FAMILY_NAME : preferredFontDescription.family;
726 fontDescription.weight = ( ( FontWeight::NONE == preferredFontDescription.weight ) ? IntToWeightType( DEFAULT_FONT_WEIGHT ) : preferredFontDescription.weight );
727 fontDescription.width = ( ( FontWidth::NONE == preferredFontDescription.width ) ? IntToWidthType( DEFAULT_FONT_WIDTH ) : preferredFontDescription.width );
728 fontDescription.slant = ( ( FontSlant::NONE == preferredFontDescription.slant ) ? IntToSlantType( DEFAULT_FONT_SLANT ) : preferredFontDescription.slant );
730 DALI_LOG_INFO( gLogFilter, Debug::General, " preferredFontDescription --> fontDescription\n" );
731 DALI_LOG_INFO( gLogFilter, Debug::General, " [%s] --> [%s]\n", preferredFontDescription.family.c_str(), fontDescription.family.c_str() );
732 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontWeight::Name[preferredFontDescription.weight], FontWeight::Name[fontDescription.weight] );
733 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontWidth::Name[preferredFontDescription.width], FontWidth::Name[fontDescription.width] );
734 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontSlant::Name[preferredFontDescription.slant], FontSlant::Name[fontDescription.slant] );
736 // Check first if the font's description has been queried before.
737 FontList* fontList = NULL;
738 CharacterSetList* characterSetList = NULL;
740 if( !FindFallbackFontList( fontDescription, fontList, characterSetList ) )
742 fontList = new FontList;
743 characterSetList = new CharacterSetList;
745 SetFontList( fontDescription, *fontList, *characterSetList );
747 // Add the font-list to the cache.
748 mFallbackCache.push_back( FallbackCacheItem( fontDescription, fontList, characterSetList ) );
751 if( fontList && characterSetList )
753 fontId = FindFontForCharacter( *fontList, *characterSetList, charcode, requestedPointSize, preferColor );
756 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
757 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFont\n");
761 FontId FontClient::Plugin::GetFontId( const FontPath& path,
762 PointSize26Dot6 requestedPointSize,
764 bool cacheDescription )
766 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
767 DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() );
768 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
772 if( NULL != mFreeTypeLibrary )
775 if( FindFont( path, requestedPointSize, faceIndex, foundId ) )
781 id = CreateFont( path, requestedPointSize, faceIndex, cacheDescription );
785 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
786 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
791 FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
792 PointSize26Dot6 requestedPointSize,
793 FaceIndex faceIndex )
795 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
796 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
797 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
798 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
799 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
800 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
801 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
803 // This method uses three vectors which caches:
804 // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
805 // * The path to font file names.
806 // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
808 // 1) Checks in the cache if the font's description has been validated before.
809 // If it was it gets an index to the vector with paths to font file names. Otherwise,
810 // retrieves using font config a path to a font file name which matches with the
811 // font's description. The path is stored in the cache.
813 // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
814 // font file names' exists. If exists, it gets the font id. If it doesn't it calls
815 // the GetFontId() method with the path to the font file name and the point size to
818 // The font id to be returned.
821 // Check first if the font's description have been validated before.
822 FontDescriptionId validatedFontId = 0u;
824 if( !FindValidatedFont( fontDescription,
827 // Use font config to validate the font's description.
828 ValidateFont( fontDescription,
832 // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
833 if( !FindFont( validatedFontId, requestedPointSize, fontId ) )
835 // Retrieve the font file name path.
836 const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
838 // Retrieve the font id. Do not cache the description as it has been already cached.
839 fontId = GetFontId( description.path,
844 mFontCache[fontId-1u].mCharacterSet = mCharacterSetCache[validatedFontId];
846 // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
847 mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
852 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
853 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
858 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
859 FontDescriptionId& validatedFontId )
861 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::ValidateFont\n" );
862 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
863 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
864 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
865 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
866 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
868 // Create a font pattern.
869 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
871 FontDescription description;
873 FcCharSet* characterSet = NULL;
874 bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description, &characterSet );
875 FcPatternDestroy( fontFamilyPattern );
877 if( matched && ( NULL != characterSet ) )
879 // Set the index to the vector of paths to font file names.
880 validatedFontId = mFontDescriptionCache.size();
882 DALI_LOG_INFO( gLogFilter, Debug::General, " matched description; family : [%s]\n", description.family.c_str() );
883 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", description.path.c_str() );
884 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[description.width] );
885 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[description.weight] );
886 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[description.slant] );
887 DALI_LOG_INFO( gLogFilter, Debug::General, " validatedFontId : %d\n", validatedFontId );
889 // Add the path to the cache.
890 mFontDescriptionCache.push_back( description );
891 mCharacterSetCache.PushBack( characterSet );
893 // Cache the index and the matched font's description.
894 FontDescriptionCacheItem item( description,
897 mValidatedFontCache.push_back( item );
899 if( ( fontDescription.family != description.family ) ||
900 ( fontDescription.width != description.width ) ||
901 ( fontDescription.weight != description.weight ) ||
902 ( fontDescription.slant != description.slant ) )
904 // Cache the given font's description if it's different than the matched.
905 FontDescriptionCacheItem item( fontDescription,
908 mValidatedFontCache.push_back( item );
913 DALI_LOG_INFO( gLogFilter, Debug::General, " font validation failed for font [%s]\n", fontDescription.family.c_str() );
916 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::ValidateFont\n" );
919 void FontClient::Plugin::GetFontMetrics( FontId fontId,
920 FontMetrics& metrics )
922 if( ( fontId > 0 ) &&
923 ( fontId - 1u < mFontCache.size() ) )
925 const FontFaceCacheItem& font = mFontCache[fontId-1];
927 metrics = font.mMetrics;
929 // Adjust the metrics if the fixed-size font should be down-scaled
930 if( font.mIsFixedSizeBitmap )
932 const float desiredFixedSize = static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
934 if( desiredFixedSize > 0.f )
936 const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
938 metrics.ascender = floorf( metrics.ascender * scaleFactor );
939 metrics.descender = floorf( metrics.descender * scaleFactor );
940 metrics.height = floorf( metrics.height * scaleFactor );
941 metrics.underlinePosition = floorf( metrics.underlinePosition * scaleFactor );
942 metrics.underlineThickness = floorf( metrics.underlineThickness * scaleFactor );
948 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId );
952 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
955 GlyphIndex index = 0u;
957 if( ( fontId > 0u ) &&
958 ( fontId - 1u < mFontCache.size() ) )
960 FT_Face ftFace = mFontCache[fontId-1u].mFreeTypeFace;
962 index = FT_Get_Char_Index( ftFace, charcode );
968 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
973 if( VECTOR_GLYPH == type )
975 return GetVectorMetrics( array, size, horizontal );
978 return GetBitmapMetrics( array, size, horizontal );
981 bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array,
985 bool success( true );
987 for( unsigned int i=0; i<size; ++i )
989 GlyphInfo& glyph = array[i];
991 FontId fontId = glyph.fontId;
994 fontId-1 < mFontCache.size() )
996 const FontFaceCacheItem& font = mFontCache[fontId-1];
998 FT_Face ftFace = font.mFreeTypeFace;
1000 #ifdef FREETYPE_BITMAP_SUPPORT
1001 // Check to see if we should be loading a Fixed Size bitmap?
1002 if ( font.mIsFixedSizeBitmap )
1004 int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_COLOR );
1005 if ( FT_Err_Ok == error )
1007 glyph.width = font.mFixedWidthPixels;
1008 glyph.height = font.mFixedHeightPixels;
1009 glyph.advance = font.mFixedWidthPixels;
1010 glyph.xBearing = 0.0f;
1011 glyph.yBearing = font.mFixedHeightPixels;
1013 // Adjust the metrics if the fixed-size font should be down-scaled
1014 const float desiredFixedSize = static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
1016 if( desiredFixedSize > 0.f )
1018 const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
1020 glyph.width = floorf( glyph.width * scaleFactor );
1021 glyph.height = floorf( glyph.height * scaleFactor );
1022 glyph.advance = floorf( glyph.advance * scaleFactor );
1023 glyph.xBearing = floorf( glyph.xBearing * scaleFactor );
1024 glyph.yBearing = floorf( glyph.yBearing * scaleFactor );
1026 glyph.scaleFactor = scaleFactor;
1031 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetBitmapMetrics. FreeType Bitmap Load_Glyph error %d\n", error );
1038 int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_NO_AUTOHINT );
1040 if( FT_Err_Ok == error )
1042 glyph.width = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
1043 glyph.height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
1046 glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
1047 glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
1051 glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
1052 glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
1070 bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array,
1074 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
1075 bool success( true );
1077 for( unsigned int i=0; i<size; ++i )
1079 FontId fontId = array[i].fontId;
1082 fontId-1 < mFontCache.size() )
1084 FontFaceCacheItem& font = mFontCache[fontId-1];
1086 if( ! font.mVectorFontId )
1088 font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
1091 mVectorFontCache->GetGlyphMetrics( font.mVectorFontId, array[i] );
1093 // Vector metrics are in EMs, convert to pixels
1094 const float scale = ( static_cast<float>( font.mRequestedPointSize ) * FROM_266 ) * static_cast<float>( mDpiVertical ) / POINTS_PER_INCH;
1095 array[i].width *= scale;
1096 array[i].height *= scale;
1097 array[i].xBearing *= scale;
1098 array[i].yBearing *= scale;
1099 array[i].advance *= scale;
1113 void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
1115 if( ( fontId > 0 ) &&
1116 ( fontId - 1u < mFontCache.size() ) )
1118 FT_Face ftFace = mFontCache[fontId - 1u].mFreeTypeFace;
1122 #ifdef FREETYPE_BITMAP_SUPPORT
1123 // Check to see if this is fixed size bitmap
1124 if ( mFontCache[fontId - 1u].mIsFixedSizeBitmap )
1126 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1131 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_NO_AUTOHINT );
1133 if( FT_Err_Ok == error )
1136 error = FT_Get_Glyph( ftFace->glyph, &glyph );
1138 // Convert to bitmap if necessary
1139 if ( FT_Err_Ok == error )
1141 if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
1143 // Check whether we should create a bitmap for the outline
1144 if( glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0 )
1148 error = FT_Stroker_New(mFreeTypeLibrary, &stroker );
1150 if ( FT_Err_Ok == error )
1152 FT_Stroker_Set( stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 );
1153 error = FT_Glyph_StrokeBorder( &glyph, stroker, 0, 1 );
1155 if ( FT_Err_Ok == error )
1157 FT_Stroker_Done( stroker );
1161 DALI_LOG_ERROR( "FT_Glyph_StrokeBorder Failed with error: %d\n", error );
1166 DALI_LOG_ERROR( "FT_Stroker_New Failed with error: %d\n", error );
1170 error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
1171 if ( FT_Err_Ok == error )
1173 FT_BitmapGlyph bitmapGlyph = reinterpret_cast< FT_BitmapGlyph >( glyph );
1174 ConvertBitmap( data, bitmapGlyph->bitmap );
1178 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Get_Glyph Failed with error: %d\n", error );
1183 ConvertBitmap( data, ftFace->glyph->bitmap );
1186 // Created FT_Glyph object must be released with FT_Done_Glyph
1187 FT_Done_Glyph( glyph );
1192 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Load_Glyph Failed with error: %d\n", error );
1197 PixelData FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
1199 TextAbstraction::FontClient::GlyphBufferData data;
1201 CreateBitmap( fontId, glyphIndex, data, outlineWidth );
1203 return PixelData::New( data.buffer,
1204 data.width * data.height * Pixel::GetBytesPerPixel( data.format ),
1208 PixelData::DELETE_ARRAY );
1211 void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
1216 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
1218 fontId-1 < mFontCache.size() )
1220 FontFaceCacheItem& font = mFontCache[fontId-1];
1222 if( ! font.mVectorFontId )
1224 font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
1227 mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
1232 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
1234 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetEllipsisGlyph\n" );
1235 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize %d.\n", requestedPointSize );
1237 // First look into the cache if there is an ellipsis glyph for the requested point size.
1238 for( Vector<EllipsisItem>::ConstIterator it = mEllipsisCache.Begin(),
1239 endIt = mEllipsisCache.End();
1243 const EllipsisItem& item = *it;
1245 if( fabsf( item.requestedPointSize - requestedPointSize ) < Math::MACHINE_EPSILON_1000 )
1247 // Use the glyph in the cache.
1249 DALI_LOG_INFO( gLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index );
1250 DALI_LOG_INFO( gLogFilter, Debug::General, " font %d.\n", item.glyph.fontId );
1251 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
1257 // No glyph has been found. Create one.
1258 mEllipsisCache.PushBack( EllipsisItem() );
1259 EllipsisItem& item = *( mEllipsisCache.End() - 1u );
1261 item.requestedPointSize = requestedPointSize;
1263 // Find a font for the ellipsis glyph.
1264 item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
1268 // Set the character index to access the glyph inside the font.
1269 item.glyph.index = FT_Get_Char_Index( mFontCache[item.glyph.fontId-1].mFreeTypeFace,
1270 ELLIPSIS_CHARACTER );
1272 GetBitmapMetrics( &item.glyph, 1u, true );
1274 DALI_LOG_INFO( gLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index );
1275 DALI_LOG_INFO( gLogFilter, Debug::General, " font %d.\n", item.glyph.fontId );
1276 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
1281 bool FontClient::Plugin::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
1283 FT_Error error = -1;
1285 #ifdef FREETYPE_BITMAP_SUPPORT
1286 if( ( fontId > 0 ) &&
1287 ( fontId - 1u < mFontCache.size() ) )
1289 const FontFaceCacheItem& item = mFontCache[fontId - 1u];
1290 FT_Face ftFace = item.mFreeTypeFace;
1292 // Check to see if this is fixed size bitmap
1293 if( item.mHasColorTables )
1295 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1300 return FT_Err_Ok == error;
1303 bool FontClient::Plugin::AddCustomFontDirectory( const FontPath& path )
1305 // NULL as first parameter means the current configuration is used.
1306 return FcConfigAppFontAddDir( NULL, reinterpret_cast<const FcChar8 *>( path.c_str() ) );
1309 void FontClient::Plugin::InitSystemFonts()
1311 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::InitSystemFonts\n" );
1313 FcFontSet* fontSet = GetFcFontSet();
1317 DALI_LOG_INFO( gLogFilter, Debug::General, " number of system fonts : %d\n", fontSet->nfont );
1319 // Reserve some space to avoid reallocations.
1320 mSystemFonts.reserve( fontSet->nfont );
1322 for( int i = 0u; i < fontSet->nfont; ++i )
1324 FcPattern* fontPattern = fontSet->fonts[i];
1328 // Skip fonts with no path
1329 if( GetFcString( fontPattern, FC_FILE, path ) )
1331 mSystemFonts.push_back( FontDescription() );
1332 FontDescription& fontDescription = mSystemFonts.back();
1334 fontDescription.path = path;
1339 GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
1340 GetFcInt( fontPattern, FC_WIDTH, width );
1341 GetFcInt( fontPattern, FC_WEIGHT, weight );
1342 GetFcInt( fontPattern, FC_SLANT, slant );
1343 fontDescription.width = IntToWidthType( width );
1344 fontDescription.weight = IntToWeightType( weight );
1345 fontDescription.slant = IntToSlantType( slant );
1347 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", fontDescription.family.c_str() );
1348 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1349 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1350 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1351 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1355 FcFontSetDestroy( fontSet );
1357 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::InitSystemFonts\n" );
1360 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet )
1362 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1364 FcResult result = FcResultMatch;
1365 FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
1367 const bool matched = NULL != match;
1368 DALI_LOG_INFO( gLogFilter, Debug::General, " pattern matched : %s\n", ( matched ? "true" : "false" ) );
1375 GetFcString( match, FC_FILE, fontDescription.path );
1376 GetFcString( match, FC_FAMILY, fontDescription.family );
1377 GetFcInt( match, FC_WIDTH, width );
1378 GetFcInt( match, FC_WEIGHT, weight );
1379 GetFcInt( match, FC_SLANT, slant );
1380 fontDescription.width = IntToWidthType( width );
1381 fontDescription.weight = IntToWeightType( weight );
1382 fontDescription.slant = IntToSlantType( slant );
1384 // Cache the character ranges.
1385 FcPatternGetCharSet( match, FC_CHARSET, 0u, characterSet );
1387 // destroyed the matched pattern
1388 FcPatternDestroy( match );
1390 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
1391 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1392 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1393 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1394 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1397 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1401 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription ) const
1403 // create the cached font family lookup pattern
1404 // a pattern holds a set of names, each name refers to a property of the font
1405 FcPattern* fontFamilyPattern = FcPatternCreate();
1407 if( !fontFamilyPattern )
1412 // add a property to the pattern for the font family
1413 FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
1415 // add a property to the pattern for local setting.
1416 const char* locale = setlocale( LC_MESSAGES, NULL );
1419 FcPatternAddString( fontFamilyPattern, FC_LANG, reinterpret_cast<const FcChar8*>( locale ) );
1422 int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
1426 width = DEFAULT_FONT_WIDTH;
1429 int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
1433 weight = DEFAULT_FONT_WEIGHT;
1436 int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
1440 slant = DEFAULT_FONT_SLANT;
1443 FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
1444 FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
1445 FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
1447 // Add a property of the pattern, to say we want to match TrueType fonts
1448 FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
1450 // modify the config, with the mFontFamilyPatterm
1451 FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
1453 // provide default values for unspecified properties in the font pattern
1454 // e.g. patterns without a specified style or weight are set to Medium
1455 FcDefaultSubstitute( fontFamilyPattern );
1457 return fontFamilyPattern;
1460 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
1462 // create a new pattern.
1463 // a pattern holds a set of names, each name refers to a property of the font
1464 FcPattern* pattern = FcPatternCreate();
1466 // create an object set used to define which properties are to be returned in the patterns from FcFontList.
1467 FcObjectSet* objectSet = FcObjectSetCreate();
1469 // build an object set from a list of property names
1470 FcObjectSetAdd( objectSet, FC_FILE );
1471 FcObjectSetAdd( objectSet, FC_FAMILY );
1472 FcObjectSetAdd( objectSet, FC_WIDTH );
1473 FcObjectSetAdd( objectSet, FC_WEIGHT );
1474 FcObjectSetAdd( objectSet, FC_SLANT );
1476 // get a list of fonts
1477 // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1478 FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
1480 // clear up the object set
1483 FcObjectSetDestroy( objectSet );
1485 // clear up the pattern
1488 FcPatternDestroy( pattern );
1494 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1495 const char* const n,
1496 std::string& string )
1498 FcChar8* file = NULL;
1499 const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1501 if( FcResultMatch == retVal )
1503 // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1504 string.assign( reinterpret_cast<const char*>( file ) );
1512 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1514 const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1516 if( FcResultMatch == retVal )
1524 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1525 PointSize26Dot6 requestedPointSize,
1526 FaceIndex faceIndex,
1527 bool cacheDescription )
1529 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::CreateFont\n" );
1530 DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() );
1531 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
1535 // Create & cache new font face
1537 int error = FT_New_Face( mFreeTypeLibrary,
1542 if( FT_Err_Ok == error )
1544 // Check if a font is scalable.
1545 const bool isScalable = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_SCALABLE ) );
1546 const bool hasFixedSizedBitmaps = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) && ( 0 != ftFace->num_fixed_sizes );
1547 const bool hasColorTables = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_COLOR ) );
1549 DALI_LOG_INFO( gLogFilter, Debug::General, " isScalable : [%s]\n", ( isScalable ? "true" : "false" ) );
1550 DALI_LOG_INFO( gLogFilter, Debug::General, " hasFixedSizedBitmaps : [%s]\n", ( hasFixedSizedBitmaps ? "true" : "false" ) );
1551 DALI_LOG_INFO( gLogFilter, Debug::General, " hasColorTables : [%s]\n", ( hasColorTables ? "true" : "false" ) );
1553 // Check to see if the font contains fixed sizes?
1554 if( !isScalable && hasFixedSizedBitmaps )
1556 PointSize26Dot6 actualPointSize = 0u;
1557 int fixedSizeIndex = 0;
1558 for( ; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex )
1560 const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
1561 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " size index : %d, size : %d\n", fixedSizeIndex, fixedSize );
1563 if( fixedSize >= requestedPointSize )
1565 actualPointSize = fixedSize;
1570 if( 0u == actualPointSize )
1572 // The requested point size is bigger than the bigest fixed size.
1573 fixedSizeIndex = ftFace->num_fixed_sizes - 1;
1574 actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
1577 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize );
1579 // Tell Freetype to use this size
1580 error = FT_Select_Size( ftFace, fixedSizeIndex );
1581 if ( FT_Err_Ok != error )
1583 DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Select_Size error: %d\n", error );
1587 float fixedWidth = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].width );
1588 float fixedHeight = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].height );
1590 // Indicate that the font is a fixed sized bitmap
1591 FontMetrics metrics( fixedHeight, // The ascender in pixels.
1593 fixedHeight, // The height in pixels.
1597 mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight, hasColorTables ) );
1598 id = mFontCache.size();
1603 error = FT_Set_Char_Size( ftFace,
1609 if( FT_Err_Ok == error )
1612 FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1614 FontMetrics metrics( static_cast< float >( ftMetrics.ascender ) * FROM_266,
1615 static_cast< float >( ftMetrics.descender ) * FROM_266,
1616 static_cast< float >( ftMetrics.height ) * FROM_266,
1617 static_cast< float >( ftFace->underline_position ) * FROM_266,
1618 static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1620 mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) );
1621 id = mFontCache.size();
1625 DALI_LOG_INFO( gLogFilter, Debug::General, " FreeType Set_Char_Size error: %d for pointSize %d\n", error, requestedPointSize );
1631 if( cacheDescription )
1633 CacheFontPath( ftFace, id, requestedPointSize, path );
1639 DALI_LOG_INFO( gLogFilter, Debug::General, " FreeType New_Face error: %d for [%s]\n", error, path.c_str() );
1642 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
1643 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::CreateFont\n" );
1648 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap )
1650 if( srcBitmap.width*srcBitmap.rows > 0 )
1652 switch( srcBitmap.pixel_mode )
1654 case FT_PIXEL_MODE_GRAY:
1656 if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
1658 const unsigned int bufferSize = srcBitmap.width * srcBitmap.rows;
1659 data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1660 data.width = srcBitmap.width;
1661 data.height = srcBitmap.rows;
1662 data.format = Pixel::L8;
1663 memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1668 #ifdef FREETYPE_BITMAP_SUPPORT
1669 case FT_PIXEL_MODE_BGRA:
1671 if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
1673 // Set the input dimensions.
1674 const ImageDimensions inputDimensions( srcBitmap.width, srcBitmap.rows );
1676 // Set the output dimensions.
1677 // If the output dimension is not given, the input dimension is set
1678 // and won't be downscaling.
1679 data.width = ( data.width == 0 ) ? srcBitmap.width : data.width;
1680 data.height = ( data.height == 0 ) ? srcBitmap.rows : data.height;
1681 const ImageDimensions desiredDimensions( data.width, data.height );
1683 // Creates the output buffer
1684 const unsigned int bufferSize = data.width * data.height * 4u;
1685 data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1687 if( inputDimensions == desiredDimensions )
1689 // There isn't downscaling.
1690 memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1694 Dali::Internal::Platform::LanczosSample4BPP( srcBitmap.buffer,
1697 desiredDimensions );
1699 data.format = Pixel::BGRA8888;
1706 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::ConvertBitmap. FontClient Unable to create Bitmap of this PixelType\n" );
1713 bool FontClient::Plugin::FindFont( const FontPath& path,
1714 PointSize26Dot6 requestedPointSize,
1715 FaceIndex faceIndex,
1716 FontId& fontId ) const
1718 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1719 DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() );
1720 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
1721 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of fonts in the cache : %d\n", mFontCache.size() );
1724 for( std::vector<FontFaceCacheItem>::const_iterator it = mFontCache.begin(),
1725 endIt = mFontCache.end();
1729 const FontFaceCacheItem& cacheItem = *it;
1731 if( cacheItem.mRequestedPointSize == requestedPointSize &&
1732 cacheItem.mFaceIndex == faceIndex &&
1733 cacheItem.mPath == path )
1737 DALI_LOG_INFO( gLogFilter, Debug::General, " font found, id : %d\n", fontId );
1738 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1744 DALI_LOG_INFO( gLogFilter, Debug::General, " font not found\n" );
1745 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1750 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1751 FontDescriptionId& validatedFontId )
1753 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindValidatedFont\n" );
1754 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
1755 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1756 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1757 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1758 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1759 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of validated fonts in the cache : %d\n", mValidatedFontCache.size() );
1761 validatedFontId = 0u;
1763 for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
1764 endIt = mValidatedFontCache.end();
1768 const FontDescriptionCacheItem& item = *it;
1770 if( !fontDescription.family.empty() &&
1771 ( fontDescription.family == item.fontDescription.family ) &&
1772 ( fontDescription.width == item.fontDescription.width ) &&
1773 ( fontDescription.weight == item.fontDescription.weight ) &&
1774 ( fontDescription.slant == item.fontDescription.slant ) )
1776 validatedFontId = item.index;
1778 DALI_LOG_INFO( gLogFilter, Debug::General, " validated font found, id : %d\n", validatedFontId );
1779 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1784 DALI_LOG_INFO( gLogFilter, Debug::General, " validated font not found\n" );
1785 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1789 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1790 FontList*& fontList,
1791 CharacterSetList*& characterSetList )
1793 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFontList\n" );
1794 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
1795 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1796 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1797 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1798 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1799 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of fallback font lists in the cache : %d\n", mFallbackCache.size() );
1803 for( std::vector<FallbackCacheItem>::const_iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
1807 const FallbackCacheItem& item = *it;
1809 if( !fontDescription.family.empty() &&
1810 ( fontDescription.family == item.fontDescription.family ) &&
1811 ( fontDescription.width == item.fontDescription.width ) &&
1812 ( fontDescription.weight == item.fontDescription.weight ) &&
1813 ( fontDescription.slant == item.fontDescription.slant ) )
1815 fontList = item.fallbackFonts;
1816 characterSetList = item.characterSets;
1818 DALI_LOG_INFO( gLogFilter, Debug::General, " fallback font list found.\n" );
1819 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1824 DALI_LOG_INFO( gLogFilter, Debug::General, " fallback font list not found.\n" );
1825 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1829 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1830 PointSize26Dot6 requestedPointSize,
1833 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1834 DALI_LOG_INFO( gLogFilter, Debug::General, " validatedFontId : %d\n", validatedFontId );
1835 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
1839 for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
1840 endIt = mFontIdCache.end();
1844 const FontIdCacheItem& item = *it;
1846 if( ( validatedFontId == item.validatedFontId ) &&
1847 ( requestedPointSize == item.requestedPointSize ) )
1849 fontId = item.fontId;
1851 DALI_LOG_INFO( gLogFilter, Debug::General, " font found, id : %d\n", fontId );
1852 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1857 DALI_LOG_INFO( gLogFilter, Debug::General, " font not found.\n" );
1858 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1862 bool FontClient::Plugin::IsScalable( const FontPath& path )
1864 bool isScalable = false;
1867 int error = FT_New_Face( mFreeTypeLibrary,
1871 if( FT_Err_Ok != error )
1873 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: %s\n", path.c_str() );
1877 isScalable = ftFace->face_flags & FT_FACE_FLAG_SCALABLE;
1883 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1885 // Create a font pattern.
1886 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1888 FcResult result = FcResultMatch;
1890 // match the pattern
1891 FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1892 bool isScalable = false;
1896 // Get the path to the font file name.
1898 GetFcString( match, FC_FILE, path );
1899 isScalable = IsScalable( path );
1903 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1905 FcPatternDestroy( fontFamilyPattern );
1906 FcPatternDestroy( match );
1910 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1912 // Empty the caller container
1916 int error = FT_New_Face( mFreeTypeLibrary,
1920 if( FT_Err_Ok != error )
1922 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font path : [%s]\n", path.c_str() );
1925 // Fetch the number of fixed sizes available
1926 if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1928 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1930 sizes.PushBack( ftFace->available_sizes[ i ].size );
1935 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1936 Vector< PointSize26Dot6 >& sizes )
1938 // Create a font pattern.
1939 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1941 FcResult result = FcResultMatch;
1943 // match the pattern
1944 FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1948 // Get the path to the font file name.
1950 GetFcString( match, FC_FILE, path );
1951 GetFixedSizes( path, sizes );
1955 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1957 FcPatternDestroy( match );
1958 FcPatternDestroy( fontFamilyPattern );
1961 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize, const FontPath& path )
1963 FontDescription description;
1964 description.path = path;
1965 description.family = FontFamily( ftFace->family_name );
1966 description.weight = FontWeight::NONE;
1967 description.width = FontWidth::NONE;
1968 description.slant = FontSlant::NONE;
1970 // Note FreeType doesn't give too much info to build a proper font style.
1971 if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1973 description.slant = FontSlant::ITALIC;
1975 if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1977 description.weight = FontWeight::BOLD;
1980 FontDescriptionId validatedFontId = 0u;
1981 if( !FindValidatedFont( description,
1984 // Set the index to the vector of paths to font file names.
1985 validatedFontId = mFontDescriptionCache.size();
1987 FcPattern* pattern = CreateFontFamilyPattern( description );
1989 FcResult result = FcResultMatch;
1990 FcPattern* match = FcFontMatch( NULL, pattern, &result );
1992 FcCharSet* characterSet = NULL;
1993 FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
1995 FcPatternDestroy( pattern );
1997 mMatchedFcPatternCache.PushBack( match );
1999 mFontCache[id-1u].mCharacterSet = characterSet;
2001 // Add the path to the cache.
2002 mFontDescriptionCache.push_back( description );
2003 mCharacterSetCache.PushBack( characterSet );
2005 // Cache the index and the font's description.
2006 FontDescriptionCacheItem item( description,
2009 mValidatedFontCache.push_back( item );
2011 // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
2012 mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
2018 FcCharSet* FontClient::Plugin::CreateCharacterSetFromDescription( const FontDescription& description )
2020 FcCharSet* characterSet = NULL;
2022 FcPattern* pattern = CreateFontFamilyPattern( description );
2024 if( NULL != pattern )
2026 FcResult result = FcResultMatch;
2027 FcPattern* match = FcFontMatch( NULL, pattern, &result );
2029 FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
2031 mMatchedFcPatternCache.PushBack( match );
2033 FcPatternDestroy( pattern );
2036 return characterSet;
2039 void FontClient::Plugin::DestroyMatchedPatterns()
2041 for (auto & object : mMatchedFcPatternCache) {
2042 FcPatternDestroy(reinterpret_cast<FcPattern*>(object));
2044 mMatchedFcPatternCache.Clear();
2047 } // namespace Internal
2049 } // namespace TextAbstraction