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-abstraction/font-client-plugin-impl.h>
22 #include <dali/devel-api/text-abstraction/font-list.h>
24 #include <dali/public-api/common/dali-vector.h>
25 #include <dali/public-api/common/vector-wrapper.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/integration-api/platform-abstraction.h>
28 #include <dali/internal/text-abstraction/font-client-helper.h>
29 #include <platform-abstractions/portable/image-operations.h>
30 #include <adaptor-impl.h>
33 #include <fontconfig/fontconfig.h>
38 #if defined(DEBUG_ENABLED)
39 Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
43 * Conversion from Fractional26.6 to float
45 const float FROM_266 = 1.0f / 64.0f;
46 const float POINTS_PER_INCH = 72.f;
47 const FT_Fixed FONT_SLANT_TANGENT = 0.221694663 * 0x10000; // For support software italic
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 ) );
145 FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( FontDescription&& font, FontList* fallbackFonts, CharacterSetList* characterSets )
146 : fontDescription{ std::move( font ) },
147 fallbackFonts{ fallbackFonts },
148 characterSets{ characterSets }
152 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
153 FontDescriptionId index )
154 : fontDescription{ fontDescription },
159 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( FontDescription&& fontDescription,
160 FontDescriptionId index )
161 : fontDescription{ std::move( fontDescription ) },
166 FontClient::Plugin::FontDescriptionSizeCacheItem::FontDescriptionSizeCacheItem( FontDescriptionId validatedFontId,
167 PointSize26Dot6 requestedPointSize,
169 : validatedFontId( validatedFontId ),
170 requestedPointSize( requestedPointSize ),
175 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
176 const FontPath& path,
177 PointSize26Dot6 requestedPointSize,
179 const FontMetrics& metrics )
180 : mFreeTypeFace( ftFace ),
182 mRequestedPointSize( requestedPointSize ),
185 mCharacterSet( nullptr ),
186 mFixedWidthPixels( 0.0f ),
187 mFixedHeightPixels( 0.0f ),
189 mIsFixedSizeBitmap( false ),
190 mHasColorTables( false )
194 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
195 const FontPath& path,
196 PointSize26Dot6 requestedPointSize,
198 const FontMetrics& metrics,
201 bool hasColorTables )
202 : mFreeTypeFace( ftFace ),
204 mRequestedPointSize( requestedPointSize ),
207 mCharacterSet( nullptr ),
208 mFixedWidthPixels( fixedWidth ),
209 mFixedHeightPixels( fixedHeight ),
211 mIsFixedSizeBitmap( true ),
212 mHasColorTables( hasColorTables )
216 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
217 unsigned int verticalDpi )
218 : mFreeTypeLibrary( nullptr ),
219 mDpiHorizontal( horizontalDpi ),
220 mDpiVertical( verticalDpi ),
221 mDefaultFontDescription(),
225 mValidatedFontCache(),
226 mFontDescriptionCache( 1u ),
227 mCharacterSetCache(),
228 mFontDescriptionSizeCache(),
229 mVectorFontCache( nullptr ),
231 mDefaultFontDescriptionCached( false )
233 mCharacterSetCache.Resize( 1u );
235 int error = FT_Init_FreeType( &mFreeTypeLibrary );
236 if( FT_Err_Ok != error )
238 DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Init error: %d\n", error );
241 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
242 mVectorFontCache = new VectorFontCache( mFreeTypeLibrary );
247 FontClient::Plugin::~Plugin()
249 for( auto& item : mFallbackCache )
251 if( item.fallbackFonts )
253 delete item.fallbackFonts;
254 delete item.characterSets;
255 item.fallbackFonts = nullptr;
256 item.characterSets = nullptr;
260 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
261 delete mVectorFontCache;
263 DestroyMatchedPatterns();
264 FT_Done_FreeType( mFreeTypeLibrary );
267 void FontClient::Plugin::ClearCache()
269 mFontFaceCache.clear();
270 mValidatedFontCache.clear();
271 mFontDescriptionCache.clear();
272 mFontDescriptionCache.resize( 1u );
274 mCharacterSetCache.Clear();
275 mCharacterSetCache.Resize( 1u );
277 mFontDescriptionSizeCache.clear();
278 mFallbackCache.clear();
280 mEllipsisCache.Clear();
281 mSystemFonts.clear();
282 mDefaultFonts.clear();
283 mDefaultFontDescriptionCached = false;
284 mDefaultFontCharacterSets.Clear();
285 mDefaultFontDescription = FontDescription();
286 DestroyMatchedPatterns();
289 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
290 unsigned int verticalDpi )
292 mDpiHorizontal = horizontalDpi;
293 mDpiVertical = verticalDpi;
296 void FontClient::Plugin::ResetSystemDefaults()
298 mDefaultFontDescriptionCached = false;
301 void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList )
303 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::SetFontList\n" );
304 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
305 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
306 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
307 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
311 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
313 FcResult result = FcResultMatch;
315 // Match the pattern.
316 FcFontSet* fontSet = FcFontSort( nullptr /* use default configure */,
318 false /* don't trim */,
322 if( nullptr != fontSet )
324 DALI_LOG_INFO( gLogFilter, Debug::General, " number of fonts found : [%d]\n", fontSet->nfont );
325 // Reserve some space to avoid reallocations.
326 fontList.reserve( fontSet->nfont );
328 for( int i = 0u; i < fontSet->nfont; ++i )
330 FcPattern* fontPattern = fontSet->fonts[i];
334 // Skip fonts with no path
335 if( GetFcString( fontPattern, FC_FILE, path ) )
337 FcCharSet* characterSet = nullptr;
338 FcPatternGetCharSet( fontPattern, FC_CHARSET, 0u, &characterSet );
340 characterSetList.PushBack( characterSet );
341 fontList.push_back( FontDescription() );
342 FontDescription& newFontDescription = fontList.back();
344 newFontDescription.path = std::move( path );
349 GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
350 GetFcInt( fontPattern, FC_WIDTH, width );
351 GetFcInt( fontPattern, FC_WEIGHT, weight );
352 GetFcInt( fontPattern, FC_SLANT, slant );
353 newFontDescription.width = IntToWidthType( width );
354 newFontDescription.weight = IntToWeightType( weight );
355 newFontDescription.slant = IntToSlantType( slant );
357 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", newFontDescription.family.c_str() );
358 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", newFontDescription.path.c_str() );
359 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[newFontDescription.width] );
360 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[newFontDescription.weight] );
361 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[newFontDescription.slant] );
365 FcFontSetDestroy( fontSet );
369 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " No fonts found.\n" );
372 FcPatternDestroy( fontFamilyPattern );
373 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::SetFontList\n" );
376 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
378 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultFonts\n" );
380 if( mDefaultFonts.empty() )
382 FontDescription fontDescription;
383 fontDescription.family = DEFAULT_FONT_FAMILY_NAME; // todo This could be set to the Platform font
384 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
385 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
386 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
387 SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
390 defaultFonts = mDefaultFonts;
392 DALI_LOG_INFO( gLogFilter, Debug::General, " number of default fonts : [%d]\n", mDefaultFonts.size() );
393 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultFonts\n" );
396 void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
398 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultPlatformFontDescription\n");
400 if( !mDefaultFontDescriptionCached )
402 // Clear any font config stored info in the caches.
403 mDefaultFontCharacterSets.Clear();
404 mCharacterSetCache.Clear();
406 for( auto& item : mFallbackCache )
408 item.characterSets->Clear();
411 for( auto& item : mFontFaceCache )
413 // Set the character set pointer as null. Will be created again the next time IsCharacterSupportedByFont()
414 item.mCharacterSet = nullptr;
417 // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
418 FcInitReinitialize();
420 FcPattern* matchPattern = FcPatternCreate();
424 FcConfigSubstitute( nullptr, matchPattern, FcMatchPattern );
425 FcDefaultSubstitute( matchPattern );
427 FcCharSet* characterSet = nullptr;
428 MatchFontDescriptionToPattern( matchPattern, mDefaultFontDescription, &characterSet );
429 FcPatternDestroy( matchPattern );
432 // Create again the character sets as they are not valid after FcInitReinitialize()
434 for( const auto& description : mDefaultFonts )
436 mDefaultFontCharacterSets.PushBack( CreateCharacterSetFromDescription( description ) );
439 for( const auto& description : mFontDescriptionCache )
441 mCharacterSetCache.PushBack( CreateCharacterSetFromDescription( description ) );
444 for( auto& item : mFallbackCache )
446 if( nullptr != item.fallbackFonts )
448 if( nullptr == item.characterSets )
450 item.characterSets = new CharacterSetList;
453 for( const auto& description : *( item.fallbackFonts ) )
455 item.characterSets->PushBack( CreateCharacterSetFromDescription( description ) );
460 mDefaultFontDescriptionCached = true;
463 fontDescription.path = mDefaultFontDescription.path;
464 fontDescription.family = mDefaultFontDescription.family;
465 fontDescription.width = mDefaultFontDescription.width;
466 fontDescription.weight = mDefaultFontDescription.weight;
467 fontDescription.slant = mDefaultFontDescription.slant;
469 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
470 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
471 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
472 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
473 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
474 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultPlatformFontDescription\n");
477 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
479 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetSystemFonts\n");
481 if( mSystemFonts.empty() )
486 systemFonts = mSystemFonts;
487 DALI_LOG_INFO( gLogFilter, Debug::General, " number of system fonts : [%d]\n", mSystemFonts.size() );
488 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetSystemFonts\n");
491 void FontClient::Plugin::GetDescription( FontId id,
492 FontDescription& fontDescription ) const
494 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDescription\n");
495 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
497 for( const auto& item : mFontDescriptionSizeCache )
499 if( item.fontId == id )
501 fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
503 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
504 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
505 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
506 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
507 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
508 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
513 DALI_LOG_INFO( gLogFilter, Debug::General, " No description found for the font ID %d\n", id );
514 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
517 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
519 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetPointSize\n");
520 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
521 const FontId index = id - 1u;
524 ( index < mFontFaceCache.size() ) )
526 DALI_LOG_INFO( gLogFilter, Debug::General, " point size : %d\n", ( *( mFontFaceCache.begin() + index ) ).mRequestedPointSize );
527 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
528 return ( *( mFontFaceCache.begin() + index ) ).mRequestedPointSize;
532 DALI_LOG_INFO( gLogFilter, Debug::General, " Invalid font ID %d\n", id );
535 DALI_LOG_INFO( gLogFilter, Debug::General, " default point size : %d\n", TextAbstraction::FontClient::DEFAULT_POINT_SIZE );
536 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
537 return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
540 bool FontClient::Plugin::IsCharacterSupportedByFont( FontId fontId, Character character )
542 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::IsCharacterSupportedByFont\n");
543 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
544 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", character );
546 if( ( fontId < 1u ) || ( fontId > mFontFaceCache.size() ) )
548 DALI_LOG_INFO( gLogFilter, Debug::General, " Invalid font id. Number of items in the cache: %d\n",mFontFaceCache.size());
549 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
555 bool isSupported = false;
557 FontFaceCacheItem& cacheItem = mFontFaceCache[fontId];
559 if( nullptr == cacheItem.mCharacterSet )
561 // Create again the character set.
562 // It can be null if the ResetSystemDefaults() method has been called.
564 FontDescription description;
565 description.path = cacheItem.mPath;
566 description.family = std::move( FontFamily( cacheItem.mFreeTypeFace->family_name ) );
567 description.weight = FontWeight::NONE;
568 description.width = FontWidth::NONE;
569 description.slant = FontSlant::NONE;
571 // Note FreeType doesn't give too much info to build a proper font style.
572 if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC )
574 description.slant = FontSlant::ITALIC;
576 if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_BOLD )
578 description.weight = FontWeight::BOLD;
581 cacheItem.mCharacterSet = CreateCharacterSetFromDescription( description );
584 isSupported = FcCharSetHasChar( cacheItem.mCharacterSet, character );
586 DALI_LOG_INFO( gLogFilter, Debug::General, " is supported : %s\n", (isSupported ? "true" : "false") );
587 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
591 FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
592 const CharacterSetList& characterSetList,
594 PointSize26Dot6 requestedPointSize,
597 DALI_ASSERT_DEBUG( ( fontList.size() == characterSetList.Count() ) && "FontClient::Plugin::FindFontForCharacter. Different number of fonts and character sets." );
599 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFontForCharacter\n" );
600 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", character );
601 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
602 DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) );
605 bool foundColor = false;
607 DALI_LOG_INFO( gLogFilter, Debug::General, " number of fonts : %d\n", fontList.size() );
609 // Traverse the list of fonts.
610 // Check for each font if supports the character.
611 for( unsigned int index = 0u, numberOfFonts = fontList.size(); index < numberOfFonts; ++index )
613 const FontDescription& description = fontList[index];
614 const FcCharSet* const characterSet = characterSetList[index];
616 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", description.family.c_str() );
617 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", description.path.c_str() );
618 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[description.width] );
619 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[description.weight] );
620 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[description.slant] );
622 bool foundInRanges = false;
623 if( nullptr != characterSet )
625 foundInRanges = FcCharSetHasChar( characterSet, character );
630 fontId = GetFontId( description,
634 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " font id : %d\n", fontId );
638 if( ( fontId > 0 ) &&
639 ( fontId - 1u < mFontFaceCache.size() ) )
641 const FontFaceCacheItem& item = mFontFaceCache[fontId - 1u];
643 foundColor = item.mHasColorTables;
646 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " foundColor : %s\n", ( foundColor ? "true" : "false" ) );
649 // Keep going unless we prefer a different (color) font.
650 if( !preferColor || foundColor )
657 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
658 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFontForCharacter\n" );
662 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
663 PointSize26Dot6 requestedPointSize,
666 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindDefaultFont\n" );
667 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", charcode );
668 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
669 DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) );
673 // Create the list of default fonts if it has not been created.
674 if( mDefaultFonts.empty() )
676 FontDescription fontDescription;
677 fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
678 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
679 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
680 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
682 SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
684 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of default fonts : %d\n", mDefaultFonts.size() );
687 // Traverse the list of default fonts.
688 // Check for each default font if supports the character.
689 fontId = FindFontForCharacter( mDefaultFonts, mDefaultFontCharacterSets, charcode, requestedPointSize, preferColor );
691 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
692 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindDefaultFont\n" );
697 FontId FontClient::Plugin::FindFallbackFont( Character charcode,
698 const FontDescription& preferredFontDescription,
699 PointSize26Dot6 requestedPointSize,
702 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFont\n" );
703 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", charcode );
704 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
705 DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) );
707 // The font id to be returned.
710 FontDescription fontDescription;
712 // Fill the font description with the preferred font description and complete with the defaults.
713 fontDescription.family = preferredFontDescription.family.empty() ? DEFAULT_FONT_FAMILY_NAME : preferredFontDescription.family;
714 fontDescription.weight = ( ( FontWeight::NONE == preferredFontDescription.weight ) ? IntToWeightType( DEFAULT_FONT_WEIGHT ) : preferredFontDescription.weight );
715 fontDescription.width = ( ( FontWidth::NONE == preferredFontDescription.width ) ? IntToWidthType( DEFAULT_FONT_WIDTH ) : preferredFontDescription.width );
716 fontDescription.slant = ( ( FontSlant::NONE == preferredFontDescription.slant ) ? IntToSlantType( DEFAULT_FONT_SLANT ) : preferredFontDescription.slant );
718 DALI_LOG_INFO( gLogFilter, Debug::General, " preferredFontDescription --> fontDescription\n" );
719 DALI_LOG_INFO( gLogFilter, Debug::General, " [%s] --> [%s]\n", preferredFontDescription.family.c_str(), fontDescription.family.c_str() );
720 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontWeight::Name[preferredFontDescription.weight], FontWeight::Name[fontDescription.weight] );
721 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontWidth::Name[preferredFontDescription.width], FontWidth::Name[fontDescription.width] );
722 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontSlant::Name[preferredFontDescription.slant], FontSlant::Name[fontDescription.slant] );
724 // Check first if the font's description has been queried before.
725 FontList* fontList = nullptr;
726 CharacterSetList* characterSetList = nullptr;
728 if( !FindFallbackFontList( fontDescription, fontList, characterSetList ) )
730 fontList = new FontList;
731 characterSetList = new CharacterSetList;
733 SetFontList( fontDescription, *fontList, *characterSetList );
735 // Add the font-list to the cache.
736 mFallbackCache.push_back( std::move( FallbackCacheItem( std::move( fontDescription ), fontList, characterSetList ) ) );
739 if( fontList && characterSetList )
741 fontId = FindFontForCharacter( *fontList, *characterSetList, charcode, requestedPointSize, preferColor );
744 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
745 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFont\n");
749 FontId FontClient::Plugin::GetFontId( const FontPath& path,
750 PointSize26Dot6 requestedPointSize,
752 bool cacheDescription )
754 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
755 DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() );
756 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
760 if( nullptr != mFreeTypeLibrary )
763 if( FindFont( path, requestedPointSize, faceIndex, foundId ) )
769 id = CreateFont( path, requestedPointSize, faceIndex, cacheDescription );
773 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
774 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
779 FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
780 PointSize26Dot6 requestedPointSize,
781 FaceIndex faceIndex )
783 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
784 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
785 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
786 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
787 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
788 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
789 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
791 // This method uses three vectors which caches:
792 // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
793 // * The path to font file names.
794 // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
796 // 1) Checks in the cache if the font's description has been validated before.
797 // If it was it gets an index to the vector with paths to font file names. Otherwise,
798 // retrieves using font config a path to a font file name which matches with the
799 // font's description. The path is stored in the cache.
801 // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
802 // font file names' exists. If exists, it gets the font id. If it doesn't it calls
803 // the GetFontId() method with the path to the font file name and the point size to
806 // The font id to be returned.
809 // Check first if the font's description have been validated before.
810 FontDescriptionId validatedFontId = 0u;
812 if( !FindValidatedFont( fontDescription,
815 // Use font config to validate the font's description.
816 ValidateFont( fontDescription,
820 // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
821 if( !FindFont( validatedFontId, requestedPointSize, fontId ) )
823 // Retrieve the font file name path.
824 const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
826 // Retrieve the font id. Do not cache the description as it has been already cached.
827 fontId = GetFontId( description.path,
832 mFontFaceCache[fontId-1u].mCharacterSet = mCharacterSetCache[validatedFontId];
834 // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
835 mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
840 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
841 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
846 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
847 FontDescriptionId& validatedFontId )
849 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::ValidateFont\n" );
850 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
851 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
852 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
853 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
854 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
856 // Create a font pattern.
857 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
859 FontDescription description;
861 FcCharSet* characterSet = nullptr;
862 bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description, &characterSet );
863 FcPatternDestroy( fontFamilyPattern );
865 if( matched && ( nullptr != characterSet ) )
867 // Set the index to the vector of paths to font file names.
868 validatedFontId = mFontDescriptionCache.size();
870 DALI_LOG_INFO( gLogFilter, Debug::General, " matched description; family : [%s]\n", description.family.c_str() );
871 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", description.path.c_str() );
872 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[description.width] );
873 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[description.weight] );
874 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[description.slant] );
875 DALI_LOG_INFO( gLogFilter, Debug::General, " validatedFontId : %d\n", validatedFontId );
877 // Add the path to the cache.
878 mFontDescriptionCache.push_back( description );
879 mCharacterSetCache.PushBack( characterSet );
881 // Cache the index and the matched font's description.
882 FontDescriptionCacheItem item( description,
885 mValidatedFontCache.push_back( std::move( item ) );
887 if( ( fontDescription.family != description.family ) ||
888 ( fontDescription.width != description.width ) ||
889 ( fontDescription.weight != description.weight ) ||
890 ( fontDescription.slant != description.slant ) )
892 // Cache the given font's description if it's different than the matched.
893 FontDescriptionCacheItem item( fontDescription,
896 mValidatedFontCache.push_back( std::move( item ) );
901 DALI_LOG_INFO( gLogFilter, Debug::General, " font validation failed for font [%s]\n", fontDescription.family.c_str() );
904 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::ValidateFont\n" );
907 void FontClient::Plugin::GetFontMetrics( FontId fontId,
908 FontMetrics& metrics )
910 if( ( fontId > 0 ) &&
911 ( fontId - 1u < mFontFaceCache.size() ) )
913 const FontFaceCacheItem& font = mFontFaceCache[fontId-1];
915 metrics = font.mMetrics;
917 // Adjust the metrics if the fixed-size font should be down-scaled
918 if( font.mIsFixedSizeBitmap )
920 const float desiredFixedSize = static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
922 if( desiredFixedSize > 0.f )
924 const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
926 metrics.ascender = floorf( metrics.ascender * scaleFactor );
927 metrics.descender = floorf( metrics.descender * scaleFactor );
928 metrics.height = floorf( metrics.height * scaleFactor );
929 metrics.underlinePosition = floorf( metrics.underlinePosition * scaleFactor );
930 metrics.underlineThickness = floorf( metrics.underlineThickness * scaleFactor );
936 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId );
940 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
943 GlyphIndex index = 0u;
945 if( ( fontId > 0u ) &&
946 ( fontId - 1u < mFontFaceCache.size() ) )
948 FT_Face ftFace = mFontFaceCache[fontId-1u].mFreeTypeFace;
950 index = FT_Get_Char_Index( ftFace, charcode );
956 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
961 if( VECTOR_GLYPH == type )
963 return GetVectorMetrics( array, size, horizontal );
966 return GetBitmapMetrics( array, size, horizontal );
969 bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array,
973 bool success( true );
975 for( unsigned int i=0; i<size; ++i )
977 GlyphInfo& glyph = array[i];
979 FontId fontId = glyph.fontId;
982 fontId-1 < mFontFaceCache.size() )
984 const FontFaceCacheItem& font = mFontFaceCache[fontId-1];
986 FT_Face ftFace = font.mFreeTypeFace;
988 #ifdef FREETYPE_BITMAP_SUPPORT
989 // Check to see if we should be loading a Fixed Size bitmap?
990 if ( font.mIsFixedSizeBitmap )
992 int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_COLOR );
993 if ( FT_Err_Ok == error )
995 glyph.width = font.mFixedWidthPixels;
996 glyph.height = font.mFixedHeightPixels;
997 glyph.advance = font.mFixedWidthPixels;
998 glyph.xBearing = 0.0f;
999 glyph.yBearing = font.mFixedHeightPixels;
1001 // Adjust the metrics if the fixed-size font should be down-scaled
1002 const float desiredFixedSize = static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
1004 if( desiredFixedSize > 0.f )
1006 const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
1008 glyph.width = floorf( glyph.width * scaleFactor );
1009 glyph.height = floorf( glyph.height * scaleFactor );
1010 glyph.advance = floorf( glyph.advance * scaleFactor );
1011 glyph.xBearing = floorf( glyph.xBearing * scaleFactor );
1012 glyph.yBearing = floorf( glyph.yBearing * scaleFactor );
1014 glyph.scaleFactor = scaleFactor;
1019 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetBitmapMetrics. FreeType Bitmap Load_Glyph error %d\n", error );
1026 int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_NO_AUTOHINT );
1028 if( FT_Err_Ok == error )
1030 glyph.width = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
1031 glyph.height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
1034 glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
1035 glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
1039 glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
1040 glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
1058 bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array,
1062 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
1063 bool success( true );
1065 for( unsigned int i=0; i<size; ++i )
1067 FontId fontId = array[i].fontId;
1070 fontId-1 < mFontFaceCache.size() )
1072 FontFaceCacheItem& font = mFontFaceCache[fontId-1];
1074 if( ! font.mVectorFontId )
1076 font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
1079 mVectorFontCache->GetGlyphMetrics( font.mVectorFontId, array[i] );
1081 // Vector metrics are in EMs, convert to pixels
1082 const float scale = ( static_cast<float>( font.mRequestedPointSize ) * FROM_266 ) * static_cast<float>( mDpiVertical ) / POINTS_PER_INCH;
1083 array[i].width *= scale;
1084 array[i].height *= scale;
1085 array[i].xBearing *= scale;
1086 array[i].yBearing *= scale;
1087 array[i].advance *= scale;
1101 void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool softwareItalic, bool softwareBold, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
1103 if( ( fontId > 0 ) &&
1104 ( fontId - 1u < mFontFaceCache.size() ) )
1106 FT_Face ftFace = mFontFaceCache[fontId - 1u].mFreeTypeFace;
1110 #ifdef FREETYPE_BITMAP_SUPPORT
1111 // Check to see if this is fixed size bitmap
1112 if ( mFontFaceCache[fontId - 1u].mIsFixedSizeBitmap )
1114 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1119 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_NO_AUTOHINT );
1121 if( FT_Err_Ok == error )
1127 FT_GlyphSlot_Embolden(ftFace->glyph);
1130 if( softwareItalic )
1132 // FT Matrix uses 16.16 fixed-point format
1133 FT_Matrix transform = {0x10000, FONT_SLANT_TANGENT, 0x00000, 0x10000};
1134 FT_Outline_Transform(&ftFace->glyph->outline, &transform);
1137 error = FT_Get_Glyph( ftFace->glyph, &glyph );
1139 // Convert to bitmap if necessary
1140 if ( FT_Err_Ok == error )
1142 if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
1144 // Check whether we should create a bitmap for the outline
1145 if( glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0 )
1149 error = FT_Stroker_New(mFreeTypeLibrary, &stroker );
1151 if ( FT_Err_Ok == error )
1153 FT_Stroker_Set( stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 );
1154 error = FT_Glyph_StrokeBorder( &glyph, stroker, 0, 1 );
1156 if ( FT_Err_Ok == error )
1158 FT_Stroker_Done( stroker );
1162 DALI_LOG_ERROR( "FT_Glyph_StrokeBorder Failed with error: %d\n", error );
1167 DALI_LOG_ERROR( "FT_Stroker_New Failed with error: %d\n", error );
1171 error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
1172 if ( FT_Err_Ok == error )
1174 FT_BitmapGlyph bitmapGlyph = reinterpret_cast< FT_BitmapGlyph >( glyph );
1175 ConvertBitmap( data, bitmapGlyph->bitmap );
1179 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Get_Glyph Failed with error: %d\n", error );
1184 ConvertBitmap( data, ftFace->glyph->bitmap );
1187 // Created FT_Glyph object must be released with FT_Done_Glyph
1188 FT_Done_Glyph( glyph );
1193 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Load_Glyph Failed with error: %d\n", error );
1198 PixelData FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
1200 TextAbstraction::FontClient::GlyphBufferData data;
1202 CreateBitmap( fontId, glyphIndex, false, false, data, outlineWidth );
1204 return PixelData::New( data.buffer,
1205 data.width * data.height * Pixel::GetBytesPerPixel( data.format ),
1209 PixelData::DELETE_ARRAY );
1212 void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
1217 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
1219 fontId-1 < mFontFaceCache.size() )
1221 FontFaceCacheItem& font = mFontFaceCache[fontId-1];
1223 if( ! font.mVectorFontId )
1225 font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
1228 mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
1233 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
1235 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetEllipsisGlyph\n" );
1236 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize %d.\n", requestedPointSize );
1238 // First look into the cache if there is an ellipsis glyph for the requested point size.
1239 for( const auto& item : mEllipsisCache )
1241 if( fabsf( item.requestedPointSize - requestedPointSize ) < Math::MACHINE_EPSILON_1000 )
1243 // Use the glyph in the cache.
1245 DALI_LOG_INFO( gLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index );
1246 DALI_LOG_INFO( gLogFilter, Debug::General, " font %d.\n", item.glyph.fontId );
1247 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
1253 // No glyph has been found. Create one.
1254 mEllipsisCache.PushBack( EllipsisItem() );
1255 EllipsisItem& item = *( mEllipsisCache.End() - 1u );
1257 item.requestedPointSize = requestedPointSize;
1259 // Find a font for the ellipsis glyph.
1260 item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
1264 // Set the character index to access the glyph inside the font.
1265 item.glyph.index = FT_Get_Char_Index( mFontFaceCache[item.glyph.fontId-1].mFreeTypeFace,
1266 ELLIPSIS_CHARACTER );
1268 GetBitmapMetrics( &item.glyph, 1u, true );
1270 DALI_LOG_INFO( gLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index );
1271 DALI_LOG_INFO( gLogFilter, Debug::General, " font %d.\n", item.glyph.fontId );
1272 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
1277 bool FontClient::Plugin::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
1279 FT_Error error = -1;
1281 #ifdef FREETYPE_BITMAP_SUPPORT
1282 if( ( fontId > 0 ) &&
1283 ( fontId - 1u < mFontFaceCache.size() ) )
1285 const FontFaceCacheItem& item = mFontFaceCache[fontId - 1u];
1286 FT_Face ftFace = item.mFreeTypeFace;
1288 // Check to see if this is fixed size bitmap
1289 if( item.mHasColorTables )
1291 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1296 return FT_Err_Ok == error;
1299 bool FontClient::Plugin::AddCustomFontDirectory( const FontPath& path )
1301 // nullptr as first parameter means the current configuration is used.
1302 return FcConfigAppFontAddDir( nullptr, reinterpret_cast<const FcChar8 *>( path.c_str() ) );
1305 void FontClient::Plugin::InitSystemFonts()
1307 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::InitSystemFonts\n" );
1309 FcFontSet* fontSet = GetFcFontSet();
1313 DALI_LOG_INFO( gLogFilter, Debug::General, " number of system fonts : %d\n", fontSet->nfont );
1315 // Reserve some space to avoid reallocations.
1316 mSystemFonts.reserve( fontSet->nfont );
1318 for( int i = 0u; i < fontSet->nfont; ++i )
1320 FcPattern* fontPattern = fontSet->fonts[i];
1324 // Skip fonts with no path
1325 if( GetFcString( fontPattern, FC_FILE, path ) )
1327 mSystemFonts.push_back( FontDescription() );
1328 FontDescription& fontDescription = mSystemFonts.back();
1330 fontDescription.path = std::move( path );
1335 GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
1336 GetFcInt( fontPattern, FC_WIDTH, width );
1337 GetFcInt( fontPattern, FC_WEIGHT, weight );
1338 GetFcInt( fontPattern, FC_SLANT, slant );
1339 fontDescription.width = IntToWidthType( width );
1340 fontDescription.weight = IntToWeightType( weight );
1341 fontDescription.slant = IntToSlantType( slant );
1343 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", fontDescription.family.c_str() );
1344 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1345 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1346 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1347 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1351 FcFontSetDestroy( fontSet );
1353 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::InitSystemFonts\n" );
1356 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet )
1358 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1360 FcResult result = FcResultMatch;
1361 FcPattern* match = FcFontMatch( nullptr /* use default configure */, pattern, &result );
1363 const bool matched = nullptr != match;
1364 DALI_LOG_INFO( gLogFilter, Debug::General, " pattern matched : %s\n", ( matched ? "true" : "false" ) );
1371 GetFcString( match, FC_FILE, fontDescription.path );
1372 GetFcString( match, FC_FAMILY, fontDescription.family );
1373 GetFcInt( match, FC_WIDTH, width );
1374 GetFcInt( match, FC_WEIGHT, weight );
1375 GetFcInt( match, FC_SLANT, slant );
1376 fontDescription.width = IntToWidthType( width );
1377 fontDescription.weight = IntToWeightType( weight );
1378 fontDescription.slant = IntToSlantType( slant );
1380 // Cache the character ranges.
1381 FcPatternGetCharSet( match, FC_CHARSET, 0u, characterSet );
1383 // destroyed the matched pattern
1384 FcPatternDestroy( match );
1386 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
1387 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1388 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1389 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1390 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1393 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1397 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription ) const
1399 // create the cached font family lookup pattern
1400 // a pattern holds a set of names, each name refers to a property of the font
1401 FcPattern* fontFamilyPattern = FcPatternCreate();
1403 if( !fontFamilyPattern )
1408 // add a property to the pattern for the font family
1409 FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
1411 // add a property to the pattern for local setting.
1412 const char* locale = setlocale( LC_MESSAGES, nullptr );
1413 if( locale != nullptr)
1415 FcPatternAddString( fontFamilyPattern, FC_LANG, reinterpret_cast<const FcChar8*>( locale ) );
1418 int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
1422 width = DEFAULT_FONT_WIDTH;
1425 int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
1429 weight = DEFAULT_FONT_WEIGHT;
1432 int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
1436 slant = DEFAULT_FONT_SLANT;
1439 FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
1440 FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
1441 FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
1443 // Add a property of the pattern, to say we want to match TrueType fonts
1444 FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
1446 // modify the config, with the mFontFamilyPatterm
1447 FcConfigSubstitute( nullptr /* use default configure */, fontFamilyPattern, FcMatchPattern );
1449 // provide default values for unspecified properties in the font pattern
1450 // e.g. patterns without a specified style or weight are set to Medium
1451 FcDefaultSubstitute( fontFamilyPattern );
1453 return fontFamilyPattern;
1456 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
1458 // create a new pattern.
1459 // a pattern holds a set of names, each name refers to a property of the font
1460 FcPattern* pattern = FcPatternCreate();
1462 // create an object set used to define which properties are to be returned in the patterns from FcFontList.
1463 FcObjectSet* objectSet = FcObjectSetCreate();
1465 // build an object set from a list of property names
1466 FcObjectSetAdd( objectSet, FC_FILE );
1467 FcObjectSetAdd( objectSet, FC_FAMILY );
1468 FcObjectSetAdd( objectSet, FC_WIDTH );
1469 FcObjectSetAdd( objectSet, FC_WEIGHT );
1470 FcObjectSetAdd( objectSet, FC_SLANT );
1472 // get a list of fonts
1473 // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1474 FcFontSet* fontset = FcFontList( nullptr /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
1476 // clear up the object set
1479 FcObjectSetDestroy( objectSet );
1481 // clear up the pattern
1484 FcPatternDestroy( pattern );
1490 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1491 const char* const n,
1492 std::string& string )
1494 FcChar8* file = nullptr;
1495 const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1497 if( FcResultMatch == retVal )
1499 // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1500 string.assign( reinterpret_cast<const char*>( file ) );
1508 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1510 const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1512 if( FcResultMatch == retVal )
1520 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1521 PointSize26Dot6 requestedPointSize,
1522 FaceIndex faceIndex,
1523 bool cacheDescription )
1525 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::CreateFont\n" );
1526 DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() );
1527 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
1531 // Create & cache new font face
1533 int error = FT_New_Face( mFreeTypeLibrary,
1538 if( FT_Err_Ok == error )
1540 // Check if a font is scalable.
1541 const bool isScalable = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_SCALABLE ) );
1542 const bool hasFixedSizedBitmaps = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) && ( 0 != ftFace->num_fixed_sizes );
1543 const bool hasColorTables = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_COLOR ) );
1545 DALI_LOG_INFO( gLogFilter, Debug::General, " isScalable : [%s]\n", ( isScalable ? "true" : "false" ) );
1546 DALI_LOG_INFO( gLogFilter, Debug::General, " hasFixedSizedBitmaps : [%s]\n", ( hasFixedSizedBitmaps ? "true" : "false" ) );
1547 DALI_LOG_INFO( gLogFilter, Debug::General, " hasColorTables : [%s]\n", ( hasColorTables ? "true" : "false" ) );
1549 // Check to see if the font contains fixed sizes?
1550 if( !isScalable && hasFixedSizedBitmaps )
1552 PointSize26Dot6 actualPointSize = 0u;
1553 int fixedSizeIndex = 0;
1554 for( ; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex )
1556 const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
1557 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " size index : %d, size : %d\n", fixedSizeIndex, fixedSize );
1559 if( fixedSize >= requestedPointSize )
1561 actualPointSize = fixedSize;
1566 if( 0u == actualPointSize )
1568 // The requested point size is bigger than the bigest fixed size.
1569 fixedSizeIndex = ftFace->num_fixed_sizes - 1;
1570 actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
1573 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize );
1575 // Tell Freetype to use this size
1576 error = FT_Select_Size( ftFace, fixedSizeIndex );
1577 if ( FT_Err_Ok != error )
1579 DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Select_Size error: %d\n", error );
1583 float fixedWidth = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].width );
1584 float fixedHeight = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].height );
1586 // Indicate that the font is a fixed sized bitmap
1587 FontMetrics metrics( fixedHeight, // The ascender in pixels.
1589 fixedHeight, // The height in pixels.
1593 mFontFaceCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight, hasColorTables ) );
1594 id = mFontFaceCache.size();
1599 error = FT_Set_Char_Size( ftFace,
1605 if( FT_Err_Ok == error )
1608 FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1610 FontMetrics metrics( static_cast< float >( ftMetrics.ascender ) * FROM_266,
1611 static_cast< float >( ftMetrics.descender ) * FROM_266,
1612 static_cast< float >( ftMetrics.height ) * FROM_266,
1613 static_cast< float >( ftFace->underline_position ) * FROM_266,
1614 static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1616 mFontFaceCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) );
1617 id = mFontFaceCache.size();
1621 DALI_LOG_INFO( gLogFilter, Debug::General, " FreeType Set_Char_Size error: %d for pointSize %d\n", error, requestedPointSize );
1627 if( cacheDescription )
1629 CacheFontPath( ftFace, id, requestedPointSize, path );
1635 DALI_LOG_INFO( gLogFilter, Debug::General, " FreeType New_Face error: %d for [%s]\n", error, path.c_str() );
1638 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
1639 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::CreateFont\n" );
1644 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap )
1646 if( srcBitmap.width*srcBitmap.rows > 0 )
1648 switch( srcBitmap.pixel_mode )
1650 case FT_PIXEL_MODE_GRAY:
1652 if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
1654 const unsigned int bufferSize = srcBitmap.width * srcBitmap.rows;
1655 data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1656 data.width = srcBitmap.width;
1657 data.height = srcBitmap.rows;
1658 data.format = Pixel::L8;
1659 memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1664 #ifdef FREETYPE_BITMAP_SUPPORT
1665 case FT_PIXEL_MODE_BGRA:
1667 if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
1669 // Set the input dimensions.
1670 const ImageDimensions inputDimensions( srcBitmap.width, srcBitmap.rows );
1672 // Set the output dimensions.
1673 // If the output dimension is not given, the input dimension is set
1674 // and won't be downscaling.
1675 data.width = ( data.width == 0 ) ? srcBitmap.width : data.width;
1676 data.height = ( data.height == 0 ) ? srcBitmap.rows : data.height;
1677 const ImageDimensions desiredDimensions( data.width, data.height );
1679 // Creates the output buffer
1680 const unsigned int bufferSize = data.width * data.height * 4u;
1681 data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1683 if( inputDimensions == desiredDimensions )
1685 // There isn't downscaling.
1686 memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1690 Dali::Internal::Platform::LanczosSample4BPP( srcBitmap.buffer,
1693 desiredDimensions );
1695 data.format = Pixel::BGRA8888;
1702 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::ConvertBitmap. FontClient Unable to create Bitmap of this PixelType\n" );
1709 bool FontClient::Plugin::FindFont( const FontPath& path,
1710 PointSize26Dot6 requestedPointSize,
1711 FaceIndex faceIndex,
1712 FontId& fontId ) const
1714 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1715 DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() );
1716 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
1717 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of fonts in the cache : %d\n", mFontFaceCache.size() );
1720 for( const auto& cacheItem : mFontFaceCache )
1723 if( cacheItem.mRequestedPointSize == requestedPointSize &&
1724 cacheItem.mFaceIndex == faceIndex &&
1725 cacheItem.mPath == path )
1727 DALI_LOG_INFO( gLogFilter, Debug::General, " font found, id : %d\n", fontId );
1728 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1734 DALI_LOG_INFO( gLogFilter, Debug::General, " font not found\n" );
1735 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1741 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1742 FontDescriptionId& validatedFontId )
1744 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindValidatedFont\n" );
1745 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
1746 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1747 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1748 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1749 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1750 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of validated fonts in the cache : %d\n", mValidatedFontCache.size() );
1752 validatedFontId = 0u;
1754 for( const auto& item : mValidatedFontCache )
1756 if( !fontDescription.family.empty() &&
1757 ( fontDescription.family == item.fontDescription.family ) &&
1758 ( fontDescription.width == item.fontDescription.width ) &&
1759 ( fontDescription.weight == item.fontDescription.weight ) &&
1760 ( fontDescription.slant == item.fontDescription.slant ) )
1762 validatedFontId = item.index;
1764 DALI_LOG_INFO( gLogFilter, Debug::General, " validated font found, id : %d\n", validatedFontId );
1765 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1770 DALI_LOG_INFO( gLogFilter, Debug::General, " validated font not found\n" );
1771 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1775 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1776 FontList*& fontList,
1777 CharacterSetList*& characterSetList )
1779 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFontList\n" );
1780 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
1781 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1782 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1783 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1784 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1785 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of fallback font lists in the cache : %d\n", mFallbackCache.size() );
1789 for( const auto& item : mFallbackCache )
1791 if( !fontDescription.family.empty() &&
1792 ( fontDescription.family == item.fontDescription.family ) &&
1793 ( fontDescription.width == item.fontDescription.width ) &&
1794 ( fontDescription.weight == item.fontDescription.weight ) &&
1795 ( fontDescription.slant == item.fontDescription.slant ) )
1797 fontList = item.fallbackFonts;
1798 characterSetList = item.characterSets;
1800 DALI_LOG_INFO( gLogFilter, Debug::General, " fallback font list found.\n" );
1801 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1806 DALI_LOG_INFO( gLogFilter, Debug::General, " fallback font list not found.\n" );
1807 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1811 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1812 PointSize26Dot6 requestedPointSize,
1815 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1816 DALI_LOG_INFO( gLogFilter, Debug::General, " validatedFontId : %d\n", validatedFontId );
1817 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
1821 for( const auto& item : mFontDescriptionSizeCache )
1823 if( ( validatedFontId == item.validatedFontId ) &&
1824 ( requestedPointSize == item.requestedPointSize ) )
1826 fontId = item.fontId;
1828 DALI_LOG_INFO( gLogFilter, Debug::General, " font found, id : %d\n", fontId );
1829 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1834 DALI_LOG_INFO( gLogFilter, Debug::General, " font not found.\n" );
1835 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1839 bool FontClient::Plugin::IsScalable( const FontPath& path )
1841 bool isScalable = false;
1844 int error = FT_New_Face( mFreeTypeLibrary,
1848 if( FT_Err_Ok != error )
1850 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: %s\n", path.c_str() );
1854 isScalable = ftFace->face_flags & FT_FACE_FLAG_SCALABLE;
1860 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1862 // Create a font pattern.
1863 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1865 FcResult result = FcResultMatch;
1867 // match the pattern
1868 FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result );
1869 bool isScalable = false;
1873 // Get the path to the font file name.
1875 GetFcString( match, FC_FILE, path );
1876 isScalable = IsScalable( path );
1880 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1882 FcPatternDestroy( fontFamilyPattern );
1883 FcPatternDestroy( match );
1887 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1889 // Empty the caller container
1893 int error = FT_New_Face( mFreeTypeLibrary,
1897 if( FT_Err_Ok != error )
1899 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font path : [%s]\n", path.c_str() );
1902 // Fetch the number of fixed sizes available
1903 if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1905 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1907 sizes.PushBack( ftFace->available_sizes[ i ].size );
1912 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1913 Vector< PointSize26Dot6 >& sizes )
1915 // Create a font pattern.
1916 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1918 FcResult result = FcResultMatch;
1920 // match the pattern
1921 FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result );
1925 // Get the path to the font file name.
1927 GetFcString( match, FC_FILE, path );
1928 GetFixedSizes( path, sizes );
1932 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1934 FcPatternDestroy( match );
1935 FcPatternDestroy( fontFamilyPattern );
1938 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize, const FontPath& path )
1940 FontDescription description;
1941 description.path = path;
1942 description.family = std::move( FontFamily( ftFace->family_name ) );
1943 description.weight = FontWeight::NONE;
1944 description.width = FontWidth::NONE;
1945 description.slant = FontSlant::NONE;
1947 // Note FreeType doesn't give too much info to build a proper font style.
1948 if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1950 description.slant = FontSlant::ITALIC;
1952 if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1954 description.weight = FontWeight::BOLD;
1957 FontDescriptionId validatedFontId = 0u;
1958 if( !FindValidatedFont( description,
1961 // Set the index to the vector of paths to font file names.
1962 validatedFontId = mFontDescriptionCache.size();
1964 FcPattern* pattern = CreateFontFamilyPattern( description );
1966 FcResult result = FcResultMatch;
1967 FcPattern* match = FcFontMatch( nullptr, pattern, &result );
1969 FcCharSet* characterSet = nullptr;
1970 FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
1972 FcPatternDestroy( pattern );
1974 mMatchedFcPatternCache.PushBack( match );
1976 mFontFaceCache[id-1u].mCharacterSet = characterSet;
1978 // Add the path to the cache.
1979 mFontDescriptionCache.push_back( description );
1980 mCharacterSetCache.PushBack( characterSet );
1982 // Cache the index and the font's description.
1983 mValidatedFontCache.push_back( std::move( FontDescriptionCacheItem( std::move( description ),
1984 validatedFontId) ) );
1986 // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
1987 mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
1993 FcCharSet* FontClient::Plugin::CreateCharacterSetFromDescription( const FontDescription& description )
1995 FcCharSet* characterSet = nullptr;
1997 FcPattern* pattern = CreateFontFamilyPattern( description );
1999 if( nullptr != pattern )
2001 FcResult result = FcResultMatch;
2002 FcPattern* match = FcFontMatch( nullptr, pattern, &result );
2004 FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
2006 mMatchedFcPatternCache.PushBack( match );
2008 FcPatternDestroy( pattern );
2011 return characterSet;
2014 void FontClient::Plugin::DestroyMatchedPatterns()
2016 for (auto & object : mMatchedFcPatternCache)
2018 FcPatternDestroy(reinterpret_cast<FcPattern*>(object));
2020 mMatchedFcPatternCache.Clear();
2023 } // namespace Internal
2025 } // namespace TextAbstraction