2 * Copyright (c) 2018 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/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/text-abstraction/font-client-helper.h>
29 #include <dali/internal/imaging/common/image-operations.h>
30 #include <dali/internal/adaptor/common/adaptor-impl.h>
31 #include <dali/devel-api/adaptor-framework/image-loading.h>
34 #include <fontconfig/fontconfig.h>
39 #if defined(DEBUG_ENABLED)
40 Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
44 * Conversion from Fractional26.6 to float
46 const float FROM_266 = 1.0f / 64.0f;
47 const float POINTS_PER_INCH = 72.f;
49 const std::string FONT_FORMAT( "TrueType" );
50 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
51 const int DEFAULT_FONT_WIDTH = 100; // normal
52 const int DEFAULT_FONT_WEIGHT = 80; // normal
53 const int DEFAULT_FONT_SLANT = 0; // normal
55 const uint32_t ELLIPSIS_CHARACTER = 0x2026;
57 // http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
59 // NONE -1 --> DEFAULT_FONT_WIDTH (NORMAL) will be used.
69 const int FONT_WIDTH_TYPE_TO_INT[] = { -1, 50, 63, 75, 87, 100, 113, 125, 150, 200 };
70 const unsigned int NUM_FONT_WIDTH_TYPE = sizeof( FONT_WIDTH_TYPE_TO_INT ) / sizeof( int );
72 // NONE -1 --> DEFAULT_FONT_WEIGHT (NORMAL) will be used.
74 // ULTRA_LIGHT, EXTRA_LIGHT 40
76 // DEMI_LIGHT, SEMI_LIGHT 55
80 // DEMI_BOLD, SEMI_BOLD 180
82 // ULTRA_BOLD, EXTRA_BOLD 205
83 // BLACK, HEAVY, EXTRA_BLACK 210
84 const int FONT_WEIGHT_TYPE_TO_INT[] = { -1, 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210 };
85 const unsigned int NUM_FONT_WEIGHT_TYPE = sizeof( FONT_WEIGHT_TYPE_TO_INT ) / sizeof( int );
87 // NONE -1 --> DEFAULT_FONT_SLANT (NORMAL) will be used.
91 const int FONT_SLANT_TYPE_TO_INT[] = { -1, 0, 100, 110 };
92 const unsigned int NUM_FONT_SLANT_TYPE = sizeof( FONT_SLANT_TYPE_TO_INT ) / sizeof( int );
103 namespace TextAbstraction
110 * @brief Returns the FontWidth's enum index for the given width value.
112 * @param[in] width The width value.
114 * @return The FontWidth's enum index.
116 FontWidth::Type IntToWidthType( int width )
118 return static_cast<FontWidth::Type>( ValueToIndex( width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u ) );
122 * @brief Returns the FontWeight's enum index for the given weight value.
124 * @param[in] weight The weight value.
126 * @return The FontWeight's enum index.
128 FontWeight::Type IntToWeightType( int weight )
130 return static_cast<FontWeight::Type>( ValueToIndex( weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u ) );
134 * @brief Returns the FontSlant's enum index for the given slant value.
136 * @param[in] slant The slant value.
138 * @return The FontSlant's enum index.
140 FontSlant::Type IntToSlantType( int slant )
142 return static_cast<FontSlant::Type>( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) );
146 * @brief Free the resources allocated by the FcCharSet objects.
148 * @param[in] characterSets The vector of character sets.
150 void DestroyCharacterSets( CharacterSetList& characterSets )
152 for( auto& item : characterSets )
154 FcCharSetDestroy( item );
158 FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( FontDescription&& font, FontList* fallbackFonts, CharacterSetList* characterSets )
159 : fontDescription{ std::move( font ) },
160 fallbackFonts{ fallbackFonts },
161 characterSets{ characterSets }
165 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
166 FontDescriptionId index )
167 : fontDescription{ fontDescription },
172 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( FontDescription&& fontDescription,
173 FontDescriptionId index )
174 : fontDescription{ std::move( fontDescription ) },
179 FontClient::Plugin::FontDescriptionSizeCacheItem::FontDescriptionSizeCacheItem( FontDescriptionId validatedFontId,
180 PointSize26Dot6 requestedPointSize,
182 : validatedFontId( validatedFontId ),
183 requestedPointSize( requestedPointSize ),
188 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
189 const FontPath& path,
190 PointSize26Dot6 requestedPointSize,
192 const FontMetrics& metrics )
193 : mFreeTypeFace( ftFace ),
195 mRequestedPointSize( requestedPointSize ),
198 mCharacterSet( nullptr ),
199 mFixedSizeIndex( 0 ),
200 mFixedWidthPixels( 0.f ),
201 mFixedHeightPixels( 0.f ),
204 mIsFixedSizeBitmap( false ),
205 mHasColorTables( false )
209 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
210 const FontPath& path,
211 PointSize26Dot6 requestedPointSize,
213 const FontMetrics& metrics,
217 bool hasColorTables )
218 : mFreeTypeFace( ftFace ),
220 mRequestedPointSize( requestedPointSize ),
223 mCharacterSet( nullptr ),
224 mFixedSizeIndex( fixedSizeIndex ),
225 mFixedWidthPixels( fixedWidth ),
226 mFixedHeightPixels( fixedHeight ),
229 mIsFixedSizeBitmap( true ),
230 mHasColorTables( hasColorTables )
234 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
235 unsigned int verticalDpi )
236 : mFreeTypeLibrary( nullptr ),
237 mDpiHorizontal( horizontalDpi ),
238 mDpiVertical( verticalDpi ),
239 mDefaultFontDescription(),
244 mValidatedFontCache(),
245 mFontDescriptionCache( 1u ),
246 mCharacterSetCache(),
247 mFontDescriptionSizeCache(),
248 mVectorFontCache( nullptr ),
250 mEmbeddedItemCache(),
251 mDefaultFontDescriptionCached( false )
253 mCharacterSetCache.Resize( 1u );
255 int error = FT_Init_FreeType( &mFreeTypeLibrary );
256 if( FT_Err_Ok != error )
258 DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Init error: %d\n", error );
261 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
262 mVectorFontCache = new VectorFontCache( mFreeTypeLibrary );
267 FontClient::Plugin::~Plugin()
269 ClearFallbackCache( mFallbackCache );
271 // Free the resources allocated by the FcCharSet objects.
272 DestroyCharacterSets( mDefaultFontCharacterSets );
273 DestroyCharacterSets( mCharacterSetCache );
274 ClearCharacterSetFromFontFaceCache();
276 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
277 delete mVectorFontCache;
279 FT_Done_FreeType( mFreeTypeLibrary );
282 void FontClient::Plugin::ClearCache()
284 mDefaultFontDescription = FontDescription();
286 mSystemFonts.clear();
287 mDefaultFonts.clear();
289 DestroyCharacterSets( mDefaultFontCharacterSets );
290 mDefaultFontCharacterSets.Clear();
292 ClearFallbackCache( mFallbackCache );
293 mFallbackCache.clear();
295 mFontIdCache.Clear();
297 ClearCharacterSetFromFontFaceCache();
298 mFontFaceCache.clear();
300 mValidatedFontCache.clear();
301 mFontDescriptionCache.clear();
302 mFontDescriptionCache.resize( 1u );
304 DestroyCharacterSets( mCharacterSetCache );
305 mCharacterSetCache.Clear();
306 mCharacterSetCache.Resize( 1u );
308 mFontDescriptionSizeCache.clear();
310 mEllipsisCache.Clear();
311 mPixelBufferCache.clear();
312 mEmbeddedItemCache.Clear();
313 mBitmapFontCache.clear();
315 mDefaultFontDescriptionCached = false;
318 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
319 unsigned int verticalDpi )
321 mDpiHorizontal = horizontalDpi;
322 mDpiVertical = verticalDpi;
325 void FontClient::Plugin::ResetSystemDefaults()
327 mDefaultFontDescriptionCached = false;
330 void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList )
332 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::SetFontList\n" );
333 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
334 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
335 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
336 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
340 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription ); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
342 FcResult result = FcResultMatch;
344 // Match the pattern.
345 FcFontSet* fontSet = FcFontSort( nullptr /* use default configure */,
347 false /* don't trim */,
349 &result ); // FcFontSort creates a font set that needs to be destroyed by calling FcFontSetDestroy.
351 if( nullptr != fontSet )
353 DALI_LOG_INFO( gLogFilter, Debug::General, " number of fonts found : [%d]\n", fontSet->nfont );
354 // Reserve some space to avoid reallocations.
355 fontList.reserve( fontSet->nfont );
357 for( int i = 0u; i < fontSet->nfont; ++i )
359 FcPattern* fontPattern = fontSet->fonts[i];
363 // Skip fonts with no path
364 if( GetFcString( fontPattern, FC_FILE, path ) )
366 // Retrieve the character set. Need to call FcCharSetDestroy to free the resources.
367 FcCharSet* characterSet = nullptr;
368 FcPatternGetCharSet( fontPattern, FC_CHARSET, 0u, &characterSet );
370 // Increase the reference counter of the character set.
371 characterSetList.PushBack( FcCharSetCopy( characterSet ) );
373 fontList.push_back( FontDescription() );
374 FontDescription& newFontDescription = fontList.back();
376 newFontDescription.path = std::move( path );
381 GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
382 GetFcInt( fontPattern, FC_WIDTH, width );
383 GetFcInt( fontPattern, FC_WEIGHT, weight );
384 GetFcInt( fontPattern, FC_SLANT, slant );
385 newFontDescription.width = IntToWidthType( width );
386 newFontDescription.weight = IntToWeightType( weight );
387 newFontDescription.slant = IntToSlantType( slant );
389 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", newFontDescription.family.c_str() );
390 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", newFontDescription.path.c_str() );
391 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[newFontDescription.width] );
392 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[newFontDescription.weight] );
393 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[newFontDescription.slant] );
397 // Destroys the font set created by FcFontSort.
398 FcFontSetDestroy( fontSet );
402 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " No fonts found.\n" );
405 // Destroys the pattern created by FcPatternCreate in CreateFontFamilyPattern.
406 FcPatternDestroy( fontFamilyPattern );
408 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::SetFontList\n" );
411 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
413 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultFonts\n" );
415 if( mDefaultFonts.empty() )
417 FontDescription fontDescription;
418 fontDescription.family = DEFAULT_FONT_FAMILY_NAME; // todo This could be set to the Platform font
419 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
420 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
421 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
422 SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
425 defaultFonts = mDefaultFonts;
427 DALI_LOG_INFO( gLogFilter, Debug::General, " number of default fonts : [%d]\n", mDefaultFonts.size() );
428 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultFonts\n" );
431 void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
433 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultPlatformFontDescription\n");
435 if( !mDefaultFontDescriptionCached )
437 // Clear any font config stored info in the caches.
439 // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
440 DestroyCharacterSets( mDefaultFontCharacterSets );
441 DestroyCharacterSets( mCharacterSetCache );
442 mDefaultFontCharacterSets.Clear();
443 mCharacterSetCache.Clear();
445 for( auto& item : mFallbackCache )
447 // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
448 DestroyCharacterSets( *item.characterSets );
450 delete item.characterSets;
451 item.characterSets = nullptr;
454 // Set the character set pointer as null. Will be created again the next time IsCharacterSupportedByFont()
455 ClearCharacterSetFromFontFaceCache();
457 // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
458 FcInitReinitialize();
460 FcPattern* matchPattern = FcPatternCreate(); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
462 if( nullptr != matchPattern )
464 FcConfigSubstitute( nullptr, matchPattern, FcMatchPattern );
465 FcDefaultSubstitute( matchPattern );
467 FcCharSet* characterSet = nullptr;
468 MatchFontDescriptionToPattern( matchPattern, mDefaultFontDescription, &characterSet );
469 // Decrease the reference counter of the character set as it's not stored.
470 FcCharSetDestroy( characterSet );
472 // Destroys the pattern created.
473 FcPatternDestroy( matchPattern );
476 // Create again the character sets as they are not valid after FcInitReinitialize()
478 for( const auto& description : mDefaultFonts )
480 mDefaultFontCharacterSets.PushBack( FcCharSetCopy( CreateCharacterSetFromDescription( description ) ) );
483 for( const auto& description : mFontDescriptionCache )
485 mCharacterSetCache.PushBack( FcCharSetCopy( CreateCharacterSetFromDescription( description ) ) );
488 for( auto& item : mFallbackCache )
490 if( nullptr != item.fallbackFonts )
492 if( nullptr == item.characterSets )
494 item.characterSets = new CharacterSetList;
497 for( const auto& description : *( item.fallbackFonts ) )
499 item.characterSets->PushBack( FcCharSetCopy( CreateCharacterSetFromDescription( description ) ) );
504 mDefaultFontDescriptionCached = true;
507 fontDescription.path = mDefaultFontDescription.path;
508 fontDescription.family = mDefaultFontDescription.family;
509 fontDescription.width = mDefaultFontDescription.width;
510 fontDescription.weight = mDefaultFontDescription.weight;
511 fontDescription.slant = mDefaultFontDescription.slant;
513 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
514 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
515 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
516 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
517 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
518 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultPlatformFontDescription\n");
521 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
523 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetSystemFonts\n");
525 if( mSystemFonts.empty() )
530 systemFonts = mSystemFonts;
531 DALI_LOG_INFO( gLogFilter, Debug::General, " number of system fonts : [%d]\n", mSystemFonts.size() );
532 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetSystemFonts\n");
535 void FontClient::Plugin::GetDescription( FontId id,
536 FontDescription& fontDescription ) const
538 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDescription\n");
539 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
540 const FontId index = id - 1u;
542 if( ( id > 0u ) && ( index < mFontIdCache.Count() ) )
544 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
545 switch( fontIdCacheItem.type )
547 case FontDescription::FACE_FONT:
549 for( const auto& item : mFontDescriptionSizeCache )
551 if( item.fontId == fontIdCacheItem.id )
553 fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
555 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
556 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
557 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
558 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
559 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
560 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
566 case FontDescription::BITMAP_FONT:
568 fontDescription.type = FontDescription::BITMAP_FONT;
569 fontDescription.family = mBitmapFontCache[fontIdCacheItem.id].font.name;
574 DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
575 fontDescription.type = FontDescription::INVALID;
576 fontDescription.family.clear();
581 DALI_LOG_INFO( gLogFilter, Debug::General, " No description found for the font ID %d\n", id );
582 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
585 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
587 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetPointSize\n");
588 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
589 const FontId index = id - 1u;
592 ( index < mFontIdCache.Count() ) )
594 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
596 switch( fontIdCacheItem.type )
598 case FontDescription::FACE_FONT:
600 DALI_LOG_INFO( gLogFilter, Debug::General, " point size : %d\n", ( *( mFontFaceCache.begin() + fontIdCacheItem.id ) ).mRequestedPointSize );
601 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
602 return ( *( mFontFaceCache.begin() + fontIdCacheItem.id ) ).mRequestedPointSize;
604 case FontDescription::BITMAP_FONT:
606 return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
610 DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
616 DALI_LOG_INFO( gLogFilter, Debug::General, " Invalid font ID %d\n", id );
619 DALI_LOG_INFO( gLogFilter, Debug::General, " default point size : %d\n", TextAbstraction::FontClient::DEFAULT_POINT_SIZE );
620 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
621 return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
624 bool FontClient::Plugin::IsCharacterSupportedByFont( FontId fontId, Character character )
626 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::IsCharacterSupportedByFont\n");
627 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
628 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", character );
630 if( ( fontId < 1u ) || ( fontId > mFontIdCache.Count() ) )
632 DALI_LOG_INFO( gLogFilter, Debug::General, " Invalid font id. Number of items in the cache: %d\n",mFontIdCache.Count());
633 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
639 bool isSupported = false;
641 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[fontId];
643 switch( fontIdCacheItem.type )
645 case FontDescription::FACE_FONT:
647 if( fontIdCacheItem.id < mFontFaceCache.size() )
649 FontFaceCacheItem& cacheItem = mFontFaceCache[fontIdCacheItem.id];
651 if( nullptr == cacheItem.mCharacterSet )
653 // Create again the character set.
654 // It can be null if the ResetSystemDefaults() method has been called.
656 FontDescription description;
657 description.path = cacheItem.mPath;
658 description.family = std::move( FontFamily( cacheItem.mFreeTypeFace->family_name ) );
659 description.weight = FontWeight::NONE;
660 description.width = FontWidth::NONE;
661 description.slant = FontSlant::NONE;
663 // Note FreeType doesn't give too much info to build a proper font style.
664 if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC )
666 description.slant = FontSlant::ITALIC;
668 if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_BOLD )
670 description.weight = FontWeight::BOLD;
673 cacheItem.mCharacterSet = FcCharSetCopy( CreateCharacterSetFromDescription( description ) );
676 isSupported = FcCharSetHasChar( cacheItem.mCharacterSet, character );
680 case FontDescription::BITMAP_FONT:
682 const BitmapFont& bitmapFont = mBitmapFontCache[fontIdCacheItem.id].font;
684 for( const auto& glyph : bitmapFont.glyphs )
686 if( glyph.utf32 == character )
696 DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
700 DALI_LOG_INFO( gLogFilter, Debug::General, " is supported : %s\n", (isSupported ? "true" : "false") );
701 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
705 FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
706 const CharacterSetList& characterSetList,
708 PointSize26Dot6 requestedPointSize,
711 DALI_ASSERT_DEBUG( ( fontList.size() == characterSetList.Count() ) && "FontClient::Plugin::FindFontForCharacter. Different number of fonts and character sets." );
713 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFontForCharacter\n" );
714 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", character );
715 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
716 DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) );
719 bool foundColor = false;
721 DALI_LOG_INFO( gLogFilter, Debug::General, " number of fonts : %d\n", fontList.size() );
723 // Traverse the list of fonts.
724 // Check for each font if supports the character.
725 for( unsigned int index = 0u, numberOfFonts = fontList.size(); index < numberOfFonts; ++index )
727 const FontDescription& description = fontList[index];
728 const FcCharSet* const characterSet = characterSetList[index];
730 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", description.family.c_str() );
731 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", description.path.c_str() );
732 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[description.width] );
733 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[description.weight] );
734 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[description.slant] );
736 bool foundInRanges = false;
737 if( nullptr != characterSet )
739 foundInRanges = FcCharSetHasChar( characterSet, character );
744 fontId = GetFontId( description,
748 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " font id : %d\n", fontId );
752 if( ( fontId > 0 ) &&
753 ( fontId - 1u < mFontIdCache.Count() ) )
755 const FontFaceCacheItem& item = mFontFaceCache[mFontIdCache[fontId - 1u].id];
757 foundColor = item.mHasColorTables;
760 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " foundColor : %s\n", ( foundColor ? "true" : "false" ) );
763 // Keep going unless we prefer a different (color) font.
764 if( !preferColor || foundColor )
771 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
772 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFontForCharacter\n" );
776 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
777 PointSize26Dot6 requestedPointSize,
780 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindDefaultFont\n" );
781 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", charcode );
782 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
783 DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) );
787 // Create the list of default fonts if it has not been created.
788 if( mDefaultFonts.empty() )
790 FontDescription fontDescription;
791 fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
792 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
793 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
794 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
796 SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
798 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of default fonts : %d\n", mDefaultFonts.size() );
801 // Traverse the list of default fonts.
802 // Check for each default font if supports the character.
803 fontId = FindFontForCharacter( mDefaultFonts, mDefaultFontCharacterSets, charcode, requestedPointSize, preferColor );
805 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
806 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindDefaultFont\n" );
811 FontId FontClient::Plugin::FindFallbackFont( Character charcode,
812 const FontDescription& preferredFontDescription,
813 PointSize26Dot6 requestedPointSize,
816 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFont\n" );
817 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", charcode );
818 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
819 DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) );
821 // The font id to be returned.
824 FontDescription fontDescription;
826 // Fill the font description with the preferred font description and complete with the defaults.
827 fontDescription.family = preferredFontDescription.family.empty() ? DEFAULT_FONT_FAMILY_NAME : preferredFontDescription.family;
828 fontDescription.weight = ( ( FontWeight::NONE == preferredFontDescription.weight ) ? IntToWeightType( DEFAULT_FONT_WEIGHT ) : preferredFontDescription.weight );
829 fontDescription.width = ( ( FontWidth::NONE == preferredFontDescription.width ) ? IntToWidthType( DEFAULT_FONT_WIDTH ) : preferredFontDescription.width );
830 fontDescription.slant = ( ( FontSlant::NONE == preferredFontDescription.slant ) ? IntToSlantType( DEFAULT_FONT_SLANT ) : preferredFontDescription.slant );
832 DALI_LOG_INFO( gLogFilter, Debug::General, " preferredFontDescription --> fontDescription\n" );
833 DALI_LOG_INFO( gLogFilter, Debug::General, " [%s] --> [%s]\n", preferredFontDescription.family.c_str(), fontDescription.family.c_str() );
834 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontWeight::Name[preferredFontDescription.weight], FontWeight::Name[fontDescription.weight] );
835 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontWidth::Name[preferredFontDescription.width], FontWidth::Name[fontDescription.width] );
836 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontSlant::Name[preferredFontDescription.slant], FontSlant::Name[fontDescription.slant] );
838 // Check first if the font's description has been queried before.
839 FontList* fontList = nullptr;
840 CharacterSetList* characterSetList = nullptr;
842 if( !FindFallbackFontList( fontDescription, fontList, characterSetList ) )
844 fontList = new FontList;
845 characterSetList = new CharacterSetList;
847 SetFontList( fontDescription, *fontList, *characterSetList );
849 // Add the font-list to the cache.
850 mFallbackCache.push_back( std::move( FallbackCacheItem( std::move( fontDescription ), fontList, characterSetList ) ) );
853 if( fontList && characterSetList )
855 fontId = FindFontForCharacter( *fontList, *characterSetList, charcode, requestedPointSize, preferColor );
858 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
859 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFont\n");
863 FontId FontClient::Plugin::GetFontId( const FontPath& path,
864 PointSize26Dot6 requestedPointSize,
866 bool cacheDescription )
868 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
869 DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() );
870 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
874 if( nullptr != mFreeTypeLibrary )
877 if( FindFont( path, requestedPointSize, faceIndex, foundId ) )
883 id = CreateFont( path, requestedPointSize, faceIndex, cacheDescription );
887 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
888 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
893 FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
894 PointSize26Dot6 requestedPointSize,
895 FaceIndex faceIndex )
897 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
898 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
899 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
900 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
901 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
902 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
903 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
905 // This method uses three vectors which caches:
906 // * The bitmap font cache
907 // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
908 // * The path to font file names.
909 // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
911 // 1) Checks if the font description matches with a previously loaded bitmap font.
912 // Returns if a font is found.
913 // 2) Checks in the cache if the font's description has been validated before.
914 // If it was it gets an index to the vector with paths to font file names. Otherwise,
915 // retrieves using font config a path to a font file name which matches with the
916 // font's description. The path is stored in the cache.
918 // 3) Checks in the cache if the pair 'font point size, index to the vector with paths to
919 // font file names' exists. If exists, it gets the font id. If it doesn't it calls
920 // the GetFontId() method with the path to the font file name and the point size to
923 // The font id to be returned.
926 // Check first if the font description matches with a previously loaded bitmap font.
927 if( FindBitmapFont( fontDescription.family, fontId ) )
932 // Check if the font's description have been validated before.
933 FontDescriptionId validatedFontId = 0u;
935 if( !FindValidatedFont( fontDescription,
938 // Use font config to validate the font's description.
939 ValidateFont( fontDescription,
943 FontId fontFaceId = 0u;
944 // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
945 if( !FindFont( validatedFontId, requestedPointSize, fontFaceId ) )
947 // Retrieve the font file name path.
948 const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
950 // Retrieve the font id. Do not cache the description as it has been already cached.
951 fontId = GetFontId( description.path,
956 fontFaceId = mFontIdCache[fontId-1u].id;
957 mFontFaceCache[fontFaceId].mCharacterSet = FcCharSetCopy( mCharacterSetCache[validatedFontId] );
959 // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
960 mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
966 fontId = mFontFaceCache[fontFaceId].mFontId + 1u;
969 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
970 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
975 FontId FontClient::Plugin::GetFontId( const BitmapFont& bitmapFont )
977 for( const auto& item : mBitmapFontCache )
979 if( bitmapFont.name == item.font.name )
985 BitmapFontCacheItem bitmapFontCacheItem;
986 bitmapFontCacheItem.font = bitmapFont;
987 bitmapFontCacheItem.id = mFontIdCache.Count();
989 // Resize the vector with the pixel buffers.
990 bitmapFontCacheItem.pixelBuffers.resize( bitmapFont.glyphs.size() );
992 // Traverse all the glyphs and load the pixel buffer of those with ascender and descender equal to zero.
993 unsigned int index = 0u;
994 for( auto& glyph : bitmapFontCacheItem.font.glyphs )
996 Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
998 if( EqualsZero( glyph.ascender ) && EqualsZero( glyph.descender ) )
1001 pixelBuffer = LoadImageFromFile( glyph.url );
1005 glyph.ascender = static_cast<float>(pixelBuffer.GetHeight());
1009 bitmapFontCacheItem.font.ascender = std::max( glyph.ascender, bitmapFontCacheItem.font.ascender );
1010 bitmapFontCacheItem.font.descender = std::min( glyph.descender, bitmapFontCacheItem.font.descender );
1015 FontIdCacheItem fontIdCacheItem;
1016 fontIdCacheItem.type = FontDescription::BITMAP_FONT;
1017 fontIdCacheItem.id = mBitmapFontCache.size();
1019 mBitmapFontCache.push_back( std::move( bitmapFontCacheItem ) );
1020 mFontIdCache.PushBack( fontIdCacheItem );
1022 return bitmapFontCacheItem.id + 1u;
1025 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
1026 FontDescriptionId& validatedFontId )
1028 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::ValidateFont\n" );
1029 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
1030 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1031 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1032 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1033 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1035 // Create a font pattern.
1036 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1038 FontDescription description;
1040 FcCharSet* characterSet = nullptr;
1041 bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description, &characterSet );
1042 FcPatternDestroy( fontFamilyPattern );
1044 if( matched && ( nullptr != characterSet ) )
1046 // Set the index to the vector of paths to font file names.
1047 validatedFontId = mFontDescriptionCache.size();
1049 DALI_LOG_INFO( gLogFilter, Debug::General, " matched description; family : [%s]\n", description.family.c_str() );
1050 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", description.path.c_str() );
1051 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[description.width] );
1052 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[description.weight] );
1053 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[description.slant] );
1054 DALI_LOG_INFO( gLogFilter, Debug::General, " validatedFontId : %d\n", validatedFontId );
1056 // Add the path to the cache.
1057 description.type = FontDescription::FACE_FONT;
1058 mFontDescriptionCache.push_back( description );
1060 // The reference counter of the character set has already been increased in MatchFontDescriptionToPattern.
1061 mCharacterSetCache.PushBack( characterSet );
1063 // Cache the index and the matched font's description.
1064 FontDescriptionCacheItem item( description,
1067 mValidatedFontCache.push_back( std::move( item ) );
1069 if( ( fontDescription.family != description.family ) ||
1070 ( fontDescription.width != description.width ) ||
1071 ( fontDescription.weight != description.weight ) ||
1072 ( fontDescription.slant != description.slant ) )
1074 // Cache the given font's description if it's different than the matched.
1075 FontDescriptionCacheItem item( fontDescription,
1078 mValidatedFontCache.push_back( std::move( item ) );
1083 DALI_LOG_INFO( gLogFilter, Debug::General, " font validation failed for font [%s]\n", fontDescription.family.c_str() );
1086 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::ValidateFont\n" );
1089 void FontClient::Plugin::GetFontMetrics( FontId fontId,
1090 FontMetrics& metrics )
1092 const FontId index = fontId - 1u;
1094 if( ( fontId > 0 ) &&
1095 ( index < mFontIdCache.Count() ) )
1097 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1099 switch( fontIdCacheItem.type )
1101 case FontDescription::FACE_FONT:
1103 const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
1105 metrics = font.mMetrics;
1107 // Adjust the metrics if the fixed-size font should be down-scaled
1108 if( font.mIsFixedSizeBitmap )
1110 const float desiredFixedSize = static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
1112 if( desiredFixedSize > 0.f )
1114 const float scaleFactor = desiredFixedSize / font.mFixedHeightPixels;
1116 metrics.ascender = metrics.ascender * scaleFactor;
1117 metrics.descender = metrics.descender * scaleFactor;
1118 metrics.height = metrics.height * scaleFactor;
1119 metrics.underlinePosition = metrics.underlinePosition * scaleFactor;
1120 metrics.underlineThickness = metrics.underlineThickness * scaleFactor;
1125 case FontDescription::BITMAP_FONT:
1127 const BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
1129 metrics.ascender = bitmapFontCacheItem.font.ascender;
1130 metrics.descender = bitmapFontCacheItem.font.descender;
1131 metrics.height = metrics.ascender - metrics.descender;
1132 metrics.underlinePosition = bitmapFontCacheItem.font.underlinePosition;
1133 metrics.underlineThickness = bitmapFontCacheItem.font.underlineThickness;
1138 DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
1144 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId );
1148 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
1149 Character charcode )
1151 GlyphIndex glyphIndex = 0u;
1152 const FontId index = fontId - 1u;
1154 if( ( fontId > 0u ) &&
1155 ( index < mFontIdCache.Count() ) )
1157 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1159 if( FontDescription::FACE_FONT == fontIdCacheItem.type )
1161 FT_Face ftFace = mFontFaceCache[fontIdCacheItem.id].mFreeTypeFace;
1163 glyphIndex = FT_Get_Char_Index( ftFace, charcode );
1170 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
1175 if( VECTOR_GLYPH == type )
1177 return GetVectorMetrics( array, size, horizontal );
1180 return GetBitmapMetrics( array, size, horizontal );
1183 bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array,
1187 bool success( true );
1189 for( unsigned int i=0; i<size; ++i )
1191 GlyphInfo& glyph = array[i];
1193 FontId index = glyph.fontId - 1u;
1195 if( ( glyph.fontId > 0u ) &&
1196 ( index < mFontIdCache.Count() ) )
1198 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1200 switch( fontIdCacheItem.type )
1202 case FontDescription::FACE_FONT:
1204 const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
1206 FT_Face ftFace = font.mFreeTypeFace;
1208 #ifdef FREETYPE_BITMAP_SUPPORT
1209 // Check to see if we should be loading a Fixed Size bitmap?
1210 if( font.mIsFixedSizeBitmap )
1212 FT_Select_Size( ftFace, font.mFixedSizeIndex ); ///< @todo: needs to be investigated why it's needed to select the size again.
1213 int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_COLOR );
1214 if ( FT_Err_Ok == error )
1216 glyph.width = font.mFixedWidthPixels;
1217 glyph.height = font.mFixedHeightPixels;
1218 glyph.advance = font.mFixedWidthPixels;
1219 glyph.xBearing = 0.0f;
1220 glyph.yBearing = font.mFixedHeightPixels;
1222 // Adjust the metrics if the fixed-size font should be down-scaled
1223 const float desiredFixedSize = static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
1225 if( desiredFixedSize > 0.f )
1227 const float scaleFactor = desiredFixedSize / font.mFixedHeightPixels;
1229 glyph.width = glyph.width * scaleFactor ;
1230 glyph.height = glyph.height * scaleFactor;
1231 glyph.advance = glyph.advance * scaleFactor;
1232 glyph.xBearing = glyph.xBearing * scaleFactor;
1233 glyph.yBearing = glyph.yBearing * scaleFactor;
1235 glyph.scaleFactor = scaleFactor;
1240 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetBitmapMetrics. FreeType Bitmap Load_Glyph error %d\n", error );
1247 int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_NO_AUTOHINT );
1249 if( FT_Err_Ok == error )
1251 glyph.width = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
1252 glyph.height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
1255 glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
1256 glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
1260 glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
1261 glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
1271 case FontDescription::BITMAP_FONT:
1273 BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
1275 unsigned int index = 0u;
1276 for( auto& item : bitmapFontCacheItem.font.glyphs )
1278 if( item.utf32 == glyph.index )
1280 Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
1283 pixelBuffer = LoadImageFromFile( item.url );
1286 glyph.width = static_cast< float >( pixelBuffer.GetWidth() );
1287 glyph.height = static_cast< float >( pixelBuffer.GetHeight() );
1288 glyph.xBearing = 0.f;
1289 glyph.yBearing = glyph.height + item.descender;
1290 glyph.advance = glyph.width;
1291 glyph.scaleFactor = 1.f;
1302 DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
1308 // Check if it's an embedded image.
1309 if( ( 0u == glyph.fontId ) && ( 0u != glyph.index ) && ( glyph.index <= mEmbeddedItemCache.Count() ) )
1311 const EmbeddedItem& item = mEmbeddedItemCache[glyph.index - 1u];
1313 glyph.width = static_cast<float>( item.width );
1314 glyph.height = static_cast<float>( item.height );
1315 glyph.xBearing = 0.f;
1316 glyph.yBearing = glyph.height;
1317 glyph.advance = glyph.width;
1318 glyph.scaleFactor = 1.f;
1330 bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array,
1334 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
1335 bool success( true );
1337 for( unsigned int i = 0u; i < size; ++i )
1339 FontId fontId = array[i].fontId;
1341 if( ( fontId > 0u ) &&
1342 ( fontId - 1u ) < mFontIdCache.Count() )
1344 FontFaceCacheItem& font = mFontFaceCache[mFontIdCache[fontId - 1u].id];
1346 if( ! font.mVectorFontId )
1348 font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
1351 mVectorFontCache->GetGlyphMetrics( font.mVectorFontId, array[i] );
1353 // Vector metrics are in EMs, convert to pixels
1354 const float scale = ( static_cast<float>( font.mRequestedPointSize ) * FROM_266 ) * static_cast<float>( mDpiVertical ) / POINTS_PER_INCH;
1355 array[i].width *= scale;
1356 array[i].height *= scale;
1357 array[i].xBearing *= scale;
1358 array[i].yBearing *= scale;
1359 array[i].advance *= scale;
1373 void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
1375 const FontId index = fontId - 1u;
1377 if( ( fontId > 0u ) &&
1378 ( index < mFontIdCache.Count() ) )
1380 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1382 switch( fontIdCacheItem.type )
1384 case FontDescription::FACE_FONT:
1386 // For the software italics.
1387 bool isShearRequired = false;
1389 const FontFaceCacheItem& fontFaceCacheItem = mFontFaceCache[fontIdCacheItem.id];
1390 FT_Face ftFace = fontFaceCacheItem.mFreeTypeFace;
1394 #ifdef FREETYPE_BITMAP_SUPPORT
1395 // Check to see if this is fixed size bitmap
1396 if( fontFaceCacheItem.mIsFixedSizeBitmap )
1398 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1403 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_NO_AUTOHINT );
1405 if( FT_Err_Ok == error )
1407 if( isBoldRequired && !( ftFace->style_flags & FT_STYLE_FLAG_BOLD ) )
1409 // Does the software bold.
1410 FT_GlyphSlot_Embolden( ftFace->glyph );
1413 if( isItalicRequired && !( ftFace->style_flags & FT_STYLE_FLAG_ITALIC ) )
1415 // Will do the software italic.
1416 isShearRequired = true;
1420 error = FT_Get_Glyph( ftFace->glyph, &glyph );
1422 // Convert to bitmap if necessary
1423 if ( FT_Err_Ok == error )
1425 if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
1427 // Check whether we should create a bitmap for the outline
1428 if( glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0 )
1432 error = FT_Stroker_New( mFreeTypeLibrary, &stroker );
1434 if( FT_Err_Ok == error )
1436 FT_Stroker_Set( stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 );
1437 error = FT_Glyph_StrokeBorder( &glyph, stroker, 0, 1 );
1439 if( FT_Err_Ok == error )
1441 FT_Stroker_Done( stroker );
1445 DALI_LOG_ERROR( "FT_Glyph_StrokeBorder Failed with error: %d\n", error );
1450 DALI_LOG_ERROR( "FT_Stroker_New Failed with error: %d\n", error );
1454 error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
1455 if( FT_Err_Ok == error )
1457 FT_BitmapGlyph bitmapGlyph = reinterpret_cast< FT_BitmapGlyph >( glyph );
1458 ConvertBitmap( data, bitmapGlyph->bitmap, isShearRequired );
1462 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Get_Glyph Failed with error: %d\n", error );
1467 ConvertBitmap( data, ftFace->glyph->bitmap, isShearRequired );
1470 // Created FT_Glyph object must be released with FT_Done_Glyph
1471 FT_Done_Glyph( glyph );
1476 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Load_Glyph Failed with error: %d\n", error );
1480 case FontDescription::BITMAP_FONT:
1482 BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
1484 unsigned int index = 0u;
1485 for( auto& item : bitmapFontCacheItem.font.glyphs )
1487 if( item.utf32 == glyphIndex )
1489 Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
1492 pixelBuffer = LoadImageFromFile( item.url );
1495 data.width = pixelBuffer.GetWidth();
1496 data.height = pixelBuffer.GetHeight();
1498 ConvertBitmap( data, data.width, data.height, pixelBuffer.GetBuffer() );
1500 // Sets the pixel format.
1501 data.format = pixelBuffer.GetPixelFormat();
1510 DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
1516 if( ( 0u != glyphIndex ) && ( glyphIndex <= mEmbeddedItemCache.Count() ) )
1518 // It's an embedded item.
1519 const EmbeddedItem& item = mEmbeddedItemCache[glyphIndex - 1u];
1521 data.width = item.width;
1522 data.height = item.height;
1523 if( 0u != item.pixelBufferId )
1525 Devel::PixelBuffer pixelBuffer = mPixelBufferCache[item.pixelBufferId-1u].pixelBuffer;
1528 ConvertBitmap( data, pixelBuffer.GetWidth(), pixelBuffer.GetHeight(), pixelBuffer.GetBuffer() );
1530 // Sets the pixel format.
1531 data.format = pixelBuffer.GetPixelFormat();
1536 // Creates the output buffer
1537 const unsigned int bufferSize = data.width * data.height * 4u;
1538 data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1540 memset( data.buffer, 0u, bufferSize );
1542 // Just creates a void buffer. Doesn't matter what pixel format is set as is the application code the responsible of filling it.
1548 PixelData FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
1550 TextAbstraction::FontClient::GlyphBufferData data;
1552 CreateBitmap( fontId, glyphIndex, false, false, data, outlineWidth );
1554 return PixelData::New( data.buffer,
1555 data.width * data.height * Pixel::GetBytesPerPixel( data.format ),
1559 PixelData::DELETE_ARRAY );
1562 void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
1567 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
1568 if( ( fontId > 0u ) &&
1569 ( fontId - 1u < mFontIdCache.Count() ) )
1571 const FontId fontFaceId = mFontIdCache[fontId - 1u].id;
1572 FontFaceCacheItem& font = mFontFaceCache[fontFaceId];
1574 if( ! font.mVectorFontId )
1576 font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
1579 mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontFaceId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
1584 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
1586 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetEllipsisGlyph\n" );
1587 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize %d.\n", requestedPointSize );
1589 // First look into the cache if there is an ellipsis glyph for the requested point size.
1590 for( const auto& item : mEllipsisCache )
1592 if( item.requestedPointSize != requestedPointSize )
1594 // Use the glyph in the cache.
1596 DALI_LOG_INFO( gLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index );
1597 DALI_LOG_INFO( gLogFilter, Debug::General, " font %d.\n", item.glyph.fontId );
1598 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
1604 // No glyph has been found. Create one.
1605 mEllipsisCache.PushBack( EllipsisItem() );
1606 EllipsisItem& item = *( mEllipsisCache.End() - 1u );
1608 item.requestedPointSize = requestedPointSize;
1610 // Find a font for the ellipsis glyph.
1611 item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
1615 // Set the character index to access the glyph inside the font.
1616 item.glyph.index = FT_Get_Char_Index( mFontFaceCache[mFontIdCache[item.glyph.fontId-1u].id].mFreeTypeFace,
1617 ELLIPSIS_CHARACTER );
1619 GetBitmapMetrics( &item.glyph, 1u, true );
1621 DALI_LOG_INFO( gLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index );
1622 DALI_LOG_INFO( gLogFilter, Debug::General, " font %d.\n", item.glyph.fontId );
1623 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
1628 bool FontClient::Plugin::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
1630 FT_Error error = -1;
1632 const FontId index = fontId - 1u;
1634 #ifdef FREETYPE_BITMAP_SUPPORT
1635 if( ( fontId > 0u ) &&
1636 ( index < mFontIdCache.Count() ) )
1638 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1640 switch( fontIdCacheItem.type )
1642 case FontDescription::FACE_FONT:
1644 const FontFaceCacheItem& item = mFontFaceCache[fontIdCacheItem.id];
1645 FT_Face ftFace = item.mFreeTypeFace;
1647 // Check to see if this is fixed size bitmap
1648 if( item.mHasColorTables )
1650 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1654 case FontDescription::BITMAP_FONT:
1656 error = FT_Err_Ok; // Will return true;
1661 DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
1667 return FT_Err_Ok == error;
1670 FT_FaceRec_* FontClient::Plugin::GetFreetypeFace( FontId fontId )
1672 FT_Face fontFace = nullptr;
1674 const FontId index = fontId - 1u;
1675 if( ( fontId > 0u ) &&
1676 ( index < mFontIdCache.Count() ) )
1678 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1680 if( FontDescription::FACE_FONT == fontIdCacheItem.type )
1682 fontFace = mFontFaceCache[fontIdCacheItem.id].mFreeTypeFace;
1688 FontDescription::Type FontClient::Plugin::GetFontType( FontId fontId )
1690 const FontId index = fontId - 1u;
1691 if( ( fontId > 0u ) &&
1692 ( index < mFontIdCache.Count() ) )
1694 return mFontIdCache[index].type;
1696 return FontDescription::INVALID;
1699 bool FontClient::Plugin::AddCustomFontDirectory( const FontPath& path )
1701 // nullptr as first parameter means the current configuration is used.
1702 return FcConfigAppFontAddDir( nullptr, reinterpret_cast<const FcChar8 *>( path.c_str() ) );
1705 GlyphIndex FontClient::Plugin::CreateEmbeddedItem( const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat )
1707 EmbeddedItem embeddedItem;
1709 embeddedItem.pixelBufferId = 0u;
1710 embeddedItem.width = description.width;
1711 embeddedItem.height = description.height;
1713 pixelFormat = Pixel::A8;
1715 if( !description.url.empty() )
1717 // Check if the url is in the cache.
1718 PixelBufferId index = 0u;
1720 for( const auto& cacheItem : mPixelBufferCache )
1723 if( cacheItem.url == description.url )
1725 // The url is in the pixel buffer cache.
1726 // Set the index +1 to the vector.
1727 embeddedItem.pixelBufferId = index;
1732 Devel::PixelBuffer pixelBuffer;
1733 if( 0u == embeddedItem.pixelBufferId )
1735 // The pixel buffer is not in the cache. Create one and cache it.
1737 // Load the image from the url.
1738 pixelBuffer = LoadImageFromFile( description.url );
1740 // Create the cache item.
1741 PixelBufferCacheItem pixelBufferCacheItem;
1742 pixelBufferCacheItem.pixelBuffer = pixelBuffer;
1743 pixelBufferCacheItem.url = description.url;
1745 // Store the cache item in the cache.
1746 mPixelBufferCache.push_back( std::move( pixelBufferCacheItem ) );
1748 // Set the pixel buffer id to the embedded item.
1749 embeddedItem.pixelBufferId = mPixelBufferCache.size();
1753 // Retrieve the pixel buffer from the cache to set the pixel format.
1754 pixelBuffer = mPixelBufferCache[embeddedItem.pixelBufferId-1u].pixelBuffer;
1759 // Set the size of the embedded item if it has not been set.
1760 if( 0u == embeddedItem.width )
1762 embeddedItem.width = static_cast<unsigned int>( pixelBuffer.GetWidth() );
1765 if( 0u == embeddedItem.height )
1767 embeddedItem.height = static_cast<unsigned int>( pixelBuffer.GetHeight() );
1770 // Set the pixel format.
1771 pixelFormat = pixelBuffer.GetPixelFormat();
1775 // Find if the same embeddedItem has already been created.
1776 unsigned int index = 0u;
1777 for( const auto& item : mEmbeddedItemCache )
1780 if( ( item.pixelBufferId == embeddedItem.pixelBufferId ) &&
1781 ( item.width == embeddedItem.width ) &&
1782 ( item.height == embeddedItem.height ) )
1788 // Cache the embedded item.
1789 mEmbeddedItemCache.PushBack( embeddedItem );
1791 return mEmbeddedItemCache.Count();
1794 void FontClient::Plugin::InitSystemFonts()
1796 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::InitSystemFonts\n" );
1798 FcFontSet* fontSet = GetFcFontSet(); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
1802 DALI_LOG_INFO( gLogFilter, Debug::General, " number of system fonts : %d\n", fontSet->nfont );
1804 // Reserve some space to avoid reallocations.
1805 mSystemFonts.reserve( fontSet->nfont );
1807 for( int i = 0u; i < fontSet->nfont; ++i )
1809 FcPattern* fontPattern = fontSet->fonts[i];
1813 // Skip fonts with no path
1814 if( GetFcString( fontPattern, FC_FILE, path ) )
1816 mSystemFonts.push_back( FontDescription() );
1817 FontDescription& fontDescription = mSystemFonts.back();
1819 fontDescription.path = std::move( path );
1824 GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
1825 GetFcInt( fontPattern, FC_WIDTH, width );
1826 GetFcInt( fontPattern, FC_WEIGHT, weight );
1827 GetFcInt( fontPattern, FC_SLANT, slant );
1828 fontDescription.width = IntToWidthType( width );
1829 fontDescription.weight = IntToWeightType( weight );
1830 fontDescription.slant = IntToSlantType( slant );
1832 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", fontDescription.family.c_str() );
1833 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1834 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1835 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1836 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1840 // Destroys the font set created.
1841 FcFontSetDestroy( fontSet );
1843 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::InitSystemFonts\n" );
1846 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet )
1848 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1850 FcResult result = FcResultMatch;
1851 FcPattern* match = FcFontMatch( nullptr /* use default configure */, pattern, &result ); // Creates a new font pattern that needs to be destroyed by calling FcPatternDestroy.
1853 const bool matched = nullptr != match;
1854 DALI_LOG_INFO( gLogFilter, Debug::General, " pattern matched : %s\n", ( matched ? "true" : "false" ) );
1861 GetFcString( match, FC_FILE, fontDescription.path );
1862 GetFcString( match, FC_FAMILY, fontDescription.family );
1863 GetFcInt( match, FC_WIDTH, width );
1864 GetFcInt( match, FC_WEIGHT, weight );
1865 GetFcInt( match, FC_SLANT, slant );
1866 fontDescription.width = IntToWidthType( width );
1867 fontDescription.weight = IntToWeightType( weight );
1868 fontDescription.slant = IntToSlantType( slant );
1870 // Retrieve the character set and increase the reference counter.
1871 FcPatternGetCharSet( match, FC_CHARSET, 0u, characterSet );
1872 *characterSet = FcCharSetCopy( *characterSet );
1874 // destroyed the matched pattern
1875 FcPatternDestroy( match );
1877 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
1878 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1879 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1880 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1881 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1884 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1888 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription ) const
1890 // create the cached font family lookup pattern
1891 // a pattern holds a set of names, each name refers to a property of the font
1892 FcPattern* fontFamilyPattern = FcPatternCreate(); // FcPatternCreate creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
1894 if( !fontFamilyPattern )
1899 // add a property to the pattern for the font family
1900 FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
1902 // add a property to the pattern for local setting.
1903 const char* locale = setlocale( LC_MESSAGES, nullptr );
1904 if( locale != nullptr)
1906 FcPatternAddString( fontFamilyPattern, FC_LANG, reinterpret_cast<const FcChar8*>( locale ) );
1909 int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
1913 width = DEFAULT_FONT_WIDTH;
1916 int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
1920 weight = DEFAULT_FONT_WEIGHT;
1923 int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
1927 slant = DEFAULT_FONT_SLANT;
1930 FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
1931 FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
1932 FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
1934 // Add a property of the pattern, to say we want to match TrueType fonts
1935 FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
1937 // modify the config, with the mFontFamilyPatterm
1938 FcConfigSubstitute( nullptr /* use default configure */, fontFamilyPattern, FcMatchPattern );
1940 // provide default values for unspecified properties in the font pattern
1941 // e.g. patterns without a specified style or weight are set to Medium
1942 FcDefaultSubstitute( fontFamilyPattern );
1944 return fontFamilyPattern;
1947 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
1949 FcFontSet* fontset = nullptr;
1951 // create a new pattern.
1952 // a pattern holds a set of names, each name refers to a property of the font
1953 FcPattern* pattern = FcPatternCreate();
1955 if( nullptr != pattern )
1957 // create an object set used to define which properties are to be returned in the patterns from FcFontList.
1958 FcObjectSet* objectSet = FcObjectSetCreate();
1960 if( nullptr != objectSet )
1962 // build an object set from a list of property names
1963 FcObjectSetAdd( objectSet, FC_FILE );
1964 FcObjectSetAdd( objectSet, FC_FAMILY );
1965 FcObjectSetAdd( objectSet, FC_WIDTH );
1966 FcObjectSetAdd( objectSet, FC_WEIGHT );
1967 FcObjectSetAdd( objectSet, FC_SLANT );
1969 // get a list of fonts
1970 // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1971 fontset = FcFontList( nullptr /* the default configuration is checked to be up to date, and used */, pattern, objectSet ); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
1973 // clear up the object set
1974 FcObjectSetDestroy( objectSet );
1977 // clear up the pattern
1978 FcPatternDestroy( pattern );
1984 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1985 const char* const n,
1986 std::string& string )
1988 FcChar8* file = nullptr;
1989 const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1991 if( FcResultMatch == retVal )
1993 // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1994 string.assign( reinterpret_cast<const char*>( file ) );
2002 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
2004 const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
2006 if( FcResultMatch == retVal )
2014 FontId FontClient::Plugin::CreateFont( const FontPath& path,
2015 PointSize26Dot6 requestedPointSize,
2016 FaceIndex faceIndex,
2017 bool cacheDescription )
2019 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::CreateFont\n" );
2020 DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() );
2021 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
2025 // Create & cache new font face
2027 int error = FT_New_Face( mFreeTypeLibrary,
2032 if( FT_Err_Ok == error )
2034 // Check if a font is scalable.
2035 const bool isScalable = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_SCALABLE ) );
2036 const bool hasFixedSizedBitmaps = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) && ( 0 != ftFace->num_fixed_sizes );
2037 const bool hasColorTables = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_COLOR ) );
2038 FontId fontFaceId = 0u;
2040 DALI_LOG_INFO( gLogFilter, Debug::General, " isScalable : [%s]\n", ( isScalable ? "true" : "false" ) );
2041 DALI_LOG_INFO( gLogFilter, Debug::General, " hasFixedSizedBitmaps : [%s]\n", ( hasFixedSizedBitmaps ? "true" : "false" ) );
2042 DALI_LOG_INFO( gLogFilter, Debug::General, " hasColorTables : [%s]\n", ( hasColorTables ? "true" : "false" ) );
2044 // Check to see if the font contains fixed sizes?
2045 if( !isScalable && hasFixedSizedBitmaps )
2047 PointSize26Dot6 actualPointSize = 0u;
2048 int fixedSizeIndex = 0;
2049 for( ; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex )
2051 const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
2052 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " size index : %d, size : %d\n", fixedSizeIndex, fixedSize );
2054 if( fixedSize >= requestedPointSize )
2056 actualPointSize = fixedSize;
2061 if( 0u == actualPointSize )
2063 // The requested point size is bigger than the bigest fixed size.
2064 fixedSizeIndex = ftFace->num_fixed_sizes - 1;
2065 actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
2068 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize );
2070 // Tell Freetype to use this size
2071 error = FT_Select_Size( ftFace, fixedSizeIndex );
2072 if ( FT_Err_Ok != error )
2074 DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Select_Size error: %d\n", error );
2078 const float fixedWidth = static_cast<float>( ftFace->available_sizes[ fixedSizeIndex ].width );
2079 const float fixedHeight = static_cast<float>( ftFace->available_sizes[ fixedSizeIndex ].height );
2081 // Indicate that the font is a fixed sized bitmap
2082 FontMetrics metrics( fixedHeight, // The ascender in pixels.
2084 fixedHeight, // The height in pixels.
2088 // Create the FreeType font face item to cache.
2089 FontFaceCacheItem fontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedSizeIndex, fixedWidth, fixedHeight, hasColorTables );
2091 // Set the index to the font's id cache.
2092 fontFaceCacheItem.mFontId = mFontIdCache.Count();
2094 // Create the font id item to cache.
2095 FontIdCacheItem fontIdCacheItem;
2096 fontIdCacheItem.type = FontDescription::FACE_FONT;
2098 // Set the index to the FreeType font face cache.
2099 fontIdCacheItem.id = mFontFaceCache.size();
2100 fontFaceId = fontIdCacheItem.id + 1u;
2103 mFontFaceCache.push_back( fontFaceCacheItem );
2104 mFontIdCache.PushBack( fontIdCacheItem );
2106 // Set the font id to be returned.
2107 id = mFontIdCache.Count();
2112 error = FT_Set_Char_Size( ftFace,
2118 if( FT_Err_Ok == error )
2121 FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
2123 FontMetrics metrics( static_cast< float >( ftMetrics.ascender ) * FROM_266,
2124 static_cast< float >( ftMetrics.descender ) * FROM_266,
2125 static_cast< float >( ftMetrics.height ) * FROM_266,
2126 static_cast< float >( ftFace->underline_position ) * FROM_266,
2127 static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
2129 // Create the FreeType font face item to cache.
2130 FontFaceCacheItem fontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics );
2132 // Set the index to the font's id cache.
2133 fontFaceCacheItem.mFontId = mFontIdCache.Count();
2135 // Create the font id item to cache.
2136 FontIdCacheItem fontIdCacheItem;
2137 fontIdCacheItem.type = FontDescription::FACE_FONT;
2139 // Set the index to the FreeType font face cache.
2140 fontIdCacheItem.id = mFontFaceCache.size();
2141 fontFaceId = fontIdCacheItem.id + 1u;
2144 mFontFaceCache.push_back( fontFaceCacheItem );
2145 mFontIdCache.PushBack( fontIdCacheItem );
2147 // Set the font id to be returned.
2148 id = mFontIdCache.Count();
2152 DALI_LOG_INFO( gLogFilter, Debug::General, " FreeType Set_Char_Size error: %d for pointSize %d\n", error, requestedPointSize );
2156 if( 0u != fontFaceId )
2158 if( cacheDescription )
2160 CacheFontPath( ftFace, fontFaceId, requestedPointSize, path );
2166 DALI_LOG_INFO( gLogFilter, Debug::General, " FreeType New_Face error: %d for [%s]\n", error, path.c_str() );
2169 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
2170 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::CreateFont\n" );
2175 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, unsigned int srcWidth, unsigned int srcHeight, const unsigned char* const srcBuffer )
2177 // Set the input dimensions.
2178 const ImageDimensions inputDimensions( srcWidth, srcHeight );
2180 // Set the output dimensions.
2181 // If the output dimension is not given, the input dimension is set
2182 // and won't be downscaling.
2183 data.width = ( data.width == 0 ) ? srcWidth : data.width;
2184 data.height = ( data.height == 0 ) ? srcHeight : data.height;
2185 const ImageDimensions desiredDimensions( data.width, data.height );
2187 // Creates the output buffer
2188 const unsigned int bufferSize = data.width * data.height * 4u;
2189 data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
2191 if( inputDimensions == desiredDimensions )
2193 // There isn't downscaling.
2194 memcpy( data.buffer, srcBuffer, bufferSize );
2198 Dali::Internal::Platform::LanczosSample4BPP( srcBuffer,
2201 desiredDimensions );
2205 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap, bool isShearRequired )
2207 if( srcBitmap.width*srcBitmap.rows > 0 )
2209 switch( srcBitmap.pixel_mode )
2211 case FT_PIXEL_MODE_GRAY:
2213 if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
2215 uint8_t* pixelsIn = srcBitmap.buffer;
2216 unsigned int width = srcBitmap.width;
2217 unsigned height = srcBitmap.rows;
2219 std::unique_ptr<uint8_t, void(*)(void*)> pixelsOutPtr( nullptr, free );
2221 if( isShearRequired )
2224 * Glyphs' bitmaps with no slant retrieved from FreeType:
2234 * Expected glyphs' bitmaps with italic slant:
2235 * ____________ ______
2242 * ------------ ------
2244 * Glyphs' bitmaps with software italic slant retrieved from FreeType:
2254 * This difference in some bitmaps' width causes an overlap of some glyphs. This is the reason why a shear operation is done here instead of relying on the experimental FT_GlyphSlot_Oblique() implementation.
2256 unsigned int widthOut = 0u;
2257 unsigned int heightOut = 0u;
2258 uint8_t* pixelsOut = nullptr;
2260 Dali::Internal::Platform::HorizontalShear( pixelsIn,
2264 -TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE,
2271 pixelsIn = pixelsOut;
2272 pixelsOutPtr.reset( pixelsOut );
2275 const unsigned int bufferSize = width * height;
2276 data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
2278 data.height = height;
2279 data.format = Pixel::L8; // Sets the pixel format.
2280 memcpy( data.buffer, pixelsIn, bufferSize );
2285 #ifdef FREETYPE_BITMAP_SUPPORT
2286 case FT_PIXEL_MODE_BGRA:
2288 if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
2290 ConvertBitmap( data, srcBitmap.width, srcBitmap.rows, srcBitmap.buffer );
2292 // Sets the pixel format.
2293 data.format = Pixel::BGRA8888;
2300 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::ConvertBitmap. FontClient Unable to create Bitmap of this PixelType\n" );
2307 bool FontClient::Plugin::FindFont( const FontPath& path,
2308 PointSize26Dot6 requestedPointSize,
2309 FaceIndex faceIndex,
2310 FontId& fontId ) const
2312 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
2313 DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() );
2314 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
2315 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of fonts in the cache : %d\n", mFontFaceCache.size() );
2318 for( const auto& cacheItem : mFontFaceCache )
2320 if( cacheItem.mRequestedPointSize == requestedPointSize &&
2321 cacheItem.mFaceIndex == faceIndex &&
2322 cacheItem.mPath == path )
2324 fontId = cacheItem.mFontId + 1u;
2326 DALI_LOG_INFO( gLogFilter, Debug::General, " font found, id : %d\n", fontId );
2327 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
2333 DALI_LOG_INFO( gLogFilter, Debug::General, " font not found\n" );
2334 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
2339 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
2340 FontDescriptionId& validatedFontId )
2342 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindValidatedFont\n" );
2343 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
2344 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
2345 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
2346 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
2347 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
2348 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of validated fonts in the cache : %d\n", mValidatedFontCache.size() );
2350 validatedFontId = 0u;
2352 for( const auto& item : mValidatedFontCache )
2354 if( !fontDescription.family.empty() &&
2355 ( fontDescription.family == item.fontDescription.family ) &&
2356 ( fontDescription.width == item.fontDescription.width ) &&
2357 ( fontDescription.weight == item.fontDescription.weight ) &&
2358 ( fontDescription.slant == item.fontDescription.slant ) )
2360 validatedFontId = item.index;
2362 DALI_LOG_INFO( gLogFilter, Debug::General, " validated font found, id : %d\n", validatedFontId );
2363 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
2368 DALI_LOG_INFO( gLogFilter, Debug::General, " validated font not found\n" );
2369 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
2373 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
2374 FontList*& fontList,
2375 CharacterSetList*& characterSetList )
2377 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFontList\n" );
2378 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
2379 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
2380 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
2381 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
2382 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
2383 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of fallback font lists in the cache : %d\n", mFallbackCache.size() );
2387 for( const auto& item : mFallbackCache )
2389 if( !fontDescription.family.empty() &&
2390 ( fontDescription.family == item.fontDescription.family ) &&
2391 ( fontDescription.width == item.fontDescription.width ) &&
2392 ( fontDescription.weight == item.fontDescription.weight ) &&
2393 ( fontDescription.slant == item.fontDescription.slant ) )
2395 fontList = item.fallbackFonts;
2396 characterSetList = item.characterSets;
2398 DALI_LOG_INFO( gLogFilter, Debug::General, " fallback font list found.\n" );
2399 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
2404 DALI_LOG_INFO( gLogFilter, Debug::General, " fallback font list not found.\n" );
2405 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
2409 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
2410 PointSize26Dot6 requestedPointSize,
2413 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
2414 DALI_LOG_INFO( gLogFilter, Debug::General, " validatedFontId : %d\n", validatedFontId );
2415 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
2419 for( const auto& item : mFontDescriptionSizeCache )
2421 if( ( validatedFontId == item.validatedFontId ) &&
2422 ( requestedPointSize == item.requestedPointSize ) )
2424 fontId = item.fontId;
2426 DALI_LOG_INFO( gLogFilter, Debug::General, " font found, id : %d\n", fontId );
2427 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
2432 DALI_LOG_INFO( gLogFilter, Debug::General, " font not found.\n" );
2433 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
2437 bool FontClient::Plugin::FindBitmapFont( const FontFamily& bitmapFont, FontId& fontId ) const
2441 for( const auto& item : mBitmapFontCache )
2443 if( bitmapFont == item.font.name )
2445 fontId = item.id + 1u;
2453 bool FontClient::Plugin::IsScalable( const FontPath& path )
2455 bool isScalable = false;
2458 int error = FT_New_Face( mFreeTypeLibrary,
2462 if( FT_Err_Ok != error )
2464 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: %s\n", path.c_str() );
2468 isScalable = ftFace->face_flags & FT_FACE_FLAG_SCALABLE;
2474 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
2476 // Create a font pattern.
2477 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription ); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
2479 FcResult result = FcResultMatch;
2481 // match the pattern
2482 FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result ); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
2483 bool isScalable = false;
2487 // Get the path to the font file name.
2489 GetFcString( match, FC_FILE, path );
2490 isScalable = IsScalable( path );
2494 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
2497 // Destroys the created patterns.
2498 FcPatternDestroy( match );
2499 FcPatternDestroy( fontFamilyPattern );
2504 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
2506 // Empty the caller container
2510 int error = FT_New_Face( mFreeTypeLibrary,
2514 if( FT_Err_Ok != error )
2516 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font path : [%s]\n", path.c_str() );
2519 // Fetch the number of fixed sizes available
2520 if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
2522 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
2524 sizes.PushBack( ftFace->available_sizes[ i ].size );
2529 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
2530 Vector< PointSize26Dot6 >& sizes )
2532 // Create a font pattern.
2533 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription ); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
2535 FcResult result = FcResultMatch;
2537 // match the pattern
2538 FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result ); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
2542 // Get the path to the font file name.
2544 GetFcString( match, FC_FILE, path );
2545 GetFixedSizes( path, sizes );
2549 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
2552 // Destroys the created patterns.
2553 FcPatternDestroy( match );
2554 FcPatternDestroy( fontFamilyPattern );
2557 bool FontClient::Plugin::HasItalicStyle( FontId fontId ) const
2559 bool hasItalicStyle = false;
2561 const FontId index = fontId - 1u;
2563 if( ( fontId > 0 ) &&
2564 ( index < mFontIdCache.Count() ) )
2566 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
2568 if( FontDescription::FACE_FONT == fontIdCacheItem.type )
2570 const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
2572 hasItalicStyle = 0u != ( font.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC );
2577 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId );
2580 return hasItalicStyle;
2583 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize, const FontPath& path )
2585 FontDescription description;
2586 description.path = path;
2587 description.family = std::move( FontFamily( ftFace->family_name ) );
2588 description.weight = FontWeight::NONE;
2589 description.width = FontWidth::NONE;
2590 description.slant = FontSlant::NONE;
2592 // Note FreeType doesn't give too much info to build a proper font style.
2593 if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
2595 description.slant = FontSlant::ITALIC;
2597 if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
2599 description.weight = FontWeight::BOLD;
2602 FontDescriptionId validatedFontId = 0u;
2603 if( !FindValidatedFont( description,
2606 // Set the index to the vector of paths to font file names.
2607 validatedFontId = mFontDescriptionCache.size();
2609 FcPattern* pattern = CreateFontFamilyPattern( description ); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
2611 FcResult result = FcResultMatch;
2612 FcPattern* match = FcFontMatch( nullptr, pattern, &result ); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
2614 FcCharSet* characterSet = nullptr;
2615 FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
2617 const FontId fontFaceId = id - 1u;
2618 mFontFaceCache[fontFaceId].mCharacterSet = FcCharSetCopy( characterSet ); // Increases the reference counter.
2620 // Destroys the created patterns.
2621 FcPatternDestroy( match );
2622 FcPatternDestroy( pattern );
2624 // Add the path to the cache.
2625 description.type = FontDescription::FACE_FONT;
2626 mFontDescriptionCache.push_back( description );
2628 // Increase the reference counter and add the character set to the cache.
2629 mCharacterSetCache.PushBack( FcCharSetCopy( characterSet ) );
2631 // Cache the index and the font's description.
2632 mValidatedFontCache.push_back( std::move( FontDescriptionCacheItem( std::move( description ),
2633 validatedFontId) ) );
2635 // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
2636 mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
2642 FcCharSet* FontClient::Plugin::CreateCharacterSetFromDescription( const FontDescription& description )
2644 FcCharSet* characterSet = nullptr;
2646 FcPattern* pattern = CreateFontFamilyPattern( description ); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
2648 if( nullptr != pattern )
2650 FcResult result = FcResultMatch;
2651 FcPattern* match = FcFontMatch( nullptr, pattern, &result ); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
2653 FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
2655 // Destroys the created patterns.
2656 FcPatternDestroy( match );
2657 FcPatternDestroy( pattern );
2660 return characterSet;
2663 void FontClient::Plugin::ClearFallbackCache( std::vector<FallbackCacheItem>& fallbackCache )
2665 for( auto& item : fallbackCache )
2667 if( nullptr != item.fallbackFonts )
2669 delete item.fallbackFonts;
2672 if( nullptr != item.characterSets )
2674 // Free the resources allocated by the FcCharSet objects in the 'characterSets' vector.
2675 DestroyCharacterSets( *item.characterSets );
2676 delete item.characterSets;
2681 void FontClient::Plugin::ClearCharacterSetFromFontFaceCache()
2683 for( auto& item : mFontFaceCache )
2685 FcCharSetDestroy( item.mCharacterSet );
2686 item.mCharacterSet = nullptr;
2690 } // namespace Internal
2692 } // namespace TextAbstraction