2 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/text/text-abstraction/font-client-plugin-impl.h>
22 #include <dali/devel-api/text-abstraction/font-list.h>
23 #include <dali/public-api/common/dali-vector.h>
24 #include <dali/public-api/common/vector-wrapper.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/integration-api/platform-abstraction.h>
27 #include <dali/internal/text/text-abstraction/font-client-helper.h>
28 #include <dali/internal/imaging/common/image-operations.h>
29 #include <dali/internal/adaptor/common/adaptor-impl.h>
32 #include <fontconfig/fontconfig.h>
37 #if defined(DEBUG_ENABLED)
38 Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
42 * Conversion from Fractional26.6 to float
44 const float FROM_266 = 1.0f / 64.0f;
45 const float POINTS_PER_INCH = 72.f;
46 const FT_Fixed FONT_SLANT_TANGENT = 0.221694663 * 0x10000; // For support software italic
48 const std::string FONT_FORMAT( "TrueType" );
49 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
50 const int DEFAULT_FONT_WIDTH = 100; // normal
51 const int DEFAULT_FONT_WEIGHT = 80; // normal
52 const int DEFAULT_FONT_SLANT = 0; // normal
54 const uint32_t ELLIPSIS_CHARACTER = 0x2026;
56 // http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
58 // NONE -1 --> DEFAULT_FONT_WIDTH (NORMAL) will be used.
68 const int FONT_WIDTH_TYPE_TO_INT[] = { -1, 50, 63, 75, 87, 100, 113, 125, 150, 200 };
69 const unsigned int NUM_FONT_WIDTH_TYPE = sizeof( FONT_WIDTH_TYPE_TO_INT ) / sizeof( int );
71 // NONE -1 --> DEFAULT_FONT_WEIGHT (NORMAL) will be used.
73 // ULTRA_LIGHT, EXTRA_LIGHT 40
75 // DEMI_LIGHT, SEMI_LIGHT 55
79 // DEMI_BOLD, SEMI_BOLD 180
81 // ULTRA_BOLD, EXTRA_BOLD 205
82 // BLACK, HEAVY, EXTRA_BLACK 210
83 const int FONT_WEIGHT_TYPE_TO_INT[] = { -1, 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210 };
84 const unsigned int NUM_FONT_WEIGHT_TYPE = sizeof( FONT_WEIGHT_TYPE_TO_INT ) / sizeof( int );
86 // NONE -1 --> DEFAULT_FONT_SLANT (NORMAL) will be used.
90 const int FONT_SLANT_TYPE_TO_INT[] = { -1, 0, 100, 110 };
91 const unsigned int NUM_FONT_SLANT_TYPE = sizeof( FONT_SLANT_TYPE_TO_INT ) / sizeof( int );
100 namespace TextAbstraction
107 * @brief Returns the FontWidth's enum index for the given width value.
109 * @param[in] width The width value.
111 * @return The FontWidth's enum index.
113 FontWidth::Type IntToWidthType( int width )
115 return static_cast<FontWidth::Type>( ValueToIndex( width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u ) );
119 * @brief Returns the FontWeight's enum index for the given weight value.
121 * @param[in] weight The weight value.
123 * @return The FontWeight's enum index.
125 FontWeight::Type IntToWeightType( int weight )
127 return static_cast<FontWeight::Type>( ValueToIndex( weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u ) );
131 * @brief Returns the FontSlant's enum index for the given slant value.
133 * @param[in] slant The slant value.
135 * @return The FontSlant's enum index.
137 FontSlant::Type IntToSlantType( int slant )
139 return static_cast<FontSlant::Type>( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) );
142 FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( FontDescription&& font, FontList* fallbackFonts, CharacterSetList* characterSets )
143 : fontDescription{ std::move( font ) },
144 fallbackFonts{ fallbackFonts },
145 characterSets{ characterSets }
149 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
150 FontDescriptionId index )
151 : fontDescription{ fontDescription },
156 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( FontDescription&& fontDescription,
157 FontDescriptionId index )
158 : fontDescription{ std::move( fontDescription ) },
163 FontClient::Plugin::FontDescriptionSizeCacheItem::FontDescriptionSizeCacheItem( FontDescriptionId validatedFontId,
164 PointSize26Dot6 requestedPointSize,
166 : validatedFontId( validatedFontId ),
167 requestedPointSize( requestedPointSize ),
172 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
173 const FontPath& path,
174 PointSize26Dot6 requestedPointSize,
176 const FontMetrics& metrics )
177 : mFreeTypeFace( ftFace ),
179 mRequestedPointSize( requestedPointSize ),
182 mCharacterSet( nullptr ),
183 mFixedWidthPixels( 0.0f ),
184 mFixedHeightPixels( 0.0f ),
186 mIsFixedSizeBitmap( false ),
187 mHasColorTables( false )
191 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
192 const FontPath& path,
193 PointSize26Dot6 requestedPointSize,
195 const FontMetrics& metrics,
198 bool hasColorTables )
199 : mFreeTypeFace( ftFace ),
201 mRequestedPointSize( requestedPointSize ),
204 mCharacterSet( nullptr ),
205 mFixedWidthPixels( fixedWidth ),
206 mFixedHeightPixels( fixedHeight ),
208 mIsFixedSizeBitmap( true ),
209 mHasColorTables( hasColorTables )
213 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
214 unsigned int verticalDpi )
215 : mFreeTypeLibrary( nullptr ),
216 mDpiHorizontal( horizontalDpi ),
217 mDpiVertical( verticalDpi ),
218 mDefaultFontDescription(),
222 mValidatedFontCache(),
223 mFontDescriptionCache( 1u ),
224 mCharacterSetCache(),
225 mFontDescriptionSizeCache(),
226 mVectorFontCache( nullptr ),
228 mDefaultFontDescriptionCached( false )
230 mCharacterSetCache.Resize( 1u );
232 int error = FT_Init_FreeType( &mFreeTypeLibrary );
233 if( FT_Err_Ok != error )
235 DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Init error: %d\n", error );
238 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
239 mVectorFontCache = new VectorFontCache( mFreeTypeLibrary );
243 FontClient::Plugin::~Plugin()
245 for( auto& item : mFallbackCache )
247 if( item.fallbackFonts )
249 delete item.fallbackFonts;
250 delete item.characterSets;
251 item.fallbackFonts = nullptr;
252 item.characterSets = nullptr;
256 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
257 delete mVectorFontCache;
259 DestroyMatchedPatterns();
260 FT_Done_FreeType( mFreeTypeLibrary );
263 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
264 unsigned int verticalDpi )
266 mDpiHorizontal = horizontalDpi;
267 mDpiVertical = verticalDpi;
270 void FontClient::Plugin::ResetSystemDefaults()
272 mDefaultFontDescriptionCached = false;
275 void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList )
277 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::SetFontList\n" );
278 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
279 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
280 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
281 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
285 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
287 FcResult result = FcResultMatch;
289 // Match the pattern.
290 FcFontSet* fontSet = FcFontSort( nullptr /* use default configure */,
292 false /* don't trim */,
296 if( nullptr != fontSet )
298 DALI_LOG_INFO( gLogFilter, Debug::General, " number of fonts found : [%d]\n", fontSet->nfont );
299 // Reserve some space to avoid reallocations.
300 fontList.reserve( fontSet->nfont );
302 for( int i = 0u; i < fontSet->nfont; ++i )
304 FcPattern* fontPattern = fontSet->fonts[i];
308 // Skip fonts with no path
309 if( GetFcString( fontPattern, FC_FILE, path ) )
311 FcCharSet* characterSet = nullptr;
312 FcPatternGetCharSet( fontPattern, FC_CHARSET, 0u, &characterSet );
314 characterSetList.PushBack( characterSet );
315 fontList.push_back( FontDescription() );
316 FontDescription& newFontDescription = fontList.back();
318 newFontDescription.path = std::move( path );
323 GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
324 GetFcInt( fontPattern, FC_WIDTH, width );
325 GetFcInt( fontPattern, FC_WEIGHT, weight );
326 GetFcInt( fontPattern, FC_SLANT, slant );
327 newFontDescription.width = IntToWidthType( width );
328 newFontDescription.weight = IntToWeightType( weight );
329 newFontDescription.slant = IntToSlantType( slant );
331 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", newFontDescription.family.c_str() );
332 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", newFontDescription.path.c_str() );
333 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[newFontDescription.width] );
334 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[newFontDescription.weight] );
335 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[newFontDescription.slant] );
339 FcFontSetDestroy( fontSet );
343 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " No fonts found.\n" );
346 FcPatternDestroy( fontFamilyPattern );
347 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::SetFontList\n" );
350 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
352 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultFonts\n" );
354 if( mDefaultFonts.empty() )
356 FontDescription fontDescription;
357 fontDescription.family = DEFAULT_FONT_FAMILY_NAME; // todo This could be set to the Platform font
358 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
359 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
360 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
361 SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
364 defaultFonts = mDefaultFonts;
366 DALI_LOG_INFO( gLogFilter, Debug::General, " number of default fonts : [%d]\n", mDefaultFonts.size() );
367 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultFonts\n" );
370 void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
372 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultPlatformFontDescription\n");
374 if( !mDefaultFontDescriptionCached )
376 // Clear any font config stored info in the caches.
377 mDefaultFontCharacterSets.Clear();
378 mCharacterSetCache.Clear();
380 for( auto& item : mFallbackCache )
382 item.characterSets->Clear();
385 for( auto& item : mFontFaceCache )
387 // Set the character set pointer as null. Will be created again the next time IsCharacterSupportedByFont()
388 item.mCharacterSet = nullptr;
391 // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
392 FcInitReinitialize();
394 FcPattern* matchPattern = FcPatternCreate();
398 FcConfigSubstitute( nullptr, matchPattern, FcMatchPattern );
399 FcDefaultSubstitute( matchPattern );
401 FcCharSet* characterSet = nullptr;
402 MatchFontDescriptionToPattern( matchPattern, mDefaultFontDescription, &characterSet );
403 FcPatternDestroy( matchPattern );
406 // Create again the character sets as they are not valid after FcInitReinitialize()
408 for( const auto& description : mDefaultFonts )
410 mDefaultFontCharacterSets.PushBack( CreateCharacterSetFromDescription( description ) );
413 for( const auto& description : mFontDescriptionCache )
415 mCharacterSetCache.PushBack( CreateCharacterSetFromDescription( description ) );
418 for( auto& item : mFallbackCache )
420 if( nullptr != item.fallbackFonts )
422 if( nullptr == item.characterSets )
424 item.characterSets = new CharacterSetList;
427 for( const auto& description : *( item.fallbackFonts ) )
429 item.characterSets->PushBack( CreateCharacterSetFromDescription( description ) );
434 mDefaultFontDescriptionCached = true;
437 fontDescription.path = mDefaultFontDescription.path;
438 fontDescription.family = mDefaultFontDescription.family;
439 fontDescription.width = mDefaultFontDescription.width;
440 fontDescription.weight = mDefaultFontDescription.weight;
441 fontDescription.slant = mDefaultFontDescription.slant;
443 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
444 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
445 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
446 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
447 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
448 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultPlatformFontDescription\n");
451 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
453 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetSystemFonts\n");
455 if( mSystemFonts.empty() )
460 systemFonts = mSystemFonts;
461 DALI_LOG_INFO( gLogFilter, Debug::General, " number of system fonts : [%d]\n", mSystemFonts.size() );
462 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetSystemFonts\n");
465 void FontClient::Plugin::GetDescription( FontId id,
466 FontDescription& fontDescription ) const
468 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDescription\n");
469 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
471 for( const auto& item : mFontDescriptionSizeCache )
473 if( item.fontId == id )
475 fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
477 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
478 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
479 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
480 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
481 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
482 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
487 DALI_LOG_INFO( gLogFilter, Debug::General, " No description found for the font ID %d\n", id );
488 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
491 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
493 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetPointSize\n");
494 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
495 const FontId index = id - 1u;
498 ( index < mFontFaceCache.size() ) )
500 DALI_LOG_INFO( gLogFilter, Debug::General, " point size : %d\n", ( *( mFontFaceCache.begin() + index ) ).mRequestedPointSize );
501 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
502 return ( *( mFontFaceCache.begin() + index ) ).mRequestedPointSize;
506 DALI_LOG_INFO( gLogFilter, Debug::General, " Invalid font ID %d\n", id );
509 DALI_LOG_INFO( gLogFilter, Debug::General, " default point size : %d\n", TextAbstraction::FontClient::DEFAULT_POINT_SIZE );
510 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
511 return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
514 bool FontClient::Plugin::IsCharacterSupportedByFont( FontId fontId, Character character )
516 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::IsCharacterSupportedByFont\n");
517 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
518 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", character );
520 if( ( fontId < 1u ) || ( fontId > mFontFaceCache.size() ) )
522 DALI_LOG_INFO( gLogFilter, Debug::General, " Invalid font id. Number of items in the cache: %d\n",mFontFaceCache.size());
523 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
529 bool isSupported = false;
531 FontFaceCacheItem& cacheItem = mFontFaceCache[fontId];
533 if( nullptr == cacheItem.mCharacterSet )
535 // Create again the character set.
536 // It can be null if the ResetSystemDefaults() method has been called.
538 FontDescription description;
539 description.path = cacheItem.mPath;
540 description.family = std::move( FontFamily( cacheItem.mFreeTypeFace->family_name ) );
541 description.weight = FontWeight::NONE;
542 description.width = FontWidth::NONE;
543 description.slant = FontSlant::NONE;
545 // Note FreeType doesn't give too much info to build a proper font style.
546 if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC )
548 description.slant = FontSlant::ITALIC;
550 if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_BOLD )
552 description.weight = FontWeight::BOLD;
555 cacheItem.mCharacterSet = CreateCharacterSetFromDescription( description );
558 isSupported = FcCharSetHasChar( cacheItem.mCharacterSet, character );
560 DALI_LOG_INFO( gLogFilter, Debug::General, " is supported : %s\n", (isSupported ? "true" : "false") );
561 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
565 FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
566 const CharacterSetList& characterSetList,
568 PointSize26Dot6 requestedPointSize,
571 DALI_ASSERT_DEBUG( ( fontList.size() == characterSetList.Count() ) && "FontClient::Plugin::FindFontForCharacter. Different number of fonts and character sets." );
573 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFontForCharacter\n" );
574 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", character );
575 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
576 DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) );
579 bool foundColor = false;
581 DALI_LOG_INFO( gLogFilter, Debug::General, " number of fonts : %d\n", fontList.size() );
583 // Traverse the list of fonts.
584 // Check for each font if supports the character.
585 for( unsigned int index = 0u, numberOfFonts = fontList.size(); index < numberOfFonts; ++index )
587 const FontDescription& description = fontList[index];
588 const FcCharSet* const characterSet = characterSetList[index];
590 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", description.family.c_str() );
591 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", description.path.c_str() );
592 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[description.width] );
593 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[description.weight] );
594 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[description.slant] );
596 bool foundInRanges = false;
597 if( nullptr != characterSet )
599 foundInRanges = FcCharSetHasChar( characterSet, character );
604 fontId = GetFontId( description,
608 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " font id : %d\n", fontId );
612 if( ( fontId > 0 ) &&
613 ( fontId - 1u < mFontFaceCache.size() ) )
615 const FontFaceCacheItem& item = mFontFaceCache[fontId - 1u];
617 foundColor = item.mHasColorTables;
620 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " foundColor : %s\n", ( foundColor ? "true" : "false" ) );
623 // Keep going unless we prefer a different (color) font.
624 if( !preferColor || foundColor )
631 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
632 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFontForCharacter\n" );
636 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
637 PointSize26Dot6 requestedPointSize,
640 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindDefaultFont\n" );
641 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", charcode );
642 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
643 DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) );
647 // Create the list of default fonts if it has not been created.
648 if( mDefaultFonts.empty() )
650 FontDescription fontDescription;
651 fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
652 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
653 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
654 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
656 SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
658 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of default fonts : %d\n", mDefaultFonts.size() );
661 // Traverse the list of default fonts.
662 // Check for each default font if supports the character.
663 fontId = FindFontForCharacter( mDefaultFonts, mDefaultFontCharacterSets, charcode, requestedPointSize, preferColor );
665 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
666 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindDefaultFont\n" );
671 FontId FontClient::Plugin::FindFallbackFont( Character charcode,
672 const FontDescription& preferredFontDescription,
673 PointSize26Dot6 requestedPointSize,
676 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFont\n" );
677 DALI_LOG_INFO( gLogFilter, Debug::General, " character : %p\n", charcode );
678 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
679 DALI_LOG_INFO( gLogFilter, Debug::General, " preferColor : %s\n", ( preferColor ? "true" : "false" ) );
681 // The font id to be returned.
684 FontDescription fontDescription;
686 // Fill the font description with the preferred font description and complete with the defaults.
687 fontDescription.family = preferredFontDescription.family.empty() ? DEFAULT_FONT_FAMILY_NAME : preferredFontDescription.family;
688 fontDescription.weight = ( ( FontWeight::NONE == preferredFontDescription.weight ) ? IntToWeightType( DEFAULT_FONT_WEIGHT ) : preferredFontDescription.weight );
689 fontDescription.width = ( ( FontWidth::NONE == preferredFontDescription.width ) ? IntToWidthType( DEFAULT_FONT_WIDTH ) : preferredFontDescription.width );
690 fontDescription.slant = ( ( FontSlant::NONE == preferredFontDescription.slant ) ? IntToSlantType( DEFAULT_FONT_SLANT ) : preferredFontDescription.slant );
692 DALI_LOG_INFO( gLogFilter, Debug::General, " preferredFontDescription --> fontDescription\n" );
693 DALI_LOG_INFO( gLogFilter, Debug::General, " [%s] --> [%s]\n", preferredFontDescription.family.c_str(), fontDescription.family.c_str() );
694 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontWeight::Name[preferredFontDescription.weight], FontWeight::Name[fontDescription.weight] );
695 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontWidth::Name[preferredFontDescription.width], FontWidth::Name[fontDescription.width] );
696 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontSlant::Name[preferredFontDescription.slant], FontSlant::Name[fontDescription.slant] );
698 // Check first if the font's description has been queried before.
699 FontList* fontList = nullptr;
700 CharacterSetList* characterSetList = nullptr;
702 if( !FindFallbackFontList( fontDescription, fontList, characterSetList ) )
704 fontList = new FontList;
705 characterSetList = new CharacterSetList;
707 SetFontList( fontDescription, *fontList, *characterSetList );
709 // Add the font-list to the cache.
710 mFallbackCache.push_back( std::move( FallbackCacheItem( std::move( fontDescription ), fontList, characterSetList ) ) );
713 if( fontList && characterSetList )
715 fontId = FindFontForCharacter( *fontList, *characterSetList, charcode, requestedPointSize, preferColor );
718 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
719 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFont\n");
723 FontId FontClient::Plugin::GetFontId( const FontPath& path,
724 PointSize26Dot6 requestedPointSize,
726 bool cacheDescription )
728 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
729 DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() );
730 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
734 if( nullptr != mFreeTypeLibrary )
737 if( FindFont( path, requestedPointSize, faceIndex, foundId ) )
743 id = CreateFont( path, requestedPointSize, faceIndex, cacheDescription );
747 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
748 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
753 FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
754 PointSize26Dot6 requestedPointSize,
755 FaceIndex faceIndex )
757 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
758 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
759 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
760 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
761 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
762 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
763 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
765 // This method uses three vectors which caches:
766 // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
767 // * The path to font file names.
768 // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
770 // 1) Checks in the cache if the font's description has been validated before.
771 // If it was it gets an index to the vector with paths to font file names. Otherwise,
772 // retrieves using font config a path to a font file name which matches with the
773 // font's description. The path is stored in the cache.
775 // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
776 // font file names' exists. If exists, it gets the font id. If it doesn't it calls
777 // the GetFontId() method with the path to the font file name and the point size to
780 // The font id to be returned.
783 // Check first if the font's description have been validated before.
784 FontDescriptionId validatedFontId = 0u;
786 if( !FindValidatedFont( fontDescription,
789 // Use font config to validate the font's description.
790 ValidateFont( fontDescription,
794 // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
795 if( !FindFont( validatedFontId, requestedPointSize, fontId ) )
797 // Retrieve the font file name path.
798 const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
800 // Retrieve the font id. Do not cache the description as it has been already cached.
801 fontId = GetFontId( description.path,
806 mFontFaceCache[fontId-1u].mCharacterSet = mCharacterSetCache[validatedFontId];
808 // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
809 mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
814 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", fontId );
815 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
820 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
821 FontDescriptionId& validatedFontId )
823 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::ValidateFont\n" );
824 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
825 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
826 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
827 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
828 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
830 // Create a font pattern.
831 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
833 FontDescription description;
835 FcCharSet* characterSet = nullptr;
836 bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description, &characterSet );
837 FcPatternDestroy( fontFamilyPattern );
839 if( matched && ( nullptr != characterSet ) )
841 // Set the index to the vector of paths to font file names.
842 validatedFontId = mFontDescriptionCache.size();
844 DALI_LOG_INFO( gLogFilter, Debug::General, " matched description; family : [%s]\n", description.family.c_str() );
845 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", description.path.c_str() );
846 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[description.width] );
847 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[description.weight] );
848 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[description.slant] );
849 DALI_LOG_INFO( gLogFilter, Debug::General, " validatedFontId : %d\n", validatedFontId );
851 // Add the path to the cache.
852 mFontDescriptionCache.push_back( description );
853 mCharacterSetCache.PushBack( characterSet );
855 // Cache the index and the matched font's description.
856 FontDescriptionCacheItem item( description,
859 mValidatedFontCache.push_back( std::move( item ) );
861 if( ( fontDescription.family != description.family ) ||
862 ( fontDescription.width != description.width ) ||
863 ( fontDescription.weight != description.weight ) ||
864 ( fontDescription.slant != description.slant ) )
866 // Cache the given font's description if it's different than the matched.
867 FontDescriptionCacheItem item( fontDescription,
870 mValidatedFontCache.push_back( std::move( item ) );
875 DALI_LOG_INFO( gLogFilter, Debug::General, " font validation failed for font [%s]\n", fontDescription.family.c_str() );
878 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::ValidateFont\n" );
881 void FontClient::Plugin::GetFontMetrics( FontId fontId,
882 FontMetrics& metrics )
884 if( ( fontId > 0 ) &&
885 ( fontId - 1u < mFontFaceCache.size() ) )
887 const FontFaceCacheItem& font = mFontFaceCache[fontId-1];
889 metrics = font.mMetrics;
891 // Adjust the metrics if the fixed-size font should be down-scaled
892 if( font.mIsFixedSizeBitmap )
894 const float desiredFixedSize = static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
896 if( desiredFixedSize > 0.f )
898 const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
900 metrics.ascender = floorf( metrics.ascender * scaleFactor );
901 metrics.descender = floorf( metrics.descender * scaleFactor );
902 metrics.height = floorf( metrics.height * scaleFactor );
903 metrics.underlinePosition = floorf( metrics.underlinePosition * scaleFactor );
904 metrics.underlineThickness = floorf( metrics.underlineThickness * scaleFactor );
910 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId );
914 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
917 GlyphIndex index = 0u;
919 if( ( fontId > 0u ) &&
920 ( fontId - 1u < mFontFaceCache.size() ) )
922 FT_Face ftFace = mFontFaceCache[fontId-1u].mFreeTypeFace;
924 index = FT_Get_Char_Index( ftFace, charcode );
930 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
935 if( VECTOR_GLYPH == type )
937 return GetVectorMetrics( array, size, horizontal );
940 return GetBitmapMetrics( array, size, horizontal );
943 bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array,
947 bool success( true );
949 for( unsigned int i=0; i<size; ++i )
951 GlyphInfo& glyph = array[i];
953 FontId fontId = glyph.fontId;
956 fontId-1 < mFontFaceCache.size() )
958 const FontFaceCacheItem& font = mFontFaceCache[fontId-1];
960 FT_Face ftFace = font.mFreeTypeFace;
962 #ifdef FREETYPE_BITMAP_SUPPORT
963 // Check to see if we should be loading a Fixed Size bitmap?
964 if ( font.mIsFixedSizeBitmap )
966 int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_COLOR );
967 if ( FT_Err_Ok == error )
969 glyph.width = font.mFixedWidthPixels;
970 glyph.height = font.mFixedHeightPixels;
971 glyph.advance = font.mFixedWidthPixels;
972 glyph.xBearing = 0.0f;
973 glyph.yBearing = font.mFixedHeightPixels;
975 // Adjust the metrics if the fixed-size font should be down-scaled
976 const float desiredFixedSize = static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
978 if( desiredFixedSize > 0.f )
980 const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
982 glyph.width = floorf( glyph.width * scaleFactor );
983 glyph.height = floorf( glyph.height * scaleFactor );
984 glyph.advance = floorf( glyph.advance * scaleFactor );
985 glyph.xBearing = floorf( glyph.xBearing * scaleFactor );
986 glyph.yBearing = floorf( glyph.yBearing * scaleFactor );
988 glyph.scaleFactor = scaleFactor;
993 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetBitmapMetrics. FreeType Bitmap Load_Glyph error %d\n", error );
1000 int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_NO_AUTOHINT );
1002 if( FT_Err_Ok == error )
1004 glyph.width = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
1005 glyph.height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
1008 glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
1009 glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
1013 glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
1014 glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
1032 bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array,
1036 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
1037 bool success( true );
1039 for( unsigned int i=0; i<size; ++i )
1041 FontId fontId = array[i].fontId;
1044 fontId-1 < mFontFaceCache.size() )
1046 FontFaceCacheItem& font = mFontFaceCache[fontId-1];
1048 if( ! font.mVectorFontId )
1050 font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
1053 mVectorFontCache->GetGlyphMetrics( font.mVectorFontId, array[i] );
1055 // Vector metrics are in EMs, convert to pixels
1056 const float scale = ( static_cast<float>( font.mRequestedPointSize ) * FROM_266 ) * static_cast<float>( mDpiVertical ) / POINTS_PER_INCH;
1057 array[i].width *= scale;
1058 array[i].height *= scale;
1059 array[i].xBearing *= scale;
1060 array[i].yBearing *= scale;
1061 array[i].advance *= scale;
1075 void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool softwareItalic, bool softwareBold, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
1077 if( ( fontId > 0 ) &&
1078 ( fontId - 1u < mFontFaceCache.size() ) )
1080 FT_Face ftFace = mFontFaceCache[fontId - 1u].mFreeTypeFace;
1084 #ifdef FREETYPE_BITMAP_SUPPORT
1085 // Check to see if this is fixed size bitmap
1086 if ( mFontFaceCache[fontId - 1u].mIsFixedSizeBitmap )
1088 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1093 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_NO_AUTOHINT );
1095 if( FT_Err_Ok == error )
1101 FT_GlyphSlot_Embolden(ftFace->glyph);
1104 if( softwareItalic )
1106 // FT Matrix uses 16.16 fixed-point format
1107 FT_Matrix transform = {0x10000, FONT_SLANT_TANGENT, 0x00000, 0x10000};
1108 FT_Outline_Transform(&ftFace->glyph->outline, &transform);
1111 error = FT_Get_Glyph( ftFace->glyph, &glyph );
1113 // Convert to bitmap if necessary
1114 if ( FT_Err_Ok == error )
1116 if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
1118 // Check whether we should create a bitmap for the outline
1119 if( glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0 )
1123 error = FT_Stroker_New(mFreeTypeLibrary, &stroker );
1125 if ( FT_Err_Ok == error )
1127 FT_Stroker_Set( stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 );
1128 error = FT_Glyph_StrokeBorder( &glyph, stroker, 0, 1 );
1130 if ( FT_Err_Ok == error )
1132 FT_Stroker_Done( stroker );
1136 DALI_LOG_ERROR( "FT_Glyph_StrokeBorder Failed with error: %d\n", error );
1141 DALI_LOG_ERROR( "FT_Stroker_New Failed with error: %d\n", error );
1145 error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
1146 if ( FT_Err_Ok == error )
1148 FT_BitmapGlyph bitmapGlyph = reinterpret_cast< FT_BitmapGlyph >( glyph );
1149 ConvertBitmap( data, bitmapGlyph->bitmap );
1153 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Get_Glyph Failed with error: %d\n", error );
1158 ConvertBitmap( data, ftFace->glyph->bitmap );
1161 // Created FT_Glyph object must be released with FT_Done_Glyph
1162 FT_Done_Glyph( glyph );
1167 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Load_Glyph Failed with error: %d\n", error );
1172 PixelData FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
1174 TextAbstraction::FontClient::GlyphBufferData data;
1176 CreateBitmap( fontId, glyphIndex, false, false, data, outlineWidth );
1178 return PixelData::New( data.buffer,
1179 data.width * data.height * Pixel::GetBytesPerPixel( data.format ),
1183 PixelData::DELETE_ARRAY );
1186 void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
1191 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
1193 fontId-1 < mFontFaceCache.size() )
1195 FontFaceCacheItem& font = mFontFaceCache[fontId-1];
1197 if( ! font.mVectorFontId )
1199 font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
1202 mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
1207 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
1209 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetEllipsisGlyph\n" );
1210 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize %d.\n", requestedPointSize );
1212 // First look into the cache if there is an ellipsis glyph for the requested point size.
1213 for( const auto& item : mEllipsisCache )
1215 if( fabsf( item.requestedPointSize - requestedPointSize ) < Math::MACHINE_EPSILON_1000 )
1217 // Use the glyph in the cache.
1219 DALI_LOG_INFO( gLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index );
1220 DALI_LOG_INFO( gLogFilter, Debug::General, " font %d.\n", item.glyph.fontId );
1221 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
1227 // No glyph has been found. Create one.
1228 mEllipsisCache.PushBack( EllipsisItem() );
1229 EllipsisItem& item = *( mEllipsisCache.End() - 1u );
1231 item.requestedPointSize = requestedPointSize;
1233 // Find a font for the ellipsis glyph.
1234 item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
1238 // Set the character index to access the glyph inside the font.
1239 item.glyph.index = FT_Get_Char_Index( mFontFaceCache[item.glyph.fontId-1].mFreeTypeFace,
1240 ELLIPSIS_CHARACTER );
1242 GetBitmapMetrics( &item.glyph, 1u, true );
1244 DALI_LOG_INFO( gLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index );
1245 DALI_LOG_INFO( gLogFilter, Debug::General, " font %d.\n", item.glyph.fontId );
1246 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
1251 bool FontClient::Plugin::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
1253 FT_Error error = -1;
1255 #ifdef FREETYPE_BITMAP_SUPPORT
1256 if( ( fontId > 0 ) &&
1257 ( fontId - 1u < mFontFaceCache.size() ) )
1259 const FontFaceCacheItem& item = mFontFaceCache[fontId - 1u];
1260 FT_Face ftFace = item.mFreeTypeFace;
1262 // Check to see if this is fixed size bitmap
1263 if( item.mHasColorTables )
1265 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1270 return FT_Err_Ok == error;
1273 FT_FaceRec_* FontClient::Plugin::GetFreetypeFace( FontId fontId )
1275 FT_Face fontFace = nullptr;
1277 if( ( fontId > 0u ) &&
1278 ( fontId - 1u < mFontFaceCache.size() ) )
1280 fontFace = mFontFaceCache[fontId - 1u].mFreeTypeFace;
1286 bool FontClient::Plugin::AddCustomFontDirectory( const FontPath& path )
1288 // NULL as first parameter means the current configuration is used.
1289 return FcConfigAppFontAddDir( NULL, reinterpret_cast<const FcChar8 *>( path.c_str() ) );
1292 void FontClient::Plugin::InitSystemFonts()
1294 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::InitSystemFonts\n" );
1296 FcFontSet* fontSet = GetFcFontSet();
1300 DALI_LOG_INFO( gLogFilter, Debug::General, " number of system fonts : %d\n", fontSet->nfont );
1302 // Reserve some space to avoid reallocations.
1303 mSystemFonts.reserve( fontSet->nfont );
1305 for( int i = 0u; i < fontSet->nfont; ++i )
1307 FcPattern* fontPattern = fontSet->fonts[i];
1311 // Skip fonts with no path
1312 if( GetFcString( fontPattern, FC_FILE, path ) )
1314 mSystemFonts.push_back( FontDescription() );
1315 FontDescription& fontDescription = mSystemFonts.back();
1317 fontDescription.path = std::move( path );
1322 GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
1323 GetFcInt( fontPattern, FC_WIDTH, width );
1324 GetFcInt( fontPattern, FC_WEIGHT, weight );
1325 GetFcInt( fontPattern, FC_SLANT, slant );
1326 fontDescription.width = IntToWidthType( width );
1327 fontDescription.weight = IntToWeightType( weight );
1328 fontDescription.slant = IntToSlantType( slant );
1330 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " description; family : [%s]\n", fontDescription.family.c_str() );
1331 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1332 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1333 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1334 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1338 FcFontSetDestroy( fontSet );
1340 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::InitSystemFonts\n" );
1343 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet )
1345 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1347 FcResult result = FcResultMatch;
1348 FcPattern* match = FcFontMatch( nullptr /* use default configure */, pattern, &result );
1350 const bool matched = nullptr != match;
1351 DALI_LOG_INFO( gLogFilter, Debug::General, " pattern matched : %s\n", ( matched ? "true" : "false" ) );
1358 GetFcString( match, FC_FILE, fontDescription.path );
1359 GetFcString( match, FC_FAMILY, fontDescription.family );
1360 GetFcInt( match, FC_WIDTH, width );
1361 GetFcInt( match, FC_WEIGHT, weight );
1362 GetFcInt( match, FC_SLANT, slant );
1363 fontDescription.width = IntToWidthType( width );
1364 fontDescription.weight = IntToWeightType( weight );
1365 fontDescription.slant = IntToSlantType( slant );
1367 // Cache the character ranges.
1368 FcPatternGetCharSet( match, FC_CHARSET, 0u, characterSet );
1370 // destroyed the matched pattern
1371 FcPatternDestroy( match );
1373 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
1374 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1375 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1376 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1377 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1380 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::MatchFontDescriptionToPattern\n" );
1384 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription ) const
1386 // create the cached font family lookup pattern
1387 // a pattern holds a set of names, each name refers to a property of the font
1388 FcPattern* fontFamilyPattern = FcPatternCreate();
1390 if( !fontFamilyPattern )
1395 // add a property to the pattern for the font family
1396 FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
1398 // add a property to the pattern for local setting.
1399 const char* locale = setlocale( LC_MESSAGES, NULL );
1402 FcPatternAddString( fontFamilyPattern, FC_LANG, reinterpret_cast<const FcChar8*>( locale ) );
1405 int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
1409 width = DEFAULT_FONT_WIDTH;
1412 int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
1416 weight = DEFAULT_FONT_WEIGHT;
1419 int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
1423 slant = DEFAULT_FONT_SLANT;
1426 FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
1427 FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
1428 FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
1430 // Add a property of the pattern, to say we want to match TrueType fonts
1431 FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
1433 // modify the config, with the mFontFamilyPatterm
1434 FcConfigSubstitute( nullptr /* use default configure */, fontFamilyPattern, FcMatchPattern );
1436 // provide default values for unspecified properties in the font pattern
1437 // e.g. patterns without a specified style or weight are set to Medium
1438 FcDefaultSubstitute( fontFamilyPattern );
1440 return fontFamilyPattern;
1443 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
1445 // create a new pattern.
1446 // a pattern holds a set of names, each name refers to a property of the font
1447 FcPattern* pattern = FcPatternCreate();
1449 FcFontSet* fontset = NULL;
1451 // create an object set used to define which properties are to be returned in the patterns from FcFontList.
1452 FcObjectSet* objectSet = FcObjectSetCreate();
1456 // build an object set from a list of property names
1457 FcObjectSetAdd( objectSet, FC_FILE );
1458 FcObjectSetAdd( objectSet, FC_FAMILY );
1459 FcObjectSetAdd( objectSet, FC_WIDTH );
1460 FcObjectSetAdd( objectSet, FC_WEIGHT );
1461 FcObjectSetAdd( objectSet, FC_SLANT );
1463 // get a list of fonts
1464 // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1465 fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
1467 // clear up the object set
1468 FcObjectSetDestroy( objectSet );
1470 // clear up the pattern
1473 FcPatternDestroy( pattern );
1479 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1480 const char* const n,
1481 std::string& string )
1483 FcChar8* file = nullptr;
1484 const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1486 if( FcResultMatch == retVal )
1488 // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1489 string.assign( reinterpret_cast<const char*>( file ) );
1497 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1499 const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1501 if( FcResultMatch == retVal )
1509 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1510 PointSize26Dot6 requestedPointSize,
1511 FaceIndex faceIndex,
1512 bool cacheDescription )
1514 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::CreateFont\n" );
1515 DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() );
1516 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
1520 // Create & cache new font face
1522 int error = FT_New_Face( mFreeTypeLibrary,
1527 if( FT_Err_Ok == error )
1529 // Check if a font is scalable.
1530 const bool isScalable = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_SCALABLE ) );
1531 const bool hasFixedSizedBitmaps = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) && ( 0 != ftFace->num_fixed_sizes );
1532 const bool hasColorTables = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_COLOR ) );
1534 DALI_LOG_INFO( gLogFilter, Debug::General, " isScalable : [%s]\n", ( isScalable ? "true" : "false" ) );
1535 DALI_LOG_INFO( gLogFilter, Debug::General, " hasFixedSizedBitmaps : [%s]\n", ( hasFixedSizedBitmaps ? "true" : "false" ) );
1536 DALI_LOG_INFO( gLogFilter, Debug::General, " hasColorTables : [%s]\n", ( hasColorTables ? "true" : "false" ) );
1538 // Check to see if the font contains fixed sizes?
1539 if( !isScalable && hasFixedSizedBitmaps )
1541 PointSize26Dot6 actualPointSize = 0u;
1542 int fixedSizeIndex = 0;
1543 for( ; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex )
1545 const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
1546 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " size index : %d, size : %d\n", fixedSizeIndex, fixedSize );
1548 if( fixedSize >= requestedPointSize )
1550 actualPointSize = fixedSize;
1555 if( 0u == actualPointSize )
1557 // The requested point size is bigger than the bigest fixed size.
1558 fixedSizeIndex = ftFace->num_fixed_sizes - 1;
1559 actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
1562 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize );
1564 // Tell Freetype to use this size
1565 error = FT_Select_Size( ftFace, fixedSizeIndex );
1566 if ( FT_Err_Ok != error )
1568 DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Select_Size error: %d\n", error );
1572 float fixedWidth = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].width );
1573 float fixedHeight = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].height );
1575 // Indicate that the font is a fixed sized bitmap
1576 FontMetrics metrics( fixedHeight, // The ascender in pixels.
1578 fixedHeight, // The height in pixels.
1582 mFontFaceCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight, hasColorTables ) );
1583 id = mFontFaceCache.size();
1588 error = FT_Set_Char_Size( ftFace,
1594 if( FT_Err_Ok == error )
1597 FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1599 FontMetrics metrics( static_cast< float >( ftMetrics.ascender ) * FROM_266,
1600 static_cast< float >( ftMetrics.descender ) * FROM_266,
1601 static_cast< float >( ftMetrics.height ) * FROM_266,
1602 static_cast< float >( ftFace->underline_position ) * FROM_266,
1603 static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1605 mFontFaceCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) );
1606 id = mFontFaceCache.size();
1610 DALI_LOG_INFO( gLogFilter, Debug::General, " FreeType Set_Char_Size error: %d for pointSize %d\n", error, requestedPointSize );
1616 if( cacheDescription )
1618 CacheFontPath( ftFace, id, requestedPointSize, path );
1624 DALI_LOG_INFO( gLogFilter, Debug::General, " FreeType New_Face error: %d for [%s]\n", error, path.c_str() );
1627 DALI_LOG_INFO( gLogFilter, Debug::General, " font id : %d\n", id );
1628 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::CreateFont\n" );
1633 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap )
1635 if( srcBitmap.width*srcBitmap.rows > 0 )
1637 switch( srcBitmap.pixel_mode )
1639 case FT_PIXEL_MODE_GRAY:
1641 if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
1643 const unsigned int bufferSize = srcBitmap.width * srcBitmap.rows;
1644 data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1645 data.width = srcBitmap.width;
1646 data.height = srcBitmap.rows;
1647 data.format = Pixel::L8;
1648 memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1653 #ifdef FREETYPE_BITMAP_SUPPORT
1654 case FT_PIXEL_MODE_BGRA:
1656 if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
1658 // Set the input dimensions.
1659 const ImageDimensions inputDimensions( srcBitmap.width, srcBitmap.rows );
1661 // Set the output dimensions.
1662 // If the output dimension is not given, the input dimension is set
1663 // and won't be downscaling.
1664 data.width = ( data.width == 0 ) ? srcBitmap.width : data.width;
1665 data.height = ( data.height == 0 ) ? srcBitmap.rows : data.height;
1666 const ImageDimensions desiredDimensions( data.width, data.height );
1668 // Creates the output buffer
1669 const unsigned int bufferSize = data.width * data.height * 4u;
1670 data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1672 if( inputDimensions == desiredDimensions )
1674 // There isn't downscaling.
1675 memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1679 Dali::Internal::Platform::LanczosSample4BPP( srcBitmap.buffer,
1682 desiredDimensions );
1684 data.format = Pixel::BGRA8888;
1691 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::ConvertBitmap. FontClient Unable to create Bitmap of this PixelType\n" );
1698 bool FontClient::Plugin::FindFont( const FontPath& path,
1699 PointSize26Dot6 requestedPointSize,
1700 FaceIndex faceIndex,
1701 FontId& fontId ) const
1703 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1704 DALI_LOG_INFO( gLogFilter, Debug::General, " path : [%s]\n", path.c_str() );
1705 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
1706 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of fonts in the cache : %d\n", mFontFaceCache.size() );
1709 for( const auto& cacheItem : mFontFaceCache )
1712 if( cacheItem.mRequestedPointSize == requestedPointSize &&
1713 cacheItem.mFaceIndex == faceIndex &&
1714 cacheItem.mPath == path )
1717 DALI_LOG_INFO( gLogFilter, Debug::General, " font found, id : %d\n", fontId );
1718 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1724 DALI_LOG_INFO( gLogFilter, Debug::General, " font not found\n" );
1725 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1731 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1732 FontDescriptionId& validatedFontId )
1734 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindValidatedFont\n" );
1735 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
1736 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1737 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1738 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1739 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1740 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of validated fonts in the cache : %d\n", mValidatedFontCache.size() );
1742 validatedFontId = 0u;
1744 for( const auto& item : mValidatedFontCache )
1746 if( !fontDescription.family.empty() &&
1747 ( fontDescription.family == item.fontDescription.family ) &&
1748 ( fontDescription.width == item.fontDescription.width ) &&
1749 ( fontDescription.weight == item.fontDescription.weight ) &&
1750 ( fontDescription.slant == item.fontDescription.slant ) )
1752 validatedFontId = item.index;
1754 DALI_LOG_INFO( gLogFilter, Debug::General, " validated font found, id : %d\n", validatedFontId );
1755 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1760 DALI_LOG_INFO( gLogFilter, Debug::General, " validated font not found\n" );
1761 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
1765 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1766 FontList*& fontList,
1767 CharacterSetList*& characterSetList )
1769 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFontList\n" );
1770 DALI_LOG_INFO( gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str() );
1771 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str() );
1772 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width] );
1773 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
1774 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
1775 DALI_LOG_INFO( gLogFilter, Debug::Verbose, " number of fallback font lists in the cache : %d\n", mFallbackCache.size() );
1779 for( const auto& item : mFallbackCache )
1781 if( !fontDescription.family.empty() &&
1782 ( fontDescription.family == item.fontDescription.family ) &&
1783 ( fontDescription.width == item.fontDescription.width ) &&
1784 ( fontDescription.weight == item.fontDescription.weight ) &&
1785 ( fontDescription.slant == item.fontDescription.slant ) )
1787 fontList = item.fallbackFonts;
1788 characterSetList = item.characterSets;
1790 DALI_LOG_INFO( gLogFilter, Debug::General, " fallback font list found.\n" );
1791 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1796 DALI_LOG_INFO( gLogFilter, Debug::General, " fallback font list not found.\n" );
1797 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
1801 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1802 PointSize26Dot6 requestedPointSize,
1805 DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
1806 DALI_LOG_INFO( gLogFilter, Debug::General, " validatedFontId : %d\n", validatedFontId );
1807 DALI_LOG_INFO( gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize );
1811 for( const auto& item : mFontDescriptionSizeCache )
1813 if( ( validatedFontId == item.validatedFontId ) &&
1814 ( requestedPointSize == item.requestedPointSize ) )
1816 fontId = item.fontId;
1818 DALI_LOG_INFO( gLogFilter, Debug::General, " font found, id : %d\n", fontId );
1819 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1824 DALI_LOG_INFO( gLogFilter, Debug::General, " font not found.\n" );
1825 DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
1829 bool FontClient::Plugin::IsScalable( const FontPath& path )
1831 bool isScalable = false;
1834 int error = FT_New_Face( mFreeTypeLibrary,
1838 if( FT_Err_Ok != error )
1840 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: %s\n", path.c_str() );
1844 isScalable = ftFace->face_flags & FT_FACE_FLAG_SCALABLE;
1850 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1852 // Create a font pattern.
1853 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1855 FcResult result = FcResultMatch;
1857 // match the pattern
1858 FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result );
1859 bool isScalable = false;
1863 // Get the path to the font file name.
1865 GetFcString( match, FC_FILE, path );
1866 isScalable = IsScalable( path );
1870 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1872 FcPatternDestroy( fontFamilyPattern );
1873 FcPatternDestroy( match );
1877 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1879 // Empty the caller container
1883 int error = FT_New_Face( mFreeTypeLibrary,
1887 if( FT_Err_Ok != error )
1889 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font path : [%s]\n", path.c_str() );
1892 // Fetch the number of fixed sizes available
1893 if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1895 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1897 sizes.PushBack( ftFace->available_sizes[ i ].size );
1902 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1903 Vector< PointSize26Dot6 >& sizes )
1905 // Create a font pattern.
1906 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1908 FcResult result = FcResultMatch;
1910 // match the pattern
1911 FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result );
1915 // Get the path to the font file name.
1917 GetFcString( match, FC_FILE, path );
1918 GetFixedSizes( path, sizes );
1922 DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
1924 FcPatternDestroy( match );
1925 FcPatternDestroy( fontFamilyPattern );
1928 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize, const FontPath& path )
1930 FontDescription description;
1931 description.path = path;
1932 description.family = std::move( FontFamily( ftFace->family_name ) );
1933 description.weight = FontWeight::NONE;
1934 description.width = FontWidth::NONE;
1935 description.slant = FontSlant::NONE;
1937 // Note FreeType doesn't give too much info to build a proper font style.
1938 if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1940 description.slant = FontSlant::ITALIC;
1942 if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1944 description.weight = FontWeight::BOLD;
1947 FontDescriptionId validatedFontId = 0u;
1948 if( !FindValidatedFont( description,
1951 // Set the index to the vector of paths to font file names.
1952 validatedFontId = mFontDescriptionCache.size();
1954 FcPattern* pattern = CreateFontFamilyPattern( description );
1956 FcResult result = FcResultMatch;
1957 FcPattern* match = FcFontMatch( nullptr, pattern, &result );
1959 FcCharSet* characterSet = nullptr;
1960 FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
1962 FcPatternDestroy( pattern );
1964 mMatchedFcPatternCache.PushBack( match );
1966 mFontFaceCache[id-1u].mCharacterSet = characterSet;
1968 // Add the path to the cache.
1969 mFontDescriptionCache.push_back( description );
1970 mCharacterSetCache.PushBack( characterSet );
1972 // Cache the index and the font's description.
1973 mValidatedFontCache.push_back( std::move( FontDescriptionCacheItem( std::move( description ),
1974 validatedFontId) ) );
1976 // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
1977 mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
1983 FcCharSet* FontClient::Plugin::CreateCharacterSetFromDescription( const FontDescription& description )
1985 FcCharSet* characterSet = nullptr;
1987 FcPattern* pattern = CreateFontFamilyPattern( description );
1989 if( nullptr != pattern )
1991 FcResult result = FcResultMatch;
1992 FcPattern* match = FcFontMatch( nullptr, pattern, &result );
1994 FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
1995 mMatchedFcPatternCache.PushBack( match );
1997 FcPatternDestroy( pattern );
2000 return characterSet;
2003 void FontClient::Plugin::DestroyMatchedPatterns()
2005 for (auto & object : mMatchedFcPatternCache)
2007 FcPatternDestroy(reinterpret_cast<FcPattern*>(object));
2009 mMatchedFcPatternCache.Clear();
2012 } // namespace Internal
2014 } // namespace TextAbstraction