2 * Copyright (c) 2019 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 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 );
101 namespace TextAbstraction
108 * @brief Returns the FontWidth's enum index for the given width value.
110 * @param[in] width The width value.
112 * @return The FontWidth's enum index.
114 FontWidth::Type IntToWidthType( int width )
116 return static_cast<FontWidth::Type>( ValueToIndex( width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u ) );
120 * @brief Returns the FontWeight's enum index for the given weight value.
122 * @param[in] weight The weight value.
124 * @return The FontWeight's enum index.
126 FontWeight::Type IntToWeightType( int weight )
128 return static_cast<FontWeight::Type>( ValueToIndex( weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u ) );
132 * @brief Returns the FontSlant's enum index for the given slant value.
134 * @param[in] slant The slant value.
136 * @return The FontSlant's enum index.
138 FontSlant::Type IntToSlantType( int slant )
140 return static_cast<FontSlant::Type>( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) );
144 * @brief Free the resources allocated by the FcCharSet objects.
146 * @param[in] characterSets The vector of character sets.
148 void DestroyCharacterSets( CharacterSetList& characterSets )
150 for( auto& item : characterSets )
154 FcCharSetDestroy( item );
159 FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( FontDescription&& font, FontList* fallbackFonts, CharacterSetList* characterSets )
160 : fontDescription{ std::move( font ) },
161 fallbackFonts{ fallbackFonts },
162 characterSets{ characterSets }
166 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
167 FontDescriptionId index )
168 : fontDescription{ fontDescription },
173 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( FontDescription&& fontDescription,
174 FontDescriptionId index )
175 : fontDescription{ std::move( fontDescription ) },
180 FontClient::Plugin::FontDescriptionSizeCacheItem::FontDescriptionSizeCacheItem( FontDescriptionId validatedFontId,
181 PointSize26Dot6 requestedPointSize,
183 : validatedFontId( validatedFontId ),
184 requestedPointSize( requestedPointSize ),
189 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
190 const FontPath& path,
191 PointSize26Dot6 requestedPointSize,
193 const FontMetrics& metrics )
194 : mFreeTypeFace( ftFace ),
196 mRequestedPointSize( requestedPointSize ),
199 mCharacterSet( nullptr ),
200 mFixedSizeIndex( 0 ),
201 mFixedWidthPixels( 0.f ),
202 mFixedHeightPixels( 0.f ),
205 mIsFixedSizeBitmap( false ),
206 mHasColorTables( false )
210 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
211 const FontPath& path,
212 PointSize26Dot6 requestedPointSize,
214 const FontMetrics& metrics,
218 bool hasColorTables )
219 : mFreeTypeFace( ftFace ),
221 mRequestedPointSize( requestedPointSize ),
224 mCharacterSet( nullptr ),
225 mFixedSizeIndex( fixedSizeIndex ),
226 mFixedWidthPixels( fixedWidth ),
227 mFixedHeightPixels( fixedHeight ),
230 mIsFixedSizeBitmap( true ),
231 mHasColorTables( hasColorTables )
235 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
236 unsigned int verticalDpi )
237 : mFreeTypeLibrary( nullptr ),
238 mDpiHorizontal( horizontalDpi ),
239 mDpiVertical( verticalDpi ),
240 mDefaultFontDescription(),
245 mValidatedFontCache(),
246 mFontDescriptionCache(),
247 mCharacterSetCache(),
248 mFontDescriptionSizeCache(),
249 mVectorFontCache( nullptr ),
251 mEmbeddedItemCache(),
252 mDefaultFontDescriptionCached( false )
254 int error = FT_Init_FreeType( &mFreeTypeLibrary );
255 if( FT_Err_Ok != error )
257 DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Init error: %d\n", error );
260 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
261 mVectorFontCache = new VectorFontCache( mFreeTypeLibrary );
265 FontClient::Plugin::~Plugin()
267 ClearFallbackCache( mFallbackCache );
269 // Free the resources allocated by the FcCharSet objects.
270 DestroyCharacterSets( mDefaultFontCharacterSets );
271 DestroyCharacterSets( mCharacterSetCache );
272 ClearCharacterSetFromFontFaceCache();
274 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
275 delete mVectorFontCache;
277 FT_Done_FreeType( mFreeTypeLibrary );
280 void FontClient::Plugin::ClearCache()
282 mDefaultFontDescription = FontDescription();
284 mSystemFonts.clear();
285 mDefaultFonts.clear();
287 DestroyCharacterSets( mDefaultFontCharacterSets );
288 mDefaultFontCharacterSets.Clear();
290 ClearFallbackCache( mFallbackCache );
291 mFallbackCache.clear();
293 mFontIdCache.Clear();
295 ClearCharacterSetFromFontFaceCache();
296 mFontFaceCache.clear();
298 mValidatedFontCache.clear();
299 mFontDescriptionCache.clear();
301 DestroyCharacterSets( mCharacterSetCache );
302 mCharacterSetCache.Clear();
304 mFontDescriptionSizeCache.clear();
306 mEllipsisCache.Clear();
307 mPixelBufferCache.clear();
308 mEmbeddedItemCache.Clear();
309 mBitmapFontCache.clear();
311 mDefaultFontDescriptionCached = false;
314 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
315 unsigned int verticalDpi )
317 mDpiHorizontal = horizontalDpi;
318 mDpiVertical = verticalDpi;
321 void FontClient::Plugin::ResetSystemDefaults()
323 mDefaultFontDescriptionCached = false;
326 void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList )
328 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::SetFontList\n" );
329 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
330 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
331 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
332 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
336 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription ); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
338 FcResult result = FcResultMatch;
340 // Match the pattern.
341 FcFontSet* fontSet = FcFontSort( nullptr /* use default configure */,
343 false /* don't trim */,
345 &result ); // FcFontSort creates a font set that needs to be destroyed by calling FcFontSetDestroy.
347 if( nullptr != fontSet )
349 DALI_LOG_INFO( gLogFilter, Debug::General, " number of fonts found : [%d]\n", fontSet->nfont );
350 // Reserve some space to avoid reallocations.
351 fontList.reserve( fontSet->nfont );
353 for( int i = 0u; i < fontSet->nfont; ++i )
355 FcPattern* fontPattern = fontSet->fonts[i];
359 // Skip fonts with no path
360 if( GetFcString( fontPattern, FC_FILE, path ) )
362 // Retrieve the character set. Need to call FcCharSetDestroy to free the resources.
363 FcCharSet* characterSet = nullptr;
364 FcPatternGetCharSet( fontPattern, FC_CHARSET, 0u, &characterSet );
366 // Increase the reference counter of the character set.
367 characterSetList.PushBack( FcCharSetCopy( characterSet ) );
369 fontList.push_back( FontDescription() );
370 FontDescription& newFontDescription = fontList.back();
372 newFontDescription.path = std::move( path );
377 GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
378 GetFcInt( fontPattern, FC_WIDTH, width );
379 GetFcInt( fontPattern, FC_WEIGHT, weight );
380 GetFcInt( fontPattern, FC_SLANT, slant );
381 newFontDescription.width = IntToWidthType( width );
382 newFontDescription.weight = IntToWeightType( weight );
383 newFontDescription.slant = IntToSlantType( slant );
385 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", newFontDescription.family.c_str() );
386 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", newFontDescription.path.c_str() );
387 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[newFontDescription.width] );
388 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[newFontDescription.weight] );
389 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[newFontDescription.slant] );
393 // Destroys the font set created by FcFontSort.
394 FcFontSetDestroy( fontSet );
398 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " No fonts found.\n" );
401 // Destroys the pattern created by FcPatternCreate in CreateFontFamilyPattern.
402 FcPatternDestroy( fontFamilyPattern );
404 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::SetFontList\n" );
407 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
409 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultFonts\n" );
411 if( mDefaultFonts.empty() )
413 FontDescription fontDescription;
414 fontDescription.family = DEFAULT_FONT_FAMILY_NAME; // todo This could be set to the Platform font
415 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
416 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
417 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
418 SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
421 defaultFonts = mDefaultFonts;
423 DALI_LOG_INFO( gLogFilter, Debug::General, " number of default fonts : [%d]\n", mDefaultFonts.size() );
424 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultFonts\n" );
427 void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
429 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultPlatformFontDescription\n");
431 if( !mDefaultFontDescriptionCached )
433 // Clear any font config stored info in the caches.
435 // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
436 DestroyCharacterSets( mDefaultFontCharacterSets );
437 DestroyCharacterSets( mCharacterSetCache );
438 mDefaultFontCharacterSets.Clear();
439 mCharacterSetCache.Clear();
441 for( auto& item : mFallbackCache )
443 // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
444 DestroyCharacterSets( *item.characterSets );
446 delete item.characterSets;
447 item.characterSets = nullptr;
450 // Set the character set pointer as null. Will be created again the next time IsCharacterSupportedByFont()
451 ClearCharacterSetFromFontFaceCache();
453 // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
454 FcInitReinitialize();
456 FcPattern* matchPattern = FcPatternCreate(); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
458 if( nullptr != matchPattern )
460 FcConfigSubstitute( nullptr, matchPattern, FcMatchPattern );
461 FcDefaultSubstitute( matchPattern );
463 FcCharSet* characterSet = nullptr;
464 MatchFontDescriptionToPattern( matchPattern, mDefaultFontDescription, &characterSet );
465 // Decrease the reference counter of the character set as it's not stored.
466 FcCharSetDestroy( characterSet );
468 // Destroys the pattern created.
469 FcPatternDestroy( matchPattern );
472 // Create again the character sets as they are not valid after FcInitReinitialize()
474 for( const auto& description : mDefaultFonts )
476 mDefaultFontCharacterSets.PushBack( FcCharSetCopy( CreateCharacterSetFromDescription( description ) ) );
479 for( const auto& description : mFontDescriptionCache )
481 mCharacterSetCache.PushBack( FcCharSetCopy( CreateCharacterSetFromDescription( description ) ) );
484 for( auto& item : mFallbackCache )
486 if( nullptr != item.fallbackFonts )
488 if( nullptr == item.characterSets )
490 item.characterSets = new CharacterSetList;
493 for( const auto& description : *( item.fallbackFonts ) )
495 item.characterSets->PushBack( FcCharSetCopy( CreateCharacterSetFromDescription( description ) ) );
500 mDefaultFontDescriptionCached = true;
503 fontDescription.path = mDefaultFontDescription.path;
504 fontDescription.family = mDefaultFontDescription.family;
505 fontDescription.width = mDefaultFontDescription.width;
506 fontDescription.weight = mDefaultFontDescription.weight;
507 fontDescription.slant = mDefaultFontDescription.slant;
509 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
510 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
511 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
512 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
513 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
514 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultPlatformFontDescription\n");
517 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
519 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetSystemFonts\n");
521 if( mSystemFonts.empty() )
526 systemFonts = mSystemFonts;
527 DALI_LOG_INFO( gLogFilter, Debug::General, " number of system fonts : [%d]\n", mSystemFonts.size() );
528 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetSystemFonts\n");
531 void FontClient::Plugin::GetDescription( FontId id,
532 FontDescription& fontDescription ) const
534 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDescription\n");
535 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
536 const FontId index = id - 1u;
538 if( ( id > 0u ) && ( index < mFontIdCache.Count() ) )
540 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
541 switch( fontIdCacheItem.type )
543 case FontDescription::FACE_FONT:
545 for( const auto& item : mFontDescriptionSizeCache )
547 if( item.fontId == fontIdCacheItem.id )
549 fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId - 1u );
551 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
552 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
553 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
554 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
555 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
556 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
562 case FontDescription::BITMAP_FONT:
564 fontDescription.type = FontDescription::BITMAP_FONT;
565 fontDescription.family = mBitmapFontCache[fontIdCacheItem.id].font.name;
570 DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
571 fontDescription.type = FontDescription::INVALID;
572 fontDescription.family.clear();
577 DALI_LOG_INFO( gLogFilter, Debug::General, " No description found for the font ID %d\n", id );
578 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
581 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
583 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetPointSize\n");
584 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
585 const FontId index = id - 1u;
588 ( index < mFontIdCache.Count() ) )
590 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
592 switch( fontIdCacheItem.type )
594 case FontDescription::FACE_FONT:
596 DALI_LOG_INFO( gLogFilter, Debug::General, " point size : %d\n", ( *( mFontFaceCache.begin() + fontIdCacheItem.id ) ).mRequestedPointSize );
597 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
598 return ( *( mFontFaceCache.begin() + fontIdCacheItem.id ) ).mRequestedPointSize;
600 case FontDescription::BITMAP_FONT:
602 return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
606 DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
612 DALI_LOG_INFO( gLogFilter, Debug::General, " Invalid font ID %d\n", id );
615 DALI_LOG_INFO( gLogFilter, Debug::General, " default point size : %d\n", TextAbstraction::FontClient::DEFAULT_POINT_SIZE );
616 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
617 return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
620 bool FontClient::Plugin::IsCharacterSupportedByFont( FontId fontId, Character character )
622 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::IsCharacterSupportedByFont\n");
623 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
624 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", character );
626 if( ( fontId < 1u ) || ( fontId > mFontIdCache.Count() ) )
628 DALI_LOG_INFO( gLogFilter, Debug::General, " Invalid font id. Number of items in the cache: %d\n",mFontIdCache.Count());
629 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
635 bool isSupported = false;
637 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[fontId];
639 switch( fontIdCacheItem.type )
641 case FontDescription::FACE_FONT:
643 if( fontIdCacheItem.id < mFontFaceCache.size() )
645 FontFaceCacheItem& cacheItem = mFontFaceCache[fontIdCacheItem.id];
647 if( nullptr == cacheItem.mCharacterSet )
649 // Create again the character set.
650 // It can be null if the ResetSystemDefaults() method has been called.
652 FontDescription description;
653 description.path = cacheItem.mPath;
654 description.family = std::move( FontFamily( cacheItem.mFreeTypeFace->family_name ) );
655 description.weight = FontWeight::NONE;
656 description.width = FontWidth::NONE;
657 description.slant = FontSlant::NONE;
659 // Note FreeType doesn't give too much info to build a proper font style.
660 if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC )
662 description.slant = FontSlant::ITALIC;
664 if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_BOLD )
666 description.weight = FontWeight::BOLD;
669 cacheItem.mCharacterSet = FcCharSetCopy( CreateCharacterSetFromDescription( description ) );
672 isSupported = FcCharSetHasChar( cacheItem.mCharacterSet, character );
676 case FontDescription::BITMAP_FONT:
678 const BitmapFont& bitmapFont = mBitmapFontCache[fontIdCacheItem.id].font;
680 for( const auto& glyph : bitmapFont.glyphs )
682 if( glyph.utf32 == character )
692 DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
696 DALI_LOG_INFO( gLogFilter, Debug::General, " is supported : %s\n", (isSupported ? "true" : "false") );
697 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
701 FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
702 const CharacterSetList& characterSetList,
704 PointSize26Dot6 requestedPointSize,
707 DALI_ASSERT_DEBUG( ( fontList.size() == characterSetList.Count() ) && "FontClient::Plugin::FindFontForCharacter. Different number of fonts and character sets." );
709 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFontForCharacter\n" );
710 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", character );
711 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
712 DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) );
715 bool foundColor = false;
717 DALI_LOG_INFO( gLogFilter, Debug::General, " number of fonts : %d\n", fontList.size() );
719 // Traverse the list of fonts.
720 // Check for each font if supports the character.
721 for( unsigned int index = 0u, numberOfFonts = fontList.size(); index < numberOfFonts; ++index )
723 const FontDescription& description = fontList[index];
724 const FcCharSet* const characterSet = characterSetList[index];
726 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", description.family.c_str() );
727 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", description.path.c_str() );
728 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[description.width] );
729 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[description.weight] );
730 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[description.slant] );
732 bool foundInRanges = false;
733 if( nullptr != characterSet )
735 foundInRanges = FcCharSetHasChar( characterSet, character );
740 fontId = GetFontId( description,
744 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " font id : %d\n", fontId );
748 if( ( fontId > 0 ) &&
749 ( fontId - 1u < mFontIdCache.Count() ) )
751 const FontFaceCacheItem& item = mFontFaceCache[mFontIdCache[fontId - 1u].id];
753 foundColor = item.mHasColorTables;
756 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " foundColor : %s\n", ( foundColor ? "true" : "false" ) );
759 // Keep going unless we prefer a different (color) font.
760 if( !preferColor || foundColor )
767 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
768 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFontForCharacter\n" );
772 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
773 PointSize26Dot6 requestedPointSize,
776 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindDefaultFont\n" );
777 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", charcode );
778 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
779 DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) );
783 // Create the list of default fonts if it has not been created.
784 if( mDefaultFonts.empty() )
786 FontDescription fontDescription;
787 fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
788 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
789 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
790 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
792 SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
794 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of default fonts : %d\n", mDefaultFonts.size() );
797 // Traverse the list of default fonts.
798 // Check for each default font if supports the character.
799 fontId = FindFontForCharacter( mDefaultFonts, mDefaultFontCharacterSets, charcode, requestedPointSize, preferColor );
801 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
802 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindDefaultFont\n" );
807 FontId FontClient::Plugin::FindFallbackFont( Character charcode,
808 const FontDescription& preferredFontDescription,
809 PointSize26Dot6 requestedPointSize,
812 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFont\n" );
813 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", charcode );
814 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
815 DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) );
817 // The font id to be returned.
820 FontDescription fontDescription;
822 // Fill the font description with the preferred font description and complete with the defaults.
823 fontDescription.family = preferredFontDescription.family.empty() ? DEFAULT_FONT_FAMILY_NAME : preferredFontDescription.family;
824 fontDescription.weight = ( ( FontWeight::NONE == preferredFontDescription.weight ) ? IntToWeightType( DEFAULT_FONT_WEIGHT ) : preferredFontDescription.weight );
825 fontDescription.width = ( ( FontWidth::NONE == preferredFontDescription.width ) ? IntToWidthType( DEFAULT_FONT_WIDTH ) : preferredFontDescription.width );
826 fontDescription.slant = ( ( FontSlant::NONE == preferredFontDescription.slant ) ? IntToSlantType( DEFAULT_FONT_SLANT ) : preferredFontDescription.slant );
828 DALI_LOG_INFO( gLogFilter, Debug::General, " preferredFontDescription --> fontDescription\n" );
829 DALI_LOG_INFO( gLogFilter, Debug::General, " [%s] --> [%s]\n", preferredFontDescription.family.c_str(), fontDescription.family.c_str() );
830 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontWeight::Name[preferredFontDescription.weight], FontWeight::Name[fontDescription.weight] );
831 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontWidth::Name[preferredFontDescription.width], FontWidth::Name[fontDescription.width] );
832 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontSlant::Name[preferredFontDescription.slant], FontSlant::Name[fontDescription.slant] );
834 // Check first if the font's description has been queried before.
835 FontList* fontList = nullptr;
836 CharacterSetList* characterSetList = nullptr;
838 if( !FindFallbackFontList( fontDescription, fontList, characterSetList ) )
840 fontList = new FontList;
841 characterSetList = new CharacterSetList;
843 SetFontList( fontDescription, *fontList, *characterSetList );
845 // Add the font-list to the cache.
846 mFallbackCache.push_back( std::move( FallbackCacheItem( std::move( fontDescription ), fontList, characterSetList ) ) );
849 if( fontList && characterSetList )
851 fontId = FindFontForCharacter( *fontList, *characterSetList, charcode, requestedPointSize, preferColor );
854 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
855 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFont\n");
859 FontId FontClient::Plugin::GetFontId( const FontPath& path,
860 PointSize26Dot6 requestedPointSize,
862 bool cacheDescription )
864 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
865 DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() );
866 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
870 if( nullptr != mFreeTypeLibrary )
873 if( FindFont( path, requestedPointSize, faceIndex, foundId ) )
879 id = CreateFont( path, requestedPointSize, faceIndex, cacheDescription );
883 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
884 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
889 FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
890 PointSize26Dot6 requestedPointSize,
891 FaceIndex faceIndex )
893 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
894 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
895 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
896 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
897 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
898 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
899 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
901 // This method uses three vectors which caches:
902 // * The bitmap font cache
903 // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
904 // * The path to font file names.
905 // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
907 // 1) Checks if the font description matches with a previously loaded bitmap font.
908 // Returns if a font is found.
909 // 2) Checks in the cache if the font's description has been validated before.
910 // If it was it gets an index to the vector with paths to font file names. Otherwise,
911 // retrieves using font config a path to a font file name which matches with the
912 // font's description. The path is stored in the cache.
914 // 3) Checks in the cache if the pair 'font point size, index to the vector with paths to
915 // font file names' exists. If exists, it gets the font id. If it doesn't it calls
916 // the GetFontId() method with the path to the font file name and the point size to
919 // The font id to be returned.
922 // Check first if the font description matches with a previously loaded bitmap font.
923 if( FindBitmapFont( fontDescription.family, fontId ) )
928 // Check if the font's description have been validated before.
929 FontDescriptionId validatedFontId = 0u;
931 if( !FindValidatedFont( fontDescription,
934 // Use font config to validate the font's description.
935 ValidateFont( fontDescription,
939 FontId fontFaceId = 0u;
940 // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
941 if( !FindFont( validatedFontId, requestedPointSize, fontFaceId ) )
943 // Retrieve the font file name path.
944 const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId - 1u );
946 // Retrieve the font id. Do not cache the description as it has been already cached.
947 fontId = GetFontId( description.path,
952 fontFaceId = mFontIdCache[fontId-1u].id;
953 mFontFaceCache[fontFaceId].mCharacterSet = FcCharSetCopy( mCharacterSetCache[validatedFontId - 1u] );
955 // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
956 mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
962 fontId = mFontFaceCache[fontFaceId].mFontId + 1u;
965 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
966 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
971 FontId FontClient::Plugin::GetFontId( const BitmapFont& bitmapFont )
973 for( const auto& item : mBitmapFontCache )
975 if( bitmapFont.name == item.font.name )
981 BitmapFontCacheItem bitmapFontCacheItem;
982 bitmapFontCacheItem.font = bitmapFont;
983 bitmapFontCacheItem.id = mFontIdCache.Count();
985 // Resize the vector with the pixel buffers.
986 bitmapFontCacheItem.pixelBuffers.resize( bitmapFont.glyphs.size() );
988 // Traverse all the glyphs and load the pixel buffer of those with ascender and descender equal to zero.
989 unsigned int index = 0u;
990 for( auto& glyph : bitmapFontCacheItem.font.glyphs )
992 Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
994 if( EqualsZero( glyph.ascender ) && EqualsZero( glyph.descender ) )
997 pixelBuffer = LoadImageFromFile( glyph.url );
1001 glyph.ascender = static_cast<float>(pixelBuffer.GetHeight());
1005 bitmapFontCacheItem.font.ascender = std::max( glyph.ascender, bitmapFontCacheItem.font.ascender );
1006 bitmapFontCacheItem.font.descender = std::min( glyph.descender, bitmapFontCacheItem.font.descender );
1011 FontIdCacheItem fontIdCacheItem;
1012 fontIdCacheItem.type = FontDescription::BITMAP_FONT;
1013 fontIdCacheItem.id = mBitmapFontCache.size();
1015 mBitmapFontCache.push_back( std::move( bitmapFontCacheItem ) );
1016 mFontIdCache.PushBack( fontIdCacheItem );
1018 return bitmapFontCacheItem.id + 1u;
1021 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
1022 FontDescriptionId& validatedFontId )
1024 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::ValidateFont\n" );
1025 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
1026 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1027 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1028 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1029 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1031 // Create a font pattern.
1032 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1034 FontDescription description;
1036 FcCharSet* characterSet = nullptr;
1037 bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description, &characterSet );
1038 FcPatternDestroy( fontFamilyPattern );
1040 if( matched && ( nullptr != characterSet ) )
1042 // Add the path to the cache.
1043 description.type = FontDescription::FACE_FONT;
1044 mFontDescriptionCache.push_back( description );
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 // The reference counter of the character set has already been increased in MatchFontDescriptionToPattern.
1057 mCharacterSetCache.PushBack( characterSet );
1059 // Cache the index and the matched font's description.
1060 FontDescriptionCacheItem item( description,
1063 mValidatedFontCache.push_back( std::move( item ) );
1065 if( ( fontDescription.family != description.family ) ||
1066 ( fontDescription.width != description.width ) ||
1067 ( fontDescription.weight != description.weight ) ||
1068 ( fontDescription.slant != description.slant ) )
1070 // Cache the given font's description if it's different than the matched.
1071 FontDescriptionCacheItem item( fontDescription,
1074 mValidatedFontCache.push_back( std::move( item ) );
1079 DALI_LOG_INFO( gLogFilter, Debug::General, " font validation failed for font [%s]\n", fontDescription.family.c_str() );
1082 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::ValidateFont\n" );
1085 void FontClient::Plugin::GetFontMetrics( FontId fontId,
1086 FontMetrics& metrics )
1088 const FontId index = fontId - 1u;
1090 if( ( fontId > 0 ) &&
1091 ( index < mFontIdCache.Count() ) )
1093 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1095 switch( fontIdCacheItem.type )
1097 case FontDescription::FACE_FONT:
1099 const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
1101 metrics = font.mMetrics;
1103 // Adjust the metrics if the fixed-size font should be down-scaled
1104 if( font.mIsFixedSizeBitmap )
1106 const float desiredFixedSize = static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
1108 if( desiredFixedSize > 0.f )
1110 const float scaleFactor = desiredFixedSize / font.mFixedHeightPixels;
1112 metrics.ascender = metrics.ascender * scaleFactor;
1113 metrics.descender = metrics.descender * scaleFactor;
1114 metrics.height = metrics.height * scaleFactor;
1115 metrics.underlinePosition = metrics.underlinePosition * scaleFactor;
1116 metrics.underlineThickness = metrics.underlineThickness * scaleFactor;
1121 case FontDescription::BITMAP_FONT:
1123 const BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
1125 metrics.ascender = bitmapFontCacheItem.font.ascender;
1126 metrics.descender = bitmapFontCacheItem.font.descender;
1127 metrics.height = metrics.ascender - metrics.descender;
1128 metrics.underlinePosition = bitmapFontCacheItem.font.underlinePosition;
1129 metrics.underlineThickness = bitmapFontCacheItem.font.underlineThickness;
1134 DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
1140 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId );
1144 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
1145 Character charcode )
1147 GlyphIndex glyphIndex = 0u;
1148 const FontId index = fontId - 1u;
1150 if( ( fontId > 0u ) &&
1151 ( index < mFontIdCache.Count() ) )
1153 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1155 if( FontDescription::FACE_FONT == fontIdCacheItem.type )
1157 FT_Face ftFace = mFontFaceCache[fontIdCacheItem.id].mFreeTypeFace;
1159 glyphIndex = FT_Get_Char_Index( ftFace, charcode );
1166 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
1171 if( VECTOR_GLYPH == type )
1173 return GetVectorMetrics( array, size, horizontal );
1176 return GetBitmapMetrics( array, size, horizontal );
1179 bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array,
1183 bool success( true );
1185 for( unsigned int i=0; i<size; ++i )
1187 GlyphInfo& glyph = array[i];
1189 FontId index = glyph.fontId - 1u;
1191 if( ( glyph.fontId > 0u ) &&
1192 ( index < mFontIdCache.Count() ) )
1194 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1196 switch( fontIdCacheItem.type )
1198 case FontDescription::FACE_FONT:
1200 const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
1202 FT_Face ftFace = font.mFreeTypeFace;
1204 #ifdef FREETYPE_BITMAP_SUPPORT
1205 // Check to see if we should be loading a Fixed Size bitmap?
1206 if( font.mIsFixedSizeBitmap )
1208 FT_Select_Size( ftFace, font.mFixedSizeIndex ); ///< @todo: needs to be investigated why it's needed to select the size again.
1209 int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_COLOR );
1210 if ( FT_Err_Ok == error )
1212 glyph.width = font.mFixedWidthPixels;
1213 glyph.height = font.mFixedHeightPixels;
1214 glyph.advance = font.mFixedWidthPixels;
1215 glyph.xBearing = 0.0f;
1216 glyph.yBearing = font.mFixedHeightPixels;
1218 // Adjust the metrics if the fixed-size font should be down-scaled
1219 const float desiredFixedSize = static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
1221 if( desiredFixedSize > 0.f )
1223 const float scaleFactor = desiredFixedSize / font.mFixedHeightPixels;
1225 glyph.width = glyph.width * scaleFactor ;
1226 glyph.height = glyph.height * scaleFactor;
1227 glyph.advance = glyph.advance * scaleFactor;
1228 glyph.xBearing = glyph.xBearing * scaleFactor;
1229 glyph.yBearing = glyph.yBearing * scaleFactor;
1231 glyph.scaleFactor = scaleFactor;
1236 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetBitmapMetrics. FreeType Bitmap Load_Glyph error %d\n", error );
1243 // FT_LOAD_DEFAULT causes some issues in the alignment of the glyph inside the bitmap.
1244 // i.e. with the SNum-3R font.
1245 // @todo: add an option to use the FT_LOAD_DEFAULT if required?
1246 int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_NO_AUTOHINT );
1248 // Keep the width of the glyph before doing the software emboldening.
1249 // It will be used to calculate a scale factor to be applied to the
1250 // advance as Harfbuzz doesn't apply any SW emboldening to calculate
1251 // the advance of the glyph.
1252 const float width = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
1254 if( FT_Err_Ok == error )
1256 const bool isEmboldeningRequired = glyph.isBoldRequired && !( ftFace->style_flags & FT_STYLE_FLAG_BOLD );
1257 if( isEmboldeningRequired )
1259 // Does the software bold.
1260 FT_GlyphSlot_Embolden( ftFace->glyph );
1263 glyph.width = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
1264 glyph.height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266;
1267 glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
1268 glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
1272 glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
1273 glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
1276 if( isEmboldeningRequired && !Dali::EqualsZero( width ) )
1278 // If the glyph is emboldened by software, the advance is multiplied by a
1279 // scale factor to make it slightly bigger.
1280 glyph.advance *= ( glyph.width / width );
1283 // Use the bounding box of the bitmap to correct the metrics.
1284 // For some fonts i.e the SNum-3R the metrics need to be corrected,
1285 // otherwise the glyphs 'dance' up and down depending on the
1286 // font's point size.
1289 error = FT_Get_Glyph( ftFace->glyph, &ftGlyph );
1292 FT_Glyph_Get_CBox( ftGlyph, FT_GLYPH_BBOX_GRIDFIT, &bbox );
1294 const float descender = glyph.height - glyph.yBearing;
1295 glyph.height = ( bbox.yMax - bbox.yMin) * FROM_266;
1296 glyph.yBearing = glyph.height - round( descender );
1298 // Created FT_Glyph object must be released with FT_Done_Glyph
1299 FT_Done_Glyph( ftGlyph );
1308 case FontDescription::BITMAP_FONT:
1310 BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
1312 unsigned int index = 0u;
1313 for( auto& item : bitmapFontCacheItem.font.glyphs )
1315 if( item.utf32 == glyph.index )
1317 Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
1320 pixelBuffer = LoadImageFromFile( item.url );
1323 glyph.width = static_cast< float >( pixelBuffer.GetWidth() );
1324 glyph.height = static_cast< float >( pixelBuffer.GetHeight() );
1325 glyph.xBearing = 0.f;
1326 glyph.yBearing = glyph.height + item.descender;
1327 glyph.advance = glyph.width;
1328 glyph.scaleFactor = 1.f;
1339 DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
1345 // Check if it's an embedded image.
1346 if( ( 0u == glyph.fontId ) && ( 0u != glyph.index ) && ( glyph.index <= mEmbeddedItemCache.Count() ) )
1348 const EmbeddedItem& item = mEmbeddedItemCache[glyph.index - 1u];
1350 glyph.width = static_cast<float>( item.width );
1351 glyph.height = static_cast<float>( item.height );
1352 glyph.xBearing = 0.f;
1353 glyph.yBearing = glyph.height;
1354 glyph.advance = glyph.width;
1355 glyph.scaleFactor = 1.f;
1367 bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array,
1371 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
1372 bool success( true );
1374 for( unsigned int i = 0u; i < size; ++i )
1376 FontId fontId = array[i].fontId;
1378 if( ( fontId > 0u ) &&
1379 ( fontId - 1u ) < mFontIdCache.Count() )
1381 FontFaceCacheItem& font = mFontFaceCache[mFontIdCache[fontId - 1u].id];
1383 if( ! font.mVectorFontId )
1385 font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
1388 mVectorFontCache->GetGlyphMetrics( font.mVectorFontId, array[i] );
1390 // Vector metrics are in EMs, convert to pixels
1391 const float scale = ( static_cast<float>( font.mRequestedPointSize ) * FROM_266 ) * static_cast<float>( mDpiVertical ) / POINTS_PER_INCH;
1392 array[i].width *= scale;
1393 array[i].height *= scale;
1394 array[i].xBearing *= scale;
1395 array[i].yBearing *= scale;
1396 array[i].advance *= scale;
1410 void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
1412 const FontId index = fontId - 1u;
1414 if( ( fontId > 0u ) &&
1415 ( index < mFontIdCache.Count() ) )
1417 data.isColorBitmap = false;
1418 data.isColorEmoji = false;
1420 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1422 switch( fontIdCacheItem.type )
1424 case FontDescription::FACE_FONT:
1426 // For the software italics.
1427 bool isShearRequired = false;
1429 const FontFaceCacheItem& fontFaceCacheItem = mFontFaceCache[fontIdCacheItem.id];
1430 FT_Face ftFace = fontFaceCacheItem.mFreeTypeFace;
1434 #ifdef FREETYPE_BITMAP_SUPPORT
1435 // Check to see if this is fixed size bitmap
1436 if( fontFaceCacheItem.mIsFixedSizeBitmap )
1438 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1443 // FT_LOAD_DEFAULT causes some issues in the alignment of the glyph inside the bitmap.
1444 // i.e. with the SNum-3R font.
1445 // @todo: add an option to use the FT_LOAD_DEFAULT if required?
1446 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_NO_AUTOHINT );
1448 if( FT_Err_Ok == error )
1450 if( isBoldRequired && !( ftFace->style_flags & FT_STYLE_FLAG_BOLD ) )
1452 // Does the software bold.
1453 FT_GlyphSlot_Embolden( ftFace->glyph );
1456 if( isItalicRequired && !( ftFace->style_flags & FT_STYLE_FLAG_ITALIC ) )
1458 // Will do the software italic.
1459 isShearRequired = true;
1463 error = FT_Get_Glyph( ftFace->glyph, &glyph );
1465 // Convert to bitmap if necessary
1466 if( FT_Err_Ok == error )
1468 if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
1470 int offsetX = 0, offsetY = 0;
1471 bool isOutlineGlyph = ( glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0 );
1473 // Create a bitmap for the outline
1474 if( isOutlineGlyph )
1476 // Retrieve the horizontal and vertical distance from the current pen position to the
1477 // left and top border of the glyph bitmap for a normal glyph before applying the outline.
1478 if( FT_Err_Ok == error )
1480 FT_Glyph normalGlyph;
1481 error = FT_Get_Glyph( ftFace->glyph, &normalGlyph );
1483 error = FT_Glyph_To_Bitmap( &normalGlyph, FT_RENDER_MODE_NORMAL, 0, 1 );
1484 if( FT_Err_Ok == error )
1486 FT_BitmapGlyph bitmapGlyph = reinterpret_cast< FT_BitmapGlyph >( normalGlyph );
1488 offsetX = bitmapGlyph->left;
1489 offsetY = bitmapGlyph->top;
1492 // Created FT_Glyph object must be released with FT_Done_Glyph
1493 FT_Done_Glyph( normalGlyph );
1496 // Now apply the outline
1500 error = FT_Stroker_New( mFreeTypeLibrary, &stroker );
1502 if( FT_Err_Ok == error )
1504 FT_Stroker_Set( stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 );
1505 error = FT_Glyph_StrokeBorder( &glyph, stroker, 0, 1 );
1507 if( FT_Err_Ok == error )
1509 FT_Stroker_Done( stroker );
1513 DALI_LOG_ERROR( "FT_Glyph_StrokeBorder Failed with error: %d\n", error );
1518 DALI_LOG_ERROR( "FT_Stroker_New Failed with error: %d\n", error );
1522 error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
1523 if( FT_Err_Ok == error )
1525 FT_BitmapGlyph bitmapGlyph = reinterpret_cast< FT_BitmapGlyph >( glyph );
1527 if( isOutlineGlyph )
1529 // Calculate the additional horizontal and vertical offsets needed for the position of the outline glyph
1530 data.outlineOffsetX = offsetX - bitmapGlyph->left - outlineWidth;
1531 data.outlineOffsetY = bitmapGlyph->top - offsetY - outlineWidth;
1534 ConvertBitmap( data, bitmapGlyph->bitmap, isShearRequired );
1538 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Get_Glyph Failed with error: %d\n", error );
1543 ConvertBitmap( data, ftFace->glyph->bitmap, isShearRequired );
1546 data.isColorEmoji = fontFaceCacheItem.mIsFixedSizeBitmap;
1548 // Created FT_Glyph object must be released with FT_Done_Glyph
1549 FT_Done_Glyph( glyph );
1554 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Load_Glyph Failed with error: %d\n", error );
1558 case FontDescription::BITMAP_FONT:
1560 BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
1562 unsigned int index = 0u;
1563 for( auto& item : bitmapFontCacheItem.font.glyphs )
1565 if( item.utf32 == glyphIndex )
1567 Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
1570 pixelBuffer = LoadImageFromFile( item.url );
1573 data.width = pixelBuffer.GetWidth();
1574 data.height = pixelBuffer.GetHeight();
1576 data.isColorBitmap = bitmapFontCacheItem.font.isColorFont;
1578 ConvertBitmap( data, data.width, data.height, pixelBuffer.GetBuffer() );
1580 // Sets the pixel format.
1581 data.format = pixelBuffer.GetPixelFormat();
1590 DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
1596 if( ( 0u != glyphIndex ) && ( glyphIndex <= mEmbeddedItemCache.Count() ) )
1598 // It's an embedded item.
1599 const EmbeddedItem& item = mEmbeddedItemCache[glyphIndex - 1u];
1601 data.width = item.width;
1602 data.height = item.height;
1603 if( 0u != item.pixelBufferId )
1605 Devel::PixelBuffer pixelBuffer = mPixelBufferCache[item.pixelBufferId-1u].pixelBuffer;
1608 ConvertBitmap( data, pixelBuffer.GetWidth(), pixelBuffer.GetHeight(), pixelBuffer.GetBuffer() );
1610 // Sets the pixel format.
1611 data.format = pixelBuffer.GetPixelFormat();
1616 // Creates the output buffer
1617 const unsigned int bufferSize = data.width * data.height * 4u;
1618 data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1620 memset( data.buffer, 0u, bufferSize );
1622 // Just creates a void buffer. Doesn't matter what pixel format is set as is the application code the responsible of filling it.
1628 PixelData FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
1630 TextAbstraction::FontClient::GlyphBufferData data;
1632 CreateBitmap( fontId, glyphIndex, false, false, data, outlineWidth );
1634 return PixelData::New( data.buffer,
1635 data.width * data.height * Pixel::GetBytesPerPixel( data.format ),
1639 PixelData::DELETE_ARRAY );
1642 void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
1647 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
1648 if( ( fontId > 0u ) &&
1649 ( fontId - 1u < mFontIdCache.Count() ) )
1651 const FontId fontFaceId = mFontIdCache[fontId - 1u].id;
1652 FontFaceCacheItem& font = mFontFaceCache[fontFaceId];
1654 if( ! font.mVectorFontId )
1656 font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
1659 mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontFaceId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
1664 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
1666 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetEllipsisGlyph\n" );
1667 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize %d.\n", requestedPointSize );
1669 // First look into the cache if there is an ellipsis glyph for the requested point size.
1670 for( const auto& item : mEllipsisCache )
1672 if( item.requestedPointSize == requestedPointSize )
1674 // Use the glyph in the cache.
1676 DALI_LOG_INFO( gLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index );
1677 DALI_LOG_INFO( gLogFilter, Debug::General, " font %d.\n", item.glyph.fontId );
1678 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
1684 // No glyph has been found. Create one.
1685 mEllipsisCache.PushBack( EllipsisItem() );
1686 EllipsisItem& item = *( mEllipsisCache.End() - 1u );
1688 item.requestedPointSize = requestedPointSize;
1690 // Find a font for the ellipsis glyph.
1691 item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
1695 // Set the character index to access the glyph inside the font.
1696 item.glyph.index = FT_Get_Char_Index( mFontFaceCache[mFontIdCache[item.glyph.fontId-1u].id].mFreeTypeFace,
1697 ELLIPSIS_CHARACTER );
1699 GetBitmapMetrics( &item.glyph, 1u, true );
1701 DALI_LOG_INFO( gLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index );
1702 DALI_LOG_INFO( gLogFilter, Debug::General, " font %d.\n", item.glyph.fontId );
1703 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
1708 bool FontClient::Plugin::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
1710 FT_Error error = -1;
1712 const FontId index = fontId - 1u;
1714 if( ( fontId > 0u ) &&
1715 ( index < mFontIdCache.Count() ) )
1717 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1719 switch( fontIdCacheItem.type )
1721 case FontDescription::FACE_FONT:
1723 #ifdef FREETYPE_BITMAP_SUPPORT
1724 const FontFaceCacheItem& item = mFontFaceCache[fontIdCacheItem.id];
1725 FT_Face ftFace = item.mFreeTypeFace;
1727 // Check to see if this is fixed size bitmap
1728 if( item.mHasColorTables )
1730 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1735 case FontDescription::BITMAP_FONT:
1737 error = FT_Err_Ok; // Will return true;
1742 DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
1747 return FT_Err_Ok == error;
1750 FT_FaceRec_* FontClient::Plugin::GetFreetypeFace( FontId fontId )
1752 FT_Face fontFace = nullptr;
1754 const FontId index = fontId - 1u;
1755 if( ( fontId > 0u ) &&
1756 ( index < mFontIdCache.Count() ) )
1758 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
1760 if( FontDescription::FACE_FONT == fontIdCacheItem.type )
1762 fontFace = mFontFaceCache[fontIdCacheItem.id].mFreeTypeFace;
1768 FontDescription::Type FontClient::Plugin::GetFontType( FontId fontId )
1770 const FontId index = fontId - 1u;
1771 if( ( fontId > 0u ) &&
1772 ( index < mFontIdCache.Count() ) )
1774 return mFontIdCache[index].type;
1776 return FontDescription::INVALID;
1779 bool FontClient::Plugin::AddCustomFontDirectory( const FontPath& path )
1781 // nullptr as first parameter means the current configuration is used.
1782 return FcConfigAppFontAddDir( nullptr, reinterpret_cast<const FcChar8 *>( path.c_str() ) );
1785 GlyphIndex FontClient::Plugin::CreateEmbeddedItem( const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat )
1787 EmbeddedItem embeddedItem;
1789 embeddedItem.pixelBufferId = 0u;
1790 embeddedItem.width = description.width;
1791 embeddedItem.height = description.height;
1793 pixelFormat = Pixel::A8;
1795 if( !description.url.empty() )
1797 // Check if the url is in the cache.
1798 PixelBufferId index = 0u;
1800 for( const auto& cacheItem : mPixelBufferCache )
1803 if( cacheItem.url == description.url )
1805 // The url is in the pixel buffer cache.
1806 // Set the index +1 to the vector.
1807 embeddedItem.pixelBufferId = index;
1812 Devel::PixelBuffer pixelBuffer;
1813 if( 0u == embeddedItem.pixelBufferId )
1815 // The pixel buffer is not in the cache. Create one and cache it.
1817 // Load the image from the url.
1818 pixelBuffer = LoadImageFromFile( description.url );
1820 // Create the cache item.
1821 PixelBufferCacheItem pixelBufferCacheItem;
1822 pixelBufferCacheItem.pixelBuffer = pixelBuffer;
1823 pixelBufferCacheItem.url = description.url;
1825 // Store the cache item in the cache.
1826 mPixelBufferCache.push_back( std::move( pixelBufferCacheItem ) );
1828 // Set the pixel buffer id to the embedded item.
1829 embeddedItem.pixelBufferId = mPixelBufferCache.size();
1833 // Retrieve the pixel buffer from the cache to set the pixel format.
1834 pixelBuffer = mPixelBufferCache[embeddedItem.pixelBufferId-1u].pixelBuffer;
1839 // Set the size of the embedded item if it has not been set.
1840 if( 0u == embeddedItem.width )
1842 embeddedItem.width = static_cast<unsigned int>( pixelBuffer.GetWidth() );
1845 if( 0u == embeddedItem.height )
1847 embeddedItem.height = static_cast<unsigned int>( pixelBuffer.GetHeight() );
1850 // Set the pixel format.
1851 pixelFormat = pixelBuffer.GetPixelFormat();
1855 // Find if the same embeddedItem has already been created.
1856 unsigned int index = 0u;
1857 for( const auto& item : mEmbeddedItemCache )
1860 if( ( item.pixelBufferId == embeddedItem.pixelBufferId ) &&
1861 ( item.width == embeddedItem.width ) &&
1862 ( item.height == embeddedItem.height ) )
1868 // Cache the embedded item.
1869 mEmbeddedItemCache.PushBack( embeddedItem );
1871 return mEmbeddedItemCache.Count();
1874 void FontClient::Plugin::InitSystemFonts()
1876 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::InitSystemFonts\n" );
1878 FcFontSet* fontSet = GetFcFontSet(); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
1882 DALI_LOG_INFO( gLogFilter, Debug::General, " number of system fonts : %d\n", fontSet->nfont );
1884 // Reserve some space to avoid reallocations.
1885 mSystemFonts.reserve( fontSet->nfont );
1887 for( int i = 0u; i < fontSet->nfont; ++i )
1889 FcPattern* fontPattern = fontSet->fonts[i];
1893 // Skip fonts with no path
1894 if( GetFcString( fontPattern, FC_FILE, path ) )
1896 mSystemFonts.push_back( FontDescription() );
1897 FontDescription& fontDescription = mSystemFonts.back();
1899 fontDescription.path = std::move( path );
1904 GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
1905 GetFcInt( fontPattern, FC_WIDTH, width );
1906 GetFcInt( fontPattern, FC_WEIGHT, weight );
1907 GetFcInt( fontPattern, FC_SLANT, slant );
1908 fontDescription.width = IntToWidthType( width );
1909 fontDescription.weight = IntToWeightType( weight );
1910 fontDescription.slant = IntToSlantType( slant );
1912 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", fontDescription.family.c_str() );
1913 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1914 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1915 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1916 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1920 // Destroys the font set created.
1921 FcFontSetDestroy( fontSet );
1923 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::InitSystemFonts\n" );
1926 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet )
1928 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1930 FcResult result = FcResultMatch;
1931 FcPattern* match = FcFontMatch( nullptr /* use default configure */, pattern, &result ); // Creates a new font pattern that needs to be destroyed by calling FcPatternDestroy.
1933 const bool matched = nullptr != match;
1934 DALI_LOG_INFO( gLogFilter, Debug::General, " pattern matched : %s\n", ( matched ? "true" : "false" ) );
1941 GetFcString( match, FC_FILE, fontDescription.path );
1942 GetFcString( match, FC_FAMILY, fontDescription.family );
1943 GetFcInt( match, FC_WIDTH, width );
1944 GetFcInt( match, FC_WEIGHT, weight );
1945 GetFcInt( match, FC_SLANT, slant );
1946 fontDescription.width = IntToWidthType( width );
1947 fontDescription.weight = IntToWeightType( weight );
1948 fontDescription.slant = IntToSlantType( slant );
1950 // Retrieve the character set and increase the reference counter.
1951 FcPatternGetCharSet( match, FC_CHARSET, 0u, characterSet );
1952 *characterSet = FcCharSetCopy( *characterSet );
1954 // destroyed the matched pattern
1955 FcPatternDestroy( match );
1957 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
1958 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1959 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1960 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1961 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1964 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1968 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription ) const
1970 // create the cached font family lookup pattern
1971 // a pattern holds a set of names, each name refers to a property of the font
1972 FcPattern* fontFamilyPattern = FcPatternCreate(); // FcPatternCreate creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
1974 if( !fontFamilyPattern )
1979 // add a property to the pattern for the font family
1980 FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
1982 // add a property to the pattern for local setting.
1983 const char* locale = setlocale( LC_MESSAGES, nullptr );
1984 if( locale != nullptr)
1986 FcPatternAddString( fontFamilyPattern, FC_LANG, reinterpret_cast<const FcChar8*>( locale ) );
1989 int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
1993 width = DEFAULT_FONT_WIDTH;
1996 int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
2000 weight = DEFAULT_FONT_WEIGHT;
2003 int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
2007 slant = DEFAULT_FONT_SLANT;
2010 FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
2011 FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
2012 FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
2014 // modify the config, with the mFontFamilyPatterm
2015 FcConfigSubstitute( nullptr /* use default configure */, fontFamilyPattern, FcMatchPattern );
2017 // provide default values for unspecified properties in the font pattern
2018 // e.g. patterns without a specified style or weight are set to Medium
2019 FcDefaultSubstitute( fontFamilyPattern );
2021 return fontFamilyPattern;
2024 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
2026 FcFontSet* fontset = nullptr;
2028 // create a new pattern.
2029 // a pattern holds a set of names, each name refers to a property of the font
2030 FcPattern* pattern = FcPatternCreate();
2032 if( nullptr != pattern )
2034 // create an object set used to define which properties are to be returned in the patterns from FcFontList.
2035 FcObjectSet* objectSet = FcObjectSetCreate();
2037 if( nullptr != objectSet )
2039 // build an object set from a list of property names
2040 FcObjectSetAdd( objectSet, FC_FILE );
2041 FcObjectSetAdd( objectSet, FC_FAMILY );
2042 FcObjectSetAdd( objectSet, FC_WIDTH );
2043 FcObjectSetAdd( objectSet, FC_WEIGHT );
2044 FcObjectSetAdd( objectSet, FC_SLANT );
2046 // get a list of fonts
2047 // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
2048 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.
2050 // clear up the object set
2051 FcObjectSetDestroy( objectSet );
2054 // clear up the pattern
2055 FcPatternDestroy( pattern );
2061 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
2062 const char* const n,
2063 std::string& string )
2065 FcChar8* file = nullptr;
2066 const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
2068 if( FcResultMatch == retVal )
2070 // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
2071 string.assign( reinterpret_cast<const char*>( file ) );
2079 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
2081 const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
2083 if( FcResultMatch == retVal )
2091 FontId FontClient::Plugin::CreateFont( const FontPath& path,
2092 PointSize26Dot6 requestedPointSize,
2093 FaceIndex faceIndex,
2094 bool cacheDescription )
2096 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::CreateFont\n" );
2097 DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() );
2098 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
2102 // Create & cache new font face
2104 int error = FT_New_Face( mFreeTypeLibrary,
2109 if( FT_Err_Ok == error )
2111 // Check if a font is scalable.
2112 const bool isScalable = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_SCALABLE ) );
2113 const bool hasFixedSizedBitmaps = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) && ( 0 != ftFace->num_fixed_sizes );
2114 const bool hasColorTables = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_COLOR ) );
2115 FontId fontFaceId = 0u;
2117 DALI_LOG_INFO( gLogFilter, Debug::General, " isScalable : [%s]\n", ( isScalable ? "true" : "false" ) );
2118 DALI_LOG_INFO( gLogFilter, Debug::General, " hasFixedSizedBitmaps : [%s]\n", ( hasFixedSizedBitmaps ? "true" : "false" ) );
2119 DALI_LOG_INFO( gLogFilter, Debug::General, " hasColorTables : [%s]\n", ( hasColorTables ? "true" : "false" ) );
2121 // Check to see if the font contains fixed sizes?
2122 if( !isScalable && hasFixedSizedBitmaps )
2124 PointSize26Dot6 actualPointSize = 0u;
2125 int fixedSizeIndex = 0;
2126 for( ; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex )
2128 const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
2129 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " size index : %d, size : %d\n", fixedSizeIndex, fixedSize );
2131 if( fixedSize >= requestedPointSize )
2133 actualPointSize = fixedSize;
2138 if( 0u == actualPointSize )
2140 // The requested point size is bigger than the bigest fixed size.
2141 fixedSizeIndex = ftFace->num_fixed_sizes - 1;
2142 actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
2145 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize );
2147 // Tell Freetype to use this size
2148 error = FT_Select_Size( ftFace, fixedSizeIndex );
2149 if ( FT_Err_Ok != error )
2151 DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Select_Size error: %d\n", error );
2155 const float fixedWidth = static_cast<float>( ftFace->available_sizes[ fixedSizeIndex ].width );
2156 const float fixedHeight = static_cast<float>( ftFace->available_sizes[ fixedSizeIndex ].height );
2158 // Indicate that the font is a fixed sized bitmap
2159 FontMetrics metrics( fixedHeight, // The ascender in pixels.
2161 fixedHeight, // The height in pixels.
2165 // Create the FreeType font face item to cache.
2166 FontFaceCacheItem fontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedSizeIndex, fixedWidth, fixedHeight, hasColorTables );
2168 // Set the index to the font's id cache.
2169 fontFaceCacheItem.mFontId = mFontIdCache.Count();
2171 // Create the font id item to cache.
2172 FontIdCacheItem fontIdCacheItem;
2173 fontIdCacheItem.type = FontDescription::FACE_FONT;
2175 // Set the index to the FreeType font face cache.
2176 fontIdCacheItem.id = mFontFaceCache.size();
2177 fontFaceId = fontIdCacheItem.id + 1u;
2180 mFontFaceCache.push_back( fontFaceCacheItem );
2181 mFontIdCache.PushBack( fontIdCacheItem );
2183 // Set the font id to be returned.
2184 id = mFontIdCache.Count();
2189 error = FT_Set_Char_Size( ftFace,
2195 if( FT_Err_Ok == error )
2198 FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
2200 FontMetrics metrics( static_cast< float >( ftMetrics.ascender ) * FROM_266,
2201 static_cast< float >( ftMetrics.descender ) * FROM_266,
2202 static_cast< float >( ftMetrics.height ) * FROM_266,
2203 static_cast< float >( ftFace->underline_position ) * FROM_266,
2204 static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
2206 // Create the FreeType font face item to cache.
2207 FontFaceCacheItem fontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics );
2209 // Set the index to the font's id cache.
2210 fontFaceCacheItem.mFontId = mFontIdCache.Count();
2212 // Create the font id item to cache.
2213 FontIdCacheItem fontIdCacheItem;
2214 fontIdCacheItem.type = FontDescription::FACE_FONT;
2216 // Set the index to the FreeType font face cache.
2217 fontIdCacheItem.id = mFontFaceCache.size();
2218 fontFaceId = fontIdCacheItem.id + 1u;
2221 mFontFaceCache.push_back( fontFaceCacheItem );
2222 mFontIdCache.PushBack( fontIdCacheItem );
2224 // Set the font id to be returned.
2225 id = mFontIdCache.Count();
2229 DALI_LOG_INFO( gLogFilter, Debug::General, " FreeType Set_Char_Size error: %d for pointSize %d\n", error, requestedPointSize );
2233 if( 0u != fontFaceId )
2235 if( cacheDescription )
2237 CacheFontPath( ftFace, fontFaceId, requestedPointSize, path );
2243 DALI_LOG_INFO( gLogFilter, Debug::General, " FreeType New_Face error: %d for [%s]\n", error, path.c_str() );
2246 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
2247 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::CreateFont\n" );
2252 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, unsigned int srcWidth, unsigned int srcHeight, const unsigned char* const srcBuffer )
2254 // Set the input dimensions.
2255 const ImageDimensions inputDimensions( srcWidth, srcHeight );
2257 // Set the output dimensions.
2258 // If the output dimension is not given, the input dimension is set
2259 // and won't be downscaling.
2260 data.width = ( data.width == 0 ) ? srcWidth : data.width;
2261 data.height = ( data.height == 0 ) ? srcHeight : data.height;
2262 const ImageDimensions desiredDimensions( data.width, data.height );
2264 // Creates the output buffer
2265 const unsigned int bufferSize = data.width * data.height * 4u;
2266 data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
2268 if( inputDimensions == desiredDimensions )
2270 // There isn't downscaling.
2271 memcpy( data.buffer, srcBuffer, bufferSize );
2275 Dali::Internal::Platform::LanczosSample4BPP( srcBuffer,
2278 desiredDimensions );
2282 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap, bool isShearRequired )
2284 if( srcBitmap.width*srcBitmap.rows > 0 )
2286 switch( srcBitmap.pixel_mode )
2288 case FT_PIXEL_MODE_GRAY:
2290 if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
2292 uint8_t* pixelsIn = srcBitmap.buffer;
2293 unsigned int width = srcBitmap.width;
2294 unsigned height = srcBitmap.rows;
2296 std::unique_ptr<uint8_t, void(*)(void*)> pixelsOutPtr( nullptr, free );
2298 if( isShearRequired )
2301 * Glyphs' bitmaps with no slant retrieved from FreeType:
2311 * Expected glyphs' bitmaps with italic slant:
2312 * ____________ ______
2319 * ------------ ------
2321 * Glyphs' bitmaps with software italic slant retrieved from FreeType:
2331 * 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.
2333 unsigned int widthOut = 0u;
2334 unsigned int heightOut = 0u;
2335 uint8_t* pixelsOut = nullptr;
2337 Dali::Internal::Platform::HorizontalShear( pixelsIn,
2341 -TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE,
2348 pixelsIn = pixelsOut;
2349 pixelsOutPtr.reset( pixelsOut );
2352 const unsigned int bufferSize = width * height;
2353 data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
2355 data.height = height;
2356 data.format = Pixel::L8; // Sets the pixel format.
2357 memcpy( data.buffer, pixelsIn, bufferSize );
2362 #ifdef FREETYPE_BITMAP_SUPPORT
2363 case FT_PIXEL_MODE_BGRA:
2365 if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
2367 ConvertBitmap( data, srcBitmap.width, srcBitmap.rows, srcBitmap.buffer );
2369 // Sets the pixel format.
2370 data.format = Pixel::BGRA8888;
2377 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::ConvertBitmap. FontClient Unable to create Bitmap of this PixelType\n" );
2384 bool FontClient::Plugin::FindFont( const FontPath& path,
2385 PointSize26Dot6 requestedPointSize,
2386 FaceIndex faceIndex,
2387 FontId& fontId ) const
2389 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
2390 DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() );
2391 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
2392 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of fonts in the cache : %d\n", mFontFaceCache.size() );
2395 for( const auto& cacheItem : mFontFaceCache )
2397 if( cacheItem.mRequestedPointSize == requestedPointSize &&
2398 cacheItem.mFaceIndex == faceIndex &&
2399 cacheItem.mPath == path )
2401 fontId = cacheItem.mFontId + 1u;
2403 DALI_LOG_INFO( gLogFilter, Debug::General, " font found, id : %d\n", fontId );
2404 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
2410 DALI_LOG_INFO( gLogFilter, Debug::General, " font not found\n" );
2411 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
2416 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
2417 FontDescriptionId& validatedFontId )
2419 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindValidatedFont\n" );
2420 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
2421 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
2422 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
2423 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
2424 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
2425 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of validated fonts in the cache : %d\n", mValidatedFontCache.size() );
2427 validatedFontId = 0u;
2429 for( const auto& item : mValidatedFontCache )
2431 if( !fontDescription.family.empty() &&
2432 ( fontDescription.family == item.fontDescription.family ) &&
2433 ( fontDescription.width == item.fontDescription.width ) &&
2434 ( fontDescription.weight == item.fontDescription.weight ) &&
2435 ( fontDescription.slant == item.fontDescription.slant ) )
2437 validatedFontId = item.index;
2439 DALI_LOG_INFO( gLogFilter, Debug::General, " validated font found, id : %d\n", validatedFontId );
2440 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
2445 DALI_LOG_INFO( gLogFilter, Debug::General, " validated font not found\n" );
2446 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
2450 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
2451 FontList*& fontList,
2452 CharacterSetList*& characterSetList )
2454 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFontList\n" );
2455 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
2456 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
2457 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
2458 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
2459 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
2460 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of fallback font lists in the cache : %d\n", mFallbackCache.size() );
2464 for( const auto& item : mFallbackCache )
2466 if( !fontDescription.family.empty() &&
2467 ( fontDescription.family == item.fontDescription.family ) &&
2468 ( fontDescription.width == item.fontDescription.width ) &&
2469 ( fontDescription.weight == item.fontDescription.weight ) &&
2470 ( fontDescription.slant == item.fontDescription.slant ) )
2472 fontList = item.fallbackFonts;
2473 characterSetList = item.characterSets;
2475 DALI_LOG_INFO( gLogFilter, Debug::General, " fallback font list found.\n" );
2476 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
2481 DALI_LOG_INFO( gLogFilter, Debug::General, " fallback font list not found.\n" );
2482 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
2486 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
2487 PointSize26Dot6 requestedPointSize,
2490 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
2491 DALI_LOG_INFO( gLogFilter, Debug::General, " validatedFontId : %d\n", validatedFontId );
2492 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
2496 for( const auto& item : mFontDescriptionSizeCache )
2498 if( ( validatedFontId == item.validatedFontId ) &&
2499 ( requestedPointSize == item.requestedPointSize ) )
2501 fontId = item.fontId;
2503 DALI_LOG_INFO( gLogFilter, Debug::General, " font found, id : %d\n", fontId );
2504 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
2509 DALI_LOG_INFO( gLogFilter, Debug::General, " font not found.\n" );
2510 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
2514 bool FontClient::Plugin::FindBitmapFont( const FontFamily& bitmapFont, FontId& fontId ) const
2518 for( const auto& item : mBitmapFontCache )
2520 if( bitmapFont == item.font.name )
2522 fontId = item.id + 1u;
2530 bool FontClient::Plugin::IsScalable( const FontPath& path )
2532 bool isScalable = false;
2535 int error = FT_New_Face( mFreeTypeLibrary,
2539 if( FT_Err_Ok != error )
2541 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: %s\n", path.c_str() );
2545 isScalable = ftFace->face_flags & FT_FACE_FLAG_SCALABLE;
2551 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
2553 // Create a font pattern.
2554 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription ); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
2556 FcResult result = FcResultMatch;
2558 // match the pattern
2559 FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result ); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
2560 bool isScalable = false;
2564 // Get the path to the font file name.
2566 GetFcString( match, FC_FILE, path );
2567 isScalable = IsScalable( path );
2571 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
2574 // Destroys the created patterns.
2575 FcPatternDestroy( match );
2576 FcPatternDestroy( fontFamilyPattern );
2581 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
2583 // Empty the caller container
2587 int error = FT_New_Face( mFreeTypeLibrary,
2591 if( FT_Err_Ok != error )
2593 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font path : [%s]\n", path.c_str() );
2596 // Fetch the number of fixed sizes available
2597 if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
2599 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
2601 sizes.PushBack( ftFace->available_sizes[ i ].size );
2606 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
2607 Vector< PointSize26Dot6 >& sizes )
2609 // Create a font pattern.
2610 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription ); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
2612 FcResult result = FcResultMatch;
2614 // match the pattern
2615 FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result ); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
2619 // Get the path to the font file name.
2621 GetFcString( match, FC_FILE, path );
2622 GetFixedSizes( path, sizes );
2626 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
2629 // Destroys the created patterns.
2630 FcPatternDestroy( match );
2631 FcPatternDestroy( fontFamilyPattern );
2634 bool FontClient::Plugin::HasItalicStyle( FontId fontId ) const
2636 bool hasItalicStyle = false;
2638 const FontId index = fontId - 1u;
2640 if( ( fontId > 0 ) &&
2641 ( index < mFontIdCache.Count() ) )
2643 const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
2645 if( FontDescription::FACE_FONT == fontIdCacheItem.type )
2647 const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
2649 hasItalicStyle = 0u != ( font.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC );
2654 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId );
2657 return hasItalicStyle;
2660 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize, const FontPath& path )
2662 FontDescription description;
2663 description.path = path;
2664 description.family = std::move( FontFamily( ftFace->family_name ) );
2665 description.weight = FontWeight::NONE;
2666 description.width = FontWidth::NONE;
2667 description.slant = FontSlant::NONE;
2669 // Note FreeType doesn't give too much info to build a proper font style.
2670 if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
2672 description.slant = FontSlant::ITALIC;
2674 if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
2676 description.weight = FontWeight::BOLD;
2679 FontDescriptionId validatedFontId = 0u;
2680 if( !FindValidatedFont( description,
2683 FcPattern* pattern = CreateFontFamilyPattern( description ); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
2685 FcResult result = FcResultMatch;
2686 FcPattern* match = FcFontMatch( nullptr, pattern, &result ); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
2688 FcCharSet* characterSet = nullptr;
2689 FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
2691 const FontId fontFaceId = id - 1u;
2692 mFontFaceCache[fontFaceId].mCharacterSet = FcCharSetCopy( characterSet ); // Increases the reference counter.
2694 // Destroys the created patterns.
2695 FcPatternDestroy( match );
2696 FcPatternDestroy( pattern );
2698 // Add the path to the cache.
2699 description.type = FontDescription::FACE_FONT;
2700 mFontDescriptionCache.push_back( description );
2702 // Set the index to the vector of paths to font file names.
2703 validatedFontId = mFontDescriptionCache.size();
2705 // Increase the reference counter and add the character set to the cache.
2706 mCharacterSetCache.PushBack( FcCharSetCopy( characterSet ) );
2708 // Cache the index and the font's description.
2709 mValidatedFontCache.push_back( std::move( FontDescriptionCacheItem( std::move( description ),
2710 validatedFontId) ) );
2712 // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
2713 mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
2719 FcCharSet* FontClient::Plugin::CreateCharacterSetFromDescription( const FontDescription& description )
2721 FcCharSet* characterSet = nullptr;
2723 FcPattern* pattern = CreateFontFamilyPattern( description ); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
2725 if( nullptr != pattern )
2727 FcResult result = FcResultMatch;
2728 FcPattern* match = FcFontMatch( nullptr, pattern, &result ); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
2730 FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
2732 // Destroys the created patterns.
2733 FcPatternDestroy( match );
2734 FcPatternDestroy( pattern );
2737 return characterSet;
2740 void FontClient::Plugin::ClearFallbackCache( std::vector<FallbackCacheItem>& fallbackCache )
2742 for( auto& item : fallbackCache )
2744 if( nullptr != item.fallbackFonts )
2746 delete item.fallbackFonts;
2749 if( nullptr != item.characterSets )
2751 // Free the resources allocated by the FcCharSet objects in the 'characterSets' vector.
2752 DestroyCharacterSets( *item.characterSets );
2753 delete item.characterSets;
2758 void FontClient::Plugin::ClearCharacterSetFromFontFaceCache()
2760 for( auto& item : mFontFaceCache )
2762 FcCharSetDestroy( item.mCharacterSet );
2763 item.mCharacterSet = nullptr;
2767 } // namespace Internal
2769 } // namespace TextAbstraction